afxParticlePool_T3D.cpp
Engine/source/afx/util/afxParticlePool_T3D.cpp
Detailed Description
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include "afx/arcaneFX.h" 28 29#include "scene/sceneRenderState.h" 30#include "T3D/fx/particleEmitter.h" 31#include "renderInstance/renderPassManager.h" 32#include "lighting/lightInfo.h" 33#include "lighting/lightManager.h" 34 35#include "afx/util/afxParticlePool.h" 36 37void afxParticlePool::prepRenderImage(SceneRenderState* state) 38{ 39 const LightInfo *sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); 40 pool_prepBatchRender(state->getRenderPass(), state->getCameraPosition(), sunlight->getAmbient()); 41}; 42 43void afxParticlePool::pool_prepBatchRender(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor) 44{ 45 if (emitters.empty()) 46 return; 47 48 switch (mDataBlock->pool_type) 49 { 50 case afxParticlePoolData::POOL_TWOPASS : 51 pool_renderObject_TwoPass(renderManager, camPos, ambientColor); 52 break; 53 case afxParticlePoolData::POOL_NORMAL : 54 default: 55 pool_renderObject_Normal(renderManager, camPos, ambientColor); 56 } 57} 58 59void afxParticlePool::pool_renderObject_Normal(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor) 60{ 61 S32 n_parts = 0; 62 for (S32 i = 0; i < emitters.size(); i++) 63 n_parts += emitters[i]->n_parts; 64 65 if (n_parts == 0) 66 return; 67 68 ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock; 69 70 main_emitter_data->allocPrimBuffer(n_parts); 71 72 orderedVector.clear(); 73 74 MatrixF modelview = GFX->getWorldMatrix(); 75 Point3F viewvec; modelview.getRow(1, &viewvec); 76 77 for (U32 i=0; i < emitters.size(); i++) 78 { 79 // add each particle and a distance based sort key to orderedVector 80 for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next) 81 { 82 orderedVector.increment(); 83 orderedVector.last().p = pp; 84 orderedVector.last().k = mDot(pp->pos, viewvec); 85 orderedVector.last().emitter = emitters[i]; 86 } 87 } 88 89 // qsort the list into far to near ordering 90 dQsort(orderedVector.address(), orderedVector.size(), sizeof(SortParticlePool), cmpSortParticlePool); 91 92 static Vector<GFXVertexPCT> tempBuff(2048); 93 tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough 94 GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster) 95 96 Point3F basePoints[4]; 97 basePoints[0] = Point3F(-1.0, 0.0, -1.0); 98 basePoints[1] = Point3F( 1.0, 0.0, -1.0); 99 basePoints[2] = Point3F( 1.0, 0.0, 1.0); 100 basePoints[3] = Point3F(-1.0, 0.0, 1.0); 101 102 MatrixF camView = GFX->getWorldMatrix(); 103 camView.transpose(); // inverse - this gets the particles facing camera 104 105 for (U32 i = 0; i < orderedVector.size(); i++) 106 { 107 Particle* particle = orderedVector[i].p; 108 ParticleEmitter* emitter = orderedVector[i].emitter; 109 110 if (emitter->mDataBlock->orientParticles) 111 emitter->setupOriented(particle, camPos, ambientColor, buffPtr); 112 else 113 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 114 buffPtr+=4; 115 } 116 117 // create new VB if emitter size grows 118 if( !mVertBuff || n_parts > mCurBuffSize ) 119 { 120 mCurBuffSize = n_parts; 121 mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic); 122 } 123 // lock and copy tempBuff to video RAM 124 GFXVertexPCT *verts = mVertBuff.lock(); 125 dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) ); 126 mVertBuff.unlock(); 127 128 //MeshRenderInst *ri = gRenderInstManager->allocInst<MeshRenderInst>(); 129 ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); 130 ri->vertBuff = &mVertBuff; 131 ri->primBuff = &main_emitter_data->primBuff; 132 ri->translucentSort = true; 133 ri->type = RenderPassManager::RIT_Particle; 134 ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos ); 135 136 ri->defaultKey = (-sort_priority*100); 137 138 ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() * 139 GFX->getViewMatrix() * 140 GFX->getWorldMatrix() ); 141 142 ri->count = n_parts; 143 144 ri->blendStyle = main_emitter_data->blendStyle; 145 146 // use first particle's texture unless there is an emitter texture to override it 147 if (main_emitter_data->textureHandle) 148 ri->diffuseTex = &*(main_emitter_data->textureHandle); 149 else 150 ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureHandle); 151 152 ri->softnessDistance = main_emitter_data->softnessDistance; 153 154 // Sort by texture too. 155 //ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; 156 157 renderManager->addInst( ri ); 158} 159 160void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor) 161{ 162 S32 n_parts = 0; 163 for (S32 i = 0; i < emitters.size(); i++) 164 n_parts += emitters[i]->n_parts; 165 166 if (n_parts == 0) 167 return; 168 169 ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock; 170 171 main_emitter_data->allocPrimBuffer(n_parts); 172 173 orderedVector.clear(); 174 175 F32 min_d=0.0f, max_d=0.0f; 176 177 for (U32 i=0; i < emitters.size(); i++) 178 { 179 if (!emitters[i]->mDataBlock->pool_depth_fade || !emitters[i]->mDataBlock->pool_radial_fade) 180 continue; 181 182 // add particles to orderedVector and calc distance and min/max distance 183 for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next) 184 { 185 F32 dist = (pp->pos-camPos).len(); 186 if (dist > max_d) 187 max_d = dist; 188 else if (dist < min_d) 189 min_d = dist; 190 191 orderedVector.increment(); 192 orderedVector.last().p = pp; 193 orderedVector.last().k = dist; 194 orderedVector.last().emitter = emitters[i]; 195 } 196 } 197 198 // Add remaining emitters particles to the orderedVector that do not participate in the 199 // above depth computations: 200 for (U32 i=0; i < emitters.size(); i++) 201 { 202 if (emitters[i]->mDataBlock->pool_depth_fade || emitters[i]->mDataBlock->pool_radial_fade) 203 continue; 204 205 for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next) 206 { 207 orderedVector.increment(); 208 orderedVector.last().p = pp; 209 orderedVector.last().k = 0; // no need to compute depth here 210 orderedVector.last().emitter = emitters[i]; 211 } 212 } 213 214 static Vector<GFXVertexPCT> tempBuff(2048); 215 tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough 216 GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster) 217 218 Point3F basePoints[4]; 219 basePoints[0] = Point3F(-1.0, 0.0, -1.0); 220 basePoints[1] = Point3F( 1.0, 0.0, -1.0); 221 basePoints[2] = Point3F( 1.0, 0.0, 1.0); 222 basePoints[3] = Point3F(-1.0, 0.0, 1.0); 223 224 MatrixF camView = GFX->getWorldMatrix(); 225 camView.transpose(); // inverse - this gets the particles facing camera 226 227 //~~~~~~~~~~~~~~~~~~~~// 228 229 Point3F bbox_center; mObjBox.getCenter(&bbox_center); 230 F32 d_range = max_d - min_d; 231 bool d_safe = (d_range>0.0001); 232 F32 d_half = min_d + (d_range*0.5f); 233 234 //~~~~~~~~~~~~~~~~~~~~// 235 236 for (U32 i = 0; i < orderedVector.size(); i++) 237 { 238 Particle* particle = orderedVector[i].p; 239 ParticleEmitter* emitter = orderedVector[i].emitter; 240 241 LinearColorF color_save = particle->color; 242 particle->color.set(mDataBlock->base_color.red, mDataBlock->base_color.green, mDataBlock->base_color.blue, mDataBlock->base_color.alpha*particle->color.alpha); 243 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 244 particle->color = color_save; 245 246 buffPtr+=4; 247 } 248 249 // create new VB if emitter size grows 250 if( !mVertBuff || n_parts > mCurBuffSize ) 251 { 252 mCurBuffSize = n_parts; 253 mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic); 254 } 255 // lock and copy tempBuff to video RAM 256 GFXVertexPCT *verts = mVertBuff.lock(); 257 dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) ); 258 mVertBuff.unlock(); 259 260 ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); 261 ri->vertBuff = &mVertBuff; 262 ri->primBuff = &main_emitter_data->primBuff; 263 ri->translucentSort = true; 264 ri->type = RenderPassManager::RIT_Particle; 265 ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos ); 266 267 ri->defaultKey = (-sort_priority*100); 268 269 ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() * 270 GFX->getViewMatrix() * 271 GFX->getWorldMatrix() ); 272 273 ri->count = n_parts; 274 275 ri->blendStyle = ParticleRenderInst::BlendNormal; 276 277 // use first particle's texture unless there is an emitter texture to override it 278 //if (main_emitter_data->textureHandle) 279 // ri->diffuseTex = &*(main_emitter_data->textureHandle); 280 //else 281 ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureExtHandle); 282 283 F32 save_sort_dist = ri->sortDistSq; 284 285 ri->softnessDistance = main_emitter_data->softnessDistance; 286 287 renderManager->addInst( ri ); 288 289 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 290 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 291 // 2nd-pass 292 293 buffPtr = tempBuff.address(); 294 295 bbox_center.z = mObjBox.minExtents.z; 296 F32 max_radius = (max_d-min_d)*0.5f; 297 298 // gather fade settings 299 bool do_mixed_fades = false; 300 bool do_radial_fades = (emitters[0]->mDataBlock->pool_radial_fade && (max_radius>0.0001f)); 301 bool do_depth_fades = (emitters[0]->mDataBlock->pool_depth_fade && d_safe); 302 for (U32 i = 1; i < emitters.size(); i++) 303 { 304 if ( (do_radial_fades != (emitters[i]->mDataBlock->pool_radial_fade && (max_radius>0.0001f))) || 305 (do_depth_fades != (emitters[i]->mDataBlock->pool_depth_fade && d_safe))) 306 { 307 do_mixed_fades = true; 308 break; 309 } 310 } 311 312 if (do_mixed_fades) 313 { 314 for (U32 i = 0; i < orderedVector.size(); i++) 315 { 316 Particle* particle = orderedVector[i].p; 317 ParticleEmitter* emitter = orderedVector[i].emitter; 318 319 F32 bf = 1.0; // blend factor 320 321 // blend factor due to radius 322 if (emitter->mDataBlock->pool_radial_fade && (max_radius>0.0001f)) 323 { 324 F32 p_radius = (particle->pos-bbox_center).len(); 325 F32 bf_radius = p_radius/max_radius; 326 if (bf_radius>1.0f) bf_radius = 1.0f; 327 bf *= bf_radius*bf_radius; // quadratic for faster falloff 328 } 329 330 // blend factor, depth based 331 if (emitter->mDataBlock->pool_depth_fade && d_safe && (orderedVector[i].k > d_half)) 332 { 333 F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f)); 334 bf *= bf_depth; 335 } 336 337 // overall blend factor weight 338 bf *= mDataBlock->blend_weight; 339 340 LinearColorF color_save = particle->color; 341 particle->color = particle->color*bf; 342 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 343 particle->color = color_save; 344 345 buffPtr+=4; 346 } 347 } 348 else if (do_radial_fades && do_depth_fades) 349 { 350 for (U32 i = 0; i < orderedVector.size(); i++) 351 { 352 Particle* particle = orderedVector[i].p; 353 ParticleEmitter* emitter = orderedVector[i].emitter; 354 355 F32 bf = 1.0; // blend factor 356 357 // blend factor due to radius 358 F32 p_radius = (particle->pos-bbox_center).len(); 359 F32 bf_radius = p_radius/max_radius; 360 if (bf_radius>1.0f) bf_radius = 1.0f; 361 bf *= bf_radius*bf_radius; // quadratic for faster falloff 362 363 // blend factor, depth based 364 if (orderedVector[i].k > d_half) 365 { 366 F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f)); 367 bf *= bf_depth; 368 } 369 370 // overall blend factor weight 371 bf *= mDataBlock->blend_weight; 372 373 LinearColorF color_save = particle->color; 374 particle->color = particle->color*bf; 375 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 376 particle->color = color_save; 377 378 buffPtr+=4; 379 } 380 } 381 else if (do_radial_fades) // && !do_depth_fades 382 { 383 for (U32 i = 0; i < orderedVector.size(); i++) 384 { 385 Particle* particle = orderedVector[i].p; 386 ParticleEmitter* emitter = orderedVector[i].emitter; 387 388 F32 bf = 1.0; // blend factor 389 390 // blend factor due to radius 391 F32 p_radius = (particle->pos-bbox_center).len(); 392 F32 bf_radius = p_radius/max_radius; 393 if (bf_radius>1.0f) bf_radius = 1.0f; 394 bf *= bf_radius*bf_radius; // quadratic for faster falloff 395 396 // overall blend factor weight 397 bf *= mDataBlock->blend_weight; 398 399 LinearColorF color_save = particle->color; 400 particle->color = particle->color*bf; 401 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 402 particle->color = color_save; 403 404 buffPtr+=4; 405 } 406 } 407 else if (do_depth_fades) // && !do_radial_fades 408 { 409 for (U32 i = 0; i < orderedVector.size(); i++) 410 { 411 Particle* particle = orderedVector[i].p; 412 ParticleEmitter* emitter = orderedVector[i].emitter; 413 414 F32 bf = 1.0; // blend factor 415 416 // blend factor, depth based 417 if (orderedVector[i].k > d_half) 418 { 419 F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f)); 420 bf *= bf_depth; 421 } 422 423 // overall blend factor weight 424 bf *= mDataBlock->blend_weight; 425 426 LinearColorF color_save = particle->color; 427 particle->color = particle->color*bf; 428 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 429 particle->color = color_save; 430 431 buffPtr+=4; 432 } 433 } 434 else // (no fades) 435 { 436 for (U32 i = 0; i < orderedVector.size(); i++) 437 { 438 Particle* particle = orderedVector[i].p; 439 ParticleEmitter* emitter = orderedVector[i].emitter; 440 441 F32 bf = mDataBlock->blend_weight; // blend factor 442 443 LinearColorF color_save = particle->color; 444 particle->color = particle->color*bf; 445 emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr); 446 particle->color = color_save; 447 448 buffPtr+=4; 449 } 450 } 451 452 // create new VB if emitter size grows 453 if( !mVertBuff2 || n_parts > mCurBuffSize2 ) 454 { 455 mCurBuffSize2 = n_parts; 456 mVertBuff2.set(GFX, n_parts*4, GFXBufferTypeDynamic); 457 } 458 459 // lock and copy tempBuff to video RAM 460 verts = mVertBuff2.lock(); 461 dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) ); 462 mVertBuff2.unlock(); 463 464 ri = renderManager->allocInst<ParticleRenderInst>(); 465 ri->vertBuff = &mVertBuff2; 466 ri->primBuff = &main_emitter_data->primBuff; 467 ri->translucentSort = true; 468 ri->type = RenderPassManager::RIT_Particle; 469 ri->sortDistSq = save_sort_dist; 470 471 ri->defaultKey = (-sort_priority*100) + 1; 472 473 ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() * 474 GFX->getViewMatrix() * 475 GFX->getWorldMatrix() ); 476 477 ri->count = n_parts; 478 479 ri->blendStyle = ParticleRenderInst::BlendAdditive; 480 481 // use first particle's texture unless there is an emitter texture to override it 482 if (main_emitter_data->textureHandle) 483 ri->diffuseTex = &*(main_emitter_data->textureHandle); 484 else 485 ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureHandle); 486 487 ri->softnessDistance = main_emitter_data->softnessDistance; 488 489 renderManager->addInst( ri ); 490} 491 492//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 493