载入中...
搜索中...
未找到
ParticleConfig.cpp
浏览该文件的文档.
2
3#include "common/Json.h"
4#include "common/Module.h"
8#include "graphics/Graphics.h"
9
10#include <memory>
11
12namespace eve::particles {
13namespace {
14
15using Json = eve::json::Value;
16
17bool readVec2(const Json &o, const char *key, float &a, float &b) {
18 if (!o || !o.has(key)) return false;
19 const Json arr = o.get(key);
20 if (!arr.isArray() || arr.size() < 2) return false;
21 a = arr.at(0).asFloat(a);
22 b = arr.at(1).asFloat(b);
23 return true;
24}
25
26bool readVec4(const Json &o, const char *key, float &a, float &b, float &c, float &d) {
27 if (!o || !o.has(key)) return false;
28 const Json arr = o.get(key);
29 if (!arr.isArray() || arr.size() < 4) return false;
30 a = arr.at(0).asFloat(a);
31 b = arr.at(1).asFloat(b);
32 c = arr.at(2).asFloat(c);
33 d = arr.at(3).asFloat(d);
34 return true;
35}
36
37bool readVec3(const Json &o, const char *key, float &a, float &b, float &c) {
38 if (!o || !o.has(key)) return false;
39 const Json arr = o.get(key);
40 if (!arr.isArray() || arr.size() < 3) return false;
41 a = arr.at(0).asFloat(a);
42 b = arr.at(1).asFloat(b);
43 c = arr.at(2).asFloat(c);
44 return true;
45}
46
47bool readCurveArray(const Json &arr, ParticleCurve &curve) {
48 if (!arr.isArray()) return false;
49 bool any = false;
50 for (size_t i = 0; i < arr.size(); ++i) {
51 const Json item = arr.at(i);
52 if (item.isObject()) {
53 curve.add(item.getFloat("t", 0.f), item.getFloat("v", 0.f));
54 any = true;
55 } else if (item.isArray() && item.size() >= 2) {
56 curve.add(item.at(0).asFloat(0.f), item.at(1).asFloat(0.f));
57 any = true;
58 }
59 }
60 return any;
61}
62
63bool readGradientArray(const Json &arr, ParticleGradient &gradient) {
64 if (!arr.isArray()) return false;
65 bool any = false;
66 for (size_t i = 0; i < arr.size(); ++i) {
67 float t = 0.f, r = 1.f, g = 1.f, b = 1.f, a = 1.f;
68 const Json item = arr.at(i);
69 if (item.isObject()) {
70 t = item.getFloat("t", t);
71 r = item.getFloat("r", r);
72 g = item.getFloat("g", g);
73 b = item.getFloat("b", b);
74 a = item.has("a") ? item.getFloat("a", a) : a;
75 gradient.add(t, r, g, b, a);
76 any = true;
77 } else if (item.isArray() && item.size() >= 5) {
78 t = item.at(0).asFloat(t);
79 r = item.at(1).asFloat(r);
80 g = item.at(2).asFloat(g);
81 b = item.at(3).asFloat(b);
82 a = item.at(4).asFloat(a);
83 gradient.add(t, r, g, b, a);
84 any = true;
85 }
86 }
87 return any;
88}
89
90void tryLoadTexture(ParticleEmitter *emitter, const std::string &path, bool normalMap = false) {
91 if (path.empty()) return;
92 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
93 if (!gfx) return;
94 try {
95 graphics::Texture *tex = gfx->newTextureFromFile(path);
96 if (normalMap)
97 emitter->setNormalTexture(tex);
98 else
99 emitter->setTexture(tex);
100 if (auto *hot = eve::ModuleManager::getInstance<eve::filesystem::HotReload>("HotReload"))
101 hot->bind(path, "texture");
102 } catch (...) {
103 // Leave existing / null texture; config still applied.
104 }
105}
106
107int64_t fileModtime(const std::string &path) {
108 auto *fs = eve::ModuleManager::getInstance<eve::filesystem::Filesystem>("Filesystem");
109 if (!fs) fs = eve::filesystem::Filesystem::create();
111 if (!fs->getInfo(path, info)) return -1;
112 return info.modtime;
113}
114
115} // namespace
116
118 if (!emitter || !root.isObject())
120 "config root must be an object", "particles.config"));
121 const Json obj = root;
122
123 // Optional named preset first; later keys override.
124 if (obj.has("preset")) {
125 std::string preset = obj.getString("preset");
126 if (!preset.empty()) emitter->applyPreset(preset);
127 }
128
129 if (obj.has("x") || obj.has("y")) {
130 float x = emitter->getX();
131 float y = emitter->getY();
132 if (obj.has("x")) x = obj.getFloat("x", x);
133 if (obj.has("y")) y = obj.getFloat("y", y);
134 emitter->setPosition(x, y);
135 }
136
137 if (obj.has("emissionRate")) emitter->setEmissionRate(obj.getFloat("emissionRate", emitter->getEmissionRate()));
138 if (obj.has("emissionRateOverDistance"))
139 emitter->setEmissionRateOverDistance(
140 obj.getFloat("emissionRateOverDistance", emitter->getEmissionRateOverDistance()));
141
142 float lifeMin = emitter->getParticleLifetimeMin();
143 float lifeMax = emitter->getParticleLifetimeMax();
144 if (readVec2(obj, "particleLife", lifeMin, lifeMax))
145 emitter->setParticleLifetime(lifeMin, lifeMax);
146 else {
147 if (obj.has("lifeMin")) lifeMin = obj.getFloat("lifeMin", lifeMin);
148 if (obj.has("lifeMax")) lifeMax = obj.getFloat("lifeMax", lifeMax);
149 if (obj.has("lifeMin") || obj.has("lifeMax")) emitter->setParticleLifetime(lifeMin, lifeMax);
150 }
151
152 if (obj.has("emitterLife")) emitter->setEmitterLifetime(obj.getFloat("emitterLife", emitter->getEmitterLifetime()));
153 if (obj.has("looping")) emitter->setLooping(obj.getBool("looping", emitter->getLooping()));
154 if (obj.has("playbackSpeed")) emitter->setPlaybackSpeed(obj.getFloat("playbackSpeed", emitter->getPlaybackSpeed()));
155 if (obj.has("fixedTimeStep")) {
156 const float step = obj.getFloat("fixedTimeStep", emitter->getFixedTimeStep());
157 const int maxSteps = obj.has("maxSubSteps") ? obj.getInt("maxSubSteps", 8) : emitter->config()->maxSubSteps;
158 emitter->setFixedTimeStep(step, maxSteps);
159 }
160 if (obj.has("randomSeed")) emitter->setRandomSeed(obj.getInt("randomSeed", 0));
161 if (obj.has("autoRandomSeed")) emitter->setAutoRandomSeed(obj.getBool("autoRandomSeed", true));
162
163 if (obj.has("direction")) emitter->setDirection(obj.getFloat("direction", emitter->getDirection()));
164 if (obj.has("spread")) emitter->setSpread(obj.getFloat("spread", emitter->getSpread()));
165
166 float speedMin = 0.f, speedMax = 0.f;
167 if (readVec2(obj, "speed", speedMin, speedMax)) emitter->setSpeed(speedMin, speedMax);
168
169 float ax0 = 0, ay0 = 0, ax1 = 0, ay1 = 0;
170 if (readVec4(obj, "linearAcceleration", ax0, ay0, ax1, ay1)) emitter->setLinearAcceleration(ax0, ay0, ax1, ay1);
171
172 float rad0 = 0, rad1 = 0;
173 if (readVec2(obj, "radialAcceleration", rad0, rad1)) emitter->setRadialAcceleration(rad0, rad1);
174
175 float tan0 = 0, tan1 = 0;
176 if (readVec2(obj, "tangentialAcceleration", tan0, tan1)) emitter->setTangentialAcceleration(tan0, tan1);
177
178 if (obj.has("emissionArea")) {
179 const Json area = obj.get("emissionArea");
180 if (area.isObject()) {
181 std::string type = area.has("type") ? area.getString("type") : "none";
182 float ax = area.has("x") ? area.getFloat("x", 0.f) : 0.f;
183 float ay = area.has("y") ? area.getFloat("y", 0.f) : 0.f;
184 emitter->setEmissionArea(type, ax, ay);
185 }
186 } else if (obj.has("areaType")) {
187 float ax = emitter->getEmissionAreaX();
188 float ay = emitter->getEmissionAreaY();
189 readVec2(obj, "areaSize", ax, ay);
190 emitter->setEmissionArea(obj.getString("areaType"), ax, ay);
191 }
192
193 float pw = emitter->getParticleWidth(), ph = emitter->getParticleHeight();
194 if (readVec2(obj, "particleSize", pw, ph)) emitter->setParticleSize(pw, ph);
195
196 float ss = 1.f, se = 1.f;
197 if (readVec2(obj, "sizes", ss, se)) emitter->setSizes(ss, se);
198
199 if (obj.has("sizeVariation")) emitter->setSizeVariation(obj.getFloat("sizeVariation", emitter->getSizeVariation()));
200
201 float spin0 = 0, spin1 = 0;
202 if (readVec2(obj, "spin", spin0, spin1)) emitter->setSpin(spin0, spin1);
203
204 float sr0 = 0, sr1 = 0;
205 if (readVec2(obj, "startRotation", sr0, sr1)) emitter->setStartRotation(sr0, sr1);
206
207 if (obj.has("bursts")) {
208 const Json arr = obj.get("bursts");
209 if (arr.isArray()) {
210 emitter->clearBursts();
211 for (size_t i = 0; i < arr.size(); ++i) {
212 float t = 0.f;
213 int count = 0;
214 const Json item = arr.at(i);
215 if (item.isObject()) {
216 t = item.getFloat("time", 0.f);
217 count = item.getInt("count", 0);
218 } else if (item.isArray() && item.size() >= 2) {
219 t = item.at(0).asFloat(0.f);
220 count = item.at(1).asInt(0);
221 }
222 if (count > 0) emitter->addBurst(t, count);
223 }
224 }
225 }
226
227 if (obj.has("prewarm")) emitter->setPrewarm(obj.getFloat("prewarm", 0.f));
228
229 float gx = 0, gy = 0;
230 if (readVec2(obj, "gravity", gx, gy)) emitter->setGravity(gx, gy);
231 if (obj.has("damping")) emitter->setDamping(obj.getFloat("damping", 0.f));
232 if (obj.has("limitVelocity")) emitter->setLimitVelocity(obj.getFloat("limitVelocity", 0.f));
233 if (obj.has("velocityOverLifetime")) {
234 const Json arr = obj.get("velocityOverLifetime");
235 if (arr.isArray()) {
236 emitter->clearVelocityCurve();
237 readCurveArray(arr, emitter->config()->velocityCurve);
238 }
239 }
240 if (obj.has("inheritVelocity")) emitter->setInheritVelocity(obj.getFloat("inheritVelocity", 0.f));
241 if (obj.has("simulationSpace")) emitter->setSimulationSpace(obj.getString("simulationSpace"));
242
243 if (obj.has("noise")) {
244 const Json n = obj.get("noise");
245 if (n.isObject()) {
246 float strength = n.has("strength") ? n.getFloat("strength", 0.f) : emitter->config()->noiseStrength;
247 float freq = n.has("frequency") ? n.getFloat("frequency", 1.f) : emitter->config()->noiseFrequency;
248 float speed = n.has("speed") ? n.getFloat("speed", 1.f) : emitter->config()->noiseSpeed;
249 emitter->setNoise(strength, freq, speed);
250 }
251 } else if (obj.has("noiseStrength")) {
252 emitter->setNoise(
253 obj.getFloat("noiseStrength", 0.f),
254 obj.has("noiseFrequency") ? obj.getFloat("noiseFrequency", 1.f) : emitter->config()->noiseFrequency,
255 obj.has("noiseSpeed") ? obj.getFloat("noiseSpeed", 1.f) : emitter->config()->noiseSpeed);
256 }
257
258 if (obj.has("collision")) {
259 const Json col = obj.get("collision");
260 if (col.isObject()) {
261 std::string mode = col.has("mode") ? col.getString("mode") : "none";
262 float radius = col.has("radius") ? col.getFloat("radius", 0.f) : emitter->config()->collisionRadius;
263 float restitution =
264 col.has("restitution") ? col.getFloat("restitution", 0.6f) : emitter->config()->collisionRestitution;
265 float loss =
266 col.has("lifetimeLoss") ? col.getFloat("lifetimeLoss", 0.f) : emitter->config()->collisionLifetimeLoss;
267 emitter->setCollision(mode, radius, restitution, loss);
268 }
269 }
270 if (obj.has("collisionBounds")) {
271 const Json cb = obj.get("collisionBounds");
272 if (cb.isObject()) {
273 bool enabled = cb.has("enabled") ? cb.getBool("enabled", false) : emitter->config()->collisionBoundsEnabled;
274 float minX = cb.has("minX") ? cb.getFloat("minX", 0.f) : emitter->config()->boundsMinX;
275 float minY = cb.has("minY") ? cb.getFloat("minY", 0.f) : emitter->config()->boundsMinY;
276 float maxX = cb.has("maxX") ? cb.getFloat("maxX", 0.f) : emitter->config()->boundsMaxX;
277 float maxY = cb.has("maxY") ? cb.getFloat("maxY", 0.f) : emitter->config()->boundsMaxY;
278 emitter->setCollisionBounds(enabled, minX, minY, maxX, maxY);
279 }
280 }
281 if (obj.has("worldCollision")) emitter->setWorldCollision(obj.getBool("worldCollision", false));
282 if (obj.has("motionVectorPolicy")) emitter->setMotionVectorPolicy(obj.getString("motionVectorPolicy"));
283
284 if (obj.has("renderMode")) {
285 float stretch = obj.has("stretch") ? obj.getFloat("stretch", 1.f) : emitter->config()->stretchFactor;
286 emitter->setRenderMode(obj.getString("renderMode"), stretch);
287 } else if (obj.has("stretch")) {
288 emitter->setRenderMode("stretched", obj.getFloat("stretch", 1.f));
289 }
290 if (obj.has("renderAxis")) emitter->setRenderAxis(obj.getFloat("renderAxis", 0.f));
291 if (obj.has("ribbon")) {
292 const Json ribbon = obj.get("ribbon");
293 if (ribbon.isObject()) {
294 const float width = ribbon.has("width") ? ribbon.getFloat("width", 1.f) : 1.f;
295 const float minSegment = ribbon.has("minSegmentLength") ? ribbon.getFloat("minSegmentLength", 1.f) : 1.f;
296 emitter->setRibbon(width, minSegment);
297 }
298 }
299 if (obj.has("sortMode")) emitter->setSortMode(obj.getString("sortMode"));
300 if (obj.has("materialMode")) emitter->setMaterialMode(obj.getString("materialMode"));
301 if (obj.has("material")) {
302 const Json material = obj.get("material");
303 if (material.isObject()) {
304 if (material.has("mode")) emitter->setMaterialMode(material.getString("mode"));
305 if (material.has("distortionStrength"))
306 emitter->setDistortionStrength(material.getFloat("distortionStrength", 8.f));
307 if (material.has("normalTexture")) {
308 const std::string path = material.getString("normalTexture");
309 emitter->resource()->normalTexturePath = path;
310 tryLoadTexture(emitter, path, true);
311 }
312 }
313 }
314 if (obj.has("parameters")) {
315 const Json parameters = obj.get("parameters");
316 if (parameters.isObject()) {
317 for (const auto &key : parameters.keys())
318 emitter->setFloatParameter(key, parameters.getFloat(key.c_str(), 0.f));
319 }
320 }
321 if (obj.has("parameterBindings")) {
322 const Json bindings = obj.get("parameterBindings");
323 if (bindings.isArray()) {
324 emitter->clearFloatParameterBindings();
325 for (size_t i = 0; i < bindings.size(); ++i) {
326 const Json binding = bindings.at(i);
327 if (!binding.isObject()) continue;
328 emitter->bindFloatParameter(binding.getString("parameter"), binding.getString("target"),
329 binding.has("scale") ? binding.getFloat("scale", 1.f) : 1.f,
330 binding.has("offset") ? binding.getFloat("offset", 0.f) : 0.f);
331 }
332 }
333 }
334 if (obj.has("softParticles")) {
335 const Json soft = obj.get("softParticles");
336 if (soft.isObject()) {
337 const bool enabled = soft.has("enabled") ? soft.getBool("enabled", true) : true;
338 const float depth = soft.has("depth") ? soft.getFloat("depth", 0.5f) : 0.5f;
339 const float fade = soft.has("fadeDistance") ? soft.getFloat("fadeDistance", 0.05f) : 0.05f;
340 emitter->setSoftParticles(enabled, depth, fade);
341 }
342 }
343 if (obj.has("overflowMode")) emitter->setOverflowMode(obj.getString("overflowMode"));
344 if (obj.has("maxDeltaTime")) emitter->setMaxDeltaTime(obj.getFloat("maxDeltaTime", 0.f));
345 if (obj.has("gpuSimulation")) emitter->setGpuSimulation(obj.getBool("gpuSimulation", false));
346 if (obj.has("priority")) emitter->setPriority(obj.getInt("priority", 0));
347 if (obj.has("minimumQuality")) emitter->setMinimumQuality(obj.getInt("minimumQuality", 0));
348 if (obj.has("cullingMode")) emitter->setCullingMode(obj.getString("cullingMode"));
349 if (obj.has("cullDistance")) emitter->setCullDistance(obj.getFloat("cullDistance", 0.f));
350 if (obj.has("maxSpawnPerFrame")) emitter->setMaxSpawnPerFrame(obj.getInt("maxSpawnPerFrame", 0));
351
352 if (obj.has("forceFields")) {
353 const Json arr = obj.get("forceFields");
354 if (arr.isArray()) {
355 emitter->clearForceFields();
356 for (size_t i = 0; i < arr.size(); ++i) {
357 const Json f = arr.at(i);
358 if (!f.isObject()) continue;
359 float x = f.getFloat("x", 0.f);
360 float y = f.getFloat("y", 0.f);
361 float radius = f.getFloat("radius", 0.f);
362 float strength = f.getFloat("strength", 0.f);
363 float falloff = f.has("falloff") ? f.getFloat("falloff", 1.f) : 1.f;
364 emitter->addForceField(x, y, radius, strength, falloff);
365 }
366 }
367 }
368
369 if (obj.has("lights")) {
370 const Json lg = obj.get("lights");
371 if (lg.isObject()) {
372 bool enabled = lg.has("enabled") ? lg.getBool("enabled", false) : emitter->config()->lights.enabled;
373 float radius = lg.has("radius") ? lg.getFloat("radius", 120.f) : emitter->config()->lights.radius;
374 float intensity = lg.has("intensity") ? lg.getFloat("intensity", 1.f) : emitter->config()->lights.intensity;
375 float lr = emitter->config()->lights.r;
376 float lg2 = emitter->config()->lights.g;
377 float lb = emitter->config()->lights.b;
378 readVec3(lg, "color", lr, lg2, lb);
379 if (lg.has("r")) lr = lg.getFloat("r", lr);
380 if (lg.has("g")) lg2 = lg.getFloat("g", lg2);
381 if (lg.has("b")) lb = lg.getFloat("b", lb);
382 int maxL = lg.has("max") ? lg.getInt("max", 4) : emitter->config()->lights.max;
383 emitter->setLights(enabled, radius, intensity, lr, lg2, lb, maxL);
384 }
385 }
386
387 float r = 1, g = 1, b = 1, a = 1;
388 if (readVec4(obj, "colorStart", r, g, b, a)) emitter->setColorStart(r, g, b, a);
389 if (readVec4(obj, "colorEnd", r, g, b, a)) emitter->setColorEnd(r, g, b, a);
390
391 if (obj.has("colorOverLife")) {
392 const Json arr = obj.get("colorOverLife");
393 if (arr.isArray()) {
394 emitter->clearColorGradient();
395 readGradientArray(arr, emitter->config()->colorGradient);
396 }
397 }
398
399 if (obj.has("sizeOverLife")) {
400 const Json arr = obj.get("sizeOverLife");
401 if (arr.isArray()) {
402 emitter->clearSizeCurve();
403 readCurveArray(arr, emitter->config()->sizeCurve);
404 }
405 }
406
407 if (obj.has("rotationOverLife")) {
408 const Json arr = obj.get("rotationOverLife");
409 if (arr.isArray()) {
410 emitter->clearRotationCurve();
411 readCurveArray(arr, emitter->config()->rotationCurve);
412 }
413 }
414
415 if (obj.has("blendMode")) emitter->setBlendMode(obj.getString("blendMode"));
416
417 if (obj.has("flipbook")) {
418 const Json fb = obj.get("flipbook");
419 if (fb.isObject()) {
420 auto c = emitter->config();
421 int h = fb.has("hframes") ? fb.getInt("hframes", 1) : c->hframes;
422 int v = fb.has("vframes") ? fb.getInt("vframes", 1) : c->vframes;
423 float rate = fb.has("frameRate") ? fb.getFloat("frameRate", 0.f) : c->frameRate;
424 float rs = fb.has("frameRandomStart") ? fb.getFloat("frameRandomStart", 0.f) : c->frameRandomStart;
425 emitter->setFlipbook(h, v, rate, rs);
426 }
427 } else if (obj.has("hframes") || obj.has("vframes") || obj.has("frameRate") || obj.has("frameRandomStart")) {
428 auto c = emitter->config();
429 int h = obj.has("hframes") ? obj.getInt("hframes", 1) : c->hframes;
430 int v = obj.has("vframes") ? obj.getInt("vframes", 1) : c->vframes;
431 float rate = obj.has("frameRate") ? obj.getFloat("frameRate", 0.f) : c->frameRate;
432 float rs = obj.has("frameRandomStart") ? obj.getFloat("frameRandomStart", 0.f) : c->frameRandomStart;
433 emitter->setFlipbook(h, v, rate, rs);
434 }
435
436 if (obj.has("layer")) emitter->setLayer(obj.getInt("layer", emitter->getLayer()));
437 if (obj.has("visible")) emitter->setVisible(obj.getBool("visible", emitter->isVisible()));
438
439 if (obj.has("texture")) {
440 std::string texPath = obj.getString("texture");
441 emitter->resource()->texturePath = texPath;
442 tryLoadTexture(emitter, texPath);
443 }
444
445 if (obj.has("autoReload")) emitter->resource()->autoReload = obj.getBool("autoReload", true);
446
447 if (obj.has("autoStart") && obj.getBool("autoStart", false)) emitter->start();
448
450}
451
452bool applyConfigText(ParticleEmitter *emitter, const std::string &json, std::string *error) {
453 std::string err;
454 auto doc = eve::json::Document::parse(json, &err);
455 if (!doc.valid()) {
456 if (error) *error = err.empty() ? "invalid json" : err;
457 return false;
458 }
459 const Json root = doc.root();
460 if (!root.isObject()) {
461 if (error) *error = "config root must be object";
462 return false;
463 }
464 auto applied = applyConfigDocument(emitter, root);
465 if (!applied) {
466 if (error) {
467 const auto* diag = applied.error();
468 *error = (diag && !diag->message().empty()) ? diag->message() : "config root must be object";
469 }
470 return false;
471 }
472 return true;
473}
474
475bool loadConfigFile(ParticleEmitter *emitter, const std::string &path, std::string *error) {
476 if (!emitter || path.empty()) {
477 if (error) *error = "empty path";
478 return false;
479 }
480 auto *fs = eve::ModuleManager::getInstance<eve::filesystem::Filesystem>("Filesystem");
481 if (!fs) fs = eve::filesystem::Filesystem::create();
482
483 std::unique_ptr<eve::filesystem::FileData> data;
484 try {
485 data.reset(fs->read(path));
486 } catch (...) {
487 if (error) *error = "read failed: " + path;
488 return false;
489 }
490 if (!data || data->getSize() == 0) {
491 if (error) *error = "empty file: " + path;
492 return false;
493 }
494
495 std::string text(static_cast<const char *>(data->getData()), data->getSize());
496 if (!applyConfigText(emitter, text, error)) return false;
497
498 auto res = emitter->resource();
499 res->path = path;
500 res->modtime = fileModtime(path);
501 // Prefer OS watch; mtime remains a fallback in ParticleConfigSystem.
502 fs->watch(path);
503 if (auto *hot = eve::ModuleManager::getInstance<eve::filesystem::HotReload>("HotReload"))
504 hot->bind(path, "particle");
505 return true;
506}
507
509 if (!emitter) return false;
510 const std::string &path = emitter->resource()->path;
511 if (path.empty()) {
512 if (error) *error = "no config path";
513 return false;
514 }
516}
517
518} // namespace eve::particles
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
int root
Definition AnimSmr.cpp:119
int ax
Definition CaveMesh.cpp:113
int ay
Definition CaveMesh.cpp:113
tensor::Graph g
Definition GpuGraph.cpp:7
float soft[4]
std::uint32_t key
float area
Definition Grass.cpp:62
glm::vec3 n
Definition Grass.cpp:63
double r
float v
std::int32_t c
int h
std::uint32_t width
std::string text
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
std::vector< std::shared_ptr< DeviceBytes > > bindings
Definition OnnxGpgpu.cpp:38
std::string error
Definition Package.cpp:60
eve::action::ActionVfxBinding binding
float f
float radius
std::string path
Definition PlayHost.cpp:110
float d
float t
Material * material
std::uint32_t count
double restitution
std::unique_ptr< TrailEmitter > emitter
Heightmap curve
float step
Definition TreeMesh.cpp:314
std::uint32_t depth
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Document parse(const std::string &text, std::string *error=nullptr)
Parse.
Definition Json.cpp:581
EVENGINE_API_FOUNDATION public API.
Definition Json.h:38
float asFloat(float fallback=0.f) const
As float.
Definition Json.cpp:407
Value get(const char *key) const
Returns the value.
Definition Json.cpp:336
Value at(size_t index) const
At.
Definition Json.cpp:358
ECS emitter entity. Script configures components; ParticleSimSystem / ParticleRenderSystem drive per-...
bool loadConfigFile(ParticleEmitter *emitter, const std::string &path, std::string *error)
Read path via Filesystem, apply, and bind Resource.path + modtime for hot reload. Returns false if fi...
eve::Result< void > applyConfigDocument(ParticleEmitter *emitter, eve::json::Value root)
Apply particle JSON config onto an emitter, including material texture resources. Does not change buf...
bool reloadConfigFile(ParticleEmitter *emitter, std::string *error)
Re-read Resource.path if set; updates modtime.
bool applyConfigText(ParticleEmitter *emitter, const std::string &json, std::string *error)
Parse JSON text and apply.
bool enabled
glm::uvec4 info