diff --git a/Deer/Include/DeerRender/DataManagment.h b/Deer/Include/DeerRender/DataManagment.h deleted file mode 100644 index 49578f7..0000000 --- a/Deer/Include/DeerRender/DataManagment.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include "DeerCore/Tools/Memory.h" -#include "DeerCore/Tools/TypeDefs.h" - -#include -#include -#include - -namespace Deer { - - using StorageMetadata = std::unordered_map; - template - concept HasMetadata = requires(const std::string& location) { - { T::loadMetadata(location) } -> std::same_as; - { T::saveMetadata(StorageMetadata{}, location) }; - }; - - class StorageData { - public: - StorageData() = default; - StorageData(uint32_t dataSize) : size(dataSize), data(MakeScope(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 - Scope deserialize(); - - template - static StorageData serialize(const T&); - - inline explicit operator bool() const { return size != 0; } - - private: - StorageMetadata metadata; - Scope data = nullptr; - uint32_t size = 0; - }; - - template - 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 - class DataManager { - public: - template - static Scope load(const std::string& dataId) { - StorageData data = StorageBackend::loadData(dataId); - - if constexpr (HasMetadata>) { - data.getMetadata() = StorageBackend::loadMetadata(dataId); - data.getMetadata()["dataId"] = dataId; - } - - return data.deserialize(); - } - - template - static void store(const std::string& dataId, T& value) { - StorageData data = StorageData::serialize(value); - StorageBackend::saveData(dataId, data); - if constexpr (HasMetadata>) { - StorageBackend::saveMetadata(data.getMetadata(), dataId); - } - } - }; -} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/Resource.h b/Deer/Include/DeerRender/Resource.h index 1f2d646..3d844b4 100644 --- a/Deer/Include/DeerRender/Resource.h +++ b/Deer/Include/DeerRender/Resource.h @@ -1,5 +1,4 @@ #pragma once -#include "DeerRender/DataManagment.h" #include "DeerRender/Log.h" #include "DeerRender/Tools/Memory.h" #include "DeerRender/Tools/Path.h" @@ -12,27 +11,33 @@ namespace Deer { template class ResourceManager; + typedef uint32_t StorageType; + + template + class StorageBackend { + public: + template + static Scope load(StorageType storageId); + }; template class Resource { public: int32_t getResourceId() const { return resourceId; } + StorageType getStorageId() const { return ResourceManager::getStorageId(*this); } bool isValid() const { return ResourceManager::isValid(*this); } T& getData() { return ResourceManager::getResourceData(*this); } - const std::string& getStorageId() const { return ResourceManager::getStorageId(*this); } - - inline explicit operator bool() const { return resourceId >= 0; } - static Resource unsafeFromId(int32_t id) { Resource res; res.resourceId = id; return res; } + inline explicit operator bool() const { return resourceId >= 0; } + private: - // -1 = no resource loaded int32_t resourceId = -1; friend ResourceManager; }; @@ -52,37 +57,25 @@ namespace Deer { private: struct ResourceData { public: - ResourceData(const std::string& _resourceId, Scope&& _data) - : storageId(_resourceId), data(std::move(_data)) {} - + ResourceData(Scope _data, StorageType _storageId) : data(_data), storageId(_storageId) {} Scope data; - const std::string storageId; + StorageType storageId; }; static std::vector resources; - static std::unordered_map> resourceCache; + static std::unordered_map> resourceCache; public: template - static Resource loadResource(const std::string& storageId) { + static Resource loadResource(StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; - using ResourceBuilderBaseDataType = typename ResourceBuilder::BaseDataType; + using ResourceBaseType = typename ResourceBuilder::BaseDataType; Scope data; - if constexpr (!std::is_void_v) { - Scope baseData = DataManager::template load(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(); - } - data = ResourceBuilder::buildResource(*baseData.get()); - } else { - data = ResourceBuilder::buildResource(); // No base data - } + Scope baseData = StorageBackend::template load(storageId); + data = ResourceBuilder::buildResource(*baseData.get()); Resource resource = Resource::unsafeFromId(resources.size()); resources.push_back({storageId, std::move(data)}); @@ -91,21 +84,21 @@ namespace Deer { return resource; } - static Resource getResource(const std::string& storageId) { + static Resource getResource(StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; return Resource(); } - static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, const std::string& storageId) { + static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; Scope data = ResourceBuilder::buildResource(resourceData); Resource resource = Resource::unsafeFromId(resources.size()); - resources.push_back({storageId, std::move(data)}); + resources.push_back({std::move(data), storageId}); resourceCache[storageId] = resource; return resource; @@ -120,10 +113,9 @@ namespace Deer { return res.resourceId >= 0 && res.resourceId < static_cast(resources.size()); } - static inline const std::string& getStorageId(Resource res) { - const static std::string invalid("NULL"); + static inline StorageType getStorageId(Resource res) { if (!isValid(res)) - return invalid; + return 0; return resources[res.resourceId].storageId; } @@ -136,5 +128,11 @@ namespace Deer { template std::vector::ResourceData> ResourceManager::resources; template - std::unordered_map> ResourceManager::resourceCache; + std::unordered_map> ResourceManager::resourceCache; } // namespace Deer + +// BUILTIN RESOURCE IDS + +#define RESOURCE_CUBE_ID 0x1 +#define RESOURCE_SPHERE_ID 0x2 +#define RESOURCE_BASIC_SHADER_ID 0x3 \ No newline at end of file diff --git a/Deer/src/DeerRender/Mesh/BuiltinCube.cpp b/Deer/src/DeerRender/Mesh/BuiltinCube.cpp index 76d8c0a..fa5ad49 100644 --- a/Deer/src/DeerRender/Mesh/BuiltinCube.cpp +++ b/Deer/src/DeerRender/Mesh/BuiltinCube.cpp @@ -2,7 +2,6 @@ namespace Deer { namespace Builtin { - // Vertex positions (duplicated per face for correct normals) VertexPosition cubeVertexPositions[] = { // Front (+Z) @@ -97,7 +96,7 @@ namespace Deer { } // namespace Builtin Resource Builtin::cube() { - Resource cubeMesh = ResourceManager::getResource("Builtin:Cube"); + Resource cubeMesh = ResourceManager::getResource(RESOURCE_CUBE_ID); if (cubeMesh.isValid()) return cubeMesh; @@ -119,7 +118,7 @@ namespace Deer { for (size_t i = 0; i < 36; i++) meshData.getIndexData()[i] = cubeIndices[i]; - return ResourceManager::loadResourceFromData(meshData, "Builtin:Cube"); + return ResourceManager::loadResourceFromData(meshData, RESOURCE_CUBE_ID); } } // namespace Deer diff --git a/Deer/src/DeerRender/Mesh/BuiltinSphere.cpp b/Deer/src/DeerRender/Mesh/BuiltinSphere.cpp index 5cf34c4..45c8abe 100644 --- a/Deer/src/DeerRender/Mesh/BuiltinSphere.cpp +++ b/Deer/src/DeerRender/Mesh/BuiltinSphere.cpp @@ -9,7 +9,7 @@ namespace Deer { } // namespace Builtin Resource Builtin::sphere() { - Resource sphereMesh = ResourceManager::getResource("Builtin:Sphere"); + Resource sphereMesh = ResourceManager::getResource(RESOURCE_SPHERE_ID); if (sphereMesh.isValid()) return sphereMesh; @@ -70,7 +70,7 @@ namespace Deer { } } - return ResourceManager::loadResourceFromData(meshData, "Builtin:Sphere"); + return ResourceManager::loadResourceFromData(meshData, RESOURCE_SPHERE_ID); } } // namespace Deer diff --git a/DeerStudio/headers/DeerStudio/EditorDataImporter.h b/DeerStudio/headers/DeerStudio/EditorDataImporter.h deleted file mode 100644 index 48c63c8..0000000 --- a/DeerStudio/headers/DeerStudio/EditorDataImporter.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "DeerRender/DataManagment.h" - -namespace Deer { - class EditorDataImporter; - - class MeshData; - class ShaderData; - class TextureData; - - template <> - Scope StorageData::deserialize(); - - template <> - Scope StorageData::deserialize(); - - template <> - Scope StorageData::deserialize(); -} \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/EditorDataSource.h b/DeerStudio/headers/DeerStudio/EditorDataSource.h deleted file mode 100644 index 0d254d4..0000000 --- a/DeerStudio/headers/DeerStudio/EditorDataSource.h +++ /dev/null @@ -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 { - public: - static StorageData loadData(const std::string& location); - static void saveData(const std::string& location, const StorageData& data); - }; -} // namespace Deer \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/ResourceDataSource.h b/DeerStudio/headers/DeerStudio/ResourceDataSource.h deleted file mode 100644 index d7a93b4..0000000 --- a/DeerStudio/headers/DeerStudio/ResourceDataSource.h +++ /dev/null @@ -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 { - 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 \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/ResourceStorageBackend.h b/DeerStudio/headers/DeerStudio/ResourceStorageBackend.h new file mode 100644 index 0000000..1930a40 --- /dev/null +++ b/DeerStudio/headers/DeerStudio/ResourceStorageBackend.h @@ -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 { + public: + static Scope load(StorageType storageId); + static Scope load(StorageType storageId); + static Scope load(StorageType storageId); + }; +} // namespace Deer \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/StudioAPI.h b/DeerStudio/headers/DeerStudio/StudioAPI.h index ed1537e..30400f6 100644 --- a/DeerStudio/headers/DeerStudio/StudioAPI.h +++ b/DeerStudio/headers/DeerStudio/StudioAPI.h @@ -1,5 +1,6 @@ #pragma once #include "DeerRender/Resource.h" + #include class CScriptArray; @@ -15,7 +16,20 @@ namespace Deer { }; namespace StudioAPI { - Resource 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 + getIcon(std::string&); CScriptArray* getResourceFolders(std::string& path); CScriptArray* getResourceFiles(std::string& path); diff --git a/DeerStudio/headers/DeerStudio/StudioResources.h b/DeerStudio/headers/DeerStudio/StudioResources.h index bcaea1e..0b4be23 100644 --- a/DeerStudio/headers/DeerStudio/StudioResources.h +++ b/DeerStudio/headers/DeerStudio/StudioResources.h @@ -12,18 +12,23 @@ namespace Deer { }; struct ResourceInformation { - time_t lastUpdate; - std::string resourcePath; - ResourceType resourceType; + // Saved info 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 void serialize(Archive& archive) { archive(cereal::make_nvp("Id", resourceId)); - archive(cereal::make_nvp("Path", resourcePath)); archive(cereal::make_nvp("Type", resourceType)); + archive(cereal::make_nvp("Path", resourcePath)); } }; diff --git a/DeerStudio/src/DeerStudio/EditorDataImporter/MeshData.cpp b/DeerStudio/src/DeerStudio/EditorDataImporter/MeshData.cpp index b48ed63..903e70b 100644 --- a/DeerStudio/src/DeerStudio/EditorDataImporter/MeshData.cpp +++ b/DeerStudio/src/DeerStudio/EditorDataImporter/MeshData.cpp @@ -1,6 +1,8 @@ #include "DeerRender/Log.h" #include "DeerRender/Mesh.h" -#include "DeerStudio/EditorDataImporter.h" + +#include "DeerStudio/ResourceStorageBackend.h" +#include "DeerStudio/StudioResources.h" #include "assimp/Importer.hpp" #include "assimp/metadata.h" @@ -14,15 +16,12 @@ namespace Deer { Scope convertAssimpMesh(const aiMesh* mesh); template <> - Scope StorageData::deserialize() { - Assimp::Importer importer; + Scope StorageBackend::load(StorageType storageId) { + ResourceInformation* info = StudioResources::getResourceInfoFromId(storageId); + if (!info) + return Scope(); - std::string extension; - const char* extension_char = nullptr; - if (getMetadata().contains("dataId")) { - extension = Path(getMetadata()["dataId"]).extension().string(); - extension_char = extension.c_str(); - }; + Assimp::Importer importer; const aiScene* scene = importer.ReadFileFromMemory(data.get(), size, aiProcess_Triangulate, extension_char); // aiProcess_JoinIdenticalVertices aiProcess_GenNormals | if (scene == nullptr) { @@ -46,7 +45,7 @@ namespace Deer { Scope result = MakeScope(); result->createVertices(mesh->mNumVertices); - if (mesh->HasVertexColors(0)) + if (mesh->HasVertexColors(0)) result->createColorData(); VertexPosition* vertexData = result->getVertexPosition(); diff --git a/DeerStudio/src/DeerStudio/StudioResources.cpp b/DeerStudio/src/DeerStudio/StudioResources.cpp index 83f380b..e861379 100644 --- a/DeerStudio/src/DeerStudio/StudioResources.cpp +++ b/DeerStudio/src/DeerStudio/StudioResources.cpp @@ -48,6 +48,7 @@ namespace Deer { struct FolderInfo { std::string name; std::string parent; + std::string fullPath; std::vector resources; std::vector subfolders; }; @@ -58,9 +59,11 @@ namespace Deer { std::unordered_map resourceIdToIndex; std::vector folders; - std::unordered_map resourceIdToFolderIndex; std::unordered_map folderPathToFolderIndex; + void registerResource(ResourceInformation& resource, size_t index); + FolderInfo& getFolderInfo(std::string folderStr); + ResourceType getResourceType(const std::string& dir) { Path path(dir); std::string extension = path.extension().string(); @@ -82,49 +85,58 @@ namespace Deer { } // namespace StudioResources ResourceInformation* StudioResources::getResourceInfoFromPath(const std::string& path) { - if (!resourceMap.contains(path)) + if (!resourcePathToIndex.contains(path)) return nullptr; - return resources[resourceMap[path]]; + return &resources[resourcePathToIndex[path]]; } ResourceInformation* StudioResources::getResourceInfoFromId(uint32_t resource) { if (!resourceIdToIndex.contains(resource)) return nullptr; - return resources[resourceIdToIndex[resource]]; + return &resources[resourceIdToIndex[resource]]; } - size_t getFolderIndex(std::string folder) { - size_t folderIndex; - - FolderInfo & folder; - if (folderPathToFolderIndex.contains(folderIndex)) { - folderIndex = folderPathToFolderIndex[folderPathStr]; - folder = folders[folderIndex]; + FolderInfo& StudioResources::getFolderInfo(std::string folderStr) { + FolderInfo* folderInfo; + if (folderPathToFolderIndex.contains(folderStr)) { + size_t folderIndex = folderPathToFolderIndex[folderStr]; + folderInfo = &folders[folderIndex]; } else { - newFolder.name = folderPath.filename().string(); - newFolder.fullPath = folderPathStr; - folders.push_back(std::move(newFolder)); - folder = folders.back(); + Path folderPath(folderStr); - 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) { - 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(); + void StudioResources::registerResource(ResourceInformation& resource, size_t index) { + Path pathId = resource.resourcePath; + std::string pathFolderId = pathId.parent_path().generic_string(); - 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() { @@ -133,7 +145,6 @@ namespace Deer { resourceIdToIndex.clear(); folders.clear(); - resourceIdToFolderIndex.clear(); folderPathToFolderIndex.clear(); 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)) { Path filePath = file.path(); ResourceType type = getResourceType(filePath); @@ -157,7 +172,10 @@ namespace Deer { if (type == ResourceType::NONE) 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); if (!referencingResource) { @@ -168,56 +186,17 @@ namespace Deer { resources.push_back(resourceInformation); referencingResource = &resources.back(); + + registerResource(*referencingResource, resources.size() - 1); } auto ftime = file.last_write_time(); auto sctp = std::chrono::time_point_cast(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); - } - - 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(folderIndex); + referencingResource->lastUpdate = lastUpdate; + referencingResource->exists = true; + referencingResource->fullPath = std::filesystem::absolute(pathIdPath).generic_string(); } { diff --git a/Resources/ResourceData.json b/Resources/ResourceData.json index be35df5..69bc605 100644 --- a/Resources/ResourceData.json +++ b/Resources/ResourceData.json @@ -1,269 +1,269 @@ { "Resources": [ { - "Id": 3069814959, - "Path": "shader_uv.glsl", - "Type": "SHADER" + "Id": 1996334571, + "Type": "SHADER", + "Path": "shader_uv.glsl" }, { - "Id": 104674944, - "Path": "shader_darkBlue.glsl", - "Type": "SHADER" + "Id": 4117089048, + "Type": "SHADER", + "Path": "shader_darkBlue.glsl" }, { - "Id": 2366771542, - "Path": "normal.glsl", - "Type": "SHADER" + "Id": 2432150072, + "Type": "SHADER", + "Path": "normal.glsl" }, { - "Id": 2694733599, - "Path": "train-locomotive-a.obj", - "Type": "MESH" + "Id": 1489680410, + "Type": "MESH", + "Path": "train-locomotive-a.obj" }, { - "Id": 4256579129, - "Path": "Kenney/OBJ format/ship-ocean-liner.obj", - "Type": "MESH" + "Id": 3308275089, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-ocean-liner.obj" }, { - "Id": 3739632882, - "Path": "Kenney/OBJ format/boat-fan.obj", - "Type": "MESH" + "Id": 122166032, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-fan.obj" }, { - "Id": 3532984180, - "Path": "Kenney/OBJ format/boat-row-small.obj", - "Type": "MESH" + "Id": 4256221285, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-row-small.obj" }, { - "Id": 1925528477, - "Path": "Kenney/OBJ format/boat-tug-b.obj", - "Type": "MESH" + "Id": 2574703391, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-tug-b.obj" }, { - "Id": 2275934537, - "Path": "Kenney/OBJ format/ship-large.obj", - "Type": "MESH" + "Id": 123183629, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-large.obj" }, { - "Id": 95651136, - "Path": "Kenney/OBJ format/boat-speed-a.obj", - "Type": "MESH" + "Id": 366638598, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-a.obj" }, { - "Id": 2559379043, - "Path": "Kenney/OBJ format/cargo-pile-b.obj", - "Type": "MESH" + "Id": 3743423117, + "Type": "MESH", + "Path": "Kenney/OBJ format/cargo-pile-b.obj" }, { - "Id": 4114347144, - "Path": "Kenney/OBJ format/cargo-container-a.obj", - "Type": "MESH" + "Id": 1606032738, + "Type": "MESH", + "Path": "Kenney/OBJ format/cargo-container-a.obj" }, { - "Id": 1349019805, - "Path": "Kenney/OBJ format/ship-ocean-liner-small.obj", - "Type": "MESH" + "Id": 1230607952, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-ocean-liner-small.obj" }, { - "Id": 1178824383, - "Path": "Kenney/OBJ format/boat-house-b.obj", - "Type": "MESH" + "Id": 2017122979, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-house-b.obj" }, { - "Id": 1756987657, - "Path": "Kenney/OBJ format/boat-house-d.obj", - "Type": "MESH" + "Id": 4186785049, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-house-d.obj" }, { - "Id": 2681564794, - "Path": "Kenney/OBJ format/cargo-pile-a.obj", - "Type": "MESH" + "Id": 2343534403, + "Type": "MESH", + "Path": "Kenney/OBJ format/cargo-pile-a.obj" }, { - "Id": 3501520615, - "Path": "Kenney/OBJ format/cargo-container-b.obj", - "Type": "MESH" + "Id": 2678227798, + "Type": "MESH", + "Path": "Kenney/OBJ format/cargo-container-b.obj" }, { - "Id": 3889696810, - "Path": "Kenney/OBJ format/boat-tug-c.obj", - "Type": "MESH" + "Id": 2785550750, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-tug-c.obj" }, { - "Id": 852751301, - "Path": "Kenney/OBJ format/boat-sail-b.obj", - "Type": "MESH" + "Id": 2559111478, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-sail-b.obj" }, { - "Id": 1602018002, - "Path": "Kenney/OBJ format/boat-house-a.obj", - "Type": "MESH" + "Id": 593379183, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-house-a.obj" }, { - "Id": 3198781315, - "Path": "Kenney/OBJ format/ship-small-ghost.obj", - "Type": "MESH" + "Id": 1429854906, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-small-ghost.obj" }, { - "Id": 311499906, - "Path": "Kenney/OBJ format/cargo-container-c.obj", - "Type": "MESH" + "Id": 3171063378, + "Type": "MESH", + "Path": "Kenney/OBJ format/cargo-container-c.obj" }, { - "Id": 4215786342, - "Path": "Kenney/OBJ format/boat-speed-h.obj", - "Type": "MESH" + "Id": 1704557733, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-h.obj" }, { - "Id": 4100856350, - "Path": "Kenney/OBJ format/ramp.obj", - "Type": "MESH" + "Id": 373724868, + "Type": "MESH", + "Path": "Kenney/OBJ format/ramp.obj" }, { - "Id": 3814904649, - "Path": "Kenney/OBJ format/boat-speed-e.obj", - "Type": "MESH" + "Id": 2322714265, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-e.obj" }, { - "Id": 2019280713, - "Path": "Kenney/OBJ format/arrow.obj", - "Type": "MESH" + "Id": 2345008259, + "Type": "MESH", + "Path": "Kenney/OBJ format/arrow.obj" }, { - "Id": 1507032232, - "Path": "Kenney/OBJ format/boat-tow-b.obj", - "Type": "MESH" + "Id": 4168217512, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-tow-b.obj" }, { - "Id": 198501249, - "Path": "Kenney/OBJ format/ramp-wide.obj", - "Type": "MESH" + "Id": 2386706163, + "Type": "MESH", + "Path": "Kenney/OBJ format/ramp-wide.obj" }, { - "Id": 4136095909, - "Path": "Kenney/OBJ format/boat-tow-a.obj", - "Type": "MESH" + "Id": 781063641, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-tow-a.obj" }, { - "Id": 1565745400, - "Path": "Kenney/OBJ format/boat-sail-a.obj", - "Type": "MESH" + "Id": 411632088, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-sail-a.obj" }, { - "Id": 919433681, - "Path": "Kenney/OBJ format/boat-fishing-small.obj", - "Type": "MESH" + "Id": 4159754074, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-fishing-small.obj" }, { - "Id": 1374732749, - "Path": "Kenney/OBJ format/boat-speed-i.obj", - "Type": "MESH" + "Id": 695516138, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-i.obj" }, { - "Id": 434341145, - "Path": "Kenney/OBJ format/arrow-standing.obj", - "Type": "MESH" + "Id": 3326308007, + "Type": "MESH", + "Path": "Kenney/OBJ format/arrow-standing.obj" }, { - "Id": 500626431, - "Path": "Kenney/OBJ format/boat-tug-a.obj", - "Type": "MESH" + "Id": 1676376107, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-tug-a.obj" }, { - "Id": 3009449850, - "Path": "Kenney/OBJ format/boat-speed-c.obj", - "Type": "MESH" + "Id": 1755194382, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-c.obj" }, { - "Id": 1928134758, - "Path": "Kenney/OBJ format/boat-speed-d.obj", - "Type": "MESH" + "Id": 2186708766, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-d.obj" }, { - "Id": 815434663, - "Path": "Kenney/OBJ format/gate-finish.obj", - "Type": "MESH" + "Id": 3481535109, + "Type": "MESH", + "Path": "Kenney/OBJ format/gate-finish.obj" }, { - "Id": 584294637, - "Path": "Kenney/OBJ format/boat-speed-g.obj", - "Type": "MESH" + "Id": 2993881808, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-g.obj" }, { - "Id": 2079718166, - "Path": "Kenney/OBJ format/boat-speed-b.obj", - "Type": "MESH" + "Id": 2186777546, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-b.obj" }, { - "Id": 2407778965, - "Path": "Kenney/OBJ format/buoy.obj", - "Type": "MESH" + "Id": 3821824996, + "Type": "MESH", + "Path": "Kenney/OBJ format/buoy.obj" }, { - "Id": 2607493592, - "Path": "Kenney/OBJ format/ship-cargo-c.obj", - "Type": "MESH" + "Id": 2667317039, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-cargo-c.obj" }, { - "Id": 2561363166, - "Path": "Kenney/OBJ format/ship-cargo-a.obj", - "Type": "MESH" + "Id": 1573589900, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-cargo-a.obj" }, { - "Id": 3016804499, - "Path": "Kenney/OBJ format/boat-speed-j.obj", - "Type": "MESH" + "Id": 3055235902, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-j.obj" }, { - "Id": 2318332737, - "Path": "Kenney/OBJ format/ship-small.obj", - "Type": "MESH" + "Id": 1767229641, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-small.obj" }, { - "Id": 3596619090, - "Path": "Kenney/OBJ format/boat-speed-f.obj", - "Type": "MESH" + "Id": 2959466698, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-speed-f.obj" }, { - "Id": 2289035505, - "Path": "Kenney/OBJ format/boat-row-large.obj", - "Type": "MESH" + "Id": 2695923609, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-row-large.obj" }, { - "Id": 4228274168, - "Path": "Kenney/OBJ format/gate.obj", - "Type": "MESH" + "Id": 3688026614, + "Type": "MESH", + "Path": "Kenney/OBJ format/gate.obj" }, { - "Id": 202169080, - "Path": "Kenney/OBJ format/ship-cargo-b.obj", - "Type": "MESH" + "Id": 1689379446, + "Type": "MESH", + "Path": "Kenney/OBJ format/ship-cargo-b.obj" }, { - "Id": 2037323258, - "Path": "Kenney/OBJ format/buoy-flag.obj", - "Type": "MESH" + "Id": 3413754323, + "Type": "MESH", + "Path": "Kenney/OBJ format/buoy-flag.obj" }, { - "Id": 3045406746, - "Path": "Kenney/OBJ format/boat-house-c.obj", - "Type": "MESH" + "Id": 2221202314, + "Type": "MESH", + "Path": "Kenney/OBJ format/boat-house-c.obj" }, { - "Id": 1098769283, - "Path": "Kenney/Textures/colormap.png", - "Type": "TEXTURE" + "Id": 2901226354, + "Type": "TEXTURE", + "Path": "Kenney/Textures/colormap.png" }, { - "Id": 360224249, - "Path": "monkey.obj", - "Type": "MESH" + "Id": 301223896, + "Type": "MESH", + "Path": "monkey.obj" }, { - "Id": 3705973655, - "Path": "shader.glsl", - "Type": "SHADER" + "Id": 1799029827, + "Type": "SHADER", + "Path": "shader.glsl" } ] } \ No newline at end of file