123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "afx/arcaneFX.h"
- #include "scene/sceneRenderState.h"
- #include "T3D/fx/particleEmitter.h"
- #include "renderInstance/renderPassManager.h"
- #include "lighting/lightInfo.h"
- #include "lighting/lightManager.h"
- #include "afx/util/afxParticlePool.h"
- void afxParticlePool::prepRenderImage(SceneRenderState* state)
- {
- const LightInfo *sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
- pool_prepBatchRender(state->getRenderPass(), state->getCameraPosition(), sunlight->getAmbient());
- };
- void afxParticlePool::pool_prepBatchRender(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
- {
- if (emitters.empty())
- return;
- switch (mDataBlock->pool_type)
- {
- case afxParticlePoolData::POOL_TWOPASS :
- pool_renderObject_TwoPass(renderManager, camPos, ambientColor);
- break;
- case afxParticlePoolData::POOL_NORMAL :
- default:
- pool_renderObject_Normal(renderManager, camPos, ambientColor);
- }
- }
- void afxParticlePool::pool_renderObject_Normal(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
- {
- S32 n_parts = 0;
- for (S32 i = 0; i < emitters.size(); i++)
- n_parts += emitters[i]->n_parts;
- if (n_parts == 0)
- return;
- ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
-
- main_emitter_data->allocPrimBuffer(n_parts);
- orderedVector.clear();
- MatrixF modelview = GFX->getWorldMatrix();
- Point3F viewvec; modelview.getRow(1, &viewvec);
- for (U32 i=0; i < emitters.size(); i++)
- {
- // add each particle and a distance based sort key to orderedVector
- for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
- {
- orderedVector.increment();
- orderedVector.last().p = pp;
- orderedVector.last().k = mDot(pp->pos, viewvec);
- orderedVector.last().emitter = emitters[i];
- }
- }
- // qsort the list into far to near ordering
- dQsort(orderedVector.address(), orderedVector.size(), sizeof(SortParticlePool), cmpSortParticlePool);
- static Vector<GFXVertexPCT> tempBuff(2048);
- tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
- GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
- Point3F basePoints[4];
- basePoints[0] = Point3F(-1.0, 0.0, -1.0);
- basePoints[1] = Point3F( 1.0, 0.0, -1.0);
- basePoints[2] = Point3F( 1.0, 0.0, 1.0);
- basePoints[3] = Point3F(-1.0, 0.0, 1.0);
- MatrixF camView = GFX->getWorldMatrix();
- camView.transpose(); // inverse - this gets the particles facing camera
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- if (emitter->mDataBlock->orientParticles)
- emitter->setupOriented(particle, camPos, ambientColor, buffPtr);
- else
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- buffPtr+=4;
- }
- // create new VB if emitter size grows
- if( !mVertBuff || n_parts > mCurBuffSize )
- {
- mCurBuffSize = n_parts;
- mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
- }
- // lock and copy tempBuff to video RAM
- GFXVertexPCT *verts = mVertBuff.lock();
- dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
- mVertBuff.unlock();
- //MeshRenderInst *ri = gRenderInstManager->allocInst<MeshRenderInst>();
- ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
- ri->vertBuff = &mVertBuff;
- ri->primBuff = &main_emitter_data->primBuff;
- ri->translucentSort = true;
- ri->type = RenderPassManager::RIT_Particle;
- ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
- ri->defaultKey = (-sort_priority*100);
- ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
- GFX->getViewMatrix() *
- GFX->getWorldMatrix() );
- ri->count = n_parts;
- ri->blendStyle = main_emitter_data->blendStyle;
- // use first particle's texture unless there is an emitter texture to override it
- if (main_emitter_data->textureHandle)
- ri->diffuseTex = &*(main_emitter_data->textureHandle);
- else
- ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource());
- ri->softnessDistance = main_emitter_data->softnessDistance;
- // Sort by texture too.
- //ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff;
- renderManager->addInst( ri );
- }
- void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
- {
- S32 n_parts = 0;
- for (S32 i = 0; i < emitters.size(); i++)
- n_parts += emitters[i]->n_parts;
- if (n_parts == 0)
- return;
- ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
-
- main_emitter_data->allocPrimBuffer(n_parts);
- orderedVector.clear();
- F32 min_d=0.0f, max_d=0.0f;
- for (U32 i=0; i < emitters.size(); i++)
- {
- if (!emitters[i]->mDataBlock->pool_depth_fade || !emitters[i]->mDataBlock->pool_radial_fade)
- continue;
- // add particles to orderedVector and calc distance and min/max distance
- for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
- {
- F32 dist = (pp->pos-camPos).len();
- if (dist > max_d)
- max_d = dist;
- else if (dist < min_d)
- min_d = dist;
- orderedVector.increment();
- orderedVector.last().p = pp;
- orderedVector.last().k = dist;
- orderedVector.last().emitter = emitters[i];
- }
- }
- // Add remaining emitters particles to the orderedVector that do not participate in the
- // above depth computations:
- for (U32 i=0; i < emitters.size(); i++)
- {
- if (emitters[i]->mDataBlock->pool_depth_fade || emitters[i]->mDataBlock->pool_radial_fade)
- continue;
- for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
- {
- orderedVector.increment();
- orderedVector.last().p = pp;
- orderedVector.last().k = 0; // no need to compute depth here
- orderedVector.last().emitter = emitters[i];
- }
- }
- static Vector<GFXVertexPCT> tempBuff(2048);
- tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
- GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
- Point3F basePoints[4];
- basePoints[0] = Point3F(-1.0, 0.0, -1.0);
- basePoints[1] = Point3F( 1.0, 0.0, -1.0);
- basePoints[2] = Point3F( 1.0, 0.0, 1.0);
- basePoints[3] = Point3F(-1.0, 0.0, 1.0);
- MatrixF camView = GFX->getWorldMatrix();
- camView.transpose(); // inverse - this gets the particles facing camera
- //~~~~~~~~~~~~~~~~~~~~//
- Point3F bbox_center; mObjBox.getCenter(&bbox_center);
- F32 d_range = max_d - min_d;
- bool d_safe = (d_range>0.0001);
- F32 d_half = min_d + (d_range*0.5f);
- //~~~~~~~~~~~~~~~~~~~~//
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- LinearColorF color_save = particle->color;
- particle->color.set(mDataBlock->base_color.red, mDataBlock->base_color.green, mDataBlock->base_color.blue, mDataBlock->base_color.alpha*particle->color.alpha);
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- // create new VB if emitter size grows
- if( !mVertBuff || n_parts > mCurBuffSize )
- {
- mCurBuffSize = n_parts;
- mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
- }
- // lock and copy tempBuff to video RAM
- GFXVertexPCT *verts = mVertBuff.lock();
- dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
- mVertBuff.unlock();
- ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
- ri->vertBuff = &mVertBuff;
- ri->primBuff = &main_emitter_data->primBuff;
- ri->translucentSort = true;
- ri->type = RenderPassManager::RIT_Particle;
- ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
- ri->defaultKey = (-sort_priority*100);
- ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
- GFX->getViewMatrix() *
- GFX->getWorldMatrix() );
- ri->count = n_parts;
- ri->blendStyle = ParticleRenderInst::BlendNormal;
- // use first particle's texture unless there is an emitter texture to override it
- //if (main_emitter_data->textureHandle)
- // ri->diffuseTex = &*(main_emitter_data->textureHandle);
- //else
- ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureExtResource());
- F32 save_sort_dist = ri->sortDistSq;
- ri->softnessDistance = main_emitter_data->softnessDistance;
- renderManager->addInst( ri );
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
- // 2nd-pass
- buffPtr = tempBuff.address();
- bbox_center.z = mObjBox.minExtents.z;
- F32 max_radius = (max_d-min_d)*0.5f;
- // gather fade settings
- bool do_mixed_fades = false;
- bool do_radial_fades = (emitters[0]->mDataBlock->pool_radial_fade && (max_radius>0.0001f));
- bool do_depth_fades = (emitters[0]->mDataBlock->pool_depth_fade && d_safe);
- for (U32 i = 1; i < emitters.size(); i++)
- {
- if ( (do_radial_fades != (emitters[i]->mDataBlock->pool_radial_fade && (max_radius>0.0001f))) ||
- (do_depth_fades != (emitters[i]->mDataBlock->pool_depth_fade && d_safe)))
- {
- do_mixed_fades = true;
- break;
- }
- }
- if (do_mixed_fades)
- {
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- F32 bf = 1.0; // blend factor
- // blend factor due to radius
- if (emitter->mDataBlock->pool_radial_fade && (max_radius>0.0001f))
- {
- F32 p_radius = (particle->pos-bbox_center).len();
- F32 bf_radius = p_radius/max_radius;
- if (bf_radius>1.0f) bf_radius = 1.0f;
- bf *= bf_radius*bf_radius; // quadratic for faster falloff
- }
- // blend factor, depth based
- if (emitter->mDataBlock->pool_depth_fade && d_safe && (orderedVector[i].k > d_half))
- {
- F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
- bf *= bf_depth;
- }
- // overall blend factor weight
- bf *= mDataBlock->blend_weight;
- LinearColorF color_save = particle->color;
- particle->color = particle->color*bf;
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- }
- else if (do_radial_fades && do_depth_fades)
- {
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- F32 bf = 1.0; // blend factor
- // blend factor due to radius
- F32 p_radius = (particle->pos-bbox_center).len();
- F32 bf_radius = p_radius/max_radius;
- if (bf_radius>1.0f) bf_radius = 1.0f;
- bf *= bf_radius*bf_radius; // quadratic for faster falloff
- // blend factor, depth based
- if (orderedVector[i].k > d_half)
- {
- F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
- bf *= bf_depth;
- }
- // overall blend factor weight
- bf *= mDataBlock->blend_weight;
- LinearColorF color_save = particle->color;
- particle->color = particle->color*bf;
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- }
- else if (do_radial_fades) // && !do_depth_fades
- {
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- F32 bf = 1.0; // blend factor
- // blend factor due to radius
- F32 p_radius = (particle->pos-bbox_center).len();
- F32 bf_radius = p_radius/max_radius;
- if (bf_radius>1.0f) bf_radius = 1.0f;
- bf *= bf_radius*bf_radius; // quadratic for faster falloff
- // overall blend factor weight
- bf *= mDataBlock->blend_weight;
- LinearColorF color_save = particle->color;
- particle->color = particle->color*bf;
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- }
- else if (do_depth_fades) // && !do_radial_fades
- {
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- F32 bf = 1.0; // blend factor
- // blend factor, depth based
- if (orderedVector[i].k > d_half)
- {
- F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
- bf *= bf_depth;
- }
- // overall blend factor weight
- bf *= mDataBlock->blend_weight;
- LinearColorF color_save = particle->color;
- particle->color = particle->color*bf;
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- }
- else // (no fades)
- {
- for (U32 i = 0; i < orderedVector.size(); i++)
- {
- Particle* particle = orderedVector[i].p;
- ParticleEmitter* emitter = orderedVector[i].emitter;
- F32 bf = mDataBlock->blend_weight; // blend factor
- LinearColorF color_save = particle->color;
- particle->color = particle->color*bf;
- emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
- particle->color = color_save;
- buffPtr+=4;
- }
- }
- // create new VB if emitter size grows
- if( !mVertBuff2 || n_parts > mCurBuffSize2 )
- {
- mCurBuffSize2 = n_parts;
- mVertBuff2.set(GFX, n_parts*4, GFXBufferTypeDynamic);
- }
- // lock and copy tempBuff to video RAM
- verts = mVertBuff2.lock();
- dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
- mVertBuff2.unlock();
- ri = renderManager->allocInst<ParticleRenderInst>();
- ri->vertBuff = &mVertBuff2;
- ri->primBuff = &main_emitter_data->primBuff;
- ri->translucentSort = true;
- ri->type = RenderPassManager::RIT_Particle;
- ri->sortDistSq = save_sort_dist;
- ri->defaultKey = (-sort_priority*100) + 1;
- ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
- GFX->getViewMatrix() *
- GFX->getWorldMatrix() );
- ri->count = n_parts;
- ri->blendStyle = ParticleRenderInst::BlendAdditive;
- // use first particle's texture unless there is an emitter texture to override it
- if (main_emitter_data->textureHandle)
- ri->diffuseTex = &*(main_emitter_data->textureHandle);
- else
- ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource());
- ri->softnessDistance = main_emitter_data->softnessDistance;
- renderManager->addInst( ri );
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|