00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef _CPARTICLE_H
00010 #define _CPARTICLE_H
00011
00012 #include <list>
00013 #include <vector>
00014 #include <math.h>
00015
00026 struct cParticle {
00028 std::vector<float> ori;
00030 std::vector<float> pos;
00032 std::vector<float> old;
00034 std::vector<float> vel;
00036 std::vector<float> fce;
00038 float mass;
00040 float mass_inv;
00042 float friction;
00044 float cwm2;
00046 float fuel;
00048 float timer;
00050 float spawn;
00052 OID target;
00054 float radius;
00056 unsigned int sound;
00058 unsigned int texture;
00060 int type;
00062 void* data;
00064 std::list<cParticle*> trail;
00065
00066 cParticle() :
00067 ori(4), pos(3), old(3), vel(3), fce(3),
00068 mass(1.0f), mass_inv(1.0f), friction(0.0f), cwm2(0.0f), fuel(1), timer(0),
00069 spawn(-1), target(0), radius(0), sound(-1), texture(-1), type(0), data(NULL) {
00070 }
00071
00073
00074 cParticle(cParticle * original) {
00075 if (original == NULL) {
00076 cParticle();
00077 return;
00078 }
00079 ori = original->ori;
00080 pos = original->pos;
00081 old = original->old;
00082 vel = original->vel;
00083 fce = original->fce;
00084 mass = original->mass;
00085 mass_inv = original->mass_inv;
00086 friction = original->friction;
00087 cwm2 = original->cwm2;
00088 fuel = original->fuel;
00089 timer = original->timer;
00090 spawn = original->spawn;
00091 target = original->target;
00092 radius = original->radius;
00093 sound = original->sound;
00094 texture = original->texture;
00095 type = original->type;
00096 data = original->data;
00097
00098 foreach(i, original->trail) {
00099 trail.push_back(new cParticle(*i));
00100 }
00101 }
00102
00104
00105 inline void applyGravityForce(float* gravity_m_per_s) {
00106 if (!finitef(mass_inv)) return;
00107 fce[0] += mass * gravity_m_per_s[0];
00108 fce[1] += mass * gravity_m_per_s[1];
00109 fce[2] += mass * gravity_m_per_s[2];
00110 }
00111
00113
00114 inline void applyFrictionForce(float dt) {
00115 if (friction == 0.0f) return;
00116 float c_step = friction / dt;
00117 fce[0] += -c_step * vel[0] * mass;
00118 fce[1] += -c_step * vel[1] * mass;
00119 fce[2] += -c_step * vel[2] * mass;
00120 }
00121
00123
00124 inline void applyAirdragForce(float density_kg_per_m3 = 1.204f) {
00125 if (cwm2 == 0.0f) return;
00126 const float p = density_kg_per_m3;
00127 float vx2 = vel[0] * vel[0];
00128 float vy2 = vel[1] * vel[1];
00129 float vz2 = vel[2] * vel[2];
00130 float velocity = sqrt(vx2 + vy2 + vz2);
00131 float velocity_inv = (velocity != 0) ? (1.0f / velocity) : (0.0f);
00132 float pstau = p * 0.5f * velocity * velocity;
00133 float F = cwm2 * pstau;
00134 fce[0] += F * -vel[0] * velocity_inv;
00135 fce[1] += F * -vel[1] * velocity_inv;
00136 fce[2] += F * -vel[2] * velocity_inv;
00137 }
00138
00140
00141 inline float applySpringForce(cParticle* other, float strength, float rest_length) {
00142 float* c = this->pos.data();
00143 float* p = other->pos.data();
00144 float cp[3] = {
00145 (p[0] - c[0]),
00146 (p[1] - c[1]),
00147 (p[2] - c[2])
00148 };
00149 float actual_length = sqrt(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2]);
00150
00151 float force = strength * (rest_length - actual_length) * -0.5f;
00152
00153 float force3[] = {cp[0] * force, cp[1] * force, cp[2] * force};
00154
00155 c[0] += force3[0] * this->mass_inv;
00156 c[1] += force3[1] * this->mass_inv;
00157 c[2] += force3[2] * this->mass_inv;
00158 p[0] -= force3[0] * other->mass_inv;
00159 p[1] -= force3[1] * other->mass_inv;
00160 p[2] -= force3[2] * other->mass_inv;
00161
00162 return force;
00163 }
00164
00176 inline void stepEuler(float dt, float damping = 0.01f) {
00177 cParticle::stepEuler(pos.data(), old.data(), vel.data(), fce.data(), mass_inv, dt, damping);
00178 }
00179
00195 static inline void stepEuler(float* pos, float* old, float* vel, float* fce, float mass_inv, float dt, float damping = 0.01f) {
00196 vel[0] *= (1.0f - damping);
00197 vel[1] *= (1.0f - damping);
00198 vel[2] *= (1.0f - damping);
00199 vel[0] += fce[0] * mass_inv;
00200 vel[1] += fce[1] * mass_inv;
00201 vel[2] += fce[2] * mass_inv;
00202 fce[0] = fce[1] = fce[2] = 0.0f;
00203 old[0] = pos[0];
00204 old[1] = pos[1];
00205 old[2] = pos[2];
00206 pos[0] += dt * vel[0];
00207 pos[1] += dt * vel[1];
00208 pos[2] += dt * vel[2];
00209 }
00210
00220 inline void stepVerlet(float dt_inv, float dt2, float damping = 0.01f) {
00221 cParticle::stepVerlet(pos.data(), old.data(), vel.data(), fce.data(), mass_inv, dt_inv, dt2, damping);
00222 }
00223
00237 static inline void stepVerlet(float* pos, float* old, float* vel, float* fce, float mass_inv, float dt_inv, float dt2, float damping = 0.01f) {
00238
00239 vel[0] = (pos[0] - old[0]) * dt_inv;
00240 vel[1] = (pos[1] - old[1]) * dt_inv;
00241 vel[2] = (pos[2] - old[2]) * dt_inv;
00242
00243 float acc[] = {
00244 fce[0] * mass_inv,
00245 fce[1] * mass_inv,
00246 fce[2] * mass_inv
00247 };
00248
00249 fce[0] = fce[1] = fce[2] = 0.0f;
00250
00251 float f = damping;
00252 float next[] = {
00253 (2.0f - f) * pos[0] - (1.0f - f) * old[0] + acc[0] * dt2,
00254 (2.0f - f) * pos[1] - (1.0f - f) * old[1] + acc[1] * dt2,
00255 (2.0f - f) * pos[2] - (1.0f - f) * old[2] + acc[2] * dt2
00256 };
00257 old[0] = pos[0];
00258 old[1] = pos[1];
00259 old[2] = pos[2];
00260 pos[0] = next[0];
00261 pos[1] = next[1];
00262 pos[2] = next[2];
00263 }
00264
00265 static inline float constrainParticleByStick(float* particle3fv, float* center3fv, float radius, float* projection3fv, float adjustment = 1.0f, float* centerprojection3fv = NULL) {
00266
00267 float cp[] = {
00268 particle3fv[0] - center3fv[0],
00269 particle3fv[1] - center3fv[1],
00270 particle3fv[2] - center3fv[2]
00271 };
00272
00273 float cp_len = sqrt_(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2]);
00274 float depth = (radius - cp_len);
00275 float norm_depth = (depth / cp_len) * adjustment;
00276
00277 projection3fv[0] = particle3fv[0] + cp[0] * norm_depth;
00278 projection3fv[1] = particle3fv[1] + cp[1] * norm_depth;
00279 projection3fv[2] = particle3fv[2] + cp[2] * norm_depth;
00280
00281
00282 if (centerprojection3fv != NULL) {
00283 centerprojection3fv[0] = center3fv[0] - cp[0] * norm_depth;
00284 centerprojection3fv[1] = center3fv[1] - cp[1] * norm_depth;
00285 centerprojection3fv[2] = center3fv[2] - cp[2] * norm_depth;
00286 }
00287
00288 return depth;
00289 }
00290
00291 static inline float constraintParticleBySphere(float* particle3fv, float* center3fv, float radius, float* projection3fv) {
00292 float r2 = radius * radius;
00293
00294 float cp[] = {
00295 particle3fv[0] - center3fv[0],
00296 particle3fv[1] - center3fv[1],
00297 particle3fv[2] - center3fv[2]
00298 };
00299
00300 float cp_len2 = cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2];
00301 if (cp_len2 > r2) return 0;
00302
00303 float cp_len = sqrt_(cp_len2);
00304 float depth = (radius - cp_len);
00305 float norm_offset = (depth / cp_len);
00306
00307 projection3fv[0] = particle3fv[0] + cp[0] * norm_offset;
00308 projection3fv[1] = particle3fv[1] + cp[1] * norm_offset;
00309 projection3fv[2] = particle3fv[2] + cp[2] * norm_offset;
00310
00311 return depth;
00312 }
00313
00314 static inline float constraintParticleByCylinder(float* particle3fv, float* base3fv, float radius, float height, float* projection3fv) {
00315 float r2 = radius * radius;
00316 float dist[] = {particle3fv[0] - base3fv[0], 0, particle3fv[2] - base3fv[2]};
00317
00318
00319 float r2dist = dist[0] * dist[0] + dist[2] * dist[2];
00320 if (r2dist > r2) return 0;
00321
00322
00323 float bottom = base3fv[1] - particle3fv[1];
00324 if (bottom > 0) return 0;
00325
00326
00327 float top = particle3fv[1] - (base3fv[1] + height);
00328 if (top > 0) return 0;
00329
00330 float rdist = sqrt_(r2dist);
00331 float side = rdist - radius;
00332
00333 bool top_or_bottom_not_side = top > side || bottom > side;
00334 bool top_not_bottom = top > bottom;
00335
00336 if (top_or_bottom_not_side) {
00337 if (top_not_bottom) {
00338 projection3fv[0] = particle3fv[0];
00339 projection3fv[1] = base3fv[1] + height;
00340 projection3fv[2] = particle3fv[2];
00341 return -top;
00342 } else {
00343 projection3fv[0] = particle3fv[0];
00344 projection3fv[1] = base3fv[1];
00345 projection3fv[2] = particle3fv[2];
00346 return -bottom;
00347 }
00348 } else {
00349 float proj = (radius / rdist);
00350 projection3fv[0] = base3fv[0] + dist[0] * proj;
00351 projection3fv[1] = particle3fv[1];
00352 projection3fv[2] = base3fv[2] + dist[2] * proj;
00353 return -side;
00354 }
00355 }
00356
00357 static inline float constraintParticleByAABB(float* particle3fv, float* min3fv, float* max3fv, float* projection3fv) {
00358 float dminmax[6];
00359 float* dmin = &dminmax[0];
00360 float* dmax = &dminmax[3];
00361 vector_sub(dmin, min3fv, particle3fv);
00362 vector_sub(dmax, particle3fv, max3fv);
00363 float maxval = -1000000;
00364 int maxidx = 0;
00365
00366 loopi(6) {
00367
00368 if (dminmax[i] > 0) return 0;
00369 if (dminmax[i] > maxval) {
00370 maxval = dminmax[i];
00371 maxidx = i;
00372 }
00373 }
00374
00375
00376 vector_cpy(projection3fv, particle3fv);
00377
00378 if (maxidx < 3) {
00379 projection3fv[maxidx] = min3fv[maxidx];
00380 } else {
00381 projection3fv[maxidx - 3] = max3fv[maxidx - 3];
00382 }
00383
00384 return -maxval;
00385 }
00386
00387 private:
00388
00389 static inline float sqrt_(float value) {
00390
00391
00392 if (value >= 1.0f && value < 9.0) {
00393
00394
00395 float guess = 1.0f + (value - 1.0f) * 0.45f;
00396 return 0.5f * (guess + value / guess);
00397 } else {
00398
00399
00400 return sqrt(value);
00401 }
00402 }
00403 };
00404
00405
00406 #endif
00407