afxPath.cpp

Engine/source/afx/util/afxPath.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(afxPathData , "@brief A datablock <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> specifiying <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use with <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxUtil\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
ImplementEnumType(afxPath3DLoopType , "Possible loop types <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxPath.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxPath\n\n</a>" )

Detailed Description

Public Variables

 EndImplementEnumType 

Public Functions

ConsoleDocClass(afxPathData , "@brief A datablock <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> specifiying <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use with <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxUtil\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(afxPathData )

ImplementEnumType(afxPath3DLoopType , "Possible loop types <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxPath.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxPath\n\n</a>" )

  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 "console/consoleTypes.h"
 30#include "core/stream/bitStream.h"
 31#include "math/mathIO.h"
 32
 33#include "afx/util/afxPath.h"
 34#include "afx/util/afxPath3D.h"
 35
 36//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 37// afxPathData
 38
 39IMPLEMENT_CO_DATABLOCK_V1(afxPathData);
 40
 41ConsoleDocClass( afxPathData,
 42   "@brief A datablock for specifiying a 3D path for use with AFX.\n\n"
 43
 44   "@ingroup afxUtil\n"
 45   "@ingroup AFX\n"
 46   "@ingroup Datablocks\n"
 47);
 48
 49StringTableEntry afxPathData::POINTS_FIELD;
 50StringTableEntry afxPathData::ROLL_FIELD;
 51StringTableEntry afxPathData::TIMES_FIELD;
 52
 53ImplementEnumType( afxPath3DLoopType, "Possible loop types for an afxPath.\n" "@ingroup afxPath\n\n" )
 54   { afxPath3D::LOOP_CONSTANT,  "constant",     "..." },
 55   { afxPath3D::LOOP_CYCLE,     "cycle",        "..." },   
 56   { afxPath3D::LOOP_OSCILLATE, "oscillate",    "..." }, 
 57EndImplementEnumType;
 58
 59afxPathData::afxPathData()
 60{
 61  if (POINTS_FIELD == 0)
 62  {
 63    POINTS_FIELD = StringTable->insert("points");
 64    ROLL_FIELD = StringTable->insert("roll");
 65    TIMES_FIELD = StringTable->insert("times");
 66  }
 67
 68  loop_string   = ST_NULLSTRING;
 69  delay = 0;
 70  lifetime = 0;
 71  loop_type = 0;
 72  mult = 1.0f;
 73  time_offset = 0.0f;
 74  resolved = false;
 75  reverse = false;
 76  offset.zero();
 77  echo = false;
 78  concentric = false;
 79
 80  points_string = ST_NULLSTRING;
 81  points = 0;
 82  num_points = 0;
 83  update_points = true;
 84
 85  roll_string   = ST_NULLSTRING;
 86  rolls = 0;
 87  update_rolls = true;
 88
 89  times_string = ST_NULLSTRING;
 90  times = 0;
 91  update_times = true;
 92}
 93
 94afxPathData::afxPathData(const afxPathData& other, bool temp_clone) : GameBaseData(other, temp_clone)
 95{
 96  points_string = other.points_string;
 97  roll_string = other.roll_string;
 98  loop_string = other.loop_string;
 99  delay = other.delay;
100  lifetime = other.lifetime;
101  loop_type = other.loop_type; // --
102  mult = other.mult;
103  time_offset = other.time_offset;
104  resolved = other.resolved; // --
105  reverse = other.reverse;
106  offset = other.offset;
107  echo = other.echo;
108  concentric = other.concentric;
109  times_string = other.times_string;
110
111  num_points = other.num_points; // --
112  if (other.points && num_points > 0)
113  {
114    points = new Point3F[num_points];
115    dMemcpy(points, other.points, sizeof(Point3F)*num_points); // --
116  }
117  else
118    points = 0;
119  if (other.rolls && num_points > 0)
120  {
121    rolls = new F32[num_points];
122    dMemcpy(rolls, other.rolls, sizeof(F32)*num_points); // --
123  }
124  else
125    rolls = 0;
126  if (other.times && num_points > 0)
127  {
128    times = new F32[num_points];
129    dMemcpy(times, other.times, sizeof(F32)*num_points); // --
130  }
131  else
132    times = 0;
133
134  update_points = other.update_points; // --
135  update_rolls = other.update_rolls; // --
136  update_times = other.update_times; // --
137}
138
139afxPathData::~afxPathData()
140{
141  clear_arrays();
142}
143
144void afxPathData::initPersistFields()
145{
146  addField("points",     TypeString,  Offset(points_string, afxPathData),
147    "...");
148  addField("roll",       TypeString,  Offset(roll_string,   afxPathData),
149    "...");
150  addField("times",      TypeString,  Offset(times_string,  afxPathData),
151    "...");
152  addField("loop",       TypeString,  Offset(loop_string,   afxPathData),
153    "...");
154  addField("mult",       TypeF32,     Offset(mult,          afxPathData),
155    "...");
156  addField("delay",      TypeF32,     Offset(delay,         afxPathData),
157    "...");
158  addField("lifetime",   TypeF32,     Offset(lifetime,      afxPathData),
159    "...");
160  addField("timeOffset", TypeF32,     Offset(time_offset,   afxPathData),
161    "...");
162  addField("reverse",    TypeBool,    Offset(reverse,       afxPathData),
163    "...");
164  addField("offset",     TypePoint3F, Offset(offset,        afxPathData),
165    "...");
166  addField("echo",       TypeBool,    Offset(echo,          afxPathData),
167    "...");
168  addField("concentric", TypeBool,    Offset(concentric,    afxPathData),
169    "...");
170
171  Parent::initPersistFields();
172}
173
174bool afxPathData::onAdd()
175{
176  if (Parent::onAdd() == false)
177    return false;
178
179  update_derived_values();
180
181  return true;
182}
183
184void afxPathData::onRemove()
185{
186  clear_arrays();
187  loop_type = 0;
188
189  Parent::onRemove();
190}
191
192void afxPathData::packData(BitStream* stream)
193{
194  Parent::packData(stream);
195
196  stream->write(num_points);
197  if (num_points > 0)
198  {
199    for (U32 i = 0; i < num_points; i++)
200      mathWrite(*stream, points[i]);
201    if (stream->writeFlag(rolls != 0))
202    {
203      for (U32 i = 0; i < num_points; i++)
204        stream->write(rolls[i]);
205    }
206    if (stream->writeFlag(times != 0))
207    {
208      for (U32 i = 0; i < num_points; i++)
209        stream->write(times[i]);
210    }
211  }
212
213  stream->writeString(loop_string);
214  stream->write(delay);
215  stream->write(lifetime);
216  stream->write(time_offset);
217  stream->write(mult);
218  stream->writeFlag(reverse);
219  mathWrite(*stream, offset);
220  stream->writeFlag(echo);
221  stream->writeFlag(concentric);
222}
223
224void afxPathData::unpackData(BitStream* stream)
225{
226  Parent::unpackData(stream);
227
228  clear_arrays();
229
230  // read the points and rolls
231  stream->read(&num_points);
232  if (num_points > 0)
233  {
234    points = new Point3F[num_points];
235    for (U32 i = 0; i < num_points; i++)
236      mathRead(*stream, &points[i]);
237    update_points = false;
238    if (stream->readFlag())
239    {
240      rolls = new F32[num_points]; 
241      for (U32 i = 0; i < num_points; i++)
242        stream->read(&rolls[i]);
243      update_rolls = false;
244    }
245    if (stream->readFlag())
246    {
247      times = new F32[num_points]; 
248      for (U32 i = 0; i < num_points; i++)
249        stream->read(&times[i]);
250      update_times = false;
251    }
252  }
253
254  loop_string = stream->readSTString();
255  stream->read(&delay);
256  stream->read(&lifetime);
257  stream->read(&time_offset);
258  stream->read(&mult);
259  reverse = stream->readFlag();
260  mathRead(*stream, &offset);
261  echo = stream->readFlag();
262  concentric = stream->readFlag();
263}
264
265void afxPathData::update_derived_values()
266{
267  U32 num_rolls = (rolls != 0) ? num_points : 0;
268  U32 num_times = (times != 0) ? num_points : 0;
269
270  if (update_points)
271  {
272    derive_points_array();
273    update_points = false;
274  }
275
276  if (update_rolls || num_rolls != num_points)
277  {
278    derive_rolls_array();
279    update_rolls = false;
280  }
281
282  if (update_times || num_times != num_points)
283  {
284    derive_times_array();
285    update_times = false;
286  }
287
288  // CAUTION: The following block of code is fragile and tricky since it depends
289  // on the underlying structures defined by ImplementEnumType/EndImplementEnumType.
290  // This done because the enum text is parsed from a longer string.
291  if (loop_string != ST_NULLSTRING) 
292  {
293     for (unsigned int i = 0; i < _afxPath3DLoopType::_sEnumTable.getNumValues(); i++)
294     {
295        if (dStricmp(_afxPath3DLoopType::_sEnumTable[i].mName, loop_string) == 0)
296        {
297           loop_type = _afxPath3DLoopType::_sEnumTable[i].mInt;
298           break;
299        }
300     }
301  }
302  else 
303  {
304     loop_string = _afxPath3DLoopType::_sEnumTable[0].mName;
305     loop_type   = _afxPath3DLoopType::_sEnumTable[0].mInt;
306  }  
307}
308
309bool afxPathData::preload(bool server, String &errorStr)
310{
311  if (!Parent::preload(server, errorStr))
312    return false;
313
314  update_derived_values();
315
316  return true;
317}
318
319void afxPathData::onStaticModified(const char* slot, const char* newValue)
320{
321   Parent::onStaticModified(slot, newValue);
322
323  if (slot == POINTS_FIELD)
324  {
325    update_points = true;
326    return;
327  }
328  if (slot == ROLL_FIELD)
329  {
330    update_rolls = true;
331    return;
332  }
333  if (slot == TIMES_FIELD)
334  {
335    update_times = true;
336    return;
337  }
338}
339
340void afxPathData::extract_floats_from_string(Vector<F32>& values, const char* points_str)
341{
342  values.clear();
343
344  if (!points_str)
345    return;
346
347  // make a copy of points_str for tokenizing
348  char* tokCopy = dStrdup(points_str);
349
350  // extract each token, convert to float, add to values[]
351  char* currTok = dStrtok(tokCopy, " \t");
352  while (currTok != NULL) 
353  {
354    F32 value = dAtof(currTok);
355    values.push_back(value);
356    currTok = dStrtok(NULL, " \t");
357  }
358
359  dFree(tokCopy); 
360}
361
362Point3F* afxPathData::build_points_array(Vector<F32>& values, U32& n_points, bool reverse)
363{
364  AssertFatal(values.size() > 0, "Values array is empty.");
365  AssertFatal(values.size()%3 == 0, "Values array is not a multiple of 3.");
366
367  n_points = values.size()/3;
368  Point3F* points = new Point3F[n_points];
369
370  if (reverse)
371  {    
372    U32 p_i = 0;
373    for (S32 i = values.size()-1; i > 1; i-=3)
374      points[p_i++].set(values[i-2], values[i-1], values[i]);        
375  }
376  else
377  {
378    U32 p_i = 0;
379    for (U32 i = 0; i < values.size(); i+=3)
380      points[p_i++].set(values[i], values[i+1], values[i+2]);
381  }
382
383  return points;
384}
385
386F32* afxPathData::build_floats_array(Vector<F32>& values, U32& n_floats, bool reverse)
387{
388  AssertFatal(values.size() > 0, "Values array is empty.");
389
390  n_floats = values.size();
391  F32* floats = new F32[n_floats];
392
393  if (reverse)
394  {    
395    F32* f = floats;
396    for (S32 i = values.size()-1; i >= 0; i--)
397    {
398      *f = values[i]; 
399      f++;
400    }
401  }
402  else
403  {
404    for (U32 i = 0; i < values.size(); i++)
405     floats[i] = values[i]; 
406  }
407
408  return floats;
409}
410
411void afxPathData::clear_arrays()
412{
413  num_points = 0;
414  if (points)
415  {
416    delete [] points;
417    points = 0;
418  }
419  if (rolls)
420  {
421    delete [] rolls;
422    rolls = 0;
423  }
424  if (times)
425  {
426    delete [] times;
427    times = 0;
428  }
429  update_points = true;
430  update_rolls = true;
431  update_times = true;
432}
433
434void afxPathData::derive_points_array()
435{
436  if (points_string == ST_NULLSTRING) 
437    return;
438
439  if (points)
440  {
441    delete [] points;
442    points = 0;
443  }
444  num_points = 0;
445
446  Vector<F32> values;
447  extract_floats_from_string(values, points_string);
448  if (values.size() == 0)
449  {
450    Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) empty points field, datablock is invalid.", getName());
451    return;
452  }
453  if (values.size()%3 != 0)
454  {
455    Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total points values is not a multiple of 3, datablock is invalid.", getName());
456    return;
457  }
458
459  points = build_points_array(values, num_points, reverse);
460
461  if (offset.x != 0.0f || offset.y != 0.0f || offset.z != 0.0f)
462  {
463    // add offset here for efficiency (saves an addition from afxXM_PathConform)
464    for (U32 i = 0; i < num_points; i++)
465      points[i] += offset;
466  }
467}
468
469void afxPathData::derive_rolls_array()
470{
471  if (roll_string == ST_NULLSTRING) 
472    return;
473
474  if (rolls)
475  {
476    delete [] rolls;
477    rolls = 0;
478  }
479  
480  Vector<F32> values;
481  extract_floats_from_string(values, roll_string);
482  if (values.size() == 0)
483    return;
484
485  if (values.size() != num_points)
486  {
487    Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total roll values is not equal to total points, rolls ignored.", getName());
488    return;
489  }
490
491  U32 num_rolls = 0;
492  rolls = build_floats_array(values, num_rolls, reverse);
493
494  AssertFatal(num_rolls == num_points, "Unexpected error: num_rolls disagrees with num_points.");
495}
496
497void afxPathData::derive_times_array()
498{
499  if (times_string == ST_NULLSTRING) 
500    return;
501
502  if (times)
503  {
504    delete [] times;
505    times = 0;
506  }
507  
508  Vector<F32> values;
509  extract_floats_from_string(values, times_string);
510  if (values.size() == 0)
511    return;
512
513  if (values.size() != num_points)
514  {
515    Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total time values is not equal to total points, times ignored", getName());
516    return;
517  }
518
519  U32 num_times = 0;
520  times = build_floats_array(values, num_times, reverse);
521
522  AssertFatal(num_times == num_points, "Unexpected error: num_times disagrees with num_points.");
523}
524
525void afxPathData::onPerformSubstitutions()
526{
527  Parent::onPerformSubstitutions();
528  update_derived_values();
529}
530
531//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
532