Blender  V2.93
boids.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 by Janne Karhu.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_object_force_types.h"
30 #include "DNA_scene_types.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_kdtree.h"
34 #include "BLI_math.h"
35 #include "BLI_rand.h"
36 #include "BLI_utildefines.h"
37 
38 #include "BKE_boids.h"
39 #include "BKE_collision.h"
40 #include "BKE_effect.h"
41 #include "BKE_particle.h"
42 #include "BLI_kdopbvh.h"
43 
44 #include "BKE_modifier.h"
45 
46 #include "RNA_enum_types.h"
47 
48 static float len_squared_v3v3_with_normal_bias(const float co_search[3],
49  const float co_test[3],
50  const void *user_data)
51 {
52  const float *normal = user_data;
53  float d[3], dist;
54 
55  sub_v3_v3v3(d, co_test, co_search);
56 
57  dist = len_squared_v3(d);
58 
59  /* Avoid head-on collisions. */
60  if (dot_v3v3(d, normal) < 0.0f) {
61  dist *= 10.0f;
62  }
63  return dist;
64 }
65 
66 typedef struct BoidValues {
71 
72 static bool apply_boid_rule(
73  BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
74 
75 static bool rule_none(BoidRule *UNUSED(rule),
77  BoidValues *UNUSED(val),
78  ParticleData *UNUSED(pa))
79 {
80  return false;
81 }
82 
83 static bool rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
84 {
85  BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
86  BoidSettings *boids = bbd->part->boids;
87  BoidParticle *bpa = pa->boid;
88  EffectedPoint epoint;
89  ListBase *effectors = bbd->sim->psys->effectors;
90  EffectorCache *cur, *eff = NULL;
91  EffectorCache temp_eff;
92  EffectorData efd, cur_efd;
93  float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
94  float priority = 0.0f, len = 0.0f;
95  bool ret = false;
96 
97  int p = 0;
98  efd.index = cur_efd.index = &p;
99 
100  pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
101 
102  /* first find out goal/predator with highest priority */
103  if (effectors) {
104  for (cur = effectors->first; cur; cur = cur->next) {
105  Object *eob = cur->ob;
106  PartDeflect *pd = cur->pd;
107 
108  if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
109  if (gabr->ob == eob) {
110  /* TODO: effectors with multiple points */
111  if (get_effector_data(cur, &efd, &epoint, 0)) {
112  if (cur->pd && cur->pd->forcefield == PFIELD_BOID) {
113  priority = mul * pd->f_strength *
114  effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
115  }
116  else {
117  priority = 1.0;
118  }
119 
120  eff = cur;
121  }
122  break;
123  }
124  }
125  else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) {
126  /* skip current object */
127  }
128  else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f &&
129  get_effector_data(cur, &cur_efd, &epoint, 0)) {
130  float temp = mul * pd->f_strength *
131  effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
132 
133  if (temp == 0.0f) {
134  /* do nothing */
135  }
136  else if (temp > priority) {
137  priority = temp;
138  eff = cur;
139  efd = cur_efd;
140  len = efd.distance;
141  }
142  /* choose closest object with same priority */
143  else if (temp == priority && efd.distance < len) {
144  eff = cur;
145  efd = cur_efd;
146  len = efd.distance;
147  }
148  }
149  }
150  }
151 
152  /* if the object doesn't have effector data we have to fake it */
153  if (eff == NULL && gabr->ob) {
154  memset(&temp_eff, 0, sizeof(EffectorCache));
155  temp_eff.ob = gabr->ob;
156  temp_eff.depsgraph = bbd->sim->depsgraph;
157  temp_eff.scene = bbd->sim->scene;
158  eff = &temp_eff;
159  get_effector_data(eff, &efd, &epoint, 0);
160  priority = 1.0f;
161  }
162 
163  /* then use that effector */
164  if (priority > (rule->type == eBoidRuleType_Avoid ?
165  gabr->fear_factor :
166  0.0f)) { /* with avoid, factor is "fear factor" */
167  Object *eob = eff->ob;
168  PartDeflect *pd = eff->pd;
169  float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
170 
171  if (gabr->options & BRULE_GOAL_AVOID_PREDICT) {
172  /* estimate future location of target */
173  get_effector_data(eff, &efd, &epoint, 1);
174 
175  mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
176  add_v3_v3(efd.loc, efd.vel);
177  sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc);
178  efd.distance = len_v3(efd.vec_to_point);
179  }
180 
181  if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface != 0.0f) {
182  if (!bbd->goal_ob || bbd->goal_priority < priority) {
183  bbd->goal_ob = eob;
184  copy_v3_v3(bbd->goal_co, efd.loc);
185  copy_v3_v3(bbd->goal_nor, efd.nor);
186  }
187  }
188  else if ((rule->type == eBoidRuleType_Avoid) && (bpa->data.mode == eBoidMode_Climbing) &&
189  (priority > 2.0f * gabr->fear_factor)) {
190  /* detach from surface and try to fly away from danger */
191  negate_v3_v3(efd.vec_to_point, bpa->gravity);
192  }
193 
194  copy_v3_v3(bbd->wanted_co, efd.vec_to_point);
195  mul_v3_fl(bbd->wanted_co, mul);
196 
197  bbd->wanted_speed = val->max_speed * priority;
198 
199  /* with goals factor is approach velocity factor */
200  if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
201  float len2 = 2.0f * len_v3(pa->prev_state.vel);
202 
203  surface *= pa->size * boids->height;
204 
205  if (len2 > 0.0f && efd.distance - surface < len2) {
206  len2 = (efd.distance - surface) / len2;
207  bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
208  }
209  }
210 
211  ret = true;
212  }
213 
214  return ret;
215 }
216 
217 static bool rule_avoid_collision(BoidRule *rule,
218  BoidBrainData *bbd,
219  BoidValues *val,
220  ParticleData *pa)
221 {
222  const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
224  KDTreeNearest_3d *ptn = NULL;
225  ParticleTarget *pt;
226  BoidParticle *bpa = pa->boid;
227  ColliderCache *coll;
228  float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
229  float co1[3], vel1[3], co2[3], vel2[3];
230  float len, t, inp, t_min = 2.0f;
231  int n, neighbors = 0, nearest = 0;
232  bool ret = 0;
233 
234  // check deflector objects first
235  if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
237  BVHTreeRayHit hit;
238  float radius = val->personal_space * pa->size, ray_dir[3];
239 
240  memset(&col, 0, sizeof(ParticleCollision));
241 
242  copy_v3_v3(col.co1, pa->prev_state.co);
243  add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
244  sub_v3_v3v3(ray_dir, col.co2, col.co1);
245  mul_v3_fl(ray_dir, acbr->look_ahead);
246  col.f = 0.0f;
247  hit.index = -1;
248  hit.dist = col.original_ray_length = normalize_v3(ray_dir);
249 
250  /* find out closest deflector object */
251  for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
252  /* don't check with current ground object */
253  if (coll->ob == bpa->ground) {
254  continue;
255  }
256 
257  col.current = coll->ob;
258  col.md = coll->collmd;
259 
260  if (col.md && col.md->bvhtree) {
261  BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
262  col.co1,
263  ray_dir,
264  radius,
265  &hit,
267  &col,
268  raycast_flag);
269  }
270  }
271  /* then avoid that object */
272  if (hit.index >= 0) {
273  t = hit.dist / col.original_ray_length;
274 
275  /* avoid head-on collision */
276  if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
277  /* don't know why, but uneven range [0.0, 1.0] */
278  /* works much better than even [-1.0, 1.0] */
279  bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
280  bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
281  bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
282  }
283  else {
284  copy_v3_v3(bbd->wanted_co, col.pce.nor);
285  }
286 
287  mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
288 
289  bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
290  bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
291 
292  return true;
293  }
294  }
295 
296  // check boids in own system
297  if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
298  neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree,
299  pa->prev_state.co,
300  &ptn,
301  acbr->look_ahead *
302  len_v3(pa->prev_state.vel),
304  pa->prev_state.ave);
305  if (neighbors > 1) {
306  for (n = 1; n < neighbors; n++) {
307  copy_v3_v3(co1, pa->prev_state.co);
308  copy_v3_v3(vel1, pa->prev_state.vel);
309  copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
310  copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
311 
312  sub_v3_v3v3(loc, co1, co2);
313 
314  sub_v3_v3v3(vec, vel1, vel2);
315 
316  inp = dot_v3v3(vec, vec);
317 
318  /* velocities not parallel */
319  if (inp != 0.0f) {
320  t = -dot_v3v3(loc, vec) / inp;
321  /* cpa is not too far in the future so investigate further */
322  if (t > 0.0f && t < t_min) {
323  madd_v3_v3fl(co1, vel1, t);
324  madd_v3_v3fl(co2, vel2, t);
325 
326  sub_v3_v3v3(vec, co2, co1);
327 
328  len = normalize_v3(vec);
329 
330  /* distance of cpa is close enough */
331  if (len < 2.0f * val->personal_space * pa->size) {
332  t_min = t;
333 
334  mul_v3_fl(vec, len_v3(vel1));
335  mul_v3_fl(vec, (2.0f - t) / 2.0f);
336  sub_v3_v3v3(bbd->wanted_co, vel1, vec);
337  bbd->wanted_speed = len_v3(bbd->wanted_co);
338  ret = 1;
339  }
340  }
341  }
342  }
343  }
344  }
345  if (ptn) {
346  MEM_freeN(ptn);
347  ptn = NULL;
348  }
349 
350  /* check boids in other systems */
351  for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
352  ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
353 
354  if (epsys) {
355  BLI_assert(epsys->tree != NULL);
356  neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(epsys->tree,
357  pa->prev_state.co,
358  &ptn,
359  acbr->look_ahead *
360  len_v3(pa->prev_state.vel),
362  pa->prev_state.ave);
363 
364  if (neighbors > 0) {
365  for (n = 0; n < neighbors; n++) {
366  copy_v3_v3(co1, pa->prev_state.co);
367  copy_v3_v3(vel1, pa->prev_state.vel);
368  copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
369  copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
370 
371  sub_v3_v3v3(loc, co1, co2);
372 
373  sub_v3_v3v3(vec, vel1, vel2);
374 
375  inp = dot_v3v3(vec, vec);
376 
377  /* velocities not parallel */
378  if (inp != 0.0f) {
379  t = -dot_v3v3(loc, vec) / inp;
380  /* cpa is not too far in the future so investigate further */
381  if (t > 0.0f && t < t_min) {
382  madd_v3_v3fl(co1, vel1, t);
383  madd_v3_v3fl(co2, vel2, t);
384 
385  sub_v3_v3v3(vec, co2, co1);
386 
387  len = normalize_v3(vec);
388 
389  /* distance of cpa is close enough */
390  if (len < 2.0f * val->personal_space * pa->size) {
391  t_min = t;
392 
393  mul_v3_fl(vec, len_v3(vel1));
394  mul_v3_fl(vec, (2.0f - t) / 2.0f);
395  sub_v3_v3v3(bbd->wanted_co, vel1, vec);
396  bbd->wanted_speed = len_v3(bbd->wanted_co);
397  ret = 1;
398  }
399  }
400  }
401  }
402  }
403 
404  if (ptn) {
405  MEM_freeN(ptn);
406  ptn = NULL;
407  }
408  }
409  }
410 
411  if (ptn && nearest == 0) {
412  MEM_freeN(ptn);
413  }
414 
415  return ret;
416 }
417 static bool rule_separate(BoidRule *UNUSED(rule),
418  BoidBrainData *bbd,
419  BoidValues *val,
420  ParticleData *pa)
421 {
422  KDTreeNearest_3d *ptn = NULL;
423  ParticleTarget *pt;
424  float len = 2.0f * val->personal_space * pa->size + 1.0f;
425  float vec[3] = {0.0f, 0.0f, 0.0f};
426  int neighbors = BLI_kdtree_3d_range_search(
427  bbd->sim->psys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
428  bool ret = false;
429 
430  if (neighbors > 1 && ptn[1].dist != 0.0f) {
431  sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
432  mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
433  add_v3_v3(bbd->wanted_co, vec);
434  bbd->wanted_speed = val->max_speed;
435  len = ptn[1].dist;
436  ret = 1;
437  }
438  if (ptn) {
439  MEM_freeN(ptn);
440  ptn = NULL;
441  }
442 
443  /* check other boid systems */
444  for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
445  ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
446 
447  if (epsys) {
448  neighbors = BLI_kdtree_3d_range_search(
449  epsys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
450 
451  if (neighbors > 0 && ptn[0].dist < len) {
452  sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
453  mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
454  add_v3_v3(bbd->wanted_co, vec);
455  bbd->wanted_speed = val->max_speed;
456  len = ptn[0].dist;
457  ret = true;
458  }
459 
460  if (ptn) {
461  MEM_freeN(ptn);
462  ptn = NULL;
463  }
464  }
465  }
466  return ret;
467 }
468 static bool rule_flock(BoidRule *UNUSED(rule),
469  BoidBrainData *bbd,
470  BoidValues *UNUSED(val),
471  ParticleData *pa)
472 {
473  KDTreeNearest_3d ptn[11];
474  float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
475  int neighbors = BLI_kdtree_3d_find_nearest_n_with_len_squared_cb(
476  bbd->sim->psys->tree,
477  pa->state.co,
478  ptn,
479  ARRAY_SIZE(ptn),
481  pa->prev_state.ave);
482  int n;
483  bool ret = false;
484 
485  if (neighbors > 1) {
486  for (n = 1; n < neighbors; n++) {
487  add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
488  add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
489  }
490 
491  mul_v3_fl(loc, 1.0f / ((float)neighbors - 1.0f));
492  mul_v3_fl(vec, 1.0f / ((float)neighbors - 1.0f));
493 
494  sub_v3_v3(loc, pa->prev_state.co);
495  sub_v3_v3(vec, pa->prev_state.vel);
496 
497  add_v3_v3(bbd->wanted_co, vec);
498  add_v3_v3(bbd->wanted_co, loc);
499  bbd->wanted_speed = len_v3(bbd->wanted_co);
500 
501  ret = true;
502  }
503  return ret;
504 }
505 static bool rule_follow_leader(BoidRule *rule,
506  BoidBrainData *bbd,
507  BoidValues *val,
508  ParticleData *pa)
509 {
511  float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
512  float mul, len;
513  int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
514  int i, p = pa - bbd->sim->psys->particles;
515  bool ret = false;
516 
517  if (flbr->ob) {
518  float vec2[3], t;
519 
520  /* first check we're not blocking the leader */
521  sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
522  mul_v3_fl(vec, 1.0f / bbd->timestep);
523 
524  sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
525 
526  mul = dot_v3v3(vec, vec);
527 
528  /* leader is not moving */
529  if (mul < 0.01f) {
530  len = len_v3(loc);
531  /* too close to leader */
532  if (len < 2.0f * val->personal_space * pa->size) {
533  copy_v3_v3(bbd->wanted_co, loc);
534  bbd->wanted_speed = val->max_speed;
535  return true;
536  }
537  }
538  else {
539  t = dot_v3v3(loc, vec) / mul;
540 
541  /* possible blocking of leader in near future */
542  if (t > 0.0f && t < 3.0f) {
543  copy_v3_v3(vec2, vec);
544  mul_v3_fl(vec2, t);
545 
546  sub_v3_v3v3(vec2, loc, vec2);
547 
548  len = len_v3(vec2);
549 
550  if (len < 2.0f * val->personal_space * pa->size) {
551  copy_v3_v3(bbd->wanted_co, vec2);
552  bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
553  return true;
554  }
555  }
556  }
557 
558  /* not blocking so try to follow leader */
559  if (p && flbr->options & BRULE_LEADER_IN_LINE) {
560  copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
561  copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
562  }
563  else {
564  copy_v3_v3(loc, flbr->oloc);
565  sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
566  mul_v3_fl(vec, 1.0f / bbd->timestep);
567  }
568 
569  /* fac is seconds behind leader */
570  madd_v3_v3fl(loc, vec, -flbr->distance);
571 
572  sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
573  bbd->wanted_speed = len_v3(bbd->wanted_co);
574 
575  ret = true;
576  }
577  else if (p % n) {
578  float vec2[3], t, t_min = 3.0f;
579 
580  /* first check we're not blocking any leaders */
581  for (i = 0; i < bbd->sim->psys->totpart; i += n) {
582  copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
583 
584  sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
585 
586  mul = dot_v3v3(vec, vec);
587 
588  /* leader is not moving */
589  if (mul < 0.01f) {
590  len = len_v3(loc);
591  /* too close to leader */
592  if (len < 2.0f * val->personal_space * pa->size) {
593  copy_v3_v3(bbd->wanted_co, loc);
594  bbd->wanted_speed = val->max_speed;
595  return true;
596  }
597  }
598  else {
599  t = dot_v3v3(loc, vec) / mul;
600 
601  /* possible blocking of leader in near future */
602  if (t > 0.0f && t < t_min) {
603  copy_v3_v3(vec2, vec);
604  mul_v3_fl(vec2, t);
605 
606  sub_v3_v3v3(vec2, loc, vec2);
607 
608  len = len_v3(vec2);
609 
610  if (len < 2.0f * val->personal_space * pa->size) {
611  t_min = t;
612  copy_v3_v3(bbd->wanted_co, loc);
613  bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
614  ret = true;
615  }
616  }
617  }
618  }
619 
620  if (ret) {
621  return true;
622  }
623 
624  /* not blocking so try to follow leader */
625  if (flbr->options & BRULE_LEADER_IN_LINE) {
626  copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
627  copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
628  }
629  else {
630  copy_v3_v3(vec, bbd->sim->psys->particles[p - p % n].prev_state.vel);
631  copy_v3_v3(loc, bbd->sim->psys->particles[p - p % n].prev_state.co);
632  }
633 
634  /* fac is seconds behind leader */
635  madd_v3_v3fl(loc, vec, -flbr->distance);
636 
637  sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
638  bbd->wanted_speed = len_v3(bbd->wanted_co);
639 
640  ret = true;
641  }
642 
643  return ret;
644 }
645 static bool rule_average_speed(BoidRule *rule,
646  BoidBrainData *bbd,
647  BoidValues *val,
648  ParticleData *pa)
649 {
650  BoidParticle *bpa = pa->boid;
652  float vec[3] = {0.0f, 0.0f, 0.0f};
653 
654  if (asbr->wander > 0.0f) {
655  /* abuse pa->r_ave for wandering */
656  bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
657  bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
658  bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
659 
660  normalize_v3(bpa->wander);
661 
662  copy_v3_v3(vec, bpa->wander);
663 
664  mul_qt_v3(pa->prev_state.rot, vec);
665 
666  copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
667 
668  mul_v3_fl(bbd->wanted_co, 1.1f);
669 
670  add_v3_v3(bbd->wanted_co, vec);
671 
672  /* leveling */
673  if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
675  mul_v3_fl(vec, asbr->level);
676  sub_v3_v3(bbd->wanted_co, vec);
677  }
678  }
679  else {
680  copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
681 
682  /* may happen at birth */
683  if (dot_v2v2(bbd->wanted_co, bbd->wanted_co) == 0.0f) {
684  bbd->wanted_co[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
685  bbd->wanted_co[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
686  bbd->wanted_co[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
687  }
688 
689  /* leveling */
690  if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
692  mul_v3_fl(vec, asbr->level);
693  sub_v3_v3(bbd->wanted_co, vec);
694  }
695  }
696  bbd->wanted_speed = asbr->speed * val->max_speed;
697 
698  return true;
699 }
700 static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
701 {
702  BoidRuleFight *fbr = (BoidRuleFight *)rule;
703  KDTreeNearest_3d *ptn = NULL;
704  ParticleTarget *pt;
705  ParticleData *epars;
706  ParticleData *enemy_pa = NULL;
707  BoidParticle *bpa;
708  /* friends & enemies */
709  float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
710  float closest_dist = fbr->distance + 1.0f;
711  float f_strength = 0.0f, e_strength = 0.0f;
712  float health = 0.0f;
713  int n;
714  bool ret = false;
715 
716  /* calculate own group strength */
717  int neighbors = BLI_kdtree_3d_range_search(
718  bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance);
719  for (n = 0; n < neighbors; n++) {
720  bpa = bbd->sim->psys->particles[ptn[n].index].boid;
721  health += bpa->data.health;
722  }
723 
724  f_strength += bbd->part->boids->strength * health;
725 
726  if (ptn) {
727  MEM_freeN(ptn);
728  ptn = NULL;
729  }
730 
731  /* add other friendlies and calculate enemy strength and find closest enemy */
732  for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
733  ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
734  if (epsys) {
735  epars = epsys->particles;
736 
737  neighbors = BLI_kdtree_3d_range_search(epsys->tree, pa->prev_state.co, &ptn, fbr->distance);
738 
739  health = 0.0f;
740 
741  for (n = 0; n < neighbors; n++) {
742  bpa = epars[ptn[n].index].boid;
743  health += bpa->data.health;
744 
745  if (n == 0 && pt->mode == PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
746  copy_v3_v3(closest_enemy, ptn[n].co);
747  closest_dist = ptn[n].dist;
748  enemy_pa = epars + ptn[n].index;
749  }
750  }
751  if (pt->mode == PTARGET_MODE_ENEMY) {
752  e_strength += epsys->part->boids->strength * health;
753  }
754  else if (pt->mode == PTARGET_MODE_FRIEND) {
755  f_strength += epsys->part->boids->strength * health;
756  }
757 
758  if (ptn) {
759  MEM_freeN(ptn);
760  ptn = NULL;
761  }
762  }
763  }
764  /* decide action if enemy presence found */
765  if (e_strength > 0.0f) {
766  sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
767 
768  /* attack if in range */
769  if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
770  float damage = BLI_rng_get_float(bbd->rng);
771  float enemy_dir[3];
772 
773  normalize_v3_v3(enemy_dir, bbd->wanted_co);
774 
775  /* fight mode */
776  bbd->wanted_speed = 0.0f;
777 
778  /* must face enemy to fight */
779  if (dot_v3v3(pa->prev_state.ave, enemy_dir) > 0.5f) {
780  bpa = enemy_pa->boid;
781  bpa->data.health -= bbd->part->boids->strength * bbd->timestep *
782  ((1.0f - bbd->part->boids->accuracy) * damage +
783  bbd->part->boids->accuracy);
784  }
785  }
786  else {
787  /* approach mode */
788  bbd->wanted_speed = val->max_speed;
789  }
790 
791  /* check if boid doesn't want to fight */
792  bpa = pa->boid;
793  if (bpa->data.health / bbd->part->boids->health * bbd->part->boids->aggression <
794  e_strength / f_strength) {
795  /* decide to flee */
796  if (closest_dist < fbr->flee_distance * fbr->distance) {
797  negate_v3(bbd->wanted_co);
798  bbd->wanted_speed = val->max_speed;
799  }
800  else { /* wait for better odds */
801  bbd->wanted_speed = 0.0f;
802  }
803  }
804 
805  ret = true;
806  }
807 
808  return ret;
809 }
810 
811 typedef bool (*boid_rule_cb)(BoidRule *rule,
813  BoidValues *val,
814  ParticleData *pa);
815 
817  rule_none,
822  rule_flock,
825  rule_fight,
826  // rule_help,
827  // rule_protect,
828  // rule_hide,
829  // rule_follow_path,
830  // rule_follow_wall,
831 };
832 
833 static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
834 {
835  BoidParticle *bpa = pa->boid;
836 
838  val->max_speed = boids->land_max_speed * bpa->data.health / boids->health;
839  val->max_acc = boids->land_max_acc * val->max_speed;
840  val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health / boids->health;
841  val->min_speed = 0.0f; /* no minimum speed on land */
842  val->personal_space = boids->land_personal_space;
843  val->jump_speed = boids->land_jump_speed * bpa->data.health / boids->health;
844  }
845  else {
846  val->max_speed = boids->air_max_speed * bpa->data.health / boids->health;
847  val->max_acc = boids->air_max_acc * val->max_speed;
848  val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health / boids->health;
849  val->min_speed = boids->air_min_speed * boids->air_max_speed;
850  val->personal_space = boids->air_personal_space;
851  val->jump_speed = 0.0f; /* no jumping in air */
852  }
853 }
854 
856  ParticleData *pa,
857  float ground_co[3],
858  float ground_nor[3])
859 {
860  const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
861  BoidParticle *bpa = pa->boid;
862 
863  if (bpa->data.mode == eBoidMode_Climbing) {
864  SurfaceModifierData *surmd = NULL;
865  float x[3], v[3];
866 
868 
869  /* take surface velocity into account */
870  closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
871  add_v3_v3(x, v);
872 
873  /* get actual position on surface */
874  closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
875 
876  return bpa->ground;
877  }
878 
879  const float zvec[3] = {0.0f, 0.0f, 2000.0f};
881  ColliderCache *coll;
882  BVHTreeRayHit hit;
883  float radius = 0.0f, t, ray_dir[3];
884 
885  if (!bbd->sim->colliders) {
886  return NULL;
887  }
888 
889  memset(&col, 0, sizeof(ParticleCollision));
890 
891  /* first try to find below boid */
892  copy_v3_v3(col.co1, pa->state.co);
893  sub_v3_v3v3(col.co2, pa->state.co, zvec);
894  sub_v3_v3v3(ray_dir, col.co2, col.co1);
895  col.f = 0.0f;
896  hit.index = -1;
897  hit.dist = col.original_ray_length = normalize_v3(ray_dir);
898  col.pce.inside = 0;
899 
900  for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
901  col.current = coll->ob;
902  col.md = coll->collmd;
903  col.fac1 = col.fac2 = 0.0f;
904 
905  if (col.md && col.md->bvhtree) {
906  BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
907  col.co1,
908  ray_dir,
909  radius,
910  &hit,
912  &col,
913  raycast_flag);
914  }
915  }
916  /* then use that object */
917  if (hit.index >= 0) {
918  t = hit.dist / col.original_ray_length;
919  interp_v3_v3v3(ground_co, col.co1, col.co2, t);
920  normalize_v3_v3(ground_nor, col.pce.nor);
921  return col.hit;
922  }
923 
924  /* couldn't find below, so find upmost deflector object */
925  add_v3_v3v3(col.co1, pa->state.co, zvec);
926  sub_v3_v3v3(col.co2, pa->state.co, zvec);
927  sub_v3_v3(col.co2, zvec);
928  sub_v3_v3v3(ray_dir, col.co2, col.co1);
929  col.f = 0.0f;
930  hit.index = -1;
931  hit.dist = col.original_ray_length = normalize_v3(ray_dir);
932 
933  for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
934  col.current = coll->ob;
935  col.md = coll->collmd;
936 
937  if (col.md && col.md->bvhtree) {
938  BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
939  col.co1,
940  ray_dir,
941  radius,
942  &hit,
944  &col,
945  raycast_flag);
946  }
947  }
948  /* then use that object */
949  if (hit.index >= 0) {
950  t = hit.dist / col.original_ray_length;
951  interp_v3_v3v3(ground_co, col.co1, col.co2, t);
952  normalize_v3_v3(ground_nor, col.pce.nor);
953  return col.hit;
954  }
955 
956  /* default to z=0 */
957  copy_v3_v3(ground_co, pa->state.co);
958  ground_co[2] = 0;
959  ground_nor[0] = ground_nor[1] = 0.0f;
960  ground_nor[2] = 1.0f;
961  return NULL;
962 }
964 {
965  BoidParticle *bpa = pa->boid;
966 
967  if (rule == NULL) {
968  return false;
969  }
970 
972  rule->flag & BOIDRULE_ON_LAND) {
973  return true;
974  }
975 
976  if (bpa->data.mode == eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) {
977  return true;
978  }
979 
980  return false;
981 }
982 void boids_precalc_rules(ParticleSettings *part, float cfra)
983 {
984  BoidState *state = part->boids->states.first;
985  BoidRule *rule;
986  for (; state; state = state->next) {
987  for (rule = state->rules.first; rule; rule = rule->next) {
988  if (rule->type == eBoidRuleType_FollowLeader) {
990 
991  if (flbr->ob && flbr->cfra != cfra) {
992  /* save object locations for velocity calculations */
993  copy_v3_v3(flbr->oloc, flbr->loc);
994  copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
995  flbr->cfra = cfra;
996  }
997  }
998  }
999  }
1000 }
1001 static void boid_climb(BoidSettings *boids,
1002  ParticleData *pa,
1003  float *surface_co,
1004  float *surface_nor)
1005 {
1006  BoidParticle *bpa = pa->boid;
1007  float nor[3], vel[3];
1008  copy_v3_v3(nor, surface_nor);
1009 
1010  /* gather apparent gravity */
1011  madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
1012  normalize_v3(bpa->gravity);
1013 
1014  /* raise boid it's size from surface */
1015  mul_v3_fl(nor, pa->size * boids->height);
1016  add_v3_v3v3(pa->state.co, surface_co, nor);
1017 
1018  /* remove normal component from velocity */
1019  project_v3_v3v3(vel, pa->state.vel, surface_nor);
1020  sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
1021 }
1022 static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
1023 {
1024  float vec[3];
1025 
1026  sub_v3_v3v3(vec, boid_co, goal_co);
1027 
1028  return dot_v3v3(vec, goal_nor);
1029 }
1030 /* wanted_co is relative to boid location */
1031 static bool apply_boid_rule(
1032  BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
1033 {
1034  if (rule == NULL) {
1035  return false;
1036  }
1037 
1038  if (!boid_rule_applies(pa, bbd->part->boids, rule)) {
1039  return false;
1040  }
1041 
1042  if (!boid_rules[rule->type](rule, bbd, val, pa)) {
1043  return false;
1044  }
1045 
1046  if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co,
1047  pa->prev_state.vel,
1048  fuzziness * len_v3(pa->prev_state.vel)) == 0) {
1049  return true;
1050  }
1051  return false;
1052 }
1054 {
1055  BoidState *state = boids->states.first;
1056  BoidParticle *bpa = pa->boid;
1057 
1058  for (; state; state = state->next) {
1059  if (state->id == bpa->data.state_id) {
1060  return state;
1061  }
1062  }
1063 
1064  /* for some reason particle isn't at a valid state */
1065  state = boids->states.first;
1066  if (state) {
1067  bpa->data.state_id = state->id;
1068  }
1069 
1070  return state;
1071 }
1072 // static int boid_condition_is_true(BoidCondition *cond)
1073 //{
1074 // /* TODO */
1075 // return 0;
1076 //}
1077 
1078 /* determines the velocity the boid wants to have */
1079 void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
1080 {
1081  BoidRule *rule;
1082  BoidSettings *boids = bbd->part->boids;
1083  BoidValues val;
1084  BoidState *state = get_boid_state(boids, pa);
1085  BoidParticle *bpa = pa->boid;
1086  ParticleSystem *psys = bbd->sim->psys;
1087  int rand;
1088  // BoidCondition *cond;
1089 
1090  if (bpa->data.health <= 0.0f) {
1091  pa->alive = PARS_DYING;
1092  pa->dietime = bbd->cfra;
1093  return;
1094  }
1095 
1096  // planned for near future
1097  // cond = state->conditions.first;
1098  // for (; cond; cond=cond->next) {
1099  // if (boid_condition_is_true(cond)) {
1100  // pa->boid->state_id = cond->state_id;
1101  // state = get_boid_state(boids, pa);
1102  // break; /* only first true condition is used */
1103  // }
1104  //}
1105 
1106  zero_v3(bbd->wanted_co);
1107  bbd->wanted_speed = 0.0f;
1108 
1109  /* create random seed for every particle & frame */
1110  rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
1111  rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);
1112 
1113  set_boid_values(&val, bbd->part->boids, pa);
1114 
1115  /* go through rules */
1116  switch (state->ruleset_type) {
1117  case eBoidRulesetType_Fuzzy: {
1118  for (rule = state->rules.first; rule; rule = rule->next) {
1119  if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness)) {
1120  break; /* only first nonzero rule that comes through fuzzy rule is applied */
1121  }
1122  }
1123  break;
1124  }
1125  case eBoidRulesetType_Random: {
1126  /* use random rule for each particle (always same for same particle though) */
1127  const int n = BLI_listbase_count(&state->rules);
1128  if (n) {
1129  rule = BLI_findlink(&state->rules, rand % n);
1130  apply_boid_rule(bbd, rule, &val, pa, -1.0);
1131  }
1132  break;
1133  }
1134  case eBoidRulesetType_Average: {
1135  float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
1136  int n = 0;
1137  for (rule = state->rules.first; rule; rule = rule->next) {
1138  if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
1139  add_v3_v3(wanted_co, bbd->wanted_co);
1140  wanted_speed += bbd->wanted_speed;
1141  n++;
1142  zero_v3(bbd->wanted_co);
1143  bbd->wanted_speed = 0.0f;
1144  }
1145  }
1146 
1147  if (n > 1) {
1148  mul_v3_fl(wanted_co, 1.0f / (float)n);
1149  wanted_speed /= (float)n;
1150  }
1151 
1152  copy_v3_v3(bbd->wanted_co, wanted_co);
1153  bbd->wanted_speed = wanted_speed;
1154  break;
1155  }
1156  }
1157 
1158  /* decide on jumping & liftoff */
1159  if (bpa->data.mode == eBoidMode_OnLand) {
1160  /* fuzziness makes boids capable of misjudgement */
1161  float mul = 1.0f + state->rule_fuzziness;
1162 
1163  if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
1164  float cvel[3], dir[3];
1165 
1166  copy_v3_v3(dir, pa->prev_state.ave);
1167  normalize_v2(dir);
1168 
1169  copy_v3_v3(cvel, bbd->wanted_co);
1170  normalize_v2(cvel);
1171 
1172  if (dot_v2v2(cvel, dir) > 0.95f / mul) {
1173  bpa->data.mode = eBoidMode_Liftoff;
1174  }
1175  }
1176  else if (val.jump_speed > 0.0f) {
1177  float jump_v[3];
1178  int jump = 0;
1179 
1180  /* jump to get to a location */
1181  if (bbd->wanted_co[2] > 0.0f) {
1182  float cvel[3], dir[3];
1183  float z_v, ground_v, cur_v;
1184  float len;
1185 
1186  copy_v3_v3(dir, pa->prev_state.ave);
1187  normalize_v2(dir);
1188 
1189  copy_v3_v3(cvel, bbd->wanted_co);
1190  normalize_v2(cvel);
1191 
1192  len = len_v2(pa->prev_state.vel);
1193 
1194  /* first of all, are we going in a suitable direction? */
1195  /* or at a suitably slow speed */
1196  if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
1197  /* try to reach goal at highest point of the parabolic path */
1198  cur_v = len_v2(pa->prev_state.vel);
1199  z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
1200  ground_v = len_v2(bbd->wanted_co) *
1201  sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] /
1202  bbd->wanted_co[2]);
1203 
1204  len = sasqrt((ground_v - cur_v) * (ground_v - cur_v) + z_v * z_v);
1205 
1206  if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
1207  jump = 1;
1208 
1209  len = MIN2(len, val.jump_speed);
1210 
1211  copy_v3_v3(jump_v, dir);
1212  jump_v[2] = z_v;
1213  mul_v3_fl(jump_v, ground_v);
1214 
1215  normalize_v3(jump_v);
1216  mul_v3_fl(jump_v, len);
1217  add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
1218  }
1219  }
1220  }
1221 
1222  /* jump to go faster */
1223  if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
1224  /* pass */
1225  }
1226 
1227  if (jump) {
1228  copy_v3_v3(pa->prev_state.vel, jump_v);
1229  bpa->data.mode = eBoidMode_Falling;
1230  }
1231  }
1232  }
1233 }
1234 /* tries to realize the wanted velocity taking all constraints into account */
1236 {
1237  BoidSettings *boids = bbd->part->boids;
1238  BoidParticle *bpa = pa->boid;
1239  BoidValues val;
1240  EffectedPoint epoint;
1241  float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
1242  float dvec[3], bvec[3];
1243  float new_dir[3], new_speed;
1244  float old_dir[3], old_speed;
1245  float wanted_dir[3];
1246  float q[4], mat[3][3]; /* rotation */
1247  float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
1248  float force[3] = {0.0f, 0.0f, 0.0f};
1249  float pa_mass = bbd->part->mass, dtime = bbd->dfra * bbd->timestep;
1250 
1251  set_boid_values(&val, boids, pa);
1252 
1253  /* make sure there's something in new velocity, location & rotation */
1254  copy_particle_key(&pa->state, &pa->prev_state, 0);
1255 
1256  if (bbd->part->flag & PART_SIZEMASS) {
1257  pa_mass *= pa->size;
1258  }
1259 
1260  /* if boids can't fly they fall to the ground */
1261  if ((boids->options & BOID_ALLOW_FLIGHT) == 0 &&
1263  psys_uses_gravity(bbd->sim)) {
1264  bpa->data.mode = eBoidMode_Falling;
1265  }
1266 
1267  if (bpa->data.mode == eBoidMode_Falling) {
1268  /* Falling boids are only effected by gravity. */
1269  acc[2] = bbd->sim->scene->physics_settings.gravity[2];
1270  }
1271  else {
1272  /* figure out acceleration */
1273  float landing_level = 2.0f;
1274  float level = landing_level + 1.0f;
1275  float new_vel[3];
1276 
1277  if (bpa->data.mode == eBoidMode_Liftoff) {
1278  bpa->data.mode = eBoidMode_InAir;
1279  bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1280  }
1281  else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
1282  /* auto-leveling & landing if close to ground */
1283 
1284  bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1285 
1286  /* level = how many particle sizes above ground */
1287  level = (pa->prev_state.co[2] - ground_co[2]) / (2.0f * pa->size) - 0.5f;
1288 
1289  landing_level = -boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
1290 
1291  if (pa->prev_state.vel[2] < 0.0f) {
1292  if (level < 1.0f) {
1293  bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
1294  bbd->wanted_speed = 0.0f;
1295  bpa->data.mode = eBoidMode_Falling;
1296  }
1297  else if (level < landing_level) {
1298  bbd->wanted_speed *= (level - 1.0f) / landing_level;
1299  bbd->wanted_co[2] *= (level - 1.0f) / landing_level;
1300  }
1301  }
1302  }
1303 
1304  copy_v3_v3(old_dir, pa->prev_state.ave);
1305  new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
1306 
1307  /* first check if we have valid direction we want to go towards */
1308  if (new_speed == 0.0f) {
1309  copy_v3_v3(new_dir, old_dir);
1310  }
1311  else {
1312  float old_dir2[2], wanted_dir2[2], nor[3], angle;
1313  copy_v2_v2(old_dir2, old_dir);
1314  normalize_v2(old_dir2);
1315  copy_v2_v2(wanted_dir2, wanted_dir);
1316  normalize_v2(wanted_dir2);
1317 
1318  /* choose random direction to turn if wanted velocity */
1319  /* is directly behind regardless of z-coordinate */
1320  if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
1321  wanted_dir[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1322  wanted_dir[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1323  wanted_dir[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
1324  normalize_v3(wanted_dir);
1325  }
1326 
1327  /* constrain direction with maximum angular velocity */
1328  angle = saacos(dot_v3v3(old_dir, wanted_dir));
1329  angle = min_ff(angle, val.max_ave);
1330 
1331  cross_v3_v3v3(nor, old_dir, wanted_dir);
1333  copy_v3_v3(new_dir, old_dir);
1334  mul_qt_v3(q, new_dir);
1335  normalize_v3(new_dir);
1336 
1337  /* save direction in case resulting velocity too small */
1338  axis_angle_to_quat(q, nor, angle * dtime);
1339  copy_v3_v3(pa->state.ave, old_dir);
1340  mul_qt_v3(q, pa->state.ave);
1341  normalize_v3(pa->state.ave);
1342  }
1343 
1344  /* constrain speed with maximum acceleration */
1345  old_speed = len_v3(pa->prev_state.vel);
1346 
1347  if (bbd->wanted_speed < old_speed) {
1348  new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
1349  }
1350  else {
1351  new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
1352  }
1353 
1354  /* combine direction and speed */
1355  copy_v3_v3(new_vel, new_dir);
1356  mul_v3_fl(new_vel, new_speed);
1357 
1358  /* maintain minimum flying velocity if not landing */
1359  if (level >= landing_level) {
1360  float len2 = dot_v2v2(new_vel, new_vel);
1361  float root;
1362 
1363  len2 = MAX2(len2, val.min_speed * val.min_speed);
1364  root = sasqrt(new_speed * new_speed - len2);
1365 
1366  new_vel[2] = new_vel[2] < 0.0f ? -root : root;
1367 
1368  normalize_v2(new_vel);
1369  mul_v2_fl(new_vel, sasqrt(len2));
1370  }
1371 
1372  /* finally constrain speed to max speed */
1373  new_speed = normalize_v3(new_vel);
1374  mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));
1375 
1376  /* get acceleration from difference of velocities */
1377  sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
1378 
1379  /* break acceleration to components */
1380  project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
1381  sub_v3_v3v3(nor_acc, acc, tan_acc);
1382  }
1383 
1384  /* account for effectors */
1385  pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
1387  bbd->sim->colliders,
1388  bbd->part->effector_weights,
1389  &epoint,
1390  force,
1391  NULL,
1392  NULL);
1393 
1395  float length = normalize_v3(force);
1396 
1397  length = MAX2(0.0f, length - boids->land_stick_force);
1398 
1399  mul_v3_fl(force, length);
1400  }
1401 
1402  add_v3_v3(acc, force);
1403 
1404  /* store smoothed acceleration for nice banking etc. */
1405  madd_v3_v3fl(bpa->data.acc, acc, dtime);
1406  mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));
1407 
1408  /* integrate new location & velocity */
1409 
1410  /* by regarding the acceleration as a force at this stage we
1411  * can get better control although it's a bit unphysical */
1412  mul_v3_fl(acc, 1.0f / pa_mass);
1413 
1414  copy_v3_v3(dvec, acc);
1415  mul_v3_fl(dvec, dtime * dtime * 0.5f);
1416 
1417  copy_v3_v3(bvec, pa->prev_state.vel);
1418  mul_v3_fl(bvec, dtime);
1419  add_v3_v3(dvec, bvec);
1420  add_v3_v3(pa->state.co, dvec);
1421 
1422  madd_v3_v3fl(pa->state.vel, acc, dtime);
1423 
1424  // if (bpa->data.mode != eBoidMode_InAir)
1425  bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
1426 
1427  /* change modes, constrain movement & keep track of down vector */
1428  switch (bpa->data.mode) {
1429  case eBoidMode_InAir: {
1430  float grav[3];
1431 
1432  grav[0] = 0.0f;
1433  grav[1] = 0.0f;
1434  grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
1435 
1436  /* don't take forward acceleration into account (better banking) */
1437  if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
1438  project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
1439  sub_v3_v3v3(dvec, bpa->data.acc, dvec);
1440  }
1441  else {
1442  copy_v3_v3(dvec, bpa->data.acc);
1443  }
1444 
1445  /* gather apparent gravity */
1446  madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
1447  normalize_v3(bpa->gravity);
1448 
1449  /* stick boid on goal when close enough */
1450  if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1451  pa->size * boids->height) {
1452  bpa->data.mode = eBoidMode_Climbing;
1453  bpa->ground = bbd->goal_ob;
1454  boid_find_ground(bbd, pa, ground_co, ground_nor);
1455  boid_climb(boids, pa, ground_co, ground_nor);
1456  }
1457  else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
1458  /* land boid when below ground */
1459  if (boids->options & BOID_ALLOW_LAND) {
1460  pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1461  pa->state.vel[2] = 0.0f;
1462  bpa->data.mode = eBoidMode_OnLand;
1463  }
1464  /* fly above ground */
1465  else if (bpa->ground) {
1466  pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1467  pa->state.vel[2] = 0.0f;
1468  }
1469  }
1470  break;
1471  }
1472  case eBoidMode_Falling: {
1473  float grav[3];
1474 
1475  grav[0] = 0.0f;
1476  grav[1] = 0.0f;
1477  grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
1478 
1479  /* gather apparent gravity */
1480  madd_v3_v3fl(bpa->gravity, grav, dtime);
1481  normalize_v3(bpa->gravity);
1482 
1483  if (boids->options & BOID_ALLOW_LAND) {
1484  /* stick boid on goal when close enough */
1485  if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1486  pa->size * boids->height) {
1487  bpa->data.mode = eBoidMode_Climbing;
1488  bpa->ground = bbd->goal_ob;
1489  boid_find_ground(bbd, pa, ground_co, ground_nor);
1490  boid_climb(boids, pa, ground_co, ground_nor);
1491  }
1492  /* land boid when really near ground */
1493  else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) {
1494  pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1495  pa->state.vel[2] = 0.0f;
1496  bpa->data.mode = eBoidMode_OnLand;
1497  }
1498  /* if we're falling, can fly and want to go upwards lets fly */
1499  else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
1500  bpa->data.mode = eBoidMode_InAir;
1501  }
1502  }
1503  else {
1504  bpa->data.mode = eBoidMode_InAir;
1505  }
1506  break;
1507  }
1508  case eBoidMode_Climbing: {
1509  boid_climb(boids, pa, ground_co, ground_nor);
1510  // float nor[3];
1511  // copy_v3_v3(nor, ground_nor);
1512 
1514  // madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
1515  // normalize_v3(pa->r_ve);
1516 
1518  // mul_v3_fl(nor, pa->size * boids->height);
1519  // add_v3_v3v3(pa->state.co, ground_co, nor);
1520 
1522  // project_v3_v3v3(v, pa->state.vel, ground_nor);
1523  // sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
1524  break;
1525  }
1526  case eBoidMode_OnLand: {
1527  /* stick boid on goal when close enough */
1528  if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
1529  pa->size * boids->height) {
1530  bpa->data.mode = eBoidMode_Climbing;
1531  bpa->ground = bbd->goal_ob;
1532  boid_find_ground(bbd, pa, ground_co, ground_nor);
1533  boid_climb(boids, pa, ground_co, ground_nor);
1534  }
1535  /* ground is too far away so boid falls */
1536  else if (pa->state.co[2] - ground_co[2] > 1.1f * pa->size * boids->height) {
1537  bpa->data.mode = eBoidMode_Falling;
1538  }
1539  else {
1540  /* constrain to surface */
1541  pa->state.co[2] = ground_co[2] + pa->size * boids->height;
1542  pa->state.vel[2] = 0.0f;
1543  }
1544 
1545  if (boids->banking > 0.0f) {
1546  float grav[3];
1547  /* Don't take gravity's strength in to account, */
1548  /* otherwise amount of banking is hard to control. */
1549  negate_v3_v3(grav, ground_nor);
1550 
1551  project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
1552  sub_v3_v3v3(dvec, bpa->data.acc, dvec);
1553 
1554  /* gather apparent gravity */
1555  madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
1556  normalize_v3(bpa->gravity);
1557  }
1558  else {
1559  /* gather negative surface normal */
1560  madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
1561  normalize_v3(bpa->gravity);
1562  }
1563  break;
1564  }
1565  }
1566 
1567  /* save direction to state.ave unless the boid is falling */
1568  /* (boids can't effect their direction when falling) */
1569  if (bpa->data.mode != eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f * pa->size) {
1570  copy_v3_v3(pa->state.ave, pa->state.vel);
1571  pa->state.ave[2] *= bbd->part->boids->pitch;
1572  normalize_v3(pa->state.ave);
1573  }
1574 
1575  /* apply damping */
1577  mul_v3_fl(pa->state.vel, 1.0f - 0.2f * bbd->part->dampfac);
1578  }
1579 
1580  /* calculate rotation matrix based on forward & down vectors */
1581  if (bpa->data.mode == eBoidMode_InAir) {
1582  copy_v3_v3(mat[0], pa->state.ave);
1583 
1584  project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
1585  sub_v3_v3v3(mat[2], bpa->gravity, dvec);
1586  normalize_v3(mat[2]);
1587  }
1588  else {
1589  project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
1590  sub_v3_v3v3(mat[0], pa->state.ave, dvec);
1591  normalize_v3(mat[0]);
1592 
1593  copy_v3_v3(mat[2], bpa->gravity);
1594  }
1595  negate_v3(mat[2]);
1596  cross_v3_v3v3(mat[1], mat[2], mat[0]);
1597 
1598  /* apply rotation */
1599  mat3_to_quat_is_ok(q, mat);
1600  copy_qt_qt(pa->state.rot, q);
1601 }
1602 
1604 {
1605  BoidRule *rule = NULL;
1606  if (type <= 0) {
1607  return NULL;
1608  }
1609 
1610  switch (type) {
1611  case eBoidRuleType_Goal:
1612  case eBoidRuleType_Avoid:
1613  rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid");
1614  break;
1616  rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision");
1617  ((BoidRuleAvoidCollision *)rule)->look_ahead = 2.0f;
1618  break;
1620  rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader");
1621  ((BoidRuleFollowLeader *)rule)->distance = 1.0f;
1622  break;
1624  rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed");
1625  ((BoidRuleAverageSpeed *)rule)->speed = 0.5f;
1626  break;
1627  case eBoidRuleType_Fight:
1628  rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight");
1629  ((BoidRuleFight *)rule)->distance = 100.0f;
1630  ((BoidRuleFight *)rule)->flee_distance = 100.0f;
1631  break;
1632  default:
1633  rule = MEM_callocN(sizeof(BoidRule), "BoidRule");
1634  break;
1635  }
1636 
1637  rule->type = type;
1639  BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type - 1].name, sizeof(rule->name));
1640 
1641  return rule;
1642 }
1644 {
1645  boids->air_max_speed = 10.0f;
1646  boids->air_max_acc = 0.5f;
1647  boids->air_max_ave = 0.5f;
1648  boids->air_personal_space = 1.0f;
1649 
1650  boids->land_max_speed = 5.0f;
1651  boids->land_max_acc = 0.5f;
1652  boids->land_max_ave = 0.5f;
1653  boids->land_personal_space = 1.0f;
1654 
1655  boids->options = BOID_ALLOW_FLIGHT;
1656 
1657  boids->landing_smoothness = 3.0f;
1658  boids->banking = 1.0f;
1659  boids->pitch = 1.0f;
1660  boids->height = 1.0f;
1661 
1662  boids->health = 1.0f;
1663  boids->accuracy = 1.0f;
1664  boids->aggression = 2.0f;
1665  boids->range = 1.0f;
1666  boids->strength = 0.1f;
1667 }
1668 
1670 {
1671  BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
1672 
1673  state->id = boids->last_state_id++;
1674  if (state->id) {
1675  BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id);
1676  }
1677  else {
1678  strcpy(state->name, "State");
1679  }
1680 
1681  state->rule_fuzziness = 0.5;
1682  state->volume = 1.0f;
1683  state->channels |= ~0;
1684 
1685  return state;
1686 }
1687 
1689 {
1690  BoidState *staten = MEM_dupallocN(state);
1691 
1692  BLI_duplicatelist(&staten->rules, &state->rules);
1693  BLI_duplicatelist(&staten->conditions, &state->conditions);
1694  BLI_duplicatelist(&staten->actions, &state->actions);
1695 
1696  staten->id = boids->last_state_id++;
1697 
1698  return staten;
1699 }
1701 {
1702  if (boids) {
1703  BoidState *state = boids->states.first;
1704 
1705  for (; state; state = state->next) {
1706  BLI_freelistN(&state->rules);
1707  BLI_freelistN(&state->conditions);
1708  BLI_freelistN(&state->actions);
1709  }
1710 
1711  BLI_freelistN(&boids->states);
1712 
1713  MEM_freeN(boids);
1714  }
1715 }
1717 {
1718  BoidSettings *nboids = NULL;
1719 
1720  if (boids) {
1721  BoidState *state;
1722  BoidState *nstate;
1723 
1724  nboids = MEM_dupallocN(boids);
1725 
1726  BLI_duplicatelist(&nboids->states, &boids->states);
1727 
1728  state = boids->states.first;
1729  nstate = nboids->states.first;
1730  for (; state; state = state->next, nstate = nstate->next) {
1731  BLI_duplicatelist(&nstate->rules, &state->rules);
1732  BLI_duplicatelist(&nstate->conditions, &state->conditions);
1733  BLI_duplicatelist(&nstate->actions, &state->actions);
1734  }
1735  }
1736 
1737  return nboids;
1738 }
1740 {
1741  BoidState *state = boids->states.first;
1742 
1743  for (; state; state = state->next) {
1744  if (state->flag & BOIDSTATE_CURRENT) {
1745  break;
1746  }
1747  }
1748 
1749  return state;
1750 }
typedef float(TangentPoint)[2]
float effector_falloff(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, struct EffectorWeights *weights)
int get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, int real_velocity)
Definition: effect.c:693
void BKE_effectors_apply(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *wind_force, float *impulse)
Definition: effect.c:1145
int closest_point_on_surface(struct SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3])
Definition: effect.c:657
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point)
Definition: effect.c:402
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
struct ParticleSystem * psys_get_target_system(struct Object *ob, struct ParticleTarget *pt)
void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time)
Definition: particle.c:3763
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit)
int psys_uses_gravity(struct ParticleSimulationData *sim)
Definition: particle.c:907
BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
Definition: BKE_particle.h:266
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BVH_RAYCAST_DEFAULT
Definition: BLI_kdopbvh.h:104
int BLI_bvhtree_ray_cast_ex(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata, int flag)
Definition: BLI_kdopbvh.c:1939
@ BVH_RAYCAST_WATERTIGHT
Definition: BLI_kdopbvh.h:102
A kd-tree for nearest neighbor search.
void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float saacos(float fac)
MINLINE float min_ff(float a, float b)
#define M_PI
Definition: BLI_math_base.h:38
MINLINE float sasqrt(float fac)
void axis_angle_to_quat(float r[4], const float axis[3], const float angle)
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:97
void mat3_to_quat_is_ok(float q[4], const float mat[3][3])
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:52
MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
Definition: math_vector.c:674
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v2(float r[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Random number functions.
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define ARRAY_SIZE(arr)
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
#define MIN2(a, b)
#define BRULE_ACOLL_WITH_BOIDS
#define BOIDSTATE_CURRENT
#define BOID_ALLOW_FLIGHT
@ eBoidMode_OnLand
@ eBoidMode_Liftoff
@ eBoidMode_Climbing
@ eBoidMode_Falling
@ eBoidMode_InAir
#define BRULE_ACOLL_WITH_DEFLECTORS
#define BRULE_LEADER_IN_LINE
#define BOIDRULE_IN_AIR
@ eBoidRulesetType_Average
@ eBoidRulesetType_Fuzzy
@ eBoidRulesetType_Random
#define BOID_ALLOW_LAND
#define BOIDRULE_ON_LAND
#define BOID_ALLOW_CLIMB
#define BRULE_GOAL_AVOID_PREDICT
@ eBoidRuleType_Goal
@ eBoidRuleType_Fight
@ eBoidRuleType_Avoid
@ eBoidRuleType_FollowLeader
@ eBoidRuleType_AvoidCollision
@ eBoidRuleType_AverageSpeed
@ eModifierType_Surface
#define PFIELD_SHAPE_SURFACE
#define PTARGET_MODE_FRIEND
#define PART_SIZEMASS
#define PTARGET_MODE_ENEMY
#define PARS_DYING
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
void boid_free_settings(BoidSettings *boids)
Definition: boids.c:1700
static bool rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa)
Definition: boids.c:468
BoidState * boid_duplicate_state(BoidSettings *boids, BoidState *state)
Definition: boids.c:1688
BoidState * boid_get_current_state(BoidSettings *boids)
Definition: boids.c:1739
static bool boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
Definition: boids.c:963
BoidState * boid_new_state(BoidSettings *boids)
Definition: boids.c:1669
static bool rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:645
static Object * boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3])
Definition: boids.c:855
struct BoidValues BoidValues
BoidRule * boid_new_rule(int type)
Definition: boids.c:1603
static bool rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:505
static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
Definition: boids.c:1001
static bool apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
Definition: boids.c:1031
void boid_body(BoidBrainData *bbd, ParticleData *pa)
Definition: boids.c:1235
static bool rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:83
void boids_precalc_rules(ParticleSettings *part, float cfra)
Definition: boids.c:982
static bool rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:217
static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:700
static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
Definition: boids.c:1022
bool(* boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa)
Definition: boids.c:811
BoidSettings * boid_copy_settings(const BoidSettings *boids)
Definition: boids.c:1716
static float len_squared_v3v3_with_normal_bias(const float co_search[3], const float co_test[3], const void *user_data)
Definition: boids.c:48
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
Definition: boids.c:1079
static bool rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
Definition: boids.c:417
static boid_rule_cb boid_rules[]
Definition: boids.c:816
static BoidState * get_boid_state(BoidSettings *boids, ParticleData *pa)
Definition: boids.c:1053
static bool rule_none(BoidRule *UNUSED(rule), BoidBrainData *UNUSED(data), BoidValues *UNUSED(val), ParticleData *UNUSED(pa))
Definition: boids.c:75
static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
Definition: boids.c:833
void boid_default_settings(BoidSettings *boids)
Definition: boids.c:1643
void jump(const btVector3 &v=btVector3(0, 0, 0))
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
static void mul(btAlignedObjectArray< T > &items, const Q &value)
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
void * user_data
struct @203::@204 surface
uint nor
uint col
IconTextureDrawCall normal
#define powf(x, y)
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong state[N]
return ret
const EnumPropertyItem rna_enum_boidrule_type_items[]
Definition: rna_boid.c:43
float wanted_co[3]
Definition: BKE_boids.h:42
float cfra
Definition: BKE_boids.h:41
float dfra
Definition: BKE_boids.h:41
float goal_nor[3]
Definition: BKE_boids.h:47
struct ParticleSettings * part
Definition: BKE_boids.h:40
struct Object * goal_ob
Definition: BKE_boids.h:45
struct RNG * rng
Definition: BKE_boids.h:50
float timestep
Definition: BKE_boids.h:41
float wanted_speed
Definition: BKE_boids.h:42
float goal_priority
Definition: BKE_boids.h:48
struct ParticleSimulationData * sim
Definition: BKE_boids.h:39
float goal_co[3]
Definition: BKE_boids.h:46
short state_id
float health
float acc[3]
struct Object * ground
struct BoidData data
struct Object * ob
struct Object * ob
struct BoidRule * next
char name[32]
float land_max_speed
struct ListBase states
float landing_smoothness
float land_jump_speed
float land_stick_force
float air_personal_space
float land_personal_space
ListBase conditions
ListBase actions
ListBase rules
struct BoidState * next
float personal_space
Definition: boids.c:69
float min_speed
Definition: boids.c:68
float max_ave
Definition: boids.c:68
float max_speed
Definition: boids.c:67
float max_acc
Definition: boids.c:67
float jump_speed
Definition: boids.c:69
struct Object * ob
struct CollisionModifierData * collmd
struct ColliderCache * next
struct Scene * scene
Definition: BKE_effect.h:89
struct PartDeflect * pd
Definition: BKE_effect.h:94
struct EffectorCache * next
Definition: BKE_effect.h:86
struct Object * ob
Definition: BKE_effect.h:90
struct Depsgraph * depsgraph
Definition: BKE_effect.h:88
float loc[3]
Definition: BKE_effect.h:68
float distance
Definition: BKE_effect.h:73
float vec_to_point[3]
Definition: BKE_effect.h:72
int * index
Definition: BKE_effect.h:81
float nor[3]
Definition: BKE_effect.h:69
float vel[3]
Definition: BKE_effect.h:70
const char * name
Definition: RNA_types.h:450
void * first
Definition: DNA_listBase.h:47
float obmat[4][4]
BoidParticle * boid
ParticleKey state
ParticleKey prev_state
struct BoidSettings * boids
struct EffectorWeights * effector_weights
struct Depsgraph * depsgraph
Definition: BKE_particle.h:87
struct Scene * scene
Definition: BKE_particle.h:88
struct ParticleSystem * psys
Definition: BKE_particle.h:90
struct Object * ob
Definition: BKE_particle.h:89
struct ListBase * colliders
Definition: BKE_particle.h:92
ParticleData * particles
struct ListBase targets
ParticleSettings * part
struct ListBase * effectors
struct KDTree_3d * tree
struct ParticleTarget * next
struct PhysicsSettings physics_settings
uint len