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
00072 cParticle(cParticle * original) {
00073 if (original == NULL) {
00074 cParticle();
00075 return;
00076 }
00077 ori = original->ori;
00078 pos = original->pos;
00079 old = original->old;
00080 vel = original->vel;
00081 fce = original->fce;
00082 mass = original->mass;
00083 mass_inv = original->mass_inv;
00084 friction = original->friction;
00085 cwm2 = original->cwm2;
00086 fuel = original->fuel;
00087 timer = original->timer;
00088 spawn = original->spawn;
00089 target = original->target;
00090 radius = original->radius;
00091 sound = original->sound;
00092 texture = original->texture;
00093 type = original->type;
00094 data = original->data;
00095
00096 foreach(i, original->trail) {
00097 trail.push_back(new cParticle(*i));
00098 }
00099 }
00100
00102
00103 inline void applyGravityForce(float* gravity_m_per_s) {
00104 if (!finitef(mass_inv)) return;
00105 fce[0] += mass * gravity_m_per_s[0];
00106 fce[1] += mass * gravity_m_per_s[1];
00107 fce[2] += mass * gravity_m_per_s[2];
00108 }
00109
00111
00112 inline void applyFrictionForce(float dt) {
00113 if (friction == 0.0f) return;
00114 float c_step = friction / dt;
00115 fce[0] += -c_step * vel[0] * mass;
00116 fce[1] += -c_step * vel[1] * mass;
00117 fce[2] += -c_step * vel[2] * mass;
00118 }
00119
00121
00122 inline void applyAirdragForce(float density_kg_per_m3 = 1.204f) {
00123 if (cwm2 == 0.0f) return;
00124 const float p = density_kg_per_m3;
00125 float vx2 = vel[0] * vel[0];
00126 float vy2 = vel[1] * vel[1];
00127 float vz2 = vel[2] * vel[2];
00128 float velocity = sqrt(vx2 + vy2 + vz2);
00129 float velocity_inv = (velocity != 0) ? (1.0f / velocity) : (0.0f);
00130 float pstau = p * 0.5f * velocity * velocity;
00131 float F = cwm2 * pstau;
00132 fce[0] += F * -vel[0] * velocity_inv;
00133 fce[1] += F * -vel[1] * velocity_inv;
00134 fce[2] += F * -vel[2] * velocity_inv;
00135 }
00136
00148 inline void stepEuler(float dt, float damping = 0.01f) {
00149 cParticle::stepEuler(pos.data(), old.data(), vel.data(), fce.data(), mass_inv, dt, damping);
00150 }
00151
00167 static inline void stepEuler(float* pos, float* old, float* vel, float* fce, float mass_inv, float dt, float damping = 0.01f) {
00168 vel[0] *= (1.0f - damping);
00169 vel[1] *= (1.0f - damping);
00170 vel[2] *= (1.0f - damping);
00171 vel[0] += fce[0] * mass_inv;
00172 vel[1] += fce[1] * mass_inv;
00173 vel[2] += fce[2] * mass_inv;
00174 fce[0] = fce[1] = fce[2] = 0.0f;
00175 old[0] = pos[0];
00176 old[1] = pos[1];
00177 old[2] = pos[2];
00178 pos[0] += dt * vel[0];
00179 pos[1] += dt * vel[1];
00180 pos[2] += dt * vel[2];
00181 }
00182
00192 inline void stepVerlet(float dt_inv, float dt2, float damping = 0.01f) {
00193 cParticle::stepVerlet(pos.data(), old.data(), vel.data(), fce.data(), mass_inv, dt_inv, dt2, damping);
00194 }
00195
00209 static inline void stepVerlet(float* pos, float* old, float* vel, float* fce, float mass_inv, float dt_inv, float dt2, float damping = 0.01f) {
00210
00211 vel[0] = (pos[0] - old[0]) * dt_inv;
00212 vel[1] = (pos[1] - old[1]) * dt_inv;
00213 vel[2] = (pos[2] - old[2]) * dt_inv;
00214
00215 float acc[] = {
00216 fce[0] * mass_inv,
00217 fce[1] * mass_inv,
00218 fce[2] * mass_inv
00219 };
00220
00221 fce[0] = fce[1] = fce[2] = 0.0f;
00222
00223 float f = damping;
00224 float next[] = {
00225 (2.0f - f) * pos[0] - (1.0f - f) * old[0] + acc[0] * dt2,
00226 (2.0f - f) * pos[1] - (1.0f - f) * old[1] + acc[1] * dt2,
00227 (2.0f - f) * pos[2] - (1.0f - f) * old[2] + acc[2] * dt2
00228 };
00229 old[0] = pos[0];
00230 old[1] = pos[1];
00231 old[2] = pos[2];
00232 pos[0] = next[0];
00233 pos[1] = next[1];
00234 pos[2] = next[2];
00235 }
00236
00237 static inline float collideParticleWithSphere(float* particle3fv, float* center3fv, float radius, float* projection3fv) {
00238 float r2 = radius * radius;
00239 float dist[] = {
00240 center3fv[0] - particle3fv[0],
00241 center3fv[1] - particle3fv[1],
00242 center3fv[2] - particle3fv[2]
00243 };
00244
00245 float r2dist = dist[0] * dist[0] + dist[1] * dist[1] + dist[2] * dist[2];
00246 if (r2dist > r2) return 0;
00247
00248 float rdist = sqrt_(r2dist);
00249 float proj = (radius / rdist);
00250 projection3fv[0] = center3fv[0] + dist[0] * proj;
00251 projection3fv[1] = center3fv[1] + dist[1] * proj;
00252 projection3fv[2] = center3fv[2] + dist[2] * proj;
00253
00254 float depth = radius - rdist;
00255 return depth;
00256 }
00257
00258 static inline float collideParticleWithCylinder(float* particle3fv, float* base3fv, float radius, float height, float* projection3fv) {
00259 float r2 = radius * radius;
00260 float dist[] = {particle3fv[0] - base3fv[0], 0, particle3fv[2] - base3fv[2]};
00261
00262
00263 float r2dist = dist[0] * dist[0] + dist[2] * dist[2];
00264 if (r2dist > r2) return 0;
00265
00266
00267 float bottom = base3fv[1] - particle3fv[1];
00268 if (bottom > 0) return 0;
00269
00270
00271 float top = particle3fv[1] - (base3fv[1] + height);
00272 if (top > 0) return 0;
00273
00274 float rdist = sqrt_(r2dist);
00275 float side = rdist - radius;
00276
00277 bool top_or_bottom_not_side = top > side || bottom > side;
00278 bool top_not_bottom = top > bottom;
00279
00280 if (top_or_bottom_not_side) {
00281 if (top_not_bottom) {
00282 projection3fv[0] = particle3fv[0];
00283 projection3fv[1] = base3fv[1] + height;
00284 projection3fv[2] = particle3fv[2];
00285 return -top;
00286 } else {
00287 projection3fv[0] = particle3fv[0];
00288 projection3fv[1] = base3fv[1];
00289 projection3fv[2] = particle3fv[2];
00290 return -bottom;
00291 }
00292 } else {
00293 float proj = (radius / rdist);
00294 projection3fv[0] = base3fv[0] + dist[0] * proj;
00295 projection3fv[1] = particle3fv[1];
00296 projection3fv[2] = base3fv[2] + dist[2] * proj;
00297 return -side;
00298 }
00299 }
00300
00301 static inline float collideParticleWithAABB(float* particle3fv, float* min3fv, float* max3fv, float* projection3fv) {
00302 float dminmax[6];
00303 float* dmin = &dminmax[0];
00304 float* dmax = &dminmax[3];
00305 vector_sub(dmin, min3fv, particle3fv);
00306 vector_sub(dmax, particle3fv, max3fv);
00307 float maxval = -1000000;
00308 int maxidx = 0;
00309
00310 loopi(6) {
00311
00312 if (dminmax[i] > 0) return 0;
00313 if (dminmax[i] > maxval) {
00314 maxval = dminmax[i];
00315 maxidx = i;
00316 }
00317 }
00318
00319
00320 vector_cpy(projection3fv, particle3fv);
00321
00322 if (maxidx < 3) {
00323 projection3fv[maxidx] = min3fv[maxidx];
00324 } else {
00325 projection3fv[maxidx - 3] = max3fv[maxidx - 3];
00326 }
00327
00328 return -maxval;
00329 }
00330
00331 private:
00332
00333 static inline float sqrt_(float value) {
00334
00335
00336 if (value >= 1.0f && value < 9.0) {
00337
00338
00339 float guess = 1.0f + (value - 1.0f) * 0.45f;
00340 return 0.5f * (guess + value / guess);
00341 } else {
00342
00343
00344 return sqrt(value);
00345 }
00346 }
00347 };
00348
00349
00350 #endif
00351