| 
									
										
										
										
											2011-10-10 09:38:02 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2009 by Janne Karhu. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bke | 
					
						
							| 
									
										
										
										
											2011-02-27 20:40:57 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | #include <math.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 11:14:08 +11:00
										 |  |  | #include "DNA_object_force_types.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | #include "DNA_scene_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h"
 | 
					
						
							|  |  |  | #include "BLI_kdtree.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BLI_math.h"
 | 
					
						
							|  |  |  | #include "BLI_rand.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 18:36:47 +00:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BKE_boids.h"
 | 
					
						
							| 
									
										
											  
											
												Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons) 
  instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group 
  setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
	- "Point" is most like the old effectors and uses the 
	  effector location as the effector point.
	- "Plane" uses the closest point on effectors local xy-plane 
	  as the effector point.
	- "Surface" uses the closest point on an effector object's 
	  surface as the effector point.
	- "Every Point" uses every point in a mesh effector object 
	  as an effector point.
	- The falloff is calculated from this point, so for example 
	  with "surface" shape and "use only negative z axis" it's 
	  possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer 
  just spherical.
* New effector parameter "flow", which makes the effector act as 
  surrounding air velocity, so the resulting force is 
  proportional to the velocity difference of the point and "air 
  velocity". For example a wind field with flow=1.0 results in 
  proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random 
  flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force 
  (note. the z-axis is the surface normal in the case of 
  effector shape "surface")
* New "force field" submenu in add menu, which adds an empty 
  with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector 
  system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for 
  particles, softbody & cloth, since their final effect depends on many external 
  factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through 
  DAG_id_flush_update(..).
  
Known issues
* Curve guides don't yet have all ui buttons in place, but they 
  should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50 
  frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to 
  free pidlists after use :).
											
										 
											2009-09-30 22:10:14 +00:00
										 |  |  | #include "BKE_collision.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | #include "BKE_effect.h"
 | 
					
						
							|  |  |  | #include "BKE_particle.h"
 | 
					
						
							| 
									
										
										
										
											2020-12-15 10:47:58 +11:00
										 |  |  | #include "BLI_kdopbvh.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:18:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | #include "BKE_modifier.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "RNA_enum_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static float len_squared_v3v3_with_normal_bias(const float co_search[3], | 
					
						
							|  |  |  |                                                const float co_test[3], | 
					
						
							|  |  |  |                                                const void *user_data) | 
					
						
							| 
									
										
										
										
											2019-03-18 09:28:32 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const float *normal = user_data; | 
					
						
							|  |  |  |   float d[3], dist; | 
					
						
							| 
									
										
										
										
											2019-03-18 09:28:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   sub_v3_v3v3(d, co_test, co_search); | 
					
						
							| 
									
										
										
										
											2019-03-18 09:28:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   dist = len_squared_v3(d); | 
					
						
							| 
									
										
										
										
											2019-03-18 09:28:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Avoid head-on collisions. */ | 
					
						
							|  |  |  |   if (dot_v3v3(d, normal) < 0.0f) { | 
					
						
							|  |  |  |     dist *= 10.0f; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return dist; | 
					
						
							| 
									
										
										
										
											2019-03-18 09:28:32 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | typedef struct BoidValues { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float max_speed, max_acc; | 
					
						
							|  |  |  |   float max_ave, min_speed; | 
					
						
							|  |  |  |   float personal_space, jump_speed; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } BoidValues; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool apply_boid_rule( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_none(BoidRule *UNUSED(rule), | 
					
						
							|  |  |  |                       BoidBrainData *UNUSED(data), | 
					
						
							|  |  |  |                       BoidValues *UNUSED(val), | 
					
						
							|  |  |  |                       ParticleData *UNUSED(pa)) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; | 
					
						
							|  |  |  |   BoidSettings *boids = bbd->part->boids; | 
					
						
							|  |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   EffectedPoint epoint; | 
					
						
							|  |  |  |   ListBase *effectors = bbd->sim->psys->effectors; | 
					
						
							|  |  |  |   EffectorCache *cur, *eff = NULL; | 
					
						
							|  |  |  |   EffectorCache temp_eff; | 
					
						
							|  |  |  |   EffectorData efd, cur_efd; | 
					
						
							|  |  |  |   float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0); | 
					
						
							|  |  |  |   float priority = 0.0f, len = 0.0f; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   bool ret = false; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   int p = 0; | 
					
						
							|  |  |  |   efd.index = cur_efd.index = &p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* first find out goal/predator with highest priority */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (effectors) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (cur = effectors->first; cur; cur = cur->next) { | 
					
						
							|  |  |  |       Object *eob = cur->ob; | 
					
						
							|  |  |  |       PartDeflect *pd = cur->pd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) { | 
					
						
							|  |  |  |         if (gabr->ob == eob) { | 
					
						
							|  |  |  |           /* TODO: effectors with multiple points */ | 
					
						
							|  |  |  |           if (get_effector_data(cur, &efd, &epoint, 0)) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |             if (cur->pd && cur->pd->forcefield == PFIELD_BOID) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |               priority = mul * pd->f_strength * | 
					
						
							|  |  |  |                          effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |               priority = 1.0; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             eff = cur; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) { | 
					
						
							|  |  |  |         /* skip current object */ | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && | 
					
						
							|  |  |  |                get_effector_data(cur, &cur_efd, &epoint, 0)) { | 
					
						
							|  |  |  |         float temp = mul * pd->f_strength * | 
					
						
							|  |  |  |                      effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (temp == 0.0f) { | 
					
						
							|  |  |  |           /* do nothing */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (temp > priority) { | 
					
						
							|  |  |  |           priority = temp; | 
					
						
							|  |  |  |           eff = cur; | 
					
						
							|  |  |  |           efd = cur_efd; | 
					
						
							|  |  |  |           len = efd.distance; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* choose closest object with same priority */ | 
					
						
							|  |  |  |         else if (temp == priority && efd.distance < len) { | 
					
						
							|  |  |  |           eff = cur; | 
					
						
							|  |  |  |           efd = cur_efd; | 
					
						
							|  |  |  |           len = efd.distance; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* if the object doesn't have effector data we have to fake it */ | 
					
						
							|  |  |  |   if (eff == NULL && gabr->ob) { | 
					
						
							|  |  |  |     memset(&temp_eff, 0, sizeof(EffectorCache)); | 
					
						
							|  |  |  |     temp_eff.ob = gabr->ob; | 
					
						
							|  |  |  |     temp_eff.depsgraph = bbd->sim->depsgraph; | 
					
						
							|  |  |  |     temp_eff.scene = bbd->sim->scene; | 
					
						
							|  |  |  |     eff = &temp_eff; | 
					
						
							|  |  |  |     get_effector_data(eff, &efd, &epoint, 0); | 
					
						
							|  |  |  |     priority = 1.0f; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* then use that effector */ | 
					
						
							|  |  |  |   if (priority > (rule->type == eBoidRuleType_Avoid ? | 
					
						
							|  |  |  |                       gabr->fear_factor : | 
					
						
							|  |  |  |                       0.0f)) { /* with avoid, factor is "fear factor" */ | 
					
						
							|  |  |  |     Object *eob = eff->ob; | 
					
						
							|  |  |  |     PartDeflect *pd = eff->pd; | 
					
						
							|  |  |  |     float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (gabr->options & BRULE_GOAL_AVOID_PREDICT) { | 
					
						
							|  |  |  |       /* estimate future location of target */ | 
					
						
							|  |  |  |       get_effector_data(eff, &efd, &epoint, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep)); | 
					
						
							|  |  |  |       add_v3_v3(efd.loc, efd.vel); | 
					
						
							|  |  |  |       sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc); | 
					
						
							|  |  |  |       efd.distance = len_v3(efd.vec_to_point); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface != 0.0f) { | 
					
						
							|  |  |  |       if (!bbd->goal_ob || bbd->goal_priority < priority) { | 
					
						
							|  |  |  |         bbd->goal_ob = eob; | 
					
						
							|  |  |  |         copy_v3_v3(bbd->goal_co, efd.loc); | 
					
						
							|  |  |  |         copy_v3_v3(bbd->goal_nor, efd.nor); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if ((rule->type == eBoidRuleType_Avoid) && (bpa->data.mode == eBoidMode_Climbing) && | 
					
						
							|  |  |  |              (priority > 2.0f * gabr->fear_factor)) { | 
					
						
							|  |  |  |       /* detach from surface and try to fly away from danger */ | 
					
						
							|  |  |  |       negate_v3_v3(efd.vec_to_point, bpa->gravity); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(bbd->wanted_co, efd.vec_to_point); | 
					
						
							|  |  |  |     mul_v3_fl(bbd->wanted_co, mul); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bbd->wanted_speed = val->max_speed * priority; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* with goals factor is approach velocity factor */ | 
					
						
							|  |  |  |     if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) { | 
					
						
							|  |  |  |       float len2 = 2.0f * len_v3(pa->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       surface *= pa->size * boids->height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (len2 > 0.0f && efd.distance - surface < len2) { | 
					
						
							|  |  |  |         len2 = (efd.distance - surface) / len2; | 
					
						
							|  |  |  |         bbd->wanted_speed *= powf(len2, boids->landing_smoothness); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_avoid_collision(BoidRule *rule, | 
					
						
							|  |  |  |                                  BoidBrainData *bbd, | 
					
						
							|  |  |  |                                  BoidValues *val, | 
					
						
							|  |  |  |                                  ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-18 12:21:38 +10:00
										 |  |  |   const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision *)rule; | 
					
						
							|  |  |  |   KDTreeNearest_3d *ptn = NULL; | 
					
						
							|  |  |  |   ParticleTarget *pt; | 
					
						
							|  |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   ColliderCache *coll; | 
					
						
							|  |  |  |   float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   float co1[3], vel1[3], co2[3], vel2[3]; | 
					
						
							|  |  |  |   float len, t, inp, t_min = 2.0f; | 
					
						
							|  |  |  |   int n, neighbors = 0, nearest = 0; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   bool ret = 0; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |   // check deflector objects first
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { | 
					
						
							|  |  |  |     ParticleCollision col; | 
					
						
							|  |  |  |     BVHTreeRayHit hit; | 
					
						
							|  |  |  |     float radius = val->personal_space * pa->size, ray_dir[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memset(&col, 0, sizeof(ParticleCollision)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(col.co1, pa->prev_state.co); | 
					
						
							|  |  |  |     add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); | 
					
						
							|  |  |  |     sub_v3_v3v3(ray_dir, col.co2, col.co1); | 
					
						
							|  |  |  |     mul_v3_fl(ray_dir, acbr->look_ahead); | 
					
						
							|  |  |  |     col.f = 0.0f; | 
					
						
							|  |  |  |     hit.index = -1; | 
					
						
							|  |  |  |     hit.dist = col.original_ray_length = normalize_v3(ray_dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* find out closest deflector object */ | 
					
						
							|  |  |  |     for (coll = bbd->sim->colliders->first; coll; coll = coll->next) { | 
					
						
							|  |  |  |       /* don't check with current ground object */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (coll->ob == bpa->ground) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       col.current = coll->ob; | 
					
						
							|  |  |  |       col.md = coll->collmd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (col.md && col.md->bvhtree) { | 
					
						
							|  |  |  |         BLI_bvhtree_ray_cast_ex(col.md->bvhtree, | 
					
						
							|  |  |  |                                 col.co1, | 
					
						
							|  |  |  |                                 ray_dir, | 
					
						
							|  |  |  |                                 radius, | 
					
						
							|  |  |  |                                 &hit, | 
					
						
							|  |  |  |                                 BKE_psys_collision_neartest_cb, | 
					
						
							|  |  |  |                                 &col, | 
					
						
							|  |  |  |                                 raycast_flag); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* then avoid that object */ | 
					
						
							|  |  |  |     if (hit.index >= 0) { | 
					
						
							|  |  |  |       t = hit.dist / col.original_ray_length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* avoid head-on collision */ | 
					
						
							|  |  |  |       if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) { | 
					
						
							|  |  |  |         /* don't know why, but uneven range [0.0, 1.0] */ | 
					
						
							|  |  |  |         /* works much better than even [-1.0, 1.0] */ | 
					
						
							|  |  |  |         bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng); | 
					
						
							|  |  |  |         bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng); | 
					
						
							|  |  |  |         bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         copy_v3_v3(bbd->wanted_co, col.pce.nor); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel); | 
					
						
							|  |  |  |       bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |   // check boids in own system
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (acbr->options & BRULE_ACOLL_WITH_BOIDS) { | 
					
						
							|  |  |  |     neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree, | 
					
						
							|  |  |  |                                                                pa->prev_state.co, | 
					
						
							|  |  |  |                                                                &ptn, | 
					
						
							|  |  |  |                                                                acbr->look_ahead * | 
					
						
							|  |  |  |                                                                    len_v3(pa->prev_state.vel), | 
					
						
							|  |  |  |                                                                len_squared_v3v3_with_normal_bias, | 
					
						
							|  |  |  |                                                                pa->prev_state.ave); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (neighbors > 1) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       for (n = 1; n < neighbors; n++) { | 
					
						
							|  |  |  |         copy_v3_v3(co1, pa->prev_state.co); | 
					
						
							|  |  |  |         copy_v3_v3(vel1, pa->prev_state.vel); | 
					
						
							|  |  |  |         copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co); | 
					
						
							|  |  |  |         copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sub_v3_v3v3(loc, co1, co2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sub_v3_v3v3(vec, vel1, vel2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inp = dot_v3v3(vec, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* velocities not parallel */ | 
					
						
							|  |  |  |         if (inp != 0.0f) { | 
					
						
							|  |  |  |           t = -dot_v3v3(loc, vec) / inp; | 
					
						
							|  |  |  |           /* cpa is not too far in the future so investigate further */ | 
					
						
							|  |  |  |           if (t > 0.0f && t < t_min) { | 
					
						
							|  |  |  |             madd_v3_v3fl(co1, vel1, t); | 
					
						
							|  |  |  |             madd_v3_v3fl(co2, vel2, t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             sub_v3_v3v3(vec, co2, co1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             len = normalize_v3(vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* distance of cpa is close enough */ | 
					
						
							|  |  |  |             if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |               t_min = t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               mul_v3_fl(vec, len_v3(vel1)); | 
					
						
							|  |  |  |               mul_v3_fl(vec, (2.0f - t) / 2.0f); | 
					
						
							|  |  |  |               sub_v3_v3v3(bbd->wanted_co, vel1, vec); | 
					
						
							|  |  |  |               bbd->wanted_speed = len_v3(bbd->wanted_co); | 
					
						
							|  |  |  |               ret = 1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (ptn) { | 
					
						
							|  |  |  |     MEM_freeN(ptn); | 
					
						
							|  |  |  |     ptn = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* check boids in other systems */ | 
					
						
							|  |  |  |   for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) { | 
					
						
							|  |  |  |     ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (epsys) { | 
					
						
							|  |  |  |       BLI_assert(epsys->tree != NULL); | 
					
						
							|  |  |  |       neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(epsys->tree, | 
					
						
							|  |  |  |                                                                  pa->prev_state.co, | 
					
						
							|  |  |  |                                                                  &ptn, | 
					
						
							|  |  |  |                                                                  acbr->look_ahead * | 
					
						
							|  |  |  |                                                                      len_v3(pa->prev_state.vel), | 
					
						
							|  |  |  |                                                                  len_squared_v3v3_with_normal_bias, | 
					
						
							|  |  |  |                                                                  pa->prev_state.ave); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (neighbors > 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         for (n = 0; n < neighbors; n++) { | 
					
						
							|  |  |  |           copy_v3_v3(co1, pa->prev_state.co); | 
					
						
							|  |  |  |           copy_v3_v3(vel1, pa->prev_state.vel); | 
					
						
							|  |  |  |           copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co); | 
					
						
							|  |  |  |           copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           sub_v3_v3v3(loc, co1, co2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           sub_v3_v3v3(vec, vel1, vel2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           inp = dot_v3v3(vec, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           /* velocities not parallel */ | 
					
						
							|  |  |  |           if (inp != 0.0f) { | 
					
						
							|  |  |  |             t = -dot_v3v3(loc, vec) / inp; | 
					
						
							|  |  |  |             /* cpa is not too far in the future so investigate further */ | 
					
						
							|  |  |  |             if (t > 0.0f && t < t_min) { | 
					
						
							|  |  |  |               madd_v3_v3fl(co1, vel1, t); | 
					
						
							|  |  |  |               madd_v3_v3fl(co2, vel2, t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               sub_v3_v3v3(vec, co2, co1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               len = normalize_v3(vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               /* distance of cpa is close enough */ | 
					
						
							|  |  |  |               if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |                 t_min = t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 mul_v3_fl(vec, len_v3(vel1)); | 
					
						
							|  |  |  |                 mul_v3_fl(vec, (2.0f - t) / 2.0f); | 
					
						
							|  |  |  |                 sub_v3_v3v3(bbd->wanted_co, vel1, vec); | 
					
						
							|  |  |  |                 bbd->wanted_speed = len_v3(bbd->wanted_co); | 
					
						
							|  |  |  |                 ret = 1; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (ptn) { | 
					
						
							|  |  |  |         MEM_freeN(ptn); | 
					
						
							|  |  |  |         ptn = NULL; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (ptn && nearest == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(ptn); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_separate(BoidRule *UNUSED(rule), | 
					
						
							|  |  |  |                           BoidBrainData *bbd, | 
					
						
							|  |  |  |                           BoidValues *val, | 
					
						
							|  |  |  |                           ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   KDTreeNearest_3d *ptn = NULL; | 
					
						
							|  |  |  |   ParticleTarget *pt; | 
					
						
							|  |  |  |   float len = 2.0f * val->personal_space * pa->size + 1.0f; | 
					
						
							|  |  |  |   float vec[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   int neighbors = BLI_kdtree_3d_range_search( | 
					
						
							|  |  |  |       bbd->sim->psys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size); | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   bool ret = false; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (neighbors > 1 && ptn[1].dist != 0.0f) { | 
					
						
							|  |  |  |     sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co); | 
					
						
							|  |  |  |     mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist); | 
					
						
							|  |  |  |     add_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  |     bbd->wanted_speed = val->max_speed; | 
					
						
							|  |  |  |     len = ptn[1].dist; | 
					
						
							|  |  |  |     ret = 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (ptn) { | 
					
						
							|  |  |  |     MEM_freeN(ptn); | 
					
						
							|  |  |  |     ptn = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* check other boid systems */ | 
					
						
							|  |  |  |   for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) { | 
					
						
							|  |  |  |     ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (epsys) { | 
					
						
							|  |  |  |       neighbors = BLI_kdtree_3d_range_search( | 
					
						
							|  |  |  |           epsys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (neighbors > 0 && ptn[0].dist < len) { | 
					
						
							|  |  |  |         sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co); | 
					
						
							|  |  |  |         mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist); | 
					
						
							|  |  |  |         add_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  |         bbd->wanted_speed = val->max_speed; | 
					
						
							|  |  |  |         len = ptn[0].dist; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |         ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (ptn) { | 
					
						
							|  |  |  |         MEM_freeN(ptn); | 
					
						
							|  |  |  |         ptn = NULL; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_flock(BoidRule *UNUSED(rule), | 
					
						
							|  |  |  |                        BoidBrainData *bbd, | 
					
						
							|  |  |  |                        BoidValues *UNUSED(val), | 
					
						
							|  |  |  |                        ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   KDTreeNearest_3d ptn[11]; | 
					
						
							|  |  |  |   float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   int neighbors = BLI_kdtree_3d_find_nearest_n_with_len_squared_cb( | 
					
						
							|  |  |  |       bbd->sim->psys->tree, | 
					
						
							|  |  |  |       pa->state.co, | 
					
						
							|  |  |  |       ptn, | 
					
						
							|  |  |  |       ARRAY_SIZE(ptn), | 
					
						
							|  |  |  |       len_squared_v3v3_with_normal_bias, | 
					
						
							|  |  |  |       pa->prev_state.ave); | 
					
						
							|  |  |  |   int n; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   bool ret = false; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (neighbors > 1) { | 
					
						
							|  |  |  |     for (n = 1; n < neighbors; n++) { | 
					
						
							|  |  |  |       add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co); | 
					
						
							|  |  |  |       add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mul_v3_fl(loc, 1.0f / ((float)neighbors - 1.0f)); | 
					
						
							|  |  |  |     mul_v3_fl(vec, 1.0f / ((float)neighbors - 1.0f)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sub_v3_v3(loc, pa->prev_state.co); | 
					
						
							|  |  |  |     sub_v3_v3(vec, pa->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     add_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  |     add_v3_v3(bbd->wanted_co, loc); | 
					
						
							|  |  |  |     bbd->wanted_speed = len_v3(bbd->wanted_co); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_follow_leader(BoidRule *rule, | 
					
						
							|  |  |  |                                BoidBrainData *bbd, | 
					
						
							|  |  |  |                                BoidValues *val, | 
					
						
							|  |  |  |                                ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; | 
					
						
							|  |  |  |   float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   float mul, len; | 
					
						
							|  |  |  |   int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   int i, p = pa - bbd->sim->psys->particles; | 
					
						
							|  |  |  |   bool ret = false; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (flbr->ob) { | 
					
						
							|  |  |  |     float vec2[3], t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* first check we're not blocking the leader */ | 
					
						
							|  |  |  |     sub_v3_v3v3(vec, flbr->loc, flbr->oloc); | 
					
						
							|  |  |  |     mul_v3_fl(vec, 1.0f / bbd->timestep); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mul = dot_v3v3(vec, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* leader is not moving */ | 
					
						
							|  |  |  |     if (mul < 0.01f) { | 
					
						
							|  |  |  |       len = len_v3(loc); | 
					
						
							|  |  |  |       /* too close to leader */ | 
					
						
							|  |  |  |       if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |         copy_v3_v3(bbd->wanted_co, loc); | 
					
						
							|  |  |  |         bbd->wanted_speed = val->max_speed; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       t = dot_v3v3(loc, vec) / mul; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* possible blocking of leader in near future */ | 
					
						
							|  |  |  |       if (t > 0.0f && t < 3.0f) { | 
					
						
							|  |  |  |         copy_v3_v3(vec2, vec); | 
					
						
							|  |  |  |         mul_v3_fl(vec2, t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sub_v3_v3v3(vec2, loc, vec2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         len = len_v3(vec2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |           copy_v3_v3(bbd->wanted_co, vec2); | 
					
						
							|  |  |  |           bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |           return true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* not blocking so try to follow leader */ | 
					
						
							|  |  |  |     if (p && flbr->options & BRULE_LEADER_IN_LINE) { | 
					
						
							|  |  |  |       copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel); | 
					
						
							|  |  |  |       copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       copy_v3_v3(loc, flbr->oloc); | 
					
						
							|  |  |  |       sub_v3_v3v3(vec, flbr->loc, flbr->oloc); | 
					
						
							|  |  |  |       mul_v3_fl(vec, 1.0f / bbd->timestep); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* fac is seconds behind leader */ | 
					
						
							|  |  |  |     madd_v3_v3fl(loc, vec, -flbr->distance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); | 
					
						
							|  |  |  |     bbd->wanted_speed = len_v3(bbd->wanted_co); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (p % n) { | 
					
						
							|  |  |  |     float vec2[3], t, t_min = 3.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* first check we're not blocking any leaders */ | 
					
						
							|  |  |  |     for (i = 0; i < bbd->sim->psys->totpart; i += n) { | 
					
						
							|  |  |  |       copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       mul = dot_v3v3(vec, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* leader is not moving */ | 
					
						
							|  |  |  |       if (mul < 0.01f) { | 
					
						
							|  |  |  |         len = len_v3(loc); | 
					
						
							|  |  |  |         /* too close to leader */ | 
					
						
							|  |  |  |         if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |           copy_v3_v3(bbd->wanted_co, loc); | 
					
						
							|  |  |  |           bbd->wanted_speed = val->max_speed; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |           return true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         t = dot_v3v3(loc, vec) / mul; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* possible blocking of leader in near future */ | 
					
						
							|  |  |  |         if (t > 0.0f && t < t_min) { | 
					
						
							|  |  |  |           copy_v3_v3(vec2, vec); | 
					
						
							|  |  |  |           mul_v3_fl(vec2, t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           sub_v3_v3v3(vec2, loc, vec2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           len = len_v3(vec2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (len < 2.0f * val->personal_space * pa->size) { | 
					
						
							|  |  |  |             t_min = t; | 
					
						
							|  |  |  |             copy_v3_v3(bbd->wanted_co, loc); | 
					
						
							|  |  |  |             bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |             ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (ret) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* not blocking so try to follow leader */ | 
					
						
							|  |  |  |     if (flbr->options & BRULE_LEADER_IN_LINE) { | 
					
						
							|  |  |  |       copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel); | 
					
						
							|  |  |  |       copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       copy_v3_v3(vec, bbd->sim->psys->particles[p - p % n].prev_state.vel); | 
					
						
							|  |  |  |       copy_v3_v3(loc, bbd->sim->psys->particles[p - p % n].prev_state.co); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* fac is seconds behind leader */ | 
					
						
							|  |  |  |     madd_v3_v3fl(loc, vec, -flbr->distance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co); | 
					
						
							|  |  |  |     bbd->wanted_speed = len_v3(bbd->wanted_co); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_average_speed(BoidRule *rule, | 
					
						
							|  |  |  |                                BoidBrainData *bbd, | 
					
						
							|  |  |  |                                BoidValues *val, | 
					
						
							|  |  |  |                                ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed *)rule; | 
					
						
							|  |  |  |   float vec[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (asbr->wander > 0.0f) { | 
					
						
							|  |  |  |     /* abuse pa->r_ave for wandering */ | 
					
						
							|  |  |  |     bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |     bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |     bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     normalize_v3(bpa->wander); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(vec, bpa->wander); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mul_qt_v3(pa->prev_state.rot, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(bbd->wanted_co, pa->prev_state.ave); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mul_v3_fl(bbd->wanted_co, 1.1f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     add_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* leveling */ | 
					
						
							|  |  |  |     if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) { | 
					
						
							|  |  |  |       project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity); | 
					
						
							|  |  |  |       mul_v3_fl(vec, asbr->level); | 
					
						
							|  |  |  |       sub_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     copy_v3_v3(bbd->wanted_co, pa->prev_state.ave); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* may happen at birth */ | 
					
						
							|  |  |  |     if (dot_v2v2(bbd->wanted_co, bbd->wanted_co) == 0.0f) { | 
					
						
							|  |  |  |       bbd->wanted_co[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |       bbd->wanted_co[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |       bbd->wanted_co[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* leveling */ | 
					
						
							|  |  |  |     if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) { | 
					
						
							|  |  |  |       project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity); | 
					
						
							|  |  |  |       mul_v3_fl(vec, asbr->level); | 
					
						
							|  |  |  |       sub_v3_v3(bbd->wanted_co, vec); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   bbd->wanted_speed = asbr->speed * val->max_speed; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRuleFight *fbr = (BoidRuleFight *)rule; | 
					
						
							|  |  |  |   KDTreeNearest_3d *ptn = NULL; | 
					
						
							|  |  |  |   ParticleTarget *pt; | 
					
						
							|  |  |  |   ParticleData *epars; | 
					
						
							|  |  |  |   ParticleData *enemy_pa = NULL; | 
					
						
							|  |  |  |   BoidParticle *bpa; | 
					
						
							|  |  |  |   /* friends & enemies */ | 
					
						
							|  |  |  |   float closest_enemy[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   float closest_dist = fbr->distance + 1.0f; | 
					
						
							|  |  |  |   float f_strength = 0.0f, e_strength = 0.0f; | 
					
						
							|  |  |  |   float health = 0.0f; | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   int n; | 
					
						
							|  |  |  |   bool ret = false; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* calculate own group strength */ | 
					
						
							|  |  |  |   int neighbors = BLI_kdtree_3d_range_search( | 
					
						
							|  |  |  |       bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance); | 
					
						
							|  |  |  |   for (n = 0; n < neighbors; n++) { | 
					
						
							|  |  |  |     bpa = bbd->sim->psys->particles[ptn[n].index].boid; | 
					
						
							|  |  |  |     health += bpa->data.health; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   f_strength += bbd->part->boids->strength * health; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ptn) { | 
					
						
							|  |  |  |     MEM_freeN(ptn); | 
					
						
							|  |  |  |     ptn = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* add other friendlies and calculate enemy strength and find closest enemy */ | 
					
						
							|  |  |  |   for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) { | 
					
						
							|  |  |  |     ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); | 
					
						
							|  |  |  |     if (epsys) { | 
					
						
							|  |  |  |       epars = epsys->particles; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       neighbors = BLI_kdtree_3d_range_search(epsys->tree, pa->prev_state.co, &ptn, fbr->distance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       health = 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (n = 0; n < neighbors; n++) { | 
					
						
							|  |  |  |         bpa = epars[ptn[n].index].boid; | 
					
						
							|  |  |  |         health += bpa->data.health; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (n == 0 && pt->mode == PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) { | 
					
						
							|  |  |  |           copy_v3_v3(closest_enemy, ptn[n].co); | 
					
						
							|  |  |  |           closest_dist = ptn[n].dist; | 
					
						
							|  |  |  |           enemy_pa = epars + ptn[n].index; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (pt->mode == PTARGET_MODE_ENEMY) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         e_strength += epsys->part->boids->strength * health; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else if (pt->mode == PTARGET_MODE_FRIEND) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         f_strength += epsys->part->boids->strength * health; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (ptn) { | 
					
						
							|  |  |  |         MEM_freeN(ptn); | 
					
						
							|  |  |  |         ptn = NULL; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* decide action if enemy presence found */ | 
					
						
							|  |  |  |   if (e_strength > 0.0f) { | 
					
						
							|  |  |  |     sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* attack if in range */ | 
					
						
							|  |  |  |     if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) { | 
					
						
							|  |  |  |       float damage = BLI_rng_get_float(bbd->rng); | 
					
						
							|  |  |  |       float enemy_dir[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       normalize_v3_v3(enemy_dir, bbd->wanted_co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* fight mode */ | 
					
						
							|  |  |  |       bbd->wanted_speed = 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* must face enemy to fight */ | 
					
						
							|  |  |  |       if (dot_v3v3(pa->prev_state.ave, enemy_dir) > 0.5f) { | 
					
						
							|  |  |  |         bpa = enemy_pa->boid; | 
					
						
							|  |  |  |         bpa->data.health -= bbd->part->boids->strength * bbd->timestep * | 
					
						
							|  |  |  |                             ((1.0f - bbd->part->boids->accuracy) * damage + | 
					
						
							|  |  |  |                              bbd->part->boids->accuracy); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       /* approach mode */ | 
					
						
							|  |  |  |       bbd->wanted_speed = val->max_speed; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* check if boid doesn't want to fight */ | 
					
						
							|  |  |  |     bpa = pa->boid; | 
					
						
							|  |  |  |     if (bpa->data.health / bbd->part->boids->health * bbd->part->boids->aggression < | 
					
						
							|  |  |  |         e_strength / f_strength) { | 
					
						
							|  |  |  |       /* decide to flee */ | 
					
						
							|  |  |  |       if (closest_dist < fbr->flee_distance * fbr->distance) { | 
					
						
							|  |  |  |         negate_v3(bbd->wanted_co); | 
					
						
							|  |  |  |         bbd->wanted_speed = val->max_speed; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { /* wait for better odds */ | 
					
						
							|  |  |  |         bbd->wanted_speed = 0.0f; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     ret = true; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | typedef bool (*boid_rule_cb)(BoidRule *rule, | 
					
						
							|  |  |  |                              BoidBrainData *data, | 
					
						
							|  |  |  |                              BoidValues *val, | 
					
						
							|  |  |  |                              ParticleData *pa); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static boid_rule_cb boid_rules[] = { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     rule_none, | 
					
						
							|  |  |  |     rule_goal_avoid, | 
					
						
							|  |  |  |     rule_goal_avoid, | 
					
						
							|  |  |  |     rule_avoid_collision, | 
					
						
							|  |  |  |     rule_separate, | 
					
						
							|  |  |  |     rule_flock, | 
					
						
							|  |  |  |     rule_follow_leader, | 
					
						
							|  |  |  |     rule_average_speed, | 
					
						
							|  |  |  |     rule_fight, | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |     // rule_help,
 | 
					
						
							|  |  |  |     // rule_protect,
 | 
					
						
							|  |  |  |     // rule_hide,
 | 
					
						
							|  |  |  |     // rule_follow_path,
 | 
					
						
							|  |  |  |     // rule_follow_wall,
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { | 
					
						
							|  |  |  |     val->max_speed = boids->land_max_speed * bpa->data.health / boids->health; | 
					
						
							|  |  |  |     val->max_acc = boids->land_max_acc * val->max_speed; | 
					
						
							|  |  |  |     val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health / boids->health; | 
					
						
							|  |  |  |     val->min_speed = 0.0f; /* no minimum speed on land */ | 
					
						
							|  |  |  |     val->personal_space = boids->land_personal_space; | 
					
						
							|  |  |  |     val->jump_speed = boids->land_jump_speed * bpa->data.health / boids->health; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     val->max_speed = boids->air_max_speed * bpa->data.health / boids->health; | 
					
						
							|  |  |  |     val->max_acc = boids->air_max_acc * val->max_speed; | 
					
						
							|  |  |  |     val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health / boids->health; | 
					
						
							|  |  |  |     val->min_speed = boids->air_min_speed * boids->air_max_speed; | 
					
						
							|  |  |  |     val->personal_space = boids->air_personal_space; | 
					
						
							|  |  |  |     val->jump_speed = 0.0f; /* no jumping in air */ | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-09-16 20:00:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static Object *boid_find_ground(BoidBrainData *bbd, | 
					
						
							|  |  |  |                                 ParticleData *pa, | 
					
						
							|  |  |  |                                 float ground_co[3], | 
					
						
							|  |  |  |                                 float ground_nor[3]) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-18 12:21:38 +10:00
										 |  |  |   const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (bpa->data.mode == eBoidMode_Climbing) { | 
					
						
							|  |  |  |     SurfaceModifierData *surmd = NULL; | 
					
						
							|  |  |  |     float x[3], v[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |     surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(bpa->ground, eModifierType_Surface); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* take surface velocity into account */ | 
					
						
							|  |  |  |     closest_point_on_surface(surmd, pa->state.co, x, NULL, v); | 
					
						
							|  |  |  |     add_v3_v3(x, v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* get actual position on surface */ | 
					
						
							|  |  |  |     closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return bpa->ground; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-07 22:36:11 +10:00
										 |  |  |   const float zvec[3] = {0.0f, 0.0f, 2000.0f}; | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   ParticleCollision col; | 
					
						
							|  |  |  |   ColliderCache *coll; | 
					
						
							|  |  |  |   BVHTreeRayHit hit; | 
					
						
							|  |  |  |   float radius = 0.0f, t, ray_dir[3]; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   if (!bbd->sim->colliders) { | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   memset(&col, 0, sizeof(ParticleCollision)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* first try to find below boid */ | 
					
						
							|  |  |  |   copy_v3_v3(col.co1, pa->state.co); | 
					
						
							|  |  |  |   sub_v3_v3v3(col.co2, pa->state.co, zvec); | 
					
						
							|  |  |  |   sub_v3_v3v3(ray_dir, col.co2, col.co1); | 
					
						
							|  |  |  |   col.f = 0.0f; | 
					
						
							|  |  |  |   hit.index = -1; | 
					
						
							|  |  |  |   hit.dist = col.original_ray_length = normalize_v3(ray_dir); | 
					
						
							|  |  |  |   col.pce.inside = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (coll = bbd->sim->colliders->first; coll; coll = coll->next) { | 
					
						
							|  |  |  |     col.current = coll->ob; | 
					
						
							|  |  |  |     col.md = coll->collmd; | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:27 +11:00
										 |  |  |     col.fac1 = col.fac2 = 0.0f; | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (col.md && col.md->bvhtree) { | 
					
						
							|  |  |  |       BLI_bvhtree_ray_cast_ex(col.md->bvhtree, | 
					
						
							|  |  |  |                               col.co1, | 
					
						
							|  |  |  |                               ray_dir, | 
					
						
							|  |  |  |                               radius, | 
					
						
							|  |  |  |                               &hit, | 
					
						
							|  |  |  |                               BKE_psys_collision_neartest_cb, | 
					
						
							|  |  |  |                               &col, | 
					
						
							|  |  |  |                               raycast_flag); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   /* then use that object */ | 
					
						
							|  |  |  |   if (hit.index >= 0) { | 
					
						
							|  |  |  |     t = hit.dist / col.original_ray_length; | 
					
						
							|  |  |  |     interp_v3_v3v3(ground_co, col.co1, col.co2, t); | 
					
						
							|  |  |  |     normalize_v3_v3(ground_nor, col.pce.nor); | 
					
						
							|  |  |  |     return col.hit; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   /* couldn't find below, so find upmost deflector object */ | 
					
						
							|  |  |  |   add_v3_v3v3(col.co1, pa->state.co, zvec); | 
					
						
							|  |  |  |   sub_v3_v3v3(col.co2, pa->state.co, zvec); | 
					
						
							|  |  |  |   sub_v3_v3(col.co2, zvec); | 
					
						
							|  |  |  |   sub_v3_v3v3(ray_dir, col.co2, col.co1); | 
					
						
							|  |  |  |   col.f = 0.0f; | 
					
						
							|  |  |  |   hit.index = -1; | 
					
						
							|  |  |  |   hit.dist = col.original_ray_length = normalize_v3(ray_dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (coll = bbd->sim->colliders->first; coll; coll = coll->next) { | 
					
						
							|  |  |  |     col.current = coll->ob; | 
					
						
							|  |  |  |     col.md = coll->collmd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (col.md && col.md->bvhtree) { | 
					
						
							|  |  |  |       BLI_bvhtree_ray_cast_ex(col.md->bvhtree, | 
					
						
							|  |  |  |                               col.co1, | 
					
						
							|  |  |  |                               ray_dir, | 
					
						
							|  |  |  |                               radius, | 
					
						
							|  |  |  |                               &hit, | 
					
						
							|  |  |  |                               BKE_psys_collision_neartest_cb, | 
					
						
							|  |  |  |                               &col, | 
					
						
							|  |  |  |                               raycast_flag); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 18:04:40 +02:00
										 |  |  |   /* then use that object */ | 
					
						
							|  |  |  |   if (hit.index >= 0) { | 
					
						
							|  |  |  |     t = hit.dist / col.original_ray_length; | 
					
						
							|  |  |  |     interp_v3_v3v3(ground_co, col.co1, col.co2, t); | 
					
						
							|  |  |  |     normalize_v3_v3(ground_nor, col.pce.nor); | 
					
						
							|  |  |  |     return col.hit; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* default to z=0 */ | 
					
						
							|  |  |  |   copy_v3_v3(ground_co, pa->state.co); | 
					
						
							|  |  |  |   ground_co[2] = 0; | 
					
						
							|  |  |  |   ground_nor[0] = ground_nor[1] = 0.0f; | 
					
						
							|  |  |  |   ground_nor[2] = 1.0f; | 
					
						
							|  |  |  |   return NULL; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							| 
									
										
										
										
											2009-09-04 23:06:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (rule == NULL) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && | 
					
						
							|  |  |  |       rule->flag & BOIDRULE_ON_LAND) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (bpa->data.mode == eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void boids_precalc_rules(ParticleSettings *part, float cfra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidState *state = part->boids->states.first; | 
					
						
							|  |  |  |   BoidRule *rule; | 
					
						
							|  |  |  |   for (; state; state = state->next) { | 
					
						
							|  |  |  |     for (rule = state->rules.first; rule; rule = rule->next) { | 
					
						
							|  |  |  |       if (rule->type == eBoidRuleType_FollowLeader) { | 
					
						
							|  |  |  |         BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (flbr->ob && flbr->cfra != cfra) { | 
					
						
							|  |  |  |           /* save object locations for velocity calculations */ | 
					
						
							|  |  |  |           copy_v3_v3(flbr->oloc, flbr->loc); | 
					
						
							|  |  |  |           copy_v3_v3(flbr->loc, flbr->ob->obmat[3]); | 
					
						
							|  |  |  |           flbr->cfra = cfra; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void boid_climb(BoidSettings *boids, | 
					
						
							|  |  |  |                        ParticleData *pa, | 
					
						
							|  |  |  |                        float *surface_co, | 
					
						
							|  |  |  |                        float *surface_nor) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   float nor[3], vel[3]; | 
					
						
							|  |  |  |   copy_v3_v3(nor, surface_nor); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* gather apparent gravity */ | 
					
						
							|  |  |  |   madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f); | 
					
						
							|  |  |  |   normalize_v3(bpa->gravity); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* raise boid it's size from surface */ | 
					
						
							|  |  |  |   mul_v3_fl(nor, pa->size * boids->height); | 
					
						
							|  |  |  |   add_v3_v3v3(pa->state.co, surface_co, nor); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* remove normal component from velocity */ | 
					
						
							|  |  |  |   project_v3_v3v3(vel, pa->state.vel, surface_nor); | 
					
						
							|  |  |  |   sub_v3_v3v3(pa->state.vel, pa->state.vel, vel); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float vec[3]; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   sub_v3_v3v3(vec, boid_co, goal_co); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return dot_v3v3(vec, goal_nor); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | /* wanted_co is relative to boid location */ | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  | static bool apply_boid_rule( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (rule == NULL) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   if (!boid_rule_applies(pa, bbd->part->boids, rule)) { | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   if (!boid_rules[rule->type](rule, bbd, val, pa)) { | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co, | 
					
						
							|  |  |  |                                            pa->prev_state.vel, | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |                                            fuzziness * len_v3(pa->prev_state.vel)) == 0) { | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-09-09 10:37:42 +02:00
										 |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-09-28 05:53:40 +00:00
										 |  |  | static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidState *state = boids->states.first; | 
					
						
							|  |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (; state; state = state->next) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (state->id == bpa->data.state_id) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return state; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* for some reason particle isn't at a valid state */ | 
					
						
							|  |  |  |   state = boids->states.first; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (state) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     bpa->data.state_id = state->id; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return state; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  | // static int boid_condition_is_true(BoidCondition *cond)
 | 
					
						
							| 
									
										
										
										
											2012-06-20 16:43:48 +00:00
										 |  |  | //{
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | //  /* TODO */
 | 
					
						
							|  |  |  | //  return 0;
 | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | //}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* determines the velocity the boid wants to have */ | 
					
						
							|  |  |  | void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRule *rule; | 
					
						
							|  |  |  |   BoidSettings *boids = bbd->part->boids; | 
					
						
							|  |  |  |   BoidValues val; | 
					
						
							|  |  |  |   BoidState *state = get_boid_state(boids, pa); | 
					
						
							|  |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   ParticleSystem *psys = bbd->sim->psys; | 
					
						
							|  |  |  |   int rand; | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |   // BoidCondition *cond;
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (bpa->data.health <= 0.0f) { | 
					
						
							|  |  |  |     pa->alive = PARS_DYING; | 
					
						
							|  |  |  |     pa->dietime = bbd->cfra; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |   // planned for near future
 | 
					
						
							|  |  |  |   // cond = state->conditions.first;
 | 
					
						
							|  |  |  |   // for (; cond; cond=cond->next) {
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   //  if (boid_condition_is_true(cond)) {
 | 
					
						
							|  |  |  |   //      pa->boid->state_id = cond->state_id;
 | 
					
						
							|  |  |  |   //      state = get_boid_state(boids, pa);
 | 
					
						
							|  |  |  |   //      break; /* only first true condition is used */
 | 
					
						
							|  |  |  |   //  }
 | 
					
						
							|  |  |  |   //}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   zero_v3(bbd->wanted_co); | 
					
						
							|  |  |  |   bbd->wanted_speed = 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* create random seed for every particle & frame */ | 
					
						
							|  |  |  |   rand = (int)(psys_frand(psys, psys->seed + p) * 1000); | 
					
						
							|  |  |  |   rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   set_boid_values(&val, bbd->part->boids, pa); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* go through rules */ | 
					
						
							|  |  |  |   switch (state->ruleset_type) { | 
					
						
							|  |  |  |     case eBoidRulesetType_Fuzzy: { | 
					
						
							|  |  |  |       for (rule = state->rules.first; rule; rule = rule->next) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; /* only first nonzero rule that comes through fuzzy rule is applied */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case eBoidRulesetType_Random: { | 
					
						
							|  |  |  |       /* use random rule for each particle (always same for same particle though) */ | 
					
						
							|  |  |  |       const int n = BLI_listbase_count(&state->rules); | 
					
						
							|  |  |  |       if (n) { | 
					
						
							|  |  |  |         rule = BLI_findlink(&state->rules, rand % n); | 
					
						
							|  |  |  |         apply_boid_rule(bbd, rule, &val, pa, -1.0); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case eBoidRulesetType_Average: { | 
					
						
							|  |  |  |       float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f; | 
					
						
							|  |  |  |       int n = 0; | 
					
						
							|  |  |  |       for (rule = state->rules.first; rule; rule = rule->next) { | 
					
						
							|  |  |  |         if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) { | 
					
						
							|  |  |  |           add_v3_v3(wanted_co, bbd->wanted_co); | 
					
						
							|  |  |  |           wanted_speed += bbd->wanted_speed; | 
					
						
							|  |  |  |           n++; | 
					
						
							|  |  |  |           zero_v3(bbd->wanted_co); | 
					
						
							|  |  |  |           bbd->wanted_speed = 0.0f; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (n > 1) { | 
					
						
							|  |  |  |         mul_v3_fl(wanted_co, 1.0f / (float)n); | 
					
						
							|  |  |  |         wanted_speed /= (float)n; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       copy_v3_v3(bbd->wanted_co, wanted_co); | 
					
						
							|  |  |  |       bbd->wanted_speed = wanted_speed; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* decide on jumping & liftoff */ | 
					
						
							|  |  |  |   if (bpa->data.mode == eBoidMode_OnLand) { | 
					
						
							|  |  |  |     /* fuzziness makes boids capable of misjudgement */ | 
					
						
							|  |  |  |     float mul = 1.0f + state->rule_fuzziness; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) { | 
					
						
							|  |  |  |       float cvel[3], dir[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       copy_v3_v3(dir, pa->prev_state.ave); | 
					
						
							|  |  |  |       normalize_v2(dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       copy_v3_v3(cvel, bbd->wanted_co); | 
					
						
							|  |  |  |       normalize_v2(cvel); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (dot_v2v2(cvel, dir) > 0.95f / mul) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         bpa->data.mode = eBoidMode_Liftoff; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (val.jump_speed > 0.0f) { | 
					
						
							|  |  |  |       float jump_v[3]; | 
					
						
							|  |  |  |       int jump = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* jump to get to a location */ | 
					
						
							|  |  |  |       if (bbd->wanted_co[2] > 0.0f) { | 
					
						
							|  |  |  |         float cvel[3], dir[3]; | 
					
						
							|  |  |  |         float z_v, ground_v, cur_v; | 
					
						
							|  |  |  |         float len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         copy_v3_v3(dir, pa->prev_state.ave); | 
					
						
							|  |  |  |         normalize_v2(dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         copy_v3_v3(cvel, bbd->wanted_co); | 
					
						
							|  |  |  |         normalize_v2(cvel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         len = len_v2(pa->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* first of all, are we going in a suitable direction? */ | 
					
						
							|  |  |  |         /* or at a suitably slow speed */ | 
					
						
							|  |  |  |         if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) { | 
					
						
							|  |  |  |           /* try to reach goal at highest point of the parabolic path */ | 
					
						
							|  |  |  |           cur_v = len_v2(pa->prev_state.vel); | 
					
						
							|  |  |  |           z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]); | 
					
						
							|  |  |  |           ground_v = len_v2(bbd->wanted_co) * | 
					
						
							|  |  |  |                      sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / | 
					
						
							|  |  |  |                             bbd->wanted_co[2]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           len = sasqrt((ground_v - cur_v) * (ground_v - cur_v) + z_v * z_v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) { | 
					
						
							|  |  |  |             jump = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             len = MIN2(len, val.jump_speed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             copy_v3_v3(jump_v, dir); | 
					
						
							|  |  |  |             jump_v[2] = z_v; | 
					
						
							|  |  |  |             mul_v3_fl(jump_v, ground_v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             normalize_v3(jump_v); | 
					
						
							|  |  |  |             mul_v3_fl(jump_v, len); | 
					
						
							|  |  |  |             add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* jump to go faster */ | 
					
						
							|  |  |  |       if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) { | 
					
						
							|  |  |  |         /* pass */ | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (jump) { | 
					
						
							|  |  |  |         copy_v3_v3(pa->prev_state.vel, jump_v); | 
					
						
							|  |  |  |         bpa->data.mode = eBoidMode_Falling; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | /* tries to realize the wanted velocity taking all constraints into account */ | 
					
						
							|  |  |  | void boid_body(BoidBrainData *bbd, ParticleData *pa) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidSettings *boids = bbd->part->boids; | 
					
						
							|  |  |  |   BoidParticle *bpa = pa->boid; | 
					
						
							|  |  |  |   BoidValues val; | 
					
						
							|  |  |  |   EffectedPoint epoint; | 
					
						
							|  |  |  |   float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; | 
					
						
							|  |  |  |   float dvec[3], bvec[3]; | 
					
						
							|  |  |  |   float new_dir[3], new_speed; | 
					
						
							|  |  |  |   float old_dir[3], old_speed; | 
					
						
							|  |  |  |   float wanted_dir[3]; | 
					
						
							|  |  |  |   float q[4], mat[3][3]; /* rotation */ | 
					
						
							|  |  |  |   float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; | 
					
						
							|  |  |  |   float force[3] = {0.0f, 0.0f, 0.0f}; | 
					
						
							|  |  |  |   float pa_mass = bbd->part->mass, dtime = bbd->dfra * bbd->timestep; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   set_boid_values(&val, boids, pa); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* make sure there's something in new velocity, location & rotation */ | 
					
						
							|  |  |  |   copy_particle_key(&pa->state, &pa->prev_state, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (bbd->part->flag & PART_SIZEMASS) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pa_mass *= pa->size; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* if boids can't fly they fall to the ground */ | 
					
						
							|  |  |  |   if ((boids->options & BOID_ALLOW_FLIGHT) == 0 && | 
					
						
							|  |  |  |       ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) == 0 && | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       psys_uses_gravity(bbd->sim)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     bpa->data.mode = eBoidMode_Falling; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (bpa->data.mode == eBoidMode_Falling) { | 
					
						
							|  |  |  |     /* Falling boids are only effected by gravity. */ | 
					
						
							|  |  |  |     acc[2] = bbd->sim->scene->physics_settings.gravity[2]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* figure out acceleration */ | 
					
						
							|  |  |  |     float landing_level = 2.0f; | 
					
						
							|  |  |  |     float level = landing_level + 1.0f; | 
					
						
							|  |  |  |     float new_vel[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bpa->data.mode == eBoidMode_Liftoff) { | 
					
						
							|  |  |  |       bpa->data.mode = eBoidMode_InAir; | 
					
						
							|  |  |  |       bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) { | 
					
						
							|  |  |  |       /* auto-leveling & landing if close to ground */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* level = how many particle sizes above ground */ | 
					
						
							|  |  |  |       level = (pa->prev_state.co[2] - ground_co[2]) / (2.0f * pa->size) - 0.5f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       landing_level = -boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (pa->prev_state.vel[2] < 0.0f) { | 
					
						
							|  |  |  |         if (level < 1.0f) { | 
					
						
							|  |  |  |           bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f; | 
					
						
							|  |  |  |           bbd->wanted_speed = 0.0f; | 
					
						
							|  |  |  |           bpa->data.mode = eBoidMode_Falling; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (level < landing_level) { | 
					
						
							|  |  |  |           bbd->wanted_speed *= (level - 1.0f) / landing_level; | 
					
						
							|  |  |  |           bbd->wanted_co[2] *= (level - 1.0f) / landing_level; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(old_dir, pa->prev_state.ave); | 
					
						
							|  |  |  |     new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* first check if we have valid direction we want to go towards */ | 
					
						
							|  |  |  |     if (new_speed == 0.0f) { | 
					
						
							|  |  |  |       copy_v3_v3(new_dir, old_dir); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       float old_dir2[2], wanted_dir2[2], nor[3], angle; | 
					
						
							|  |  |  |       copy_v2_v2(old_dir2, old_dir); | 
					
						
							|  |  |  |       normalize_v2(old_dir2); | 
					
						
							|  |  |  |       copy_v2_v2(wanted_dir2, wanted_dir); | 
					
						
							|  |  |  |       normalize_v2(wanted_dir2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* choose random direction to turn if wanted velocity */ | 
					
						
							|  |  |  |       /* is directly behind regardless of z-coordinate */ | 
					
						
							|  |  |  |       if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) { | 
					
						
							|  |  |  |         wanted_dir[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |         wanted_dir[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |         wanted_dir[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng)); | 
					
						
							|  |  |  |         normalize_v3(wanted_dir); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* constrain direction with maximum angular velocity */ | 
					
						
							|  |  |  |       angle = saacos(dot_v3v3(old_dir, wanted_dir)); | 
					
						
							|  |  |  |       angle = min_ff(angle, val.max_ave); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       cross_v3_v3v3(nor, old_dir, wanted_dir); | 
					
						
							|  |  |  |       axis_angle_to_quat(q, nor, angle); | 
					
						
							|  |  |  |       copy_v3_v3(new_dir, old_dir); | 
					
						
							|  |  |  |       mul_qt_v3(q, new_dir); | 
					
						
							|  |  |  |       normalize_v3(new_dir); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* save direction in case resulting velocity too small */ | 
					
						
							|  |  |  |       axis_angle_to_quat(q, nor, angle * dtime); | 
					
						
							|  |  |  |       copy_v3_v3(pa->state.ave, old_dir); | 
					
						
							|  |  |  |       mul_qt_v3(q, pa->state.ave); | 
					
						
							|  |  |  |       normalize_v3(pa->state.ave); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* constrain speed with maximum acceleration */ | 
					
						
							|  |  |  |     old_speed = len_v3(pa->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (bbd->wanted_speed < old_speed) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* combine direction and speed */ | 
					
						
							|  |  |  |     copy_v3_v3(new_vel, new_dir); | 
					
						
							|  |  |  |     mul_v3_fl(new_vel, new_speed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* maintain minimum flying velocity if not landing */ | 
					
						
							|  |  |  |     if (level >= landing_level) { | 
					
						
							|  |  |  |       float len2 = dot_v2v2(new_vel, new_vel); | 
					
						
							|  |  |  |       float root; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       len2 = MAX2(len2, val.min_speed * val.min_speed); | 
					
						
							|  |  |  |       root = sasqrt(new_speed * new_speed - len2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       new_vel[2] = new_vel[2] < 0.0f ? -root : root; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       normalize_v2(new_vel); | 
					
						
							|  |  |  |       mul_v2_fl(new_vel, sasqrt(len2)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* finally constrain speed to max speed */ | 
					
						
							|  |  |  |     new_speed = normalize_v3(new_vel); | 
					
						
							|  |  |  |     mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* get acceleration from difference of velocities */ | 
					
						
							|  |  |  |     sub_v3_v3v3(acc, new_vel, pa->prev_state.vel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* break acceleration to components */ | 
					
						
							|  |  |  |     project_v3_v3v3(tan_acc, acc, pa->prev_state.ave); | 
					
						
							|  |  |  |     sub_v3_v3v3(nor_acc, acc, tan_acc); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* account for effectors */ | 
					
						
							|  |  |  |   pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); | 
					
						
							|  |  |  |   BKE_effectors_apply(bbd->sim->psys->effectors, | 
					
						
							|  |  |  |                       bbd->sim->colliders, | 
					
						
							|  |  |  |                       bbd->part->effector_weights, | 
					
						
							|  |  |  |                       &epoint, | 
					
						
							|  |  |  |                       force, | 
					
						
							| 
									
										
										
										
											2020-06-12 21:33:38 +03:00
										 |  |  |                       NULL, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |                       NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { | 
					
						
							|  |  |  |     float length = normalize_v3(force); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     length = MAX2(0.0f, length - boids->land_stick_force); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mul_v3_fl(force, length); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   add_v3_v3(acc, force); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* store smoothed acceleration for nice banking etc. */ | 
					
						
							|  |  |  |   madd_v3_v3fl(bpa->data.acc, acc, dtime); | 
					
						
							|  |  |  |   mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* integrate new location & velocity */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* by regarding the acceleration as a force at this stage we
 | 
					
						
							|  |  |  |    * can get better control although it's a bit unphysical */ | 
					
						
							|  |  |  |   mul_v3_fl(acc, 1.0f / pa_mass); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   copy_v3_v3(dvec, acc); | 
					
						
							|  |  |  |   mul_v3_fl(dvec, dtime * dtime * 0.5f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   copy_v3_v3(bvec, pa->prev_state.vel); | 
					
						
							|  |  |  |   mul_v3_fl(bvec, dtime); | 
					
						
							|  |  |  |   add_v3_v3(dvec, bvec); | 
					
						
							|  |  |  |   add_v3_v3(pa->state.co, dvec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   madd_v3_v3fl(pa->state.vel, acc, dtime); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |   // if (bpa->data.mode != eBoidMode_InAir)
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* change modes, constrain movement & keep track of down vector */ | 
					
						
							|  |  |  |   switch (bpa->data.mode) { | 
					
						
							|  |  |  |     case eBoidMode_InAir: { | 
					
						
							|  |  |  |       float grav[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       grav[0] = 0.0f; | 
					
						
							|  |  |  |       grav[1] = 0.0f; | 
					
						
							|  |  |  |       grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* don't take forward acceleration into account (better banking) */ | 
					
						
							|  |  |  |       if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) { | 
					
						
							|  |  |  |         project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); | 
					
						
							|  |  |  |         sub_v3_v3v3(dvec, bpa->data.acc, dvec); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         copy_v3_v3(dvec, bpa->data.acc); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* gather apparent gravity */ | 
					
						
							|  |  |  |       madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); | 
					
						
							|  |  |  |       normalize_v3(bpa->gravity); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* stick boid on goal when close enough */ | 
					
						
							|  |  |  |       if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= | 
					
						
							|  |  |  |                               pa->size * boids->height) { | 
					
						
							|  |  |  |         bpa->data.mode = eBoidMode_Climbing; | 
					
						
							|  |  |  |         bpa->ground = bbd->goal_ob; | 
					
						
							|  |  |  |         boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |         boid_climb(boids, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) { | 
					
						
							|  |  |  |         /* land boid when below ground */ | 
					
						
							|  |  |  |         if (boids->options & BOID_ALLOW_LAND) { | 
					
						
							|  |  |  |           pa->state.co[2] = ground_co[2] + pa->size * boids->height; | 
					
						
							|  |  |  |           pa->state.vel[2] = 0.0f; | 
					
						
							|  |  |  |           bpa->data.mode = eBoidMode_OnLand; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* fly above ground */ | 
					
						
							|  |  |  |         else if (bpa->ground) { | 
					
						
							|  |  |  |           pa->state.co[2] = ground_co[2] + pa->size * boids->height; | 
					
						
							|  |  |  |           pa->state.vel[2] = 0.0f; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case eBoidMode_Falling: { | 
					
						
							|  |  |  |       float grav[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       grav[0] = 0.0f; | 
					
						
							|  |  |  |       grav[1] = 0.0f; | 
					
						
							|  |  |  |       grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* gather apparent gravity */ | 
					
						
							|  |  |  |       madd_v3_v3fl(bpa->gravity, grav, dtime); | 
					
						
							|  |  |  |       normalize_v3(bpa->gravity); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (boids->options & BOID_ALLOW_LAND) { | 
					
						
							|  |  |  |         /* stick boid on goal when close enough */ | 
					
						
							|  |  |  |         if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= | 
					
						
							|  |  |  |                                 pa->size * boids->height) { | 
					
						
							|  |  |  |           bpa->data.mode = eBoidMode_Climbing; | 
					
						
							|  |  |  |           bpa->ground = bbd->goal_ob; | 
					
						
							|  |  |  |           boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |           boid_climb(boids, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* land boid when really near ground */ | 
					
						
							|  |  |  |         else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) { | 
					
						
							|  |  |  |           pa->state.co[2] = ground_co[2] + pa->size * boids->height; | 
					
						
							|  |  |  |           pa->state.vel[2] = 0.0f; | 
					
						
							|  |  |  |           bpa->data.mode = eBoidMode_OnLand; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* if we're falling, can fly and want to go upwards lets fly */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           bpa->data.mode = eBoidMode_InAir; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         bpa->data.mode = eBoidMode_InAir; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case eBoidMode_Climbing: { | 
					
						
							|  |  |  |       boid_climb(boids, pa, ground_co, ground_nor); | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |       // float nor[3];
 | 
					
						
							|  |  |  |       // copy_v3_v3(nor, ground_nor);
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       ///* gather apparent gravity to r_ve */
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |       // madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
 | 
					
						
							|  |  |  |       // normalize_v3(pa->r_ve);
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       ///* raise boid it's size from surface */
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |       // mul_v3_fl(nor, pa->size * boids->height);
 | 
					
						
							|  |  |  |       // add_v3_v3v3(pa->state.co, ground_co, nor);
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       ///* remove normal component from velocity */
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |       // project_v3_v3v3(v, pa->state.vel, ground_nor);
 | 
					
						
							|  |  |  |       // sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case eBoidMode_OnLand: { | 
					
						
							|  |  |  |       /* stick boid on goal when close enough */ | 
					
						
							|  |  |  |       if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= | 
					
						
							|  |  |  |                               pa->size * boids->height) { | 
					
						
							|  |  |  |         bpa->data.mode = eBoidMode_Climbing; | 
					
						
							|  |  |  |         bpa->ground = bbd->goal_ob; | 
					
						
							|  |  |  |         boid_find_ground(bbd, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |         boid_climb(boids, pa, ground_co, ground_nor); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       /* ground is too far away so boid falls */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       else if (pa->state.co[2] - ground_co[2] > 1.1f * pa->size * boids->height) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         bpa->data.mode = eBoidMode_Falling; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       else { | 
					
						
							|  |  |  |         /* constrain to surface */ | 
					
						
							|  |  |  |         pa->state.co[2] = ground_co[2] + pa->size * boids->height; | 
					
						
							|  |  |  |         pa->state.vel[2] = 0.0f; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (boids->banking > 0.0f) { | 
					
						
							|  |  |  |         float grav[3]; | 
					
						
							|  |  |  |         /* Don't take gravity's strength in to account, */ | 
					
						
							|  |  |  |         /* otherwise amount of banking is hard to control. */ | 
					
						
							|  |  |  |         negate_v3_v3(grav, ground_nor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); | 
					
						
							|  |  |  |         sub_v3_v3v3(dvec, bpa->data.acc, dvec); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* gather apparent gravity */ | 
					
						
							|  |  |  |         madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); | 
					
						
							|  |  |  |         normalize_v3(bpa->gravity); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         /* gather negative surface normal */ | 
					
						
							|  |  |  |         madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f); | 
					
						
							|  |  |  |         normalize_v3(bpa->gravity); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* save direction to state.ave unless the boid is falling */ | 
					
						
							|  |  |  |   /* (boids can't effect their direction when falling) */ | 
					
						
							|  |  |  |   if (bpa->data.mode != eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f * pa->size) { | 
					
						
							|  |  |  |     copy_v3_v3(pa->state.ave, pa->state.vel); | 
					
						
							|  |  |  |     pa->state.ave[2] *= bbd->part->boids->pitch; | 
					
						
							|  |  |  |     normalize_v3(pa->state.ave); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* apply damping */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_v3_fl(pa->state.vel, 1.0f - 0.2f * bbd->part->dampfac); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* calculate rotation matrix based on forward & down vectors */ | 
					
						
							|  |  |  |   if (bpa->data.mode == eBoidMode_InAir) { | 
					
						
							|  |  |  |     copy_v3_v3(mat[0], pa->state.ave); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     project_v3_v3v3(dvec, bpa->gravity, pa->state.ave); | 
					
						
							|  |  |  |     sub_v3_v3v3(mat[2], bpa->gravity, dvec); | 
					
						
							|  |  |  |     normalize_v3(mat[2]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     project_v3_v3v3(dvec, pa->state.ave, bpa->gravity); | 
					
						
							|  |  |  |     sub_v3_v3v3(mat[0], pa->state.ave, dvec); | 
					
						
							|  |  |  |     normalize_v3(mat[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_v3_v3(mat[2], bpa->gravity); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   negate_v3(mat[2]); | 
					
						
							|  |  |  |   cross_v3_v3v3(mat[1], mat[2], mat[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* apply rotation */ | 
					
						
							|  |  |  |   mat3_to_quat_is_ok(q, mat); | 
					
						
							|  |  |  |   copy_qt_qt(pa->state.rot, q); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BoidRule *boid_new_rule(int type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidRule *rule = NULL; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (type <= 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (type) { | 
					
						
							|  |  |  |     case eBoidRuleType_Goal: | 
					
						
							|  |  |  |     case eBoidRuleType_Avoid: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case eBoidRuleType_AvoidCollision: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision"); | 
					
						
							|  |  |  |       ((BoidRuleAvoidCollision *)rule)->look_ahead = 2.0f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case eBoidRuleType_FollowLeader: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader"); | 
					
						
							|  |  |  |       ((BoidRuleFollowLeader *)rule)->distance = 1.0f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case eBoidRuleType_AverageSpeed: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed"); | 
					
						
							|  |  |  |       ((BoidRuleAverageSpeed *)rule)->speed = 0.5f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case eBoidRuleType_Fight: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight"); | 
					
						
							|  |  |  |       ((BoidRuleFight *)rule)->distance = 100.0f; | 
					
						
							|  |  |  |       ((BoidRuleFight *)rule)->flee_distance = 100.0f; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       rule = MEM_callocN(sizeof(BoidRule), "BoidRule"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   rule->type = type; | 
					
						
							|  |  |  |   rule->flag |= BOIDRULE_IN_AIR | BOIDRULE_ON_LAND; | 
					
						
							|  |  |  |   BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type - 1].name, sizeof(rule->name)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return rule; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void boid_default_settings(BoidSettings *boids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   boids->air_max_speed = 10.0f; | 
					
						
							|  |  |  |   boids->air_max_acc = 0.5f; | 
					
						
							|  |  |  |   boids->air_max_ave = 0.5f; | 
					
						
							|  |  |  |   boids->air_personal_space = 1.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   boids->land_max_speed = 5.0f; | 
					
						
							|  |  |  |   boids->land_max_acc = 0.5f; | 
					
						
							|  |  |  |   boids->land_max_ave = 0.5f; | 
					
						
							|  |  |  |   boids->land_personal_space = 1.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   boids->options = BOID_ALLOW_FLIGHT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   boids->landing_smoothness = 3.0f; | 
					
						
							|  |  |  |   boids->banking = 1.0f; | 
					
						
							|  |  |  |   boids->pitch = 1.0f; | 
					
						
							|  |  |  |   boids->height = 1.0f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   boids->health = 1.0f; | 
					
						
							|  |  |  |   boids->accuracy = 1.0f; | 
					
						
							|  |  |  |   boids->aggression = 2.0f; | 
					
						
							|  |  |  |   boids->range = 1.0f; | 
					
						
							|  |  |  |   boids->strength = 0.1f; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BoidState *boid_new_state(BoidSettings *boids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState"); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   state->id = boids->last_state_id++; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (state->id) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     strcpy(state->name, "State"); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   state->rule_fuzziness = 0.5; | 
					
						
							|  |  |  |   state->volume = 1.0f; | 
					
						
							|  |  |  |   state->channels |= ~0; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return state; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-17 00:52:36 +00:00
										 |  |  | BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidState *staten = MEM_dupallocN(state); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_duplicatelist(&staten->rules, &state->rules); | 
					
						
							|  |  |  |   BLI_duplicatelist(&staten->conditions, &state->conditions); | 
					
						
							|  |  |  |   BLI_duplicatelist(&staten->actions, &state->actions); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   staten->id = boids->last_state_id++; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return staten; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void boid_free_settings(BoidSettings *boids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (boids) { | 
					
						
							|  |  |  |     BoidState *state = boids->states.first; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (; state; state = state->next) { | 
					
						
							|  |  |  |       BLI_freelistN(&state->rules); | 
					
						
							|  |  |  |       BLI_freelistN(&state->conditions); | 
					
						
							|  |  |  |       BLI_freelistN(&state->actions); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BLI_freelistN(&boids->states); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(boids); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-14 22:36:30 +02:00
										 |  |  | BoidSettings *boid_copy_settings(const BoidSettings *boids) | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidSettings *nboids = NULL; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (boids) { | 
					
						
							|  |  |  |     BoidState *state; | 
					
						
							|  |  |  |     BoidState *nstate; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     nboids = MEM_dupallocN(boids); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BLI_duplicatelist(&nboids->states, &boids->states); | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     state = boids->states.first; | 
					
						
							|  |  |  |     nstate = nboids->states.first; | 
					
						
							|  |  |  |     for (; state; state = state->next, nstate = nstate->next) { | 
					
						
							|  |  |  |       BLI_duplicatelist(&nstate->rules, &state->rules); | 
					
						
							|  |  |  |       BLI_duplicatelist(&nstate->conditions, &state->conditions); | 
					
						
							|  |  |  |       BLI_duplicatelist(&nstate->actions, &state->actions); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return nboids; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | } | 
					
						
							|  |  |  | BoidState *boid_get_current_state(BoidSettings *boids) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BoidState *state = boids->states.first; | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (; state; state = state->next) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (state->flag & BOIDSTATE_CURRENT) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-07-20 23:52:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return state; | 
					
						
							| 
									
										
										
										
											2009-07-25 22:20:26 +00:00
										 |  |  | } |