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