Cogs.Core
AssetManager.cpp
1#include "AssetManager.h"
2
3#include "Context.h"
4
5#include "Services/Variables.h"
6#include "Services/TaskManager.h"
7#include "Services/Services.h"
8#include "Services/Features.h"
9
10#include "Generators/TextureGenerator.h"
11
12#include "DataFetcherManager.h"
13#include "ModelManager.h"
14#include "MaterialManager.h"
15#include "TextureManager.h"
16#include "ResourceStore.h"
17
18#include "Foundation/Logging/Logger.h"
19#include "Foundation/Platform/FileContents.h"
20#include "Foundation/Platform/IO.h"
21
22namespace
23{
24 Cogs::Logging::Log logger = Cogs::Logging::getLogger("AssetManager");
25 const std::string zstdExtension = ".zst";
26}
27
29{
30
31}
32
33void Cogs::Core::AssetManager::initialize()
34{
35 defaultResource = create();
36 defaultResource->setName("Global");
37 defaultResource->setActive();
38}
39
40Cogs::Core::AssetHandle Cogs::Core::AssetManager::loadAsset(const StringView & path, ResourceId resourceId, AssetLoadFlags flags)
41{
42 AssetLoadInfo & loadInfo = *createLoadInfo();
43 loadInfo.resourceId = resourceId;
44 loadInfo.resourcePath = path.to_string();
45 loadInfo.loadFlags = (ResourceLoadFlags)flags;
46
47 if (context->variables->get("resources.assets.autoReload", false)) {
48 loadInfo.loadFlags |= ResourceLoadFlags::AutoReload;
49 }
50
51 return loadResource(&loadInfo);
52}
53
54void Cogs::Core::AssetManager::reloadAsset(AssetHandle & asset)
55{
56 handleReload(asset);
57}
58
59void Cogs::Core::AssetManager::handleReload(ResourceHandleBase handle)
60{
61 AssetHandle asset(handle);
62
63 AssetLoadInfo & loadInfo = *createLoadInfo();
64 loadInfo.resourceId = asset->getId();
65 loadInfo.resourcePath = asset->getSource().to_string();
66 loadInfo.loadFlags = ResourceLoadFlags::Reload;
67 loadInfo.handle = asset;
68
69 loadResource(&loadInfo);
70}
71
73{
74 const auto ext = Cogs::IO::extension(loadInfo->resourcePath);
75 auto compressed = (ext.compare(zstdExtension) == 0);
76
77 // For Async fetches avoid DataFetcherManager::fetchAsync if asset defined in resources as this only reads from files.
78 if (!loadInfo->loadSync() && context->features->prefers(PlatformPreference::AsyncFetch) &&
79 !context->resourceStore->hasResource(loadInfo->resourcePath)) {
80
81 auto handleResult = [that = this, ctx = context, loadInfo, compressed](std::unique_ptr<FileContents> data)
82 {
83 AssetDefinition definition;
84 if (data && readAssetDefinitionFromFileContents(ctx, std::move(data), definition, compressed)) {
85 if (loadInfo->loadSync()) {
86 AssetHandle(loadInfo->handle)->definition = std::move(definition);
87 }
88 else {
89 auto asset = that->lock(loadInfo->handle);
90 asset->definition = std::move(definition);
91 }
92 }
93 else {
94 LOG_WARNING(logger, "Could not %sload asset definition.", loadInfo->isReload() ? "re" : "");
95 auto asset = that->lock(loadInfo->handle);
96 asset->setFailedLoad();
97 }
98 that->setProcessed(loadInfo, !loadInfo->loadSync());
99 };
100
101 DataFetcherManager::fetchAsync(context, loadInfo->resourcePath, handleResult);
102 }
103
104 else {
105
106 auto loadResource = [=, this]()
107 {
108 AssetDefinition definition;
109 if (readAssetDefinitionFromFile(context, loadInfo->resourcePath, definition, compressed)) {
110 if (loadInfo->loadSync()) {
111 AssetHandle(loadInfo->handle)->definition = std::move(definition);
112 }
113 else {
114 auto asset = lock(loadInfo->handle);
115 asset->definition = std::move(definition);
116 }
117 }
118 else {
119 if (loadInfo->isReload()) {
120 LOG_WARNING(logger, "Could not reload asset definition.");
121 }
122 else {
123 LOG_WARNING(logger, "Could not load asset definition.");
124 }
125 }
126
127 setProcessed(loadInfo, !loadInfo->loadSync());
128 };
129
130 if (loadInfo->loadSync() || !context->features->prefers(PlatformPreference::BackgroundTasks)) {
131 loadResource();
132 }
133 else {
134 context->taskManager->enqueue(TaskManager::ResourceQueue, loadResource);
135 }
136 }
137}
138
139void Cogs::Core::AssetManager::instantiateResource(AssetHandle asset, const ResourceDefinition & resourceDefinition)
140{
141 switch (resourceDefinition.type) {
142 case ResourceTypes::MaterialInstance:
143 {
144 instantiateMaterialInstance(asset, resourceDefinition);
145 break;
146 }
147 case ResourceTypes::Model:
148 {
149 instantiateModel(asset, resourceDefinition);
150 break;
151 }
152 case ResourceTypes::Texture:
153 {
154 instantiateTexture(asset, resourceDefinition);
155 break;
156 }
157 default:
158 LOG_ERROR(logger, "Unknown resource type for asset resource %s", resourceDefinition.name.c_str());
159 break;
160 }
161}
162
163Cogs::Core::AssetHandle Cogs::Core::AssetManager::instantiateAsset(AssetHandle owner, const ResourceDefinition& assetDefinition)
164{
165 auto assetHandle = context->assetManager->loadAsset(assetDefinition.source, NoResourceId, AssetLoadFlags::None);
166 assetHandle->setName(assetDefinition.name);
167
168 if (owner) {
169 auto found = std::find_if(owner->assets.begin(), owner->assets.end(), [&](const AssetHandle& m) { return m.resolve() == assetHandle.resolve(); });
170
171 if (found == owner->assets.end()) {
172 owner->assets.emplace_back(assetHandle);
173 }
174 }
175
176 return assetHandle;
177}
178
179Cogs::Core::ModelHandle Cogs::Core::AssetManager::instantiateModel(AssetHandle asset, const ResourceDefinition & modelDefinition)
180{
181 auto model = context->modelManager->loadModel(modelDefinition.source, NoResourceId, ModelLoadFlags::None);
182 model->setName(modelDefinition.name);
183
184 if (asset) {
185 auto found = std::find_if(asset->models.begin(), asset->models.end(), [&](const ModelHandle & m) { return m.resolve() == model.resolve(); });
186
187 if (found == asset->models.end()) {
188 asset->models.emplace_back(model);
189 }
190 }
191
192 return model;
193}
194
195Cogs::Core::TextureHandle Cogs::Core::AssetManager::instantiateTexture(AssetHandle asset, const ResourceDefinition & textureDefinition)
196{
197 TextureHandle texture;
198
199 auto existing = context->textureManager->getTexture(textureDefinition.name, true);
200
201 if (existing) {
202 texture = existing;
203 } else {
204 if (!textureDefinition.source.empty() && !textureDefinition.textureGenerator) {
205 texture = context->textureManager->loadTexture(textureDefinition.source, NoResourceId, textureDefinition.loadFlags);
206 } else {
207 texture = context->textureManager->create();
208
209 texture->description = textureDefinition.textureDescription;
210
211 if (texture->description.flags & TextureFlags::RenderTarget) {
212 texture->setChanged();
213 }
214
215 if (textureDefinition.textureGenerator) {
216 auto textureGenerator = context->services->getService<TextureGenerator>();
217
218 context->taskManager->enqueue(TaskManager::ResourceQueue, [=, this]()
219 {
220 auto locked = context->textureManager->lock(texture);
221
222 textureGenerator->getTexture(locked.operator->(), textureDefinition.imageDefinition);
223 });
224 }
225 }
226
227 texture->setName(textureDefinition.name);
228 }
229
230 if (asset) {
231 auto found = std::find_if(asset->textures.begin(), asset->textures.end(), [&](const TextureHandle & t) { return t.resolve() == texture.resolve(); });
232
233 if (found == asset->textures.end()) {
234 asset->textures.emplace_back(texture);
235 }
236 }
237
238 return texture;
239}
240
241Cogs::Core::MaterialInstanceHandle Cogs::Core::AssetManager::instantiateMaterialInstance(AssetHandle /*asset*/, const ResourceDefinition & materialInstanceDefinition)
242{
243 if (!materialInstanceDefinition.reference.empty()) {
244 auto reference = context->materialInstanceManager->getMaterialInstance(materialInstanceDefinition.reference);
245
246 return reference;
247 }
248
249 auto material = context->materialManager->getMaterial(materialInstanceDefinition.material);
250
251 if (!material) {
252 LOG_ERROR(logger, "No material with name \"%s\" found.", materialInstanceDefinition.material.c_str());
254 }
255
256 auto materialInstance = context->materialInstanceManager->createMaterialInstance(material);
257
258 materialInstance->setName(materialInstanceDefinition.name);
259
260 updateMaterialInstance(context, materialInstance.resolve(), materialInstanceDefinition);
261
262 return materialInstance;
263}
void handleLoad(AssetLoadInfo *loadInfo) override
Overridden to handle loading assets.
~AssetManager()
Destructs the AssetManager.
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Definition: TaskManager.h:232
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
void updateMaterialInstance(Context *context, MaterialInstance *materialInstance, const MaterialInstanceDefinition &materialInstanceValue)
Apply material instance values.
ResourceLoadFlags
Flags for describing how to load a resource.
Definition: ResourceFlags.h:16
AssetLoadFlags
Asset and Scene loading flags. May be combined with resource loading flags.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
void setName(const StringView &name)
Set the user friendly name of the resource.
Definition: ResourceBase.h:298
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
std::string resourcePath
Resource path. Used to locate resource.
ResourceHandleBase handle
Handle to resource structure for holding actual resource data.
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120