|
10 | 10 | #pragma once
|
11 | 11 |
|
12 | 12 | #include <map>
|
| 13 | +#include <future> |
13 | 14 | #include <memory>
|
14 | 15 | #include <utility>
|
15 | 16 | #include <vector>
|
|
18 | 19 | #include <celutil/reshandle.h>
|
19 | 20 |
|
20 | 21 |
|
21 |
| -enum class ResourceState { |
| 22 | +enum class ResourceState |
| 23 | +{ |
22 | 24 | NotLoaded = 0,
|
23 | 25 | Loaded = 1,
|
24 | 26 | LoadingFailed = 2,
|
| 27 | + LoadingAsync = 3, |
25 | 28 | };
|
26 | 29 |
|
27 | 30 |
|
28 |
| -template<class T> class ResourceManager |
| 31 | +template<class T, bool A = false> class ResourceManager |
29 | 32 | {
|
30 |
| - public: |
| 33 | + static constexpr bool async = A; |
| 34 | +public: |
31 | 35 | explicit ResourceManager(const fs::path& _baseDir) : baseDir(_baseDir) {};
|
32 | 36 | ~ResourceManager() = default;
|
33 | 37 |
|
@@ -63,20 +67,25 @@ template<class T> class ResourceManager
|
63 | 67 | {
|
64 | 68 | loadResource(resources[h]);
|
65 | 69 | }
|
| 70 | + else if (resources[h].state == ResourceState::LoadingAsync) |
| 71 | + { |
| 72 | + handleAsyncLoad(resources[h]); |
| 73 | + } |
66 | 74 |
|
67 | 75 | return resources[h].state == ResourceState::Loaded
|
68 | 76 | ? resources[h].resource.get()
|
69 | 77 | : nullptr;
|
70 | 78 | }
|
71 | 79 |
|
72 |
| - private: |
| 80 | +private: |
73 | 81 | using KeyType = typename T::ResourceKey;
|
74 | 82 |
|
75 | 83 | struct InfoType
|
76 | 84 | {
|
77 | 85 | T info;
|
78 | 86 | ResourceState state{ ResourceState::NotLoaded };
|
79 | 87 | std::shared_ptr<ResourceType> resource{ nullptr };
|
| 88 | + std::future<bool> future; |
80 | 89 |
|
81 | 90 | explicit InfoType(T _info) : info(std::move(_info)) {}
|
82 | 91 | InfoType(const InfoType&) = delete;
|
@@ -113,7 +122,39 @@ template<class T> class ResourceManager
|
113 | 122 | info.resource = std::move(resource);
|
114 | 123 | info.state = ResourceState::Loaded;
|
115 | 124 | }
|
116 |
| - else if (info.load(resolvedKey)) |
| 125 | + else |
| 126 | + { |
| 127 | + if constexpr (async) |
| 128 | + { |
| 129 | + info.future = std::async(std::launch::async, [&info, resolvedKey]() |
| 130 | + { |
| 131 | + return info.load(resolvedKey); |
| 132 | + }); |
| 133 | + info.state = ResourceState::LoadingAsync; |
| 134 | + } |
| 135 | + else |
| 136 | + { |
| 137 | + bool good = info.load(resolvedKey); |
| 138 | + finish(good, info, resolvedKey); |
| 139 | + } |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + void handleAsyncLoad(InfoType& info) |
| 144 | + { |
| 145 | + if constexpr (async) |
| 146 | + { |
| 147 | + if (info.future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) |
| 148 | + { |
| 149 | + bool good = info.future.get(); |
| 150 | + finish(good, info, info.resolve(baseDir)); |
| 151 | + } |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + void finish(bool good, InfoType& info, const KeyType &resolvedKey) |
| 156 | + { |
| 157 | + if (good) |
117 | 158 | {
|
118 | 159 | info.state = ResourceState::Loaded;
|
119 | 160 | if (auto [iter, inserted] = loadedResources.try_emplace(std::move(resolvedKey), info.resource); !inserted)
|
|
0 commit comments