afxResidueMgr.cpp
Engine/source/afx/afxResidueMgr.cpp
Public Functions
ConsoleDocClass(afxResidueMgr , "@brief A class that manages certain AFX effects that can persist <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> long <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">durations.\n\n</a>" "A class that manages certain AFX effects that can persist much longer than the duration of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">choreographers.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
Detailed Description
Public Functions
ConsoleDocClass(afxResidueMgr , "@brief A class that manages certain AFX effects that can persist <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> long <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">durations.\n\n</a>" "A class that manages certain AFX effects that can persist much longer than the duration of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">choreographers.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
IMPLEMENT_CONOBJECT(afxResidueMgr )
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 "ts/tsShapeInstance.h" 30 31#include "afx/ce/afxZodiacMgr.h" 32#include "afx/ce/afxModel.h" 33#include "afx/afxResidueMgr.h" 34 35//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 36 37int QSORT_CALLBACK afxResidueMgr::ResidueList::compare_residue(const void* p1, const void* p2) 38{ 39 const afxResidueMgr::Residue** pd1 = (const afxResidueMgr::Residue**)p1; 40 const afxResidueMgr::Residue** pd2 = (const afxResidueMgr::Residue**)p2; 41 42 return int(((char*)(*pd1)->data.simobject) - ((char*)(*pd2)->data.simobject)); 43} 44 45//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 46//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 47 48inline void afxResidueMgr::ResidueList::swap_array_ptrs() 49{ 50 Vector<Residue*>* tmp = m_array; 51 m_array = m_scratch_array; 52 m_scratch_array = tmp; 53} 54 55void afxResidueMgr::ResidueList::free_residue(Residue* residue) 56{ 57 if (the_mgr == NULL) 58 return; 59 60 if (the_mgr->requires_delete_tracking(residue)) 61 the_mgr->disable_delete_tracking(residue); 62 the_mgr->free_residue(residue); 63} 64 65afxResidueMgr::ResidueList::ResidueList() 66{ 67 VECTOR_SET_ASSOCIATION(m_array_a); 68 VECTOR_SET_ASSOCIATION(m_array_b); 69 70 m_array = &m_array_a; 71 m_scratch_array = &m_array_b ; 72 73 m_dirty = false; 74 m_pending = -1; 75} 76 77afxResidueMgr::ResidueList::~ResidueList() 78{ 79 clear(); 80} 81 82void afxResidueMgr::ResidueList::clear() 83{ 84 if (the_mgr) 85 { 86 for (S32 i = 0; i < m_array->size(); i++) 87 { 88 Residue* r = (*m_array)[i]; 89 the_mgr->free_residue(r); 90 } 91 } 92 93 m_array_a.clear(); 94 m_array_b.clear(); 95} 96 97void afxResidueMgr::ResidueList::sort() 98{ 99 dQsort(m_array->address(), m_array->size(), sizeof(Residue*), compare_residue); 100 m_dirty = false; 101} 102 103void afxResidueMgr::ResidueList::fadeAndCull(U32 now) 104{ 105 for (S32 i = 0; i < m_array->size(); i++) 106 { 107 Residue* r = (*m_array)[i]; 108 109 // done 110 if (now >= r->stop_time) 111 { 112 free_residue(r); 113 } 114 // fading 115 else if (now >= r->fade_time) 116 { 117 r->fade = 1.0f - ((F32)(now - r->fade_time))/((F32)(r->stop_time - r->fade_time)); 118 m_scratch_array->push_back(r); 119 } 120 // opaque 121 else 122 { 123 r->fade = 1.0f; 124 m_scratch_array->push_back(r); 125 } 126 } 127 128 m_array->clear(); 129 swap_array_ptrs(); 130} 131 132// removes all residue with datablock matching obj 133void afxResidueMgr::ResidueList::stripMatchingObjects(SimObject* db, bool del_notify) 134{ 135 if (del_notify) 136 { 137 for (S32 i = 0; i < m_array->size(); i++) 138 { 139 Residue* r = (*m_array)[i]; 140 if (db == r->data.simobject && the_mgr != NULL) 141 the_mgr->free_residue(r); 142 else 143 m_scratch_array->push_back(r); 144 } 145 } 146 else 147 { 148 for (S32 i = 0; i < m_array->size(); i++) 149 { 150 Residue* r = (*m_array)[i]; 151 if (db == r->data.simobject) 152 free_residue(r); 153 else 154 m_scratch_array->push_back(r); 155 } 156 } 157 158 m_array->clear(); 159 swap_array_ptrs(); 160} 161 162void afxResidueMgr::ResidueList::add(Residue* residue) 163{ 164 m_array->push_back(residue); 165 m_dirty = true; 166} 167 168void afxResidueMgr::manage_residue(const Residue* r) 169{ 170 if (r == NULL || r->fade < 0.01f) 171 return; 172 173 if (r->type == ZODIAC) 174 { 175 LinearColorF zode_color = ColorI(r->params.zodiac.r, r->params.zodiac.g, r->params.zodiac.b, r->params.zodiac.a); 176 177 afxZodiacData* zd = (afxZodiacData*) r->data.zodiac; 178 if (zd->blend_flags == afxZodiacDefs::BLEND_SUBTRACTIVE) 179 zode_color *= r->fade; 180 else 181 zode_color.alpha *= r->fade; 182 183 Point3F zode_pos(r->params.zodiac.pos_x, r->params.zodiac.pos_y, r->params.zodiac.pos_z); 184 Point2F zode_vrange(r->params.zodiac.vrange_dn, r->params.zodiac.vrange_dn); 185 if (r->params.zodiac.on_terrain) 186 { 187 afxZodiacMgr::addTerrainZodiac(zode_pos, r->params.zodiac.rad, zode_color, r->params.zodiac.ang, zd); 188 } 189 else 190 { 191 afxZodiacMgr::addInteriorZodiac(zode_pos, r->params.zodiac.rad, zode_vrange, zode_color, r->params.zodiac.ang, zd); 192 } 193 } 194 else if (r->type == MODEL) 195 { 196 r->data.model->setFadeAmount(r->fade); 197 } 198} 199 200void afxResidueMgr::ResidueList::manage() 201{ 202 if (the_mgr == NULL) 203 return; 204 205 S32 n_residue = m_array->size(); 206 207 for (S32 x = 0; x < n_residue; x++) 208 the_mgr->manage_residue((*m_array)[x]); 209} 210 211U32 afxResidueMgr::ResidueList::findPendingBestBump(U32 look_max) 212{ 213 U32 soonest = 1000*60*60*24; 214 m_pending = -1; 215 216 U32 n = m_array->size(); 217 for (U32 i = 0; i < n && i < look_max; i++) 218 { 219 Residue* r = (*m_array)[i]; 220 if (r->stop_time < soonest) 221 { 222 soonest = r->stop_time; 223 m_pending = i; 224 } 225 } 226 227 return soonest; 228} 229 230void afxResidueMgr::ResidueList::bumpPending() 231{ 232 if (m_pending >= 0 && m_pending < m_array->size()) 233 { 234 Residue* r = (*m_array)[m_pending]; 235 m_array->erase(m_pending); 236 free_residue(r); 237 } 238 239 m_pending = -1; 240} 241 242bool afxResidueMgr::requires_delete_tracking(Residue* r) 243{ 244 return (r->type == MODEL); 245} 246 247void afxResidueMgr::enable_delete_tracking(Residue* r) 248{ 249 deleteNotify(r->data.simobject); 250} 251 252void afxResidueMgr::disable_delete_tracking(Residue* r) 253{ 254 clearNotify(r->data.simobject); 255 r->data.simobject->deleteObject(); 256 r->data.simobject = 0; 257} 258 259//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 260//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 261 262afxResidueMgr* afxResidueMgr::the_mgr = NULL; 263U32 afxResidueMgr::m_max_residue_objs = 256; 264bool afxResidueMgr::enabled = true; 265 266IMPLEMENT_CONOBJECT(afxResidueMgr); 267 268ConsoleDocClass( afxResidueMgr, 269 "@brief A class that manages certain AFX effects that can persist for long durations.\n\n" 270 271 "A class that manages certain AFX effects that can persist much longer than the duration of choreographers.\n" 272 273 "@ingroup AFX\n" 274); 275 276//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 277// free-list management 278 279afxResidueMgr::Residue* afxResidueMgr::alloc_free_pool_block() 280{ 281 // allocate new block for the free-list 282 m_free_pool_blocks.push_back(new Residue[FREE_POOL_BLOCK_SIZE]); 283 284 // link them onto the free-list 285 Residue* new_block = m_free_pool_blocks.last(); 286 for (U32 i = 0; i < FREE_POOL_BLOCK_SIZE - 1; i++) 287 new_block[i].next = &new_block[i + 1]; 288 289 // tail of free-list points to NULL 290 new_block[FREE_POOL_BLOCK_SIZE - 1].next = NULL; 291 292 return new_block; 293} 294 295afxResidueMgr::Residue* afxResidueMgr::alloc_residue() 296{ 297 // need new free-list-block if m_next_free is null 298 if (!m_next_free) 299 m_next_free = alloc_free_pool_block(); 300 301 // pop new residue from head of free-list 302 Residue* residue = m_next_free; 303 m_next_free = residue->next; 304 residue->next = NULL; 305 306 return residue; 307} 308 309void afxResidueMgr::free_residue(Residue* residue) 310{ 311 if (residue && residue->type == ZODIAC) 312 { 313 if (residue->data.zodiac && residue->data.zodiac->isTempClone()) 314 { 315 delete residue->data.zodiac; 316 residue->data.zodiac = 0; 317 } 318 } 319 320 // push residue onto head of free-list 321 residue->next = m_next_free; 322 m_next_free = residue; 323} 324 325//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 326 327void afxResidueMgr::deleteResidueObject(SimObject* obj, bool del_notify) 328{ 329 m_managed.stripMatchingObjects(obj, del_notify); 330} 331 332void afxResidueMgr::bump_residue() 333{ 334 if (m_managed.findPendingBestBump()) 335 m_managed.bumpPending(); 336} 337 338void afxResidueMgr::add_residue(Residue* residue) 339{ 340 AssertFatal(residue != NULL, "residue pointer is NULL."); 341 342 if (m_managed.size() >= m_max_residue_objs) 343 bump_residue(); 344 345 m_managed.add(residue); 346 manage_residue(residue); 347 348 if (requires_delete_tracking(residue)) 349 enable_delete_tracking(residue); 350} 351 352//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 353 354afxResidueMgr::afxResidueMgr() 355{ 356 mObjBox.minExtents.set(-1e7, -1e7, -1e7); 357 mObjBox.maxExtents.set( 1e7, 1e7, 1e7); 358 mWorldBox.minExtents.set(-1e7, -1e7, -1e7); 359 mWorldBox.maxExtents.set( 1e7, 1e7, 1e7); 360 361 m_next_free = NULL; 362 363 VECTOR_SET_ASSOCIATION(m_free_pool_blocks); 364} 365 366afxResidueMgr::~afxResidueMgr() 367{ 368 cleanup(); 369} 370 371void afxResidueMgr::cleanup() 372{ 373 m_managed.clear(); 374 375 m_next_free = NULL; 376 377 for (S32 i = 0; i < m_free_pool_blocks.size(); i++) 378 delete [] m_free_pool_blocks[i]; 379 380 m_free_pool_blocks.clear(); 381} 382 383void afxResidueMgr::onDeleteNotify(SimObject* obj) 384{ 385 deleteResidueObject(obj, true); 386 Parent::onDeleteNotify(obj); 387} 388 389void afxResidueMgr::residueAdvanceTime() 390{ 391 U32 now = Platform::getVirtualMilliseconds(); 392 m_managed.fadeAndCull(now); 393 m_managed.sortIfDirty(); 394 m_managed.manage(); 395} 396 397//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 398// add ZODIAC residue 399void afxResidueMgr::add_interior_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos, 400 F32 rad, const Point2F& vrange, const LinearColorF& col, F32 ang) 401{ 402 add_zodiac(dur, fade_dur, zode, pos, rad, vrange, col, ang, false); 403} 404 405void afxResidueMgr::add_terrain_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos, 406 F32 rad, const LinearColorF& col, F32 ang) 407{ 408 static Point2F vrange(0.0, 0.0); 409 add_zodiac(dur, fade_dur, zode, pos, rad, vrange, col, ang, true); 410} 411 412void afxResidueMgr::add_zodiac(F32 dur, F32 fade_dur, afxZodiacData* zode, const Point3F& pos, 413 F32 rad, const Point2F& vrange, const LinearColorF& col, F32 ang, bool on_terrain) 414{ 415 if (m_max_residue_objs == 0 || dur <= 0 || the_mgr == NULL) 416 return; 417 418 ColorI col_i = LinearColorF(col).toColorI(); 419 U32 now = Platform::getVirtualMilliseconds(); 420 421 Residue* residue = the_mgr->alloc_residue(); 422 // 423 residue->type = ZODIAC; 424 residue->data.zodiac = zode; 425 residue->fade_time = now + (U32)(dur*1000); 426 residue->stop_time = residue->fade_time + (U32)(fade_dur*1000); 427 residue->fade = 1.0f; 428 // 429 residue->params.zodiac.pos_x = pos.x; 430 residue->params.zodiac.pos_y = pos.y; 431 residue->params.zodiac.pos_z = pos.z; 432 residue->params.zodiac.rad = rad; 433 residue->params.zodiac.vrange_dn = vrange.x; 434 residue->params.zodiac.vrange_up = vrange.y; 435 residue->params.zodiac.r = col_i.red; 436 residue->params.zodiac.g = col_i.green; 437 residue->params.zodiac.b = col_i.blue; 438 residue->params.zodiac.a = col_i.alpha; 439 residue->params.zodiac.ang = ang; 440 residue->params.zodiac.on_terrain = on_terrain; 441 // 442 residue->next = 0; 443 444 the_mgr->add_residue(residue); 445} 446 447//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 448// add MODEL residue 449 450void afxResidueMgr::add(F32 dur, F32 fade_dur, afxModel* model) 451{ 452 if (m_max_residue_objs == 0 || dur <= 0 || the_mgr == NULL) 453 return; 454 455 U32 now = Platform::getVirtualMilliseconds(); 456 457 Residue* residue = the_mgr->alloc_residue(); 458 // 459 residue->type = MODEL; 460 residue->data.model = model; 461 residue->fade_time = now + (U32)(dur*1000); 462 residue->stop_time = residue->fade_time + (U32)(fade_dur*1000); 463 residue->fade = 1.0f; 464 // 465 residue->next = 0; 466 467 the_mgr->add_residue(residue); 468} 469 470//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 471