|
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, key = std::move(resolvedKey)]() |
| 130 | + { |
| 131 | + return info.load(key); |
| 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