This demonstrates how to evaluate a particle source for it's particles. By default, only position, transform and ID are evaluated, however it could easily be extended to support other types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This demonstrates how to evaluate a particle source for it's particles. | |
* By default, only position, transform and ID are evaluated, however it | |
* could easily be extended to support other types. | |
* | |
* To evaluate particles, you must provide a TriangleSoup to the Tableau, | |
* allowing it populate your soup with the particle data. This is very | |
* similar to reading surfaces, but we only care about vertex data, not | |
* polygons. | |
* | |
* To use this example, first query your particle source item for the | |
* ILxParticleItem interface, and in your Modifier Allocate function, call | |
* the Prepare method on the ParticleItem to allocate the channels it needs | |
* to evaluate. In your modifier Evaluate method, call the Evaluate method | |
* on the ParticleItem, passing in the index returned from the Prepare method. | |
* This should return a TableauSurface, which can be queried for particles | |
* by passing it and a vector of Particles into the Soup Sample method. | |
*/ | |
#include <lxsdk/lx_particle.hpp> | |
#include <lxsdk/lx_tableau.hpp> | |
#include <lxsdk/lx_vector.hpp> | |
struct Particle | |
{ | |
Particle () : index (0.0) | |
{ | |
LXx_VCLR (pos); | |
lx::MatrixIdent (xfrm); | |
} | |
float index; | |
LXtFVector pos; | |
LXtMatrix xfrm; | |
}; | |
enum PART_FEATURE | |
{ | |
PART_FEATURE_POS, | |
PART_FEATURE_XFRM, | |
PART_FEATURE_ID, | |
PART_FEATURE_MAX | |
}; | |
class Soup : | |
public CLxImpl_TriangleSoup, | |
public CLxSingletonPolymorph | |
{ | |
public: | |
LXxSINGLETON_METHOD; | |
Soup () | |
{ | |
AddInterface (new CLxIfc_TriangleSoup <Soup>); | |
mEnabled[PART_FEATURE_POS] = false; | |
mEnabled[PART_FEATURE_XFRM] = false; | |
mEnabled[PART_FEATURE_ID] = false; | |
mBase = 0; | |
mCurrent = 0; | |
/* | |
* Create a new TableauVertex, then add the particle | |
* features we're interested in reading. The features | |
* are returned in a single float array, so we also | |
* store the offset to lookup the values in the vector. | |
*/ | |
if (mTblSvc.NewVertex (mTblVrx)) | |
{ | |
unsigned int i = 0, count = 0; | |
if (LXx_OK (mTblVrx.AddFeature (LXiTBLX_PARTICLES, LXsTBLX_PARTICLE_POS, &i))) | |
{ | |
mEnabled[PART_FEATURE_POS] = true; | |
mOffsets[PART_FEATURE_POS] = count; | |
count += 3; | |
} | |
if (LXx_OK (mTblVrx.AddFeature (LXiTBLX_PARTICLES, LXsTBLX_PARTICLE_XFRM, &i))) | |
{ | |
mEnabled[PART_FEATURE_XFRM] = true; | |
mOffsets[PART_FEATURE_XFRM] = count; | |
count += 9; | |
} | |
if (LXx_OK (mTblVrx.AddFeature (LXiTBLX_PARTICLES, LXsTBLX_PARTICLE_ID, &i))) | |
{ | |
mEnabled[PART_FEATURE_ID] = true; | |
mOffsets[PART_FEATURE_ID] = count; | |
count += 1; | |
} | |
} | |
} | |
LXxO_TriangleSoup_Segment | |
{ | |
/* | |
* Segment is called at the start of each segment. | |
* We only care about reading points/particles, so | |
* we skip any other type. | |
*/ | |
mCurrent = mParticles->size (); | |
mBase = mCurrent; | |
return (type == LXiTBLX_SEG_POINT) ? LXe_TRUE : LXe_FALSE; | |
} | |
LXxO_TriangleSoup_Vertex | |
{ | |
/* | |
* Read the particle and add it to the vector. We | |
* only read the features that are enabled, just in | |
* case a particle source doesn't provide a specific | |
* feature. | |
*/ | |
if (!mParticles) | |
return LXe_FAILED; | |
Particle particle; | |
if (mEnabled[PART_FEATURE_POS]) | |
{ | |
particle.position[0] = vertex[mOffsets[PART_FEATURE_POS]]; | |
particle.position[1] = vertex[mOffsets[PART_FEATURE_POS] + 1]; | |
particle.position[2] = vertex[mOffsets[PART_FEATURE_POS] + 2]; | |
} | |
if (mEnabled[PART_FEATURE_XFRM]) | |
{ | |
particle.xfrm[0][0] = vertex[mOffsets[PART_FEATURE_XFRM]]; | |
particle.xfrm[0][1] = vertex[mOffsets[PART_FEATURE_XFRM] + 1]; | |
particle.xfrm[0][2] = vertex[mOffsets[PART_FEATURE_XFRM] + 2]; | |
particle.xfrm[1][0] = vertex[mOffsets[PART_FEATURE_XFRM] + 3]; | |
particle.xfrm[1][1] = vertex[mOffsets[PART_FEATURE_XFRM] + 4]; | |
particle.xfrm[1][2] = vertex[mOffsets[PART_FEATURE_XFRM] + 5]; | |
particle.xfrm[2][0] = vertex[mOffsets[PART_FEATURE_XFRM] + 6]; | |
particle.xfrm[2][1] = vertex[mOffsets[PART_FEATURE_XFRM] + 7]; | |
particle.xfrm[2][2] = vertex[mOffsets[PART_FEATURE_XFRM] + 8]; | |
} | |
if (mEnabled[PART_FEATURE_ID]) | |
particle.index = vertex[mOffsets[PART_FEATURE_ID]]; | |
mParticles->push_back (particle); | |
*index = (mCurrent++) - mBase; | |
return LXe_OK; | |
} | |
LXxO_TriangleSoup_Polygon | |
{ | |
/* | |
* We don't care about partices, but we have to | |
* implement this function, otherwise things fail. | |
*/ | |
return LXe_OK; | |
} | |
void | |
Sample ( | |
CLxUser_TableauSurface &surface, | |
std::vector <Particle> *particles) | |
{ | |
if (!surface.test () || !particles) | |
return; | |
mParticles = particles; | |
/* | |
* Sample the TableauSurface using our Soup object. | |
*/ | |
if (LXx_OK (surface.SetVertex (mTblVrx))) | |
surface.Sample (NULL, -1.0, *this); | |
mParticles = NULL; | |
} | |
private: | |
CLxUser_TableauService mTblSvc; | |
CLxLoc_TableauVertex mTblVrx; | |
std::vector <Particle> *mParticles; | |
bool mEnabled[PART_FEATURE_MAX]; | |
unsigned int mOffsets[PART_FEATURE_MAX]; | |
unsigned int mBase, mCurrent; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment