afxPath.cpp
Engine/source/afx/util/afxPath.cpp
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(×[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