.. APEX IOFx Programmers Guide

============================
APEX IOFx Programmers Guide
============================

.. image:: images/ParticlesIcon.JPG
    :height: 150
    :width: 150

Introduction
============

Since the Particle emitter spawns the IOS and the IOFx actors, most programmer interaction with this
module focuses on the rendering side of the IOFX actors and RenderVolumes.


IOFX Semantics and Render Layouts
=================================

IOFX can output different render semantics (defined in **IofxRenderSemantic** enum)::

	POSITION     - 3D Position of particle
	COLOR        - Color of particle
	VELOCITY     - 3D Linear velocity of particle
	SCALE        - 2D or 3D Scale of particle
	LIFE_REMAIN  - Normalized life of particle = 1.0 (spawned) -> 0.0 (dead)
	DENSITY      - Particle density
	SUBTEXTURE   - Sub-texture index of particle (only Sprites)
	ORIENTATION  - Particle screen orientation = angle in radians (CCW in screen plane, only Sprites)
	ROTATION     - 3D particle rotation (only Meshes)
	USER_DATA    - User data - 32 bits (passed from APEX Emitter)

Each IOS actor operates in either mesh or sprite mode, meaning all of the IOFX assets used with a
single IOS actor will either all be mesh IOFX or sprite IOFX.  This detail is not exposed to the
artist.  APEX simply creates two IOS actors if the one IOS asset is used with both sprite and mesh
IOFX assets.

The IOS actor will create sprite buffers if it is operating in sprite mode, or mesh instance buffers
if it is operating in mesh mode.  Mesh instance buffers will have fixed semantics; POSITION, ROTATION, SCALE,
VELOCITY, LIFE_REMAIN, and DENSITY if the underlying IOS supplies a density value (currently only 3.x Particle IOSes
with SPH enabled, or BasicIOS or 3.x ParticleIOS when grid density is enabled).

Sprite buffers will have semantics for the sum of all IOFX assets currently in use with an IOS
actor.  This means the semantics output by an IOS actor may change as emitters are added to or
removed from a scene.  The next time the IOFX actors of that IOS are updated by the render thread,
the old sprite buffers will be released and new sprite buffers will be allocated with the new
semantics.  No rendering data is lost for any frames because the simulation output buffer always has
the correct semantics.

Sprite/Mesh render buffer represents an array of structures, like ordinary Vertex buffer in Computer Graphics.
Each structure of render buffer is defined by render layout (corresponding to Vertex Declaration in Computer Graphics),
consisting of set {semantic, format, offset} and stride.

All available Sprite semantics & format pairs are defined in **IofxSpriteRenderLayoutElement** enum::

	POSITION_FLOAT3
	COLOR_RGBA8
	COLOR_BGRA8
	COLOR_FLOAT4
	VELOCITY_FLOAT3
	SCALE_FLOAT2
	LIFE_REMAIN_FLOAT1
	DENSITY_FLOAT1
	SUBTEXTURE_FLOAT1
	ORIENTATION_FLOAT1
	USER_DATA_UINT1

All available Mesh semantics & format pairs are defined in **IofxMeshRenderLayoutElement** enum::

	POSITION_FLOAT3
	ROTATION_SCALE_FLOAT3x3
	POSE_FLOAT3x4
	VELOCITY_LIFE_FLOAT4
	DENSITY_FLOAT1
	COLOR_RGBA8
	COLOR_BGRA8
	COLOR_FLOAT4
	USER_DATA_UINT1

Render layout for Sprite/Mesh render buffer is defined in **IofxSpriteRenderLayout/IofxMeshRenderLayout**.
It has **offsets** array indexed by layout element, which encodes render buffer structure:
if offset value is -1 the corresponding layout element is not present, otherwise it's present in the structure at the provided offset.
Stride in render layout sets the whole size of the render buffer structure, and should be enough to store all presented layout elements with corresponding offsets.

Sprite render layout also supports render from surfaces.
In this case **IofxSpriteRenderLayout::surfaceCount** value is greater than zero
and **IofxSpriteRenderLayout::surfaceDescs** array describes surfaces
and **IofxSpriteRenderLayout::surfaceElements** array defines layout for each surface.

All available Sprite surface layouts are defined in **IofxSpriteRenderLayoutSurfaceElement** enum::

	POSITION_FLOAT4
	SCALE_ORIENT_SUBTEX_FLOAT4
	COLOR_RGBA8
	COLOR_BGRA8
	COLOR_FLOAT4

By default APEX creates Sprite/Mesh render layout based on the current set of semantics, so that all output semantics are presented in the render buffer.
User can create its own render layout by implementing **IofxRenderCallback** and overriding **getIofxSpriteRenderLayout** and **getIofxMeshRenderLayout** methods::

	class IofxRenderCallbackImpl : public IofxRenderCallback
	{
	    virtual bool getIofxSpriteRenderLayout(IofxSpriteRenderLayout& spriteRenderLayout, uint32_t spriteCount, uint32_t spriteSemanticsBitmap, RenderInteropFlags::Enum interopFlags)
	    {
	        //fill spriteRenderLayout here
	        return true;
	    }
	    virtual bool getIofxMeshRenderLayout(IofxMeshRenderLayout& meshRenderLayout, uint32_t meshCount, uint32_t meshSemanticsBitmap, RenderInteropFlags::Enum interopFlags)
	    {
	        //fill meshRenderLayout here
	        return true;
	    }
	};

Argument **spriteCount/meshCount** determines the 1D size of render buffer or 2D size of render surfaces.
Surface width should be power of two and >= 32. It is a good idea to determine surface width as
a square root of spriteCount ceiled to the nearest power of two.
Non-zero bits in the **spriteSemanticsBitmap/meshSemanticsBitmap** argument correspond to the semantics defined in the 
**IofxRenderSemantic** enum and describe which semantics are presented in IOFX output.
User are free to provide any set of layout elements in the render layout, even if the corresponding semantics are not present in IOFX output,
in this case IOFX outputs default values for these semantics.
The most common case is to create just one or a few fixed render layout(s) matching user particles shader(s) input.


Renderables
===========

Rendering is implemented using IOFX Renderable object. Each IOFX actor has its own IOFX Renderable
which stores all needed rendering information and can live after the original IOFX actor has been released.
Before accessing rendering data in IOFX Renderables, it should be updated once for each rendering frame by calling **ModuleIofx::prepareRenderables(const Scene&)**.
IOFX module has method **ModuleIofx::createIofxRenderableIterator(const Scene&)** to create iterator over all IOFX renderables.
The following code snipper illustrates how to use it all together::

	mIofxModule->prepareRenderables(*mApexScene);
	IofxRenderableIterator* iter = mIofxModule->createIofxRenderableIterator(*mApexScene);
	for (IofxRenderable* renderable = iter->getFirst(); renderable ; renderable = iter->getNext())
	{
	    if (visibilityCheck(renderable->getBounds())
	    {
	        if (const IofxSpriteRenderData* spriteRenderData = renderable->getSpriteRenderData())
	        {
	            renderSprites(spriteRenderData);
	        }
	        else
	        if (const IofxMeshRenderData* meshRenderData = renderable->getMeshRenderData())
	        {
	            renderMeshes(meshRenderData);
	        }
	    }
	    renderable->release();
	}
	iter->release();

There are two kinds of render data in IOFX Renderable, one is unique per Renderable and other is shared across several Renderables.
**IofxSpriteRenderData** has references to shared **IofxSpriteSharedRenderData**,
and **IofxMeshRenderData** has references to shared **IofxMeshSharedRenderData**.

Shared render data stores Sprite/Mesh Render Layout and Sprite/Mesh Render Buffer or Sprite Surfaces.
Unique render data stores Render Resource information (Sprite material or Mesh from IOFX asset)
and a range (defined by **startIndex** and **objectCount**) which points to the corresponding shared render buffer.

.. note::
	For convenience IOFX provides a way to associate user data with each renderable object:
	**IofxRenderable** interface is derived from **ApexInteface**, which has **userData** member,
	and also **IofxRenderCallback** has 3 trigger methods **onCreatedIofxRenderable**, **onUpdatedIofxRenderable** & **onReleasingIofxRenderable**, 
	which allows user to monitor renderable life time and updates, so that associated user data can be appropriately managed.


Shared Render Buffers & Surfaces
================================

Shared render buffers for both Sprites & Meshes are implemented using **UserRenderBuffer** interface,
and shared render surfaces for Sprites are implemented using **UserRenderSurface** interface.

To access render data on CPU for both render buffer & surface user have to use **map/unmap** methods.

By default APEX creates simple render buffer/surface internally based on given render layout, it just stores render data in CPU memory,
and user need to map render buffer/surface, then copy its content to user graphics resource, and finally unmap it.
This way is simple but not efficient, so APEX has another way for user to provide its own implementation for render buffer/surface,
by overriding **createRenderBuffer()** & **createRenderSurface()** methods in **IofxRenderCallback**.

For CPU access user need to implement **map/unmap** methods, and can directly map/unmap graphics buffer, eliminating data copy.

When IOS simulation is done on GPU there is still overhead to copy data from GPU (compute) to CPU and back from CPU to GPU (graphics), 
and to eliminate this overhead IOFX supports compute-graphics interop, when IOFX writes render data directly into user graphics buffer on GPU.
In order for interop to work, user have to implement **getCUDAgraphicsResource()** method in **UserRenderBuffer/UserRenderSurface**.

.. note::
	IOFX always writes output semantics with exact formats and offsets provided by user-defined or default render layout.
	So when user graphics buffer is directly mapped or used in interop-mode, its structure have to exactly match IOFX render layout!


Render Volumes
==============

RenderVolumes are the primary renderables of the APEX Particles pipeline.  A volume "owns" a
portion of world space, though ownership volumes are explictly allowed to overlap.  Volumes are
created via an IOFx module method::

	RenderVolume *createRenderVolume( const Scene& apexScene, const PxBounds3& b, PxU32 priority, bool allIofx );

The bounds argument defines the volume's ownership bounds.  The priority is used to break ties when
particles are within multiple volumes.  If a particle is within multiple volumes of the same
priority, it will prefer its previous volume when possible.  The allIofx flag determines whether a
volume will take ownership of all particles within its bounds, or only those particles emitted to
specific IOFX assets.

The game may create or release render volumes at any time, their insertions and deletions are queued
to make them thread-safe.  As volumes take ownership of particles, IOFX actors are instantiated on
demand to manage the render resources required to draw them.  This deferred IOFX actor creation may
be disabled via an IOFx module method: disableDeferredRenderableAllocation().

Calling getBounds() on the render volume will return the bounds of all the particles in that render
volume that frame.  It is usually much smaller than the volume's ownership bounds and should be used
for culling purposes.  Culling a render volume implicitly culls all of the IOFX actors it holds.

If a particle is not owned by any volume at the end of a simulation step, it is considered
"homeless" and is not rendered.  It will be deleted on the next simulation step.


Render Volumes Use Cases
------------------------

RenderVolumes provide a lot of flexibility in the way particle render resources are managed.
Here are just a few use cases.

Simple
~~~~~~

A game may allocate just a single RenderVolume with infinite bounds, zero priority, and
allIofx set to true.


Renderable Per Emitter
~~~~~~~~~~~~~~~~~~~~~~

If your game engine prefers to have one renderable per emitter, you may create an RenderVolume
for each APEX emitter and set the volume as the emitter's preferred volume::

	PxBounds3 b; b.setInfinite();
	vol = IofxModule->createRenderVolume( scene, infBounds, 0, true );
	emitterActor->setPreferredRenderVolume( vol );

Since particles stay within the volume they were injected until they encounter a higher priority
volume, each emitter's volume will hold all the particles emitted by this emitter.  If the game
wished, they could limit the size of the bounds and update its position to follow the emitter,
though this is not strictly necessary.  In general we prefer you allow our LOD system to delete
particles that are no longer "interesting", so only restrict the bounding volume if you truly
require all of the particles drawn by that volume to be spatially coherent.


Lighting Considerations
~~~~~~~~~~~~~~~~~~~~~~~

If your game engine incurs a serious cost penalty for every light that can see any particle in a
draw call, you can use volumes per light to collect together all the particles a particular light
can see.  When used in this way, you will typically have one "world" volume with zero priority and
priority one volumes for each light.

Beware that APEX volume migration was optimized for only a few volumes being active at a time (less
than a dozen).  So the game should try to create and delete volumes as game play progresses to
keep the total count low.


Special IOFX Renderers
~~~~~~~~~~~~~~~~~~~~~~

If your game engine has special rendering code for a small number of IOFX assets, you can create a
render volume with non-zero priority and allIofx = false.  You then explicitly set the IOFX assets
you do want the render volume to affect.  That volume will then only take ownership of (and create IOFX
actors for) particles created for those IOFX assets.

Note that you could achieve the same effect by querying the IOFX asset of each IOFX actor before rendering this actor.


Explicit Culling
~~~~~~~~~~~~~~~~

If your game has live "cut scenes" where the camera path is fixed and you want to maximize the
number of particles in front of the camera, you can create a single render volume that only covers
the visible world and allow all non-visible particles to become homeless and culled.  Be aware that
finite bounds volumes can create havoc with APEX emitters that try to keep an area of the world
covered with particles, aka the Air/Ground emitter.  It is best not to combine the two.


Render Volumes At Runtime
-------------------------

In order to render Render Volume user should lock actor list and iterate over it like this::

	if (visibilityCheck(mVolume->getBounds())
	{
	    uint32_t numIofxActors;
	    IofxActor* const* iofxActors = mVolume->lockIofxActorList(numIofxActors);
	    for (uint32_t i = 0 ; i < numIofxActors ; i++)
	    {
	        IofxRenderable* renderable = iofxActors[i]->acquireRenderableReference();
	        if (renderable)
	        {
	            if (visibilityCheck(renderable->getBounds())
	            {
	                if (const IofxSpriteRenderData* spriteRenderData = renderable->getSpriteRenderData())
	                {
	                    renderSprites(spriteRenderData);
	                }
	                else
	                if (const IofxMeshRenderData* meshRenderData = renderable->getMeshRenderData())
	                {
	                    renderMeshes(meshRenderData);
	                }
	            }
	            renderable->release();
	        }
	    }
	    mVolume->unlockIofxActorList();
	}


Errors and Warnings
===================

APEX IOFx outputs the following error and warning messages using the standard APEX error stream.
All are caused by authoring problems.

+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| ERROR CODE             | MESSAGE                                                                                                     | Explanation                                                                                              |
+========================+=============================================================================================================+==========================================================================================================+
| APEX_INVALID_PARAMETER | RenderMeshAsset with name \"%s\" not found.                                                                 | The specified mesh asset could not be found.                                                             |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | Unable to set Sprite Material Name (%s). Systems can be either Mesh or Sprite, but not both. This system is | Authoring problem. The asset is marked as both a sprite and a mesh.                                      |
|                        | already a Mesh.                                                                                             |                                                                                                          |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | Unable to set Mesh Material Name (%s). Systems can be either Mesh or Sprite, but not both. This system is   | Authoring problem. The asset is marked as both a sprite and a mesh.                                      |
|                        | already a Sprite.                                                                                           |                                                                                                          |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | Unable to set Mesh Material Weight (%d). Systems can be either Mesh or Sprite, but not both. This system is | Authoring problem. The asset is marked as both a sprite and a mesh.                                      |
|                        | already a Sprite.                                                                                           |                                                                                                          |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | Specifying modifiers before specifying the mesh or sprite asset is invalid                                  | Authoring problem.  A mesh or sprite must be specified to which the modifier is applied.                 |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | The specified modifier doesn't work on that system type (e.g. Sprite Modifier on a Mesh System or           | Authoring problem.  Only mesh modifiers can be used on meshes and only sprite modifiers can be applied   |
|                        | vice-versa).                                                                                                | to sprites.                                                                                              |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | The specified modifier doesn't work in that stage.                                                          | Authoring problem.                                                                                       |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| APEX_INVALID_OPERATION | position %d is greater than modifier stack size: %d                                                         | APEX internal error                                                                                      |
+------------------------+-------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
