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