Refactoring resource
This commit is contained in:
parent
7489393d3d
commit
f154eac1e9
@ -1,76 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#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& id);
|
|
||||||
static void saveData(const std::string& id, const StorageData& data);
|
|
||||||
|
|
||||||
static StorageMetadata loadMetadata(const std::string& id);
|
|
||||||
static void saveMetadata(const StorageMetadata& metadata, const std::string& id);
|
|
||||||
};
|
|
||||||
|
|
||||||
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,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DeerRender/DataManagment.h"
|
|
||||||
#include "DeerRender/Log.h"
|
#include "DeerRender/Log.h"
|
||||||
#include "DeerRender/Tools/Memory.h"
|
#include "DeerRender/Tools/Memory.h"
|
||||||
#include "DeerRender/Tools/Path.h"
|
#include "DeerRender/Tools/Path.h"
|
||||||
@ -12,27 +11,33 @@
|
|||||||
namespace Deer {
|
namespace Deer {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
|
typedef uint32_t StorageType;
|
||||||
|
|
||||||
|
template <typename DataSource>
|
||||||
|
class StorageBackend {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
static Scope<T> load(StorageType storageId);
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Resource {
|
class Resource {
|
||||||
public:
|
public:
|
||||||
int32_t getResourceId() const { return resourceId; }
|
int32_t getResourceId() const { return resourceId; }
|
||||||
|
StorageType getStorageId() const { return ResourceManager<T>::getStorageId(*this); }
|
||||||
|
|
||||||
bool isValid() const { return ResourceManager<T>::isValid(*this); }
|
bool isValid() const { return ResourceManager<T>::isValid(*this); }
|
||||||
T& getData() { return ResourceManager<T>::getResourceData(*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) {
|
static Resource<T> unsafeFromId(int32_t id) {
|
||||||
Resource<T> res;
|
Resource<T> res;
|
||||||
res.resourceId = id;
|
res.resourceId = id;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline explicit operator bool() const { return resourceId >= 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// -1 = no resource loaded
|
|
||||||
int32_t resourceId = -1;
|
int32_t resourceId = -1;
|
||||||
friend ResourceManager<T>;
|
friend ResourceManager<T>;
|
||||||
};
|
};
|
||||||
@ -52,37 +57,25 @@ namespace Deer {
|
|||||||
private:
|
private:
|
||||||
struct ResourceData {
|
struct ResourceData {
|
||||||
public:
|
public:
|
||||||
ResourceData(const std::string& _resourceId, Scope<T>&& _data)
|
ResourceData(Scope<T> _data, StorageType _storageId) : data(_data), storageId(_storageId) {}
|
||||||
: storageId(_resourceId), data(std::move(_data)) {}
|
|
||||||
|
|
||||||
Scope<T> data;
|
Scope<T> data;
|
||||||
const std::string storageId;
|
StorageType storageId;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<ResourceData> resources;
|
static std::vector<ResourceData> resources;
|
||||||
static std::unordered_map<std::string, Resource<T>> resourceCache;
|
static std::unordered_map<StorageType, Resource<T>> resourceCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename DataSource>
|
template <typename DataSource>
|
||||||
static Resource<T> loadResource(const std::string& storageId) {
|
static Resource<T> loadResource(StorageType storageId) {
|
||||||
if (resourceCache.contains(storageId))
|
if (resourceCache.contains(storageId))
|
||||||
return resourceCache[storageId];
|
return resourceCache[storageId];
|
||||||
|
|
||||||
using ResourceBuilderBaseDataType = typename ResourceBuilder<T>::BaseDataType;
|
using ResourceBaseType = typename ResourceBuilder<T>::BaseDataType;
|
||||||
Scope<T> data;
|
Scope<T> data;
|
||||||
|
|
||||||
if constexpr (!std::is_void_v<ResourceBuilderBaseDataType>) {
|
Scope<ResourceBaseType> baseData = StorageBackend<DataSource>::template load<ResourceBaseType>(storageId);
|
||||||
Scope<ResourceBuilderBaseDataType> baseData = DataManager<DataSource>::template load<ResourceBuilderBaseDataType>(storageId);
|
data = ResourceBuilder<T>::buildResource(*baseData.get());
|
||||||
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());
|
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
||||||
resources.push_back({storageId, std::move(data)});
|
resources.push_back({storageId, std::move(data)});
|
||||||
@ -91,21 +84,21 @@ namespace Deer {
|
|||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Resource<T> getResource(const std::string& storageId) {
|
static Resource<T> getResource(StorageType storageId) {
|
||||||
if (resourceCache.contains(storageId))
|
if (resourceCache.contains(storageId))
|
||||||
return resourceCache[storageId];
|
return resourceCache[storageId];
|
||||||
|
|
||||||
return Resource<T>();
|
return Resource<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, const std::string& storageId) {
|
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, StorageType storageId) {
|
||||||
if (resourceCache.contains(storageId))
|
if (resourceCache.contains(storageId))
|
||||||
return resourceCache[storageId];
|
return resourceCache[storageId];
|
||||||
|
|
||||||
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
|
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
|
||||||
|
|
||||||
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
|
||||||
resources.push_back({storageId, std::move(data)});
|
resources.push_back({std::move(data), storageId});
|
||||||
resourceCache[storageId] = resource;
|
resourceCache[storageId] = resource;
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
@ -120,10 +113,9 @@ namespace Deer {
|
|||||||
return res.resourceId >= 0 && res.resourceId < static_cast<int32_t>(resources.size());
|
return res.resourceId >= 0 && res.resourceId < static_cast<int32_t>(resources.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const std::string& getStorageId(Resource<T> res) {
|
static inline StorageType getStorageId(Resource<T> res) {
|
||||||
const static std::string invalid("NULL");
|
|
||||||
if (!isValid(res))
|
if (!isValid(res))
|
||||||
return invalid;
|
return 0;
|
||||||
|
|
||||||
return resources[res.resourceId].storageId;
|
return resources[res.resourceId].storageId;
|
||||||
}
|
}
|
||||||
@ -136,5 +128,11 @@ namespace Deer {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<typename ResourceManager<T>::ResourceData> ResourceManager<T>::resources;
|
std::vector<typename ResourceManager<T>::ResourceData> ResourceManager<T>::resources;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unordered_map<std::string, Resource<T>> ResourceManager<T>::resourceCache;
|
std::unordered_map<StorageType, Resource<T>> ResourceManager<T>::resourceCache;
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
|
|
||||||
|
// BUILTIN RESOURCE IDS
|
||||||
|
|
||||||
|
#define RESOURCE_CUBE_ID 0x1
|
||||||
|
#define RESOURCE_SPHERE_ID 0x2
|
||||||
|
#define RESOURCE_BASIC_SHADER_ID 0x3
|
||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace Deer {
|
namespace Deer {
|
||||||
namespace Builtin {
|
namespace Builtin {
|
||||||
|
|
||||||
// Vertex positions (duplicated per face for correct normals)
|
// Vertex positions (duplicated per face for correct normals)
|
||||||
VertexPosition cubeVertexPositions[] = {
|
VertexPosition cubeVertexPositions[] = {
|
||||||
// Front (+Z)
|
// Front (+Z)
|
||||||
@ -97,7 +96,7 @@ namespace Deer {
|
|||||||
|
|
||||||
} // namespace Builtin
|
} // namespace Builtin
|
||||||
Resource<GPUMesh> Builtin::cube() {
|
Resource<GPUMesh> Builtin::cube() {
|
||||||
Resource<GPUMesh> cubeMesh = ResourceManager<GPUMesh>::getResource("Builtin:Cube");
|
Resource<GPUMesh> cubeMesh = ResourceManager<GPUMesh>::getResource(RESOURCE_CUBE_ID);
|
||||||
if (cubeMesh.isValid())
|
if (cubeMesh.isValid())
|
||||||
return cubeMesh;
|
return cubeMesh;
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ namespace Deer {
|
|||||||
for (size_t i = 0; i < 36; i++)
|
for (size_t i = 0; i < 36; i++)
|
||||||
meshData.getIndexData()[i] = cubeIndices[i];
|
meshData.getIndexData()[i] = cubeIndices[i];
|
||||||
|
|
||||||
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, "Builtin:Cube");
|
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, RESOURCE_CUBE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
|
|||||||
@ -9,7 +9,7 @@ namespace Deer {
|
|||||||
} // namespace Builtin
|
} // namespace Builtin
|
||||||
|
|
||||||
Resource<GPUMesh> Builtin::sphere() {
|
Resource<GPUMesh> Builtin::sphere() {
|
||||||
Resource<GPUMesh> sphereMesh = ResourceManager<GPUMesh>::getResource("Builtin:Sphere");
|
Resource<GPUMesh> sphereMesh = ResourceManager<GPUMesh>::getResource(RESOURCE_SPHERE_ID);
|
||||||
if (sphereMesh.isValid())
|
if (sphereMesh.isValid())
|
||||||
return sphereMesh;
|
return sphereMesh;
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ namespace Deer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, "Builtin:Sphere");
|
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, RESOURCE_SPHERE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Deer
|
} // namespace Deer
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerRender/DataManagment.h"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
class EditorDataImporter;
|
|
||||||
|
|
||||||
class MeshData;
|
|
||||||
class ShaderData;
|
|
||||||
class TextureData;
|
|
||||||
|
|
||||||
template <>
|
|
||||||
Scope<MeshData> StorageData::deserialize<EditorDataImporter, MeshData>();
|
|
||||||
|
|
||||||
template <>
|
|
||||||
Scope<ShaderData> StorageData::deserialize<EditorDataImporter, ShaderData>();
|
|
||||||
|
|
||||||
template <>
|
|
||||||
Scope<TextureData> StorageData::deserialize<EditorDataImporter, TextureData>();
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerRender/DataManagment.h"
|
|
||||||
#include "DeerRender/Tools/Path.h"
|
|
||||||
#include "EditorDataImporter.h"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
class EditorDataSource {
|
|
||||||
public:
|
|
||||||
using DataImporter = EditorDataImporter;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class StorageBackend<EditorDataSource> {
|
|
||||||
public:
|
|
||||||
static StorageData loadData(const std::string& location);
|
|
||||||
static void saveData(const std::string& location, const StorageData& data);
|
|
||||||
};
|
|
||||||
} // namespace Deer
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "DeerRender/DataManagment.h"
|
|
||||||
#include "DeerRender/Tools/Path.h"
|
|
||||||
#include "EditorDataImporter.h"
|
|
||||||
|
|
||||||
namespace Deer {
|
|
||||||
class ResourceDataSource {
|
|
||||||
public:
|
|
||||||
using DataImporter = EditorDataImporter;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class StorageBackend<ResourceDataSource> {
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Deer
|
|
||||||
19
DeerStudio/headers/DeerStudio/ResourceStorageBackend.h
Normal file
19
DeerStudio/headers/DeerStudio/ResourceStorageBackend.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#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:
|
||||||
|
static Scope<MeshData> load(StorageType storageId);
|
||||||
|
static Scope<ShaderData> load(StorageType storageId);
|
||||||
|
static Scope<TextureData> load(StorageType storageId);
|
||||||
|
};
|
||||||
|
} // namespace Deer
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "DeerRender/Resource.h"
|
#include "DeerRender/Resource.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CScriptArray;
|
class CScriptArray;
|
||||||
@ -15,7 +16,20 @@ namespace Deer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace StudioAPI {
|
namespace StudioAPI {
|
||||||
Resource<Texture> getIcon(std::string&);
|
int32_t getResourceFolder(std::string&);
|
||||||
|
|
||||||
|
bool resourceFolder_isValid(int32_t&);
|
||||||
|
bool resourceFolder_isRoot(int32_t&);
|
||||||
|
std::string resourceFolder_getName(int32_t&);
|
||||||
|
std::string resourceFolder_getFullPath(int32_t&);
|
||||||
|
int32_t resourceFolder_getParentFolder(int32_t&);
|
||||||
|
int32_t resourceFolder_getSubFolderCount(int32_t&);
|
||||||
|
int32_t resourceFolder_getSubfolderByIndex(int32_t, int32_t&);
|
||||||
|
int32_t resourceFolder_getResourceCount(int32_t&);
|
||||||
|
int32_t resourceFolder_getResourceIdByIndex(int32_t&);
|
||||||
|
|
||||||
|
Resource<Texture>
|
||||||
|
getIcon(std::string&);
|
||||||
|
|
||||||
CScriptArray* getResourceFolders(std::string& path);
|
CScriptArray* getResourceFolders(std::string& path);
|
||||||
CScriptArray* getResourceFiles(std::string& path);
|
CScriptArray* getResourceFiles(std::string& path);
|
||||||
|
|||||||
@ -12,18 +12,23 @@ namespace Deer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceInformation {
|
struct ResourceInformation {
|
||||||
time_t lastUpdate;
|
// Saved info
|
||||||
std::string resourcePath;
|
|
||||||
ResourceType resourceType;
|
|
||||||
uint32_t resourceId;
|
uint32_t resourceId;
|
||||||
|
ResourceType resourceType;
|
||||||
|
std::string resourcePath;
|
||||||
|
|
||||||
// Metadata...
|
// Runtime Info
|
||||||
|
time_t lastUpdate;
|
||||||
|
std::string folderPath;
|
||||||
|
std::string resourceName;
|
||||||
|
std::string fullPath;
|
||||||
|
bool exists = false;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& archive) {
|
void serialize(Archive& archive) {
|
||||||
archive(cereal::make_nvp("Id", resourceId));
|
archive(cereal::make_nvp("Id", resourceId));
|
||||||
archive(cereal::make_nvp("Path", resourcePath));
|
|
||||||
archive(cereal::make_nvp("Type", resourceType));
|
archive(cereal::make_nvp("Type", resourceType));
|
||||||
|
archive(cereal::make_nvp("Path", resourcePath));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "DeerRender/Log.h"
|
#include "DeerRender/Log.h"
|
||||||
#include "DeerRender/Mesh.h"
|
#include "DeerRender/Mesh.h"
|
||||||
#include "DeerStudio/EditorDataImporter.h"
|
|
||||||
|
#include "DeerStudio/ResourceStorageBackend.h"
|
||||||
|
#include "DeerStudio/StudioResources.h"
|
||||||
|
|
||||||
#include "assimp/Importer.hpp"
|
#include "assimp/Importer.hpp"
|
||||||
#include "assimp/metadata.h"
|
#include "assimp/metadata.h"
|
||||||
@ -14,15 +16,12 @@ namespace Deer {
|
|||||||
Scope<MeshData> convertAssimpMesh(const aiMesh* mesh);
|
Scope<MeshData> convertAssimpMesh(const aiMesh* mesh);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
Scope<MeshData> StorageData::deserialize<EditorDataImporter, MeshData>() {
|
Scope<MeshData> StorageBackend<EditorDataSource>::load(StorageType storageId) {
|
||||||
Assimp::Importer importer;
|
ResourceInformation* info = StudioResources::getResourceInfoFromId(storageId);
|
||||||
|
if (!info)
|
||||||
|
return Scope<MeshData>();
|
||||||
|
|
||||||
std::string extension;
|
Assimp::Importer importer;
|
||||||
const char* extension_char = nullptr;
|
|
||||||
if (getMetadata().contains("dataId")) {
|
|
||||||
extension = Path(getMetadata()["dataId"]).extension().string();
|
|
||||||
extension_char = extension.c_str();
|
|
||||||
};
|
|
||||||
const aiScene* scene = importer.ReadFileFromMemory(data.get(), size, aiProcess_Triangulate, extension_char); // aiProcess_JoinIdenticalVertices aiProcess_GenNormals |
|
const aiScene* scene = importer.ReadFileFromMemory(data.get(), size, aiProcess_Triangulate, extension_char); // aiProcess_JoinIdenticalVertices aiProcess_GenNormals |
|
||||||
|
|
||||||
if (scene == nullptr) {
|
if (scene == nullptr) {
|
||||||
@ -46,7 +45,7 @@ namespace Deer {
|
|||||||
Scope<MeshData> result = MakeScope<MeshData>();
|
Scope<MeshData> result = MakeScope<MeshData>();
|
||||||
|
|
||||||
result->createVertices(mesh->mNumVertices);
|
result->createVertices(mesh->mNumVertices);
|
||||||
if (mesh->HasVertexColors(0))
|
if (mesh->HasVertexColors(0))
|
||||||
result->createColorData();
|
result->createColorData();
|
||||||
|
|
||||||
VertexPosition* vertexData = result->getVertexPosition();
|
VertexPosition* vertexData = result->getVertexPosition();
|
||||||
|
|||||||
@ -48,6 +48,7 @@ namespace Deer {
|
|||||||
struct FolderInfo {
|
struct FolderInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string parent;
|
std::string parent;
|
||||||
|
std::string fullPath;
|
||||||
std::vector<uint32_t> resources;
|
std::vector<uint32_t> resources;
|
||||||
std::vector<std::string> subfolders;
|
std::vector<std::string> subfolders;
|
||||||
};
|
};
|
||||||
@ -58,9 +59,11 @@ namespace Deer {
|
|||||||
std::unordered_map<uint32_t, size_t> resourceIdToIndex;
|
std::unordered_map<uint32_t, size_t> resourceIdToIndex;
|
||||||
|
|
||||||
std::vector<FolderInfo> folders;
|
std::vector<FolderInfo> folders;
|
||||||
std::unordered_map<uint32_t, size_t> resourceIdToFolderIndex;
|
|
||||||
std::unordered_map<std::string, size_t> folderPathToFolderIndex;
|
std::unordered_map<std::string, size_t> folderPathToFolderIndex;
|
||||||
|
|
||||||
|
void registerResource(ResourceInformation& resource, size_t index);
|
||||||
|
FolderInfo& getFolderInfo(std::string folderStr);
|
||||||
|
|
||||||
ResourceType getResourceType(const std::string& dir) {
|
ResourceType getResourceType(const std::string& dir) {
|
||||||
Path path(dir);
|
Path path(dir);
|
||||||
std::string extension = path.extension().string();
|
std::string extension = path.extension().string();
|
||||||
@ -82,49 +85,58 @@ namespace Deer {
|
|||||||
} // namespace StudioResources
|
} // namespace StudioResources
|
||||||
|
|
||||||
ResourceInformation* StudioResources::getResourceInfoFromPath(const std::string& path) {
|
ResourceInformation* StudioResources::getResourceInfoFromPath(const std::string& path) {
|
||||||
if (!resourceMap.contains(path))
|
if (!resourcePathToIndex.contains(path))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return resources[resourceMap[path]];
|
return &resources[resourcePathToIndex[path]];
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceInformation* StudioResources::getResourceInfoFromId(uint32_t resource) {
|
ResourceInformation* StudioResources::getResourceInfoFromId(uint32_t resource) {
|
||||||
if (!resourceIdToIndex.contains(resource))
|
if (!resourceIdToIndex.contains(resource))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return resources[resourceIdToIndex[resource]];
|
return &resources[resourceIdToIndex[resource]];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getFolderIndex(std::string folder) {
|
FolderInfo& StudioResources::getFolderInfo(std::string folderStr) {
|
||||||
size_t folderIndex;
|
FolderInfo* folderInfo;
|
||||||
|
if (folderPathToFolderIndex.contains(folderStr)) {
|
||||||
FolderInfo & folder;
|
size_t folderIndex = folderPathToFolderIndex[folderStr];
|
||||||
if (folderPathToFolderIndex.contains(folderIndex)) {
|
folderInfo = &folders[folderIndex];
|
||||||
folderIndex = folderPathToFolderIndex[folderPathStr];
|
|
||||||
folder = folders[folderIndex];
|
|
||||||
} else {
|
} else {
|
||||||
newFolder.name = folderPath.filename().string();
|
Path folderPath(folderStr);
|
||||||
newFolder.fullPath = folderPathStr;
|
|
||||||
folders.push_back(std::move(newFolder));
|
|
||||||
folder = folders.back();
|
|
||||||
|
|
||||||
folderPathToFolderIndex[folderPathStr] = folders.size() - 1;
|
FolderInfo newFolder{
|
||||||
|
.name = folderPath.filename().generic_string(),
|
||||||
|
.parent = folderPath.parent_path().generic_string(),
|
||||||
|
.fullPath = folderStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
folders.push_back(newFolder);
|
||||||
|
folderInfo = &folders.back();
|
||||||
|
folderPathToFolderIndex[folderStr] = folders.size() - 1;
|
||||||
|
|
||||||
|
if (!folderStr.empty()) {
|
||||||
|
FolderInfo& parentPathInfo = getFolderInfo(folderInfo->parent);
|
||||||
|
parentPathInfo.subfolders.push_back(folderStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return *folderInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFolderToFolder(std::string childFolder, std::string parentFolder) {
|
void StudioResources::registerResource(ResourceInformation& resource, size_t index) {
|
||||||
FolderInfo & folder;
|
Path pathId = resource.resourcePath;
|
||||||
if (folderPathToFolderIndex.contains(folderIndex)) {
|
std::string pathFolderId = pathId.parent_path().generic_string();
|
||||||
folderIndex = folderPathToFolderIndex[folderPathStr];
|
|
||||||
folder = folders[folderIndex];
|
|
||||||
} else {
|
|
||||||
newFolder.name = folderPath.filename().string();
|
|
||||||
newFolder.fullPath = folderPathStr;
|
|
||||||
folders.push_back(std::move(newFolder));
|
|
||||||
folder = folders.back();
|
|
||||||
|
|
||||||
folderPathToFolderIndex[folderPathStr] = folders.size() - 1;
|
resource.folderPath = pathFolderId;
|
||||||
}
|
resource.resourceName = pathId.stem().string();
|
||||||
|
|
||||||
|
resourceIdToIndex[resource.resourceId] = index;
|
||||||
|
resourcePathToIndex[resource.resourcePath] = index;
|
||||||
|
|
||||||
|
FolderInfo& folderInfo = getFolderInfo(resource.folderPath);
|
||||||
|
folderInfo.resources.push_back(resource.resourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioResources::scanResources() {
|
void StudioResources::scanResources() {
|
||||||
@ -133,7 +145,6 @@ namespace Deer {
|
|||||||
resourceIdToIndex.clear();
|
resourceIdToIndex.clear();
|
||||||
|
|
||||||
folders.clear();
|
folders.clear();
|
||||||
resourceIdToFolderIndex.clear();
|
|
||||||
folderPathToFolderIndex.clear();
|
folderPathToFolderIndex.clear();
|
||||||
|
|
||||||
Path resourcePath("Resources");
|
Path resourcePath("Resources");
|
||||||
@ -150,6 +161,10 @@ namespace Deer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < resources.size(); i++) {
|
||||||
|
registerResource(resources[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& file : std::filesystem::recursive_directory_iterator(resourcePath)) {
|
for (auto& file : std::filesystem::recursive_directory_iterator(resourcePath)) {
|
||||||
Path filePath = file.path();
|
Path filePath = file.path();
|
||||||
ResourceType type = getResourceType(filePath);
|
ResourceType type = getResourceType(filePath);
|
||||||
@ -157,7 +172,10 @@ namespace Deer {
|
|||||||
if (type == ResourceType::NONE)
|
if (type == ResourceType::NONE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string pathId = filePath.lexically_relative(resourcePath).generic_string().c_str();
|
Path pathIdPath = filePath.lexically_relative(resourcePath);
|
||||||
|
std::string pathId = pathIdPath.generic_string();
|
||||||
|
std::string pathFolderId = pathIdPath.parent_path().generic_string();
|
||||||
|
|
||||||
ResourceInformation* referencingResource = getResourceInfoFromPath(pathId);
|
ResourceInformation* referencingResource = getResourceInfoFromPath(pathId);
|
||||||
|
|
||||||
if (!referencingResource) {
|
if (!referencingResource) {
|
||||||
@ -168,56 +186,17 @@ namespace Deer {
|
|||||||
|
|
||||||
resources.push_back(resourceInformation);
|
resources.push_back(resourceInformation);
|
||||||
referencingResource = &resources.back();
|
referencingResource = &resources.back();
|
||||||
|
|
||||||
|
registerResource(*referencingResource, resources.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ftime = file.last_write_time();
|
auto ftime = file.last_write_time();
|
||||||
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
|
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
|
||||||
|
time_t lastUpdate = std::chrono::system_clock::to_time_t(sctp);
|
||||||
|
|
||||||
referencingResource->lastUpdate = std::chrono::system_clock::to_time_t(sctp);
|
referencingResource->lastUpdate = lastUpdate;
|
||||||
}
|
referencingResource->exists = true;
|
||||||
|
referencingResource->fullPath = std::filesystem::absolute(pathIdPath).generic_string();
|
||||||
for (size_t i = 0; i < resources.size(); i++) {
|
|
||||||
const ResourceInformation& ri = resources[i];
|
|
||||||
|
|
||||||
resourceIdToIndex[ri.resourceId] = i;
|
|
||||||
resourcePathToIndex[ri.resourcePath] = i;
|
|
||||||
|
|
||||||
Path resourceFullPath = ri.resourcePath;
|
|
||||||
Path folderPath = resourceFullPath.parent_path();
|
|
||||||
|
|
||||||
std::string folderPathStr = folderPath.generic_string();
|
|
||||||
size_t folderIndex;
|
|
||||||
|
|
||||||
FolderInfo & folder;
|
|
||||||
if (folderPathToFolderIndex.contains(folderIndex)) {
|
|
||||||
folderIndex = folderPathToFolderIndex[folderPathStr];
|
|
||||||
folder = folders[folderIndex];
|
|
||||||
} else {
|
|
||||||
newFolder.name = folderPath.filename().string();
|
|
||||||
newFolder.fullPath = folderPathStr;
|
|
||||||
folders.push_back(std::move(newFolder));
|
|
||||||
folder = folders.back();
|
|
||||||
|
|
||||||
folderPathToFolderIndex[folderPathStr] = folders.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
newFolder.resources.push_back(ri.resourceId);
|
|
||||||
|
|
||||||
// Check if folder already exists
|
|
||||||
auto it = folderPathToIndex.find(folderPathStr);
|
|
||||||
if (it != folderPathToIndex.end()) {
|
|
||||||
folderIndex = it->second;
|
|
||||||
} else {
|
|
||||||
// Create new folder
|
|
||||||
}
|
|
||||||
|
|
||||||
// If folder exists, just append resource
|
|
||||||
if (it != folderPathToIndex.end()) {
|
|
||||||
folders[folderIndex].resources.push_back(ri.resourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map resource -> folder ID for fast lookup
|
|
||||||
resourceIdToFolderIndex[ri.resourceId] = static_cast<uint32_t>(folderIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,269 +1,269 @@
|
|||||||
{
|
{
|
||||||
"Resources": [
|
"Resources": [
|
||||||
{
|
{
|
||||||
"Id": 3069814959,
|
"Id": 1996334571,
|
||||||
"Path": "shader_uv.glsl",
|
"Type": "SHADER",
|
||||||
"Type": "SHADER"
|
"Path": "shader_uv.glsl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 104674944,
|
"Id": 4117089048,
|
||||||
"Path": "shader_darkBlue.glsl",
|
"Type": "SHADER",
|
||||||
"Type": "SHADER"
|
"Path": "shader_darkBlue.glsl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2366771542,
|
"Id": 2432150072,
|
||||||
"Path": "normal.glsl",
|
"Type": "SHADER",
|
||||||
"Type": "SHADER"
|
"Path": "normal.glsl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2694733599,
|
"Id": 1489680410,
|
||||||
"Path": "train-locomotive-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "train-locomotive-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4256579129,
|
"Id": 3308275089,
|
||||||
"Path": "Kenney/OBJ format/ship-ocean-liner.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-ocean-liner.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3739632882,
|
"Id": 122166032,
|
||||||
"Path": "Kenney/OBJ format/boat-fan.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-fan.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3532984180,
|
"Id": 4256221285,
|
||||||
"Path": "Kenney/OBJ format/boat-row-small.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-row-small.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1925528477,
|
"Id": 2574703391,
|
||||||
"Path": "Kenney/OBJ format/boat-tug-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-tug-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2275934537,
|
"Id": 123183629,
|
||||||
"Path": "Kenney/OBJ format/ship-large.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-large.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 95651136,
|
"Id": 366638598,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2559379043,
|
"Id": 3743423117,
|
||||||
"Path": "Kenney/OBJ format/cargo-pile-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/cargo-pile-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4114347144,
|
"Id": 1606032738,
|
||||||
"Path": "Kenney/OBJ format/cargo-container-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/cargo-container-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1349019805,
|
"Id": 1230607952,
|
||||||
"Path": "Kenney/OBJ format/ship-ocean-liner-small.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-ocean-liner-small.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1178824383,
|
"Id": 2017122979,
|
||||||
"Path": "Kenney/OBJ format/boat-house-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-house-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1756987657,
|
"Id": 4186785049,
|
||||||
"Path": "Kenney/OBJ format/boat-house-d.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-house-d.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2681564794,
|
"Id": 2343534403,
|
||||||
"Path": "Kenney/OBJ format/cargo-pile-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/cargo-pile-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3501520615,
|
"Id": 2678227798,
|
||||||
"Path": "Kenney/OBJ format/cargo-container-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/cargo-container-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3889696810,
|
"Id": 2785550750,
|
||||||
"Path": "Kenney/OBJ format/boat-tug-c.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-tug-c.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 852751301,
|
"Id": 2559111478,
|
||||||
"Path": "Kenney/OBJ format/boat-sail-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-sail-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1602018002,
|
"Id": 593379183,
|
||||||
"Path": "Kenney/OBJ format/boat-house-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-house-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3198781315,
|
"Id": 1429854906,
|
||||||
"Path": "Kenney/OBJ format/ship-small-ghost.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-small-ghost.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 311499906,
|
"Id": 3171063378,
|
||||||
"Path": "Kenney/OBJ format/cargo-container-c.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/cargo-container-c.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4215786342,
|
"Id": 1704557733,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-h.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-h.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4100856350,
|
"Id": 373724868,
|
||||||
"Path": "Kenney/OBJ format/ramp.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ramp.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3814904649,
|
"Id": 2322714265,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-e.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-e.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2019280713,
|
"Id": 2345008259,
|
||||||
"Path": "Kenney/OBJ format/arrow.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/arrow.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1507032232,
|
"Id": 4168217512,
|
||||||
"Path": "Kenney/OBJ format/boat-tow-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-tow-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 198501249,
|
"Id": 2386706163,
|
||||||
"Path": "Kenney/OBJ format/ramp-wide.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ramp-wide.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4136095909,
|
"Id": 781063641,
|
||||||
"Path": "Kenney/OBJ format/boat-tow-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-tow-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1565745400,
|
"Id": 411632088,
|
||||||
"Path": "Kenney/OBJ format/boat-sail-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-sail-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 919433681,
|
"Id": 4159754074,
|
||||||
"Path": "Kenney/OBJ format/boat-fishing-small.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-fishing-small.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1374732749,
|
"Id": 695516138,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-i.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-i.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 434341145,
|
"Id": 3326308007,
|
||||||
"Path": "Kenney/OBJ format/arrow-standing.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/arrow-standing.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 500626431,
|
"Id": 1676376107,
|
||||||
"Path": "Kenney/OBJ format/boat-tug-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-tug-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3009449850,
|
"Id": 1755194382,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-c.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-c.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1928134758,
|
"Id": 2186708766,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-d.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-d.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 815434663,
|
"Id": 3481535109,
|
||||||
"Path": "Kenney/OBJ format/gate-finish.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/gate-finish.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 584294637,
|
"Id": 2993881808,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-g.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-g.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2079718166,
|
"Id": 2186777546,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2407778965,
|
"Id": 3821824996,
|
||||||
"Path": "Kenney/OBJ format/buoy.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/buoy.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2607493592,
|
"Id": 2667317039,
|
||||||
"Path": "Kenney/OBJ format/ship-cargo-c.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-cargo-c.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2561363166,
|
"Id": 1573589900,
|
||||||
"Path": "Kenney/OBJ format/ship-cargo-a.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-cargo-a.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3016804499,
|
"Id": 3055235902,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-j.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-j.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2318332737,
|
"Id": 1767229641,
|
||||||
"Path": "Kenney/OBJ format/ship-small.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-small.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3596619090,
|
"Id": 2959466698,
|
||||||
"Path": "Kenney/OBJ format/boat-speed-f.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-speed-f.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2289035505,
|
"Id": 2695923609,
|
||||||
"Path": "Kenney/OBJ format/boat-row-large.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-row-large.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 4228274168,
|
"Id": 3688026614,
|
||||||
"Path": "Kenney/OBJ format/gate.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/gate.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 202169080,
|
"Id": 1689379446,
|
||||||
"Path": "Kenney/OBJ format/ship-cargo-b.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/ship-cargo-b.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2037323258,
|
"Id": 3413754323,
|
||||||
"Path": "Kenney/OBJ format/buoy-flag.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/buoy-flag.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3045406746,
|
"Id": 2221202314,
|
||||||
"Path": "Kenney/OBJ format/boat-house-c.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "Kenney/OBJ format/boat-house-c.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1098769283,
|
"Id": 2901226354,
|
||||||
"Path": "Kenney/Textures/colormap.png",
|
"Type": "TEXTURE",
|
||||||
"Type": "TEXTURE"
|
"Path": "Kenney/Textures/colormap.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 360224249,
|
"Id": 301223896,
|
||||||
"Path": "monkey.obj",
|
"Type": "MESH",
|
||||||
"Type": "MESH"
|
"Path": "monkey.obj"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 3705973655,
|
"Id": 1799029827,
|
||||||
"Path": "shader.glsl",
|
"Type": "SHADER",
|
||||||
"Type": "SHADER"
|
"Path": "shader.glsl"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user