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
00029 #include <UT/UT_DSOVersion.h>
00030
00031 #include <UT/UT_Math.h>
00032 #include <UT/UT_Interrupt.h>
00033 #include <UT/UT_Vector3.h>
00034 #include <UT/UT_Vector4.h>
00035
00036 #include <GEO/GEO_PrimPart.h>
00037
00038 #include <GU/GU_Detail.h>
00039 #include <GU/GU_RayIntersect.h>
00040
00041 #include <PRM/PRM_Include.h>
00042
00043 #include <OP/OP_Director.h>
00044 #include <OP/OP_Operator.h>
00045 #include <OP/OP_OperatorTable.h>
00046
00047 #include "SOP_SParticle.h"
00048
00049 using namespace HDK_Sample;
00050
00051 void
00052 newSopOperator(OP_OperatorTable *table)
00053 {
00054 table->addOperator(new OP_Operator("hdk_sparticle",
00055 "Simple Particle",
00056 SOP_SParticle::myConstructor,
00057 SOP_SParticle::myTemplateList,
00058 1,
00059 2,
00060 0));
00061 }
00062
00063
00064 static PRM_Name names[] = {
00065 PRM_Name("reset", "Reset Frame"),
00066 PRM_Name("birth", "Birth Rate"),
00067 PRM_Name("force", "Force"),
00068 };
00069
00070 static PRM_Default birthRate(10);
00071
00072 PRM_Template
00073 SOP_SParticle::myTemplateList[] = {
00074 PRM_Template(PRM_INT, 1, &names[0], PRMoneDefaults),
00075 PRM_Template(PRM_INT_J, 1, &names[1], &birthRate),
00076 PRM_Template(PRM_XYZ_J, 3, &names[2]),
00077 PRM_Template(),
00078 };
00079
00080 int *
00081 SOP_SParticle::myOffsets = 0;
00082
00083 OP_Node *
00084 SOP_SParticle::myConstructor(OP_Network *net, const char *name, OP_Operator *op)
00085 {
00086 return new SOP_SParticle(net, name, op);
00087 }
00088
00089 SOP_SParticle::SOP_SParticle(OP_Network *net, const char *name, OP_Operator *op)
00090 : SOP_Node(net, name, op)
00091 {
00092
00093
00094
00095 if (!myOffsets)
00096 myOffsets = allocIndirect(32);
00097
00098
00099 myVelocity = -1;
00100 }
00101
00102 SOP_SParticle::~SOP_SParticle() {}
00103
00104 unsigned
00105 SOP_SParticle::disableParms()
00106 {
00107 return 0;
00108 }
00109
00110 void
00111 SOP_SParticle::birthParticle()
00112 {
00113 const GEO_Point *src;
00114 GEO_Point *ppt;
00115 GEO_ParticleVertex *pvtx;
00116 float *life;
00117
00118 src = 0;
00119 pvtx = mySystem->giveBirth();
00120 if (mySource)
00121 {
00122 if (mySourceNum >= mySource->points().entries())
00123 mySourceNum = 0;
00124 if (mySource->points().entries() > 0)
00125 src = mySource->points()(mySourceNum);
00126 mySourceNum++;
00127 }
00128 if (src)
00129 {
00130 ppt = pvtx->getPt();
00131 ppt->getPos() = src->getPos();
00132 if (mySourceVel >= 0)
00133 {
00134 memcpy(ppt->castAttribData<UT_Vector3>(myVelocity),
00135 src->castAttribData<UT_Vector3>(mySourceVel), sizeof(UT_Vector3));
00136 }
00137 else memset(ppt->castAttribData<UT_Vector3>(myVelocity), 0, sizeof(UT_Vector3));
00138 }
00139 else
00140 {
00141 ppt = pvtx->getPt();
00142 ppt->getPos().assign(drand48()-.5, drand48()-.5, drand48()-.5, 1);
00143 memset(ppt->castAttribData<UT_Vector3>(myVelocity), 0, sizeof(UT_Vector3));
00144 }
00145 life = ppt->castAttribData<float>(myLife);
00146 life[0] = 0;
00147 life[1] = 30+30*drand48();
00148 }
00149
00150 int
00151 SOP_SParticle::moveParticle(GEO_ParticleVertex *pvtx, const UT_Vector3 &force)
00152 {
00153 float *life;
00154 float tinc;
00155 UT_Vector3 *vel, dir;
00156
00157 life = pvtx->getPt()->castAttribData<float>(myLife);
00158 life[0] += 1;
00159 if (life[0] >= life[1])
00160 return 0;
00161
00162 tinc = 1./30.;
00163
00164
00165
00166 vel = pvtx->getPt()->castAttribData<UT_Vector3>(myVelocity);
00167 vel->x() += tinc*force.x();
00168 vel->y() += tinc*force.y();
00169 vel->z() += tinc*force.z();
00170
00171
00172
00173 if (myCollision)
00174 {
00175 dir = *vel;
00176 dir *= tinc;
00177
00178
00179 GU_RayInfo info(dir.normalize());
00180 UT_Vector3 start;
00181
00182 start = pvtx->getPos();
00183 if (myCollision->sendRay(start, dir, info) > 0)
00184 return 0;
00185 }
00186
00187 pvtx->getPos().x() += tinc*vel->x();
00188 pvtx->getPos().y() += tinc*vel->y();
00189 pvtx->getPos().z() += tinc*vel->z();
00190
00191 return 1;
00192 }
00193
00194 void
00195 SOP_SParticle::timeStep(float now)
00196 {
00197 int i, nbirth;
00198 GEO_ParticleVertex *pvtx, *next = 0;
00199 UT_Vector3 force;
00200
00201 force.assign(FX(now), FY(now), FZ(now));
00202 nbirth = BIRTH(now);
00203
00204 if (error() >= UT_ERROR_ABORT)
00205 return;
00206
00207 for (i = nbirth; i >= 0; i--)
00208 birthParticle();
00209
00210 for (pvtx = mySystem->iterateInit(); pvtx; pvtx = next)
00211 {
00212 next = mySystem->iterateFastNext(pvtx);
00213 if (!moveParticle(pvtx, force))
00214 mySystem->deadParticle(pvtx);
00215 }
00216 }
00217
00218 void
00219 SOP_SParticle::initSystem()
00220 {
00221 if (!gdp) gdp = new GU_Detail;
00222
00223
00224 if (gdp->points().entries() > 0 || myVelocity < 0)
00225 {
00226 mySourceNum = 0;
00227 gdp->clearAndDestroy();
00228 mySystem = (GEO_PrimParticle *)gdp->appendPrimitive(GEOPRIMPART);
00229 mySystem->clearAndDestroy();
00230
00231
00232
00233 myVelocity = gdp->addPointAttrib("v", sizeof(UT_Vector3),
00234 GB_ATTRIB_VECTOR, 0);
00235 myLife = gdp->addPointAttrib("life", sizeof(float)*2,
00236 GB_ATTRIB_FLOAT, 0);
00237 }
00238 }
00239
00240 OP_ERROR
00241 SOP_SParticle::cookMySop(OP_Context &context)
00242 {
00243 float reset, currframe;
00244 CH_Manager *chman;
00245 const GU_Detail *collision;
00246
00247
00248
00249 if (lockInputs(context) >= UT_ERROR_ABORT)
00250 return error();
00251
00252
00253
00254 OP_Node::flags().timeDep = 1;
00255
00256 chman = OPgetDirector()->getChannelManager();
00257
00258
00259 currframe = chman->getSample(context.myTime);
00260 reset = RESET();
00261
00262 if (currframe <= reset)
00263 {
00264 myLastCookTime = reset;
00265 initSystem();
00266 }
00267 else
00268 {
00269
00270 collision = inputGeo(1, context);
00271 if (collision)
00272 {
00273 myCollision = new GU_RayIntersect;
00274 myCollision->init(collision);
00275 }
00276 else myCollision = 0;
00277
00278
00279 mySource = inputGeo(0, context);
00280 if (mySource)
00281 {
00282 mySourceVel = mySource->findPointAttrib("v", sizeof(UT_Vector3),
00283 GB_ATTRIB_VECTOR);
00284
00285
00286 if (mySourceVel < 0)
00287 mySourceVel = mySource->findPointAttrib("N", sizeof(UT_Vector3),
00288 GB_ATTRIB_VECTOR);
00289 }
00290
00291
00292
00293
00294 checkInputChanged(0, -1, myDetailGroupPair, (GU_Detail *)mySource, 0);
00295
00296
00297
00298
00299
00300 currframe += 0.05;
00301 while (myLastCookTime < currframe)
00302 {
00303
00304 timeStep(chman->getTime(myLastCookTime));
00305 myLastCookTime += 1;
00306 }
00307
00308 if (myCollision) delete myCollision;
00309
00310
00311
00312
00313 select(GU_SPoint);
00314 }
00315
00316 unlockInputs();
00317 return error();
00318 }
00319
00320 const char *
00321 SOP_SParticle::inputLabel(unsigned inum) const
00322 {
00323 switch (inum)
00324 {
00325 case 0: return "Particle Source Geometry";
00326 case 1: return "Collision Object";
00327 }
00328 return "Unknown source";
00329 }