Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/core/src/particle/modules/CustomDataModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ export class CustomDataModule extends ParticleGeneratorModule {
this._gradients.delete(name);
}

/**
* Remove all custom data streams.
*/
clear(): void {
for (const name of this._curves.keys()) {
this.removeCurve(name);
}
for (const name of this._gradients.keys()) {
this.removeGradient(name);
}
}

/**
* @internal
*/
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/particle/modules/SubEmittersModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ export class SubEmittersModule extends ParticleGeneratorModule {
this._generator._setTransformFeedback();
}

/**
* Remove all sub-emitter slots.
*/
clear(): void {
if (this._subEmitters.length === 0) {
return;
}
this._subEmitters.length = 0;
this._generator._setTransformFeedback();
}

override get enabled(): boolean {
return this._enabled && this._generator._renderer.engine._hardwareRenderer.isWebGL2;
}
Expand Down
11 changes: 11 additions & 0 deletions tests/src/core/particle/CustomData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ describe("CustomDataModule", function () {
expect(customData.gradients.size).to.eq(0);
});

it("clear removes every stream", function () {
const customData = particleRenderer.generator.customData;
customData.addCurve("A", new ParticleCompositeCurve(1));
customData.addGradient("B", new ParticleCompositeGradient(new Color()));

customData.clear();

expect(customData.curves.size).to.eq(0);
expect(customData.gradients.size).to.eq(0);
});

it("removeCurve / removeGradient zero out shaderData uniforms", function () {
const customData = particleRenderer.generator.customData;
const shaderData = particleRenderer.shaderData;
Expand Down
17 changes: 17 additions & 0 deletions tests/src/core/particle/SubEmitter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ describe("SubEmitter", () => {
child.entity.destroy();
});

it("clear removes every sub-emitter slot", () => {
const parent = createParticleRenderer(engine, "Parent_Clear");
const child = createParticleRenderer(engine, "Child_Clear");

parent.generator.subEmitters.enabled = true;
parent.generator.subEmitters.addSubEmitter(child, ParticleSubEmitterType.Death);
expect((parent.generator as any)._useTransformFeedback).to.equal(true);

parent.generator.subEmitters.clear();

expect(parent.generator.subEmitters.subEmitters).to.have.length(0);
expect((parent.generator as any)._useTransformFeedback).to.equal(false);

parent.entity.destroy();
child.entity.destroy();
});

it("Sub system's own EmissionModule does not double-fire when sub-emit drives it", () => {
// The target renderer has its own t=0 burst AND is auto-playing on enable.
// The slot must NOT read that burst and re-fire — sub system's own emission
Expand Down
Loading