载入中...
搜索中...
未找到
Particles.cpp
浏览该文件的文档.
2#include "common/Json.h"
3#include "common/Module.h"
4#include "common/Profile.h"
8#include "graphics/Graphics.h"
19
20#include <memory>
21#include <simplesquirrel/simplesquirrel.hpp>
22
23namespace eve::particles {
24
26
28
29namespace {
30
31int bufferFromJson(const std::string& json, int fallback) {
32 std::string err;
33 auto doc = eve::json::Document::parse(json, &err);
34 if (!doc.valid() || !doc.root().isObject()) return fallback;
35 const eve::json::Value obj = doc.root();
36 if (!obj.has("buffer")) return fallback;
37 const int n = obj.getInt("buffer", fallback);
38 return n > 0 ? n : fallback;
39}
40
41} // namespace
42
44
46
48 auto* fs = eve::ModuleManager::getInstance<eve::filesystem::Filesystem>("Filesystem");
49 if (!fs) fs = eve::filesystem::Filesystem::create();
50
51 std::unique_ptr<eve::filesystem::FileData> data;
52 try {
53 data.reset(fs->read(path));
54 } catch (...) {
55 return nullptr;
56 }
57 if (!data || data->getSize() == 0) return nullptr;
58
59 std::string text(static_cast<const char*>(data->getData()), data->getSize());
60 int buffer = bufferFromJson(text, 1000);
62 if (!loadConfigFile(e, path, nullptr)) {
63 // Entity stays in ECS registry; still return for inspection, or null?
64 // Prefer null on failed apply after create — leave entity (ECS has no destroy).
65 return e; // path may have failed; emitter still usable
66 }
67 return e;
68}
69
71 lastEffectError_.clear();
72 return ParticleEffect::fromText(json, {}, &lastEffectError_);
73}
74
76 lastEffectError_.clear();
77 return ParticleEffect::fromFile(path, &lastEffectError_);
78}
79
87
89 // Config polling is an asset-side concern. Simulation itself is driven
90 // exclusively by the injected scheduler step below.
93 if (!timelines) return eve::Result<void>::failure(timelines.status());
94 auto simulation = ParticleSimSystem::advance(step);
95 if (!simulation) {
96 timelines.ignore();
97 return eve::Result<void>::failure(simulation.status());
98 }
100 if (timelines.status().code() == eve::StatusCode::Applied) {
101 timelines.ignore();
102 simulation.ignore();
104 }
105 timelines.ignore();
106 return simulation;
107}
108
110
112
114 if (ecs::current()->getManager<ParticleEmitter>() == nullptr) return 0;
115 int n = 0;
116 auto view = ecs::View<ParticleEmitter, ParticleEmitter::Config>();
117 for (auto it = view.begin(); it != view.end(); ++it) ++n;
118 return n;
119}
120
121void Particles::setBudget(int maxParticles, int maxSimulatedEmitters) {
122 auto& budget = particleBudgetConfig();
123 budget.maxParticles = maxParticles > 0 ? maxParticles : 0;
124 budget.maxSimulatedEmitters = maxSimulatedEmitters > 0 ? maxSimulatedEmitters : 0;
125}
126
128
130
131void Particles::setQualityLevel(int quality) {
132 particleBudgetConfig().qualityLevel = quality < 0 ? 0 : (quality > 3 ? 3 : quality);
133}
134
136
140 const auto& stats = particleFrameStats();
141 return stats.emittersBudgetSkipped + stats.emittersQualitySkipped;
142}
149float Particles::getLastSimulationMs() const { return static_cast<float>(particleFrameStats().simulationMs); }
150float Particles::getLastRenderMs() const { return static_cast<float>(particleFrameStats().renderMs); }
151
152void Particles::expose(ssq::Table& table) {
153 auto cls = table.addClass(name, Particles::create, false);
154 expose(cls);
155 cls.addFunc("setBudget", &Particles::setBudget);
156 cls.addFunc("getMaxParticles", &Particles::getMaxParticles);
157 cls.addFunc("getMaxSimulatedEmitters", &Particles::getMaxSimulatedEmitters);
158 cls.addFunc("setQualityLevel", &Particles::setQualityLevel);
159 cls.addFunc("getQualityLevel", &Particles::getQualityLevel);
160 cls.addFunc("getLastSimulatedEmitters", &Particles::getLastSimulatedEmitters);
161 cls.addFunc("getLastCulledEmitters", &Particles::getLastCulledEmitters);
162 cls.addFunc("getLastBudgetSkippedEmitters", &Particles::getLastBudgetSkippedEmitters);
163 cls.addFunc("getLastParticleCount", &Particles::getLastParticleCount);
164 cls.addFunc("getLastSpawnedParticles", &Particles::getLastSpawnedParticles);
165 cls.addFunc("getLastDroppedSpawns", &Particles::getLastDroppedSpawns);
166 cls.addFunc("getLastGpuResidentEmitters", &Particles::getLastGpuResidentEmitters);
167 cls.addFunc("getLastGpuResidentParticles", &Particles::getLastGpuResidentParticles);
168 cls.addFunc("getLastRenderedParticles", &Particles::getLastRenderedParticles);
169 cls.addFunc("getLastSimulationMs", &Particles::getLastSimulationMs);
170 cls.addFunc("getLastRenderMs", &Particles::getLastRenderMs);
171 cls.addFunc("newEffectFromText", &Particles::newEffectFromText);
172 cls.addFunc("newEffectFromFile", &Particles::newEffectFromFile);
173 cls.addFunc("getLastEffectError", &Particles::getLastEffectError);
174
175 auto em = table.addClass<ParticleEmitter>(
176 "Emitter", std::function<ParticleEmitter*()>([]() -> ParticleEmitter* { return nullptr; }), true);
177 auto selector = table.addClass<PcgMaterialSelector>(
178 "PcgMaterialSelector", std::function<PcgMaterialSelector*()>([]() { return new PcgMaterialSelector(); }), true);
179 selector.addFunc("add", [vm = table.getHandle()](PcgMaterialSelector* self, graphics::Texture* texture) {
180 return eve::script::projectResult(vm, self->add(texture));
181 });
182 selector.addFunc("clear", &PcgMaterialSelector::clear);
183 selector.addFunc("count", &PcgMaterialSelector::count);
184 selector.addFunc(
185 "selectAndApply", [vm = table.getHandle()](PcgMaterialSelector* self, ParticleEmitter* emitter, int seed) {
186 return eve::script::projectResult(vm, self->selectAndApply(emitter, static_cast<std::uint32_t>(seed)),
187 [](int index) { return eve::Value(index); });
188 });
189 table.addFunc("applyUnderwaterParticles",
190 [vm = table.getHandle()](ParticleEmitter* ambience, ParticleEmitter* transition, bool active,
191 bool transitionFx, bool entered, bool exited) {
193 vm, applyUnderwaterParticles(ambience, transition, active, transitionFx, entered, exited));
194 });
195 table.addFunc("applyUnderwaterSurfaceVfx", [vm = table.getHandle()](ParticleEmitter* surfaceVfx, bool active) {
197 });
198 table.addFunc("applyGroundParticleCulling", [vm = table.getHandle()](ParticleEmitter* emitter, int playerTag,
199 int visitorTag, bool entered, bool exited) {
201 applyGroundParticleCulling(emitter, playerTag, visitorTag, entered, exited));
202 });
203 table.addFunc("shiftWorldSpaceParticles",
204 [vm = table.getHandle()](ParticleEmitter* emitter, float shiftX, float shiftY) {
206 [](int count) { return eve::Value(count); });
207 });
208
209 auto effect = table.addClass<ParticleEffect>(
210 "ParticleEffect", std::function<ParticleEffect*()>([]() -> ParticleEffect* { return nullptr; }), true);
211 effect.addFunc("getVersion", &ParticleEffect::getVersion);
212 effect.addFunc("getSourcePath", &ParticleEffect::getSourcePath);
213 effect.addFunc("getEmitterCount", &ParticleEffect::getEmitterCount);
214 effect.addFunc("getEmitterName", &ParticleEffect::getEmitterName);
215 effect.addFunc("getEmitter", &ParticleEffect::getEmitter);
216 effect.addFunc("getEmitterByName", &ParticleEffect::getEmitterByName);
217 effect.addFunc("setPosition", &ParticleEffect::setPosition);
218 effect.addFunc("getX", &ParticleEffect::getX);
219 effect.addFunc("getY", &ParticleEffect::getY);
220 effect.addFunc("setRotation", &ParticleEffect::setRotation);
221 effect.addFunc("getRotation", &ParticleEffect::getRotation);
222 effect.addFunc("setScale", &ParticleEffect::setScale);
223 effect.addFunc("getScale", &ParticleEffect::getScale);
224 effect.addFunc("setLayer", &ParticleEffect::setLayer);
225 effect.addFunc("getLayer", &ParticleEffect::getLayer);
226 effect.addFunc("setVisible", &ParticleEffect::setVisible);
227 effect.addFunc("isVisible", &ParticleEffect::isVisible);
228 effect.addFunc("start", &ParticleEffect::start);
229 effect.addFunc("stop", &ParticleEffect::stop);
230 effect.addFunc("pause", &ParticleEffect::pause);
231 effect.addFunc("reset", &ParticleEffect::reset);
232 effect.addFunc("emit", &ParticleEffect::emit);
233 effect.addFunc("setFloatParameter", &ParticleEffect::setFloatParameter);
234 effect.addFunc("getFloatParameter", &ParticleEffect::getFloatParameter);
235 effect.addFunc("hasFloatParameter", &ParticleEffect::hasFloatParameter);
236 effect.addFunc("getTimelineSeconds", &ParticleEffect::getTimelineSeconds);
237 effect.addFunc("isTimelinePlaying", &ParticleEffect::isTimelinePlaying);
238 effect.addFunc("updateTimeline", &ParticleEffect::updateTimeline);
239 effect.addFunc("reloadFromFile", [](ParticleEffect* self) {
240 if (!self) return false;
241 auto reloaded = self->reloadFromFile();
242 const bool ok = static_cast<bool>(reloaded);
243 reloaded.ignore();
244 return ok;
245 });
246 auto pool = table.addClass<ParticleEmitterPool>(
247 "ParticleEmitterPool", std::function<ParticleEmitterPool*()>([]() { return new ParticleEmitterPool(); }), true);
248 pool.addFunc("acquire", [](ParticleEmitterPool* self, int minBuffer) -> ParticleEmitter* {
249 if (!self) return nullptr;
250 auto acquired = self->acquire(minBuffer);
251 if (!acquired) {
252 acquired.ignore();
253 return nullptr;
254 }
255 return acquired.value();
256 });
257 pool.addFunc("recycle", [](ParticleEmitterPool* self, ParticleEmitter* emitter) {
258 if (!self) return false;
259 auto recycled = self->recycle(emitter);
260 const bool ok = static_cast<bool>(recycled);
261 recycled.ignore();
262 return ok;
263 });
264 pool.addFunc("clear", &ParticleEmitterPool::clear);
265 pool.addFunc("idleCount", [](ParticleEmitterPool* self) { return self ? static_cast<int>(self->idleCount()) : 0; });
266 em.addFunc("setPosition", &ParticleEmitter::setPosition);
267 em.addFunc("moveTo", &ParticleEmitter::moveTo);
268 em.addFunc("getX", &ParticleEmitter::getX);
269 em.addFunc("getY", &ParticleEmitter::getY);
270 em.addFunc("setEmissionRate", &ParticleEmitter::setEmissionRate);
271 em.addFunc("getEmissionRate", &ParticleEmitter::getEmissionRate);
272 em.addFunc("setEmissionRateOverDistance", &ParticleEmitter::setEmissionRateOverDistance);
273 em.addFunc("getEmissionRateOverDistance", &ParticleEmitter::getEmissionRateOverDistance);
274 em.addFunc("setParticleLifetime", &ParticleEmitter::setParticleLifetime);
275 // Alias — scripts often say "Life" for the same knob.
276 em.addFunc("setParticleLife", &ParticleEmitter::setParticleLifetime);
277 em.addFunc("getParticleLifetimeMin", &ParticleEmitter::getParticleLifetimeMin);
278 em.addFunc("getParticleLifetimeMax", &ParticleEmitter::getParticleLifetimeMax);
279 em.addFunc("setEmitterLifetime", &ParticleEmitter::setEmitterLifetime);
280 // Aliases — scripts may say Life/Time for the same knob.
281 em.addFunc("setEmitterLife", &ParticleEmitter::setEmitterLifetime);
282 em.addFunc("setEmitterTime", &ParticleEmitter::setEmitterLifetime);
283 em.addFunc("getEmitterLifetime", &ParticleEmitter::getEmitterLifetime);
284 em.addFunc("setLooping", &ParticleEmitter::setLooping);
285 em.addFunc("getLooping", &ParticleEmitter::getLooping);
286 em.addFunc("setPlaybackSpeed", &ParticleEmitter::setPlaybackSpeed);
287 em.addFunc("getPlaybackSpeed", &ParticleEmitter::getPlaybackSpeed);
288 em.addFunc("setFixedTimeStep", &ParticleEmitter::setFixedTimeStep);
289 em.addFunc("getFixedTimeStep", &ParticleEmitter::getFixedTimeStep);
290 em.addFunc("setRandomSeed", &ParticleEmitter::setRandomSeed);
291 em.addFunc("getRandomSeed", &ParticleEmitter::getRandomSeed);
292 em.addFunc("setAutoRandomSeed", &ParticleEmitter::setAutoRandomSeed);
293 em.addFunc("getAutoRandomSeed", &ParticleEmitter::getAutoRandomSeed);
294 em.addFunc("setDirection", &ParticleEmitter::setDirection);
295 em.addFunc("getDirection", &ParticleEmitter::getDirection);
296 em.addFunc("setSpread", &ParticleEmitter::setSpread);
297 em.addFunc("getSpread", &ParticleEmitter::getSpread);
298 em.addFunc("setSpeed", &ParticleEmitter::setSpeed);
299 em.addFunc("setLinearAcceleration", &ParticleEmitter::setLinearAcceleration);
300 em.addFunc("setRadialAcceleration", &ParticleEmitter::setRadialAcceleration);
301 em.addFunc("setTangentialAcceleration", &ParticleEmitter::setTangentialAcceleration);
302 em.addFunc("setEmissionArea", &ParticleEmitter::setEmissionArea);
303 em.addFunc("getEmissionAreaType", &ParticleEmitter::getEmissionAreaType);
304 em.addFunc("getEmissionAreaX", &ParticleEmitter::getEmissionAreaX);
305 em.addFunc("getEmissionAreaY", &ParticleEmitter::getEmissionAreaY);
306 em.addFunc("setParticleSize", &ParticleEmitter::setParticleSize);
307 em.addFunc("getParticleWidth", &ParticleEmitter::getParticleWidth);
308 em.addFunc("getParticleHeight", &ParticleEmitter::getParticleHeight);
309 em.addFunc("setSizes", &ParticleEmitter::setSizes);
310 em.addFunc("setSizeVariation", &ParticleEmitter::setSizeVariation);
311 em.addFunc("getSizeVariation", &ParticleEmitter::getSizeVariation);
312 em.addFunc("setSpin", &ParticleEmitter::setSpin);
313 em.addFunc("setStartRotation", &ParticleEmitter::setStartRotation);
314 em.addFunc("addBurst", &ParticleEmitter::addBurst);
315 em.addFunc("clearBursts", &ParticleEmitter::clearBursts);
316 em.addFunc("setPrewarm", &ParticleEmitter::setPrewarm);
317 em.addFunc("getPrewarmSeconds", &ParticleEmitter::getPrewarmSeconds);
318 em.addFunc("setGravity", &ParticleEmitter::setGravity);
319 em.addFunc("setDamping", &ParticleEmitter::setDamping);
320 em.addFunc("setLimitVelocity", &ParticleEmitter::setLimitVelocity);
321 em.addFunc("clearVelocityCurve", &ParticleEmitter::clearVelocityCurve);
322 em.addFunc("addVelocityCurvePoint", &ParticleEmitter::addVelocityCurvePoint);
323 em.addFunc("setInheritVelocity", &ParticleEmitter::setInheritVelocity);
324 em.addFunc("setSimulationSpace", &ParticleEmitter::setSimulationSpace);
325 em.addFunc("setNoise", &ParticleEmitter::setNoise);
326 em.addFunc("setGpuSimulation", &ParticleEmitter::setGpuSimulation);
327 em.addFunc("getGpuSimulation", &ParticleEmitter::getGpuSimulation);
328 em.addFunc("isGpuSimulationActive", &ParticleEmitter::isGpuSimulationActive);
329 em.addFunc("isGpuFeatureSetSupported", &ParticleEmitter::isGpuFeatureSetSupported);
330 em.addFunc("getSimulationBackend", &ParticleEmitter::getSimulationBackend);
331 em.addFunc("getGpuFallbackReason", &ParticleEmitter::getGpuFallbackReason);
332 em.addFunc("setFloatParameter", &ParticleEmitter::setFloatParameter);
333 em.addFunc("getFloatParameter", &ParticleEmitter::getFloatParameter);
334 em.addFunc("hasFloatParameter", &ParticleEmitter::hasFloatParameter);
335 em.addFunc("clearFloatParameters", &ParticleEmitter::clearFloatParameters);
336 em.addFunc("bindFloatParameter", &ParticleEmitter::bindFloatParameter);
337 em.addFunc("clearFloatParameterBindings", &ParticleEmitter::clearFloatParameterBindings);
338 em.addFunc("getResolvedParameterScale", &ParticleEmitter::getResolvedParameterScale);
339 em.addFunc("setPriority", &ParticleEmitter::setPriority);
340 em.addFunc("getPriority", &ParticleEmitter::getPriority);
341 em.addFunc("setMinimumQuality", &ParticleEmitter::setMinimumQuality);
342 em.addFunc("getMinimumQuality", &ParticleEmitter::getMinimumQuality);
343 em.addFunc("setCullingMode", &ParticleEmitter::setCullingMode);
344 em.addFunc("getCullingMode", &ParticleEmitter::getCullingMode);
345 em.addFunc("setCullDistance", &ParticleEmitter::setCullDistance);
346 em.addFunc("getCullDistance", &ParticleEmitter::getCullDistance);
347 em.addFunc("setMaxSpawnPerFrame", &ParticleEmitter::setMaxSpawnPerFrame);
348 em.addFunc("getMaxSpawnPerFrame", &ParticleEmitter::getMaxSpawnPerFrame);
349 em.addFunc("setCollision", &ParticleEmitter::setCollision);
350 em.addFunc("setCollisionBounds", &ParticleEmitter::setCollisionBounds);
351 em.addFunc("setWorldCollision", &ParticleEmitter::setWorldCollision);
352 em.addFunc("setMotionVectorPolicy", &ParticleEmitter::setMotionVectorPolicy);
353 em.addFunc("getMotionVectorPolicy", &ParticleEmitter::getMotionVectorPolicy);
354 em.addFunc("isMotionVectorActive", &ParticleEmitter::isMotionVectorActive);
355 em.addFunc("setRenderMode", &ParticleEmitter::setRenderMode);
356 em.addFunc("setRibbon", &ParticleEmitter::setRibbon);
357 em.addFunc("setSoftParticles", &ParticleEmitter::setSoftParticles);
358 em.addFunc("isSoftParticlesActive", &ParticleEmitter::isSoftParticlesActive);
359 em.addFunc("setRenderAxis", &ParticleEmitter::setRenderAxis);
360 em.addFunc("setSortMode", &ParticleEmitter::setSortMode);
361 em.addFunc("getSortMode", &ParticleEmitter::getSortMode);
362 em.addFunc("setMaterialMode", &ParticleEmitter::setMaterialMode);
363 em.addFunc("getMaterialMode", &ParticleEmitter::getMaterialMode);
364 em.addFunc("setDistortionStrength", &ParticleEmitter::setDistortionStrength);
365 em.addFunc("getDistortionStrength", &ParticleEmitter::getDistortionStrength);
366 em.addFunc("setOverflowMode", &ParticleEmitter::setOverflowMode);
367 em.addFunc("setMaxDeltaTime", &ParticleEmitter::setMaxDeltaTime);
368 em.addFunc("addSubEmitter", &ParticleEmitter::addSubEmitter);
369 em.addFunc("clearSubEmitters", &ParticleEmitter::clearSubEmitters);
370 em.addFunc("addForceField", &ParticleEmitter::addForceField);
371 em.addFunc("clearForceFields", &ParticleEmitter::clearForceFields);
372 em.addFunc("setShader", &ParticleEmitter::setShader);
373 em.addFunc("getShader", &ParticleEmitter::getShader);
374 em.addFunc("setLights", &ParticleEmitter::setLights);
375 em.addFunc("getLightsEnabled", &ParticleEmitter::getLightsEnabled);
376 em.addFunc("setBlendMode", &ParticleEmitter::setBlendMode);
377 em.addFunc("getBlendMode", &ParticleEmitter::getBlendMode);
378 em.addFunc("setFlipbook", &ParticleEmitter::setFlipbook);
379 em.addFunc("clearColorGradient", &ParticleEmitter::clearColorGradient);
380 em.addFunc("addColorStop", &ParticleEmitter::addColorStop);
381 em.addFunc("clearSizeCurve", &ParticleEmitter::clearSizeCurve);
382 em.addFunc("addSizeCurvePoint", &ParticleEmitter::addSizeCurvePoint);
383 em.addFunc("clearRotationCurve", &ParticleEmitter::clearRotationCurve);
384 em.addFunc("addRotationCurvePoint", &ParticleEmitter::addRotationCurvePoint);
385 em.addFunc("setColorStart", &ParticleEmitter::setColorStart);
386 em.addFunc("setColorEnd", &ParticleEmitter::setColorEnd);
387 em.addFunc("setTexture", &ParticleEmitter::setTexture);
388 em.addFunc("setNormalTexture", &ParticleEmitter::setNormalTexture);
389 em.addFunc("getNormalTexture", &ParticleEmitter::getNormalTexture);
390 em.addFunc("setCanvas", &ParticleEmitter::setCanvas);
391 em.addFunc("setCamera", &ParticleEmitter::setCamera);
392 em.addFunc("setLayer", &ParticleEmitter::setLayer);
393 em.addFunc("getLayer", &ParticleEmitter::getLayer);
394 em.addFunc("setVisible", &ParticleEmitter::setVisible);
395 em.addFunc("isVisible", &ParticleEmitter::isVisible);
396 em.addFunc("start", &ParticleEmitter::start);
397 em.addFunc("stop", &ParticleEmitter::stop);
398 em.addFunc("pause", &ParticleEmitter::pause);
399 em.addFunc("reset", &ParticleEmitter::reset);
400 em.addFunc("emit", &ParticleEmitter::emit);
401 em.addFunc("isActive", &ParticleEmitter::isActive);
402 em.addFunc("isPaused", &ParticleEmitter::isPaused);
403 em.addFunc("isStopped", &ParticleEmitter::isStopped);
404 em.addFunc("getCount", &ParticleEmitter::getCount);
405 em.addFunc("getBufferSize", &ParticleEmitter::getBufferSize);
406 em.addFunc("applyPreset", &ParticleEmitter::applyPreset);
407 em.addFunc("applyConfig", &ParticleEmitter::applyConfig);
408 em.addFunc("loadConfig", &ParticleEmitter::loadConfig);
409 em.addFunc("reloadConfig", &ParticleEmitter::reloadConfig);
410 em.addFunc("setAutoReload", &ParticleEmitter::setAutoReload);
411 em.addFunc("getAutoReload", &ParticleEmitter::getAutoReload);
412 em.addFunc("getConfigPath", &ParticleEmitter::getConfigPath);
413 em.addFunc("getConfigReloadObservation", &ParticleEmitter::getConfigReloadObservation);
414 em.addFunc("attachToBone", &ParticleEmitter::attachToBone);
415 em.addFunc("attachToBoneByName", &ParticleEmitter::attachToBoneByName);
416 em.addFunc("attachToSpineBone", &ParticleEmitter::attachToSpineBone);
417 em.addFunc("attachToSpineBoneByName", &ParticleEmitter::attachToSpineBoneByName);
418 em.addFunc("attachToSkeleton2D", &ParticleEmitter::attachToSkeleton2D);
419 em.addFunc("attachToSkeleton3D", &ParticleEmitter::attachToSkeleton3D);
420 em.addFunc("setAttachOffset", &ParticleEmitter::setAttachOffset);
421 em.addFunc("setAttachPlane", &ParticleEmitter::setAttachPlane);
422 em.addFunc("setAttachScale", &ParticleEmitter::setAttachScale);
423 em.addFunc("setFollowBoneRotation", &ParticleEmitter::setFollowBoneRotation);
424 em.addFunc("detach", &ParticleEmitter::detach);
425 em.addFunc("isAttached", &ParticleEmitter::isAttached);
426 em.addFunc("getAttachBone", &ParticleEmitter::getAttachBone);
427 em.addFunc("getAttachKind", &ParticleEmitter::getAttachKind);
428 em.addFunc("syncAttach", &ParticleEmitter::syncAttach);
429 em.addFunc("setSkinSource", &ParticleEmitter::setSkinSource);
430 em.addFunc("setSkinBoneFilter", &ParticleEmitter::setSkinBoneFilter);
431 em.addFunc("setSkinBoneFilterByName", &ParticleEmitter::setSkinBoneFilterByName);
432 em.addFunc("setSkinPlane", &ParticleEmitter::setSkinPlane);
433 em.addFunc("setSkinScale", &ParticleEmitter::setSkinScale);
434 em.addFunc("clearSkinSource", &ParticleEmitter::clearSkinSource);
435 em.addFunc("hasSkinSource", &ParticleEmitter::hasSkinSource);
436 em.addFunc("emitFromSkin", &ParticleEmitter::emitFromSkin);
437}
438
439void Particles::expose(ssq::Class& cls) {
440 cls.addFunc("getName", &Particles::getName);
441 cls.addFunc("newEmitter", &Particles::newEmitter);
442 cls.addFunc("newEmitterFromFile", &Particles::newEmitterFromFile);
443 cls.addFunc("update", &Particles::update);
444 cls.addFunc("render", &Particles::render);
445 cls.addFunc("pollConfigs", &Particles::pollConfigs);
446 cls.addFunc("getEmitterCount", &Particles::getEmitterCount);
447}
448
449} // namespace eve::particles
bool & active
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
glm::vec3 n
Definition Grass.cpp:63
std::string text
std::string name
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
OnnxTransferStats stats
Definition OnnxGpgpu.cpp:56
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
std::unique_ptr< ParticleEffect > effect
std::string path
Definition PlayHost.cpp:110
std::uint32_t seed
Definition PointSet.cpp:807
#define EV_PROFILE_MODULE(module, name)
Profile the enclosing scope, tagged with a module for grouping.
Definition Profile.h:140
glm::mat4 view
std::uint32_t count
The single Squirrel projection for common Result, Status and Value.
std::unique_ptr< TrailEmitter > emitter
float step
Definition TreeMesh.cpp:314
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 Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
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
bool has(const char *key) const
True when active.
Definition Json.cpp:334
int getInt(const char *key, int fallback=0) const
Returns the int.
Definition Json.cpp:422
Runtime instance of a versioned, multi-emitter particle effect asset.
bool hasFloatParameter(const std::string &name) const
Return true when the asset declares the parameter.
std::string getSourcePath() const
Return the source file path, or empty text for an in-memory asset.
ParticleEmitter * getEmitter(int index) const
Return an emitter layer by index, or null.
float getY() const
Return the group origin Y coordinate.
int getLayer() const
Return the group render-layer offset.
int getVersion() const
Return the asset schema version.
float getTimelineSeconds() const
Return the current effect-local timeline clock in seconds.
void pause()
Pause every emitter timeline and the effect clock.
void setPosition(float x, float y)
Set the group transform origin in world space.
void setScale(float scale)
Scale local emitter offsets.
void reset()
Reset every emitter timeline, clear particles, and rewind cues.
static ParticleEffect * fromFile(const std::string &path, std::string *error=nullptr)
Read, parse, and instantiate an effect asset.
void setVisible(bool visible)
Set visibility for every emitter layer.
static Result< void > advanceRegisteredTimelines(const SimulationStep &step)
Advance registered timelines from an injected scheduler step.
ParticleEmitter * getEmitterByName(const std::string &name) const
Return an emitter layer by name, or null.
bool isTimelinePlaying() const
Return true while the effect timeline is advancing.
void setLayer(int layer)
Offset all emitter render layers while preserving asset-local ordering.
float getRotation() const
Return the group rotation in radians.
bool isVisible() const
Return the group visibility state.
static ParticleEffect * fromText(const std::string &json, const std::string &sourcePath, std::string *error=nullptr)
Parse and instantiate an effect asset from JSON text.
void start()
Start every enabled emitter and the effect timeline clock.
void stop()
Stop every emitter timeline and the effect clock.
void setFloatParameter(const std::string &name, float value)
Set one gameplay parameter on every layer that declares or binds it.
int getEmitterCount() const
Return the number of named emitter layers.
float getFloatParameter(const std::string &name) const
Return an effect parameter value, or zero when unknown.
std::string getEmitterName(int index) const
Return a stable layer name by index, or empty text.
static void tickRegisteredTimelines(float dt)
Advance every effect that auto-registered a playing timeline.
void setRotation(float radians)
Rotate local offsets and emitter directions in radians.
float getX() const
Return the group origin X coordinate.
bool emit(const std::string &emitterName, int count)
Emit a manual burst from one named layer.
float getScale() const
Return the local-offset scale.
void updateTimeline(float dt)
Legacy seconds facade for timeline cues; consumes Result internally.
void clear()
Release every idle emitter and clear the pool.
ECS emitter entity. Script configures components; ParticleSimSystem / ParticleRenderSystem drive per-...
void applyPreset(const std::string &name)
Named preset: "spark" / "smoke" / "fire". Unknown → no-op.
std::string getSortMode()
Return the configured transparent ordering policy.
void addSizeCurvePoint(float t, float v)
void setDistortionStrength(float strengthPixels)
Set the maximum scene-color refraction offset in screen pixels.
void setFlipbook(int hframes, int vframes, float framesPerSecond=0.f, float randomStart=0.f)
void addColorStop(float t, float r, float g, float b, float a)
void setSkinBoneFilter(int skeletonBoneIndex, float minWeight=0.f)
void setLimitVelocity(float maxSpeed)
graphics::Texture * getNormalTexture()
Return the configured particle normal map.
void setRandomSeed(int seed)
Select a deterministic seed and disable automatic seeding.
void addVelocityCurvePoint(float t, float v)
void setFloatParameter(const std::string &name, float value)
Set a named gameplay/VFX float parameter without rebuilding the emitter.
void attachToSkeleton2D(eve::ik::Skeleton2D *skeleton, int boneId)
void attachToSkeleton3D(eve::ik::Skeleton3D *skeleton, int boneId)
std::string getMotionVectorPolicy()
Return the normalized motion-vector policy.
float getFloatParameter(const std::string &name, float fallback=0.f)
Return a named float parameter, or fallback when absent.
void setSpin(float minSpin, float maxSpin)
void setCullingMode(const std::string &mode)
Set offscreen simulation policy: automatic, pause, or always.
void setTexture(graphics::Texture *texture)
bool isGpuFeatureSetSupported()
Return whether the configured feature set can use resident GPU simulation.
std::string getSimulationBackend()
Return "gpu" for active resident simulation, otherwise "cpu".
void bindFloatParameter(const std::string &name, const std::string &target, float scale=1.f, float offset=0.f)
Bind a parameter to emission, speed, size, or playback scaling.
float getDistortionStrength()
Return the configured scene-color refraction offset in screen pixels.
void clearFloatParameters()
Remove all exposed float values.
void setPosition(float x, float y)
int getPriority()
Return the emitter budget priority.
void setRenderMode(const std::string &mode, float stretchFactor=1.f)
void attachToSpineBone(animation::SpineSkeleton *spine, int boneIndex)
void setNormalTexture(graphics::Texture *texture)
Set an optional tangent-space normal map for lit particles.
static ParticleEmitter * createEmitter(int bufferSize=1000)
void setPlaybackSpeed(float speed)
Scale simulation time; zero freezes playback.
void setMaterialMode(const std::string &mode)
Select particle shading: "unlit", "lit", or scene-color "distortion".
void setSkinBoneFilterByName(animation::AnimSkeleton *skeleton, const std::string &boneName, float minWeight=0.f)
bool loadConfig(const std::string &path)
void setCollisionBounds(bool enabled, float minX, float minY, float maxX, float maxY)
std::string getAttachKind()
"none" | "anim" | "spine" | "ik2d" | "ik3d"
bool isSoftParticlesActive()
True when soft particles have both a resident renderer and scene depth.
void setSkinPlane(const std::string &plane)
void setSizes(float startScale, float endScale)
void setRenderAxis(float degrees)
Set the fixed screen-space orientation used by render mode "axis".
void setRadialAcceleration(float minA, float maxA)
bool isGpuSimulationActive()
Return true after this emitter has migrated to a resident GPU backend.
void setSpeed(float minSpeed, float maxSpeed)
void setBlendMode(const std::string &mode)
void setMaxSpawnPerFrame(int count)
Cap automatic spawns per frame; zero is unlimited.
void addForceField(float x, float y, float radius, float strength, float falloff=1.f)
void setCanvas(graphics::Canvas *canvas)
void attachToBone(animation::AnimPose *pose, int boneIndex)
void setOverflowMode(const std::string &mode)
int getMaxSpawnPerFrame()
Return the automatic per-frame spawn cap.
void setStartRotation(float minDeg, float maxDeg)
void setCamera(graphics::Camera2D *camera)
float getResolvedParameterScale(const std::string &target)
Return the resolved non-negative multiplier for a supported target.
void setLinearAcceleration(float xmin, float ymin, float xmax, float ymax)
void emitFromSkin(int count)
Burst-emit count particles from the current skinned surface.
std::string getGpuFallbackReason()
Explain CPU fallback; empty means GPU active, "pending_activation" means eligible.
void syncAttach()
Sync Config.x/y (and direction) from the attached bone. Also called by ParticleSimSystem.
void setTangentialAcceleration(float minA, float maxA)
bool hasFloatParameter(const std::string &name)
Return whether a named float parameter exists.
bool applyConfig(const std::string &json)
bool getLooping()
Return whether the finite emitter timeline repeats.
void setSkinSource(animation::AnimSkin *skin, animation::AnimPose *pose)
void addRotationCurvePoint(float t, float v)
void setSoftParticles(bool enabled, float particleDepth=0.5f, float fadeDistance=0.05f)
Fade resident particles where they intersect sampled scene depth.
void setPriority(int priority)
Set budget order; higher values are processed first.
std::string getConfigReloadObservation() const
Return the explicit config reload observation state.
void setCollision(const std::string &mode, float radius=0.f, float restitution=0.6f, float lifetimeLoss=0.f)
void setMinimumQuality(int quality)
Set the minimum runtime quality tier in [0,3].
void addSubEmitter(ParticleEmitter *target, const std::string &trigger, float inheritVelocity=0.f)
void setColorEnd(float r, float g, float b, float a=1.f)
std::string getMaterialMode()
Return the normalized particle shading mode.
void setEmissionArea(const std::string &type, float x, float y)
void setColorStart(float r, float g, float b, float a=1.f)
bool getAutoRandomSeed()
Return whether start() generates a new random seed.
void setNoise(float strength, float frequency=1.f, float speed=1.f)
void setSortMode(const std::string &mode)
Select stable per-emitter transparent ordering.
void attachToSpineBoneByName(animation::SpineSkeleton *spine, const std::string &boneName)
float getCullDistance()
Return the camera distance cutoff.
void setAutoRandomSeed(bool enabled)
Generate a new random seed whenever start() is called.
float getEmissionRateOverDistance()
Return particles emitted per world unit travelled.
void setShader(graphics::Shader *shader)
void setMotionVectorPolicy(const std::string &policy)
Set motion-vector policy: none, velocity, or spawn_delta.
void setEmissionRateOverDistance(float rate)
Set particles emitted per world unit travelled; zero disables it.
void setFixedTimeStep(float seconds, int maxSubSteps=8)
Configure fixed stepping and the per-frame catch-up limit; zero seconds disables it.
float getPlaybackSpeed()
Return the simulation time multiplier.
void clearFloatParameterBindings()
Remove all parameter-to-runtime bindings.
void setSizeVariation(float variation)
int getMinimumQuality()
Return the minimum runtime quality tier.
void setLooping(bool looping)
Enable or disable repeating a finite emitter timeline.
void attachToBoneByName(animation::AnimPose *pose, animation::AnimSkeleton *skeleton, const std::string &boneName)
float getFixedTimeStep()
Return the fixed step in seconds, or zero for variable stepping.
void setCullDistance(float distance)
Set camera distance cutoff in world units; zero disables it.
void setSimulationSpace(const std::string &space)
void setAttachOffset(float x, float y, float z)
void setLights(bool enabled, float radius=120.f, float intensity=1.f, float r=1.f, float g=1.f, float b=1.f, int maxLights=4)
bool isMotionVectorActive()
True when a graphics path is actually writing motion vectors.
void setRibbon(float width=1.f, float minSegmentLength=1.f)
Configure connected ribbon rendering and switch to ribbon mode.
void setParticleLifetime(float minLife, float maxLife)
void addBurst(float time, int count)
void setAttachPlane(const std::string &plane)
int getRandomSeed()
Return the configured deterministic seed.
std::string getCullingMode()
Return the offscreen simulation policy.
void setInheritVelocity(float fraction)
void setGravity(float x, float y)
void setParticleSize(float width, float height)
static void render(graphics::Graphics *gfx)
Renders .
static eve::Result< void > advance(const eve::SimulationStep &step)
Advances emitters using one scheduler-owned deterministic step.
static void update(float dt)
Legacy seconds facade; conversion and Result consumption are explicit.
Particles module — factory + script binding. Per-frame: scheduler step → config reload → ParticleSimS...
Definition Particles.h:28
void setQualityLevel(int quality)
Select the runtime VFX quality tier in [0,3].
eve::Result< void > advance(const eve::SimulationStep &step)
Advance simulation from an injected scheduler step.
Definition Particles.cpp:88
int getLastGpuResidentEmitters() const
Return emitters using the resident GPU backend after the last update.
ParticleEmitter * newEmitter(int bufferSize=1000)
Creates a emitter. @ownership Caller deletes unless documented otherwise.
Definition Particles.cpp:45
int getQualityLevel() const
Return the current runtime VFX quality tier.
float getLastRenderMs() const
Return particle render-build and submission wall time in milliseconds.
ParticleEffect * newEffectFromFile(const std::string &path)
Create a versioned multi-emitter effect asset from a JSON file.
Definition Particles.cpp:75
void setBudget(int maxParticles, int maxSimulatedEmitters)
Set global soft particle and simulated-emitter budgets; zero is unlimited.
int getLastParticleCount() const
Return live particles after the last update.
int pollConfigs()
Explicit hot-reload poll; also invoked from update().
ParticleEmitter * newEmitterFromFile(const std::string &path)
Create emitter from JSON config file (reads optional "buffer").
Definition Particles.cpp:47
int getLastDroppedSpawns() const
Return automatic spawns dropped by budget during the last update.
~Particles() override
Particles.
Definition Particles.cpp:27
int getEmitterCount() const
Returns the emitter count.
int getLastRenderedParticles() const
Return particles submitted during the last render.
std::string getLastEffectError() const
Return the latest effect asset parse or load error.
Definition Particles.h:45
int getLastBudgetSkippedEmitters() const
Return emitters skipped by quality or capacity budgets.
float getLastSimulationMs() const
Return CPU simulation wall time in milliseconds.
int getLastSpawnedParticles() const
Return particles spawned during the last update.
void update(float dt)
Legacy seconds facade; invalid conversion/step is explicitly consumed.
Definition Particles.cpp:80
int getLastCulledEmitters() const
Return emitters skipped by culling during the last update.
void render(graphics::Graphics *gfx)
Renders .
int getMaxSimulatedEmitters() const
Return the per-frame simulated-emitter cap, or zero when unlimited.
int getMaxParticles() const
Return the global live-particle soft cap, or zero when unlimited.
int getLastGpuResidentParticles() const
Return the CPU lifetime estimate for resident GPU particles.
ParticleEffect * newEffectFromText(const std::string &json)
Create a versioned multi-emitter effect from JSON text.
Definition Particles.cpp:70
int getLastSimulatedEmitters() const
Return emitters simulated during the last update.
void clear()
Clear all borrowed candidates.
int count() const
Return candidate count including reserved index zero.
ParticleBudgetConfig & particleBudgetConfig()
Mutable process-wide scalability configuration.
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...
Result< void > applyGroundParticleCulling(ParticleEmitter *emitter, int playerTag, int visitorTag, bool entered, bool exited)
Apply one Pcg GroundParticlesCulling trigger event to a caller-owned emitter.
const ParticleFrameStats & particleFrameStats()
Statistics for the most recently processed particle frame.
Result< void > applyUnderwaterParticles(ParticleEmitter *ambience, ParticleEmitter *transition, bool active, bool transitionFx, bool entered, bool exited)
Apply Pcg underwater ambience and transition visibility to particle emitters.
void registerParticlesCapabilities()
Registers particles capabilities.
Result< void > applyUnderwaterSurfaceVfx(ParticleEmitter *surfaceVfx, bool active)
Apply Pcg's inverse underwater state to one surface weather or VFX emitter.
Result< int > shiftWorldSpaceParticles(ParticleEmitter *emitter, float shiftX, float shiftY)
Shift live world-space particles after a floating-origin rebase.
void unregisterParticlesAttackVfxExecutor()
Unregisters particles attack vfx executor.
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
One deterministic fixed-step emitted by SimulationClock.
Definition Time.h:158
int maxSimulatedEmitters
Maximum emitters simulated per frame; zero is unlimited.
int qualityLevel
Runtime VFX quality tier in [0,3].
int maxParticles
Soft cap for live particles across all emitters; zero is unlimited.