Skip to content

ENG2-P8-02: Particles: FFI exposure of the existing 3D emitter + new 2D emitter on the sprite core #800

Description

@aram-devdocs

Parent

  • Program: ENG2 — GoudEngine v2 Rebuild (see the pinned master tracking issue)
  • Phase / Milestone: Phase 8 — Capability Gaps (eng2-p8-capabilities)
  • Batch / Group: Batch 8.1 — Highest-demand capabilities, Group B
  • Runbook spec: docs/src/runbook/phases/phase-8.md (committed with the roadmap)

Summary

Expose the already-implemented 3D ParticleEmitter through a new ffi/renderer3d/particles.rs module and all 10 SDKs, and add a new 2D particle emitter built on the Phase 6 instanced sprite core.

Architecture Context

Layer: Layer 4 (Engine, libs/graphics/renderer3d/ — 2D emitter logic reuses the sprite core) for the 2D emitter internals; Layer 5 (FFI) for both new export surfaces.
Modules/types touched:

  • goud_engine/src/ffi/renderer3d/particles.rs (new) — wraps the existing Renderer3D::create_particle_emitter / set_particle_emitter_position / remove_particle_emitter engine API.
  • goud_engine/src/libs/graphics/renderer2d/ — new 2D particle emitter type, driven by the Phase 6 instanced sprite core's per-instance buffer rather than a bespoke draw path.
  • goud_engine/src/ffi/renderer/ — new FFI exports for the 2D emitter (naming to mirror the 3D particles.rs module).

Boundary constraints (only those that apply):

  • Raw GPU calls stay in libs/graphics/backend/ — the 2D emitter must go through the sprite core's existing instance-buffer upload path, not a new wgpu:: call site.
  • FFI exports: #[no_mangle] extern "C", #[repr(C)], null checks, // SAFETY: comments.

Pattern to follow: goud_engine/src/ffi/spatial_grid/mod.rs handle-registry pattern for exposing engine-internal u32 IDs safely across FFI (the 3D emitter already returns opaque u32 IDs from create_particle_emitter — mirror how existing FFI modules validate and scope such IDs per context). For the 2D emitter, follow whatever per-instance buffer API Phase 6's ENG2-P6-02 sprite core exposes internally — do not build a second CPU-side vertex-expansion path.

Scope

  • ffi/renderer3d/particles.rs: #[no_mangle] wrappers for create/configure/set-position/remove on the existing Renderer3D particle emitter API (core_primitives.rs:133-172).
  • New 2D particle emitter type in libs/graphics/renderer2d/, spawning/aging/killing particles on the CPU and feeding positions/colors/sizes into the sprite core's per-instance buffer (per ENG2-P6-02).
  • FFI exports for the 2D emitter (create/configure/position/remove), structurally parallel to the 3D surface.
  • Tests: spec test + unit tests for particle lifecycle (spawn rate, aging, death at lifetime) for both 2D and 3D paths.
  • Docs/rules updates: .agents/rules/graphics-patterns.md gains a short particle-system note once both paths exist.

Acceptance Criteria

  • 3D particle FFI surface is callable end-to-end from at least one SDK smoke test (create emitter, position it, observe particles render, remove it).
  • 2D particle emitter renders through the sprite core's instanced path (verified: no per-particle immediate-mode draw calls).
  • FFI particle exports have wrappers in all 10 SDKs and pass python codegen/validate_coverage.py.
  • Docs: an mdBook page documents both particle FFI surfaces with example usage.
  • cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings clean; cargo test green; ./codegen.sh && git diff --exit-code (drift gate)

Breaking Change & Throne Follow-up

None — additive/internal (new FFI exports only; no existing exports change).

Blocked By

ENG2-P6-02 (instanced sprite core — the new 2D particle emitter must render through the unified sprite core's per-instance buffer, not a fifth parallel 2D rendering path).

Files Likely Touched

  • New: goud_engine/src/ffi/renderer3d/particles.rs, goud_engine/src/libs/graphics/renderer2d/particles.rs (or equivalent), new 2D particle FFI file under goud_engine/src/ffi/renderer/
  • Generated: SDK bindings under sdks/*/ for both particle FFI surfaces
  • Modified: goud_engine/src/ffi/renderer3d/mod.rs (register particles module), codegen/goud_sdk.schema.json

Agent Notes

  • ParticleEmitterConfig (goud_engine/src/libs/graphics/renderer3d/types.rs:107-129), Particle (types.rs:267-273), and ParticleEmitter (types.rs:276-283) are fully implemented and already rendered every frame: render_instanced_and_particles (libs/graphics/renderer3d/render_instanced.rs:13) checks self.particle_emitters at lines 23 and 72 and draws them via the instanced path. This is real, working engine functionality, not a stub.
  • The engine-level public API already exists and needs no new engine logic for the 3D half of this issue: Renderer3D::create_particle_emitter (libs/graphics/renderer3d/core_primitives.rs:133-142), set_particle_emitter_position (core_primitives.rs:157-164), and remove_particle_emitter (core_primitives.rs:167-172) are all pub fn on Renderer3D. The work here is exclusively adding the FFI wrapper layer + SDK codegen — confirmed by listing goud_engine/src/ffi/renderer3d/: it contains animation.rs, camera.rs, environment/, lighting.rs, materials.rs, mod.rs, model/, postprocess.rs, primitives.rs, scene.rs, skinned.rs, state.rs and no particles.rs.
  • Note the internal types (ParticleEmitterConfig, Particle, ParticleEmitter) are scoped pub(in crate::libs::graphics::renderer3d) — FFI code cannot touch them directly and must go exclusively through the Renderer3D public methods above (which take/return plain u32 IDs and primitive floats already, so no new #[repr(C)] struct should be needed for the 3D half).
  • 2D has no particle system at all today; it must be built new on top of whatever the Phase 6 sprite core (ENG2-P6-02) exposes for per-instance buffer updates — do not build it against the pre-Phase-6 immediate or rebuild-per-call sprite paths, since those are slated for deletion in ENG2-P6-03.

Verification

cargo check && cargo fmt --all -- --check && cargo clippy -- -D warnings
cargo test
./codegen.sh && git diff --exit-code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions