Torque3D Documentation / _generateds / afxConstraint.cpp

afxConstraint.cpp

Engine/source/afx/afxConstraint.cpp

More...

Public Defines

define
CONS_BY_ID(id) ((*mConstraints_v[().index])[().sub_index])
define
CONS_BY_IJ(i, j) ((*mConstraints_v[()])[(j)])

Detailed Description

Public Defines

CONS_BY_ID(id) ((*mConstraints_v[().index])[().sub_index])
CONS_BY_IJ(i, j) ((*mConstraints_v[()])[(j)])

Public Functions

cmp_cons_defs(const void * a, const void * b)

newObjectCons(afxConstraintMgr * mgr, bool hist)

newObjectCons(afxConstraintMgr * mgr, StringTableEntry name, bool hist)

newPointCons(afxConstraintMgr * mgr, bool hist)

newShapeCons(afxConstraintMgr * mgr, bool hist)

newShapeCons(afxConstraintMgr * mgr, StringTableEntry name, bool hist)

newShapeNodeCons(afxConstraintMgr * mgr, StringTableEntry name, StringTableEntry node, bool hist)

newTransformCons(afxConstraintMgr * mgr, bool hist)

   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 "arcaneFX.h"
  28
  29#include "T3D/aiPlayer.h"
  30#include "T3D/tsStatic.h"
  31#include "sim/netConnection.h"
  32#include "ts/tsShapeInstance.h"
  33
  34#include "afxConstraint.h"
  35#include "afxChoreographer.h"
  36#include "afxEffectWrapper.h"
  37
  38//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  39// afxConstraintDef
  40
  41// static
  42StringTableEntry  afxConstraintDef::SCENE_CONS_KEY;
  43StringTableEntry  afxConstraintDef::EFFECT_CONS_KEY;
  44StringTableEntry  afxConstraintDef::GHOST_CONS_KEY;
  45
  46afxConstraintDef::afxConstraintDef()
  47{
  48  if (SCENE_CONS_KEY == 0)
  49  {
  50    SCENE_CONS_KEY = StringTable->insert("#scene");
  51    EFFECT_CONS_KEY = StringTable->insert("#effect");
  52    GHOST_CONS_KEY = StringTable->insert("#ghost");
  53  }
  54
  55  reset();
  56}
  57
  58bool afxConstraintDef::isDefined() 
  59{
  60  return (mDef_type != CONS_UNDEFINED); 
  61}
  62
  63bool afxConstraintDef::isArbitraryObject() 
  64{ 
  65  return ((mCons_src_name != ST_NULLSTRING) && (mDef_type == CONS_SCENE)); 
  66}
  67
  68void afxConstraintDef::reset()
  69{
  70  mCons_src_name = ST_NULLSTRING;
  71  mCons_node_name = ST_NULLSTRING;
  72  mDef_type = CONS_UNDEFINED;
  73  mHistory_time = 0;
  74  mSample_rate = 30;
  75  mRuns_on_server = false;
  76  mRuns_on_client = false;
  77  mPos_at_box_center = false;
  78  mTreat_as_camera = false;
  79}
  80
  81bool afxConstraintDef::parseSpec(const char* spec, bool runs_on_server, 
  82                                 bool runs_on_client)
  83{
  84  reset();
  85
  86  if (spec == 0 || spec[0] == '\0')
  87    return false;
  88
  89  mHistory_time = 0.0f;
  90  mSample_rate = 30;
  91
  92  mRuns_on_server = runs_on_server;
  93  mRuns_on_client = runs_on_client;
  94
  95  // spec should be in one of these forms:
  96  //    CONSTRAINT_NAME (only)
  97  //    CONSTRAINT_NAME.NODE (shapeBase objects only)
  98  //    CONSTRAINT_NAME.#center
  99  //    object.OBJECT_NAME
 100  //    object.OBJECT_NAME.NODE (shapeBase objects only)
 101  //    object.OBJECT_NAME.#center
 102  //    effect.EFFECT_NAME
 103  //    effect.EFFECT_NAME.NODE
 104  //    effect.EFFECT_NAME.#center
 105  //    #ghost.EFFECT_NAME
 106  //    #ghost.EFFECT_NAME.NODE
 107  //    #ghost.EFFECT_NAME.#center
 108  //
 109
 110  // create scratch buffer by duplicating spec.
 111  char special = '\b';
 112  char* buffer = dStrdup(spec);
 113
 114  // substitute a dots not inside parens with special character
 115  S32 n_nested = 0;
 116  for (char* b = buffer; (*b) != '\0'; b++)
 117  {
 118    if ((*b) == '(')
 119      n_nested++;
 120    else if ((*b) == ')')
 121      n_nested--;
 122    else if ((*b) == '.' && n_nested == 0)
 123      (*b) = special;
 124  }
 125
 126  // divide name into '.' separated tokens (up to 8)
 127  char* words[8] = {0, 0, 0, 0, 0, 0, 0, 0};
 128  char* dot = buffer;
 129  int wdx = 0;
 130  while (wdx < 8)
 131  {
 132    words[wdx] = dot;
 133    dot = dStrchr(words[wdx++], special);
 134    if (!dot)
 135      break;
 136    *(dot++) = '\0';
 137    if ((*dot) == '\0')
 138      break;
 139  }
 140
 141  int n_words = wdx;
 142
 143  // at this point the spec has been split into words. 
 144  // n_words indicates how many words we have.
 145
 146  // no words found (must have been all whitespace)
 147  if (n_words < 1)
 148  {
 149    dFree(buffer);
 150    return false;
 151  }
 152
 153  char* hist_spec = 0;
 154  char* words2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
 155  int n_words2 = 0;
 156
 157  // move words to words2 while extracting #center and #history
 158  for (S32 i = 0; i < n_words; i++)
 159  {
 160    if (String::compare(words[i], "#center") == 0)
 161      mPos_at_box_center = true;
 162    else if (dStrncmp(words[i], "#history(", 9) == 0)
 163      hist_spec = words[i];
 164    else
 165      words2[n_words2++] = words[i];
 166  }
 167
 168  // words2[] now contains just the constraint part
 169
 170  // no words found (must have been all #center and #history)
 171  if (n_words2 < 1)
 172  {
 173    dFree(buffer);
 174    return false;
 175  }
 176
 177  if (hist_spec)
 178  {
 179    char* open_paren = dStrchr(hist_spec, '(');
 180    if (open_paren)
 181    {
 182      hist_spec = open_paren+1;
 183      if ((*hist_spec) != '\0')
 184      {
 185        char* close_paren = dStrchr(hist_spec, ')');
 186        if (close_paren)
 187          (*close_paren) = '\0';
 188        char* slash = dStrchr(hist_spec, '/');
 189        if (slash)
 190          (*slash) = ' ';
 191
 192        F32 hist_age = 0.0;
 193        U32 hist_rate = 30;
 194        S32 args = dSscanf(hist_spec,"%g %d", &hist_age, &hist_rate);
 195
 196        if (args > 0)
 197          mHistory_time = hist_age;
 198        if (args > 1)
 199          mSample_rate = hist_rate;
 200      }
 201    }
 202  }
 203
 204  StringTableEntry cons_name_key = StringTable->insert(words2[0]);
 205
 206  // must be in CONSTRAINT_NAME (only) form
 207  if (n_words2 == 1)
 208  {
 209    // arbitrary object/effect constraints must have a name
 210    if (cons_name_key == SCENE_CONS_KEY || cons_name_key == EFFECT_CONS_KEY)
 211    {
 212      dFree(buffer);
 213      return false;
 214    }
 215
 216    mCons_src_name = cons_name_key;
 217    mDef_type = CONS_PREDEFINED;
 218    dFree(buffer);
 219    return true;
 220  }
 221
 222  // "#scene.NAME" or "#scene.NAME.NODE""
 223  if (cons_name_key == SCENE_CONS_KEY)
 224  {
 225    mCons_src_name = StringTable->insert(words2[1]);
 226    if (n_words2 > 2)
 227      mCons_node_name = StringTable->insert(words2[2]);
 228    mDef_type = CONS_SCENE;
 229    dFree(buffer);
 230    return true;
 231  }
 232
 233  // "#effect.NAME" or "#effect.NAME.NODE"
 234  if (cons_name_key == EFFECT_CONS_KEY)
 235  {
 236    mCons_src_name = StringTable->insert(words2[1]);
 237    if (n_words2 > 2)
 238      mCons_node_name = StringTable->insert(words2[2]);
 239    mDef_type = CONS_EFFECT;
 240    dFree(buffer);
 241    return true;
 242  }
 243
 244  // "#ghost.NAME" or "#ghost.NAME.NODE"
 245  if (cons_name_key == GHOST_CONS_KEY)
 246  {
 247    if (runs_on_server)
 248    {
 249      dFree(buffer);
 250      return false;
 251    }
 252
 253    mCons_src_name = StringTable->insert(words2[1]);
 254    if (n_words2 > 2)
 255      mCons_node_name = StringTable->insert(words2[2]);
 256    mDef_type = CONS_GHOST;
 257    dFree(buffer);
 258    return true;
 259  }
 260
 261  // "CONSTRAINT_NAME.NODE"
 262  if (n_words2 == 2)
 263  {
 264    mCons_src_name = cons_name_key;
 265    mCons_node_name = StringTable->insert(words2[1]);
 266    mDef_type = CONS_PREDEFINED;
 267    dFree(buffer);
 268    return true;
 269  }
 270
 271  // must be in unsupported form
 272  dFree(buffer); 
 273  return false;
 274}
 275
 276void afxConstraintDef::gather_cons_defs(Vector<afxConstraintDef>& defs, afxEffectList& fx)
 277{
 278  for (S32 i = 0; i <  fx.size(); i++)
 279  {
 280    if (fx[i])
 281      fx[i]->gather_cons_defs(defs);
 282  }
 283}
 284
 285//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 286//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 287// afxConstraint
 288
 289afxConstraint::afxConstraint(afxConstraintMgr* mgr)
 290{
 291  mMgr = mgr;
 292  mIs_defined = false;
 293  mIs_valid = false;
 294  mLast_pos.zero();
 295  mLast_xfm.identity();
 296  mHistory_time = 0.0f;
 297  mIs_alive = true;
 298  mGone_missing = false;
 299  mChange_code = 0;
 300}
 301
 302afxConstraint::~afxConstraint()
 303{
 304}
 305
 306//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 307
 308inline afxPointConstraint* newPointCons(afxConstraintMgr* mgr, bool hist)
 309{
 310  return (hist) ? new afxPointHistConstraint(mgr) : new afxPointConstraint(mgr);
 311}
 312
 313inline afxTransformConstraint* newTransformCons(afxConstraintMgr* mgr, bool hist)
 314{
 315  return (hist) ? new afxTransformHistConstraint(mgr) : new afxTransformConstraint(mgr);
 316}
 317
 318inline afxShapeConstraint* newShapeCons(afxConstraintMgr* mgr, bool hist)
 319{
 320  return (hist) ? new afxShapeHistConstraint(mgr) : new afxShapeConstraint(mgr);
 321}
 322
 323inline afxShapeConstraint* newShapeCons(afxConstraintMgr* mgr, StringTableEntry name, bool hist)
 324{
 325  return (hist) ? new afxShapeHistConstraint(mgr, name) : new afxShapeConstraint(mgr, name);
 326}
 327
 328inline afxShapeNodeConstraint* newShapeNodeCons(afxConstraintMgr* mgr, StringTableEntry name, StringTableEntry node, bool hist)
 329{
 330  return (hist) ? new afxShapeNodeHistConstraint(mgr, name, node) : new afxShapeNodeConstraint(mgr, name, node);
 331}
 332
 333inline afxObjectConstraint* newObjectCons(afxConstraintMgr* mgr, bool hist)
 334{
 335  return (hist) ? new afxObjectHistConstraint(mgr) : new afxObjectConstraint(mgr);
 336}
 337
 338inline afxObjectConstraint* newObjectCons(afxConstraintMgr* mgr, StringTableEntry name, bool hist)
 339{
 340  return (hist) ? new afxObjectHistConstraint(mgr, name) : new afxObjectConstraint(mgr, name);
 341}
 342
 343//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 344// afxConstraintMgr
 345
 346#define CONS_BY_ID(id) ((*mConstraints_v[(id).index])[(id).sub_index])
 347#define CONS_BY_IJ(i,j) ((*mConstraints_v[(i)])[(j)])
 348
 349afxConstraintMgr::afxConstraintMgr()
 350{
 351  mStartTime = 0;
 352  mOn_server = false;
 353  mInitialized = false;
 354  mScoping_dist_sq = 1000.0f*1000.0f;
 355  missing_objs = &missing_objs_a;
 356  missing_objs2 = &missing_objs_b;
 357}
 358
 359afxConstraintMgr::~afxConstraintMgr()
 360{
 361  for (S32 i = 0; i < mConstraints_v.size(); i++)
 362  {
 363    for (S32 j = 0; j < (*mConstraints_v[i]).size(); j++)
 364      delete CONS_BY_IJ(i,j);
 365    delete mConstraints_v[i];
 366  }
 367}
 368
 369//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
 370
 371S32 afxConstraintMgr::find_cons_idx_from_name(StringTableEntry which)
 372{
 373  for (S32 i = 0; i < mConstraints_v.size(); i++)
 374  {
 375    afxConstraint* cons = CONS_BY_IJ(i,0);
 376    if (cons && afxConstraintDef::CONS_EFFECT != cons->mCons_def.mDef_type && 
 377        which == cons->mCons_def.mCons_src_name)
 378    {
 379        return i;
 380    }
 381  }
 382
 383  return -1;
 384}
 385
 386S32 afxConstraintMgr::find_effect_cons_idx_from_name(StringTableEntry which)
 387{
 388  for (S32 i = 0; i < mConstraints_v.size(); i++)
 389  {
 390    afxConstraint* cons = CONS_BY_IJ(i,0);
 391    if (cons && afxConstraintDef::CONS_EFFECT == cons->mCons_def.mDef_type &&
 392        which == cons->mCons_def.mCons_src_name)
 393    {
 394      return i;
 395    }
 396  }
 397
 398  return -1;
 399}
 400
 401// Defines a predefined constraint with given name and type
 402void afxConstraintMgr::defineConstraint(U32 type, StringTableEntry name)
 403{
 404  preDef predef = { name, type };
 405  mPredefs.push_back(predef);
 406}
 407
 408afxConstraintID afxConstraintMgr::setReferencePoint(StringTableEntry which, Point3F point, 
 409                                                    Point3F vector)
 410{
 411  S32 idx = find_cons_idx_from_name(which);
 412  if (idx < 0)
 413    return afxConstraintID();
 414
 415  afxConstraintID id = afxConstraintID(idx);
 416  setReferencePoint(id, point, vector); 
 417
 418  return id;
 419}
 420
 421afxConstraintID afxConstraintMgr::setReferenceTransform(StringTableEntry which, MatrixF& xfm)
 422{
 423  S32 idx = find_cons_idx_from_name(which);
 424  if (idx < 0)
 425    return afxConstraintID();
 426
 427  afxConstraintID id = afxConstraintID(idx);
 428  setReferenceTransform(id, xfm); 
 429
 430  return id;
 431}
 432
 433// Assigns an existing scene-object to the named constraint
 434afxConstraintID afxConstraintMgr::setReferenceObject(StringTableEntry which, SceneObject* obj)
 435{
 436  S32 idx = find_cons_idx_from_name(which);
 437  if (idx < 0)
 438    return afxConstraintID();
 439
 440  afxConstraintID id = afxConstraintID(idx);
 441  setReferenceObject(id, obj); 
 442
 443  return id;
 444}
 445
 446// Assigns an un-scoped scene-object by scope_id to the named constraint
 447afxConstraintID afxConstraintMgr::setReferenceObjectByScopeId(StringTableEntry which, U16 scope_id, bool is_shape)
 448{
 449  S32 idx = find_cons_idx_from_name(which);
 450  if (idx < 0)
 451    return afxConstraintID();
 452
 453  afxConstraintID id = afxConstraintID(idx);
 454  setReferenceObjectByScopeId(id, scope_id, is_shape); 
 455
 456  return id;
 457}
 458
 459afxConstraintID afxConstraintMgr::setReferenceEffect(StringTableEntry which, afxEffectWrapper* ew)
 460{
 461  S32 idx = find_effect_cons_idx_from_name(which);
 462
 463  if (idx < 0)
 464    return afxConstraintID();
 465
 466  afxConstraintID id = afxConstraintID(idx);
 467  setReferenceEffect(id, ew); 
 468
 469  return id;
 470}
 471
 472afxConstraintID afxConstraintMgr::createReferenceEffect(StringTableEntry which, afxEffectWrapper* ew)
 473{
 474  afxEffectConstraint* cons = new afxEffectConstraint(this, which);
 475  //cons->cons_def = def;
 476  cons->mCons_def.mDef_type = afxConstraintDef::CONS_EFFECT;
 477  cons->mCons_def.mCons_src_name = which;
 478  afxConstraintList* list = new afxConstraintList();
 479  list->push_back(cons);
 480  mConstraints_v.push_back(list);
 481
 482  return setReferenceEffect(which, ew);
 483}
 484
 485void afxConstraintMgr::setReferencePoint(afxConstraintID id, Point3F point, Point3F vector)
 486{
 487  afxPointConstraint* pt_cons = dynamic_cast<afxPointConstraint*>(CONS_BY_ID(id));
 488
 489  // need to change type
 490  if (!pt_cons)
 491  {
 492    afxConstraint* cons = CONS_BY_ID(id);
 493    pt_cons = newPointCons(this, cons->mCons_def.mHistory_time > 0.0f);
 494    pt_cons->mCons_def = cons->mCons_def;
 495    CONS_BY_ID(id) = pt_cons;
 496    delete cons;
 497  }
 498
 499  pt_cons->set(point, vector);
 500
 501  // nullify all subnodes
 502  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 503  {
 504    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 505    if (cons)
 506      cons->unset();
 507  }
 508}
 509
 510void afxConstraintMgr::setReferenceTransform(afxConstraintID id, MatrixF& xfm)
 511{
 512  afxTransformConstraint* xfm_cons = dynamic_cast<afxTransformConstraint*>(CONS_BY_ID(id));
 513
 514  // need to change type
 515  if (!xfm_cons)
 516  {
 517    afxConstraint* cons = CONS_BY_ID(id);
 518    xfm_cons = newTransformCons(this, cons->mCons_def.mHistory_time > 0.0f);
 519    xfm_cons->mCons_def = cons->mCons_def;
 520    CONS_BY_ID(id) = xfm_cons;
 521    delete cons;
 522  }
 523
 524  xfm_cons->set(xfm);
 525
 526  // nullify all subnodes
 527  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 528  {
 529    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 530    if (cons)
 531      cons->unset();
 532  }
 533}
 534
 535void afxConstraintMgr::set_ref_shape(afxConstraintID id, ShapeBase* shape)
 536{
 537  id.sub_index = 0;
 538
 539  afxShapeConstraint* shape_cons = dynamic_cast<afxShapeConstraint*>(CONS_BY_ID(id));
 540
 541  // need to change type
 542  if (!shape_cons)
 543  {
 544    afxConstraint* cons = CONS_BY_ID(id);
 545    shape_cons = newShapeCons(this, cons->mCons_def.mHistory_time > 0.0f);
 546    shape_cons->mCons_def = cons->mCons_def;
 547    CONS_BY_ID(id) = shape_cons;
 548    delete cons;
 549  }
 550
 551  // set new shape on root 
 552  shape_cons->set(shape);
 553
 554  // update all subnodes
 555  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 556  {
 557    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 558    if (cons)
 559    {
 560      if (dynamic_cast<afxShapeNodeConstraint*>(cons))
 561        ((afxShapeNodeConstraint*)cons)->set(shape);
 562      else if (dynamic_cast<afxShapeConstraint*>(cons))
 563        ((afxShapeConstraint*)cons)->set(shape);
 564      else if (dynamic_cast<afxObjectConstraint*>(cons))
 565        ((afxObjectConstraint*)cons)->set(shape);
 566      else
 567        cons->unset();
 568    }
 569  }
 570}
 571
 572void afxConstraintMgr::set_ref_shape(afxConstraintID id, U16 scope_id)
 573{
 574  id.sub_index = 0;
 575
 576  afxShapeConstraint* shape_cons = dynamic_cast<afxShapeConstraint*>(CONS_BY_ID(id));
 577
 578  // need to change type
 579  if (!shape_cons)
 580  {
 581    afxConstraint* cons = CONS_BY_ID(id);
 582    shape_cons = newShapeCons(this, cons->mCons_def.mHistory_time > 0.0f);
 583    shape_cons->mCons_def = cons->mCons_def;
 584    CONS_BY_ID(id) = shape_cons;
 585    delete cons;
 586  }
 587
 588  // set new shape on root 
 589  shape_cons->set_scope_id(scope_id);
 590
 591  // update all subnodes
 592  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 593  {
 594    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 595    if (cons)
 596      cons->set_scope_id(scope_id);
 597  }
 598}
 599
 600// Assigns an existing scene-object to the constraint matching the given constraint-id.
 601void afxConstraintMgr::setReferenceObject(afxConstraintID id, SceneObject* obj)
 602{
 603  if (!mInitialized)
 604    Con::errorf("afxConstraintMgr::setReferenceObject() -- constraint manager not initialized");
 605
 606  if (!CONS_BY_ID(id)->mCons_def.mTreat_as_camera)
 607  {
 608    ShapeBase* shape = dynamic_cast<ShapeBase*>(obj);
 609    if (shape)
 610    {
 611      set_ref_shape(id, shape);
 612      return;
 613    }
 614  }
 615
 616  afxObjectConstraint* obj_cons = dynamic_cast<afxObjectConstraint*>(CONS_BY_ID(id));
 617
 618  // need to change type
 619  if (!obj_cons)
 620  {
 621    afxConstraint* cons = CONS_BY_ID(id);
 622    obj_cons = newObjectCons(this, cons->mCons_def.mHistory_time > 0.0f);
 623    obj_cons->mCons_def = cons->mCons_def;
 624    CONS_BY_ID(id) = obj_cons;
 625    delete cons;
 626  }
 627
 628  obj_cons->set(obj);
 629
 630  // update all subnodes
 631  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 632  {
 633    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 634    if (cons)
 635    {
 636      if (dynamic_cast<afxObjectConstraint*>(cons))
 637          ((afxObjectConstraint*)cons)->set(obj);
 638      else
 639        cons->unset();
 640    }
 641  }
 642}
 643
 644// Assigns an un-scoped scene-object by scope_id to the constraint matching the 
 645// given constraint-id.
 646void afxConstraintMgr::setReferenceObjectByScopeId(afxConstraintID id, U16 scope_id, bool is_shape)
 647{
 648  if (!mInitialized)
 649    Con::errorf("afxConstraintMgr::setReferenceObject() -- constraint manager not initialized");
 650
 651  if (is_shape)
 652  {
 653    set_ref_shape(id, scope_id);
 654    return;
 655  }
 656
 657  afxObjectConstraint* obj_cons = dynamic_cast<afxObjectConstraint*>(CONS_BY_ID(id));
 658
 659  // need to change type
 660  if (!obj_cons)
 661  {
 662    afxConstraint* cons = CONS_BY_ID(id);
 663    obj_cons = newObjectCons(this, cons->mCons_def.mHistory_time > 0.0f);
 664    obj_cons->mCons_def = cons->mCons_def;
 665    CONS_BY_ID(id) = obj_cons;
 666    delete cons;
 667  }
 668
 669  obj_cons->set_scope_id(scope_id);
 670
 671  // update all subnodes
 672  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 673  {
 674    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 675    if (cons)
 676      cons->set_scope_id(scope_id);
 677  }
 678}
 679
 680void afxConstraintMgr::setReferenceEffect(afxConstraintID id, afxEffectWrapper* ew)
 681{
 682  afxEffectConstraint* eff_cons = dynamic_cast<afxEffectConstraint*>(CONS_BY_ID(id));
 683  if (!eff_cons)
 684    return;
 685
 686  eff_cons->set(ew);
 687
 688  // update all subnodes
 689  for (S32 j = 1; j < (*mConstraints_v[id.index]).size(); j++)
 690  {
 691    afxConstraint* cons = CONS_BY_IJ(id.index,j);
 692    if (cons)
 693    {
 694      if (dynamic_cast<afxEffectNodeConstraint*>(cons))
 695        ((afxEffectNodeConstraint*)cons)->set(ew);
 696      else if (dynamic_cast<afxEffectConstraint*>(cons))
 697        ((afxEffectConstraint*)cons)->set(ew);
 698      else
 699        cons->unset();
 700    }
 701  }
 702}
 703
 704void afxConstraintMgr::invalidateReference(afxConstraintID id)
 705{
 706  afxConstraint* cons = CONS_BY_ID(id);
 707  if (cons)
 708    cons->mIs_valid = false;
 709}
 710
 711void afxConstraintMgr::create_constraint(const afxConstraintDef& def)
 712{
 713  if (def.mDef_type == afxConstraintDef::CONS_UNDEFINED)
 714    return;
 715
 716  //Con::printf("CON - %s [%s] [%s] h=%g", def.cons_type_name, def.cons_src_name, def.cons_node_name, def.history_time);
 717
 718  bool want_history = (def.mHistory_time > 0.0f);
 719
 720  // constraint is an arbitrary named scene object
 721  //
 722  if (def.mDef_type == afxConstraintDef::CONS_SCENE)
 723  {
 724    if (def.mCons_src_name == ST_NULLSTRING)
 725      return;
 726
 727    // find the arbitrary object by name
 728    SceneObject* arb_obj;
 729    if (mOn_server)
 730    {
 731      arb_obj = dynamic_cast<SceneObject*>(Sim::findObject(def.mCons_src_name));
 732      if (!arb_obj)
 733         Con::errorf("afxConstraintMgr -- failed to find scene constraint source, \"%s\" on server.", 
 734                     def.mCons_src_name);
 735    }
 736    else
 737    {
 738      arb_obj = find_object_from_name(def.mCons_src_name);
 739      if (!arb_obj)
 740         Con::errorf("afxConstraintMgr -- failed to find scene constraint source, \"%s\" on client.", 
 741                     def.mCons_src_name);
 742    }
 743
 744    // if it's a shapeBase object, create a Shape or ShapeNode constraint
 745    if (dynamic_cast<ShapeBase*>(arb_obj))
 746    {
 747      if (def.mCons_node_name == ST_NULLSTRING && !def.mPos_at_box_center)
 748      {
 749        afxShapeConstraint* cons = newShapeCons(this, def.mCons_src_name, want_history);
 750        cons->mCons_def = def;
 751        cons->set((ShapeBase*)arb_obj); 
 752        afxConstraintList* list = new afxConstraintList();
 753        list->push_back(cons);
 754      mConstraints_v.push_back(list);
 755      }
 756      else if (def.mPos_at_box_center)
 757      {
 758        afxShapeConstraint* cons = newShapeCons(this, def.mCons_src_name, want_history);
 759        cons->mCons_def = def;
 760        cons->set((ShapeBase*)arb_obj); 
 761        afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1]; // SHAPE-NODE CONS-LIST (#scene)(#center)
 762        if (list && (*list)[0])
 763          list->push_back(cons);
 764      }
 765      else
 766      {
 767        afxShapeNodeConstraint* sub = newShapeNodeCons(this, def.mCons_src_name, def.mCons_node_name, want_history);
 768        sub->mCons_def = def;
 769        sub->set((ShapeBase*)arb_obj); 
 770        afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1];
 771        if (list && (*list)[0])
 772          list->push_back(sub);
 773      }
 774    }
 775    // if it's not a shapeBase object, create an Object constraint
 776    else if (arb_obj)
 777    {
 778      if (!def.mPos_at_box_center)
 779      {
 780        afxObjectConstraint* cons = newObjectCons(this, def.mCons_src_name, want_history);
 781        cons->mCons_def = def;
 782        cons->set(arb_obj);
 783        afxConstraintList* list = new afxConstraintList(); // OBJECT CONS-LIST (#scene)
 784        list->push_back(cons);
 785      mConstraints_v.push_back(list);
 786      }
 787      else // if (def.pos_at_box_center)
 788      {
 789        afxObjectConstraint* cons = newObjectCons(this, def.mCons_src_name, want_history);
 790        cons->mCons_def = def;
 791        cons->set(arb_obj); 
 792        afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1]; // OBJECT CONS-LIST (#scene)(#center)
 793        if (list && (*list)[0])
 794          list->push_back(cons);
 795      }
 796    }
 797  }
 798
 799  // constraint is an arbitrary named effect
 800  //
 801  else if (def.mDef_type == afxConstraintDef::CONS_EFFECT)
 802  {
 803    if (def.mCons_src_name == ST_NULLSTRING)
 804      return;
 805
 806    // create an Effect constraint
 807    if (def.mCons_node_name == ST_NULLSTRING && !def.mPos_at_box_center)
 808    {
 809      afxEffectConstraint* cons = new afxEffectConstraint(this, def.mCons_src_name);
 810      cons->mCons_def = def;
 811      afxConstraintList* list = new afxConstraintList();
 812      list->push_back(cons);
 813     mConstraints_v.push_back(list);
 814    }
 815    // create an Effect #center constraint
 816    else if (def.mPos_at_box_center)
 817    {
 818      afxEffectConstraint* cons = new afxEffectConstraint(this, def.mCons_src_name);
 819      cons->mCons_def = def;
 820      afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1]; // EFFECT-NODE CONS-LIST (#effect)
 821      if (list && (*list)[0])
 822        list->push_back(cons);
 823    }
 824    // create an EffectNode constraint
 825    else
 826    {
 827      afxEffectNodeConstraint* sub = new afxEffectNodeConstraint(this, def.mCons_src_name, def.mCons_node_name);
 828      sub->mCons_def = def;
 829      afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1];
 830      if (list && (*list)[0])
 831        list->push_back(sub);
 832    }
 833  }
 834
 835  // constraint is a predefined constraint
 836  //
 837  else
 838  {
 839    afxConstraint* cons = 0;
 840    afxConstraint* cons_ctr = 0;
 841    afxConstraint* sub = 0;
 842
 843    if (def.mDef_type == afxConstraintDef::CONS_GHOST)
 844    {
 845      for (S32 i = 0; i < mPredefs.size(); i++)
 846      {
 847        if (mPredefs[i].name == def.mCons_src_name)
 848        {
 849          if (def.mCons_node_name == ST_NULLSTRING && !def.mPos_at_box_center)
 850          {
 851            cons = newShapeCons(this, want_history);
 852            cons->mCons_def = def;
 853          }
 854          else if (def.mPos_at_box_center)
 855          {
 856            cons_ctr = newShapeCons(this, want_history);
 857            cons_ctr->mCons_def = def;
 858          }
 859          else
 860          {
 861            sub = newShapeNodeCons(this, ST_NULLSTRING, def.mCons_node_name, want_history);
 862            sub->mCons_def = def;
 863          }
 864          break;
 865        }
 866      }
 867    }
 868    else
 869    {
 870      for (S32 i = 0; i < mPredefs.size(); i++)
 871      {
 872        if (mPredefs[i].name == def.mCons_src_name)
 873        {
 874          switch (mPredefs[i].type)
 875          {
 876          case POINT_CONSTRAINT:
 877            cons = newPointCons(this, want_history);
 878            cons->mCons_def = def;
 879            break;
 880          case TRANSFORM_CONSTRAINT:
 881            cons = newTransformCons(this, want_history);
 882            cons->mCons_def = def;
 883            break;
 884          case OBJECT_CONSTRAINT:
 885            if (def.mCons_node_name == ST_NULLSTRING && !def.mPos_at_box_center)
 886            {
 887              cons = newShapeCons(this, want_history);
 888              cons->mCons_def = def;
 889            }
 890            else if (def.mPos_at_box_center)
 891            {
 892              cons_ctr = newShapeCons(this, want_history);
 893              cons_ctr->mCons_def = def;
 894            }
 895            else
 896            {
 897              sub = newShapeNodeCons(this, ST_NULLSTRING, def.mCons_node_name, want_history);
 898              sub->mCons_def = def;
 899            }
 900            break;
 901          case CAMERA_CONSTRAINT:
 902            cons = newObjectCons(this, want_history);
 903            cons->mCons_def = def;
 904            cons->mCons_def.mTreat_as_camera = true;
 905            break;
 906          }
 907          break;
 908        }
 909      }
 910    }
 911
 912    if (cons)
 913    {
 914      afxConstraintList* list = new afxConstraintList();
 915      list->push_back(cons);
 916     mConstraints_v.push_back(list);
 917    }
 918    else if (cons_ctr && mConstraints_v.size() > 0)
 919    {
 920      afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1]; // PREDEF-NODE CONS-LIST
 921      if (list && (*list)[0])
 922        list->push_back(cons_ctr);
 923    }
 924    else if (sub && mConstraints_v.size() > 0)
 925    {
 926      afxConstraintList* list = mConstraints_v[mConstraints_v.size()-1];
 927      if (list && (*list)[0])
 928        list->push_back(sub);
 929    }
 930    else
 931      Con::printf("predef not found %s", def.mCons_src_name);
 932  }
 933}
 934
 935afxConstraintID afxConstraintMgr::getConstraintId(const afxConstraintDef& def)
 936{
 937  if (def.mDef_type == afxConstraintDef::CONS_UNDEFINED)
 938    return afxConstraintID();
 939
 940  if (def.mCons_src_name != ST_NULLSTRING)
 941  {
 942    for (S32 i = 0; i < mConstraints_v.size(); i++)
 943    {
 944      afxConstraintList* list = mConstraints_v[i];
 945      afxConstraint* cons = (*list)[0];
 946      if (def.mCons_src_name == cons->mCons_def.mCons_src_name)
 947      {
 948        for (S32 j = 0; j < list->size(); j++)
 949        {
 950          afxConstraint* sub = (*list)[j];
 951          if (def.mCons_node_name == sub->mCons_def.mCons_node_name &&
 952              def.mPos_at_box_center == sub->mCons_def.mPos_at_box_center &&
 953              def.mCons_src_name == sub->mCons_def.mCons_src_name)
 954          {
 955            return afxConstraintID(i, j);
 956          }
 957        }
 958
 959        // if we're here, it means the root object name matched but the node name
 960        // did not.
 961        if (def.mDef_type == afxConstraintDef::CONS_PREDEFINED && !def.mPos_at_box_center)
 962        {
 963          afxShapeConstraint* shape_cons = dynamic_cast<afxShapeConstraint*>(cons);
 964          if (shape_cons)
 965          {
 966             //Con::errorf("Append a Node constraint [%s.%s] [%d,%d]", def.cons_src_name, def.cons_node_name, i, list->size());
 967             bool want_history = (def.mHistory_time > 0.0f);
 968             afxConstraint* sub = newShapeNodeCons(this, ST_NULLSTRING, def.mCons_node_name, want_history);
 969             sub->mCons_def = def;
 970             ((afxShapeConstraint*)sub)->set(shape_cons->mShape);
 971             list->push_back(sub);
 972
 973             return afxConstraintID(i, list->size()-1);
 974          }
 975        }
 976
 977        break;
 978      }
 979    }
 980  }
 981
 982  return afxConstraintID();
 983}
 984
 985afxConstraint* afxConstraintMgr::getConstraint(afxConstraintID id)
 986{
 987  if (id.undefined())
 988    return 0;
 989
 990  afxConstraint* cons = CONS_BY_IJ(id.index,id.sub_index);
 991  if (cons && !cons->isDefined())
 992    return NULL;
 993
 994  return cons;
 995}
 996
 997void afxConstraintMgr::sample(F32 dt, U32 now, const Point3F* cam_pos)
 998{
 999  U32 elapsed = now - mStartTime;
1000
1001  for (S32 i = 0; i < mConstraints_v.size(); i++)
1002  {
1003    afxConstraintList* list = mConstraints_v[i];
1004    for (S32 j = 0; j < list->size(); j++)
1005      (*list)[j]->sample(dt, elapsed, cam_pos);
1006  }
1007}
1008
1009S32 QSORT_CALLBACK cmp_cons_defs(const void* a, const void* b)
1010{
1011  afxConstraintDef* def_a = (afxConstraintDef*) a;
1012  afxConstraintDef* def_b = (afxConstraintDef*) b;
1013
1014  if (def_a->mDef_type == def_b->mDef_type)
1015  {
1016    if (def_a->mCons_src_name == def_b->mCons_src_name)
1017    {
1018      if (def_a->mPos_at_box_center == def_b->mPos_at_box_center)
1019        return (def_a->mCons_node_name - def_b->mCons_node_name);
1020      else
1021        return (def_a->mPos_at_box_center) ? 1 : -1;
1022    }
1023    return (def_a->mCons_src_name - def_b->mCons_src_name);
1024  }
1025
1026  return (def_a->mDef_type - def_b->mDef_type);
1027}
1028
1029void afxConstraintMgr::initConstraintDefs(Vector<afxConstraintDef>& all_defs, bool on_server, F32 scoping_dist)
1030{
1031  mInitialized = true;
1032  mOn_server = on_server;
1033
1034  if (scoping_dist > 0.0)
1035    mScoping_dist_sq = scoping_dist*scoping_dist;
1036  else
1037  {
1038    SceneManager* sg = (on_server) ? gServerSceneGraph : gClientSceneGraph;
1039    F32 vis_dist = (sg) ? sg->getVisibleDistance() : 1000.0f;
1040   mScoping_dist_sq = vis_dist*vis_dist;
1041  }
1042
1043  if (all_defs.size() < 1)
1044    return;
1045
1046  // find effect ghost constraints
1047  if (!on_server)
1048  {
1049    Vector<afxConstraintDef> ghost_defs;
1050
1051    for (S32 i = 0; i < all_defs.size(); i++)
1052      if (all_defs[i].mDef_type == afxConstraintDef::CONS_GHOST && all_defs[i].mCons_src_name != ST_NULLSTRING)
1053        ghost_defs.push_back(all_defs[i]);
1054    
1055    if (ghost_defs.size() > 0)
1056    {
1057      // sort the defs
1058      if (ghost_defs.size() > 1)
1059        dQsort(ghost_defs.address(), ghost_defs.size(), sizeof(afxConstraintDef), cmp_cons_defs);
1060      
1061      S32 last = 0;
1062      defineConstraint(OBJECT_CONSTRAINT, ghost_defs[0].mCons_src_name);
1063
1064      for (S32 i = 1; i < ghost_defs.size(); i++)
1065      {
1066        if (ghost_defs[last].mCons_src_name != ghost_defs[i].mCons_src_name)
1067        {
1068          defineConstraint(OBJECT_CONSTRAINT, ghost_defs[i].mCons_src_name);
1069          last++;
1070        }
1071      }
1072    }
1073  }
1074
1075  Vector<afxConstraintDef> defs;
1076
1077  // collect defs that run here (server or client)
1078  if (on_server)
1079  {
1080    for (S32 i = 0; i < all_defs.size(); i++)
1081      if (all_defs[i].mRuns_on_server)
1082        defs.push_back(all_defs[i]);
1083  }
1084  else
1085  {
1086    for (S32 i = 0; i < all_defs.size(); i++)
1087      if (all_defs[i].mRuns_on_client)
1088        defs.push_back(all_defs[i]);
1089  }
1090
1091  // create unique set of constraints.
1092  //
1093  if (defs.size() > 0)
1094  {
1095    // sort the defs
1096    if (defs.size() > 1)
1097      dQsort(defs.address(), defs.size(), sizeof(afxConstraintDef), cmp_cons_defs);
1098    
1099    Vector<afxConstraintDef> unique_defs;
1100    S32 last = 0;
1101    
1102    // manufacture root-object def if absent
1103    if (defs[0].mCons_node_name != ST_NULLSTRING)
1104    {
1105      afxConstraintDef root_def = defs[0];
1106      root_def.mCons_node_name = ST_NULLSTRING;
1107      unique_defs.push_back(root_def);
1108      last++;
1109    }
1110    else if (defs[0].mPos_at_box_center)
1111    {
1112      afxConstraintDef root_def = defs[0];
1113      root_def.mPos_at_box_center = false;
1114      unique_defs.push_back(root_def);
1115      last++;
1116    }
1117
1118    unique_defs.push_back(defs[0]);
1119    
1120    for (S32 i = 1; i < defs.size(); i++)
1121    {
1122      if (unique_defs[last].mCons_node_name != defs[i].mCons_node_name ||
1123          unique_defs[last].mCons_src_name != defs[i].mCons_src_name ||
1124          unique_defs[last].mPos_at_box_center != defs[i].mPos_at_box_center ||
1125          unique_defs[last].mDef_type != defs[i].mDef_type)
1126      {
1127        // manufacture root-object def if absent
1128        if (defs[i].mCons_src_name != ST_NULLSTRING && unique_defs[last].mCons_src_name != defs[i].mCons_src_name)
1129        {
1130          if (defs[i].mCons_node_name != ST_NULLSTRING || defs[i].mPos_at_box_center)
1131          {
1132            afxConstraintDef root_def = defs[i];
1133            root_def.mCons_node_name = ST_NULLSTRING;
1134            root_def.mPos_at_box_center = false;
1135            unique_defs.push_back(root_def);
1136            last++;
1137          }
1138        }
1139        unique_defs.push_back(defs[i]);
1140        last++;
1141      }
1142      else
1143      {
1144        if (defs[i].mHistory_time > unique_defs[last].mHistory_time)
1145          unique_defs[last].mHistory_time = defs[i].mHistory_time;
1146        if (defs[i].mSample_rate > unique_defs[last].mSample_rate)
1147          unique_defs[last].mSample_rate = defs[i].mSample_rate;
1148      }
1149    }
1150    
1151    //Con::printf("\nConstraints on %s", (on_server) ? "server" : "client");
1152    for (S32 i = 0; i < unique_defs.size(); i++)
1153      create_constraint(unique_defs[i]);
1154  }
1155
1156  // collect the names of all the arbitrary object constraints
1157  // that run on clients and store in names_on_server array.
1158  //
1159  if (on_server)
1160  {
1161    mNames_on_server.clear();
1162    defs.clear();
1163
1164    for (S32 i = 0; i < all_defs.size(); i++)
1165      if (all_defs[i].mRuns_on_client && all_defs[i].isArbitraryObject())
1166        defs.push_back(all_defs[i]);
1167
1168    if (defs.size() < 1)
1169      return;
1170
1171    // sort the defs
1172    if (defs.size() > 1)
1173      dQsort(defs.address(), defs.size(), sizeof(afxConstraintDef), cmp_cons_defs);
1174
1175    S32 last = 0;
1176    mNames_on_server.push_back(defs[0].mCons_src_name);
1177
1178    for (S32 i = 1; i < defs.size(); i++)
1179    {
1180      if (mNames_on_server[last] != defs[i].mCons_src_name)
1181      {
1182        mNames_on_server.push_back(defs[i].mCons_src_name);
1183        last++;
1184      }
1185    }
1186  }
1187}
1188
1189void afxConstraintMgr::packConstraintNames(NetConnection* conn, BitStream* stream)
1190{
1191  // pack any named constraint names and ghost indices
1192  if (stream->writeFlag(mNames_on_server.size() > 0)) //-- ANY NAMED CONS_BY_ID?
1193  {
1194    stream->write(mNames_on_server.size());
1195    for (S32 i = 0; i < mNames_on_server.size(); i++)
1196    {
1197      stream->writeString(mNames_on_server[i]);
1198      NetObject* obj = dynamic_cast<NetObject*>(Sim::findObject(mNames_on_server[i]));
1199      if (!obj)
1200      {
1201        //Con::printf("CONSTRAINT-OBJECT %s does not exist.", names_on_server[i]);
1202        stream->write((S32)-1);
1203      }
1204      else
1205      {
1206        S32 ghost_id = conn->getGhostIndex(obj);
1207        /*
1208        if (ghost_id == -1)
1209          Con::printf("CONSTRAINT-OBJECT %s does not have a ghost.", names_on_server[i]);
1210        else
1211          Con::printf("CONSTRAINT-OBJECT %s name to server.", names_on_server[i]);
1212         */
1213        stream->write(ghost_id);
1214      }
1215    }
1216  }
1217}
1218
1219void afxConstraintMgr::unpackConstraintNames(BitStream* stream)
1220{
1221  if (stream->readFlag())                                         //-- ANY NAMED CONS_BY_ID?
1222  {
1223    mNames_on_server.clear();
1224    S32 sz; stream->read(&sz);
1225    for (S32 i = 0; i < sz; i++)
1226    {
1227      mNames_on_server.push_back(stream->readSTString());
1228      S32 ghost_id; stream->read(&ghost_id);
1229      mGhost_ids.push_back(ghost_id);
1230    }
1231  }
1232}
1233
1234//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
1235
1236SceneObject* afxConstraintMgr::find_object_from_name(StringTableEntry name)
1237{
1238  if (mNames_on_server.size() > 0)
1239  {
1240    for (S32 i = 0; i < mNames_on_server.size(); i++)
1241      if (mNames_on_server[i] == name)
1242      {
1243        if (mGhost_ids[i] == -1)
1244          return 0;
1245        NetConnection* conn = NetConnection::getConnectionToServer();
1246        if (!conn)
1247          return 0;
1248        return dynamic_cast<SceneObject*>(conn->resolveGhost(mGhost_ids[i]));
1249      }
1250  }
1251
1252  return dynamic_cast<SceneObject*>(Sim::findObject(name));
1253}
1254
1255void afxConstraintMgr::addScopeableObject(SceneObject* object)
1256{
1257  for (S32 i = 0; i < scopeable_objs.size(); i++)
1258  {
1259    if (scopeable_objs[i] == object)
1260      return;
1261  }
1262
1263  object->addScopeRef();
1264  scopeable_objs.push_back(object);
1265}
1266
1267void afxConstraintMgr::removeScopeableObject(SceneObject* object)
1268{
1269  for (S32 i = 0; i < scopeable_objs.size(); i++)
1270    if (scopeable_objs[i] == object)
1271    {
1272      object->removeScopeRef();
1273      scopeable_objs.erase_fast(i);
1274      return;
1275    }
1276}
1277
1278void afxConstraintMgr::clearAllScopeableObjs()
1279{
1280  for (S32 i = 0; i < scopeable_objs.size(); i++)
1281    scopeable_objs[i]->removeScopeRef();
1282  scopeable_objs.clear();
1283}
1284
1285void afxConstraintMgr::postMissingConstraintObject(afxConstraint* cons, bool is_deleting)
1286{
1287  if (cons->mGone_missing)
1288    return;
1289
1290  if (!is_deleting)
1291  {
1292    SceneObject* obj = arcaneFX::findScopedObject(cons->getScopeId());
1293    if (obj)
1294    {
1295      cons->restoreObject(obj);
1296      return;
1297    }
1298  }
1299
1300  cons->mGone_missing = true;
1301  missing_objs->push_back(cons);
1302}
1303
1304void afxConstraintMgr::restoreScopedObject(SceneObject* obj, afxChoreographer* ch)
1305{
1306  for (S32 i = 0; i < missing_objs->size(); i++)
1307  {
1308    if ((*missing_objs)[i]->getScopeId() == obj->getScopeId())
1309    {
1310      (*missing_objs)[i]->mGone_missing = false;
1311      (*missing_objs)[i]->restoreObject(obj);
1312      if (ch)
1313        ch->restoreObject(obj);
1314    }
1315    else
1316      missing_objs2->push_back((*missing_objs)[i]);
1317  }
1318
1319  Vector<afxConstraint*>* tmp = missing_objs;
1320  missing_objs = missing_objs2;
1321  missing_objs2 = tmp;
1322  missing_objs2->clear();
1323}
1324
1325void afxConstraintMgr::adjustProcessOrdering(afxChoreographer* ch)
1326{
1327  Vector<ProcessObject*> cons_sources;
1328
1329  // add choreographer to the list
1330  cons_sources.push_back(ch);
1331
1332  // collect all the ProcessObject related constraint sources
1333  for (S32 i = 0; i < mConstraints_v.size(); i++)
1334  {
1335    afxConstraintList* list = mConstraints_v[i];
1336    afxConstraint* cons = (*list)[0];
1337    if (cons)
1338    {
1339      ProcessObject* pobj = dynamic_cast<ProcessObject*>(cons->getSceneObject());
1340      if (pobj)
1341        cons_sources.push_back(pobj);
1342    }
1343  }
1344
1345  ProcessList* proc_list;
1346  if (ch->isServerObject())
1347    proc_list = ServerProcessList::get();
1348  else
1349    proc_list = ClientProcessList::get();
1350  if (!proc_list)
1351    return;
1352
1353  GameBase* nearest_to_end = dynamic_cast<GameBase*>(proc_list->findNearestToEnd(cons_sources));
1354  GameBase* chor = (GameBase*) ch;
1355
1356  // choreographer needs to be processed after the latest process object
1357  if (chor != nearest_to_end && nearest_to_end != 0)
1358  {
1359    //Con::printf("Choreographer processing BEFORE some of its constraints... fixing. [%s] -- %s",
1360    //   (ch->isServerObject()) ? "S" : "C", nearest_to_end->getClassName());
1361    if (chor->isProperlyAdded())
1362      ch->processAfter(nearest_to_end);
1363    else
1364      ch->postProcessAfterObject(nearest_to_end);
1365  }
1366  else
1367  {
1368    //Con::printf("Choreographer processing AFTER its constraints... fine. [%s]",
1369    //   (ch->isServerObject()) ? "S" : "C");
1370  }
1371}
1372
1373//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1374// afxPointConstraint
1375
1376afxPointConstraint::afxPointConstraint(afxConstraintMgr* mgr) 
1377  : afxConstraint(mgr)
1378{
1379  mPoint.zero();
1380  mVector.set(0,0,1);
1381}
1382
1383afxPointConstraint::~afxPointConstraint()
1384{
1385}
1386
1387void afxPointConstraint::set(Point3F point, Point3F vector)
1388{
1389  mPoint = point;
1390  mVector = vector;
1391  mIs_defined = true;
1392  mIs_valid = true;
1393  mChange_code++;
1394  sample(0.0f, 0, 0);
1395}
1396
1397void afxPointConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
1398{
1399  if (cam_pos)
1400  {
1401    Point3F dir = (*cam_pos) - mPoint;
1402    F32 dist_sq = dir.lenSquared();
1403    if (dist_sq > mMgr->getScopingDistanceSquared())
1404    {
1405      mIs_valid = false;
1406      return;
1407    }
1408    mIs_valid = true;
1409  }
1410
1411  mLast_pos = mPoint;
1412  mLast_xfm.identity();
1413  mLast_xfm.setPosition(mPoint);
1414}
1415
1416//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1417// afxTransformConstraint
1418
1419afxTransformConstraint::afxTransformConstraint(afxConstraintMgr* mgr) 
1420  : afxConstraint(mgr)
1421{
1422   mXfm.identity();
1423}
1424
1425afxTransformConstraint::~afxTransformConstraint()
1426{
1427}
1428
1429void afxTransformConstraint::set(const MatrixF& xfm)
1430{
1431  mXfm = xfm;
1432  mIs_defined = true;
1433  mIs_valid = true;
1434  mChange_code++;
1435  sample(0.0f, 0, 0);
1436}
1437
1438void afxTransformConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
1439{
1440  if (cam_pos)
1441  {
1442    Point3F dir = (*cam_pos) - mXfm.getPosition();
1443    F32 dist_sq = dir.lenSquared();
1444    if (dist_sq > mMgr->getScopingDistanceSquared())
1445    {
1446      mIs_valid = false;
1447      return;
1448    }
1449    mIs_valid = true;
1450  }
1451
1452  mLast_xfm = mXfm;
1453  mLast_pos = mXfm.getPosition();
1454}
1455
1456//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1457// afxShapeConstraint
1458
1459afxShapeConstraint::afxShapeConstraint(afxConstraintMgr* mgr) 
1460  : afxConstraint(mgr)
1461{
1462  mArb_name = ST_NULLSTRING;
1463  mShape = 0;
1464  mScope_id = 0;
1465  mClip_tag = 0;
1466  mLock_tag = 0;
1467}
1468
1469afxShapeConstraint::afxShapeConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name) 
1470  : afxConstraint(mgr)
1471{
1472  mArb_name = arb_name;
1473  mShape = 0;
1474  mScope_id = 0;
1475  mClip_tag = 0;
1476  mLock_tag = 0;
1477}
1478
1479afxShapeConstraint::~afxShapeConstraint()
1480{
1481  if (mShape)
1482    clearNotify(mShape);
1483}
1484
1485void afxShapeConstraint::set(ShapeBase* shape)
1486{
1487  if (mShape)
1488  {
1489    mScope_id = 0;
1490    clearNotify(mShape);
1491    if (mClip_tag > 0)
1492      remapAnimation(mClip_tag, shape);
1493    if (mLock_tag > 0)
1494      unlockAnimation(mLock_tag);
1495  }
1496
1497  mShape = shape;
1498
1499  if (mShape)
1500  {
1501    deleteNotify(mShape);
1502    mScope_id = mShape->getScopeId();
1503  }
1504
1505  if (mShape != NULL)
1506  {
1507    mIs_defined = true;
1508    mIs_valid = true;
1509    mChange_code++;
1510    sample(0.0f, 0, 0);
1511  }
1512  else
1513    mIs_valid = false;
1514}
1515
1516void afxShapeConstraint::set_scope_id(U16 scope_id)
1517{
1518  if (mShape)
1519    clearNotify(mShape);
1520
1521  mShape = 0;
1522  mScope_id = scope_id;
1523
1524  mIs_defined = (mScope_id > 0);
1525  mIs_valid = false;
1526  mMgr->postMissingConstraintObject(this);
1527}
1528
1529void afxShapeConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
1530{
1531  if (mGone_missing)
1532    return;
1533
1534  if (mShape)
1535  {
1536    mLast_xfm = mShape->getRenderTransform();
1537    if (mCons_def.mPos_at_box_center)
1538      mLast_pos = mShape->getBoxCenter();
1539    else
1540      mLast_pos = mShape->getRenderPosition();
1541  }
1542}
1543
1544void afxShapeConstraint::restoreObject(SceneObject* obj) 
1545{ 
1546  if (mShape)
1547  {
1548    mScope_id = 0;
1549    clearNotify(mShape);
1550  }
1551
1552  mShape = (ShapeBase* )obj;
1553
1554  if (mShape)
1555  {
1556    deleteNotify(mShape);
1557    mScope_id = mShape->getScopeId();
1558  }
1559
1560  mIs_valid = (mShape != NULL);
1561}
1562
1563void afxShapeConstraint::onDeleteNotify(SimObject* obj)
1564{
1565  if (mShape == dynamic_cast<ShapeBase*>(obj))
1566  {
1567    mShape = 0;
1568    mIs_valid = false;
1569    if (mScope_id > 0)
1570      mMgr->postMissingConstraintObject(this, true);
1571  }
1572
1573  Parent::onDeleteNotify(obj);
1574}
1575
1576U32 afxShapeConstraint::setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim)
1577{
1578  if (!mShape)
1579    return 0;
1580
1581  if (mShape->isServerObject())
1582  {
1583    AIPlayer* ai_player = dynamic_cast<AIPlayer*>(mShape);
1584    if (ai_player && !ai_player->isBlendAnimation(clip))
1585    {
1586      ai_player->saveMoveState();
1587      ai_player->stopMove();
1588    }
1589  }
1590
1591  mClip_tag = mShape->playAnimation(clip, pos, rate, trans, false/*hold*/, true/*wait*/, is_death_anim);
1592  return mClip_tag;
1593}
1594
1595void afxShapeConstraint::remapAnimation(U32 tag, ShapeBase* other_shape)
1596{
1597  if (mClip_tag == 0)
1598    return;
1599
1600  if (!mShape)
1601    return;
1602
1603  if (!other_shape)
1604  {
1605    resetAnimation(tag);
1606    return;
1607  }
1608
1609  Con::errorf("remapAnimation -- Clip name, %s.", mShape->getLastClipName(tag));
1610
1611  if (mShape->isClientObject())
1612  {
1613    mShape->restoreAnimation(tag);
1614  }
1615  else
1616  {
1617    AIPlayer* ai_player = dynamic_cast<AIPlayer*>(mShape);
1618    if (ai_player)
1619      ai_player->restartMove(tag);
1620    else
1621      mShape->restoreAnimation(tag);
1622  }
1623
1624  mClip_tag = 0;
1625}
1626
1627void afxShapeConstraint::resetAnimation(U32 tag)
1628{
1629  if (mClip_tag == 0)
1630    return;
1631
1632  if (!mShape)
1633    return;
1634  
1635  if (mShape->isClientObject())
1636  {
1637    mShape->restoreAnimation(tag);
1638  }
1639  else
1640  {
1641    AIPlayer* ai_player = dynamic_cast<AIPlayer*>(mShape);
1642    if (ai_player)
1643      ai_player->restartMove(tag);
1644    else
1645      mShape->restoreAnimation(tag);
1646  }
1647
1648  if ((tag & 0x80000000) == 0 && tag == mClip_tag)
1649    mClip_tag = 0;
1650}
1651
1652U32 afxShapeConstraint::lockAnimation()
1653{
1654  if (!mShape)
1655    return 0;
1656
1657  mLock_tag = mShape->lockAnimation();
1658  return mLock_tag;
1659}
1660
1661void afxShapeConstraint::unlockAnimation(U32 tag)
1662{
1663  if (mLock_tag == 0)
1664    return;
1665
1666  if (!mShape)
1667    return;
1668  
1669  mShape->unlockAnimation(tag);
1670  mLock_tag = 0;
1671}
1672
1673F32 afxShapeConstraint::getAnimClipDuration(const char* clip)
1674{
1675  return (mShape) ? mShape->getAnimationDuration(clip) : 0.0f;
1676}
1677
1678S32 afxShapeConstraint::getDamageState()
1679{
1680  return (mShape) ? mShape->getDamageState() : -1;
1681}
1682
1683U32 afxShapeConstraint::getTriggers()
1684{
1685  return (mShape) ? mShape->getShapeInstance()->getTriggerStateMask() : 0;
1686}
1687
1688//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1689// afxShapeNodeConstraint
1690
1691afxShapeNodeConstraint::afxShapeNodeConstraint(afxConstraintMgr* mgr)  
1692  : afxShapeConstraint(mgr)
1693{
1694  mArb_node = ST_NULLSTRING;
1695  mShape_node_ID = -1;
1696}
1697
1698afxShapeNodeConstraint::afxShapeNodeConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name, StringTableEntry arb_node)
1699  : afxShapeConstraint(mgr, arb_name)
1700{
1701  mArb_node = arb_node;
1702  mShape_node_ID = -1;
1703}
1704
1705void afxShapeNodeConstraint::set(ShapeBase* shape)
1706{
1707  if (shape)
1708  {
1709    mShape_node_ID = shape->getShape()->findNode(mArb_node);
1710    if (mShape_node_ID == -1)
1711      Con::errorf("Failed to find node [%s]", mArb_node);
1712  }
1713  else
1714     mShape_node_ID = -1;
1715
1716  Parent::set(shape);
1717}
1718
1719void afxShapeNodeConstraint::set_scope_id(U16 scope_id)
1720{
1721   mShape_node_ID = -1;
1722  Parent::set_scope_id(scope_id);
1723}
1724
1725void afxShapeNodeConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
1726{
1727  if (mShape && mShape_node_ID != -1)
1728  {
1729    mLast_xfm = mShape->getRenderTransform();
1730    mLast_xfm.scale(mShape->getScale());
1731    mLast_xfm.mul(mShape->getShapeInstance()->mNodeTransforms[mShape_node_ID]);
1732    mLast_pos = mLast_xfm.getPosition();
1733  }
1734}
1735
1736void afxShapeNodeConstraint::restoreObject(SceneObject* obj) 
1737{ 
1738  ShapeBase* shape = dynamic_cast<ShapeBase*>(obj);
1739  if (shape)
1740  {
1741    mShape_node_ID = shape->getShape()->findNode(mArb_node);
1742    if (mShape_node_ID == -1)
1743      Con::errorf("Failed to find node [%s]", mArb_node);
1744  }
1745  else
1746    mShape_node_ID = -1;
1747  Parent::restoreObject(obj);
1748}
1749
1750void afxShapeNodeConstraint::onDeleteNotify(SimObject* obj)
1751{
1752  Parent::onDeleteNotify(obj);
1753}
1754
1755//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1756// afxObjectConstraint
1757
1758afxObjectConstraint::afxObjectConstraint(afxConstraintMgr* mgr) 
1759  : afxConstraint(mgr)
1760{
1761  mArb_name = ST_NULLSTRING;
1762  mObj = 0;
1763  mScope_id = 0;
1764  mIs_camera = false;
1765}
1766
1767afxObjectConstraint::afxObjectConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name) 
1768  : afxConstraint(mgr)
1769{
1770  mArb_name = arb_name;
1771  mObj = 0;
1772  mScope_id = 0;
1773  mIs_camera = false;
1774}
1775
1776afxObjectConstraint::~afxObjectConstraint()
1777{
1778  if (mObj)
1779    clearNotify(mObj);
1780}
1781
1782void afxObjectConstraint::set(SceneObject* obj)
1783{
1784  if (mObj)
1785  {
1786    mScope_id = 0;
1787    clearNotify(mObj);
1788  }
1789
1790  mObj = obj;
1791
1792  if (mObj)
1793  {
1794    deleteNotify(mObj);
1795   mScope_id = mObj->getScopeId();
1796  }
1797
1798  if (mObj != NULL)
1799  {
1800    mIs_camera = mObj->isCamera();
1801
1802    mIs_defined = true;
1803    mIs_valid = true;
1804    mChange_code++;
1805    sample(0.0f, 0, 0);
1806  }
1807  else
1808    mIs_valid = false;
1809}
1810
1811void afxObjectConstraint::set_scope_id(U16 scope_id)
1812{
1813  if (mObj)
1814    clearNotify(mObj);
1815
1816  mObj = 0;
1817  mScope_id = scope_id;
1818
1819  mIs_defined = (scope_id > 0);
1820  mIs_valid = false;
1821  mMgr->postMissingConstraintObject(this);
1822}
1823
1824void afxObjectConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
1825{
1826  if (mGone_missing)
1827    return;
1828
1829  if (mObj)
1830  {
1831    if (!mIs_camera && mCons_def.mTreat_as_camera && dynamic_cast<ShapeBase*>(mObj))
1832    {
1833      ShapeBase* cam_obj = (ShapeBase*) mObj;
1834      F32 pov = 1.0f;
1835      cam_obj->getCameraTransform(&pov, &mLast_xfm);
1836      mLast_xfm.getColumn(3, &mLast_pos);
1837    }
1838    else
1839    {
1840      mLast_xfm = mObj->getRenderTransform();
1841      if (mCons_def.mPos_at_box_center)
1842        mLast_pos = mObj->getBoxCenter();
1843      else
1844        mLast_pos = mObj->getRenderPosition();
1845    }
1846  }
1847}
1848
1849void afxObjectConstraint::restoreObject(SceneObject* obj)
1850{
1851  if (mObj)
1852  {
1853    mScope_id = 0;
1854    clearNotify(mObj);
1855  }
1856
1857  mObj = obj;
1858
1859  if (mObj)
1860  {
1861    deleteNotify(mObj);
1862    mScope_id = mObj->getScopeId();
1863  }
1864
1865  mIs_valid = (mObj != NULL);
1866}
1867
1868void afxObjectConstraint::onDeleteNotify(SimObject* obj)
1869{
1870  if (mObj == dynamic_cast<SceneObject*>(obj))
1871  {
1872    mObj = 0;
1873    mIs_valid = false;
1874    if (mScope_id > 0)
1875      mMgr->postMissingConstraintObject(this, true);
1876  }
1877
1878  Parent::onDeleteNotify(obj);
1879}
1880
1881U32 afxObjectConstraint::getTriggers()
1882{
1883  TSStatic* ts_static = dynamic_cast<TSStatic*>(mObj);
1884  if (ts_static)
1885  {
1886    TSShapeInstance* obj_inst = ts_static->getShapeInstance();
1887    return (obj_inst) ? obj_inst->getTriggerStateMask() : 0;
1888  }
1889
1890  ShapeBase* shape_base = dynamic_cast<ShapeBase*>(mObj);
1891  if (shape_base)
1892  {
1893    TSShapeInstance* obj_inst = shape_base->getShapeInstance();
1894    return (obj_inst) ? obj_inst->getTriggerStateMask() : 0;
1895  }
1896
1897  return 0;
1898}
1899
1900//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1901// afxEffectConstraint
1902
1903afxEffectConstraint::afxEffectConstraint(afxConstraintMgr* mgr) 
1904  : afxConstraint(mgr)
1905{
1906  mEffect_name = ST_NULLSTRING;
1907  mEffect = 0;
1908  mClip_tag = 0;
1909  mIs_death_clip = false;
1910  mLock_tag = 0;
1911}
1912
1913afxEffectConstraint::afxEffectConstraint(afxConstraintMgr* mgr, StringTableEntry effect_name) 
1914  : afxConstraint(mgr)
1915{
1916  mEffect_name = effect_name;
1917  mEffect = 0;
1918  mClip_tag = 0;
1919  mIs_death_clip = false;
1920  mLock_tag = 0;
1921}
1922
1923afxEffectConstraint::~afxEffectConstraint()
1924{
1925}
1926
1927bool afxEffectConstraint::getPosition(Point3F& pos, F32 hist) 
1928{ 
1929  if (!mEffect || !mEffect->inScope())
1930    return false;
1931 
1932  if (mCons_def.mPos_at_box_center)
1933    mEffect->getUpdatedBoxCenter(pos);
1934  else
1935    mEffect->getUpdatedPosition(pos);
1936  
1937  return true;
1938}
1939
1940bool afxEffectConstraint::getTransform(MatrixF& xfm, F32 hist) 
1941{ 
1942  if (!mEffect || !mEffect->inScope())
1943    return false;
1944  
1945  mEffect->getUpdatedTransform(xfm);
1946  return true;
1947}
1948
1949bool afxEffectConstraint::getAltitudes(F32& terrain_alt, F32& interior_alt) 
1950{ 
1951  if (!mEffect)
1952    return false;
1953  
1954  mEffect->getAltitudes(terrain_alt, interior_alt);
1955  return true;
1956}
1957
1958void afxEffectConstraint::set(afxEffectWrapper* effect)
1959{
1960  mEffect = effect;
1961
1962  if (mEffect != NULL)
1963  {
1964    mIs_defined = true;
1965    mIs_valid = true;
1966    mChange_code++;
1967  }
1968  else
1969    mIs_valid = false;
1970}
1971
1972U32 afxEffectConstraint::setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans, bool is_death_anim)
1973{
1974  return (mEffect) ? mEffect->setAnimClip(clip, pos, rate, trans) : 0;
1975}
1976
1977void afxEffectConstraint::resetAnimation(U32 tag)
1978{
1979  if (mEffect)
1980    mEffect->resetAnimation(tag);
1981}
1982
1983F32 afxEffectConstraint::getAnimClipDuration(const char* clip)
1984{
1985  return (mEffect) ? getAnimClipDuration(clip) : 0;
1986}
1987
1988U32 afxEffectConstraint::getTriggers()
1989{
1990  return (mEffect) ? mEffect->getTriggers() : 0;
1991}
1992
1993//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
1994// afxEffectNodeConstraint
1995
1996afxEffectNodeConstraint::afxEffectNodeConstraint(afxConstraintMgr* mgr) 
1997  : afxEffectConstraint(mgr)
1998{
1999  mEffect_node = ST_NULLSTRING;
2000  mEffect_node_ID = -1;
2001}
2002
2003afxEffectNodeConstraint::afxEffectNodeConstraint(afxConstraintMgr* mgr, StringTableEntry name, StringTableEntry node)
2004: afxEffectConstraint(mgr, name)
2005{
2006  mEffect_node = node;
2007  mEffect_node_ID = -1;
2008}
2009
2010
2011
2012bool afxEffectNodeConstraint::getPosition(Point3F& pos, F32 hist) 
2013{ 
2014  if (!mEffect || !mEffect->inScope())
2015    return false;
2016  
2017  TSShapeInstance* ts_shape_inst = mEffect->getTSShapeInstance();
2018  if (!ts_shape_inst)
2019    return false;
2020
2021  if (mEffect_node_ID == -1)
2022  {
2023    TSShape* ts_shape = mEffect->getTSShape();
2024   mEffect_node_ID = (ts_shape) ? ts_shape->findNode(mEffect_node) : -1;
2025  }
2026
2027  if (mEffect_node_ID == -1)
2028    return false;
2029
2030  mEffect->getUpdatedTransform(mLast_xfm);
2031
2032  Point3F scale;
2033  mEffect->getUpdatedScale(scale);
2034
2035  MatrixF gag = ts_shape_inst->mNodeTransforms[mEffect_node_ID];
2036  gag.setPosition( gag.getPosition()*scale );
2037
2038  MatrixF xfm;
2039  xfm.mul(mLast_xfm, gag);
2040  //
2041  pos = xfm.getPosition();
2042
2043  return true;
2044}
2045
2046bool afxEffectNodeConstraint::getTransform(MatrixF& xfm, F32 hist) 
2047{ 
2048  if (!mEffect || !mEffect->inScope())
2049    return false;
2050  
2051  TSShapeInstance* ts_shape_inst = mEffect->getTSShapeInstance();
2052  if (!ts_shape_inst)
2053    return false;
2054
2055  if (mEffect_node_ID == -1)
2056  {
2057    TSShape* ts_shape = mEffect->getTSShape();
2058   mEffect_node_ID = (ts_shape) ? ts_shape->findNode(mEffect_node) : -1;
2059  }
2060
2061  if (mEffect_node_ID == -1)
2062    return false;
2063
2064  mEffect->getUpdatedTransform(mLast_xfm);
2065
2066  Point3F scale;
2067  mEffect->getUpdatedScale(scale);
2068
2069  MatrixF gag = ts_shape_inst->mNodeTransforms[mEffect_node_ID];
2070  gag.setPosition( gag.getPosition()*scale );
2071
2072  xfm.mul(mLast_xfm, gag);
2073
2074  return true;
2075}
2076
2077void afxEffectNodeConstraint::set(afxEffectWrapper* effect)
2078{
2079  if (effect)
2080  {
2081    TSShape* ts_shape = effect->getTSShape();
2082   mEffect_node_ID = (ts_shape) ? ts_shape->findNode(mEffect_node) : -1;
2083  }
2084  else
2085    mEffect_node_ID = -1;
2086
2087  Parent::set(effect);
2088}
2089
2090//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2091// afxSampleBuffer
2092
2093afxSampleBuffer::afxSampleBuffer()
2094{
2095  mBuffer_sz = 0;
2096  mBuffer_ms = 0;
2097  mMS_per_sample = 33;
2098  mElapsed_ms = 0;
2099  mLast_sample_ms = 0;
2100  mNext_sample_num = 0;
2101  mNum_samples = 0;
2102}
2103
2104afxSampleBuffer::~afxSampleBuffer()
2105{
2106}
2107
2108void afxSampleBuffer::configHistory(F32 hist_len, U8 sample_rate)
2109{
2110  mBuffer_sz = mCeil(hist_len*sample_rate) + 1;
2111  mMS_per_sample = mCeil(1000.0f/sample_rate);
2112  mBuffer_ms = mBuffer_sz*mMS_per_sample;
2113}
2114
2115void afxSampleBuffer::recordSample(F32 dt, U32 elapsed_ms, void* data)
2116{
2117  mElapsed_ms = elapsed_ms;
2118
2119  if (!data)
2120    return;
2121
2122  U32 now_sample_num = elapsed_ms/<a href="/coding/class/classafxsamplebuffer/#classafxsamplebuffer_1a366a1ad057f2e72aa3743bd7303454e0">mMS_per_sample</a>;
2123  if (mNext_sample_num <= now_sample_num)
2124  {
2125    mLast_sample_ms = elapsed_ms;
2126    while (mNext_sample_num <= now_sample_num)
2127    {
2128      recSample(mNext_sample_num % mBuffer_sz, data);
2129      mNext_sample_num++;
2130      mNum_samples++;
2131    }
2132  }
2133}
2134
2135inline bool afxSampleBuffer::compute_idx_from_lag(F32 lag, U32& idx) 
2136{ 
2137  bool in_bounds = true;
2138
2139  U32 lag_ms = lag*1000.0f;
2140  U32 rec_ms = (mElapsed_ms < mBuffer_ms) ? mElapsed_ms : mBuffer_ms;
2141  if (lag_ms > rec_ms)
2142  {
2143    // hasn't produced enough history
2144    lag_ms = rec_ms;
2145    in_bounds = false;
2146  }
2147
2148  U32 latest_sample_num = mLast_sample_ms/<a href="/coding/class/classafxsamplebuffer/#classafxsamplebuffer_1a366a1ad057f2e72aa3743bd7303454e0">mMS_per_sample</a>;
2149  U32 then_sample_num = (mElapsed_ms - lag_ms)/<a href="/coding/class/classafxsamplebuffer/#classafxsamplebuffer_1a366a1ad057f2e72aa3743bd7303454e0">mMS_per_sample</a>;
2150
2151  if (then_sample_num > latest_sample_num)
2152  {
2153    // latest sample is older than lag
2154    then_sample_num = latest_sample_num;
2155    in_bounds = false;
2156  }
2157
2158  idx = then_sample_num % mBuffer_sz;
2159  return in_bounds;
2160}
2161
2162inline bool afxSampleBuffer::compute_idx_from_lag(F32 lag, U32& idx1, U32& idx2, F32& t) 
2163{ 
2164  bool in_bounds = true;
2165
2166  F32 lag_ms = lag*1000.0f;
2167  F32 rec_ms = (mElapsed_ms < mBuffer_ms) ? mElapsed_ms : mBuffer_ms;
2168  if (lag_ms > rec_ms)
2169  {
2170    // hasn't produced enough history
2171    lag_ms = rec_ms;
2172    in_bounds = false;
2173  }
2174
2175  F32 per_samp = mMS_per_sample;
2176  F32 latest_sample_num = mLast_sample_ms/per_samp;
2177  F32 then_sample_num = (mElapsed_ms - lag_ms)/per_samp;
2178
2179  U32 latest_sample_num_i = latest_sample_num;
2180  U32 then_sample_num_i = then_sample_num;
2181
2182  if (then_sample_num_i >= latest_sample_num_i)
2183  {
2184    if (latest_sample_num_i < then_sample_num_i)
2185      in_bounds = false;
2186    t = 0.0;
2187    idx1 = then_sample_num_i % mBuffer_sz;
2188    idx2 = idx1;
2189  }
2190  else
2191  {
2192    t = then_sample_num - then_sample_num_i;
2193    idx1 = then_sample_num_i % mBuffer_sz;
2194    idx2 = (then_sample_num_i+1) % mBuffer_sz;
2195  }
2196
2197  return in_bounds;
2198}
2199
2200//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2201// afxSampleXfmBuffer
2202
2203afxSampleXfmBuffer::afxSampleXfmBuffer()
2204{
2205  mXfm_buffer = 0;
2206}
2207
2208afxSampleXfmBuffer::~afxSampleXfmBuffer()
2209{
2210  delete [] mXfm_buffer;
2211}
2212
2213void afxSampleXfmBuffer::configHistory(F32 hist_len, U8 sample_rate)
2214{
2215  if (!mXfm_buffer)
2216  {
2217    afxSampleBuffer::configHistory(hist_len, sample_rate);
2218    if (mBuffer_sz > 0)
2219      mXfm_buffer = new MatrixF[mBuffer_sz];
2220  }  
2221}
2222
2223void afxSampleXfmBuffer::recSample(U32 idx, void* data)
2224{
2225  mXfm_buffer[idx] = *((MatrixF*)data);
2226}
2227
2228void afxSampleXfmBuffer::getSample(F32 lag, void* data, bool& in_bounds) 
2229{ 
2230  U32 idx1, idx2;
2231  F32 t;
2232  in_bounds = compute_idx_from_lag(lag, idx1, idx2, t);
2233
2234  if (idx1 == idx2)
2235  {
2236    MatrixF* m1 = &mXfm_buffer[idx1];
2237    *((MatrixF*)data) = *m1;
2238  }
2239  else
2240  {
2241    MatrixF* m1 = &mXfm_buffer[idx1];
2242    MatrixF* m2 = &mXfm_buffer[idx2];
2243
2244    Point3F p1 = m1->getPosition();
2245    Point3F p2 = m2->getPosition();
2246    Point3F p; p.interpolate(p1, p2, t);
2247
2248    if (t < 0.5f)
2249      *((MatrixF*)data) = *m1;
2250    else
2251      *((MatrixF*)data) = *m2;
2252
2253    ((MatrixF*)data)->setPosition(p);
2254  }
2255}
2256
2257//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2258// afxPointHistConstraint
2259
2260afxPointHistConstraint::afxPointHistConstraint(afxConstraintMgr* mgr)
2261  : afxPointConstraint(mgr)
2262{
2263  mSamples = 0;
2264}
2265
2266afxPointHistConstraint::~afxPointHistConstraint()
2267{
2268  delete mSamples;
2269}
2270
2271void afxPointHistConstraint::set(Point3F point, Point3F vector)
2272{
2273  if (!mSamples)
2274  {
2275    mSamples = new afxSampleXfmBuffer;
2276   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2277  }
2278  
2279  Parent::set(point, vector);
2280}
2281
2282void afxPointHistConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
2283{
2284  Parent::sample(dt, elapsed_ms, cam_pos);
2285
2286  if (isDefined())
2287  {
2288    if (isValid())
2289      mSamples->recordSample(dt, elapsed_ms, &mLast_xfm);
2290    else
2291      mSamples->recordSample(dt, elapsed_ms, 0);
2292  }
2293}
2294
2295bool afxPointHistConstraint::getPosition(Point3F& pos, F32 hist) 
2296{ 
2297  bool in_bounds;
2298
2299  MatrixF xfm;
2300  mSamples->getSample(hist, &xfm, in_bounds);
2301
2302  pos = xfm.getPosition();
2303
2304  return in_bounds;
2305}
2306
2307bool afxPointHistConstraint::getTransform(MatrixF& xfm, F32 hist) 
2308{ 
2309  bool in_bounds;
2310
2311  mSamples->getSample(hist, &xfm, in_bounds);
2312
2313  return in_bounds; 
2314}
2315
2316//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2317// afxPointHistConstraint
2318
2319afxTransformHistConstraint::afxTransformHistConstraint(afxConstraintMgr* mgr)
2320  : afxTransformConstraint(mgr)
2321{
2322  mSamples = 0;
2323}
2324
2325afxTransformHistConstraint::~afxTransformHistConstraint()
2326{
2327  delete mSamples;
2328}
2329
2330void afxTransformHistConstraint::set(const MatrixF& xfm)
2331{
2332  if (!mSamples)
2333  {
2334    mSamples = new afxSampleXfmBuffer;
2335   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2336  }
2337  
2338  Parent::set(xfm);
2339}
2340
2341void afxTransformHistConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
2342{
2343  Parent::sample(dt, elapsed_ms, cam_pos);
2344
2345  if (isDefined())
2346  {
2347    if (isValid())
2348      mSamples->recordSample(dt, elapsed_ms, &mLast_xfm);
2349    else
2350      mSamples->recordSample(dt, elapsed_ms, 0);
2351  }
2352}
2353
2354bool afxTransformHistConstraint::getPosition(Point3F& pos, F32 hist) 
2355{ 
2356  bool in_bounds;
2357
2358  MatrixF xfm;
2359  mSamples->getSample(hist, &xfm, in_bounds);
2360
2361  pos = xfm.getPosition();
2362
2363  return in_bounds;
2364}
2365
2366bool afxTransformHistConstraint::getTransform(MatrixF& xfm, F32 hist) 
2367{ 
2368  bool in_bounds;
2369
2370  mSamples->getSample(hist, &xfm, in_bounds);
2371
2372  return in_bounds; 
2373}
2374
2375//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2376// afxShapeHistConstraint
2377
2378afxShapeHistConstraint::afxShapeHistConstraint(afxConstraintMgr* mgr)
2379  : afxShapeConstraint(mgr)
2380{
2381  mSamples = 0;
2382}
2383
2384afxShapeHistConstraint::afxShapeHistConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name)
2385  : afxShapeConstraint(mgr, arb_name)
2386{
2387  mSamples = 0;
2388}
2389
2390afxShapeHistConstraint::~afxShapeHistConstraint()
2391{
2392  delete mSamples;
2393}
2394
2395void afxShapeHistConstraint::set(ShapeBase* shape)
2396{
2397  if (shape && !mSamples)
2398  {
2399    mSamples = new afxSampleXfmBuffer;
2400   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2401  }
2402  
2403  Parent::set(shape);
2404}
2405
2406void afxShapeHistConstraint::set_scope_id(U16 scope_id)
2407{
2408  if (scope_id > 0 && !mSamples)
2409  {
2410    mSamples = new afxSampleXfmBuffer;
2411   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2412  }
2413  
2414  Parent::set_scope_id(scope_id);
2415}
2416
2417void afxShapeHistConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
2418{
2419  Parent::sample(dt, elapsed_ms, cam_pos);
2420
2421  if (isDefined())
2422  {
2423    if (isValid())
2424      mSamples->recordSample(dt, elapsed_ms, &mLast_xfm);
2425    else
2426      mSamples->recordSample(dt, elapsed_ms, 0);
2427  }
2428}
2429
2430bool afxShapeHistConstraint::getPosition(Point3F& pos, F32 hist) 
2431{ 
2432  bool in_bounds;
2433
2434  MatrixF xfm;
2435  mSamples->getSample(hist, &xfm, in_bounds);
2436
2437  pos = xfm.getPosition();
2438
2439  return in_bounds;
2440}
2441
2442bool afxShapeHistConstraint::getTransform(MatrixF& xfm, F32 hist) 
2443{ 
2444  bool in_bounds;
2445
2446  mSamples->getSample(hist, &xfm, in_bounds);
2447
2448  return in_bounds; 
2449}
2450
2451void afxShapeHistConstraint::onDeleteNotify(SimObject* obj)
2452{
2453  Parent::onDeleteNotify(obj);
2454}
2455
2456//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2457// afxShapeNodeHistConstraint
2458
2459afxShapeNodeHistConstraint::afxShapeNodeHistConstraint(afxConstraintMgr* mgr)
2460  : afxShapeNodeConstraint(mgr)
2461{
2462  mSamples = 0;
2463}
2464
2465afxShapeNodeHistConstraint::afxShapeNodeHistConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name,
2466                                                       StringTableEntry arb_node)
2467  : afxShapeNodeConstraint(mgr, arb_name, arb_node)
2468{
2469  mSamples = 0;
2470}
2471
2472afxShapeNodeHistConstraint::~afxShapeNodeHistConstraint()
2473{
2474  delete mSamples;
2475}
2476
2477void afxShapeNodeHistConstraint::set(ShapeBase* shape)
2478{
2479  if (shape && !mSamples)
2480  {
2481    mSamples = new afxSampleXfmBuffer;
2482   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2483  }
2484  
2485  Parent::set(shape);
2486}
2487
2488void afxShapeNodeHistConstraint::set_scope_id(U16 scope_id)
2489{
2490  if (scope_id > 0 && !mSamples)
2491  {
2492    mSamples = new afxSampleXfmBuffer;
2493   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2494  }
2495  
2496  Parent::set_scope_id(scope_id);
2497}
2498
2499void afxShapeNodeHistConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
2500{
2501  Parent::sample(dt, elapsed_ms, cam_pos);
2502
2503  if (isDefined())
2504  {
2505    if (isValid())
2506      mSamples->recordSample(dt, elapsed_ms, &mLast_xfm);
2507    else
2508      mSamples->recordSample(dt, elapsed_ms, 0);
2509  }
2510}
2511
2512bool afxShapeNodeHistConstraint::getPosition(Point3F& pos, F32 hist) 
2513{ 
2514  bool in_bounds;
2515
2516  MatrixF xfm;
2517  mSamples->getSample(hist, &xfm, in_bounds);
2518
2519  pos = xfm.getPosition();
2520
2521  return in_bounds;
2522}
2523
2524bool afxShapeNodeHistConstraint::getTransform(MatrixF& xfm, F32 hist) 
2525{ 
2526  bool in_bounds;
2527
2528  mSamples->getSample(hist, &xfm, in_bounds);
2529
2530  return in_bounds; 
2531}
2532
2533void afxShapeNodeHistConstraint::onDeleteNotify(SimObject* obj)
2534{
2535  Parent::onDeleteNotify(obj);
2536}
2537
2538//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2539// afxObjectHistConstraint
2540
2541afxObjectHistConstraint::afxObjectHistConstraint(afxConstraintMgr* mgr)
2542  : afxObjectConstraint(mgr)
2543{
2544  mSamples = 0;
2545}
2546
2547afxObjectHistConstraint::afxObjectHistConstraint(afxConstraintMgr* mgr, StringTableEntry arb_name)
2548  : afxObjectConstraint(mgr, arb_name)
2549{
2550  mSamples = 0;
2551}
2552
2553afxObjectHistConstraint::~afxObjectHistConstraint()
2554{
2555  delete mSamples;
2556}
2557
2558void afxObjectHistConstraint::set(SceneObject* obj)
2559{
2560  if (obj && !mSamples)
2561  {
2562    mSamples = new afxSampleXfmBuffer;
2563   mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2564  }
2565  
2566  Parent::set(obj);
2567}
2568
2569void afxObjectHistConstraint::set_scope_id(U16 scope_id)
2570{
2571  if (scope_id > 0 && !mSamples)
2572  {
2573    mSamples = new afxSampleXfmBuffer;
2574    mSamples->configHistory(mCons_def.mHistory_time, mCons_def.mSample_rate);
2575  }
2576  
2577  Parent::set_scope_id(scope_id);
2578}
2579
2580void afxObjectHistConstraint::sample(F32 dt, U32 elapsed_ms, const Point3F* cam_pos)
2581{
2582  Parent::sample(dt, elapsed_ms, cam_pos);
2583
2584  if (isDefined())
2585  {
2586    if (isValid())
2587      mSamples->recordSample(dt, elapsed_ms, &mLast_xfm);
2588    else
2589      mSamples->recordSample(dt, elapsed_ms, 0);
2590  }
2591}
2592
2593bool afxObjectHistConstraint::getPosition(Point3F& pos, F32 hist) 
2594{ 
2595  bool in_bounds;
2596
2597  MatrixF xfm;
2598  mSamples->getSample(hist, &xfm, in_bounds);
2599
2600  pos = xfm.getPosition();
2601
2602  return in_bounds;
2603}
2604
2605bool afxObjectHistConstraint::getTransform(MatrixF& xfm, F32 hist) 
2606{ 
2607  bool in_bounds;
2608
2609  mSamples->getSample(hist, &xfm, in_bounds);
2610
2611  return in_bounds; 
2612}
2613
2614void afxObjectHistConstraint::onDeleteNotify(SimObject* obj)
2615{
2616  Parent::onDeleteNotify(obj);
2617}
2618
2619//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
2620
2621