00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <UT/UT_DSOVersion.h>
00029 #include <OP/OP_OperatorTable.h>
00030
00031 #include <CH/CH_LocalVariable.h>
00032 #include <PRM/PRM_Include.h>
00033 #include <CHOP/PRM_ChopShared.h>
00034 #include <CHOP/CHOP_VariableList.h>
00035
00036 #include <UT/UT_Interrupt.h>
00037 #include <UT/UT_IStream.h>
00038
00039 #include "CHOP_Spring.h"
00040
00041 using namespace HDK_Sample;
00042
00043 CHOP_SWITCHER(7, "Spring");
00044
00045 static PRM_Name names[] = {
00046 PRM_Name("springk", "Spring Constant"),
00047 PRM_Name("mass", "Mass"),
00048 PRM_Name("dampingk", "Damping Constant"),
00049 PRM_Name("method", "Input Effect"),
00050 PRM_Name("condfromchan", "Initial Conditions From Channel"),
00051 PRM_Name("initpos", "Initial Position"),
00052 PRM_Name("initspeed", "Initial Speed"),
00053 PRM_Name(0),
00054 };
00055
00056 static PRM_Name springMethodItems[] = {
00057 PRM_Name("disp", "Position"),
00058 PRM_Name("force", "Force"),
00059 PRM_Name(0),
00060 };
00061
00062 static PRM_ChoiceList springMethodMenu((PRM_ChoiceListType)
00063 (PRM_CHOICELIST_EXCLUSIVE |
00064 PRM_CHOICELIST_REPLACE),
00065 springMethodItems);
00066
00067 static PRM_Range springConstantRange(PRM_RANGE_RESTRICTED, 0.0,
00068 PRM_RANGE_UI, 1000.0);
00069
00070 static PRM_Range massRange(PRM_RANGE_UI, 0.1f,
00071 PRM_RANGE_UI, 10.0f);
00072
00073 static PRM_Range dampingConstantRange(PRM_RANGE_RESTRICTED, 0.0,
00074 PRM_RANGE_UI, 10.0);
00075
00076 static PRM_Range initDispRange(PRM_RANGE_UI, -10.0,
00077 PRM_RANGE_UI, 10.0);
00078
00079 static PRM_Range initVelRange(PRM_RANGE_UI, -100.0,
00080 PRM_RANGE_UI, 100.0);
00081
00082 static PRM_Default springConstantDefault(100.0);
00083 static PRM_Default massDefault(1.0);
00084 static PRM_Default dampingConstantDefault(1.0);
00085 static PRM_Default initDispDefault(0.0);
00086 static PRM_Default initVelDefault(0.0);
00087
00088 PRM_Template
00089 CHOP_Spring::myTemplateList[] =
00090 {
00091 PRM_Template(PRM_SWITCHER, 2, &PRMswitcherName, switcher),
00092
00093
00094 PRM_Template(PRM_FLT, 1, &names[0], &springConstantDefault, 0,
00095 &springConstantRange),
00096 PRM_Template(PRM_FLT, 1, &names[1], &massDefault, 0,
00097 &massRange),
00098 PRM_Template(PRM_FLT, 1, &names[2], &dampingConstantDefault, 0,
00099 &dampingConstantRange),
00100 PRM_Template(PRM_ORD, 1, &names[3], PRMzeroDefaults,
00101 &springMethodMenu),
00102 PRM_Template(PRM_TOGGLE, 1, &names[4], PRMoneDefaults),
00103 PRM_Template(PRM_FLT, 1, &names[5], &initDispDefault, 0,
00104 &initDispRange),
00105 PRM_Template(PRM_FLT, 1, &names[6], &initVelDefault, 0,
00106 &initVelRange),
00107 PRM_Template(),
00108 };
00109
00110 OP_TemplatePair CHOP_Spring::myTemplatePair(
00111 CHOP_Spring::myTemplateList, &CHOP_Node::myTemplatePair);
00112
00113 unsigned
00114 CHOP_Spring::disableParms()
00115 {
00116 unsigned changes = CHOP_Node::disableParms();
00117 bool grab = GRAB_INITIAL();
00118
00119 changes += enableParm("initpos", !grab);
00120 changes += enableParm("initspeed", !grab);
00121
00122 return changes;
00123 }
00124
00125
00126
00127 enum
00128 {
00129 VAR_C = 200,
00130 VAR_NC = 201
00131 };
00132 CH_LocalVariable
00133 CHOP_Spring::myVariableList[] = {
00134 { "C", VAR_C, 0 },
00135 { "NC", VAR_NC, 0 },
00136 { 0, 0, 0 }
00137 };
00138 OP_VariablePair CHOP_Spring::myVariablePair(
00139 CHOP_Spring::myVariableList, &CHOP_Node::myVariablePair);
00140
00141 float
00142 CHOP_Spring::getVariableValue(int index, int thread)
00143 {
00144 switch(index)
00145 {
00146 case VAR_C:
00147
00148
00149 myChannelDependent=1;
00150 return (float)my_C;
00151
00152 case VAR_NC:
00153 return (float)my_NC;
00154
00155 default:
00156 break;
00157 }
00158
00159 return CHOP_Node::getVariableValue(index, thread);
00160 }
00161
00162
00163
00164 OP_Node *
00165 CHOP_Spring::myConstructor(OP_Network *net,
00166 const char *name,
00167 OP_Operator *op)
00168 {
00169 return new CHOP_Spring(net, name, op);
00170 }
00171
00172
00173 CHOP_Spring::CHOP_Spring( OP_Network *net,
00174 const char *name,
00175 OP_Operator *op)
00176 : CHOP_Realtime(net, name, op)
00177 {
00178 myParmBase = getParmList()->getParmIndex( names[0].getToken() );
00179 mySteady = 0;
00180 }
00181
00182 CHOP_Spring::~CHOP_Spring()
00183 {
00184 }
00185
00186
00187 OP_ERROR
00188 CHOP_Spring::cookMyChop(OP_Context &context)
00189 {
00190 const CL_Clip *clip = 0;
00191 const CL_Track *track = 0;
00192 CL_Track *new_track = 0;
00193 int force_method;
00194 int i, j,length, num_tracks, animated_parms;
00195 float spring_constant;
00196 float d1,d2,f,inc,d;
00197 float mass;
00198 float damping_constant;
00199 float initial_displacement;
00200 float initial_velocity;
00201 float acc, vel;
00202 UT_Interrupt *boss;
00203 int stop;
00204 int count = 0xFFFF;
00205 bool grab_init = GRAB_INITIAL();
00206
00207
00208 clip = copyInput(context, 0, 0, 1);
00209 if (!clip)
00210 return error();
00211
00212 force_method = METHOD();
00213
00214
00215 my_NC = clip->getNumTracks();
00216 my_C= 0;
00217
00218
00219 myChannelDependent=0;
00220 spring_constant = SPRING_CONSTANT(context.myTime);
00221 mass = MASS(context.myTime);
00222 damping_constant = DAMPING_CONSTANT(context.myTime);
00223 animated_parms = myChannelDependent;
00224
00225 inc = 1.0F / myClip->getSampleRate();
00226
00227
00228
00229
00230 if(!grab_init)
00231 {
00232 initial_displacement = INITIAL_DISPLACEMENT(context.myTime);
00233 initial_velocity = INITIAL_VELOCITY(context.myTime);
00234 }
00235
00236
00237 if (error() >= UT_ERROR_ABORT)
00238 return error();
00239
00240
00241 if (mass < 0.001f)
00242 {
00243 mass = 0.001f;
00244 SET_MASS(context.myTime, mass);
00245 }
00246
00247
00248 boss = UTgetInterrupt();
00249 stop = 0;
00250 if(boss->opStart("Calculating Spring"))
00251 {
00252 if (clip)
00253 {
00254 num_tracks = clip->getNumTracks();
00255 length = clip->getTrackLength();
00256
00257
00258 for (i=0; i<num_tracks; i++)
00259 {
00260
00261 my_C = i;
00262
00263 track = clip->getTrack(i);
00264 new_track = myClip->getTrack(i);
00265
00266
00267 if (!isScoped(track->getName()))
00268 {
00269 *new_track = *track;
00270 continue;
00271 }
00272
00273 if(grab_init || animated_parms)
00274 {
00275
00276
00277 if(animated_parms)
00278 {
00279 spring_constant = SPRING_CONSTANT(context.myTime);
00280 mass = MASS(context.myTime);
00281 if (mass < 0.001f)
00282 mass = 0.001f;
00283 damping_constant = DAMPING_CONSTANT(context.myTime);
00284 }
00285
00286
00287
00288 if(grab_init)
00289 {
00290 initial_displacement = clip->evaluateSingle(track,0);
00291 initial_velocity=(clip->evaluateSingle(track,1) -
00292 initial_displacement);
00293 }
00294 }
00295
00296
00297 d1 = initial_displacement;
00298 d2 = d1 - initial_velocity * inc;
00299
00300 for(j=0; j<length; j++)
00301 {
00302
00303 if(count--==0 && boss->opInterrupt())
00304 {
00305 stop = 1;
00306 break;
00307 }
00308
00309
00310 f = track->getData()[j];
00311 if(!force_method)
00312 f *= spring_constant;
00313
00314 vel = (d1-d2) / inc;
00315
00316 acc = (f - vel*damping_constant - d1*spring_constant)/mass;
00317 vel += acc * inc;
00318 d = d1 + vel * inc;
00319
00320 new_track->getData()[j] = d;
00321
00322
00323 d2 = d1;
00324 d1 = d;
00325 }
00326
00327 if(stop || boss->opInterrupt())
00328 {
00329 stop = 1;
00330 break;
00331 }
00332 }
00333 }
00334 }
00335
00336 boss->opEnd();
00337
00338 return error();
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348 class ut_SpringData : public ut_RealtimeData
00349 {
00350 public:
00351 ut_SpringData(const char *name,float d,float v);
00352 virtual ~ut_SpringData() {}
00353
00354 float myDn1;
00355 float myDn2;
00356
00357 virtual bool loadStates(UT_IStream &is, int version);
00358 virtual int saveStates(ostream &os, int binary);
00359 };
00360
00361 ut_SpringData::ut_SpringData(const char *name, float d1, float d2)
00362 : ut_RealtimeData(name),
00363 myDn1(d1),
00364 myDn2(d2)
00365 {
00366 }
00367
00368 bool
00369 ut_SpringData::loadStates(UT_IStream &is, int version)
00370 {
00371 if (!ut_RealtimeData::loadStates(is, version))
00372 return false;
00373
00374 if (!is.read(&myDn1))
00375 return false;
00376 if (!is.read(&myDn2))
00377 return false;
00378 return true;
00379 }
00380
00381 int
00382 ut_SpringData::saveStates(ostream &os, int binary)
00383 {
00384 ut_RealtimeData::saveStates(os,binary);
00385
00386 if(binary)
00387 {
00388 UTwrite(os, &myDn1);
00389 UTwrite(os, &myDn2);
00390 }
00391 else
00392 {
00393 os << myDn1 << endl;
00394 os << myDn2 << endl;
00395 }
00396 return 1;
00397 }
00398
00399 int
00400 CHOP_Spring::isSteady() const
00401 {
00402
00403
00404
00405 return mySteady;
00406 }
00407
00408 OP_ERROR
00409 CHOP_Spring::cookMySlice(OP_Context &context, int start, int end)
00410 {
00411 const CL_Clip *clip = inputClip(0,context);
00412 const CL_Track *track = 0;
00413 CL_Track *new_track = 0;
00414 int force_method;
00415 int i, j;
00416 float spring_constant;
00417 float mass;
00418 float d1,d2,f,t,inc,d, acc,vel,oldp;
00419 float damping_constant;
00420 ut_SpringData *block;
00421 float delta;
00422 int animated_parms;
00423
00424 force_method = METHOD();
00425
00426 my_NC = clip->getNumTracks();
00427 my_C= 0;
00428
00429
00430 myChannelDependent=0;
00431 spring_constant = SPRING_CONSTANT(context.myTime);
00432 mass = MASS(context.myTime);
00433 damping_constant = DAMPING_CONSTANT(context.myTime);
00434 animated_parms = myChannelDependent;
00435 inc = 1.0F / myClip->getSampleRate();
00436
00437 if (mass < 0.001f)
00438 mass = 0.001f;
00439
00440 mySteady = 1;
00441
00442 for(i=0; i<myClip->getNumTracks(); i++)
00443 {
00444 my_C = i;
00445
00446 track = clip->getTrack(i);
00447 new_track = myClip->getTrack(i);
00448
00449
00450 if(!isScoped(new_track->getName()))
00451 {
00452 clip->evaluateTime(track,
00453 myClip->getTime(start+myClip->getStart()),
00454 myClip->getTime(end+myClip->getStart()),
00455 new_track->getData(), myClip->getTrackLength());
00456 continue;
00457 }
00458
00459
00460 if(animated_parms)
00461 {
00462 spring_constant = SPRING_CONSTANT(context.myTime);
00463 mass = MASS(context.myTime);
00464 if (mass < 0.001f)
00465 mass = 0.001f;
00466 damping_constant = DAMPING_CONSTANT(context.myTime);
00467 }
00468
00469
00470
00471
00472 block = (ut_SpringData *) getDataBlock(i);
00473
00474 d1 = block->myDn1;
00475 d2 = block->myDn2;
00476
00477
00478 for(j=0; j<myClip->getTrackLength(); j++)
00479 {
00480 t = myClip->getTime(myClip->getStart() + j);
00481 oldp = f = clip->evaluateSingleTime(track, t);
00482
00483
00484 if(!force_method)
00485 f *= spring_constant;
00486 else
00487 oldp /=spring_constant;
00488
00489 vel = (d1-d2) / inc;
00490
00491 acc = (f - vel*damping_constant - d1*spring_constant)/mass;
00492 vel += acc * inc;
00493 d = d1 + vel * inc;
00494
00495 delta = SYSabs(oldp - d);
00496 if (delta > 0.001)
00497 mySteady = 0;
00498
00499 new_track->getData()[j] = d;
00500
00501 d2 = d1;
00502 d1 = d;
00503 }
00504
00505
00506
00507 block->myDn1 = d1;
00508 block->myDn2 = d2;
00509 }
00510
00511 return error();
00512 }
00513
00514 ut_RealtimeData *
00515 CHOP_Spring::newRealtimeDataBlock(const char *name,
00516 const CL_Track *track,
00517 float t)
00518 {
00519 float d, d1, v, rate;
00520
00521
00522
00523 if(GRAB_INITIAL() && track)
00524 {
00525 const CL_Clip *clip = track ? track->getClip() : 0;
00526
00527 d = clip->evaluateSingle(track,clip->getIndex(t));
00528 v = clip->evaluateSingle(track,clip->getIndex(t)+1) - d;
00529 }
00530 else
00531 {
00532 d = INITIAL_DISPLACEMENT(t);
00533 v = INITIAL_VELOCITY(t);
00534 }
00535
00536
00537
00538 rate = myClip->getSampleRate();
00539 if(rate != 0.0F)
00540 d1 = d - v/rate;
00541 else
00542 d1 = d;
00543
00544 return new ut_SpringData(name, d,d1);
00545 }
00546
00547
00548
00549 void newChopOperator(OP_OperatorTable *table)
00550 {
00551 table->addOperator(new OP_Operator("hdk_spring",
00552 "HDK Spring",
00553 CHOP_Spring::myConstructor,
00554 &CHOP_Spring::myTemplatePair,
00555 1,
00556 1,
00557 &CHOP_Spring::myVariablePair));
00558 }