Torque3D Documentation / _generateds / afxResidueMgr.cpp

afxResidueMgr.cpp

Engine/source/afx/afxResidueMgr.cpp

More...

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