pret / pokeplatinum

Decompilation of Pokémon Platinum
198 stars 63 forks source link

Document SPL #259

Closed Fexty12573 closed 3 weeks ago

Fexty12573 commented 2 months ago

This PR documents the particle system library used by the game.

Here is a quick breakdown of how the library works/how to use it:

1. Creating a Manager

To do anything with the library an instance of SPLManager must first be created. When creating one you specify a maximum number of simultaneous emitters and particles that the manager is able to create, as well as a range of polygon IDs to use:

SPLManager *mgr = SPLManager_New(
    MyAllocFunc, // Memory allocation function that the manager will use
    10, // Maximum 10 emitters
    100, // Maximum 100 particles simultaneously
    5, // Fixed polygon ID
    6, // Mininum polygon ID
    63 // Maximum polygon ID
)

2. Loading Resources

Next the manager must be provided with data that defines what particles look like and how they behave. Usually this data comes from a file, but technically it can come from anywhere. The files are a custom binary format with the .spa extension. One such file can contain multiple resources. A resource defines parameters for an emitter, which then passes those parameters to particles it creates.

void *data = NARC_AllocAndReadWholeMemberByIndexPair(...);
SPLManager_LoadResources(mgr, data);

// Both of these functions also have an Ex variant which allows you to specify a custom VRAM allocator
SPLManager_UploadTextures(mgr); // Uploads the textures to VRAM
SPLManager_UploadPalettes(mgr); // Uploads the palettes to VRAM

// Note that the data must be kept alive until the manager is destroyed

3. Creating Emitters

Now that the resources are loaded, emitters can be created. Each emitter is associated with a resource.

VecFx32 pos = {0, 0, 0}; // Initial position of the emitter
SPLEmitter *emitter = SPLManager_CreateEmitter(mgr, 0, &pos);

Note that some emitters are self-maintaining, meaning they will automatically destroy themselves when they are done. Others are not and must be manually destroyed. In the case of the former, SPLManager_CreateEmitter (and similar functions) will return NULL.

If you still want to obtain a reference to a self-maintaining emitter, you can use SPLManager_CreateEmitterWithCallback[Ex] instead. This function will call a callback function after the emitter has been initialized, passing the emitter as an argument.

4. Updating Emitters

To update the emitters, call SPLManager_Update:

SPLManager_Update(mgr);

This function should be called every frame. Also note that typically drawing is done before updating.

5. Drawing

To draw the particles, call SPLManager_Draw:

NNS_G3dGlbFlush(); // Flush the 3D pipeline
const MtxFx43 *view = NNS_G3dGlbGetCameraMtx();
SPLManager_Draw(mgr, view);

Of course, you can pass any view matrix you want.

6. Destroying Emitters

For emitters that are not self-maintaining, you must manually destroy them when they are no longer needed:

SPLManager_DeleteEmitter(mgr, emitter);

Manually Emitting Particles

Normally, emitters will emit particles automatically. However, you can manually make an emitter emit particles:

SPLManager_Emit(mgr, emitter);

// Or you can specify a position

VecFx32 pos = {0, 0, 0}; // Position of the emitter
SPLManager_EmitAt(mgr, emitter, &pos);

Particle Capabilities

All particles have a set of common parameters:

These should be self explanatory. However, there are additional behaviors that can be added to particles. Or rather, these behaviors can be added to emitters, which then pass them to particles. These behaviors include:

Without any of these behaviors, particles will simply move in a straight line until they die. Their velocity is based on their initialization parameters. Behaviors are specified in the resource file.

Additionally, particles can also have the following parameters animated:

Emitter Capabilities

Emitters are also not just static entities. They can move around and keep that of their own velocity. However, the velocity must be set manually. Emitter velocity directly affects the velocity of the particles it emits.

Emitters can also have a wide range of emission types:

Child Particles

Particles can also spawn child particles. This behavior is restricted to a single level of recursion. Child particles also have less functionality than their parents. They are limited to Scale and Alpha animations, and they cannot have their own behaviors. Though they can optionally inherit the parent's behaviors.

To make a particle spawn child particles, the resource it stems from must have a Child resource defined.