Blender V2.61 - r43446

boids.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 by Janne Karhu.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <string.h>
00034 #include <math.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "DNA_object_force.h"
00039 #include "DNA_scene_types.h"
00040 
00041 #include "BLI_rand.h"
00042 #include "BLI_math.h"
00043 #include "BLI_blenlib.h"
00044 #include "BLI_kdtree.h"
00045 #include "BLI_utildefines.h"
00046 
00047 #include "BKE_collision.h"
00048 #include "BKE_effect.h"
00049 #include "BKE_boids.h"
00050 #include "BKE_particle.h"
00051 
00052 #include "BKE_modifier.h"
00053 
00054 #include "RNA_enum_types.h"
00055 
00056 typedef struct BoidValues {
00057     float max_speed, max_acc;
00058     float max_ave, min_speed;
00059     float personal_space, jump_speed;
00060 } BoidValues;
00061 
00062 static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
00063 
00064 static int rule_none(BoidRule *UNUSED(rule), BoidBrainData *UNUSED(data), BoidValues *UNUSED(val), ParticleData *UNUSED(pa))
00065 {
00066     return 0;
00067 }
00068 
00069 static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00070 {
00071     BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
00072     BoidSettings *boids = bbd->part->boids;
00073     BoidParticle *bpa = pa->boid;
00074     EffectedPoint epoint;
00075     ListBase *effectors = bbd->sim->psys->effectors;
00076     EffectorCache *cur, *eff = NULL;
00077     EffectorCache temp_eff;
00078     EffectorData efd, cur_efd;
00079     float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
00080     float priority = 0.0f, len = 0.0f;
00081     int ret = 0;
00082 
00083     pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
00084 
00085     /* first find out goal/predator with highest priority */
00086     if(effectors) for(cur = effectors->first; cur; cur=cur->next) {
00087         Object *eob = cur->ob;
00088         PartDeflect *pd = cur->pd;
00089 
00090         if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
00091             if(gabr->ob == eob) {
00092                 /* TODO: effectors with multiple points */
00093                 if(get_effector_data(cur, &efd, &epoint, 0)) {
00094                     if(cur->pd && cur->pd->forcefield == PFIELD_BOID)
00095                         priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
00096                     else
00097                         priority = 1.0;
00098 
00099                     eff = cur;
00100                 }
00101                 break;
00102             }
00103         }
00104         else if(rule->type == eBoidRuleType_Goal && eob == bpa->ground)
00105             ; /* skip current object */
00106         else if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(cur, &cur_efd, &epoint, 0)) {
00107             float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
00108 
00109             if(temp == 0.0f)
00110                 ; /* do nothing */
00111             else if(temp > priority) {
00112                 priority = temp;
00113                 eff = cur;
00114                 efd = cur_efd;
00115                 len = efd.distance;
00116             }
00117             /* choose closest object with same priority */
00118             else if(temp == priority && efd.distance < len) {
00119                 eff = cur;
00120                 efd = cur_efd;
00121                 len = efd.distance;
00122             }
00123         }
00124     }
00125 
00126     /* if the object doesn't have effector data we have to fake it */
00127     if(eff == NULL && gabr->ob) {
00128         memset(&temp_eff, 0, sizeof(EffectorCache));
00129         temp_eff.ob = gabr->ob;
00130         temp_eff.scene = bbd->sim->scene;
00131         eff = &temp_eff;
00132         get_effector_data(eff, &efd, &epoint, 0);
00133         priority = 1.0f;
00134     }
00135 
00136     /* then use that effector */
00137     if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
00138         Object *eob = eff->ob;
00139         PartDeflect *pd = eff->pd;
00140         float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
00141 
00142         if(gabr->options & BRULE_GOAL_AVOID_PREDICT) {
00143             /* estimate future location of target */
00144             get_effector_data(eff, &efd, &epoint, 1);
00145 
00146             mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
00147             add_v3_v3(efd.loc, efd.vel);
00148             sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc);
00149             efd.distance = len_v3(efd.vec_to_point);
00150         }
00151 
00152         if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) {
00153             if(!bbd->goal_ob || bbd->goal_priority < priority) {
00154                 bbd->goal_ob = eob;
00155                 copy_v3_v3(bbd->goal_co, efd.loc);
00156                 copy_v3_v3(bbd->goal_nor, efd.nor);
00157             }
00158         }
00159         else if(rule->type == eBoidRuleType_Avoid && bpa->data.mode == eBoidMode_Climbing &&
00160             priority > 2.0f * gabr->fear_factor) {
00161             /* detach from surface and try to fly away from danger */
00162             negate_v3_v3(efd.vec_to_point, bpa->gravity);
00163         }
00164 
00165         copy_v3_v3(bbd->wanted_co, efd.vec_to_point);
00166         mul_v3_fl(bbd->wanted_co, mul);
00167 
00168         bbd->wanted_speed = val->max_speed * priority;
00169 
00170         /* with goals factor is approach velocity factor */
00171         if(rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
00172             float len2 = 2.0f*len_v3(pa->prev_state.vel);
00173 
00174             surface *= pa->size * boids->height;
00175 
00176             if(len2 > 0.0f && efd.distance - surface < len2) {
00177                 len2 = (efd.distance - surface)/len2;
00178                 bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
00179             }
00180         }
00181 
00182         ret = 1;
00183     }
00184 
00185     return ret;
00186 }
00187 
00188 static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00189 {
00190     BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
00191     KDTreeNearest *ptn = NULL;
00192     ParticleTarget *pt;
00193     BoidParticle *bpa = pa->boid;
00194     ColliderCache *coll;
00195     float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
00196     float co1[3], vel1[3], co2[3], vel2[3];
00197     float  len, t, inp, t_min = 2.0f;
00198     int n, neighbors = 0, nearest = 0;
00199     int ret = 0;
00200 
00201     //check deflector objects first
00202     if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
00203         ParticleCollision col;
00204         BVHTreeRayHit hit;
00205         float radius = val->personal_space * pa->size, ray_dir[3];
00206 
00207         copy_v3_v3(col.co1, pa->prev_state.co);
00208         add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
00209         sub_v3_v3v3(ray_dir, col.co2, col.co1);
00210         mul_v3_fl(ray_dir, acbr->look_ahead);
00211         col.f = 0.0f;
00212         hit.index = -1;
00213         hit.dist = col.original_ray_length = len_v3(ray_dir);
00214 
00215         /* find out closest deflector object */
00216         for(coll = bbd->sim->colliders->first; coll; coll=coll->next) {
00217             /* don't check with current ground object */
00218             if(coll->ob == bpa->ground)
00219                 continue;
00220 
00221             col.current = coll->ob;
00222             col.md = coll->collmd;
00223 
00224             if(col.md && col.md->bvhtree)
00225                 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col);
00226         }
00227         /* then avoid that object */
00228         if(hit.index>=0) {
00229             t = hit.dist/col.original_ray_length;
00230 
00231             /* avoid head-on collision */
00232             if(dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
00233                 /* don't know why, but uneven range [0.0,1.0] */
00234                 /* works much better than even [-1.0,1.0] */
00235                 bbd->wanted_co[0] = BLI_frand();
00236                 bbd->wanted_co[1] = BLI_frand();
00237                 bbd->wanted_co[2] = BLI_frand();
00238             }
00239             else {
00240                 copy_v3_v3(bbd->wanted_co, col.pce.nor);
00241             }
00242 
00243             mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
00244 
00245             bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
00246             bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
00247 
00248             return 1;
00249         }
00250     }
00251 
00252     //check boids in own system
00253     if(acbr->options & BRULE_ACOLL_WITH_BOIDS)
00254     {
00255         neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
00256         if(neighbors > 1) for(n=1; n<neighbors; n++) {
00257             copy_v3_v3(co1, pa->prev_state.co);
00258             copy_v3_v3(vel1, pa->prev_state.vel);
00259             copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
00260             copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
00261 
00262             sub_v3_v3v3(loc, co1, co2);
00263 
00264             sub_v3_v3v3(vec, vel1, vel2);
00265             
00266             inp = dot_v3v3(vec,vec);
00267 
00268             /* velocities not parallel */
00269             if(inp != 0.0f) {
00270                 t = -dot_v3v3(loc, vec)/inp;
00271                 /* cpa is not too far in the future so investigate further */
00272                 if(t > 0.0f && t < t_min) {
00273                     madd_v3_v3fl(co1, vel1, t);
00274                     madd_v3_v3fl(co2, vel2, t);
00275                     
00276                     sub_v3_v3v3(vec, co2, co1);
00277 
00278                     len = normalize_v3(vec);
00279 
00280                     /* distance of cpa is close enough */
00281                     if(len < 2.0f * val->personal_space * pa->size) {
00282                         t_min = t;
00283 
00284                         mul_v3_fl(vec, len_v3(vel1));
00285                         mul_v3_fl(vec, (2.0f - t)/2.0f);
00286                         sub_v3_v3v3(bbd->wanted_co, vel1, vec);
00287                         bbd->wanted_speed = len_v3(bbd->wanted_co);
00288                         ret = 1;
00289                     }
00290                 }
00291             }
00292         }
00293     }
00294     if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00295 
00296     /* check boids in other systems */
00297     for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
00298         ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
00299 
00300         if(epsys) {
00301             neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
00302             if(neighbors > 0) for(n=0; n<neighbors; n++) {
00303                 copy_v3_v3(co1, pa->prev_state.co);
00304                 copy_v3_v3(vel1, pa->prev_state.vel);
00305                 copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
00306                 copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
00307 
00308                 sub_v3_v3v3(loc, co1, co2);
00309 
00310                 sub_v3_v3v3(vec, vel1, vel2);
00311                 
00312                 inp = dot_v3v3(vec,vec);
00313 
00314                 /* velocities not parallel */
00315                 if(inp != 0.0f) {
00316                     t = -dot_v3v3(loc, vec)/inp;
00317                     /* cpa is not too far in the future so investigate further */
00318                     if(t > 0.0f && t < t_min) {
00319                         madd_v3_v3fl(co1, vel1, t);
00320                         madd_v3_v3fl(co2, vel2, t);
00321                         
00322                         sub_v3_v3v3(vec, co2, co1);
00323 
00324                         len = normalize_v3(vec);
00325 
00326                         /* distance of cpa is close enough */
00327                         if(len < 2.0f * val->personal_space * pa->size) {
00328                             t_min = t;
00329 
00330                             mul_v3_fl(vec, len_v3(vel1));
00331                             mul_v3_fl(vec, (2.0f - t)/2.0f);
00332                             sub_v3_v3v3(bbd->wanted_co, vel1, vec);
00333                             bbd->wanted_speed = len_v3(bbd->wanted_co);
00334                             ret = 1;
00335                         }
00336                     }
00337                 }
00338             }
00339 
00340             if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00341         }
00342     }
00343 
00344 
00345     if(ptn && nearest==0)
00346         MEM_freeN(ptn);
00347 
00348     return ret;
00349 }
00350 static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00351 {
00352     KDTreeNearest *ptn = NULL;
00353     ParticleTarget *pt;
00354     float len = 2.0f * val->personal_space * pa->size + 1.0f;
00355     float vec[3] = {0.0f, 0.0f, 0.0f};
00356     int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
00357     int ret = 0;
00358 
00359     if(neighbors > 1 && ptn[1].dist!=0.0f) {
00360         sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
00361         mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
00362         add_v3_v3(bbd->wanted_co, vec);
00363         bbd->wanted_speed = val->max_speed;
00364         len = ptn[1].dist;
00365         ret = 1;
00366     }
00367     if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00368 
00369     /* check other boid systems */
00370     for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
00371         ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
00372 
00373         if(epsys) {
00374             neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
00375             
00376             if(neighbors > 0 && ptn[0].dist < len) {
00377                 sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
00378                 mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
00379                 add_v3_v3(bbd->wanted_co, vec);
00380                 bbd->wanted_speed = val->max_speed;
00381                 len = ptn[0].dist;
00382                 ret = 1;
00383             }
00384 
00385             if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00386         }
00387     }
00388     return ret;
00389 }
00390 static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa)
00391 {
00392     KDTreeNearest ptn[11];
00393     float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
00394     int neighbors = BLI_kdtree_find_n_nearest(bbd->sim->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn);
00395     int n;
00396     int ret = 0;
00397 
00398     if(neighbors > 1) {
00399         for(n=1; n<neighbors; n++) {
00400             add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
00401             add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
00402         }
00403 
00404         mul_v3_fl(loc, 1.0f/((float)neighbors - 1.0f));
00405         mul_v3_fl(vec, 1.0f/((float)neighbors - 1.0f));
00406 
00407         sub_v3_v3(loc, pa->prev_state.co);
00408         sub_v3_v3(vec, pa->prev_state.vel);
00409 
00410         add_v3_v3(bbd->wanted_co, vec);
00411         add_v3_v3(bbd->wanted_co, loc);
00412         bbd->wanted_speed = len_v3(bbd->wanted_co);
00413 
00414         ret = 1;
00415     }
00416     return ret;
00417 }
00418 static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00419 {
00420     BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
00421     float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
00422     float mul, len;
00423     int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
00424     int i, ret = 0, p = pa - bbd->sim->psys->particles;
00425 
00426     if(flbr->ob) {
00427         float vec2[3], t;
00428 
00429         /* first check we're not blocking the leader*/
00430         sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
00431         mul_v3_fl(vec, 1.0f/bbd->timestep);
00432 
00433         sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
00434 
00435         mul = dot_v3v3(vec, vec);
00436 
00437         /* leader is not moving */
00438         if(mul < 0.01f) {
00439             len = len_v3(loc);
00440             /* too close to leader */
00441             if(len < 2.0f * val->personal_space * pa->size) {
00442                 copy_v3_v3(bbd->wanted_co, loc);
00443                 bbd->wanted_speed = val->max_speed;
00444                 return 1;
00445             }
00446         }
00447         else {
00448             t = dot_v3v3(loc, vec)/mul;
00449 
00450             /* possible blocking of leader in near future */
00451             if(t > 0.0f && t < 3.0f) {
00452                 copy_v3_v3(vec2, vec);
00453                 mul_v3_fl(vec2, t);
00454 
00455                 sub_v3_v3v3(vec2, loc, vec2);
00456 
00457                 len = len_v3(vec2);
00458 
00459                 if(len < 2.0f * val->personal_space * pa->size) {
00460                     copy_v3_v3(bbd->wanted_co, vec2);
00461                     bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
00462                     return 1;
00463                 }
00464             }
00465         }
00466 
00467         /* not blocking so try to follow leader */
00468         if(p && flbr->options & BRULE_LEADER_IN_LINE) {
00469             copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
00470             copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
00471         }
00472         else {
00473             copy_v3_v3(loc, flbr->oloc);
00474             sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
00475             mul_v3_fl(vec, 1.0f/bbd->timestep);
00476         }
00477         
00478         /* fac is seconds behind leader */
00479         madd_v3_v3fl(loc, vec, -flbr->distance);
00480 
00481         sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
00482         bbd->wanted_speed = len_v3(bbd->wanted_co);
00483             
00484         ret = 1;
00485     }
00486     else if(p % n) {
00487         float vec2[3], t, t_min = 3.0f;
00488 
00489         /* first check we're not blocking any leaders */
00490         for(i = 0; i< bbd->sim->psys->totpart; i+=n){
00491             copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
00492 
00493             sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
00494 
00495             mul = dot_v3v3(vec, vec);
00496 
00497             /* leader is not moving */
00498             if(mul < 0.01f) {
00499                 len = len_v3(loc);
00500                 /* too close to leader */
00501                 if(len < 2.0f * val->personal_space * pa->size) {
00502                     copy_v3_v3(bbd->wanted_co, loc);
00503                     bbd->wanted_speed = val->max_speed;
00504                     return 1;
00505                 }
00506             }
00507             else {
00508                 t = dot_v3v3(loc, vec)/mul;
00509 
00510                 /* possible blocking of leader in near future */
00511                 if(t > 0.0f && t < t_min) {
00512                     copy_v3_v3(vec2, vec);
00513                     mul_v3_fl(vec2, t);
00514 
00515                     sub_v3_v3v3(vec2, loc, vec2);
00516 
00517                     len = len_v3(vec2);
00518 
00519                     if(len < 2.0f * val->personal_space * pa->size) {
00520                         t_min = t;
00521                         copy_v3_v3(bbd->wanted_co, loc);
00522                         bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
00523                         ret = 1;
00524                     }
00525                 }
00526             }
00527         }
00528 
00529         if(ret) return 1;
00530 
00531         /* not blocking so try to follow leader */
00532         if(flbr->options & BRULE_LEADER_IN_LINE) {
00533             copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
00534             copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
00535         }
00536         else {
00537             copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel);
00538             copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co);
00539         }
00540         
00541         /* fac is seconds behind leader */
00542         madd_v3_v3fl(loc, vec, -flbr->distance);
00543 
00544         sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
00545         bbd->wanted_speed = len_v3(bbd->wanted_co);
00546         
00547         ret = 1;
00548     }
00549 
00550     return ret;
00551 }
00552 static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00553 {
00554     BoidParticle *bpa = pa->boid;
00555     BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule;
00556     float vec[3] = {0.0f, 0.0f, 0.0f};
00557 
00558     if(asbr->wander > 0.0f) {
00559         /* abuse pa->r_ave for wandering */
00560         bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
00561         bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
00562         bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
00563 
00564         normalize_v3(bpa->wander);
00565 
00566         copy_v3_v3(vec, bpa->wander);
00567 
00568         mul_qt_v3(pa->prev_state.rot, vec);
00569 
00570         copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
00571 
00572         mul_v3_fl(bbd->wanted_co, 1.1f);
00573 
00574         add_v3_v3(bbd->wanted_co, vec);
00575 
00576         /* leveling */
00577         if(asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
00578             project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
00579             mul_v3_fl(vec, asbr->level);
00580             sub_v3_v3(bbd->wanted_co, vec);
00581         }
00582     }
00583     else {
00584         copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
00585 
00586         /* may happen at birth */
00587         if(dot_v2v2(bbd->wanted_co,bbd->wanted_co)==0.0f) {
00588             bbd->wanted_co[0] = 2.0f*(0.5f - BLI_frand());
00589             bbd->wanted_co[1] = 2.0f*(0.5f - BLI_frand());
00590             bbd->wanted_co[2] = 2.0f*(0.5f - BLI_frand());
00591         }
00592         
00593         /* leveling */
00594         if(asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
00595             project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
00596             mul_v3_fl(vec, asbr->level);
00597             sub_v3_v3(bbd->wanted_co, vec);
00598         }
00599 
00600     }
00601     bbd->wanted_speed = asbr->speed * val->max_speed;
00602     
00603     return 1;
00604 }
00605 static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
00606 {
00607     BoidRuleFight *fbr = (BoidRuleFight*)rule;
00608     KDTreeNearest *ptn = NULL;
00609     ParticleTarget *pt;
00610     ParticleData *epars;
00611     ParticleData *enemy_pa = NULL;
00612     BoidParticle *bpa;
00613     /* friends & enemies */
00614     float closest_enemy[3] = {0.0f,0.0f,0.0f};
00615     float closest_dist = fbr->distance + 1.0f;
00616     float f_strength = 0.0f, e_strength = 0.0f;
00617     float health = 0.0f;
00618     int n, ret = 0;
00619 
00620     /* calculate own group strength */
00621     int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
00622     for(n=0; n<neighbors; n++) {
00623         bpa = bbd->sim->psys->particles[ptn[n].index].boid;
00624         health += bpa->data.health;
00625     }
00626 
00627     f_strength += bbd->part->boids->strength * health;
00628 
00629     if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00630 
00631     /* add other friendlies and calculate enemy strength and find closest enemy */
00632     for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
00633         ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
00634         if(epsys) {
00635             epars = epsys->particles;
00636 
00637             neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
00638             
00639             health = 0.0f;
00640 
00641             for(n=0; n<neighbors; n++) {
00642                 bpa = epars[ptn[n].index].boid;
00643                 health += bpa->data.health;
00644 
00645                 if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
00646                     copy_v3_v3(closest_enemy, ptn[n].co);
00647                     closest_dist = ptn[n].dist;
00648                     enemy_pa = epars + ptn[n].index;
00649                 }
00650             }
00651             if(pt->mode==PTARGET_MODE_ENEMY)
00652                 e_strength += epsys->part->boids->strength * health;
00653             else if(pt->mode==PTARGET_MODE_FRIEND)
00654                 f_strength += epsys->part->boids->strength * health;
00655 
00656             if(ptn){ MEM_freeN(ptn); ptn=NULL; }
00657         }
00658     }
00659     /* decide action if enemy presence found */
00660     if(e_strength > 0.0f) {
00661         sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
00662 
00663         /* attack if in range */
00664         if(closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
00665             float damage = BLI_frand();
00666             float enemy_dir[3];
00667 
00668             normalize_v3_v3(enemy_dir, bbd->wanted_co);
00669 
00670             /* fight mode */
00671             bbd->wanted_speed = 0.0f;
00672 
00673             /* must face enemy to fight */
00674             if(dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) {
00675                 bpa = enemy_pa->boid;
00676                 bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
00677             }
00678         }
00679         else {
00680             /* approach mode */
00681             bbd->wanted_speed = val->max_speed;
00682         }
00683 
00684         /* check if boid doesn't want to fight */
00685         bpa = pa->boid;
00686         if(bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
00687             /* decide to flee */
00688             if(closest_dist < fbr->flee_distance * fbr->distance) {
00689                 negate_v3(bbd->wanted_co);
00690                 bbd->wanted_speed = val->max_speed;
00691             }
00692             else { /* wait for better odds */
00693                 bbd->wanted_speed = 0.0f;
00694             }
00695         }
00696 
00697         ret = 1;
00698     }
00699 
00700     return ret;
00701 }
00702 
00703 typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa);
00704 
00705 static boid_rule_cb boid_rules[] = {
00706     rule_none,
00707     rule_goal_avoid,
00708     rule_goal_avoid,
00709     rule_avoid_collision,
00710     rule_separate,
00711     rule_flock,
00712     rule_follow_leader,
00713     rule_average_speed,
00714     rule_fight,
00715     //rule_help,
00716     //rule_protect,
00717     //rule_hide,
00718     //rule_follow_path,
00719     //rule_follow_wall
00720 };
00721 
00722 static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
00723 {
00724     BoidParticle *bpa = pa->boid;
00725 
00726     if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
00727         val->max_speed = boids->land_max_speed * bpa->data.health/boids->health;
00728         val->max_acc = boids->land_max_acc * val->max_speed;
00729         val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health/boids->health;
00730         val->min_speed = 0.0f; /* no minimum speed on land */
00731         val->personal_space = boids->land_personal_space;
00732         val->jump_speed = boids->land_jump_speed * bpa->data.health/boids->health;
00733     }
00734     else {
00735         val->max_speed = boids->air_max_speed * bpa->data.health/boids->health;
00736         val->max_acc = boids->air_max_acc * val->max_speed;
00737         val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health/boids->health;
00738         val->min_speed = boids->air_min_speed * boids->air_max_speed;
00739         val->personal_space = boids->air_personal_space;
00740         val->jump_speed = 0.0f; /* no jumping in air */
00741     }
00742 }
00743 
00744 static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3])
00745 {
00746     BoidParticle *bpa = pa->boid;
00747 
00748     if(bpa->data.mode == eBoidMode_Climbing) {
00749         SurfaceModifierData *surmd = NULL;
00750         float x[3], v[3];
00751         
00752         surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface );
00753 
00754         /* take surface velocity into account */
00755         closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
00756         add_v3_v3(x, v);
00757 
00758         /* get actual position on surface */
00759         closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
00760 
00761         return bpa->ground;
00762     }
00763     else {
00764         float zvec[3] = {0.0f, 0.0f, 2000.0f};
00765         ParticleCollision col;
00766         ColliderCache *coll;
00767         BVHTreeRayHit hit;
00768         float radius = 0.0f, t, ray_dir[3];
00769 
00770         if(!bbd->sim->colliders)
00771             return NULL;
00772 
00773         /* first try to find below boid */
00774         copy_v3_v3(col.co1, pa->state.co);
00775         sub_v3_v3v3(col.co2, pa->state.co, zvec);
00776         sub_v3_v3v3(ray_dir, col.co2, col.co1);
00777         col.f = 0.0f;
00778         hit.index = -1;
00779         hit.dist = col.original_ray_length = len_v3(ray_dir);
00780         col.pce.inside = 0;
00781 
00782         for(coll = bbd->sim->colliders->first; coll; coll = coll->next){
00783             col.current = coll->ob;
00784             col.md = coll->collmd;
00785             col.fac1 = col.fac2 = 0.f;
00786 
00787             if(col.md && col.md->bvhtree)
00788                 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col);
00789         }
00790         /* then use that object */
00791         if(hit.index>=0) {
00792             t = hit.dist/col.original_ray_length;
00793             interp_v3_v3v3(ground_co, col.co1, col.co2, t);
00794             normalize_v3_v3(ground_nor, col.pce.nor);
00795             return col.hit;
00796         }
00797 
00798         /* couldn't find below, so find upmost deflector object */
00799         add_v3_v3v3(col.co1, pa->state.co, zvec);
00800         sub_v3_v3v3(col.co2, pa->state.co, zvec);
00801         sub_v3_v3(col.co2, zvec);
00802         sub_v3_v3v3(ray_dir, col.co2, col.co1);
00803         col.f = 0.0f;
00804         hit.index = -1;
00805         hit.dist = col.original_ray_length = len_v3(ray_dir);
00806 
00807         for(coll = bbd->sim->colliders->first; coll; coll = coll->next){
00808             col.current = coll->ob;
00809             col.md = coll->collmd;
00810 
00811             if(col.md && col.md->bvhtree)
00812                 BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col);
00813         }
00814         /* then use that object */
00815         if(hit.index>=0) {
00816             t = hit.dist/col.original_ray_length;
00817             interp_v3_v3v3(ground_co, col.co1, col.co2, t);
00818             normalize_v3_v3(ground_nor, col.pce.nor);
00819             return col.hit;
00820         }
00821 
00822         /* default to z=0 */
00823         copy_v3_v3(ground_co, pa->state.co);
00824         ground_co[2] = 0;
00825         ground_nor[0] = ground_nor[1] = 0.0f;
00826         ground_nor[2] = 1.0f;
00827         return NULL;
00828     }
00829 }
00830 static int boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
00831 {
00832     BoidParticle *bpa = pa->boid;
00833 
00834     if(rule==NULL)
00835         return 0;
00836     
00837     if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
00838         return 1;
00839     
00840     if(bpa->data.mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
00841         return 1;
00842 
00843     return 0;
00844 }
00845 void boids_precalc_rules(ParticleSettings *part, float cfra)
00846 {
00847     BoidState *state = part->boids->states.first;
00848     BoidRule *rule;
00849     for(; state; state=state->next) {
00850         for(rule = state->rules.first; rule; rule=rule->next) {
00851             if(rule->type==eBoidRuleType_FollowLeader) {
00852                 BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
00853 
00854                 if(flbr->ob && flbr->cfra != cfra) {
00855                     /* save object locations for velocity calculations */
00856                     copy_v3_v3(flbr->oloc, flbr->loc);
00857                     copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
00858                     flbr->cfra = cfra;
00859                 }
00860             }
00861         }
00862     }
00863 }
00864 static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
00865 {
00866     BoidParticle *bpa = pa->boid;
00867     float nor[3], vel[3];
00868     copy_v3_v3(nor, surface_nor);
00869 
00870     /* gather apparent gravity */
00871     madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
00872     normalize_v3(bpa->gravity);
00873 
00874     /* raise boid it's size from surface */
00875     mul_v3_fl(nor, pa->size * boids->height);
00876     add_v3_v3v3(pa->state.co, surface_co, nor);
00877 
00878     /* remove normal component from velocity */
00879     project_v3_v3v3(vel, pa->state.vel, surface_nor);
00880     sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
00881 }
00882 static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
00883 {
00884     float vec[3];
00885 
00886     sub_v3_v3v3(vec, boid_co, goal_co);
00887 
00888     return dot_v3v3(vec, goal_nor);
00889 }
00890 /* wanted_co is relative to boid location */
00891 static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
00892 {
00893     if(rule==NULL)
00894         return 0;
00895 
00896     if(boid_rule_applies(pa, bbd->part->boids, rule)==0)
00897         return 0;
00898 
00899     if(boid_rules[rule->type](rule, bbd, val, pa)==0)
00900         return 0;
00901 
00902     if(fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co, pa->prev_state.vel, fuzziness * len_v3(pa->prev_state.vel))==0)
00903         return 1;
00904     else
00905         return 0;
00906 }
00907 static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa)
00908 {
00909     BoidState *state = boids->states.first;
00910     BoidParticle *bpa = pa->boid;
00911 
00912     for(; state; state=state->next) {
00913         if(state->id==bpa->data.state_id)
00914             return state;
00915     }
00916 
00917     /* for some reason particle isn't at a valid state */
00918     state = boids->states.first;
00919     if(state)
00920         bpa->data.state_id = state->id;
00921 
00922     return state;
00923 }
00924 //static int boid_condition_is_true(BoidCondition *cond) {
00925 //  /* TODO */
00926 //  return 0;
00927 //}
00928 
00929 /* determines the velocity the boid wants to have */
00930 void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
00931 {
00932     BoidRule *rule;
00933     BoidSettings *boids = bbd->part->boids;
00934     BoidValues val;
00935     BoidState *state = get_boid_state(boids, pa);
00936     BoidParticle *bpa = pa->boid;
00937     ParticleSystem *psys = bbd->sim->psys;
00938     int rand;
00939     //BoidCondition *cond;
00940 
00941     if(bpa->data.health <= 0.0f) {
00942         pa->alive = PARS_DYING;
00943         pa->dietime = bbd->cfra;
00944         return;
00945     }
00946 
00947     //planned for near future
00948     //cond = state->conditions.first;
00949     //for(; cond; cond=cond->next) {
00950     //  if(boid_condition_is_true(cond)) {
00951     //      pa->boid->state_id = cond->state_id;
00952     //      state = get_boid_state(boids, pa);
00953     //      break; /* only first true condition is used */
00954     //  }
00955     //}
00956 
00957     bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
00958 
00959     /* create random seed for every particle & frame */
00960     rand = (int)(PSYS_FRAND(psys->seed + p) * 1000);
00961     rand = (int)(PSYS_FRAND((int)bbd->cfra + rand) * 1000);
00962 
00963     set_boid_values(&val, bbd->part->boids, pa);
00964 
00965     /* go through rules */
00966     switch(state->ruleset_type) {
00967         case eBoidRulesetType_Fuzzy:
00968         {
00969             for(rule = state->rules.first; rule; rule = rule->next) {
00970                 if(apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
00971                     break; /* only first nonzero rule that comes through fuzzy rule is applied */
00972             }
00973             break;
00974         }
00975         case eBoidRulesetType_Random:
00976         {
00977             /* use random rule for each particle (allways same for same particle though) */
00978             rule = BLI_findlink(&state->rules, rand % BLI_countlist(&state->rules));
00979 
00980             apply_boid_rule(bbd, rule, &val, pa, -1.0);
00981         }
00982         case eBoidRulesetType_Average:
00983         {
00984             float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
00985             int n = 0;
00986             for(rule = state->rules.first; rule; rule=rule->next) {
00987                 if(apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
00988                     add_v3_v3(wanted_co, bbd->wanted_co);
00989                     wanted_speed += bbd->wanted_speed;
00990                     n++;
00991                     bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
00992                 }
00993             }
00994 
00995             if(n > 1) {
00996                 mul_v3_fl(wanted_co, 1.0f/(float)n);
00997                 wanted_speed /= (float)n;
00998             }
00999 
01000             copy_v3_v3(bbd->wanted_co, wanted_co);
01001             bbd->wanted_speed = wanted_speed;
01002             break;
01003         }
01004 
01005     }
01006 
01007     /* decide on jumping & liftoff */
01008     if(bpa->data.mode == eBoidMode_OnLand) {
01009         /* fuzziness makes boids capable of misjudgement */
01010         float mul = 1.0f + state->rule_fuzziness;
01011         
01012         if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
01013             float cvel[3], dir[3];
01014 
01015             copy_v3_v3(dir, pa->prev_state.ave);
01016             normalize_v2(dir);
01017 
01018             copy_v3_v3(cvel, bbd->wanted_co);
01019             normalize_v2(cvel);
01020 
01021             if(dot_v2v2(cvel, dir) > 0.95f / mul)
01022                 bpa->data.mode = eBoidMode_Liftoff;
01023         }
01024         else if(val.jump_speed > 0.0f) {
01025             float jump_v[3];
01026             int jump = 0;
01027 
01028             /* jump to get to a location */
01029             if(bbd->wanted_co[2] > 0.0f) {
01030                 float cvel[3], dir[3];
01031                 float z_v, ground_v, cur_v;
01032                 float len;
01033 
01034                 copy_v3_v3(dir, pa->prev_state.ave);
01035                 normalize_v2(dir);
01036 
01037                 copy_v3_v3(cvel, bbd->wanted_co);
01038                 normalize_v2(cvel);
01039 
01040                 len = len_v2(pa->prev_state.vel);
01041 
01042                 /* first of all, are we going in a suitable direction? */
01043                 /* or at a suitably slow speed */
01044                 if(dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
01045                     /* try to reach goal at highest point of the parabolic path */
01046                     cur_v = len_v2(pa->prev_state.vel);
01047                     z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
01048                     ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);
01049 
01050                     len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);
01051 
01052                     if(len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
01053                         jump = 1;
01054 
01055                         len = MIN2(len, val.jump_speed);
01056 
01057                         copy_v3_v3(jump_v, dir);
01058                         jump_v[2] = z_v;
01059                         mul_v3_fl(jump_v, ground_v);
01060 
01061                         normalize_v3(jump_v);
01062                         mul_v3_fl(jump_v, len);
01063                         add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
01064                     }
01065                 }
01066             }
01067 
01068             /* jump to go faster */
01069             if(jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
01070                 
01071             }
01072 
01073             if(jump) {
01074                 copy_v3_v3(pa->prev_state.vel, jump_v);
01075                 bpa->data.mode = eBoidMode_Falling;
01076             }
01077         }
01078     }
01079 }
01080 /* tries to realize the wanted velocity taking all constraints into account */
01081 void boid_body(BoidBrainData *bbd, ParticleData *pa)
01082 {
01083     BoidSettings *boids = bbd->part->boids;
01084     BoidParticle *bpa = pa->boid;
01085     BoidValues val;
01086     EffectedPoint epoint;
01087     float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
01088     float dvec[3], bvec[3];
01089     float new_dir[3], new_speed;
01090     float old_dir[3], old_speed;
01091     float wanted_dir[3];
01092     float q[4], mat[3][3]; /* rotation */
01093     float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
01094     float force[3] = {0.0f, 0.0f, 0.0f};
01095     float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
01096 
01097     set_boid_values(&val, boids, pa);
01098 
01099     /* make sure there's something in new velocity, location & rotation */
01100     copy_particle_key(&pa->state,&pa->prev_state,0);
01101 
01102     if(bbd->part->flag & PART_SIZEMASS)
01103         pa_mass*=pa->size;
01104 
01105     /* if boids can't fly they fall to the ground */
01106     if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim))
01107         bpa->data.mode = eBoidMode_Falling;
01108 
01109     if(bpa->data.mode == eBoidMode_Falling) {
01110         /* Falling boids are only effected by gravity. */
01111         acc[2] = bbd->sim->scene->physics_settings.gravity[2];
01112     }
01113     else {
01114         /* figure out acceleration */
01115         float landing_level = 2.0f;
01116         float level = landing_level + 1.0f;
01117         float new_vel[3];
01118 
01119         if(bpa->data.mode == eBoidMode_Liftoff) {
01120             bpa->data.mode = eBoidMode_InAir;
01121             bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
01122         }
01123         else if(bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
01124             /* auto-leveling & landing if close to ground */
01125 
01126             bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
01127             
01128             /* level = how many particle sizes above ground */
01129             level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f;
01130 
01131             landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
01132 
01133             if(pa->prev_state.vel[2] < 0.0f) {
01134                 if(level < 1.0f) {
01135                     bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
01136                     bbd->wanted_speed = 0.0f;
01137                     bpa->data.mode = eBoidMode_Falling;
01138                 }
01139                 else if(level < landing_level) {
01140                     bbd->wanted_speed *= (level - 1.0f)/landing_level;
01141                     bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
01142                 }
01143             }
01144         }
01145 
01146         copy_v3_v3(old_dir, pa->prev_state.ave);
01147         new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
01148 
01149         /* first check if we have valid direction we want to go towards */
01150         if(new_speed == 0.0f) {
01151             copy_v3_v3(new_dir, old_dir);
01152         }
01153         else {
01154             float old_dir2[2], wanted_dir2[2], nor[3], angle;
01155             copy_v2_v2(old_dir2, old_dir);
01156             normalize_v2(old_dir2);
01157             copy_v2_v2(wanted_dir2, wanted_dir);
01158             normalize_v2(wanted_dir2);
01159 
01160             /* choose random direction to turn if wanted velocity */
01161             /* is directly behind regardless of z-coordinate */
01162             if(dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
01163                 wanted_dir[0] = 2.0f*(0.5f - BLI_frand());
01164                 wanted_dir[1] = 2.0f*(0.5f - BLI_frand());
01165                 wanted_dir[2] = 2.0f*(0.5f - BLI_frand());
01166                 normalize_v3(wanted_dir);
01167             }
01168 
01169             /* constrain direction with maximum angular velocity */
01170             angle = saacos(dot_v3v3(old_dir, wanted_dir));
01171             angle = MIN2(angle, val.max_ave);
01172 
01173             cross_v3_v3v3(nor, old_dir, wanted_dir);
01174             axis_angle_to_quat( q,nor, angle);
01175             copy_v3_v3(new_dir, old_dir);
01176             mul_qt_v3(q, new_dir);
01177             normalize_v3(new_dir);
01178 
01179             /* save direction in case resulting velocity too small */
01180             axis_angle_to_quat( q,nor, angle*dtime);
01181             copy_v3_v3(pa->state.ave, old_dir);
01182             mul_qt_v3(q, pa->state.ave);
01183             normalize_v3(pa->state.ave);
01184         }
01185 
01186         /* constrain speed with maximum acceleration */
01187         old_speed = len_v3(pa->prev_state.vel);
01188         
01189         if(bbd->wanted_speed < old_speed)
01190             new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
01191         else
01192             new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
01193 
01194         /* combine direction and speed */
01195         copy_v3_v3(new_vel, new_dir);
01196         mul_v3_fl(new_vel, new_speed);
01197 
01198         /* maintain minimum flying velocity if not landing */
01199         if(level >= landing_level) {
01200             float len2 = dot_v2v2(new_vel,new_vel);
01201             float root;
01202 
01203             len2 = MAX2(len2, val.min_speed*val.min_speed);
01204             root = sasqrt(new_speed*new_speed - len2);
01205 
01206             new_vel[2] = new_vel[2] < 0.0f ? -root : root;
01207 
01208             normalize_v2(new_vel);
01209             mul_v2_fl(new_vel, sasqrt(len2));
01210         }
01211 
01212         /* finally constrain speed to max speed */
01213         new_speed = normalize_v3(new_vel);
01214         mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));
01215 
01216         /* get acceleration from difference of velocities */
01217         sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
01218 
01219         /* break acceleration to components */
01220         project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
01221         sub_v3_v3v3(nor_acc, acc, tan_acc);
01222     }
01223 
01224     /* account for effectors */
01225     pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
01226     pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
01227 
01228     if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
01229         float length = normalize_v3(force);
01230 
01231         length = MAX2(0.0f, length - boids->land_stick_force);
01232 
01233         mul_v3_fl(force, length);
01234     }
01235     
01236     add_v3_v3(acc, force);
01237 
01238     /* store smoothed acceleration for nice banking etc. */
01239     madd_v3_v3fl(bpa->data.acc, acc, dtime);
01240     mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));
01241 
01242     /* integrate new location & velocity */
01243 
01244     /* by regarding the acceleration as a force at this stage we*/
01245     /* can get better control allthough it's a bit unphysical   */
01246     mul_v3_fl(acc, 1.0f/pa_mass);
01247 
01248     copy_v3_v3(dvec, acc);
01249     mul_v3_fl(dvec, dtime*dtime*0.5f);
01250     
01251     copy_v3_v3(bvec, pa->prev_state.vel);
01252     mul_v3_fl(bvec, dtime);
01253     add_v3_v3(dvec, bvec);
01254     add_v3_v3(pa->state.co, dvec);
01255 
01256     madd_v3_v3fl(pa->state.vel, acc, dtime);
01257 
01258     //if(bpa->data.mode != eBoidMode_InAir)
01259     bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
01260 
01261     /* change modes, constrain movement & keep track of down vector */
01262     switch(bpa->data.mode) {
01263         case eBoidMode_InAir:
01264         {
01265             float grav[3];
01266 
01267             grav[0]= 0.0f;
01268             grav[1]= 0.0f;
01269             grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
01270 
01271             /* don't take forward acceleration into account (better banking) */
01272             if(dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
01273                 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
01274                 sub_v3_v3v3(dvec, bpa->data.acc, dvec);
01275             }
01276             else {
01277                 copy_v3_v3(dvec, bpa->data.acc);
01278             }
01279 
01280             /* gather apparent gravity */
01281             madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
01282             normalize_v3(bpa->gravity);
01283 
01284             /* stick boid on goal when close enough */
01285             if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
01286                 bpa->data.mode = eBoidMode_Climbing;
01287                 bpa->ground = bbd->goal_ob;
01288                 boid_find_ground(bbd, pa, ground_co, ground_nor);
01289                 boid_climb(boids, pa, ground_co, ground_nor);
01290             }
01291             else if(pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
01292                 /* land boid when below ground */
01293                 if(boids->options & BOID_ALLOW_LAND) {
01294                     pa->state.co[2] = ground_co[2] + pa->size * boids->height;
01295                     pa->state.vel[2] = 0.0f;
01296                     bpa->data.mode = eBoidMode_OnLand;
01297                 }
01298                 /* fly above ground */
01299                 else if(bpa->ground) {
01300                     pa->state.co[2] = ground_co[2] + pa->size * boids->height;
01301                     pa->state.vel[2] = 0.0f;
01302                 }
01303             }
01304             break;
01305         }
01306         case eBoidMode_Falling:
01307         {
01308             float grav[3];
01309 
01310             grav[0]= 0.0f;
01311             grav[1]= 0.0f;
01312             grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
01313 
01314 
01315             /* gather apparent gravity */
01316             madd_v3_v3fl(bpa->gravity, grav, dtime);
01317             normalize_v3(bpa->gravity);
01318 
01319             if(boids->options & BOID_ALLOW_LAND) {
01320                 /* stick boid on goal when close enough */
01321                 if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
01322                     bpa->data.mode = eBoidMode_Climbing;
01323                     bpa->ground = bbd->goal_ob;
01324                     boid_find_ground(bbd, pa, ground_co, ground_nor);
01325                     boid_climb(boids, pa, ground_co, ground_nor);
01326                 }
01327                 /* land boid when really near ground */
01328                 else if(pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height){
01329                     pa->state.co[2] = ground_co[2] + pa->size * boids->height;
01330                     pa->state.vel[2] = 0.0f;
01331                     bpa->data.mode = eBoidMode_OnLand;
01332                 }
01333                 /* if we're falling, can fly and want to go upwards lets fly */
01334                 else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
01335                     bpa->data.mode = eBoidMode_InAir;
01336             }
01337             else
01338                 bpa->data.mode = eBoidMode_InAir;
01339             break;
01340         }
01341         case eBoidMode_Climbing:
01342         {
01343             boid_climb(boids, pa, ground_co, ground_nor);
01344             //float nor[3];
01345             //copy_v3_v3(nor, ground_nor);
01346 
01348             //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
01349             //normalize_v3(pa->r_ve);
01350 
01352             //mul_v3_fl(nor, pa->size * boids->height);
01353             //add_v3_v3v3(pa->state.co, ground_co, nor);
01354 
01356             //project_v3_v3v3(v, pa->state.vel, ground_nor);
01357             //sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
01358             break;
01359         }
01360         case eBoidMode_OnLand:
01361         {
01362             /* stick boid on goal when close enough */
01363             if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
01364                 bpa->data.mode = eBoidMode_Climbing;
01365                 bpa->ground = bbd->goal_ob;
01366                 boid_find_ground(bbd, pa, ground_co, ground_nor);
01367                 boid_climb(boids, pa, ground_co, ground_nor);
01368             }
01369             /* ground is too far away so boid falls */
01370             else if(pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height)
01371                 bpa->data.mode = eBoidMode_Falling;
01372             else {
01373                 /* constrain to surface */
01374                 pa->state.co[2] = ground_co[2] + pa->size * boids->height;
01375                 pa->state.vel[2] = 0.0f;
01376             }
01377 
01378             if(boids->banking > 0.0f) {
01379                 float grav[3];
01380                 /* Don't take gravity's strength in to account, */
01381                 /* otherwise amount of banking is hard to control. */
01382                 negate_v3_v3(grav, ground_nor);
01383 
01384                 project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
01385                 sub_v3_v3v3(dvec, bpa->data.acc, dvec);
01386 
01387                 /* gather apparent gravity */
01388                 madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
01389                 normalize_v3(bpa->gravity);
01390             }
01391             else {
01392                 /* gather negative surface normal */
01393                 madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
01394                 normalize_v3(bpa->gravity);
01395             }
01396             break;
01397         }
01398     }
01399 
01400     /* save direction to state.ave unless the boid is falling */
01401     /* (boids can't effect their direction when falling) */
01402     if(bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) {
01403         copy_v3_v3(pa->state.ave, pa->state.vel);
01404         pa->state.ave[2] *= bbd->part->boids->pitch;
01405         normalize_v3(pa->state.ave);
01406     }
01407 
01408     /* apply damping */
01409     if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing))
01410         mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);
01411 
01412     /* calculate rotation matrix based on forward & down vectors */
01413     if(bpa->data.mode == eBoidMode_InAir) {
01414         copy_v3_v3(mat[0], pa->state.ave);
01415 
01416         project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
01417         sub_v3_v3v3(mat[2], bpa->gravity, dvec);
01418         normalize_v3(mat[2]);
01419     }
01420     else {
01421         project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
01422         sub_v3_v3v3(mat[0], pa->state.ave, dvec);
01423         normalize_v3(mat[0]);
01424 
01425         copy_v3_v3(mat[2], bpa->gravity);
01426     }
01427     negate_v3(mat[2]);
01428     cross_v3_v3v3(mat[1], mat[2], mat[0]);
01429     
01430     /* apply rotation */
01431     mat3_to_quat_is_ok( q,mat);
01432     copy_qt_qt(pa->state.rot, q);
01433 }
01434 
01435 BoidRule *boid_new_rule(int type)
01436 {
01437     BoidRule *rule = NULL;
01438     if(type <= 0)
01439         return NULL;
01440 
01441     switch(type) {
01442         case eBoidRuleType_Goal:
01443         case eBoidRuleType_Avoid:
01444             rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid");
01445             break;
01446         case eBoidRuleType_AvoidCollision:
01447             rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision");
01448             ((BoidRuleAvoidCollision*)rule)->look_ahead = 2.0f;
01449             break;
01450         case eBoidRuleType_FollowLeader:
01451             rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader");
01452             ((BoidRuleFollowLeader*)rule)->distance = 1.0f;
01453             break;
01454         case eBoidRuleType_AverageSpeed:
01455             rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed");
01456             ((BoidRuleAverageSpeed*)rule)->speed = 0.5f;
01457             break;
01458         case eBoidRuleType_Fight:
01459             rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight");
01460             ((BoidRuleFight*)rule)->distance = 100.0f;
01461             ((BoidRuleFight*)rule)->flee_distance = 100.0f;
01462             break;
01463         default:
01464             rule = MEM_callocN(sizeof(BoidRule), "BoidRule");
01465             break;
01466     }
01467 
01468     rule->type = type;
01469     rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND;
01470     BLI_strncpy(rule->name, boidrule_type_items[type-1].name, sizeof(rule->name));
01471 
01472     return rule;
01473 }
01474 void boid_default_settings(BoidSettings *boids)
01475 {
01476     boids->air_max_speed = 10.0f;
01477     boids->air_max_acc = 0.5f;
01478     boids->air_max_ave = 0.5f;
01479     boids->air_personal_space = 1.0f;
01480 
01481     boids->land_max_speed = 5.0f;
01482     boids->land_max_acc = 0.5f;
01483     boids->land_max_ave = 0.5f;
01484     boids->land_personal_space = 1.0f;
01485 
01486     boids->options = BOID_ALLOW_FLIGHT;
01487 
01488     boids->landing_smoothness = 3.0f;
01489     boids->banking = 1.0f;
01490     boids->pitch = 1.0f;
01491     boids->height = 1.0f;
01492 
01493     boids->health = 1.0f;
01494     boids->accuracy = 1.0f;
01495     boids->aggression = 2.0f;
01496     boids->range = 1.0f;
01497     boids->strength = 0.1f;
01498 }
01499 
01500 BoidState *boid_new_state(BoidSettings *boids)
01501 {
01502     BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
01503 
01504     state->id = boids->last_state_id++;
01505     if(state->id)
01506         BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id);
01507     else
01508         strcpy(state->name, "State");
01509 
01510     state->rule_fuzziness = 0.5;
01511     state->volume = 1.0f;
01512     state->channels |= ~0;
01513 
01514     return state;
01515 }
01516 
01517 BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state)
01518 {
01519     BoidState *staten = MEM_dupallocN(state);
01520 
01521     BLI_duplicatelist(&staten->rules, &state->rules);
01522     BLI_duplicatelist(&staten->conditions, &state->conditions);
01523     BLI_duplicatelist(&staten->actions, &state->actions);
01524 
01525     staten->id = boids->last_state_id++;
01526 
01527     return staten;
01528 }
01529 void boid_free_settings(BoidSettings *boids)
01530 {
01531     if(boids) {
01532         BoidState *state = boids->states.first;
01533 
01534         for(; state; state=state->next) {
01535             BLI_freelistN(&state->rules);
01536             BLI_freelistN(&state->conditions);
01537             BLI_freelistN(&state->actions);
01538         }
01539 
01540         BLI_freelistN(&boids->states);
01541 
01542         MEM_freeN(boids);
01543     }
01544 }
01545 BoidSettings *boid_copy_settings(BoidSettings *boids)
01546 {
01547     BoidSettings *nboids = NULL;
01548 
01549     if(boids) {
01550         BoidState *state;
01551         BoidState *nstate;
01552 
01553         nboids = MEM_dupallocN(boids);
01554 
01555         BLI_duplicatelist(&nboids->states, &boids->states);
01556 
01557         state = boids->states.first;
01558         nstate = nboids->states.first;
01559         for(; state; state=state->next, nstate=nstate->next) {
01560             BLI_duplicatelist(&nstate->rules, &state->rules);
01561             BLI_duplicatelist(&nstate->conditions, &state->conditions);
01562             BLI_duplicatelist(&nstate->actions, &state->actions);
01563         }
01564     }
01565 
01566     return nboids;
01567 }
01568 BoidState *boid_get_current_state(BoidSettings *boids)
01569 {
01570     BoidState *state = boids->states.first;
01571 
01572     for(; state; state=state->next) {
01573         if(state->flag & BOIDSTATE_CURRENT)
01574             break;
01575     }
01576 
01577     return state;
01578 }
01579