载入中...
搜索中...
未找到
ParticleReloader.cpp
浏览该文件的文档.
1// Reloads emitters when their JSON config changes, and re-binds emitter
2// textures when the image they reference changes.
3//
4// Registered at kConsumer priority so graphics has already re-uploaded the
5// texture by the time the emitters pick it up again.
6
8#include "common/Capability.h"
9#include "common/ECS.h"
10#include "common/Module.h"
11#include "graphics/Graphics.h"
14
15#include <cctype>
16#include <string>
17
18namespace eve::particles {
19namespace {
20
21std::string extensionOf(const std::string &path) {
22 const auto pos = path.find_last_of('.');
23 if (pos == std::string::npos) return {};
24 std::string ext = path.substr(pos);
25 for (char &c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
26 return ext;
27}
28
29bool isImagePath(const std::string &path) {
30 const std::string ext = extensionOf(path);
31 return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp" || ext == ".tga" ||
32 ext == ".gif" || ext == ".webp" || ext == ".exr" || ext == ".hdr";
33}
34
36std::string normalize(std::string path) {
37 for (char &c : path) {
38 if (c == '\\') c = '/';
39 }
40 while (path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
41 while (path.size() > 1 && path.back() == '/') path.pop_back();
42 return path;
43}
44
45class ParticleReloader : public eve::caps::IAssetReloader {
46public:
47 const char *reloadKind() const override { return "particle"; }
48
49 bool handlesPath(const std::string &normPath) const override {
50 const std::string ext = extensionOf(normPath);
51 return ext == ".json" || isImagePath(normPath);
52 }
53
54 bool reload(const std::string &normPath) override {
55 if (ecs::current()->getManager<ParticleEmitter>() == nullptr) return false;
56 return isImagePath(normPath) ? rebindTexture(normPath) : reloadConfig(normPath);
57 }
58
59private:
60 static bool reloadConfig(const std::string &normPath) {
61 int reloaded = 0;
62 auto view = ecs::View<ParticleEmitter, ParticleEmitter::Config, ParticleEmitter::Resource>();
63 for (auto it = view.begin(); it != view.end(); ++it) {
64 auto [cfg, res] = *it;
65 if (!cfg->entity || res->path.empty()) continue;
66 if (normalize(res->path) != normPath) continue;
67 if (reloadConfigFile(cfg->entity, nullptr)) ++reloaded;
68 }
69 return reloaded > 0;
70 }
71
72 static bool rebindTexture(const std::string &normPath) {
73 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
74 if (!gfx) return false;
75
76 bool any = false;
77 auto view = ecs::View<ParticleEmitter, ParticleEmitter::Config, ParticleEmitter::Resource>();
78 for (auto it = view.begin(); it != view.end(); ++it) {
79 auto [cfg, res] = *it;
80 if (!cfg->entity || res->texturePath.empty()) continue;
81 if (normalize(res->texturePath) != normPath) continue;
82 try {
83 cfg->entity->setTexture(gfx->newTextureFromFile(normPath));
84 any = true;
85 } catch (...) {
86 }
87 }
88 return any;
89 }
90};
91
92struct Register {
93 Register() {
94 static ParticleReloader reloader;
97 }
98} g_register;
99
100} // namespace
101} // namespace eve::particles
uint32_t c
glm::mat4 view
I * query()
Definition Capability.h:77
bool reloadConfigFile(ParticleEmitter *emitter, std::string *error)
Re-read Resource.path if set; updates modtime.