Initial code for boids v2
Too many new features to list! But here are the biggies: - Boids can move on air and/or land, or climb a goal object. - Proper interaction with collision objects. * Closest collision object in negative z direction is considered as ground. * Other collision objects are obstacles and boids collide with them. - Boid behavior rules are now added to a dynamic list. * Many new rules and many still not implemented. * Different rule evaluation modes (fuzzy, random, average). - Only particle systems defined by per system "boid relations" are considered for simulation of that system. * This is in addition to the boids own system of course. * Relations define other systems as "neutral", "friend" or "enemy". - All effectors now effect boid physics, not boid brains. * This allows forcing boids somewhere. * Exception to this is new "boid" effector, which defines boid predators (positive strength) and goals (negative strength). Known issue: - Boid health isn't yet stored in pointcache so simulations with "fight" rule are not be read from cache properly. - Object/Group visualization object's animation is not played in "particle time". This is definately the wanted behavior, but isn't possible with the current state of dupliobject code. Other new features: - Particle systems can now be named separately from particle settings. * Default name for particle settings is now "ParticleSettings" instead of "PSys" - Per particle system list of particle effector weights. * Enables different effection strengths for particles from different particle systems with without messing around with effector group setting. Other code changes: - KDTree now supports range search as it's needed for new boids. - "Keyed particle targets" renamed as general "particle targets", as they're needed for boids too. (this might break some files saved with new keyed particles) Bug fixes: - Object & group visualizations didn't work. - Interpolating pointcache didn't do rotation.
This commit is contained in:
@@ -40,27 +40,33 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
|
||||
col.itemO("object.particle_system_remove", icon="ICON_ZOOMOUT", text="")
|
||||
|
||||
if psys:
|
||||
split = layout.split(percentage=0.65)
|
||||
part = psys.settings
|
||||
|
||||
split.template_ID(psys, "settings", new="particle.new")
|
||||
split = layout.split(percentage=0.32)
|
||||
col = split.column()
|
||||
col.itemL(text="Name:")
|
||||
if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
|
||||
col.itemL(text="Settings:")
|
||||
col.itemL(text="Type:")
|
||||
|
||||
col = split.column()
|
||||
col.itemR(psys, "name", text="")
|
||||
if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
|
||||
col.template_ID(psys, "settings", new="particle.new")
|
||||
|
||||
#row = layout.row()
|
||||
#row.itemL(text="Viewport")
|
||||
#row.itemL(text="Render")
|
||||
|
||||
part = psys.settings
|
||||
|
||||
if part:
|
||||
ptype = psys.settings.type
|
||||
if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
|
||||
if part.type not in ('EMITTER', 'REACTOR', 'HAIR'):
|
||||
layout.itemL(text="No settings for fluid particles")
|
||||
return
|
||||
|
||||
split = layout.split(percentage=0.65)
|
||||
|
||||
split.enabled = particle_panel_enabled(psys)
|
||||
split.itemR(part, "type")
|
||||
split.itemR(psys, "seed")
|
||||
row=col.row()
|
||||
row.enabled = particle_panel_enabled(psys)
|
||||
row.itemR(part, "type", text="")
|
||||
row.itemR(psys, "seed")
|
||||
|
||||
split = layout.split(percentage=0.65)
|
||||
if part.type=='HAIR':
|
||||
@@ -183,6 +189,13 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
|
||||
class PARTICLE_PT_initial(ParticleButtonsPanel):
|
||||
__idname__= "PARTICLE_PT_initial"
|
||||
__label__ = "Velocity"
|
||||
|
||||
def poll(self, context):
|
||||
if particle_panel_poll(context):
|
||||
psys = context.particle_system
|
||||
return psys.settings.physics_type != 'BOIDS'
|
||||
else:
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -250,13 +263,11 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
|
||||
psys = context.particle_system
|
||||
part = psys.settings
|
||||
|
||||
layout.enabled = layout.enabled = particle_panel_enabled(psys)
|
||||
layout.enabled = particle_panel_enabled(psys)
|
||||
|
||||
row = layout.row()
|
||||
row.itemR(part, "physics_type", expand=True)
|
||||
if part.physics_type != 'NO':
|
||||
layout.itemR(part, "effector_group")
|
||||
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
col.itemR(part, "particle_size")
|
||||
@@ -264,12 +275,10 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
|
||||
col = row.column(align=True)
|
||||
col.itemR(part, "mass")
|
||||
col.itemR(part, "sizemass", text="Multiply mass with size")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
sub = split.column()
|
||||
|
||||
if part.physics_type == 'NEWTON':
|
||||
split = layout.split()
|
||||
sub = split.column()
|
||||
|
||||
sub.itemL(text="Forces:")
|
||||
sub.itemR(part, "brownian_factor")
|
||||
@@ -280,6 +289,9 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
|
||||
sub.itemR(part, "acceleration")
|
||||
|
||||
elif part.physics_type == 'KEYED':
|
||||
split = layout.split()
|
||||
sub = split.column()
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.active = not psys.keyed_timing
|
||||
@@ -287,38 +299,189 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
|
||||
row.itemR(psys, "keyed_timing", text="Use Timing")
|
||||
|
||||
layout.itemL(text="Keys:")
|
||||
elif part.physics_type=='BOIDS':
|
||||
boids = part.boids
|
||||
|
||||
|
||||
row = layout.row()
|
||||
row.itemR(boids, "allow_flight")
|
||||
row.itemR(boids, "allow_land")
|
||||
row.itemR(boids, "allow_climb")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
sub = split.column()
|
||||
col = sub.column(align=True)
|
||||
col.active = boids.allow_flight
|
||||
col.itemR(boids, "air_max_speed")
|
||||
col.itemR(boids, "air_min_speed", slider="True")
|
||||
col.itemR(boids, "air_max_acc", slider="True")
|
||||
col.itemR(boids, "air_max_ave", slider="True")
|
||||
col.itemR(boids, "air_personal_space")
|
||||
row = col.row()
|
||||
row.active = (boids.allow_land or boids.allow_climb) and boids.allow_flight
|
||||
row.itemR(boids, "landing_smoothness")
|
||||
|
||||
sub = split.column()
|
||||
col = sub.column(align=True)
|
||||
col.active = boids.allow_land or boids.allow_climb
|
||||
col.itemR(boids, "land_max_speed")
|
||||
col.itemR(boids, "land_jump_speed")
|
||||
col.itemR(boids, "land_max_acc", slider="True")
|
||||
col.itemR(boids, "land_max_ave", slider="True")
|
||||
col.itemR(boids, "land_personal_space")
|
||||
col.itemR(boids, "land_stick_force")
|
||||
|
||||
row = layout.row()
|
||||
|
||||
row.template_list(psys, "keyed_targets", psys, "active_keyed_target_index")
|
||||
col = row.column(align=True)
|
||||
col.itemL(text="Battle:")
|
||||
col.itemR(boids, "health")
|
||||
col.itemR(boids, "strength")
|
||||
col.itemR(boids, "aggression")
|
||||
col.itemR(boids, "accuracy")
|
||||
col.itemR(boids, "range")
|
||||
|
||||
col = row.column()
|
||||
col.itemL(text="Misc:")
|
||||
col.itemR(part, "gravity")
|
||||
col.itemR(boids, "banking", slider=True)
|
||||
col.itemR(boids, "height", slider=True)
|
||||
|
||||
if part.physics_type=='NEWTON':
|
||||
sub.itemR(part, "size_deflect")
|
||||
sub.itemR(part, "die_on_collision")
|
||||
sub.itemR(part, "sticky")
|
||||
elif part.physics_type=='KEYED' or part.physics_type=='BOIDS':
|
||||
if part.physics_type=='BOIDS':
|
||||
layout.itemL(text="Relations:")
|
||||
|
||||
row = layout.row()
|
||||
row.template_list(psys, "targets", psys, "active_particle_target_index")
|
||||
|
||||
col = row.column()
|
||||
subrow = col.row()
|
||||
subcol = subrow.column(align=True)
|
||||
subcol.itemO("particle.new_keyed_target", icon="ICON_ZOOMIN", text="")
|
||||
subcol.itemO("particle.remove_keyed_target", icon="ICON_ZOOMOUT", text="")
|
||||
subcol.itemO("particle.new_target", icon="ICON_ZOOMIN", text="")
|
||||
subcol.itemO("particle.remove_target", icon="ICON_ZOOMOUT", text="")
|
||||
subrow = col.row()
|
||||
subcol = subrow.column(align=True)
|
||||
subcol.itemO("particle.keyed_target_move_up", icon="VICON_MOVE_UP", text="")
|
||||
subcol.itemO("particle.keyed_target_move_down", icon="VICON_MOVE_DOWN", text="")
|
||||
subcol.itemO("particle.target_move_up", icon="VICON_MOVE_UP", text="")
|
||||
subcol.itemO("particle.target_move_down", icon="VICON_MOVE_DOWN", text="")
|
||||
|
||||
key = psys.active_keyed_target
|
||||
key = psys.active_particle_target
|
||||
if key:
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
#doesn't work yet
|
||||
#col.red_alert = key.valid
|
||||
col.itemR(key, "object", text="")
|
||||
col.itemR(key, "system", text="System")
|
||||
col = row.column();
|
||||
col.active = psys.keyed_timing
|
||||
col.itemR(key, "time")
|
||||
col.itemR(key, "duration")
|
||||
|
||||
if part.physics_type=='NEWTON' or part.physics_type=='BOIDS':
|
||||
if part.physics_type=='KEYED':
|
||||
col = row.column()
|
||||
#doesn't work yet
|
||||
#col.red_alert = key.valid
|
||||
col.itemR(key, "object", text="")
|
||||
col.itemR(key, "system", text="System")
|
||||
col = row.column();
|
||||
col.active = psys.keyed_timing
|
||||
col.itemR(key, "time")
|
||||
col.itemR(key, "duration")
|
||||
else:
|
||||
subrow = row.row()
|
||||
#doesn't work yet
|
||||
#subrow.red_alert = key.valid
|
||||
subrow.itemR(key, "object", text="")
|
||||
subrow.itemR(key, "system", text="System")
|
||||
|
||||
layout.itemR(key, "mode", expand=True)
|
||||
|
||||
sub.itemR(part, "size_deflect")
|
||||
sub.itemR(part, "die_on_collision")
|
||||
sub.itemR(part, "sticky")
|
||||
class PARTICLE_PT_boidbrain(ParticleButtonsPanel):
|
||||
__idname__ = "PARTICLE_PT_boidbrain"
|
||||
__label__ = "Boid Brain"
|
||||
|
||||
def poll(self, context):
|
||||
psys = context.particle_system
|
||||
if psys==None: return False
|
||||
if psys.settings==None: return False
|
||||
return psys.settings.physics_type=='BOIDS'
|
||||
|
||||
def draw(self, context):
|
||||
boids = context.particle_system.settings.boids
|
||||
layout = self.layout
|
||||
|
||||
# Currently boids can only use the first state so these are commented out for now.
|
||||
#row = layout.row()
|
||||
#row.template_list(boids, "states", boids, "active_boid_state_index", compact="True")
|
||||
#col = row.row()
|
||||
#subrow = col.row(align=True)
|
||||
#subrow.itemO("boid.boidstate_add", icon="ICON_ZOOMIN", text="")
|
||||
#subrow.itemO("boid.boidstate_del", icon="ICON_ZOOMOUT", text="")
|
||||
#subrow = row.row(align=True)
|
||||
#subrow.itemO("boid.boidstate_move_up", icon="VICON_MOVE_UP", text="")
|
||||
#subrow.itemO("boid.boidstate_move_down", icon="VICON_MOVE_DOWN", text="")
|
||||
|
||||
state = boids.active_boid_state
|
||||
|
||||
#layout.itemR(state, "name", text="State name")
|
||||
|
||||
row = layout.row()
|
||||
row.itemR(state, "ruleset_type")
|
||||
if state.ruleset_type=='FUZZY':
|
||||
row.itemR(state, "rule_fuzziness", slider=True)
|
||||
else:
|
||||
row.itemL(text="")
|
||||
|
||||
row = layout.row()
|
||||
row.template_list(state, "rules", state, "active_boid_rule_index")
|
||||
|
||||
col = row.column()
|
||||
subrow = col.row()
|
||||
subcol = subrow.column(align=True)
|
||||
subcol.item_menu_enumO("boid.boidrule_add", "type", icon="ICON_ZOOMIN", text="")
|
||||
subcol.itemO("boid.boidrule_del", icon="ICON_ZOOMOUT", text="")
|
||||
subrow = col.row()
|
||||
subcol = subrow.column(align=True)
|
||||
subcol.itemO("boid.boidrule_move_up", icon="VICON_MOVE_UP", text="")
|
||||
subcol.itemO("boid.boidrule_move_down", icon="VICON_MOVE_DOWN", text="")
|
||||
|
||||
rule = state.active_boid_rule
|
||||
|
||||
if rule:
|
||||
row = layout.row()
|
||||
row.itemR(rule, "name", text="")
|
||||
#somebody make nice icons for boids here please! -jahka
|
||||
row.itemR(rule, "in_air", icon="VICON_MOVE_UP", text="")
|
||||
row.itemR(rule, "on_land", icon="VICON_MOVE_DOWN", text="")
|
||||
|
||||
row = layout.row()
|
||||
|
||||
if rule.type == 'GOAL':
|
||||
row.itemR(rule, "object")
|
||||
row = layout.row()
|
||||
row.itemR(rule, "predict")
|
||||
elif rule.type == 'AVOID':
|
||||
row.itemR(rule, "object")
|
||||
row = layout.row()
|
||||
row.itemR(rule, "predict")
|
||||
row.itemR(rule, "fear_factor")
|
||||
elif rule.type == 'FOLLOW_PATH':
|
||||
row.itemL(text="Not yet functional.")
|
||||
elif rule.type == 'AVOID_COLLISION':
|
||||
row.itemR(rule, "boids")
|
||||
row.itemR(rule, "deflectors")
|
||||
row.itemR(rule, "look_ahead")
|
||||
elif rule.type == 'FOLLOW_LEADER':
|
||||
row.itemR(rule, "object", text="")
|
||||
row.itemR(rule, "distance")
|
||||
row = layout.row()
|
||||
row.itemR(rule, "line")
|
||||
subrow = row.row()
|
||||
subrow.active = rule.line
|
||||
subrow.itemR(rule, "queue_size")
|
||||
elif rule.type == 'AVERAGE_SPEED':
|
||||
row.itemR(rule, "speed", slider=True)
|
||||
row.itemR(rule, "wander", slider=True)
|
||||
row.itemR(rule, "level", slider=True)
|
||||
elif rule.type == 'FIGHT':
|
||||
row.itemR(rule, "distance")
|
||||
row.itemR(rule, "flee_distance")
|
||||
|
||||
|
||||
class PARTICLE_PT_render(ParticleButtonsPanel):
|
||||
__idname__= "PARTICLE_PT_render"
|
||||
@@ -596,6 +759,38 @@ class PARTICLE_PT_children(ParticleButtonsPanel):
|
||||
sub = split.column()
|
||||
sub.itemR(part, "kink_shape", slider=True)
|
||||
|
||||
class PARTICLE_PT_effectors(ParticleButtonsPanel):
|
||||
__idname__= "PARTICLE_PT_effectors"
|
||||
__label__ = "Effectors"
|
||||
__default_closed__ = True
|
||||
|
||||
def poll(self, context):
|
||||
psys = context.particle_system
|
||||
if psys==None: return False
|
||||
if psys.settings==None: return False
|
||||
return True;
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
psys = context.particle_system
|
||||
part = psys.settings
|
||||
|
||||
layout.itemR(part, "effector_group")
|
||||
|
||||
layout.itemR(part, "eweight_all", slider=True)
|
||||
|
||||
layout.itemS()
|
||||
layout.itemR(part, "eweight_spherical", slider=True)
|
||||
layout.itemR(part, "eweight_vortex", slider=True)
|
||||
layout.itemR(part, "eweight_magnetic", slider=True)
|
||||
layout.itemR(part, "eweight_wind", slider=True)
|
||||
layout.itemR(part, "eweight_curveguide", slider=True)
|
||||
layout.itemR(part, "eweight_texture", slider=True)
|
||||
layout.itemR(part, "eweight_harmonic", slider=True)
|
||||
layout.itemR(part, "eweight_charge", slider=True)
|
||||
layout.itemR(part, "eweight_lennardjones", slider=True)
|
||||
|
||||
class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
|
||||
__idname__= "PARTICLE_PT_vertexgroups"
|
||||
__label__ = "Vertexgroups"
|
||||
@@ -667,7 +862,9 @@ bpy.types.register(PARTICLE_PT_cache)
|
||||
bpy.types.register(PARTICLE_PT_emission)
|
||||
bpy.types.register(PARTICLE_PT_initial)
|
||||
bpy.types.register(PARTICLE_PT_physics)
|
||||
bpy.types.register(PARTICLE_PT_boidbrain)
|
||||
bpy.types.register(PARTICLE_PT_render)
|
||||
bpy.types.register(PARTICLE_PT_draw)
|
||||
bpy.types.register(PARTICLE_PT_children)
|
||||
bpy.types.register(PARTICLE_PT_effectors)
|
||||
bpy.types.register(PARTICLE_PT_vertexgroups)
|
||||
|
||||
@@ -53,6 +53,11 @@ class PHYSICS_PT_field(PhysicButtonsPanel):
|
||||
sub.itemR(field, "planar")
|
||||
sub.itemR(field, "surface")
|
||||
|
||||
if field.type == "BOID":
|
||||
sub.itemR(field, "strength")
|
||||
sub = split.column()
|
||||
sub.itemR(field, "surface")
|
||||
|
||||
if field.type == "MAGNET":
|
||||
sub.itemR(field, "strength")
|
||||
sub = split.column()
|
||||
@@ -75,7 +80,7 @@ class PHYSICS_PT_field(PhysicButtonsPanel):
|
||||
sub.itemR(field, "root_coordinates")
|
||||
sub.itemR(field, "force_2d")
|
||||
|
||||
if field.type in ("HARMONIC", "SPHERICAL", "CHARGE", "WIND", "VORTEX", "TEXTURE", "MAGNET"):
|
||||
if field.type in ("HARMONIC", "SPHERICAL", "CHARGE", "WIND", "VORTEX", "TEXTURE", "MAGNET", "BOID"):
|
||||
|
||||
|
||||
layout.itemS()
|
||||
|
||||
62
source/blender/blenkernel/BKE_boids.h
Normal file
62
source/blender/blenkernel/BKE_boids.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* BKE_particle.h
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2009 by Janne Karhu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef BKE_BOIDS_H
|
||||
#define BKE_BOIDS_H
|
||||
|
||||
#include "DNA_boid_types.h"
|
||||
|
||||
typedef struct BoidBrainData {
|
||||
Scene *scene;
|
||||
struct Object *ob;
|
||||
struct ParticleSystem *psys;
|
||||
struct ParticleSettings *part;
|
||||
float timestep, cfra, dfra;
|
||||
float wanted_co[3], wanted_speed;
|
||||
|
||||
/* Goal stuff */
|
||||
struct Object *goal_ob;
|
||||
float goal_co[3];
|
||||
float goal_nor[3];
|
||||
float goal_priority;
|
||||
} BoidBrainData;
|
||||
|
||||
void boids_precalc_rules(struct ParticleSettings *part, float cfra);
|
||||
void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
|
||||
void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
|
||||
void boid_default_settings(BoidSettings *boids);
|
||||
BoidRule *boid_new_rule(int type);
|
||||
BoidState *boid_new_state(BoidSettings *boids);
|
||||
BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state);
|
||||
void boid_free_settings(BoidSettings *boids);
|
||||
BoidSettings *boid_copy_settings(BoidSettings *boids);
|
||||
BoidState *boid_get_current_state(BoidSettings *boids);
|
||||
#endif
|
||||
@@ -95,16 +95,6 @@ typedef struct ParticleTexture{
|
||||
float rough1, rough2, roughe; /* used in path caching */
|
||||
} ParticleTexture;
|
||||
|
||||
typedef struct BoidVecFunc{
|
||||
void (*Addf)(float *v, float *v1, float *v2);
|
||||
void (*Subf)(float *v, float *v1, float *v2);
|
||||
void (*Mulf)(float *v, float f);
|
||||
float (*Length)(float *v);
|
||||
float (*Normalize)(float *v);
|
||||
float (*Inpf)(float *v1, float *v2);
|
||||
void (*Copyf)(float *v1, float *v2);
|
||||
} BoidVecFunc;
|
||||
|
||||
typedef struct ParticleSeam{
|
||||
float v0[3], v1[3];
|
||||
float nor[3], dir[3], tan[3];
|
||||
@@ -209,6 +199,19 @@ typedef struct ParticleBillboardData
|
||||
}
|
||||
ParticleBillboardData;
|
||||
|
||||
/* container for moving data between deflet_particle and particle_intersect_face */
|
||||
typedef struct ParticleCollision
|
||||
{
|
||||
struct Object *ob, *ob_t; // collided and current objects
|
||||
struct CollisionModifierData *md; // collision modifier for ob_t;
|
||||
float nor[3]; // normal at collision point
|
||||
float vel[3]; // velocity of collision point
|
||||
float co1[3], co2[3]; // ray start and end points
|
||||
float ray_len; // original length of co2-co1, needed for collision time evaluation
|
||||
float t; // time of previous collision, needed for substracting face velocity
|
||||
}
|
||||
ParticleCollision;
|
||||
|
||||
/* ----------- functions needed outside particlesystem ---------------- */
|
||||
/* particle.c */
|
||||
int count_particles(struct ParticleSystem *psys);
|
||||
@@ -231,6 +234,7 @@ int psys_ob_has_hair(struct Object *ob);
|
||||
int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
|
||||
int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
|
||||
|
||||
void psys_free_boid_rules(struct ListBase *list);
|
||||
void psys_free_settings(struct ParticleSettings *part);
|
||||
void free_child_path_cache(struct ParticleSystem *psys);
|
||||
void psys_free_path_cache(struct ParticleSystem *psys);
|
||||
@@ -288,6 +292,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
|
||||
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
|
||||
|
||||
/* particle_system.c */
|
||||
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
|
||||
void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
|
||||
void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys);
|
||||
|
||||
@@ -298,6 +303,8 @@ void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
|
||||
void psys_end_temp_pointcache(struct ParticleSystem *psys);
|
||||
void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra);
|
||||
|
||||
void psys_check_boid_data(struct ParticleSystem *psys);
|
||||
|
||||
void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
|
||||
|
||||
/* ----------- functions needed only inside particlesystem ------------ */
|
||||
@@ -321,11 +328,13 @@ float psys_interpolate_value_from_verts(struct DerivedMesh *dm, short from, int
|
||||
void psys_get_from_key(struct ParticleKey *key, float *loc, float *vel, float *rot, float *time);
|
||||
|
||||
int psys_intersect_dm(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_uv, float *face_minmax, float *pa_minmax, float radius, float *ipoint);
|
||||
void particle_intersect_face(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
|
||||
void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor);
|
||||
|
||||
/* particle_system.c */
|
||||
void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd);
|
||||
|
||||
int effector_find_co(struct Scene *scene, float *pco, struct SurfaceModifierData *sur, struct Object *ob, struct PartDeflect *pd, float *co, float *nor, float *vel, int *index);
|
||||
void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float *texco, float *force_field, float *vel,float framestep, float cfra);
|
||||
|
||||
void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
|
||||
|
||||
1526
source/blender/blenkernel/intern/boids.c
Normal file
1526
source/blender/blenkernel/intern/boids.c
Normal file
@@ -0,0 +1,1526 @@
|
||||
/* boids.c
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2009 by Janne Karhu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BKE_effect.h"
|
||||
#include "BKE_boids.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
typedef struct BoidValues {
|
||||
float max_speed, max_acc;
|
||||
float max_ave, min_speed;
|
||||
float personal_space, jump_speed;
|
||||
} BoidValues;
|
||||
|
||||
static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
|
||||
|
||||
static int rule_none(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
|
||||
BoidSettings *boids = bbd->part->boids;
|
||||
ParticleEffectorCache *ec;
|
||||
Object *priority_ob = NULL;
|
||||
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
|
||||
float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
|
||||
float priority = 0.0f, len;
|
||||
int ret = 0;
|
||||
|
||||
/* first find out goal/predator with highest priority */
|
||||
/* if rule->ob specified use it */
|
||||
if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != pa->stick_ob)) {
|
||||
PartDeflect *pd = gabr->ob->pd;
|
||||
float vec_to_part[3];
|
||||
|
||||
if(pd && pd->forcefield == PFIELD_BOID) {
|
||||
effector_find_co(bbd->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL);
|
||||
|
||||
VecSubf(vec_to_part, pa->prev_state.co, loc);
|
||||
|
||||
priority = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
|
||||
}
|
||||
else
|
||||
priority = 1.0;
|
||||
|
||||
priority = 1.0;
|
||||
priority_ob = gabr->ob;
|
||||
}
|
||||
else for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
|
||||
if(ec->type & PSYS_EC_EFFECTOR) {
|
||||
Object *eob = ec->ob;
|
||||
PartDeflect *pd = eob->pd;
|
||||
|
||||
/* skip current object */
|
||||
if(rule->type == eBoidRuleType_Goal && eob == pa->stick_ob)
|
||||
continue;
|
||||
|
||||
if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) {
|
||||
float vec_to_part[3], temp;
|
||||
|
||||
effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL);
|
||||
|
||||
VecSubf(vec_to_part, pa->prev_state.co, loc);
|
||||
|
||||
temp = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
|
||||
|
||||
if(temp == 0.0f)
|
||||
; /* do nothing */
|
||||
else if(temp > priority) {
|
||||
priority = temp;
|
||||
priority_ob = eob;
|
||||
len = VecLength(vec_to_part);
|
||||
}
|
||||
/* choose closest object with same priority */
|
||||
else if(temp == priority) {
|
||||
float len2 = VecLength(vec_to_part);
|
||||
|
||||
if(len2 < len) {
|
||||
priority_ob = eob;
|
||||
len = len2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* then use that effector */
|
||||
if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
|
||||
Object *eob = priority_ob;
|
||||
PartDeflect *pd = eob->pd;
|
||||
float vec_to_part[3];
|
||||
float surface = 0.0f;
|
||||
float nor[3];
|
||||
|
||||
if(gabr->options & BRULE_GOAL_AVOID_PREDICT) {
|
||||
/* estimate future location of target */
|
||||
surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL);
|
||||
|
||||
VecSubf(vec_to_part, pa->prev_state.co, loc);
|
||||
len = Normalize(vec_to_part);
|
||||
|
||||
VecMulf(vec, len / (val->max_speed * bbd->timestep));
|
||||
VecAddf(loc, loc, vec);
|
||||
VecSubf(vec_to_part, pa->prev_state.co, loc);
|
||||
}
|
||||
else {
|
||||
surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL);
|
||||
|
||||
VecSubf(vec_to_part, pa->prev_state.co, loc);
|
||||
len = VecLength(vec_to_part);
|
||||
}
|
||||
|
||||
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;
|
||||
VECCOPY(bbd->goal_co, loc);
|
||||
VECCOPY(bbd->goal_nor, nor);
|
||||
}
|
||||
}
|
||||
else if(rule->type == eBoidRuleType_Avoid && pa->boid->mode == eBoidMode_Climbing &&
|
||||
priority > 2.0f * gabr->fear_factor) {
|
||||
/* detach from surface and try to fly away from danger */
|
||||
VECCOPY(vec_to_part, pa->r_ve);
|
||||
VecMulf(vec_to_part, -1.0f);
|
||||
}
|
||||
|
||||
VECCOPY(bbd->wanted_co, vec_to_part);
|
||||
VecMulf(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*VecLength(pa->prev_state.vel);
|
||||
|
||||
surface *= pa->size * boids->height;
|
||||
|
||||
if(len2 > 0.0f && len - surface < len2) {
|
||||
len2 = (len - surface)/len2;
|
||||
bbd->wanted_speed *= pow(len2, boids->landing_smoothness);
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
|
||||
KDTreeNearest *ptn = NULL;
|
||||
ParticleEffectorCache *ec;
|
||||
ParticleTarget *pt;
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
//check deflector objects first
|
||||
if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS) {
|
||||
ParticleCollision col;
|
||||
BVHTreeRayHit hit;
|
||||
float radius = val->personal_space * pa->size, ray_dir[3];
|
||||
|
||||
VECCOPY(col.co1, pa->prev_state.co);
|
||||
VecAddf(col.co2, pa->prev_state.co, pa->prev_state.vel);
|
||||
VecSubf(ray_dir, col.co2, col.co1);
|
||||
VecMulf(ray_dir, acbr->look_ahead);
|
||||
col.t = 0.0f;
|
||||
hit.index = -1;
|
||||
hit.dist = col.ray_len = VecLength(ray_dir);
|
||||
|
||||
/* find out closest deflector object */
|
||||
for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
|
||||
if(ec->type & PSYS_EC_DEFLECT) {
|
||||
Object *eob = ec->ob;
|
||||
|
||||
/* don't check with current ground object */
|
||||
if(eob == pa->stick_ob)
|
||||
continue;
|
||||
|
||||
col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
|
||||
col.ob_t = eob;
|
||||
|
||||
if(col.md && col.md->bvhtree)
|
||||
BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
|
||||
}
|
||||
}
|
||||
/* then avoid that object */
|
||||
if(hit.index>=0) {
|
||||
/* TODO: not totally happy with this part */
|
||||
t = hit.dist/col.ray_len;
|
||||
|
||||
VECCOPY(bbd->wanted_co, col.nor);
|
||||
|
||||
VecMulf(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
|
||||
|
||||
bbd->wanted_speed = sqrt(t) * VecLength(pa->prev_state.vel);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//check boids in own system
|
||||
if(acbr->options & BRULE_ACOLL_WITH_BOIDS)
|
||||
{
|
||||
neighbors = BLI_kdtree_range_search(bbd->psys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
|
||||
if(neighbors > 1) for(n=1; n<neighbors; n++) {
|
||||
VECCOPY(co1, pa->prev_state.co);
|
||||
VECCOPY(vel1, pa->prev_state.vel);
|
||||
VECCOPY(co2, (bbd->psys->particles + ptn[n].index)->prev_state.co);
|
||||
VECCOPY(vel2, (bbd->psys->particles + ptn[n].index)->prev_state.vel);
|
||||
|
||||
VecSubf(loc, co1, co2);
|
||||
|
||||
VecSubf(vec, vel1, vel2);
|
||||
|
||||
inp = Inpf(vec,vec);
|
||||
|
||||
/* velocities not parallel */
|
||||
if(inp != 0.0f) {
|
||||
t = -Inpf(loc, vec)/inp;
|
||||
/* cpa is not too far in the future so investigate further */
|
||||
if(t > 0.0f && t < t_min) {
|
||||
VECADDFAC(co1, co1, vel1, t);
|
||||
VECADDFAC(co2, co2, vel2, t);
|
||||
|
||||
VecSubf(vec, co2, co1);
|
||||
|
||||
len = Normalize(vec);
|
||||
|
||||
/* distance of cpa is close enough */
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
t_min = t;
|
||||
|
||||
VecMulf(vec, VecLength(vel1));
|
||||
VecMulf(vec, (2.0f - t)/2.0f);
|
||||
VecSubf(bbd->wanted_co, vel1, vec);
|
||||
bbd->wanted_speed = VecLength(bbd->wanted_co);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ptn){ MEM_freeN(ptn); ptn=NULL; }
|
||||
|
||||
/* check boids in other systems */
|
||||
for(pt=bbd->psys->targets.first; pt; pt=pt->next) {
|
||||
ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
|
||||
|
||||
if(epsys) {
|
||||
neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn);
|
||||
if(neighbors > 0) for(n=0; n<neighbors; n++) {
|
||||
VECCOPY(co1, pa->prev_state.co);
|
||||
VECCOPY(vel1, pa->prev_state.vel);
|
||||
VECCOPY(co2, (epsys->particles + ptn[n].index)->prev_state.co);
|
||||
VECCOPY(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
|
||||
|
||||
VecSubf(loc, co1, co2);
|
||||
|
||||
VecSubf(vec, vel1, vel2);
|
||||
|
||||
inp = Inpf(vec,vec);
|
||||
|
||||
/* velocities not parallel */
|
||||
if(inp != 0.0f) {
|
||||
t = -Inpf(loc, vec)/inp;
|
||||
/* cpa is not too far in the future so investigate further */
|
||||
if(t > 0.0f && t < t_min) {
|
||||
VECADDFAC(co1, co1, vel1, t);
|
||||
VECADDFAC(co2, co2, vel2, t);
|
||||
|
||||
VecSubf(vec, co2, co1);
|
||||
|
||||
len = Normalize(vec);
|
||||
|
||||
/* distance of cpa is close enough */
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
t_min = t;
|
||||
|
||||
VecMulf(vec, VecLength(vel1));
|
||||
VecMulf(vec, (2.0f - t)/2.0f);
|
||||
VecSubf(bbd->wanted_co, vel1, vec);
|
||||
bbd->wanted_speed = VecLength(bbd->wanted_co);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ptn){ MEM_freeN(ptn); ptn=NULL; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(ptn && nearest==0)
|
||||
MEM_freeN(ptn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static int rule_separate(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
KDTreeNearest *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_range_search(bbd->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
|
||||
int ret = 0;
|
||||
|
||||
if(neighbors > 1 && ptn[1].dist!=0.0f) {
|
||||
VecSubf(vec, pa->prev_state.co, bbd->psys->particles[ptn[1].index].state.co);
|
||||
VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
|
||||
VecAddf(bbd->wanted_co, 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->psys->targets.first; pt; pt=pt->next) {
|
||||
ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
|
||||
|
||||
if(epsys) {
|
||||
neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn);
|
||||
|
||||
if(neighbors > 0 && ptn[0].dist < len) {
|
||||
VecSubf(vec, pa->prev_state.co, ptn[0].co);
|
||||
VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
|
||||
VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
|
||||
bbd->wanted_speed = val->max_speed;
|
||||
len = ptn[0].dist;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if(ptn){ MEM_freeN(ptn); ptn=NULL; }
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rule_flock(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
KDTreeNearest ptn[11];
|
||||
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
|
||||
int neighbors = BLI_kdtree_find_n_nearest(bbd->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn);
|
||||
int n, nearest = 1;
|
||||
int ret = 0;
|
||||
|
||||
if(neighbors > 1) {
|
||||
for(n=1; n<neighbors; n++) {
|
||||
VecAddf(loc, loc, bbd->psys->particles[ptn[n].index].prev_state.co);
|
||||
VecAddf(vec, vec, bbd->psys->particles[ptn[n].index].prev_state.vel);
|
||||
}
|
||||
|
||||
VecMulf(loc, 1.0f/((float)neighbors - 1.0f));
|
||||
VecMulf(vec, 1.0f/((float)neighbors - 1.0f));
|
||||
|
||||
VecSubf(loc, loc, pa->prev_state.co);
|
||||
VecSubf(vec, vec, pa->prev_state.vel);
|
||||
|
||||
VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
|
||||
VecAddf(bbd->wanted_co, bbd->wanted_co, loc);
|
||||
bbd->wanted_speed = VecLength(bbd->wanted_co);
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
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->psys->totpart : flbr->queue_size;
|
||||
int i, ret = 0, p = pa - bbd->psys->particles;
|
||||
|
||||
if(flbr->ob) {
|
||||
float vec2[3], t;
|
||||
|
||||
/* first check we're not blocking the leader*/
|
||||
VecSubf(vec, flbr->loc, flbr->oloc);
|
||||
VecMulf(vec, 1.0f/bbd->timestep);
|
||||
|
||||
VecSubf(loc, pa->prev_state.co, flbr->oloc);
|
||||
|
||||
mul = Inpf(vec, vec);
|
||||
|
||||
/* leader is not moving */
|
||||
if(mul < 0.01) {
|
||||
len = VecLength(loc);
|
||||
/* too close to leader */
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
VECCOPY(bbd->wanted_co, loc);
|
||||
bbd->wanted_speed = val->max_speed;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
t = Inpf(loc, vec)/mul;
|
||||
|
||||
/* possible blocking of leader in near future */
|
||||
if(t > 0.0f && t < 3.0f) {
|
||||
VECCOPY(vec2, vec);
|
||||
VecMulf(vec2, t);
|
||||
|
||||
VecSubf(vec2, loc, vec2);
|
||||
|
||||
len = VecLength(vec2);
|
||||
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
VECCOPY(bbd->wanted_co, vec2);
|
||||
bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* not blocking so try to follow leader */
|
||||
if(p && flbr->options & BRULE_LEADER_IN_LINE) {
|
||||
VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel);
|
||||
VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co);
|
||||
}
|
||||
else {
|
||||
VECCOPY(loc, flbr->oloc);
|
||||
VecSubf(vec, flbr->loc, flbr->oloc);
|
||||
VecMulf(vec, 1.0/bbd->timestep);
|
||||
}
|
||||
|
||||
/* fac is seconds behind leader */
|
||||
VECADDFAC(loc, loc, vec, -flbr->distance);
|
||||
|
||||
VecSubf(bbd->wanted_co, loc, pa->prev_state.co);
|
||||
bbd->wanted_speed = VecLength(bbd->wanted_co);
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
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->psys->totpart; i+=n){
|
||||
VECCOPY(vec, bbd->psys->particles[i].prev_state.vel);
|
||||
|
||||
VecSubf(loc, pa->prev_state.co, bbd->psys->particles[i].prev_state.co);
|
||||
|
||||
mul = Inpf(vec, vec);
|
||||
|
||||
/* leader is not moving */
|
||||
if(mul < 0.01) {
|
||||
len = VecLength(loc);
|
||||
/* too close to leader */
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
VECCOPY(bbd->wanted_co, loc);
|
||||
bbd->wanted_speed = val->max_speed;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
t = Inpf(loc, vec)/mul;
|
||||
|
||||
/* possible blocking of leader in near future */
|
||||
if(t > 0.0f && t < t_min) {
|
||||
VECCOPY(vec2, vec);
|
||||
VecMulf(vec2, t);
|
||||
|
||||
VecSubf(vec2, loc, vec2);
|
||||
|
||||
len = VecLength(vec2);
|
||||
|
||||
if(len < 2.0f * val->personal_space * pa->size) {
|
||||
t_min = t;
|
||||
VECCOPY(bbd->wanted_co, loc);
|
||||
bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ret) return 1;
|
||||
|
||||
/* not blocking so try to follow leader */
|
||||
if(flbr->options & BRULE_LEADER_IN_LINE) {
|
||||
VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel);
|
||||
VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co);
|
||||
}
|
||||
else {
|
||||
VECCOPY(vec, bbd->psys->particles[p - p%n].prev_state.vel);
|
||||
VECCOPY(loc, bbd->psys->particles[p - p%n].prev_state.co);
|
||||
}
|
||||
|
||||
/* fac is seconds behind leader */
|
||||
VECADDFAC(loc, loc, vec, -flbr->distance);
|
||||
|
||||
VecSubf(bbd->wanted_co, loc, pa->prev_state.co);
|
||||
bbd->wanted_speed = VecLength(bbd->wanted_co);
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule;
|
||||
float vec[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
if(asbr->wander > 0.0f) {
|
||||
/* abuse pa->r_ave for wandering */
|
||||
pa->r_ave[0] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
|
||||
pa->r_ave[1] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
|
||||
pa->r_ave[2] += asbr->wander * (-1.0f + 2.0f * BLI_frand());
|
||||
|
||||
Normalize(pa->r_ave);
|
||||
|
||||
VECCOPY(vec, pa->r_ave);
|
||||
|
||||
QuatMulVecf(pa->prev_state.rot, vec);
|
||||
|
||||
VECCOPY(bbd->wanted_co, pa->prev_state.ave);
|
||||
|
||||
VecMulf(bbd->wanted_co, 1.1f);
|
||||
|
||||
VecAddf(bbd->wanted_co, bbd->wanted_co, vec);
|
||||
|
||||
/* leveling */
|
||||
if(asbr->level > 0.0f) {
|
||||
Projf(vec, bbd->wanted_co, bbd->psys->part->acc);
|
||||
VecMulf(vec, asbr->level);
|
||||
VecSubf(bbd->wanted_co, bbd->wanted_co, vec);
|
||||
}
|
||||
}
|
||||
else {
|
||||
VECCOPY(bbd->wanted_co, pa->prev_state.ave);
|
||||
|
||||
/* may happen at birth */
|
||||
if(Inp2f(bbd->wanted_co,bbd->wanted_co)==0.0f) {
|
||||
bbd->wanted_co[0] = 2.0f*(0.5f - BLI_frand());
|
||||
bbd->wanted_co[1] = 2.0f*(0.5f - BLI_frand());
|
||||
bbd->wanted_co[2] = 2.0f*(0.5f - BLI_frand());
|
||||
}
|
||||
|
||||
/* leveling */
|
||||
if(asbr->level > 0.0f) {
|
||||
Projf(vec, bbd->wanted_co, bbd->psys->part->acc);
|
||||
VecMulf(vec, asbr->level);
|
||||
VecSubf(bbd->wanted_co, bbd->wanted_co, vec);
|
||||
}
|
||||
|
||||
}
|
||||
bbd->wanted_speed = asbr->speed * val->max_speed;
|
||||
|
||||
return 1;
|
||||
}
|
||||
static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
|
||||
{
|
||||
BoidRuleFight *fbr = (BoidRuleFight*)rule;
|
||||
KDTreeNearest *ptn = NULL;
|
||||
ParticleTarget *pt;
|
||||
ParticleData *epars;
|
||||
ParticleData *enemy_pa;
|
||||
/* 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;
|
||||
int n, ret = 0;
|
||||
|
||||
/* calculate own group strength */
|
||||
int neighbors = BLI_kdtree_range_search(bbd->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
|
||||
for(n=0; n<neighbors; n++)
|
||||
health += bbd->psys->particles[ptn[n].index].boid->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->psys->targets.first; pt; pt=pt->next) {
|
||||
ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt);
|
||||
if(epsys) {
|
||||
epars = epsys->particles;
|
||||
|
||||
neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
|
||||
|
||||
health = 0.0f;
|
||||
|
||||
for(n=0; n<neighbors; n++) {
|
||||
health += epars[ptn[n].index].boid->health;
|
||||
|
||||
if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
|
||||
VECCOPY(closest_enemy, ptn[n].co);
|
||||
closest_dist = ptn[n].dist;
|
||||
enemy_pa = epars + ptn[n].index;
|
||||
}
|
||||
}
|
||||
if(pt->mode==PTARGET_MODE_ENEMY)
|
||||
e_strength += epsys->part->boids->strength * health;
|
||||
else if(pt->mode==PTARGET_MODE_FRIEND)
|
||||
f_strength += epsys->part->boids->strength * health;
|
||||
|
||||
if(ptn){ MEM_freeN(ptn); ptn=NULL; }
|
||||
}
|
||||
}
|
||||
/* decide action if enemy presence found */
|
||||
if(e_strength > 0.0f) {
|
||||
VecSubf(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_frand();
|
||||
float enemy_dir[3] = {bbd->wanted_co[0],bbd->wanted_co[1],bbd->wanted_co[2]};
|
||||
|
||||
Normalize(enemy_dir);
|
||||
|
||||
/* fight mode */
|
||||
bbd->wanted_speed = 0.0f;
|
||||
|
||||
/* must face enemy to fight */
|
||||
if(Inpf(pa->prev_state.ave, enemy_dir)>0.5f) {
|
||||
enemy_pa->boid->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 */
|
||||
if(pa->boid->health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
|
||||
/* decide to flee */
|
||||
if(closest_dist < fbr->flee_distance * fbr->distance) {
|
||||
VecMulf(bbd->wanted_co, -1.0f);
|
||||
bbd->wanted_speed = val->max_speed;
|
||||
}
|
||||
else { /* wait for better odds */
|
||||
bbd->wanted_speed = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa);
|
||||
|
||||
static boid_rule_cb boid_rules[] = {
|
||||
rule_none,
|
||||
rule_goal_avoid,
|
||||
rule_goal_avoid,
|
||||
rule_avoid_collision,
|
||||
rule_separate,
|
||||
rule_flock,
|
||||
rule_follow_leader,
|
||||
rule_average_speed,
|
||||
rule_fight,
|
||||
//rule_help,
|
||||
//rule_protect,
|
||||
//rule_hide,
|
||||
//rule_follow_path,
|
||||
//rule_follow_wall
|
||||
};
|
||||
|
||||
static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
|
||||
{
|
||||
if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
|
||||
val->max_speed = boids->land_max_speed * pa->boid->health/boids->health;
|
||||
val->max_acc = boids->land_max_acc * val->max_speed;
|
||||
val->max_ave = boids->land_max_ave * M_PI * pa->boid->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 * pa->boid->health/boids->health;
|
||||
}
|
||||
else {
|
||||
val->max_speed = boids->air_max_speed * pa->boid->health/boids->health;
|
||||
val->max_acc = boids->air_max_acc * val->max_speed;
|
||||
val->max_ave = boids->air_max_ave * M_PI * pa->boid->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 */
|
||||
}
|
||||
}
|
||||
static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *ground_co, float *ground_nor)
|
||||
{
|
||||
if(pa->boid->mode == eBoidMode_Climbing) {
|
||||
SurfaceModifierData *surmd = NULL;
|
||||
float x[3], v[3];
|
||||
|
||||
surmd = (SurfaceModifierData *)modifiers_findByType ( pa->stick_ob, eModifierType_Surface );
|
||||
|
||||
/* take surface velocity into account */
|
||||
effector_find_co(bbd->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL);
|
||||
VecAddf(x, x, v);
|
||||
|
||||
/* get actual position on surface */
|
||||
effector_find_co(bbd->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL);
|
||||
|
||||
return pa->stick_ob;
|
||||
}
|
||||
else {
|
||||
float zvec[3] = {0.0f, 0.0f, 2000.0f};
|
||||
ParticleCollision col;
|
||||
BVHTreeRayHit hit;
|
||||
ParticleEffectorCache *ec;
|
||||
float radius = 0.0f, t, ray_dir[3];
|
||||
|
||||
VECCOPY(col.co1, pa->state.co);
|
||||
VECCOPY(col.co2, pa->state.co);
|
||||
VecAddf(col.co1, col.co1, zvec);
|
||||
VecSubf(col.co2, col.co2, zvec);
|
||||
VecSubf(ray_dir, col.co2, col.co1);
|
||||
col.t = 0.0f;
|
||||
hit.index = -1;
|
||||
hit.dist = col.ray_len = VecLength(ray_dir);
|
||||
|
||||
/* find out upmost deflector object */
|
||||
for(ec=bbd->psys->effectors.first; ec; ec=ec->next) {
|
||||
if(ec->type & PSYS_EC_DEFLECT) {
|
||||
Object *eob = ec->ob;
|
||||
|
||||
col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
|
||||
col.ob_t = eob;
|
||||
|
||||
if(col.md && col.md->bvhtree)
|
||||
BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
|
||||
}
|
||||
}
|
||||
/* then use that object */
|
||||
if(hit.index>=0) {
|
||||
t = hit.dist/col.ray_len;
|
||||
VecLerpf(ground_co, col.co1, col.co2, t);
|
||||
VECCOPY(ground_nor, col.nor);
|
||||
Normalize(ground_nor);
|
||||
return col.ob;
|
||||
}
|
||||
else {
|
||||
/* default to z=0 */
|
||||
VECCOPY(ground_co, pa->state.co);
|
||||
ground_co[2] = 0;
|
||||
ground_nor[0] = ground_nor[1] = 0.0f;
|
||||
ground_nor[2] = 1.0f;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
static int boid_rule_applies(ParticleData *pa, BoidSettings *boids, BoidRule *rule)
|
||||
{
|
||||
if(rule==NULL)
|
||||
return 0;
|
||||
|
||||
if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
|
||||
return 1;
|
||||
|
||||
if(pa->boid->mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void boids_precalc_rules(ParticleSettings *part, float cfra)
|
||||
{
|
||||
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 */
|
||||
VECCOPY(flbr->oloc, flbr->loc);
|
||||
VECCOPY(flbr->loc, flbr->ob->obmat[3]);
|
||||
flbr->cfra = cfra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
|
||||
{
|
||||
float nor[3], vel[3];
|
||||
VECCOPY(nor, surface_nor);
|
||||
|
||||
/* gather apparent gravity to r_ve */
|
||||
VECADDFAC(pa->r_ve, pa->r_ve, surface_nor, -1.0);
|
||||
Normalize(pa->r_ve);
|
||||
|
||||
/* raise boid it's size from surface */
|
||||
VecMulf(nor, pa->size * boids->height);
|
||||
VecAddf(pa->state.co, surface_co, nor);
|
||||
|
||||
/* remove normal component from velocity */
|
||||
Projf(vel, pa->state.vel, surface_nor);
|
||||
VecSubf(pa->state.vel, pa->state.vel, vel);
|
||||
}
|
||||
static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
|
||||
{
|
||||
float vec[3];
|
||||
|
||||
VecSubf(vec, boid_co, goal_co);
|
||||
|
||||
return Inpf(vec, goal_nor);
|
||||
}
|
||||
/* wanted_co is relative to boid location */
|
||||
static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
|
||||
{
|
||||
if(rule==NULL)
|
||||
return 0;
|
||||
|
||||
if(boid_rule_applies(pa, bbd->part->boids, rule)==0)
|
||||
return 0;
|
||||
|
||||
if(boid_rules[rule->type](rule, bbd, val, pa)==0)
|
||||
return 0;
|
||||
|
||||
if(fuzziness < 0.0f || VecLenCompare(bbd->wanted_co, pa->prev_state.vel, fuzziness * VecLength(pa->prev_state.vel))==0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) {
|
||||
BoidState *state = boids->states.first;
|
||||
|
||||
for(; state; state=state->next) {
|
||||
if(state->id==pa->boid->state_id)
|
||||
return state;
|
||||
}
|
||||
|
||||
/* for some reason particle isn't at a valid state */
|
||||
state = boids->states.first;
|
||||
if(state)
|
||||
pa->boid->state_id = state->id;
|
||||
|
||||
return state;
|
||||
}
|
||||
//static int boid_condition_is_true(BoidCondition *cond) {
|
||||
// /* TODO */
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
/* determines the velocity the boid wants to have */
|
||||
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
|
||||
{
|
||||
ParticleData *pars=bbd->psys->particles;
|
||||
ParticleEffectorCache *ec=0;
|
||||
BoidRule *rule;
|
||||
BoidSettings *boids = bbd->part->boids;
|
||||
BoidValues val;
|
||||
BoidState *state = get_boid_state(boids, pa);
|
||||
//BoidCondition *cond;
|
||||
|
||||
if(pa->boid->health <= 0.0f) {
|
||||
pa->alive = PARS_DYING;
|
||||
return;
|
||||
}
|
||||
|
||||
//planned for near future
|
||||
//cond = state->conditions.first;
|
||||
//for(; cond; cond=cond->next) {
|
||||
// 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 */
|
||||
// }
|
||||
//}
|
||||
|
||||
bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
|
||||
|
||||
/* create random seed for every particle & frame */
|
||||
BLI_srandom(bbd->psys->seed + p + (int)bbd->cfra + (int)(1000*pa->r_rot[0]));
|
||||
|
||||
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) {
|
||||
if(apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
|
||||
break; /* only first nonzero rule that comes through fuzzy rule is applied */
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eBoidRulesetType_Random:
|
||||
{
|
||||
/* use random rule for each particle (allways same for same particle though) */
|
||||
rule = BLI_findlink(&state->rules, (int)(1000.0f * pa->r_rot[1]) % BLI_countlist(&state->rules));
|
||||
|
||||
apply_boid_rule(bbd, rule, &val, pa, -1.0);
|
||||
}
|
||||
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)) {
|
||||
VecAddf(wanted_co, wanted_co, bbd->wanted_co);
|
||||
wanted_speed += bbd->wanted_speed;
|
||||
n++;
|
||||
bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if(n > 1) {
|
||||
VecMulf(wanted_co, 1.0f/(float)n);
|
||||
wanted_speed /= (float)n;
|
||||
}
|
||||
|
||||
VECCOPY(bbd->wanted_co, wanted_co);
|
||||
bbd->wanted_speed = wanted_speed;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* decide on jumping & liftoff */
|
||||
if(pa->boid->mode == eBoidMode_OnLand) {
|
||||
/* fuzziness makes boids capable of misjudgement */
|
||||
float mul = 1.0 + state->rule_fuzziness;
|
||||
|
||||
if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
|
||||
float cvel[3], dir[3];
|
||||
|
||||
VECCOPY(dir, pa->prev_state.ave);
|
||||
Normalize2(dir);
|
||||
|
||||
VECCOPY(cvel, bbd->wanted_co);
|
||||
Normalize2(cvel);
|
||||
|
||||
if(Inp2f(cvel, dir) > 0.95 / mul)
|
||||
pa->boid->mode = eBoidMode_Liftoff;
|
||||
}
|
||||
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;
|
||||
|
||||
VECCOPY(dir, pa->prev_state.ave);
|
||||
Normalize2(dir);
|
||||
|
||||
VECCOPY(cvel, bbd->wanted_co);
|
||||
Normalize2(cvel);
|
||||
|
||||
len = Vec2Length(pa->prev_state.vel);
|
||||
|
||||
/* first of all, are we going in a suitable direction? */
|
||||
/* or at a suitably slow speed */
|
||||
if(Inp2f(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
|
||||
/* try to reach goal at highest point of the parabolic path */
|
||||
cur_v = Vec2Length(pa->prev_state.vel);
|
||||
z_v = sasqrt(-2.0f * bbd->part->acc[2] * bbd->wanted_co[2]);
|
||||
ground_v = Vec2Length(bbd->wanted_co)*sasqrt(-0.5f * bbd->part->acc[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);
|
||||
|
||||
VECCOPY(jump_v, dir);
|
||||
jump_v[2] = z_v;
|
||||
VecMulf(jump_v, ground_v);
|
||||
|
||||
Normalize(jump_v);
|
||||
VecMulf(jump_v, len);
|
||||
Vec2Addf(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) {
|
||||
|
||||
}
|
||||
|
||||
if(jump) {
|
||||
VECCOPY(pa->prev_state.vel, jump_v);
|
||||
pa->boid->mode = eBoidMode_Falling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* tries to realize the wanted velocity taking all constraints into account */
|
||||
void boid_body(BoidBrainData *bbd, ParticleData *pa)
|
||||
{
|
||||
BoidSettings *boids = bbd->part->boids;
|
||||
BoidValues val;
|
||||
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}, tvel[3] = {0.0f, 0.0f, 1.0f};
|
||||
float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
|
||||
int p = pa - bbd->psys->particles;
|
||||
|
||||
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);
|
||||
|
||||
if(bbd->part->flag & PART_SIZEMASS)
|
||||
pa_mass*=pa->size;
|
||||
|
||||
/* if boids can't fly they fall to the ground */
|
||||
if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && bbd->part->acc[2] != 0.0f)
|
||||
pa->boid->mode = eBoidMode_Falling;
|
||||
|
||||
if(pa->boid->mode == eBoidMode_Falling) {
|
||||
/* Falling boids are only effected by gravity. */
|
||||
acc[2] = bbd->part->acc[2];
|
||||
}
|
||||
else {
|
||||
/* figure out acceleration */
|
||||
float landing_level = 2.0f;
|
||||
float level = landing_level + 1.0f;
|
||||
float new_vel[3];
|
||||
|
||||
if(pa->boid->mode == eBoidMode_Liftoff) {
|
||||
pa->boid->mode = eBoidMode_InAir;
|
||||
pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor);
|
||||
}
|
||||
else if(pa->boid->mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
|
||||
/* auto-leveling & landing if close to ground */
|
||||
|
||||
pa->stick_ob = 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.5;
|
||||
|
||||
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;
|
||||
pa->boid->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VECCOPY(old_dir, pa->prev_state.ave);
|
||||
VECCOPY(wanted_dir, bbd->wanted_co);
|
||||
new_speed = Normalize(wanted_dir);
|
||||
|
||||
/* first check if we have valid direction we want to go towards */
|
||||
if(new_speed == 0.0f) {
|
||||
VECCOPY(new_dir, old_dir);
|
||||
}
|
||||
else {
|
||||
float old_dir2[2], wanted_dir2[2], nor[3], angle;
|
||||
Vec2Copyf(old_dir2, old_dir);
|
||||
Normalize2(old_dir2);
|
||||
Vec2Copyf(wanted_dir2, wanted_dir);
|
||||
Normalize2(wanted_dir2);
|
||||
|
||||
/* choose random direction to turn if wanted velocity */
|
||||
/* is directly behind regardless of z-coordinate */
|
||||
if(Inp2f(old_dir2, wanted_dir2) < -0.99f) {
|
||||
wanted_dir[0] = 2.0f*(0.5f - BLI_frand());
|
||||
wanted_dir[1] = 2.0f*(0.5f - BLI_frand());
|
||||
wanted_dir[2] = 2.0f*(0.5f - BLI_frand());
|
||||
Normalize(wanted_dir);
|
||||
}
|
||||
|
||||
/* constrain direction with maximum angular velocity */
|
||||
angle = saacos(Inpf(old_dir, wanted_dir));
|
||||
angle = MIN2(angle, val.max_ave);
|
||||
|
||||
Crossf(nor, old_dir, wanted_dir);
|
||||
VecRotToQuat(nor, angle, q);
|
||||
VECCOPY(new_dir, old_dir);
|
||||
QuatMulVecf(q, new_dir);
|
||||
Normalize(new_dir);
|
||||
|
||||
/* save direction in case resulting velocity too small */
|
||||
VecRotToQuat(nor, angle*dtime, q);
|
||||
VECCOPY(pa->state.ave, old_dir);
|
||||
QuatMulVecf(q, pa->state.ave);
|
||||
Normalize(pa->state.ave);
|
||||
}
|
||||
|
||||
/* constrain speed with maximum acceleration */
|
||||
old_speed = VecLength(pa->prev_state.vel);
|
||||
|
||||
if(bbd->wanted_speed < old_speed)
|
||||
new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
|
||||
else
|
||||
new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
|
||||
|
||||
/* combine direction and speed */
|
||||
VECCOPY(new_vel, new_dir);
|
||||
VecMulf(new_vel, new_speed);
|
||||
|
||||
/* maintain minimum flying velocity if not landing */
|
||||
if(level >= landing_level) {
|
||||
float len2 = Inp2f(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;
|
||||
|
||||
Normalize2(new_vel);
|
||||
Vec2Mulf(new_vel, sasqrt(len2));
|
||||
}
|
||||
|
||||
/* finally constrain speed to max speed */
|
||||
new_speed = Normalize(new_vel);
|
||||
VecMulf(new_vel, MIN2(new_speed, val.max_speed));
|
||||
|
||||
/* get acceleration from difference of velocities */
|
||||
VecSubf(acc, new_vel, pa->prev_state.vel);
|
||||
|
||||
/* break acceleration to components */
|
||||
Projf(tan_acc, acc, pa->prev_state.ave);
|
||||
VecSubf(nor_acc, acc, tan_acc);
|
||||
}
|
||||
|
||||
/* account for effectors */
|
||||
do_effectors(p, pa, &pa->state, bbd->scene, bbd->ob, bbd->psys, pa->state.co, force, tvel, bbd->dfra, bbd->cfra);
|
||||
|
||||
if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
|
||||
float length = Normalize(force);
|
||||
|
||||
length = MAX2(0.0f, length - boids->land_stick_force);
|
||||
|
||||
VecMulf(force, length);
|
||||
}
|
||||
|
||||
VecAddf(acc, acc, force);
|
||||
|
||||
/* store smoothed acceleration for nice banking etc. */
|
||||
VECADDFAC(pa->boid->acc, pa->boid->acc, acc, dtime);
|
||||
VecMulf(pa->boid->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 allthough it's a bit unphysical */
|
||||
VecMulf(acc, 1.0f/pa_mass);
|
||||
|
||||
VECCOPY(dvec, acc);
|
||||
VecMulf(dvec, dtime*dtime*0.5f);
|
||||
|
||||
VECCOPY(bvec, pa->prev_state.vel);
|
||||
VecMulf(bvec, dtime);
|
||||
VecAddf(dvec, dvec, bvec);
|
||||
VecAddf(pa->state.co, pa->state.co, dvec);
|
||||
|
||||
VECADDFAC(pa->state.vel, pa->state.vel, acc, dtime);
|
||||
|
||||
if(pa->boid->mode != eBoidMode_InAir)
|
||||
pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor);
|
||||
|
||||
/* change modes, constrain movement & keep track of down vector */
|
||||
switch(pa->boid->mode) {
|
||||
case eBoidMode_InAir:
|
||||
{
|
||||
float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f};
|
||||
|
||||
/* don't take forward acceleration into account (better banking) */
|
||||
if(Inpf(pa->boid->acc, pa->state.vel) > 0.0f) {
|
||||
Projf(dvec, pa->boid->acc, pa->state.vel);
|
||||
VecSubf(dvec, pa->boid->acc, dvec);
|
||||
}
|
||||
else {
|
||||
VECCOPY(dvec, pa->boid->acc);
|
||||
}
|
||||
|
||||
/* gather apparent gravity to r_ve */
|
||||
VECADDFAC(pa->r_ve, grav, dvec, -boids->banking);
|
||||
Normalize(pa->r_ve);
|
||||
|
||||
/* 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) {
|
||||
pa->boid->mode = eBoidMode_Climbing;
|
||||
pa->stick_ob = bbd->goal_ob;
|
||||
boid_find_ground(bbd, pa, ground_co, ground_nor);
|
||||
boid_climb(boids, pa, ground_co, ground_nor);
|
||||
}
|
||||
/* land boid when belowg ground */
|
||||
else if(boids->options & BOID_ALLOW_LAND && pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
|
||||
pa->state.co[2] = ground_co[2] + pa->size * boids->height;
|
||||
pa->state.vel[2] = 0.0f;
|
||||
pa->boid->mode = eBoidMode_OnLand;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eBoidMode_Falling:
|
||||
{
|
||||
float zvec[3] = {0.0f,0.0f,1.0f};
|
||||
float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f};
|
||||
|
||||
/* gather apparent gravity to r_ve */
|
||||
VECADDFAC(pa->r_ve, pa->r_ve, grav, dtime);
|
||||
Normalize(pa->r_ve);
|
||||
|
||||
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) {
|
||||
pa->boid->mode = eBoidMode_Climbing;
|
||||
pa->stick_ob = 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.01 * pa->size * boids->height){
|
||||
pa->state.co[2] = ground_co[2] + pa->size * boids->height;
|
||||
pa->state.vel[2] = 0.0f;
|
||||
pa->boid->mode = eBoidMode_OnLand;
|
||||
}
|
||||
/* if we're falling, can fly and want to go upwards lets fly */
|
||||
else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
|
||||
pa->boid->mode = eBoidMode_InAir;
|
||||
}
|
||||
else
|
||||
pa->boid->mode = eBoidMode_InAir;
|
||||
break;
|
||||
}
|
||||
case eBoidMode_Climbing:
|
||||
{
|
||||
boid_climb(boids, pa, ground_co, ground_nor);
|
||||
//float nor[3];
|
||||
//VECCOPY(nor, ground_nor);
|
||||
|
||||
///* gather apparent gravity to r_ve */
|
||||
//VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0);
|
||||
//Normalize(pa->r_ve);
|
||||
|
||||
///* raise boid it's size from surface */
|
||||
//VecMulf(nor, pa->size * boids->height);
|
||||
//VecAddf(pa->state.co, ground_co, nor);
|
||||
|
||||
///* remove normal component from velocity */
|
||||
//Projf(v, pa->state.vel, ground_nor);
|
||||
//VecSubf(pa->state.vel, pa->state.vel, v);
|
||||
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) {
|
||||
pa->boid->mode = eBoidMode_Climbing;
|
||||
pa->stick_ob = 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 */
|
||||
else if(pa->state.co[2]-ground_co[2] > 1.1 * pa->size * boids->height)
|
||||
pa->boid->mode = eBoidMode_Falling;
|
||||
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. */
|
||||
VECCOPY(grav, ground_nor);
|
||||
VecMulf(grav, -1.0f);
|
||||
|
||||
Projf(dvec, pa->boid->acc, pa->state.vel);
|
||||
VecSubf(dvec, pa->boid->acc, dvec);
|
||||
|
||||
/* gather apparent gravity to r_ve */
|
||||
VECADDFAC(pa->r_ve, grav, dvec, -boids->banking);
|
||||
Normalize(pa->r_ve);
|
||||
}
|
||||
else {
|
||||
/* gather negative surface normal to r_ve */
|
||||
VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0f);
|
||||
Normalize(pa->r_ve);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* save direction to state.ave unless the boid is falling */
|
||||
/* (boids can't effect their direction when falling) */
|
||||
if(pa->boid->mode!=eBoidMode_Falling && VecLength(pa->state.vel) > 0.1*pa->size) {
|
||||
VECCOPY(pa->state.ave, pa->state.vel);
|
||||
Normalize(pa->state.ave);
|
||||
}
|
||||
|
||||
/* apply damping */
|
||||
if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing))
|
||||
VecMulf(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);
|
||||
|
||||
/* calculate rotation matrix based on forward & down vectors */
|
||||
if(pa->boid->mode == eBoidMode_InAir) {
|
||||
VECCOPY(mat[0], pa->state.ave);
|
||||
|
||||
Projf(dvec, pa->r_ve, pa->state.ave);
|
||||
VecSubf(mat[2], pa->r_ve, dvec);
|
||||
Normalize(mat[2]);
|
||||
}
|
||||
else {
|
||||
Projf(dvec, pa->state.ave, pa->r_ve);
|
||||
VecSubf(mat[0], pa->state.ave, dvec);
|
||||
Normalize(mat[0]);
|
||||
|
||||
VECCOPY(mat[2], pa->r_ve);
|
||||
}
|
||||
VecMulf(mat[2], -1.0f);
|
||||
Crossf(mat[1], mat[2], mat[0]);
|
||||
|
||||
/* apply rotation */
|
||||
Mat3ToQuat_is_ok(mat, q);
|
||||
QuatCopy(pa->state.rot, q);
|
||||
}
|
||||
|
||||
BoidRule *boid_new_rule(int type)
|
||||
{
|
||||
BoidRule *rule = NULL;
|
||||
if(type <= 0)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
strcpy(rule->name, boidrule_type_items[type-1].name);
|
||||
|
||||
return rule;
|
||||
}
|
||||
void boid_default_settings(BoidSettings *boids)
|
||||
{
|
||||
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->height = 1.0f;
|
||||
|
||||
boids->health = 1.0f;
|
||||
boids->accuracy = 1.0f;
|
||||
boids->aggression = 2.0f;
|
||||
boids->range = 1.0f;
|
||||
boids->strength = 0.1f;
|
||||
}
|
||||
|
||||
BoidState *boid_new_state(BoidSettings *boids)
|
||||
{
|
||||
BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
|
||||
|
||||
state->id = boids->last_state_id++;
|
||||
if(state->id)
|
||||
sprintf(state->name, "State %i", state->id);
|
||||
else
|
||||
strcpy(state->name, "State");
|
||||
|
||||
state->rule_fuzziness = 0.5;
|
||||
state->volume = 1.0f;
|
||||
state->channels |= ~0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) {
|
||||
BoidState *staten = MEM_dupallocN(state);
|
||||
|
||||
BLI_duplicatelist(&staten->rules, &state->rules);
|
||||
BLI_duplicatelist(&staten->conditions, &state->conditions);
|
||||
BLI_duplicatelist(&staten->actions, &state->actions);
|
||||
|
||||
staten->id = boids->last_state_id++;
|
||||
|
||||
return staten;
|
||||
}
|
||||
void boid_free_settings(BoidSettings *boids)
|
||||
{
|
||||
if(boids) {
|
||||
BoidState *state = boids->states.first;
|
||||
|
||||
for(; state; state=state->next) {
|
||||
BLI_freelistN(&state->rules);
|
||||
BLI_freelistN(&state->conditions);
|
||||
BLI_freelistN(&state->actions);
|
||||
}
|
||||
|
||||
BLI_freelistN(&boids->states);
|
||||
|
||||
MEM_freeN(boids);
|
||||
}
|
||||
}
|
||||
BoidSettings *boid_copy_settings(BoidSettings *boids)
|
||||
{
|
||||
BoidSettings *nboids = NULL;
|
||||
|
||||
if(boids) {
|
||||
BoidState *state;
|
||||
BoidState *nstate;
|
||||
|
||||
nboids = MEM_dupallocN(boids);
|
||||
|
||||
BLI_duplicatelist(&nboids->states, &boids->states);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return nboids;
|
||||
}
|
||||
BoidState *boid_get_current_state(BoidSettings *boids)
|
||||
{
|
||||
BoidState *state = boids->states.first;
|
||||
|
||||
for(; state; state=state->next) {
|
||||
if(state->flag & BOIDSTATE_CURRENT)
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_ID.h"
|
||||
@@ -555,6 +556,8 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
|
||||
GroupObject *go;
|
||||
|
||||
for(; psys; psys=psys->next) {
|
||||
BoidRule *rule = NULL;
|
||||
BoidState *state = NULL;
|
||||
ParticleSettings *part= psys->part;
|
||||
|
||||
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
|
||||
@@ -562,16 +565,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
|
||||
if(!psys_check_enabled(ob, psys))
|
||||
continue;
|
||||
|
||||
if(part->phystype==PART_PHYS_KEYED) {
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
if(ELEM(part->phystype,PART_PHYS_KEYED,PART_PHYS_BOIDS)) {
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->ob && BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1)) {
|
||||
node2 = dag_get_node(dag, kpt->ob);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Keyed Physics");
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys-1)) {
|
||||
node2 = dag_get_node(dag, pt->ob);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Targets");
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,33 +590,47 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
|
||||
}
|
||||
}
|
||||
|
||||
if(psys->effectors.first)
|
||||
psys_end_effectors(psys);
|
||||
psys_end_effectors(psys);
|
||||
psys_init_effectors(scene, ob, psys->part->eff_group, psys);
|
||||
|
||||
if(psys->effectors.first) {
|
||||
for(nec= psys->effectors.first; nec; nec= nec->next) {
|
||||
Object *ob1= nec->ob;
|
||||
for(nec= psys->effectors.first; nec; nec= nec->next) {
|
||||
Object *ob1= nec->ob;
|
||||
|
||||
if(nec->type & PSYS_EC_EFFECTOR) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
if(ob1->pd->forcefield==PFIELD_GUIDE)
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
|
||||
else
|
||||
dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field");
|
||||
}
|
||||
else if(nec->type & PSYS_EC_DEFLECT) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision");
|
||||
}
|
||||
else if(nec->type & PSYS_EC_PARTICLE) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field");
|
||||
}
|
||||
|
||||
if(nec->type & PSYS_EC_REACTOR) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor");
|
||||
if(nec->type & PSYS_EC_EFFECTOR) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
if(ob1->pd->forcefield==PFIELD_GUIDE)
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
|
||||
else
|
||||
dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field");
|
||||
}
|
||||
else if(nec->type & PSYS_EC_DEFLECT) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision");
|
||||
}
|
||||
else if(nec->type & PSYS_EC_PARTICLE) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field");
|
||||
}
|
||||
|
||||
if(nec->type & PSYS_EC_REACTOR) {
|
||||
node2 = dag_get_node(dag, ob1);
|
||||
dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor");
|
||||
}
|
||||
}
|
||||
|
||||
if(part->boids) {
|
||||
for(state = part->boids->states.first; state; state=state->next) {
|
||||
for(rule = state->rules.first; rule; rule=rule->next) {
|
||||
Object *ruleob = NULL;
|
||||
if(rule->type==eBoidRuleType_Avoid)
|
||||
ruleob = ((BoidRuleGoalAvoid*)rule)->ob;
|
||||
else if(rule->type==eBoidRuleType_FollowLeader)
|
||||
ruleob = ((BoidRuleFollowLeader*)rule)->ob;
|
||||
|
||||
if(ruleob) {
|
||||
node2 = dag_get_node(dag, ruleob);
|
||||
dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2070,7 +2085,6 @@ static void dag_object_time_update_flags(Object *ob)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* flag all objects that need recalc, for changes in time for example */
|
||||
void DAG_scene_update_flags(Scene *scene, unsigned int lay)
|
||||
{
|
||||
|
||||
@@ -505,6 +505,9 @@ void do_physical_effector(Scene *scene, Object *ob, float *opco, short type, flo
|
||||
VecAddf(field,field,mag_vec);
|
||||
break;
|
||||
}
|
||||
case PFIELD_BOID:
|
||||
/* Boid field is handled completely in boids code. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6113,9 +6113,14 @@ static void surfaceModifier_freeData(ModifierData *md)
|
||||
MEM_freeN(surmd->bvhtree);
|
||||
}
|
||||
|
||||
if(surmd->dm)
|
||||
surmd->dm->release(surmd->dm);
|
||||
surmd->dm->release(surmd->dm);
|
||||
|
||||
if(surmd->x)
|
||||
MEM_freeN(surmd->x);
|
||||
|
||||
if(surmd->v)
|
||||
MEM_freeN(surmd->v);
|
||||
|
||||
surmd->bvhtree = NULL;
|
||||
surmd->dm = NULL;
|
||||
}
|
||||
@@ -6128,7 +6133,7 @@ static int surfaceModifier_dependsOnTime(ModifierData *md)
|
||||
|
||||
static void surfaceModifier_deformVerts(
|
||||
ModifierData *md, Object *ob, DerivedMesh *derivedData,
|
||||
float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
|
||||
float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc)
|
||||
{
|
||||
SurfaceModifierData *surmd = (SurfaceModifierData*) md;
|
||||
unsigned int numverts = 0, i = 0;
|
||||
@@ -6148,14 +6153,47 @@ static void surfaceModifier_deformVerts(
|
||||
|
||||
if(surmd->dm)
|
||||
{
|
||||
int init = 0;
|
||||
float *vec;
|
||||
MVert *x, *v;
|
||||
|
||||
CDDM_apply_vert_coords(surmd->dm, vertexCos);
|
||||
CDDM_calc_normals(surmd->dm);
|
||||
|
||||
numverts = surmd->dm->getNumVerts ( surmd->dm );
|
||||
|
||||
/* convert to global coordinates */
|
||||
for(i = 0; i<numverts; i++)
|
||||
Mat4MulVecfl(ob->obmat, CDDM_get_vert(surmd->dm, i)->co);
|
||||
if(numverts != surmd->numverts || surmd->x == NULL || surmd->v == NULL || md->scene->r.cfra != surmd->cfra+1) {
|
||||
if(surmd->x) {
|
||||
MEM_freeN(surmd->x);
|
||||
surmd->x = NULL;
|
||||
}
|
||||
if(surmd->v) {
|
||||
MEM_freeN(surmd->v);
|
||||
surmd->v = NULL;
|
||||
}
|
||||
|
||||
surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert");
|
||||
surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert");
|
||||
|
||||
surmd->numverts = numverts;
|
||||
|
||||
init = 1;
|
||||
}
|
||||
|
||||
/* convert to global coordinates and calculate velocity */
|
||||
for(i = 0, x = surmd->x, v = surmd->v; i<numverts; i++, x++, v++) {
|
||||
vec = CDDM_get_vert(surmd->dm, i)->co;
|
||||
Mat4MulVecfl(ob->obmat, vec);
|
||||
|
||||
if(init)
|
||||
v->co[0] = v->co[1] = v->co[2] = 0.0f;
|
||||
else
|
||||
VecSubf(v->co, vec, x->co);
|
||||
|
||||
VecCopyf(x->co, vec);
|
||||
}
|
||||
|
||||
surmd->cfra = md->scene->r.cfra;
|
||||
|
||||
if(surmd->bvhtree)
|
||||
free_bvhtree_from_mesh(surmd->bvhtree);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
@@ -429,11 +430,13 @@ void unlink_object(Scene *scene, Object *ob)
|
||||
if(obt->particlesystem.first) {
|
||||
ParticleSystem *tpsys= obt->particlesystem.first;
|
||||
for(; tpsys; tpsys=tpsys->next) {
|
||||
KeyedParticleTarget *kpt = tpsys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->ob==ob) {
|
||||
BLI_remlink(&tpsys->keyed_targets, kpt);
|
||||
MEM_freeN(kpt);
|
||||
BoidState *state = NULL;
|
||||
BoidRule *rule = NULL;
|
||||
|
||||
ParticleTarget *pt = tpsys->targets.first;
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->ob==ob) {
|
||||
pt->ob = NULL;
|
||||
obt->recalc |= OB_RECALC_DATA;
|
||||
break;
|
||||
}
|
||||
@@ -458,6 +461,22 @@ void unlink_object(Scene *scene, Object *ob)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tpsys->part->boids) {
|
||||
for(state = tpsys->part->boids->states.first; state; state=state->next) {
|
||||
for(rule = state->rules.first; rule; rule=rule->next) {
|
||||
if(rule->type==eBoidRuleType_Avoid) {
|
||||
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*)rule;
|
||||
if(gabr->ob==ob)
|
||||
gabr->ob= NULL;
|
||||
}
|
||||
else if(rule->type==eBoidRuleType_FollowLeader) {
|
||||
BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*)rule;
|
||||
if(flbr->ob==ob)
|
||||
flbr->ob= NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ob->pd)
|
||||
obt->recalc |= OB_RECALC_DATA;
|
||||
@@ -1063,8 +1082,14 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys)
|
||||
psysn->soft->particles = psysn;
|
||||
}
|
||||
|
||||
if(psys->keyed_targets.first)
|
||||
BLI_duplicatelist(&psysn->keyed_targets, &psys->keyed_targets);
|
||||
if(psys->particles->boid) {
|
||||
psysn->particles->boid = MEM_dupallocN(psys->particles->boid);
|
||||
for(a=1, pa=psysn->particles+1; a<psysn->totpart; a++, pa++)
|
||||
pa->boid = (pa-1)->boid + 1;
|
||||
}
|
||||
|
||||
if(psys->targets.first)
|
||||
BLI_duplicatelist(&psysn->targets, &psys->targets);
|
||||
|
||||
psysn->pathcache= NULL;
|
||||
psysn->childcache= NULL;
|
||||
@@ -2369,10 +2394,17 @@ void object_handle_update(Scene *scene, Object *ob)
|
||||
if(ob->particlesystem.first) {
|
||||
ParticleSystem *tpsys, *psys;
|
||||
DerivedMesh *dm;
|
||||
ob->transflag &= ~OB_DUPLIPARTS;
|
||||
|
||||
psys= ob->particlesystem.first;
|
||||
while(psys) {
|
||||
if(psys_check_enabled(ob, psys)) {
|
||||
/* check use of dupli objects here */
|
||||
if(psys->part && psys->part->draw_as == PART_DRAW_REND &&
|
||||
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob)
|
||||
|| (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
|
||||
ob->transflag |= OB_DUPLIPARTS;
|
||||
|
||||
particle_system_update(scene, ob, psys);
|
||||
psys= psys->next;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
@@ -58,6 +59,7 @@
|
||||
|
||||
#include "BKE_anim.h"
|
||||
|
||||
#include "BKE_boids.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_lattice.h"
|
||||
@@ -355,10 +357,13 @@ void psys_free_settings(ParticleSettings *part)
|
||||
MEM_freeN(part->pd);
|
||||
part->pd = NULL;
|
||||
}
|
||||
|
||||
if(part->pd2) {
|
||||
MEM_freeN(part->pd2);
|
||||
part->pd2 = NULL;
|
||||
}
|
||||
|
||||
boid_free_settings(part->boids);
|
||||
}
|
||||
|
||||
void free_hair(ParticleSystem *psys, int softbody)
|
||||
@@ -439,6 +444,9 @@ void psys_free(Object *ob, ParticleSystem * psys)
|
||||
psys->free_edit(psys);
|
||||
|
||||
if(psys->particles){
|
||||
if(psys->particles->boid)
|
||||
MEM_freeN(psys->particles->boid);
|
||||
|
||||
MEM_freeN(psys->particles);
|
||||
psys->particles = 0;
|
||||
psys->totpart = 0;
|
||||
@@ -479,8 +487,10 @@ void psys_free(Object *ob, ParticleSystem * psys)
|
||||
if(psys->pointcache)
|
||||
BKE_ptcache_free(psys->pointcache);
|
||||
|
||||
if(psys->keyed_targets.first)
|
||||
BLI_freelistN(&psys->keyed_targets);
|
||||
if(psys->targets.first)
|
||||
BLI_freelistN(&psys->targets);
|
||||
|
||||
BLI_kdtree_free(psys->tree);
|
||||
|
||||
MEM_freeN(psys);
|
||||
}
|
||||
@@ -1043,21 +1053,21 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
|
||||
real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey-1].time - pind->kkey[0]->time);
|
||||
|
||||
if(psys->part->phystype==PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) {
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
|
||||
kpt=kpt->next;
|
||||
pt=pt->next;
|
||||
|
||||
while(kpt && pa->time + kpt->time < real_t)
|
||||
kpt= kpt->next;
|
||||
while(pt && pa->time + pt->time < real_t)
|
||||
pt= pt->next;
|
||||
|
||||
if(kpt) {
|
||||
kpt=kpt->prev;
|
||||
if(pt) {
|
||||
pt=pt->prev;
|
||||
|
||||
if(pa->time + kpt->time + kpt->duration > real_t)
|
||||
real_t = pa->time + kpt->time;
|
||||
if(pa->time + pt->time + pt->duration > real_t)
|
||||
real_t = pa->time + pt->time;
|
||||
}
|
||||
else
|
||||
real_t = pa->time + ((KeyedParticleTarget*)psys->keyed_targets.last)->time;
|
||||
real_t = pa->time + ((ParticleTarget*)psys->targets.last)->time;
|
||||
}
|
||||
|
||||
CLAMP(real_t, pa->time, pa->dietime);
|
||||
@@ -3028,7 +3038,12 @@ void object_add_particle_system(Scene *scene, Object *ob)
|
||||
psys->pointcache = BKE_ptcache_add();
|
||||
BLI_addtail(&ob->particlesystem, psys);
|
||||
|
||||
psys->part = psys_new_settings("PSys", NULL);
|
||||
psys->part = psys_new_settings("ParticleSettings", NULL);
|
||||
|
||||
if(BLI_countlist(&ob->particlesystem)>1)
|
||||
sprintf(psys->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem));
|
||||
else
|
||||
strcpy(psys->name, "ParticleSystem");
|
||||
|
||||
md= modifier_new(eModifierType_ParticleSystem);
|
||||
sprintf(md->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem));
|
||||
@@ -3099,14 +3114,8 @@ static void default_particle_settings(ParticleSettings *part)
|
||||
part->reactevent= PART_EVENT_DEATH;
|
||||
part->disp=100;
|
||||
part->from= PART_FROM_FACE;
|
||||
part->nbetween= 4;
|
||||
part->boidneighbours= 5;
|
||||
|
||||
part->normfac= 1.0f;
|
||||
part->max_vel = 10.0f;
|
||||
part->average_vel = 0.3f;
|
||||
part->max_tan_acc = 0.2f;
|
||||
part->max_lat_acc = 1.0f;
|
||||
|
||||
part->reactshape=1.0f;
|
||||
|
||||
@@ -3136,13 +3145,9 @@ static void default_particle_settings(ParticleSettings *part)
|
||||
|
||||
part->keyed_loops = 1;
|
||||
|
||||
part->banking=1.0;
|
||||
part->max_bank=1.0;
|
||||
for(i=0; i<10; i++)
|
||||
part->effector_weight[i]=1.0f;
|
||||
|
||||
for(i=0; i<BOID_TOT_RULES; i++){
|
||||
part->boidrule[i]=(char)i;
|
||||
part->boidfac[i]=0.5;
|
||||
}
|
||||
|
||||
#if 0 // XXX old animation system
|
||||
part->ipo = NULL;
|
||||
@@ -3176,6 +3181,8 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part)
|
||||
partn= copy_libblock(part);
|
||||
if(partn->pd) partn->pd= MEM_dupallocN(part->pd);
|
||||
if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2);
|
||||
|
||||
partn->boids = boid_copy_settings(part->boids);
|
||||
|
||||
return partn;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
@@ -49,6 +50,7 @@
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_ipo_types.h" // XXX old animation system stuff... to be removed!
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_jitter.h"
|
||||
@@ -60,6 +62,7 @@
|
||||
#include "BLI_threads.h"
|
||||
|
||||
#include "BKE_anim.h"
|
||||
#include "BKE_boids.h"
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_collision.h"
|
||||
#include "BKE_displist.h"
|
||||
@@ -172,6 +175,7 @@ void psys_reset(ParticleSystem *psys, int mode)
|
||||
static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
|
||||
{
|
||||
ParticleData *newpars = 0, *pa;
|
||||
BoidData *newboids = 0;
|
||||
int i, totpart, totsaved = 0;
|
||||
|
||||
if(new_totpart<0) {
|
||||
@@ -185,22 +189,34 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
|
||||
else
|
||||
totpart=new_totpart;
|
||||
|
||||
if(totpart)
|
||||
if(totpart) {
|
||||
newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
|
||||
|
||||
if(psys->part->phystype == PART_PHYS_BOIDS)
|
||||
newboids = MEM_callocN(totpart*sizeof(BoidData), "Boid Data");
|
||||
}
|
||||
if(psys->particles) {
|
||||
totsaved=MIN2(psys->totpart,totpart);
|
||||
/*save old pars*/
|
||||
if(totsaved)
|
||||
if(totsaved) {
|
||||
memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData));
|
||||
|
||||
if(newboids)
|
||||
memcpy(newboids, psys->particles->boid, totsaved*sizeof(BoidData));
|
||||
}
|
||||
|
||||
if(psys->particles->keys)
|
||||
MEM_freeN(psys->particles->keys);
|
||||
|
||||
for(i=0, pa=newpars; i<totsaved; i++, pa++)
|
||||
if(psys->particles->boid)
|
||||
MEM_freeN(psys->particles->boid);
|
||||
|
||||
for(i=0, pa=newpars; i<totsaved; i++, pa++) {
|
||||
if(pa->keys) {
|
||||
pa->keys= NULL;
|
||||
pa->totkey= 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=totsaved, pa=psys->particles+totsaved; i<psys->totpart; i++, pa++)
|
||||
if(pa->hair) MEM_freeN(pa->hair);
|
||||
@@ -209,6 +225,13 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
|
||||
}
|
||||
psys->particles=newpars;
|
||||
|
||||
if(newboids) {
|
||||
pa = psys->particles;
|
||||
pa->boid = newboids;
|
||||
for(i=1, pa++; i<totpart; i++,pa++)
|
||||
pa->boid = (pa-1)->boid + 1;
|
||||
}
|
||||
|
||||
if(psys->child) {
|
||||
MEM_freeN(psys->child);
|
||||
psys->child=0;
|
||||
@@ -1607,12 +1630,15 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps
|
||||
rand= BLI_frand();
|
||||
|
||||
/* while loops are to have a spherical distribution (avoid cubic distribution) */
|
||||
length=2.0f;
|
||||
while(length>1.0){
|
||||
pa->r_ve[0]=2.0f*(BLI_frand()-0.5f);
|
||||
pa->r_ve[1]=2.0f*(BLI_frand()-0.5f);
|
||||
pa->r_ve[2]=2.0f*(BLI_frand()-0.5f);
|
||||
length=VecLength(pa->r_ve);
|
||||
if(part->phystype != PART_PHYS_BOIDS) {
|
||||
/* boids store gravity in r_ve, so skip here */
|
||||
length=2.0f;
|
||||
while(length>1.0){
|
||||
pa->r_ve[0]=2.0f*(BLI_frand()-0.5f);
|
||||
pa->r_ve[1]=2.0f*(BLI_frand()-0.5f);
|
||||
pa->r_ve[2]=2.0f*(BLI_frand()-0.5f);
|
||||
length=VecLength(pa->r_ve);
|
||||
}
|
||||
}
|
||||
|
||||
length=2.0f;
|
||||
@@ -1828,122 +1854,164 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic
|
||||
QuatMul(r_rot,r_rot,rot);
|
||||
}
|
||||
}
|
||||
/* conversion done so now we apply new: */
|
||||
/* -velocity from: */
|
||||
|
||||
/* *reactions */
|
||||
if(dtime>0.0f){
|
||||
VECSUB(vel,pa->state.vel,pa->prev_state.vel);
|
||||
if(part->phystype==PART_PHYS_BOIDS) {
|
||||
float dvec[3], q[4], mat[3][3];
|
||||
|
||||
VECCOPY(pa->state.co,loc);
|
||||
|
||||
/* boids don't get any initial velocity */
|
||||
pa->state.vel[0]=pa->state.vel[1]=pa->state.vel[2]=0.0f;
|
||||
|
||||
/* boids store direction in ave */
|
||||
if(fabs(nor[2])==1.0f) {
|
||||
VecSubf(pa->state.ave, loc, ob->obmat[3]);
|
||||
Normalize(pa->state.ave);
|
||||
}
|
||||
else {
|
||||
VECCOPY(pa->state.ave, nor);
|
||||
}
|
||||
/* and gravity in r_ve */
|
||||
pa->r_ve[0] = pa->r_ve[1] = 0.0f;
|
||||
pa->r_ve[2] = -1.0f;
|
||||
if(part->acc[2]!=0.0f)
|
||||
pa->r_ve[2] = part->acc[2];
|
||||
|
||||
/* calculate rotation matrix */
|
||||
Projf(dvec, pa->r_ve, pa->state.ave);
|
||||
VecSubf(mat[0], pa->state.ave, dvec);
|
||||
Normalize(mat[0]);
|
||||
VECCOPY(mat[2], pa->r_ve);
|
||||
VecMulf(mat[2], -1.0f);
|
||||
Normalize(mat[2]);
|
||||
Crossf(mat[1], mat[2], mat[0]);
|
||||
|
||||
/* apply rotation */
|
||||
Mat3ToQuat_is_ok(mat, q);
|
||||
QuatCopy(pa->state.rot, q);
|
||||
|
||||
pa->boid->health = part->boids->health;
|
||||
pa->boid->mode = eBoidMode_InAir;
|
||||
pa->boid->state_id = ((BoidState*)part->boids->states.first)->id;
|
||||
pa->boid->acc[0]=pa->boid->acc[1]=pa->boid->acc[2]=0.0f;
|
||||
}
|
||||
else {
|
||||
/* conversion done so now we apply new: */
|
||||
/* -velocity from: */
|
||||
|
||||
/* *emitter velocity */
|
||||
if(dtime!=0.0 && part->obfac!=0.0){
|
||||
VECSUB(vel,loc,pa->state.co);
|
||||
VecMulf(vel,part->obfac/dtime);
|
||||
}
|
||||
|
||||
/* *emitter normal */
|
||||
if(part->normfac!=0.0)
|
||||
VECADDFAC(vel,vel,nor,part->normfac);
|
||||
|
||||
/* *emitter tangent */
|
||||
if(part->tanfac!=0.0)
|
||||
VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f));
|
||||
/* *reactions */
|
||||
if(dtime>0.0f){
|
||||
VECSUB(vel,pa->state.vel,pa->prev_state.vel);
|
||||
}
|
||||
|
||||
/* *texture */
|
||||
/* TODO */
|
||||
|
||||
/* *random */
|
||||
if(part->randfac!=0.0)
|
||||
VECADDFAC(vel,vel,r_vel,part->randfac);
|
||||
|
||||
/* *particle */
|
||||
if(part->partfac!=0.0)
|
||||
VECADDFAC(vel,vel,p_vel,part->partfac);
|
||||
|
||||
#if 0 // XXX old animation system
|
||||
icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL);
|
||||
if(icu){
|
||||
calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
|
||||
ptex.ivel*=icu->curval;
|
||||
}
|
||||
#endif // XXX old animation system
|
||||
|
||||
VecMulf(vel,ptex.ivel);
|
||||
|
||||
VECCOPY(pa->state.vel,vel);
|
||||
|
||||
/* -location from emitter */
|
||||
VECCOPY(pa->state.co,loc);
|
||||
|
||||
/* -rotation */
|
||||
pa->state.rot[0]=1.0;
|
||||
pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0;
|
||||
|
||||
if(part->rotmode){
|
||||
/* create vector into which rotation is aligned */
|
||||
switch(part->rotmode){
|
||||
case PART_ROT_NOR:
|
||||
VecCopyf(rot_vec, nor);
|
||||
break;
|
||||
case PART_ROT_VEL:
|
||||
VecCopyf(rot_vec, vel);
|
||||
break;
|
||||
case PART_ROT_GLOB_X:
|
||||
case PART_ROT_GLOB_Y:
|
||||
case PART_ROT_GLOB_Z:
|
||||
rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
|
||||
break;
|
||||
case PART_ROT_OB_X:
|
||||
case PART_ROT_OB_Y:
|
||||
case PART_ROT_OB_Z:
|
||||
VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
|
||||
break;
|
||||
/* *emitter velocity */
|
||||
if(dtime!=0.0 && part->obfac!=0.0){
|
||||
VECSUB(vel,loc,pa->state.co);
|
||||
VecMulf(vel,part->obfac/dtime);
|
||||
}
|
||||
|
||||
/* create rotation quat */
|
||||
VecNegf(rot_vec);
|
||||
vectoquat(rot_vec, OB_POSX, OB_POSZ, q2);
|
||||
/* *emitter normal */
|
||||
if(part->normfac!=0.0)
|
||||
VECADDFAC(vel,vel,nor,part->normfac);
|
||||
|
||||
/* *emitter tangent */
|
||||
if(psmd && part->tanfac!=0.0)
|
||||
VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f));
|
||||
|
||||
/* randomize rotation quat */
|
||||
if(part->randrotfac!=0.0f)
|
||||
QuatInterpol(rot, q2, r_rot, part->randrotfac);
|
||||
else
|
||||
QuatCopy(rot,q2);
|
||||
/* *texture */
|
||||
/* TODO */
|
||||
|
||||
/* rotation phase */
|
||||
phasefac = part->phasefac;
|
||||
if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */
|
||||
phasefac += part->randphasefac * pa->r_ave[0];
|
||||
VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase);
|
||||
/* *random */
|
||||
if(part->randfac!=0.0)
|
||||
VECADDFAC(vel,vel,r_vel,part->randfac);
|
||||
|
||||
/* combine base rotation & phase */
|
||||
QuatMul(pa->state.rot, rot, q_phase);
|
||||
}
|
||||
/* *particle */
|
||||
if(part->partfac!=0.0)
|
||||
VECADDFAC(vel,vel,p_vel,part->partfac);
|
||||
|
||||
/* -angular velocity */
|
||||
//icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL);
|
||||
//if(icu){
|
||||
// calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
|
||||
// ptex.ivel*=icu->curval;
|
||||
//}
|
||||
|
||||
pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0;
|
||||
VecMulf(vel,ptex.ivel);
|
||||
|
||||
if(part->avemode){
|
||||
switch(part->avemode){
|
||||
case PART_AVE_SPIN:
|
||||
VECCOPY(pa->state.ave,vel);
|
||||
break;
|
||||
case PART_AVE_RAND:
|
||||
VECCOPY(pa->state.ave,r_ave);
|
||||
break;
|
||||
//if(ELEM(part->phystype, PART_PHYS_GRADU_EX, PART_PHYS_GRADU_SIM))
|
||||
// VecAddf(vel,vel,part->acc);
|
||||
|
||||
VECCOPY(pa->state.vel,vel);
|
||||
|
||||
/* -location from emitter */
|
||||
VECCOPY(pa->state.co,loc);
|
||||
|
||||
/* -rotation */
|
||||
pa->state.rot[0]=1.0;
|
||||
pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0;
|
||||
|
||||
if(part->rotmode){
|
||||
/* create vector into which rotation is aligned */
|
||||
switch(part->rotmode){
|
||||
case PART_ROT_NOR:
|
||||
VecCopyf(rot_vec, nor);
|
||||
break;
|
||||
case PART_ROT_VEL:
|
||||
VecCopyf(rot_vec, vel);
|
||||
break;
|
||||
case PART_ROT_GLOB_X:
|
||||
case PART_ROT_GLOB_Y:
|
||||
case PART_ROT_GLOB_Z:
|
||||
rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
|
||||
break;
|
||||
case PART_ROT_OB_X:
|
||||
case PART_ROT_OB_Y:
|
||||
case PART_ROT_OB_Z:
|
||||
VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* create rotation quat */
|
||||
VecNegf(rot_vec);
|
||||
vectoquat(rot_vec, OB_POSX, OB_POSZ, q2);
|
||||
|
||||
/* randomize rotation quat */
|
||||
if(part->randrotfac!=0.0f)
|
||||
QuatInterpol(rot, q2, r_rot, part->randrotfac);
|
||||
else
|
||||
QuatCopy(rot,q2);
|
||||
|
||||
/* rotation phase */
|
||||
phasefac = part->phasefac;
|
||||
if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */
|
||||
phasefac += part->randphasefac * pa->r_ave[0];
|
||||
VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase);
|
||||
|
||||
/* combine base rotation & phase */
|
||||
QuatMul(pa->state.rot, rot, q_phase);
|
||||
}
|
||||
Normalize(pa->state.ave);
|
||||
VecMulf(pa->state.ave,part->avefac);
|
||||
|
||||
#if 0 // XXX old animation system
|
||||
icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE);
|
||||
if(icu){
|
||||
calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
|
||||
VecMulf(pa->state.ave,icu->curval);
|
||||
/* -angular velocity */
|
||||
|
||||
pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0;
|
||||
|
||||
if(part->avemode){
|
||||
switch(part->avemode){
|
||||
case PART_AVE_SPIN:
|
||||
VECCOPY(pa->state.ave,vel);
|
||||
break;
|
||||
case PART_AVE_RAND:
|
||||
VECCOPY(pa->state.ave,r_ave);
|
||||
break;
|
||||
}
|
||||
Normalize(pa->state.ave);
|
||||
VecMulf(pa->state.ave,part->avefac);
|
||||
|
||||
//icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE);
|
||||
//if(icu){
|
||||
// calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta)));
|
||||
// VecMulf(pa->state.ave,icu->curval);
|
||||
//}
|
||||
}
|
||||
#endif // XXX old animation system
|
||||
}
|
||||
|
||||
pa->dietime = pa->time + pa->lifetime;
|
||||
@@ -1971,48 +2039,46 @@ static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys,
|
||||
MEM_freeN(vg_vel);
|
||||
}
|
||||
/************************************************/
|
||||
/* Particle targets */
|
||||
/************************************************/
|
||||
ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
|
||||
{
|
||||
ParticleSystem *psys = NULL;
|
||||
|
||||
if(pt->ob == NULL || pt->ob == ob)
|
||||
psys = BLI_findlink(&ob->particlesystem, pt->psys-1);
|
||||
else
|
||||
psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
|
||||
|
||||
if(psys)
|
||||
pt->flag |= PTARGET_VALID;
|
||||
else
|
||||
pt->flag &= ~PTARGET_VALID;
|
||||
|
||||
return psys;
|
||||
}
|
||||
/************************************************/
|
||||
/* Keyed particles */
|
||||
/************************************************/
|
||||
/* Counts valid keyed targets */
|
||||
void psys_count_keyed_targets(Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
ParticleSystem *kpsys;
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
int psys_num = BLI_findindex(&ob->particlesystem, psys);
|
||||
int keys_valid = 1;
|
||||
psys->totkeyed = 0;
|
||||
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
kpsys = NULL;
|
||||
if(kpt->ob==ob || kpt->ob==NULL) {
|
||||
if(kpt->psys >= psys_num)
|
||||
kpsys = BLI_findlink(&ob->particlesystem, kpt->psys-1);
|
||||
for(; pt; pt=pt->next) {
|
||||
kpsys = psys_get_target_system(ob, pt);
|
||||
|
||||
if(kpsys && kpsys->totpart) {
|
||||
kpt->flag |= KEYED_TARGET_VALID;
|
||||
psys->totkeyed += keys_valid;
|
||||
if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f)
|
||||
psys->totkeyed += 1;
|
||||
}
|
||||
else {
|
||||
kpt->flag &= ~KEYED_TARGET_VALID;
|
||||
keys_valid = 0;
|
||||
}
|
||||
if(kpsys && kpsys->totpart) {
|
||||
psys->totkeyed += keys_valid;
|
||||
if(psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
|
||||
psys->totkeyed += 1;
|
||||
}
|
||||
else {
|
||||
if(kpt->ob)
|
||||
kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1);
|
||||
|
||||
if(kpsys && kpsys->totpart) {
|
||||
kpt->flag |= KEYED_TARGET_VALID;
|
||||
psys->totkeyed += keys_valid;
|
||||
if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f)
|
||||
psys->totkeyed += 1;
|
||||
}
|
||||
else {
|
||||
kpt->flag &= ~KEYED_TARGET_VALID;
|
||||
keys_valid = 0;
|
||||
}
|
||||
keys_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2023,10 +2089,9 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
Object *kob = ob;
|
||||
ParticleSystem *kpsys = psys;
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
ParticleData *pa;
|
||||
int totpart = psys->totpart, i, k, totkeys = psys->totkeyed;
|
||||
float prevtime, nexttime, keyedtime;
|
||||
|
||||
/* no proper targets so let's clear and bail out */
|
||||
if(psys->totkeyed==0) {
|
||||
@@ -2050,23 +2115,23 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
|
||||
psys->flag &= ~PSYS_KEYED;
|
||||
|
||||
|
||||
kpt = psys->keyed_targets.first;
|
||||
pt = psys->targets.first;
|
||||
for(k=0; k<totkeys; k++) {
|
||||
if(kpt->ob)
|
||||
kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys - 1);
|
||||
if(pt->ob)
|
||||
kpsys = BLI_findlink(&pt->ob->particlesystem, pt->psys - 1);
|
||||
else
|
||||
kpsys = BLI_findlink(&ob->particlesystem, kpt->psys - 1);
|
||||
kpsys = BLI_findlink(&ob->particlesystem, pt->psys - 1);
|
||||
|
||||
for(i=0,pa=psys->particles; i<totpart; i++, pa++) {
|
||||
(pa->keys + k)->time = -1.0; /* use current time */
|
||||
|
||||
psys_get_particle_state(scene, kpt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
|
||||
psys_get_particle_state(scene, pt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
|
||||
|
||||
if(psys->flag & PSYS_KEYED_TIMING){
|
||||
(pa->keys+k)->time = pa->time + kpt->time;
|
||||
if(kpt->duration != 0.0f && k+1 < totkeys) {
|
||||
(pa->keys+k)->time = pa->time + pt->time;
|
||||
if(pt->duration != 0.0f && k+1 < totkeys) {
|
||||
copy_particle_key(pa->keys+k+1, pa->keys+k, 1);
|
||||
(pa->keys+k+1)->time = pa->time + kpt->time + kpt->duration;
|
||||
(pa->keys+k+1)->time = pa->time + pt->time + pt->duration;
|
||||
}
|
||||
}
|
||||
else if(totkeys > 1)
|
||||
@@ -2075,10 +2140,10 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
|
||||
pa->keys->time = pa->time;
|
||||
}
|
||||
|
||||
if(psys->flag & PSYS_KEYED_TIMING && kpt->duration!=0.0f)
|
||||
if(psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f)
|
||||
k++;
|
||||
|
||||
kpt = (kpt->next && kpt->next->flag & KEYED_TARGET_VALID) ? kpt = kpt->next : psys->keyed_targets.first;
|
||||
pt = (pt->next && pt->next->flag & PTARGET_VALID) ? pt = pt->next : psys->targets.first;
|
||||
}
|
||||
|
||||
psys->flag |= PSYS_KEYED;
|
||||
@@ -2297,6 +2362,7 @@ static void particle_cache_interpolate(int index, void *psys_ptr, float frs_sec,
|
||||
VecMulf(keys[2].vel, dfra / frs_sec);
|
||||
|
||||
psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1);
|
||||
QuatInterpol(pa->state.rot, keys[1].rot,keys[2].rot, (cfra - cfra1) / dfra);
|
||||
|
||||
VecMulf(pa->state.vel, frs_sec / dfra);
|
||||
|
||||
@@ -2340,6 +2406,30 @@ static int get_particles_from_cache(Scene *scene, Object *ob, ParticleSystem *ps
|
||||
/************************************************/
|
||||
/* Effectors */
|
||||
/************************************************/
|
||||
static void update_particle_tree(ParticleSystem *psys)
|
||||
{
|
||||
if(psys) {
|
||||
ParticleData *pa = psys->particles;
|
||||
int p, totpart = psys->totpart;
|
||||
|
||||
if(!psys->tree || psys->tree_frame != psys->cfra) {
|
||||
|
||||
BLI_kdtree_free(psys->tree);
|
||||
|
||||
psys->tree = BLI_kdtree_new(totpart);
|
||||
|
||||
for(p=0, pa=psys->particles; p<totpart; p++,pa++){
|
||||
if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive != PARS_ALIVE)
|
||||
continue;
|
||||
|
||||
BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL);
|
||||
}
|
||||
BLI_kdtree_balance(psys->tree);
|
||||
|
||||
psys->tree_frame = psys->cfra;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field)
|
||||
{
|
||||
TexResult result[4];
|
||||
@@ -2541,31 +2631,29 @@ void psys_end_effectors(ParticleSystem *psys)
|
||||
/* NOTE:
|
||||
ec->ob is not valid in here anymore! - dg
|
||||
*/
|
||||
ListBase *lb=&psys->effectors;
|
||||
if(lb->first) {
|
||||
ParticleEffectorCache *ec;
|
||||
for(ec= lb->first; ec; ec= ec->next){
|
||||
if(ec->distances)
|
||||
MEM_freeN(ec->distances);
|
||||
ParticleEffectorCache *ec = psys->effectors.first;
|
||||
|
||||
if(ec->locations)
|
||||
MEM_freeN(ec->locations);
|
||||
for(; ec; ec= ec->next){
|
||||
if(ec->distances)
|
||||
MEM_freeN(ec->distances);
|
||||
|
||||
if(ec->face_minmax)
|
||||
MEM_freeN(ec->face_minmax);
|
||||
if(ec->locations)
|
||||
MEM_freeN(ec->locations);
|
||||
|
||||
if(ec->vert_cos)
|
||||
MEM_freeN(ec->vert_cos);
|
||||
if(ec->face_minmax)
|
||||
MEM_freeN(ec->face_minmax);
|
||||
|
||||
if(ec->tree)
|
||||
BLI_kdtree_free(ec->tree);
|
||||
|
||||
if(ec->rng)
|
||||
rng_free(ec->rng);
|
||||
}
|
||||
if(ec->vert_cos)
|
||||
MEM_freeN(ec->vert_cos);
|
||||
|
||||
BLI_freelistN(lb);
|
||||
if(ec->tree)
|
||||
BLI_kdtree_free(ec->tree);
|
||||
|
||||
if(ec->rng)
|
||||
rng_free(ec->rng);
|
||||
}
|
||||
|
||||
BLI_freelistN(&psys->effectors);
|
||||
}
|
||||
|
||||
static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra)
|
||||
@@ -2648,7 +2736,84 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa
|
||||
}
|
||||
}
|
||||
|
||||
int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index)
|
||||
{
|
||||
SurfaceModifierData *surmd = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if(sur)
|
||||
surmd = sur;
|
||||
else if(pd && pd->flag&PFIELD_SURFACE)
|
||||
{
|
||||
surmd = (SurfaceModifierData *)modifiers_findByType ( ob, eModifierType_Surface );
|
||||
}
|
||||
|
||||
if(surmd) {
|
||||
/* closest point in the object surface is an effector */
|
||||
BVHTreeNearest nearest;
|
||||
|
||||
nearest.index = -1;
|
||||
nearest.dist = FLT_MAX;
|
||||
|
||||
BLI_bvhtree_find_nearest(surmd->bvhtree->tree, pco, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
|
||||
|
||||
if(nearest.index != -1) {
|
||||
VECCOPY(co, nearest.co);
|
||||
|
||||
if(nor) {
|
||||
VECCOPY(nor, nearest.no);
|
||||
}
|
||||
|
||||
if(vel) {
|
||||
MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
|
||||
|
||||
VECCOPY(vel, surmd->v[mface->v1].co);
|
||||
VecAddf(vel, vel, surmd->v[mface->v2].co);
|
||||
VecAddf(vel, vel, surmd->v[mface->v3].co);
|
||||
if(mface->v4)
|
||||
VecAddf(vel, vel, surmd->v[mface->v4].co);
|
||||
|
||||
VecMulf(vel, mface->v4 ? 0.25f : 0.333f);
|
||||
}
|
||||
|
||||
if(index)
|
||||
*index = nearest.index;
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
else {
|
||||
co[0] = co[1] = co[2] = 0.0f;
|
||||
|
||||
if(nor)
|
||||
nor[0] = nor[1] = nor[2] = 0.0f;
|
||||
|
||||
if(vel)
|
||||
vel[0] = vel[1] = vel[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* use center of object for distance calculus */
|
||||
VECCOPY(co, ob->obmat[3]);
|
||||
|
||||
if(nor) {
|
||||
VECCOPY(nor, ob->obmat[2]);
|
||||
}
|
||||
|
||||
if(vel) {
|
||||
Object obcopy = *ob;
|
||||
|
||||
VECCOPY(vel, ob->obmat[3]);
|
||||
|
||||
where_is_object_time(scene, ob, scene->r.cfra - 1.0);
|
||||
|
||||
VecSubf(vel, vel, ob->obmat[3]);
|
||||
|
||||
*ob = obcopy;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* calculate forces that all effectors apply to a particle*/
|
||||
void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra)
|
||||
{
|
||||
@@ -2658,12 +2823,11 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
|
||||
ParticleData *epa;
|
||||
ParticleKey estate;
|
||||
PartDeflect *pd;
|
||||
SurfaceModifierData *surmd = NULL;
|
||||
ListBase *lb=&psys->effectors;
|
||||
ParticleEffectorCache *ec;
|
||||
float distance, vec_to_part[3];
|
||||
float falloff, charge = 0.0f;
|
||||
int p;
|
||||
float distance, vec_to_part[3], pco[3], co[3];
|
||||
float falloff, charge = 0.0f, strength;
|
||||
int p, face_index=-1;
|
||||
|
||||
/* check all effector objects for interaction */
|
||||
if(lb->first){
|
||||
@@ -2687,45 +2851,33 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
|
||||
where_is_object_time(scene, eob,cfra);
|
||||
|
||||
if(pd && pd->flag&PFIELD_SURFACE) {
|
||||
surmd = (SurfaceModifierData *)modifiers_findByType ( eob, eModifierType_Surface );
|
||||
}
|
||||
if(surmd) {
|
||||
/* closest point in the object surface is an effector */
|
||||
BVHTreeNearest nearest;
|
||||
float velocity[3];
|
||||
|
||||
nearest.index = -1;
|
||||
nearest.dist = FLT_MAX;
|
||||
|
||||
/* using velocity corrected location allows for easier sliding over effector surface */
|
||||
VecCopyf(velocity, state->vel);
|
||||
VecMulf(velocity, psys_get_timestep(psys->part));
|
||||
VecAddf(vec_to_part, state->co, velocity);
|
||||
|
||||
BLI_bvhtree_find_nearest(surmd->bvhtree->tree, vec_to_part, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
|
||||
|
||||
if(nearest.index != -1) {
|
||||
VecSubf(vec_to_part, state->co, nearest.co);
|
||||
}
|
||||
else
|
||||
vec_to_part[0] = vec_to_part[1] = vec_to_part[2] = 0.0f;
|
||||
VecAddf(pco, state->co, velocity);
|
||||
}
|
||||
else
|
||||
/* use center of object for distance calculus */
|
||||
VecSubf(vec_to_part, state->co, eob->obmat[3]);
|
||||
VECCOPY(pco, state->co);
|
||||
|
||||
effector_find_co(scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index);
|
||||
|
||||
VecSubf(vec_to_part, state->co, co);
|
||||
|
||||
distance = VecLength(vec_to_part);
|
||||
|
||||
falloff=effector_falloff(pd,eob->obmat[2],vec_to_part);
|
||||
|
||||
strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
|
||||
|
||||
if(falloff<=0.0f)
|
||||
; /* don't do anything */
|
||||
else if(pd->forcefield==PFIELD_TEXTURE) {
|
||||
do_texture_effector(pd->tex, pd->tex_mode, pd->flag&PFIELD_TEX_2D, pd->tex_nabla,
|
||||
pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat,
|
||||
pd->f_strength, falloff, force_field);
|
||||
strength, falloff, force_field);
|
||||
} else {
|
||||
do_physical_effector(scene, eob, state->co, pd->forcefield,pd->f_strength,distance,
|
||||
do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance,
|
||||
falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part,
|
||||
state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size);
|
||||
}
|
||||
@@ -2766,10 +2918,12 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene,
|
||||
|
||||
falloff=effector_falloff(pd,estate.vel,vec_to_part);
|
||||
|
||||
strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
|
||||
|
||||
if(falloff<=0.0f)
|
||||
; /* don't do anything */
|
||||
else
|
||||
do_physical_effector(scene, eob, state->co, pd->forcefield,pd->f_strength,distance,
|
||||
do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance,
|
||||
falloff,epart->size,pd->f_damp,estate.vel,vec_to_part,
|
||||
state->vel,force_field,0, ec->rng, pd->f_noise,charge,pa->size);
|
||||
}
|
||||
@@ -3121,20 +3275,7 @@ int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos
|
||||
return intersect;
|
||||
}
|
||||
|
||||
/* container for moving data between deflet_particle and particle_intersect_face */
|
||||
typedef struct ParticleCollision
|
||||
{
|
||||
struct Object *ob, *ob_t; // collided and current objects
|
||||
struct CollisionModifierData *md; // collision modifier for ob_t;
|
||||
float nor[3]; // normal at collision point
|
||||
float vel[3]; // velocity of collision point
|
||||
float co1[3], co2[3]; // ray start and end points
|
||||
float ray_len; // original length of co2-co1, needed for collision time evaluation
|
||||
float t; // time of previous collision, needed for substracting face velocity
|
||||
}
|
||||
ParticleCollision;
|
||||
|
||||
static void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
||||
void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
||||
{
|
||||
ParticleCollision *col = (ParticleCollision *) userdata;
|
||||
MFace *face = col->md->mfaces + index;
|
||||
@@ -3209,20 +3350,27 @@ static void particle_intersect_face(void *userdata, int index, const BVHTreeRay
|
||||
/* 1. check for all possible deflectors for closest intersection on particle path */
|
||||
/* 2. if deflection was found kill the particle or calculate new coordinates */
|
||||
static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float timestep, float dfra, float cfra){
|
||||
Object *ob = NULL;
|
||||
Object *ob = NULL, *skip_ob = NULL;
|
||||
ListBase *lb=&psys->effectors;
|
||||
ParticleEffectorCache *ec;
|
||||
ParticleKey reaction_state;
|
||||
ParticleCollision col;
|
||||
BVHTreeRayHit hit;
|
||||
float ray_dir[3], zerovec[3]={0.0,0.0,0.0};
|
||||
float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f);
|
||||
float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f), boid_z;
|
||||
int deflections=0, max_deflections=10;
|
||||
|
||||
VECCOPY(col.co1, pa->prev_state.co);
|
||||
VECCOPY(col.co2, pa->state.co);
|
||||
col.t = 0.0f;
|
||||
|
||||
/* override for boids */
|
||||
if(part->phystype == PART_PHYS_BOIDS) {
|
||||
radius = pa->size;
|
||||
boid_z = pa->state.co[2];
|
||||
skip_ob = pa->stick_ob;
|
||||
}
|
||||
|
||||
/* 10 iterations to catch multiple deflections */
|
||||
if(lb->first) while(deflections < max_deflections){
|
||||
/* 1. */
|
||||
@@ -3240,13 +3388,17 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
|
||||
if(ec->type & PSYS_EC_DEFLECT){
|
||||
ob= ec->ob;
|
||||
|
||||
if(part->type!=PART_HAIR)
|
||||
where_is_object_time(scene, ob,cfra);
|
||||
/* for boids: don't check with current ground object */
|
||||
if(ob==skip_ob)
|
||||
continue;
|
||||
|
||||
/* particles should not collide with emitter at birth */
|
||||
if(ob==pob && pa->time < cfra && pa->time >= psys->cfra)
|
||||
continue;
|
||||
|
||||
if(part->type!=PART_HAIR)
|
||||
where_is_object_time(scene,ob,cfra);
|
||||
|
||||
col.md = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) );
|
||||
col.ob_t = ob;
|
||||
|
||||
@@ -3378,6 +3530,13 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
|
||||
/* make sure we don't hit the current face again */
|
||||
VECADDFAC(co, co, col.nor, (through ? -0.0001f : 0.0001f));
|
||||
|
||||
if(part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
|
||||
if(pa->boid->mode == eBoidMode_OnLand || co[2] <= boid_z) {
|
||||
co[2] = boid_z;
|
||||
vel[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* store state for reactors */
|
||||
VECCOPY(reaction_state.co, co);
|
||||
VecLerpf(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt);
|
||||
@@ -3411,564 +3570,6 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa
|
||||
}
|
||||
}
|
||||
/************************************************/
|
||||
/* Boid physics */
|
||||
/************************************************/
|
||||
static int boid_see_mesh(ListBase *lb, Scene *scene, Object *pob, ParticleSystem *psys, float *vec1, float *vec2, float *loc, float *nor, float cfra)
|
||||
{
|
||||
Object *ob, *min_ob;
|
||||
DerivedMesh *dm;
|
||||
MFace *mface;
|
||||
MVert *mvert;
|
||||
ParticleEffectorCache *ec;
|
||||
ParticleSystemModifierData *psmd=psys_get_modifier(pob,psys);
|
||||
float imat[4][4];
|
||||
float co1[3], co2[3], min_w[4], min_d;
|
||||
int min_face=0, intersect=0;
|
||||
|
||||
if(lb->first){
|
||||
intersect=0;
|
||||
min_d=20000.0;
|
||||
min_ob=NULL;
|
||||
for(ec=lb->first; ec; ec=ec->next){
|
||||
if(ec->type & PSYS_EC_DEFLECT){
|
||||
ob= ec->ob;
|
||||
|
||||
if(psys->part->type!=PART_HAIR)
|
||||
where_is_object_time(scene, ob,cfra);
|
||||
|
||||
if(ob==pob)
|
||||
dm=psmd->dm;
|
||||
else
|
||||
dm=0;
|
||||
|
||||
VECCOPY(co1,vec1);
|
||||
VECCOPY(co2,vec2);
|
||||
|
||||
if(ec->vert_cos==0){
|
||||
/* convert particle coordinates to object coordinates */
|
||||
Mat4Invert(imat,ob->obmat);
|
||||
|
||||
Mat4MulVecfl(imat,co1);
|
||||
Mat4MulVecfl(imat,co2);
|
||||
}
|
||||
|
||||
if(psys_intersect_dm(scene,ob,dm,ec->vert_cos,co1,co2,&min_d,&min_face,min_w,ec->face_minmax,0,0,0))
|
||||
min_ob=ob;
|
||||
}
|
||||
}
|
||||
if(min_ob){
|
||||
ob=min_ob;
|
||||
|
||||
if(ob==pob){
|
||||
dm=psmd->dm;
|
||||
}
|
||||
else{
|
||||
psys_disable_all(ob);
|
||||
|
||||
dm=mesh_get_derived_final(scene, ob, 0);
|
||||
if(dm==0)
|
||||
dm=mesh_get_derived_deform(scene, ob, 0);
|
||||
|
||||
psys_enable_all(ob);
|
||||
}
|
||||
|
||||
mface=dm->getFaceDataArray(dm,CD_MFACE);
|
||||
mface+=min_face;
|
||||
mvert=dm->getVertDataArray(dm,CD_MVERT);
|
||||
|
||||
/* get deflection point & normal */
|
||||
psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0);
|
||||
|
||||
VECADD(nor,nor,loc);
|
||||
Mat4MulVecfl(ob->obmat,loc);
|
||||
Mat4MulVecfl(ob->obmat,nor);
|
||||
VECSUB(nor,nor,loc);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* vector calculus functions in 2d vs. 3d */
|
||||
static void set_boid_vec_func(BoidVecFunc *bvf, int is_2d)
|
||||
{
|
||||
if(is_2d){
|
||||
bvf->Addf = Vec2Addf;
|
||||
bvf->Subf = Vec2Subf;
|
||||
bvf->Mulf = Vec2Mulf;
|
||||
bvf->Length = Vec2Length;
|
||||
bvf->Normalize = Normalize2;
|
||||
bvf->Inpf = Inp2f;
|
||||
bvf->Copyf = Vec2Copyf;
|
||||
}
|
||||
else{
|
||||
bvf->Addf = VecAddf;
|
||||
bvf->Subf = VecSubf;
|
||||
bvf->Mulf = VecMulf;
|
||||
bvf->Length = VecLength;
|
||||
bvf->Normalize = Normalize;
|
||||
bvf->Inpf = Inpf;
|
||||
bvf->Copyf = VecCopyf;
|
||||
}
|
||||
}
|
||||
/* boids have limited processing capability so once there's too much information (acceleration) no more is processed */
|
||||
static int add_boid_acc(BoidVecFunc *bvf, float lat_max, float tan_max, float *lat_accu, float *tan_accu, float *acc, float *dvec, float *vel)
|
||||
{
|
||||
static float tangent[3];
|
||||
static float tan_length;
|
||||
|
||||
if(vel){
|
||||
bvf->Copyf(tangent,vel);
|
||||
tan_length=bvf->Normalize(tangent);
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
float cur_tan, cur_lat;
|
||||
float tan_acc[3], lat_acc[3];
|
||||
int ret=0;
|
||||
|
||||
bvf->Copyf(tan_acc,tangent);
|
||||
|
||||
if(tan_length>0.0){
|
||||
bvf->Mulf(tan_acc,Inpf(tangent,dvec));
|
||||
|
||||
bvf->Subf(lat_acc,dvec,tan_acc);
|
||||
}
|
||||
else{
|
||||
bvf->Copyf(tan_acc,dvec);
|
||||
lat_acc[0]=lat_acc[1]=lat_acc[2]=0.0f;
|
||||
*lat_accu=lat_max;
|
||||
}
|
||||
|
||||
cur_tan=bvf->Length(tan_acc);
|
||||
cur_lat=bvf->Length(lat_acc);
|
||||
|
||||
/* add tangential acceleration */
|
||||
if(*lat_accu+cur_lat<=lat_max){
|
||||
bvf->Addf(acc,acc,lat_acc);
|
||||
*lat_accu+=cur_lat;
|
||||
ret=1;
|
||||
}
|
||||
else{
|
||||
bvf->Mulf(lat_acc,(lat_max-*lat_accu)/cur_lat);
|
||||
bvf->Addf(acc,acc,lat_acc);
|
||||
*lat_accu=lat_max;
|
||||
}
|
||||
|
||||
/* add lateral acceleration */
|
||||
if(*tan_accu+cur_tan<=tan_max){
|
||||
bvf->Addf(acc,acc,tan_acc);
|
||||
*tan_accu+=cur_tan;
|
||||
ret=1;
|
||||
}
|
||||
else{
|
||||
bvf->Mulf(tan_acc,(tan_max-*tan_accu)/cur_tan);
|
||||
bvf->Addf(acc,acc,tan_acc);
|
||||
*tan_accu=tan_max;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* determines the acceleration that the boid tries to acchieve */
|
||||
static void boid_brain(BoidVecFunc *bvf, ParticleData *pa, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, KDTree *tree, float timestep, float cfra, float *acc)
|
||||
{
|
||||
ParticleData *pars=psys->particles;
|
||||
KDTreeNearest ptn[MAX_BOIDNEIGHBOURS+1];
|
||||
ParticleEffectorCache *ec=0;
|
||||
float dvec[3]={0.0,0.0,0.0}, ob_co[3], ob_nor[3];
|
||||
float avoid[3]={0.0,0.0,0.0}, velocity[3]={0.0,0.0,0.0}, center[3]={0.0,0.0,0.0};
|
||||
float cubedist[MAX_BOIDNEIGHBOURS+1];
|
||||
int i, n, neighbours=0, near, not_finished=1;
|
||||
|
||||
float cur_vel;
|
||||
float lat_accu=0.0f, max_lat_acc=part->max_vel*part->max_lat_acc;
|
||||
float tan_accu=0.0f, max_tan_acc=part->max_vel*part->max_tan_acc;
|
||||
float avg_vel=part->average_vel*part->max_vel;
|
||||
|
||||
acc[0]=acc[1]=acc[2]=0.0f;
|
||||
/* the +1 neighbour is because boid itself is in the tree */
|
||||
neighbours=BLI_kdtree_find_n_nearest(tree,part->boidneighbours+1,pa->state.co,NULL,ptn);
|
||||
|
||||
for(n=1; n<neighbours; n++){
|
||||
cubedist[n]=(float)pow((double)(ptn[n].dist/pa->size),3.0);
|
||||
cubedist[n]=1.0f/MAX2(cubedist[n],1.0f);
|
||||
}
|
||||
|
||||
/* initialize tangent */
|
||||
add_boid_acc(bvf,0.0,0.0,0,0,0,0,pa->state.vel);
|
||||
|
||||
for(i=0; i<BOID_TOT_RULES && not_finished; i++){
|
||||
switch(part->boidrule[i]){
|
||||
case BOID_COLLIDE:
|
||||
/* collision avoidance */
|
||||
bvf->Copyf(dvec,pa->prev_state.vel);
|
||||
bvf->Mulf(dvec,5.0f);
|
||||
bvf->Addf(dvec,dvec,pa->prev_state.co);
|
||||
if(boid_see_mesh(&psys->effectors,scene, ob,psys,pa->prev_state.co,dvec,ob_co,ob_nor,cfra)){
|
||||
float probelen = bvf->Length(dvec);
|
||||
float proj;
|
||||
float oblen;
|
||||
|
||||
Normalize(ob_nor);
|
||||
proj = bvf->Inpf(ob_nor,pa->prev_state.vel);
|
||||
|
||||
bvf->Subf(dvec,pa->prev_state.co,ob_co);
|
||||
oblen=bvf->Length(dvec);
|
||||
|
||||
bvf->Copyf(dvec,ob_nor);
|
||||
bvf->Mulf(dvec,-proj);
|
||||
bvf->Mulf(dvec,((probelen/oblen)-1.0f)*100.0f*part->boidfac[BOID_COLLIDE]);
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
break;
|
||||
case BOID_AVOID:
|
||||
/* predator avoidance */
|
||||
if(psys->effectors.first){
|
||||
for(ec=psys->effectors.first; ec; ec=ec->next){
|
||||
if(ec->type & PSYS_EC_EFFECTOR){
|
||||
Object *eob = ec->ob;
|
||||
PartDeflect *pd = eob->pd;
|
||||
|
||||
if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0){
|
||||
float distance;
|
||||
VECSUB(dvec,eob->obmat[3],pa->prev_state.co);
|
||||
|
||||
distance=Normalize(dvec);
|
||||
|
||||
if(part->flag & PART_DIE_ON_COL && distance < pd->mindist){
|
||||
pa->alive = PARS_DYING;
|
||||
pa->dietime=cfra;
|
||||
i=BOID_TOT_RULES;
|
||||
break;
|
||||
}
|
||||
|
||||
if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
|
||||
;
|
||||
else{
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ec->type & PSYS_EC_PARTICLE){
|
||||
Object *eob = ec->ob;
|
||||
ParticleSystem *epsys;
|
||||
ParticleSettings *epart;
|
||||
ParticleKey state;
|
||||
PartDeflect *pd;
|
||||
KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS];
|
||||
int totepart, p, count;
|
||||
float distance;
|
||||
epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr);
|
||||
epart= epsys->part;
|
||||
pd= epart->pd;
|
||||
totepart= epsys->totpart;
|
||||
|
||||
if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0 && ec->tree){
|
||||
count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2);
|
||||
for(p=0; p<count; p++){
|
||||
state.time=-1.0;
|
||||
if(psys_get_particle_state(scene, eob,epsys,ptn2[p].index,&state,0)){
|
||||
VECSUB(dvec, state.co, pa->prev_state.co);
|
||||
|
||||
distance = Normalize(dvec);
|
||||
|
||||
if(part->flag & PART_DIE_ON_COL && distance < (epsys->particles+ptn2[p].index)->size){
|
||||
pa->alive = PARS_DYING;
|
||||
pa->dietime=cfra;
|
||||
i=BOID_TOT_RULES;
|
||||
break;
|
||||
}
|
||||
|
||||
if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
|
||||
;
|
||||
else{
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BOID_CROWD:
|
||||
/* crowd avoidance */
|
||||
near=0;
|
||||
for(n=1; n<neighbours; n++){
|
||||
if(ptn[n].dist<2.0f*pa->size){
|
||||
if(ptn[n].dist!=0.0f) {
|
||||
bvf->Subf(dvec,pa->prev_state.co,pars[ptn[n].index].state.co);
|
||||
bvf->Mulf(dvec,(2.0f*pa->size-ptn[n].dist)/ptn[n].dist);
|
||||
bvf->Addf(avoid,avoid,dvec);
|
||||
near++;
|
||||
}
|
||||
}
|
||||
/* ptn[] is distance ordered so no need to check others */
|
||||
else break;
|
||||
}
|
||||
if(near){
|
||||
bvf->Mulf(avoid,part->boidfac[BOID_CROWD]*2.0f/timestep);
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,avoid,0);
|
||||
}
|
||||
break;
|
||||
case BOID_CENTER:
|
||||
/* flock centering */
|
||||
if(neighbours>1){
|
||||
for(n=1; n<neighbours; n++){
|
||||
bvf->Addf(center,center,pars[ptn[n].index].state.co);
|
||||
}
|
||||
bvf->Mulf(center,1.0f/((float)neighbours-1.0f));
|
||||
|
||||
bvf->Subf(dvec,center,pa->prev_state.co);
|
||||
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_CENTER]*2.0f);
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
break;
|
||||
case BOID_AV_VEL:
|
||||
/* average velocity */
|
||||
cur_vel=bvf->Length(pa->prev_state.vel);
|
||||
if(cur_vel>0.0){
|
||||
bvf->Copyf(dvec,pa->prev_state.vel);
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_AV_VEL]*(avg_vel-cur_vel)/cur_vel);
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
break;
|
||||
case BOID_VEL_MATCH:
|
||||
/* velocity matching */
|
||||
if(neighbours>1){
|
||||
for(n=1; n<neighbours; n++){
|
||||
bvf->Copyf(dvec,pars[ptn[n].index].state.vel);
|
||||
bvf->Mulf(dvec,cubedist[n]);
|
||||
bvf->Addf(velocity,velocity,dvec);
|
||||
}
|
||||
bvf->Mulf(velocity,1.0f/((float)neighbours-1.0f));
|
||||
|
||||
bvf->Subf(dvec,velocity,pa->prev_state.vel);
|
||||
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_VEL_MATCH]);
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
break;
|
||||
case BOID_GOAL:
|
||||
/* goal seeking */
|
||||
if(psys->effectors.first){
|
||||
for(ec=psys->effectors.first; ec; ec=ec->next){
|
||||
if(ec->type & PSYS_EC_EFFECTOR){
|
||||
Object *eob = ec->ob;
|
||||
PartDeflect *pd = eob->pd;
|
||||
float temp[4];
|
||||
|
||||
if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0){
|
||||
float distance;
|
||||
VECSUB(dvec,eob->obmat[3],pa->prev_state.co);
|
||||
|
||||
distance=Normalize(dvec);
|
||||
|
||||
if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
|
||||
;
|
||||
else{
|
||||
VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power));
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
}
|
||||
else if(pd->forcefield==PFIELD_GUIDE){
|
||||
float distance;
|
||||
|
||||
where_on_path(eob, (cfra-pa->time)/pa->lifetime, temp, dvec);
|
||||
|
||||
VECSUB(dvec,temp,pa->prev_state.co);
|
||||
|
||||
distance=Normalize(dvec);
|
||||
|
||||
if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
|
||||
;
|
||||
else{
|
||||
VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power));
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ec->type & PSYS_EC_PARTICLE){
|
||||
Object *eob = ec->ob;
|
||||
ParticleSystem *epsys;
|
||||
ParticleSettings *epart;
|
||||
ParticleKey state;
|
||||
PartDeflect *pd;
|
||||
KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS];
|
||||
int totepart, p, count;
|
||||
float distance;
|
||||
epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr);
|
||||
epart= epsys->part;
|
||||
pd= epart->pd;
|
||||
totepart= epsys->totpart;
|
||||
|
||||
if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0 && ec->tree){
|
||||
count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2);
|
||||
for(p=0; p<count; p++){
|
||||
state.time=-1.0;
|
||||
if(psys_get_particle_state(scene, eob,epsys,ptn2[p].index,&state,0)){
|
||||
VECSUB(dvec, state.co, pa->prev_state.co);
|
||||
|
||||
distance = Normalize(dvec);
|
||||
|
||||
if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
|
||||
;
|
||||
else{
|
||||
bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
|
||||
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BOID_LEVEL:
|
||||
/* level flight */
|
||||
if((part->flag & PART_BOIDS_2D)==0){
|
||||
dvec[0]=dvec[1]=0.0;
|
||||
dvec[2]=-pa->prev_state.vel[2];
|
||||
|
||||
VecMulf(dvec,part->boidfac[BOID_LEVEL]);
|
||||
not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* tries to realize the wanted acceleration */
|
||||
static void boid_body(Scene *scene, BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, ParticleSettings *part, float timestep, float *acc)
|
||||
{
|
||||
float dvec[3], bvec[3], length, max_vel=part->max_vel;
|
||||
float q2[4], q[4];
|
||||
float g=9.81f, pa_mass=part->mass;
|
||||
float yvec[3]={0.0,1.0,0.0}, zvec[3]={0.0,0.0,-1.0}, bank;
|
||||
|
||||
/* apply new velocity, location & rotation */
|
||||
copy_particle_key(&pa->state,&pa->prev_state,0);
|
||||
|
||||
if(part->flag & PART_SIZEMASS)
|
||||
pa_mass*=pa->size;
|
||||
|
||||
/* by regarding the acceleration as a force at this stage we*/
|
||||
/* can get better controll allthough it's a bit unphysical */
|
||||
bvf->Mulf(acc,1.0f/pa_mass);
|
||||
|
||||
bvf->Copyf(dvec,acc);
|
||||
bvf->Mulf(dvec,timestep*timestep*0.5f);
|
||||
|
||||
bvf->Copyf(bvec,pa->state.vel);
|
||||
bvf->Mulf(bvec,timestep);
|
||||
bvf->Addf(dvec,dvec,bvec);
|
||||
bvf->Addf(pa->state.co,pa->state.co,dvec);
|
||||
|
||||
/* air speed from wind and vortex effectors */
|
||||
if(psys->effectors.first) {
|
||||
ParticleEffectorCache *ec;
|
||||
for(ec=psys->effectors.first; ec; ec=ec->next) {
|
||||
if(ec->type & PSYS_EC_EFFECTOR) {
|
||||
Object *eob = ec->ob;
|
||||
PartDeflect *pd = eob->pd;
|
||||
float direction[3], vec_to_part[3];
|
||||
float falloff;
|
||||
|
||||
if(pd->f_strength != 0.0f) {
|
||||
VecCopyf(direction, eob->obmat[2]);
|
||||
VecSubf(vec_to_part, pa->state.co, eob->obmat[3]);
|
||||
|
||||
falloff=effector_falloff(pd, direction, vec_to_part);
|
||||
|
||||
switch(pd->forcefield) {
|
||||
case PFIELD_WIND:
|
||||
if(falloff <= 0.0f)
|
||||
; /* don't do anything */
|
||||
else {
|
||||
Normalize(direction);
|
||||
VecMulf(direction, pd->f_strength * falloff);
|
||||
bvf->Addf(pa->state.co, pa->state.co, direction);
|
||||
}
|
||||
break;
|
||||
case PFIELD_VORTEX:
|
||||
{
|
||||
float distance, mag_vec[3];
|
||||
Crossf(mag_vec, direction, vec_to_part);
|
||||
Normalize(mag_vec);
|
||||
|
||||
distance = VecLength(vec_to_part);
|
||||
|
||||
VecMulf(mag_vec, pd->f_strength * distance * falloff);
|
||||
bvf->Addf(pa->state.co, pa->state.co, mag_vec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if((part->flag & PART_BOIDS_2D)==0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0){
|
||||
Crossf(yvec,pa->state.vel,zvec);
|
||||
|
||||
Normalize(yvec);
|
||||
|
||||
bank=Inpf(yvec,acc);
|
||||
|
||||
bank=-(float)atan((double)(bank/g));
|
||||
|
||||
bank*=part->banking;
|
||||
|
||||
bank-=pa->bank;
|
||||
if(bank>M_PI*part->max_bank){
|
||||
bank=pa->bank+(float)M_PI*part->max_bank;
|
||||
}
|
||||
else if(bank<-M_PI*part->max_bank){
|
||||
bank=pa->bank-(float)M_PI*part->max_bank;
|
||||
}
|
||||
else
|
||||
bank+=pa->bank;
|
||||
|
||||
pa->bank=bank;
|
||||
}
|
||||
else{
|
||||
bank=0.0;
|
||||
}
|
||||
|
||||
|
||||
VecRotToQuat(pa->state.vel,bank,q);
|
||||
|
||||
VECCOPY(dvec,pa->state.vel);
|
||||
VecNegf(dvec);
|
||||
vectoquat(dvec, OB_POSX, OB_POSZ, q2);
|
||||
|
||||
QuatMul(pa->state.rot,q,q2);
|
||||
|
||||
bvf->Mulf(acc,timestep);
|
||||
bvf->Addf(pa->state.vel,pa->state.vel,acc);
|
||||
|
||||
if(part->flag & PART_BOIDS_2D){
|
||||
pa->state.vel[2]=0.0;
|
||||
pa->state.co[2]=part->groundz;
|
||||
}
|
||||
|
||||
length=bvf->Length(pa->state.vel);
|
||||
if(length > max_vel)
|
||||
bvf->Mulf(pa->state.vel,max_vel/length);
|
||||
}
|
||||
/************************************************/
|
||||
/* Hair */
|
||||
/************************************************/
|
||||
static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){
|
||||
@@ -4025,9 +3626,9 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
|
||||
ParticleData *pa;
|
||||
ParticleSettings *part=psys->part;
|
||||
KDTree *tree=0;
|
||||
BoidVecFunc bvf;
|
||||
IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system
|
||||
Material *ma=give_current_material(ob,part->omat);
|
||||
BoidBrainData bbd;
|
||||
float timestep;
|
||||
int p, totpart;
|
||||
/* current time */
|
||||
@@ -4107,16 +3708,23 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
|
||||
precalc_effectors(scene, ob,psys,psmd,cfra);
|
||||
|
||||
if(part->phystype==PART_PHYS_BOIDS){
|
||||
/* create particle tree for fast inter-particle comparisons */
|
||||
tree=BLI_kdtree_new(totpart);
|
||||
for(p=0, pa=psys->particles; p<totpart; p++,pa++){
|
||||
if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive!=PARS_ALIVE)
|
||||
continue;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
bbd.scene = scene;
|
||||
bbd.ob = ob;
|
||||
bbd.psys = psys;
|
||||
bbd.part = part;
|
||||
bbd.cfra = cfra;
|
||||
bbd.dfra = dfra;
|
||||
bbd.timestep = timestep;
|
||||
|
||||
BLI_kdtree_insert(tree, p, pa->state.co, NULL);
|
||||
update_particle_tree(psys);
|
||||
|
||||
boids_precalc_rules(part, cfra);
|
||||
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->ob)
|
||||
update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1));
|
||||
}
|
||||
BLI_kdtree_balance(tree);
|
||||
set_boid_vec_func(&bvf,part->flag&PART_BOIDS_2D);
|
||||
}
|
||||
|
||||
/* main loop: calculate physics for all particles */
|
||||
@@ -4185,10 +3793,14 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic
|
||||
break;
|
||||
case PART_PHYS_BOIDS:
|
||||
{
|
||||
float acc[3];
|
||||
boid_brain(&bvf, pa, scene, ob, psys, part, tree, timestep,cfra,acc);
|
||||
if(pa->alive != PARS_DYING)
|
||||
boid_body(scene, &bvf,pa,psys,part,timestep,acc);
|
||||
bbd.goal_ob = NULL;
|
||||
boid_brain(&bbd, p, pa);
|
||||
if(pa->alive != PARS_DYING) {
|
||||
boid_body(&bbd, pa);
|
||||
|
||||
/* deflection */
|
||||
deflect_particle(scene,ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4368,8 +3980,8 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
|
||||
dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time);
|
||||
|
||||
/* update alive status and push events */
|
||||
if(pa->time > cfra) {
|
||||
pa->alive = PARS_UNBORN;
|
||||
if(pa->time >= cfra) {
|
||||
pa->alive = pa->time==cfra ? PARS_ALIVE : PARS_UNBORN;
|
||||
reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL);
|
||||
}
|
||||
else if(dietime <= cfra){
|
||||
@@ -4454,9 +4066,33 @@ static void psys_changed_type(Object *ob, ParticleSystem *psys)
|
||||
|
||||
psys_reset(psys, PSYS_RESET_ALL);
|
||||
}
|
||||
void psys_changed_physics(Object *ob, ParticleSystem *psys)
|
||||
void psys_check_boid_data(ParticleSystem *psys)
|
||||
{
|
||||
if(ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
|
||||
ParticleData *pa = psys->particles;
|
||||
int p = 1;
|
||||
|
||||
if(!pa)
|
||||
return;
|
||||
|
||||
if(psys->part && psys->part->phystype==PART_PHYS_BOIDS) {
|
||||
if(!pa->boid) {
|
||||
pa->boid = MEM_callocN(psys->totpart * sizeof(BoidData), "Boid Data");
|
||||
|
||||
for(pa++; p<psys->totpart; p++, pa++)
|
||||
pa->boid = (pa-1)->boid + 1;
|
||||
}
|
||||
}
|
||||
else if(pa->boid){
|
||||
MEM_freeN(pa->boid);
|
||||
for(; p<psys->totpart; p++, pa++)
|
||||
pa->boid = NULL;
|
||||
}
|
||||
}
|
||||
static void psys_changed_physics(Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
ParticleSettings *part = psys->part;
|
||||
|
||||
if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
|
||||
PTCacheID pid;
|
||||
BKE_ptcache_id_from_particles(&pid, ob, psys);
|
||||
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
|
||||
@@ -4465,6 +4101,24 @@ void psys_changed_physics(Object *ob, ParticleSystem *psys)
|
||||
free_keyed_keys(psys);
|
||||
psys->flag &= ~PSYS_KEYED;
|
||||
}
|
||||
|
||||
if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) {
|
||||
BoidState *state;
|
||||
|
||||
psys_check_boid_data(psys);
|
||||
|
||||
part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings");
|
||||
boid_default_settings(part->boids);
|
||||
|
||||
state = boid_new_state(part->boids);
|
||||
BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate));
|
||||
BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock));
|
||||
|
||||
((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT;
|
||||
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
BLI_addtail(&part->boids->states, state);
|
||||
}
|
||||
}
|
||||
static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra)
|
||||
{
|
||||
|
||||
@@ -52,9 +52,13 @@ void BLI_kdtree_balance(KDTree *tree);
|
||||
|
||||
/* Find nearest returns index, and -1 if no node is found.
|
||||
* Find n nearest returns number of points found, with results in nearest.
|
||||
* Normal is optional. */
|
||||
/* Normal is optional, but if given will limit results to points in normal direction from co. */
|
||||
int BLI_kdtree_find_nearest(KDTree *tree, float *co, float *nor, KDTreeNearest *nearest);
|
||||
int BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, KDTreeNearest *nearest);
|
||||
|
||||
/* Range search returns number of points found, with results in nearest */
|
||||
/* Normal is optional, but if given will limit results to points in normal direction from co. */
|
||||
/* Remember to free nearest after use! */
|
||||
int BLI_kdtree_range_search(KDTree *tree, float range, float *co, float *nor, KDTreeNearest **nearest);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ void BLI_kdtree_balance(KDTree *tree)
|
||||
tree->root= kdtree_balance(tree->nodes, tree->totnode, 0);
|
||||
}
|
||||
|
||||
static float squared_distance(float *v1, float *v2, float *n1, float *n2)
|
||||
static float squared_distance(float *v2, float *v1, float *n1, float *n2)
|
||||
{
|
||||
float d[3], dist;
|
||||
|
||||
@@ -140,7 +140,8 @@ static float squared_distance(float *v1, float *v2, float *n1, float *n2)
|
||||
|
||||
dist= d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
|
||||
|
||||
if(n1 && n2 && n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2] < 0.0f)
|
||||
//if(n1 && n2 && n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2] < 0.0f)
|
||||
if(n2 && d[0]*n2[0] + d[1]*n2[1] + d[2]*n2[2] < 0.0f)
|
||||
dist *= 10.0f;
|
||||
|
||||
return dist;
|
||||
@@ -336,3 +337,111 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, KDTree
|
||||
return found;
|
||||
}
|
||||
|
||||
int range_compare(const void * a, const void * b)
|
||||
{
|
||||
const KDTreeNearest *kda = a;
|
||||
const KDTreeNearest *kdb = b;
|
||||
|
||||
if(kda->dist < kdb->dist)
|
||||
return -1;
|
||||
else if(kda->dist > kdb->dist)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static void add_in_range(KDTreeNearest **ptn, int found, int *totfoundstack, int index, float dist, float *co)
|
||||
{
|
||||
KDTreeNearest *to;
|
||||
|
||||
if(found+1 > *totfoundstack) {
|
||||
KDTreeNearest *temp=MEM_callocN((*totfoundstack+50)*sizeof(KDTreeNode), "psys_treefoundstack");
|
||||
memcpy(temp, *ptn, *totfoundstack * sizeof(KDTreeNearest));
|
||||
if(*ptn)
|
||||
MEM_freeN(*ptn);
|
||||
*ptn = temp;
|
||||
*totfoundstack+=50;
|
||||
}
|
||||
|
||||
to = (*ptn) + found;
|
||||
|
||||
to->index = index;
|
||||
to->dist = sqrt(dist);
|
||||
VecCopyf(to->co, co);
|
||||
}
|
||||
int BLI_kdtree_range_search(KDTree *tree, float range, float *co, float *nor, KDTreeNearest **nearest)
|
||||
{
|
||||
KDTreeNode *root, *node=0;
|
||||
KDTreeNode **stack, *defaultstack[100];
|
||||
KDTreeNearest *foundstack=NULL;
|
||||
float range2 = range*range, dist2;
|
||||
int i, totstack, cur=0, found=0, totfoundstack=0;
|
||||
|
||||
if(!tree || !tree->root)
|
||||
return 0;
|
||||
|
||||
stack= defaultstack;
|
||||
totstack= 100;
|
||||
|
||||
root= tree->root;
|
||||
|
||||
if(co[root->d] + range < root->co[root->d]) {
|
||||
if(root->left)
|
||||
stack[cur++]=root->left;
|
||||
}
|
||||
else if(co[root->d] - range > root->co[root->d]) {
|
||||
if(root->right)
|
||||
stack[cur++]=root->right;
|
||||
}
|
||||
else {
|
||||
dist2 = squared_distance(root->co, co, root->nor, nor);
|
||||
if(dist2 <= range2)
|
||||
add_in_range(&foundstack, found++, &totfoundstack, root->index, dist2, root->co);
|
||||
|
||||
if(root->left)
|
||||
stack[cur++]=root->left;
|
||||
if(root->right)
|
||||
stack[cur++]=root->right;
|
||||
}
|
||||
|
||||
while(cur--) {
|
||||
node=stack[cur];
|
||||
|
||||
if(co[node->d] + range < node->co[node->d]) {
|
||||
if(node->left)
|
||||
stack[cur++]=node->left;
|
||||
}
|
||||
else if(co[node->d] - range > node->co[node->d]) {
|
||||
if(node->right)
|
||||
stack[cur++]=node->right;
|
||||
}
|
||||
else {
|
||||
dist2 = squared_distance(node->co, co, node->nor, nor);
|
||||
if(dist2 <= range2)
|
||||
add_in_range(&foundstack, found++, &totfoundstack, node->index, dist2, node->co);
|
||||
|
||||
if(node->left)
|
||||
stack[cur++]=node->left;
|
||||
if(node->right)
|
||||
stack[cur++]=node->right;
|
||||
}
|
||||
|
||||
if(cur+3 > totstack){
|
||||
KDTreeNode **temp=MEM_callocN((totstack+100)*sizeof(KDTreeNode*), "psys_treestack");
|
||||
memcpy(temp,stack,totstack*sizeof(KDTreeNode*));
|
||||
if(stack != defaultstack)
|
||||
MEM_freeN(stack);
|
||||
stack=temp;
|
||||
totstack+=100;
|
||||
}
|
||||
}
|
||||
|
||||
if(stack != defaultstack)
|
||||
MEM_freeN(stack);
|
||||
|
||||
if(found)
|
||||
qsort(foundstack, found, sizeof(KDTreeNearest), range_compare);
|
||||
|
||||
*nearest = foundstack;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_actuator_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
@@ -2990,6 +2991,29 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
|
||||
part->dup_group = newlibadr(fd, part->id.lib, part->dup_group);
|
||||
part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
|
||||
part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
|
||||
if(part->boids) {
|
||||
BoidState *state = part->boids->states.first;
|
||||
BoidRule *rule;
|
||||
for(; state; state=state->next) {
|
||||
rule = state->rules.first;
|
||||
for(; rule; rule=rule->next)
|
||||
switch(rule->type) {
|
||||
case eBoidRuleType_Goal:
|
||||
case eBoidRuleType_Avoid:
|
||||
{
|
||||
BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid*)rule;
|
||||
brga->ob = newlibadr(fd, part->id.lib, brga->ob);
|
||||
break;
|
||||
}
|
||||
case eBoidRuleType_FollowLeader:
|
||||
{
|
||||
BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader*)rule;
|
||||
brfl->ob = newlibadr(fd, part->id.lib, brfl->ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
part->id.flag -= LIB_NEEDLINK;
|
||||
}
|
||||
part= part->id.next;
|
||||
@@ -3001,6 +3025,19 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
|
||||
part->adt= newdataadr(fd, part->adt);
|
||||
part->pd= newdataadr(fd, part->pd);
|
||||
part->pd2= newdataadr(fd, part->pd2);
|
||||
|
||||
part->boids= newdataadr(fd, part->boids);
|
||||
|
||||
if(part->boids) {
|
||||
BoidState *state;
|
||||
link_list(fd, &part->boids->states);
|
||||
|
||||
for(state=part->boids->states.first; state; state=state->next) {
|
||||
link_list(fd, &state->rules);
|
||||
link_list(fd, &state->conditions);
|
||||
link_list(fd, &state->actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles)
|
||||
@@ -3015,10 +3052,10 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase
|
||||
|
||||
psys->part = newlibadr_us(fd, id->lib, psys->part);
|
||||
if(psys->part) {
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
|
||||
for(; kpt; kpt=kpt->next)
|
||||
kpt->ob=newlibadr(fd, id->lib, kpt->ob);
|
||||
for(; pt; pt=pt->next)
|
||||
pt->ob=newlibadr(fd, id->lib, pt->ob);
|
||||
|
||||
psys->target_ob = newlibadr(fd, id->lib, psys->target_ob);
|
||||
|
||||
@@ -3042,24 +3079,38 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase
|
||||
static void direct_link_particlesystems(FileData *fd, ListBase *particles)
|
||||
{
|
||||
ParticleSystem *psys;
|
||||
ParticleData *pa;
|
||||
int a;
|
||||
|
||||
for(psys=particles->first; psys; psys=psys->next) {
|
||||
psys->particles=newdataadr(fd,psys->particles);
|
||||
|
||||
if(psys->particles && psys->particles->hair){
|
||||
ParticleData *pa = psys->particles;
|
||||
for(a=0; a<psys->totpart; a++, pa++)
|
||||
for(a=0,pa=psys->particles; a<psys->totpart; a++, pa++)
|
||||
pa->hair=newdataadr(fd,pa->hair);
|
||||
}
|
||||
|
||||
if(psys->particles && psys->particles->keys){
|
||||
ParticleData *pa = psys->particles;
|
||||
for(a=0; a<psys->totpart; a++, pa++) {
|
||||
for(a=0,pa=psys->particles; a<psys->totpart; a++, pa++) {
|
||||
pa->keys= NULL;
|
||||
pa->totkey= 0;
|
||||
}
|
||||
|
||||
psys->flag &= ~PSYS_KEYED;
|
||||
}
|
||||
|
||||
if(psys->particles->boid) {
|
||||
pa = psys->particles;
|
||||
pa->boid = newdataadr(fd, pa->boid);
|
||||
for(a=1,pa++; a<psys->totpart; a++, pa++)
|
||||
pa->boid = (pa-1)->boid + 1;
|
||||
}
|
||||
else {
|
||||
for(a=0,pa=psys->particles; a<psys->totpart; a++, pa++)
|
||||
pa->boid = NULL;
|
||||
}
|
||||
|
||||
|
||||
psys->child=newdataadr(fd,psys->child);
|
||||
psys->effectors.first=psys->effectors.last=0;
|
||||
|
||||
@@ -3076,7 +3127,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
|
||||
direct_link_pointcache(fd, sb->pointcache);
|
||||
}
|
||||
|
||||
link_list(fd, &psys->keyed_targets);
|
||||
link_list(fd, &psys->targets);
|
||||
|
||||
psys->edit = 0;
|
||||
psys->free_edit = NULL;
|
||||
@@ -3089,6 +3140,8 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
|
||||
psys->pointcache= newdataadr(fd, psys->pointcache);
|
||||
if(psys->pointcache)
|
||||
direct_link_pointcache(fd, psys->pointcache);
|
||||
|
||||
psys->tree = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3649,6 +3702,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
||||
|
||||
surmd->dm = NULL;
|
||||
surmd->bvhtree = NULL;
|
||||
surmd->x = NULL;
|
||||
surmd->v = NULL;
|
||||
surmd->numverts = 0;
|
||||
}
|
||||
else if (md->type==eModifierType_Hook) {
|
||||
HookModifierData *hmd = (HookModifierData*) md;
|
||||
@@ -8541,7 +8597,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
|
||||
psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
|
||||
psys->pointcache = BKE_ptcache_add();
|
||||
|
||||
part = psys->part = psys_new_settings("PSys", main);
|
||||
part = psys->part = psys_new_settings("ParticleSettings", main);
|
||||
|
||||
/* needed for proper libdata lookup */
|
||||
oldnewmap_insert(fd->libmap, psys->part, psys->part, 0);
|
||||
|
||||
@@ -93,6 +93,7 @@ Any case: direct data is ALWAYS after the lib block
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_actuator_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
@@ -550,6 +551,39 @@ static void write_userdef(WriteData *wd)
|
||||
}
|
||||
}
|
||||
|
||||
static void write_boid_state(WriteData *wd, BoidState *state)
|
||||
{
|
||||
BoidRule *rule = state->rules.first;
|
||||
//BoidCondition *cond = state->conditions.first;
|
||||
|
||||
writestruct(wd, DATA, "BoidState", 1, state);
|
||||
|
||||
for(; rule; rule=rule->next) {
|
||||
switch(rule->type) {
|
||||
case eBoidRuleType_Goal:
|
||||
case eBoidRuleType_Avoid:
|
||||
writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule);
|
||||
break;
|
||||
case eBoidRuleType_AvoidCollision:
|
||||
writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule);
|
||||
break;
|
||||
case eBoidRuleType_FollowLeader:
|
||||
writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule);
|
||||
break;
|
||||
case eBoidRuleType_AverageSpeed:
|
||||
writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule);
|
||||
break;
|
||||
case eBoidRuleType_Fight:
|
||||
writestruct(wd, DATA, "BoidRuleFight", 1, rule);
|
||||
break;
|
||||
default:
|
||||
writestruct(wd, DATA, "BoidRule", 1, rule);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//for(; cond; cond=cond->next)
|
||||
// writestruct(wd, DATA, "BoidCondition", 1, cond);
|
||||
}
|
||||
/* TODO: replace *cache with *cachelist once it's coded */
|
||||
#define PTCACHE_WRITE_PSYS 0
|
||||
#define PTCACHE_WRITE_CLOTH 1
|
||||
@@ -582,6 +616,15 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
|
||||
if (part->adt) write_animdata(wd, part->adt);
|
||||
writestruct(wd, DATA, "PartDeflect", 1, part->pd);
|
||||
writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
|
||||
|
||||
if(part->boids && part->phystype == PART_PHYS_BOIDS) {
|
||||
BoidState *state = part->boids->states.first;
|
||||
|
||||
writestruct(wd, DATA, "BoidSettings", 1, part->boids);
|
||||
|
||||
for(; state; state=state->next)
|
||||
write_boid_state(wd, state);
|
||||
}
|
||||
}
|
||||
part= part->id.next;
|
||||
}
|
||||
@@ -589,7 +632,7 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
|
||||
static void write_particlesystems(WriteData *wd, ListBase *particles)
|
||||
{
|
||||
ParticleSystem *psys= particles->first;
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
int a;
|
||||
|
||||
for(; psys; psys=psys->next) {
|
||||
@@ -604,10 +647,13 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
|
||||
for(a=0; a<psys->totpart; a++, pa++)
|
||||
writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
|
||||
}
|
||||
|
||||
if(psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS)
|
||||
writestruct(wd, DATA, "BoidData", psys->totpart, psys->particles->boid);
|
||||
}
|
||||
kpt = psys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next)
|
||||
writestruct(wd, DATA, "KeyedParticleTarget", 1, kpt);
|
||||
pt = psys->targets.first;
|
||||
for(; pt; pt=pt->next)
|
||||
writestruct(wd, DATA, "ParticleTarget", 1, pt);
|
||||
|
||||
if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child);
|
||||
writestruct(wd, DATA, "SoftBody", 1, psys->soft);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
/* operators */
|
||||
|
||||
void ED_operatortypes_boids(void);
|
||||
void ED_operatortypes_pointcache(void);
|
||||
void ED_operatortypes_fluid(void);
|
||||
//void ED_keymap_pointcache(struct wmWindowManager *wm);
|
||||
|
||||
433
source/blender/editors/physics/physics_boids.c
Normal file
433
source/blender/editors/physics/physics_boids.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/**
|
||||
* $Id:
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2009 Janne Karhu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
//
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
//#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
//#include "DNA_material_types.h"
|
||||
//#include "DNA_texture_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
//#include "DNA_world_types.h"
|
||||
|
||||
#include "BKE_boids.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
//#include "BKE_font.h"
|
||||
//#include "BKE_library.h"
|
||||
//#include "BKE_main.h"
|
||||
//#include "BKE_material.h"
|
||||
#include "BKE_particle.h"
|
||||
//#include "BKE_texture.h"
|
||||
//#include "BKE_utildefines.h"
|
||||
//#include "BKE_world.h"
|
||||
|
||||
//#include "BLI_editVert.h"
|
||||
#include "BLI_listbase.h"
|
||||
//
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_enum_types.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
//#include "ED_curve.h"
|
||||
//#include "ED_mesh.h"
|
||||
//
|
||||
//#include "buttons_intern.h" // own include
|
||||
|
||||
/************************ add/del boid rule operators *********************/
|
||||
static int boidrule_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob= ptr.id.data;
|
||||
ParticleSettings *part;
|
||||
int type= RNA_enum_get(op->ptr, "type");
|
||||
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
part = psys->part;
|
||||
|
||||
state = boid_get_current_state(part->boids);
|
||||
|
||||
|
||||
for(rule=state->rules.first; rule; rule=rule->next)
|
||||
rule->flag &= ~BOIDRULE_CURRENT;
|
||||
|
||||
rule = boid_new_rule(type);
|
||||
rule->flag |= BOIDRULE_CURRENT;
|
||||
|
||||
BLI_addtail(&state->rules, rule);
|
||||
|
||||
psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidrule_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Add Boid Rule";
|
||||
ot->description = "Add a boid rule to the current boid state.";
|
||||
ot->idname= "BOID_OT_boidrule_add";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke= WM_menu_invoke;
|
||||
ot->exec= boidrule_add_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
RNA_def_enum(ot->srna, "type", boidrule_type_items, 0, "Type", "");
|
||||
}
|
||||
static int boidrule_del_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
state = boid_get_current_state(psys->part->boids);
|
||||
|
||||
|
||||
for(rule=state->rules.first; rule; rule=rule->next) {
|
||||
if(rule->flag & BOIDRULE_CURRENT) {
|
||||
BLI_remlink(&state->rules, rule);
|
||||
MEM_freeN(rule);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
rule = state->rules.first;
|
||||
|
||||
if(rule)
|
||||
rule->flag |= BOIDRULE_CURRENT;
|
||||
|
||||
DAG_scene_sort(scene);
|
||||
psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidrule_del(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Remove Boid Rule";
|
||||
ot->idname= "BOID_OT_boidrule_del";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= boidrule_del_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move up/down boid rule operators *********************/
|
||||
static int boidrule_move_up_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
state = boid_get_current_state(psys->part->boids);
|
||||
for(rule = state->rules.first; rule; rule=rule->next) {
|
||||
if(rule->flag & BOIDRULE_CURRENT && rule->prev) {
|
||||
BLI_remlink(&state->rules, rule);
|
||||
BLI_insertlink(&state->rules, rule->prev->prev, rule);
|
||||
|
||||
psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidrule_move_up(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Up Boid Rule";
|
||||
ot->description= "Move boid rule up in the list.";
|
||||
ot->idname= "BOID_OT_boidrule_move_up";
|
||||
|
||||
ot->exec= boidrule_move_up_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int boidrule_move_down_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
state = boid_get_current_state(psys->part->boids);
|
||||
for(rule = state->rules.first; rule; rule=rule->next) {
|
||||
if(rule->flag & BOIDRULE_CURRENT && rule->next) {
|
||||
BLI_remlink(&state->rules, rule);
|
||||
BLI_insertlink(&state->rules, rule->next, rule);
|
||||
|
||||
psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidrule_move_down(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Down Boid Rule";
|
||||
ot->description= "Move boid rule down in the list.";
|
||||
ot->idname= "BOID_OT_boidrule_move_down";
|
||||
|
||||
ot->exec= boidrule_move_down_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
|
||||
/************************ add/del boid state operators *********************/
|
||||
static int boidstate_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob= ptr.id.data;
|
||||
ParticleSettings *part;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
part = psys->part;
|
||||
|
||||
for(state=part->boids->states.first; state; state=state->next)
|
||||
state->flag &= ~BOIDSTATE_CURRENT;
|
||||
|
||||
state = boid_new_state(part->boids);
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
|
||||
BLI_addtail(&part->boids->states, state);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidstate_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Add Boid State";
|
||||
ot->description = "Add a boid state to the particle system.";
|
||||
ot->idname= "BOID_OT_boidstate_add";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= boidstate_add_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
static int boidstate_del_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
ParticleSettings *part;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
part = psys->part;
|
||||
|
||||
for(state=part->boids->states.first; state; state=state->next) {
|
||||
if(state->flag & BOIDSTATE_CURRENT) {
|
||||
BLI_remlink(&part->boids->states, state);
|
||||
MEM_freeN(state);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* there must be at least one state */
|
||||
if(!part->boids->states.first) {
|
||||
state = boid_new_state(part->boids);
|
||||
BLI_addtail(&part->boids->states, state);
|
||||
}
|
||||
else
|
||||
state = part->boids->states.first;
|
||||
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
|
||||
DAG_scene_sort(scene);
|
||||
psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidstate_del(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Remove Boid State";
|
||||
ot->idname= "BOID_OT_boidstate_del";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= boidstate_del_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move up/down boid state operators *********************/
|
||||
static int boidstate_move_up_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
BoidSettings *boids;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
boids = psys->part->boids;
|
||||
|
||||
for(state = boids->states.first; state; state=state->next) {
|
||||
if(state->flag & BOIDSTATE_CURRENT && state->prev) {
|
||||
BLI_remlink(&boids->states, state);
|
||||
BLI_insertlink(&boids->states, state->prev->prev, state);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidstate_move_up(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Up Boid State";
|
||||
ot->description= "Move boid state up in the list.";
|
||||
ot->idname= "BOID_OT_boidstate_move_up";
|
||||
|
||||
ot->exec= boidstate_move_up_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int boidstate_move_down_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
BoidSettings *boids;
|
||||
BoidState *state;
|
||||
|
||||
if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
boids = psys->part->boids;
|
||||
|
||||
for(state = boids->states.first; state; state=state->next) {
|
||||
if(state->flag & BOIDSTATE_CURRENT && state->next) {
|
||||
BLI_remlink(&boids->states, state);
|
||||
BLI_insertlink(&boids->states, state->next, state);
|
||||
psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_boidstate_move_down(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Down Boid State";
|
||||
ot->description= "Move boid state down in the list.";
|
||||
ot->idname= "BOID_OT_boidstate_move_down";
|
||||
|
||||
ot->exec= boidstate_move_down_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
void ED_operatortypes_boids(void)
|
||||
{
|
||||
WM_operatortype_append(BOID_OT_boidrule_add);
|
||||
WM_operatortype_append(BOID_OT_boidrule_del);
|
||||
WM_operatortype_append(BOID_OT_boidrule_move_up);
|
||||
WM_operatortype_append(BOID_OT_boidrule_move_down);
|
||||
|
||||
WM_operatortype_append(BOID_OT_boidstate_add);
|
||||
WM_operatortype_append(BOID_OT_boidstate_del);
|
||||
WM_operatortype_append(BOID_OT_boidstate_move_up);
|
||||
WM_operatortype_append(BOID_OT_boidstate_move_down);
|
||||
}
|
||||
@@ -93,6 +93,7 @@ void ED_spacetypes_init(void)
|
||||
ED_operatortypes_marker();
|
||||
ED_operatortypes_pointcache();
|
||||
ED_operatortypes_fluid();
|
||||
ED_operatortypes_boids();
|
||||
|
||||
ui_view2d_operatortypes();
|
||||
|
||||
|
||||
@@ -78,10 +78,10 @@ void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_new(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_new_keyed_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_remove_keyed_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_keyed_target_move_up(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_keyed_target_move_down(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_new_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_remove_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
|
||||
|
||||
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
|
||||
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@@ -57,6 +58,7 @@
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
@@ -623,7 +625,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *op)
|
||||
if(psys->part)
|
||||
part= psys_copy_settings(psys->part);
|
||||
else
|
||||
part= psys_new_settings("PSys", bmain);
|
||||
part= psys_new_settings("ParticleSettings", bmain);
|
||||
|
||||
ob= ptr.id.data;
|
||||
|
||||
@@ -632,6 +634,8 @@ static int new_particle_settings_exec(bContext *C, wmOperator *op)
|
||||
|
||||
psys->part = part;
|
||||
|
||||
psys_check_boid_data(psys);
|
||||
|
||||
DAG_scene_sort(scene);
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
|
||||
@@ -655,28 +659,28 @@ void PARTICLE_OT_new(wmOperatorType *ot)
|
||||
|
||||
/********************** keyed particle target operators *********************/
|
||||
|
||||
static int new_keyed_particle_target_exec(bContext *C, wmOperator *op)
|
||||
static int new_particle_target_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
|
||||
if(!psys)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
kpt = psys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next)
|
||||
kpt->flag &= ~KEYED_TARGET_CURRENT;
|
||||
pt = psys->targets.first;
|
||||
for(; pt; pt=pt->next)
|
||||
pt->flag &= ~PTARGET_CURRENT;
|
||||
|
||||
kpt = MEM_callocN(sizeof(KeyedParticleTarget), "keyed particle target");
|
||||
pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");
|
||||
|
||||
kpt->flag |= KEYED_TARGET_CURRENT;
|
||||
kpt->psys = 1;
|
||||
pt->flag |= PTARGET_CURRENT;
|
||||
pt->psys = 1;
|
||||
|
||||
BLI_addtail(&psys->keyed_targets, kpt);
|
||||
BLI_addtail(&psys->targets, pt);
|
||||
|
||||
DAG_scene_sort(scene);
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
@@ -686,44 +690,44 @@ static int new_keyed_particle_target_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_new_keyed_target(wmOperatorType *ot)
|
||||
void PARTICLE_OT_new_target(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "New Keyed Particle Target";
|
||||
ot->idname= "PARTICLE_OT_new_keyed_target";
|
||||
ot->name= "New Particle Target";
|
||||
ot->idname= "PARTICLE_OT_new_target";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= new_keyed_particle_target_exec;
|
||||
ot->exec= new_particle_target_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op)
|
||||
static int remove_particle_target_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
|
||||
if(!psys)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
kpt = psys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->flag & KEYED_TARGET_CURRENT) {
|
||||
BLI_remlink(&psys->keyed_targets, kpt);
|
||||
MEM_freeN(kpt);
|
||||
pt = psys->targets.first;
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->flag & PTARGET_CURRENT) {
|
||||
BLI_remlink(&psys->targets, pt);
|
||||
MEM_freeN(pt);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
kpt = psys->keyed_targets.last;
|
||||
pt = psys->targets.last;
|
||||
|
||||
if(kpt)
|
||||
kpt->flag |= KEYED_TARGET_CURRENT;
|
||||
if(pt)
|
||||
pt->flag |= PTARGET_CURRENT;
|
||||
|
||||
DAG_scene_sort(scene);
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
@@ -733,37 +737,37 @@ static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_remove_keyed_target(wmOperatorType *ot)
|
||||
void PARTICLE_OT_remove_target(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Remove Keyed Particle Target";
|
||||
ot->idname= "PARTICLE_OT_remove_keyed_target";
|
||||
ot->name= "Remove Particle Target";
|
||||
ot->idname= "PARTICLE_OT_remove_target";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= remove_keyed_particle_target_exec;
|
||||
ot->exec= remove_particle_target_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move up modifier operator *********************/
|
||||
/************************ move up particle target operator *********************/
|
||||
|
||||
static int keyed_target_move_up_exec(bContext *C, wmOperator *op)
|
||||
static int target_move_up_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
|
||||
if(!psys)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
kpt = psys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->flag & KEYED_TARGET_CURRENT && kpt->prev) {
|
||||
BLI_remlink(&psys->keyed_targets, kpt);
|
||||
BLI_insertlink(&psys->keyed_targets, kpt->prev->prev, kpt);
|
||||
pt = psys->targets.first;
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->flag & PTARGET_CURRENT && pt->prev) {
|
||||
BLI_remlink(&psys->targets, pt);
|
||||
BLI_insertlink(&psys->targets, pt->prev->prev, pt);
|
||||
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
@@ -774,35 +778,35 @@ static int keyed_target_move_up_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_keyed_target_move_up(wmOperatorType *ot)
|
||||
void PARTICLE_OT_target_move_up(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Up Keyed Target";
|
||||
ot->description= "Move keyed particle target up in the list.";
|
||||
ot->idname= "PARTICLE_OT_keyed_target_move_up";
|
||||
ot->name= "Move Up Target";
|
||||
ot->description= "Move particle target up in the list.";
|
||||
ot->idname= "PARTICLE_OT_target_move_up";
|
||||
|
||||
ot->exec= keyed_target_move_up_exec;
|
||||
ot->exec= target_move_up_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move down modifier operator *********************/
|
||||
/************************ move down particle target operator *********************/
|
||||
|
||||
static int keyed_target_move_down_exec(bContext *C, wmOperator *op)
|
||||
static int target_move_down_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= ptr.data;
|
||||
Object *ob = ptr.id.data;
|
||||
KeyedParticleTarget *kpt;
|
||||
ParticleTarget *pt;
|
||||
|
||||
if(!psys)
|
||||
return OPERATOR_CANCELLED;
|
||||
kpt = psys->keyed_targets.first;
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->flag & KEYED_TARGET_CURRENT && kpt->next) {
|
||||
BLI_remlink(&psys->keyed_targets, kpt);
|
||||
BLI_insertlink(&psys->keyed_targets, kpt->next, kpt);
|
||||
pt = psys->targets.first;
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->flag & PTARGET_CURRENT && pt->next) {
|
||||
BLI_remlink(&psys->targets, pt);
|
||||
BLI_insertlink(&psys->targets, pt->next, pt);
|
||||
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
@@ -813,13 +817,13 @@ static int keyed_target_move_down_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_keyed_target_move_down(wmOperatorType *ot)
|
||||
void PARTICLE_OT_target_move_down(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Move Down Keyed Target";
|
||||
ot->description= "Move keyed particle target down in the list.";
|
||||
ot->idname= "PARTICLE_OT_keyed_target_move_down";
|
||||
ot->name= "Move Down Target";
|
||||
ot->description= "Move particle target down in the list.";
|
||||
ot->idname= "PARTICLE_OT_target_move_down";
|
||||
|
||||
ot->exec= keyed_target_move_down_exec;
|
||||
ot->exec= target_move_down_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
@@ -198,10 +198,10 @@ void buttons_operatortypes(void)
|
||||
WM_operatortype_append(OBJECT_OT_particle_system_remove);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_new);
|
||||
WM_operatortype_append(PARTICLE_OT_new_keyed_target);
|
||||
WM_operatortype_append(PARTICLE_OT_remove_keyed_target);
|
||||
WM_operatortype_append(PARTICLE_OT_keyed_target_move_up);
|
||||
WM_operatortype_append(PARTICLE_OT_keyed_target_move_down);
|
||||
WM_operatortype_append(PARTICLE_OT_new_target);
|
||||
WM_operatortype_append(PARTICLE_OT_remove_target);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_up);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_down);
|
||||
|
||||
WM_operatortype_append(SCENE_OT_render_layer_add);
|
||||
WM_operatortype_append(SCENE_OT_render_layer_remove);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "MTC_matrixops.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_constraint_types.h" // for drawing constraint
|
||||
@@ -3136,7 +3137,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
|
||||
Material *ma;
|
||||
float vel[3], imat[4][4];
|
||||
float timestep, pixsize=1.0, pa_size, r_tilt, r_length;
|
||||
float pa_time, pa_birthtime, pa_dietime;
|
||||
float pa_time, pa_birthtime, pa_dietime, pa_health;
|
||||
float cfra= bsystem_time(scene, ob,(float)CFRA,0.0);
|
||||
float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f;
|
||||
int a, totpart, totpoint=0, totve=0, drawn, draw_as, totchild=0;
|
||||
@@ -3362,6 +3363,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
|
||||
pa_birthtime=pa->time;
|
||||
pa_dietime = pa->dietime;
|
||||
pa_size=pa->size;
|
||||
if(part->phystype==PART_PHYS_BOIDS)
|
||||
pa_health = pa->boid->health;
|
||||
else
|
||||
pa_health = -1.0;
|
||||
|
||||
#if 0 // XXX old animation system
|
||||
if((part->flag&PART_ABS_TIME)==0){
|
||||
@@ -3424,6 +3429,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
|
||||
|
||||
pa_size=psys_get_child_size(psys,cpa,cfra,0);
|
||||
|
||||
pa_health = -1.0;
|
||||
|
||||
r_tilt = 2.0f * cpa->rand[2];
|
||||
r_length = cpa->rand[1];
|
||||
}
|
||||
@@ -3506,9 +3513,19 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
|
||||
setlinestyle(0);
|
||||
}
|
||||
|
||||
if(part->draw&PART_DRAW_NUM && !(G.f & G_RENDER_SHADOW)){
|
||||
if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){
|
||||
strcpy(val, "");
|
||||
|
||||
if(part->draw&PART_DRAW_NUM)
|
||||
sprintf(val, " %i", a);
|
||||
|
||||
if(part->draw&PART_DRAW_NUM && part->draw&PART_DRAW_HEALTH)
|
||||
sprintf(val, "%s:", val);
|
||||
|
||||
if(part->draw&PART_DRAW_HEALTH && a < totpart && part->phystype==PART_PHYS_BOIDS)
|
||||
sprintf(val, "%s %.2f", val, pa_health);
|
||||
|
||||
/* in path drawing state.co is the end point */
|
||||
sprintf(val," %i",a);
|
||||
view3d_particle_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,9 +427,14 @@ typedef struct CollisionModifierData {
|
||||
typedef struct SurfaceModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
struct MVert *x; /* old position */
|
||||
struct MVert *v; /* velocity */
|
||||
|
||||
struct DerivedMesh *dm;
|
||||
|
||||
struct BVHTreeFromMesh *bvhtree; /* bounding volume hierarchy of the mesh faces */
|
||||
|
||||
int cfra, numverts;
|
||||
} SurfaceModifierData;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -227,6 +227,7 @@ typedef struct SoftBody {
|
||||
#define PFIELD_HARMONIC 7
|
||||
#define PFIELD_CHARGE 8
|
||||
#define PFIELD_LENNARDJ 9
|
||||
#define PFIELD_BOID 10
|
||||
|
||||
|
||||
/* pd->flag: various settings */
|
||||
|
||||
@@ -61,13 +61,13 @@ typedef struct ChildParticle {
|
||||
float rand[3];
|
||||
} ChildParticle;
|
||||
|
||||
typedef struct KeyedParticleTarget {
|
||||
struct KeyedParticleTarget *next, *prev;
|
||||
typedef struct ParticleTarget {
|
||||
struct ParticleTarget *next, *prev;
|
||||
struct Object *ob;
|
||||
int psys;
|
||||
short flag, rt;
|
||||
short flag, mode;
|
||||
float time, duration;
|
||||
} KeyedParticleTarget;
|
||||
} ParticleTarget;
|
||||
|
||||
/* Everything that's non dynamic for a particle: */
|
||||
typedef struct ParticleData {
|
||||
@@ -82,7 +82,9 @@ typedef struct ParticleData {
|
||||
|
||||
ParticleKey *keys; /* keyed states */
|
||||
|
||||
float i_rot[4],r_rot[4];/* initial & random values (i_rot should be removed as it's not used anymore)*/
|
||||
struct BoidData *boid; /* boids data */
|
||||
|
||||
float r_rot[4]; /* random values */
|
||||
float r_ave[3],r_ve[3];
|
||||
|
||||
float fuv[4], foffset; /* coordinates on face/edge number "num" and depth along*/
|
||||
@@ -91,13 +93,10 @@ typedef struct ParticleData {
|
||||
float time, lifetime; /* dietime is not nescessarily time+lifetime as */
|
||||
float dietime; /* particles can die unnaturally (collision) */
|
||||
|
||||
float bank; /* banking angle for boids */
|
||||
|
||||
float size, sizemul; /* size and multiplier so that we can update size when ever */
|
||||
|
||||
int num; /* index to vert/edge/face */
|
||||
int num_dmcache; /* index to derived mesh data (face) to avoid slow lookups */
|
||||
int pad;
|
||||
|
||||
int totkey;
|
||||
int bpi; /* softbody body point start index */
|
||||
@@ -112,12 +111,14 @@ typedef struct ParticleSettings {
|
||||
ID id;
|
||||
struct AnimData *adt;
|
||||
|
||||
struct BoidSettings *boids;
|
||||
|
||||
int flag;
|
||||
short type, from, distr;
|
||||
/* physics modes */
|
||||
short phystype, rotmode, avemode, reactevent;
|
||||
short draw, draw_as, draw_size, childtype;
|
||||
short ren_as, rt2[3];
|
||||
short ren_as, rt2;
|
||||
/* number of path segments, power of 2 except */
|
||||
short draw_step, ren_step;
|
||||
short hair_step, keys_step;
|
||||
@@ -126,7 +127,7 @@ typedef struct ParticleSettings {
|
||||
short adapt_angle, adapt_pix;
|
||||
|
||||
short disp, omat, interpolation, rotfrom, integrator;
|
||||
short kink, kink_axis, nbetween, boidneighbours;
|
||||
short kink, kink_axis;
|
||||
|
||||
/* billboards */
|
||||
short bb_align, bb_uv_split, bb_anim, bb_split_offset;
|
||||
@@ -154,7 +155,7 @@ typedef struct ParticleSettings {
|
||||
/* children */
|
||||
int child_nbr, ren_child_nbr;
|
||||
float parents, childsize, childrandsize;
|
||||
float childrad, childflat, rt;
|
||||
float childrad, childflat;
|
||||
/* clumping */
|
||||
float clumpfac, clumppow;
|
||||
/* kink */
|
||||
@@ -174,11 +175,7 @@ typedef struct ParticleSettings {
|
||||
/* keyed particles */
|
||||
int keyed_loops;
|
||||
|
||||
/* boids */
|
||||
float max_vel, max_lat_acc, max_tan_acc;
|
||||
float average_vel, banking, max_bank, groundz;
|
||||
float boidfac[8];
|
||||
char boidrule[8];
|
||||
float effector_weight[10];
|
||||
|
||||
struct Group *dup_group;
|
||||
struct Group *eff_group;
|
||||
@@ -212,12 +209,14 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
|
||||
|
||||
struct ListBase effectors, reactevents; /* runtime */
|
||||
|
||||
struct ListBase keyed_targets;
|
||||
struct ListBase targets; /* used for keyed and boid physics */
|
||||
|
||||
char name[32]; /* particle system name */
|
||||
|
||||
float imat[4][4]; /* used for duplicators */
|
||||
float cfra;
|
||||
float cfra, tree_frame;
|
||||
int seed;
|
||||
int flag, totpart, totchild, totcached, totchildcache, rt;
|
||||
int flag, totpart, totchild, totcached, totchildcache;
|
||||
short recalc, target_psys, totkeyed, softflag, bakespace, rt2;
|
||||
|
||||
char bb_uvname[3][32]; /* billboard uv name */
|
||||
@@ -230,6 +229,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
|
||||
|
||||
/* point cache */
|
||||
struct PointCache *pointcache;
|
||||
|
||||
struct KDTree *tree; /* used for interactions with self and other systems */
|
||||
}ParticleSystem;
|
||||
|
||||
/* general particle maximums */
|
||||
@@ -325,7 +326,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
|
||||
//#define PART_DRAW_PATH_LEN 2
|
||||
#define PART_DRAW_SIZE 4
|
||||
#define PART_DRAW_EMITTER 8 /* render emitter also */
|
||||
//#define PART_DRAW_HEALTH 16
|
||||
#define PART_DRAW_HEALTH 16
|
||||
#define PART_ABS_PATH_TIME 32
|
||||
//#define PART_DRAW_TRAIL 64
|
||||
#define PART_DRAW_BB_LOCK 128
|
||||
@@ -460,26 +461,13 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
|
||||
#define PSYS_VG_ROT 10
|
||||
#define PSYS_VG_EFFECTOR 11
|
||||
|
||||
/* part->boidrules */
|
||||
#define BOID_TOT_RULES 8
|
||||
/* ParticleTarget->flag */
|
||||
#define PTARGET_CURRENT 1
|
||||
#define PTARGET_VALID 2
|
||||
|
||||
#define BOID_COLLIDE 0
|
||||
#define BOID_AVOID 1
|
||||
#define BOID_CROWD 2
|
||||
#define BOID_CENTER 3
|
||||
#define BOID_AV_VEL 4
|
||||
#define BOID_VEL_MATCH 5
|
||||
#define BOID_GOAL 6
|
||||
#define BOID_LEVEL 7
|
||||
|
||||
/* psys->keyed_targets->flag */
|
||||
#define KEYED_TARGET_CURRENT 1
|
||||
#define KEYED_TARGET_VALID 2
|
||||
|
||||
|
||||
//#define PSYS_INTER_CUBIC 0
|
||||
//#define PSYS_INTER_LINEAR 1
|
||||
//#define PSYS_INTER_CARDINAL 2
|
||||
//#define PSYS_INTER_BSPLINE 3
|
||||
/* ParticleTarget->mode */
|
||||
#define PTARGET_MODE_NEUTRAL 0
|
||||
#define PTARGET_MODE_FRIEND 1
|
||||
#define PTARGET_MODE_ENEMY 2
|
||||
|
||||
#endif
|
||||
|
||||
@@ -132,6 +132,7 @@ char *includefiles[] = {
|
||||
// of makesdna.c (this file) as well
|
||||
"DNA_windowmanager_types.h",
|
||||
"DNA_anim_types.h",
|
||||
"DNA_boid_types.h",
|
||||
|
||||
// empty string to indicate end of includefiles
|
||||
""
|
||||
@@ -1154,4 +1155,5 @@ int main(int argc, char ** argv)
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
/* end of list */
|
||||
|
||||
@@ -221,7 +221,7 @@ extern StructRNA RNA_Key;
|
||||
extern StructRNA RNA_KeyboardSensor;
|
||||
extern StructRNA RNA_KeyingSet;
|
||||
extern StructRNA RNA_KeyingSetPath;
|
||||
extern StructRNA RNA_KeyedParticleTarget;
|
||||
extern StructRNA RNA_ParticleTarget;
|
||||
extern StructRNA RNA_KinematicConstraint;
|
||||
extern StructRNA RNA_Lamp;
|
||||
extern StructRNA RNA_LampSkySettings;
|
||||
|
||||
@@ -34,6 +34,7 @@ extern EnumPropertyItem space_type_items[];
|
||||
extern EnumPropertyItem region_type_items[];
|
||||
extern EnumPropertyItem modifier_type_items[];
|
||||
extern EnumPropertyItem constraint_type_items[];
|
||||
extern EnumPropertyItem boidrule_type_items[];
|
||||
|
||||
extern EnumPropertyItem beztriple_handle_type_items[];
|
||||
extern EnumPropertyItem beztriple_interpolation_mode_items[];
|
||||
|
||||
@@ -1901,6 +1901,7 @@ RNAProcessItem PROCESS_ITEMS[]= {
|
||||
{"rna_animation.c", NULL, RNA_def_animation},
|
||||
{"rna_actuator.c", NULL, RNA_def_actuator},
|
||||
{"rna_armature.c", NULL, RNA_def_armature},
|
||||
{"rna_boid.c", NULL, RNA_def_boid},
|
||||
{"rna_brush.c", NULL, RNA_def_brush},
|
||||
{"rna_camera.c", NULL, RNA_def_camera},
|
||||
{"rna_cloth.c", NULL, RNA_def_cloth},
|
||||
|
||||
615
source/blender/makesrna/intern/rna_boid.c
Normal file
615
source/blender/makesrna/intern/rna_boid.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/**
|
||||
* $Id: rna_modifier.c 21514 2009-07-11 05:41:21Z aligorith $
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2009 by Janne Karhu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
EnumPropertyItem boidrule_type_items[] ={
|
||||
{eBoidRuleType_Goal, "GOAL", 0, "Goal", "Go to assigned object or loudest assigned signal source."},
|
||||
{eBoidRuleType_Avoid, "AVOID", 0, "Avoid", "Get away from assigned object or loudest assigned signal source."},
|
||||
{eBoidRuleType_AvoidCollision, "AVOID_COLLISION", 0, "Avoid Collision", "Monoeuver to avoid collisions with other boids and deflector objects in near future."},
|
||||
{eBoidRuleType_Separate, "SEPARATE", 0, "Separate", "Keep from going through other boids."},
|
||||
{eBoidRuleType_Flock, "FLOCK", 0, "Flock", "Move to center of neighbors and match their velocity."},
|
||||
{eBoidRuleType_FollowLeader, "FOLLOW_LEADER", 0, "Follow Leader", "Follow a boid or assigned object."},
|
||||
{eBoidRuleType_AverageSpeed, "AVERAGE_SPEED", 0, "Average Speed", "Maintain speed, flight level or wander."},
|
||||
{eBoidRuleType_Fight, "FIGHT", 0, "Fight", "Go to closest enemy and attack when in range."},
|
||||
//{eBoidRuleType_Protect, "PROTECT", 0, "Protect", "Go to enemy closest to target and attack when in range."},
|
||||
//{eBoidRuleType_Hide, "HIDE", 0, "Hide", "Find a deflector move to it's other side from closest enemy."},
|
||||
//{eBoidRuleType_FollowPath, "FOLLOW_PATH", 0, "Follow Path", "Move along a assigned curve or closest curve in a group."},
|
||||
//{eBoidRuleType_FollowWall, "FOLLOW_WALL", 0, "Follow Wall", "Move next to a deflector object's in direction of it's tangent."},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
EnumPropertyItem boidruleset_type_items[] ={
|
||||
{eBoidRulesetType_Fuzzy, "FUZZY", 0, "Fuzzy", "Rules are gone through top to bottom. Only the first rule that effect above fuzziness threshold is evaluated."},
|
||||
{eBoidRulesetType_Random, "RANDOM", 0, "Random", "A random rule is selected for each boid."},
|
||||
{eBoidRulesetType_Average, "AVERAGE", 0, "Average", "All rules are averaged."},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_particle.h"
|
||||
|
||||
static void rna_Boids_reset(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ParticleSettings *part;
|
||||
|
||||
if(ptr->type==&RNA_ParticleSystem) {
|
||||
ParticleSystem *psys = (ParticleSystem*)ptr->data;
|
||||
Object *ob = psys_find_object(scene, psys);
|
||||
|
||||
psys->recalc = PSYS_RECALC_RESET;
|
||||
|
||||
if(ob) {
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
part = ptr->id.data;
|
||||
psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
|
||||
}
|
||||
}
|
||||
static void rna_Boids_reset_deps(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ParticleSettings *part;
|
||||
|
||||
if(ptr->type==&RNA_ParticleSystem) {
|
||||
ParticleSystem *psys = (ParticleSystem*)ptr->data;
|
||||
Object *ob = psys_find_object(scene, psys);
|
||||
|
||||
psys->recalc = PSYS_RECALC_RESET;
|
||||
|
||||
if(ob) {
|
||||
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
part = ptr->id.data;
|
||||
psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
|
||||
DAG_scene_sort(scene);
|
||||
}
|
||||
}
|
||||
|
||||
static StructRNA* rna_BoidRule_refine(struct PointerRNA *ptr)
|
||||
{
|
||||
BoidRule *rule= (BoidRule*)ptr->data;
|
||||
|
||||
switch(rule->type) {
|
||||
case eBoidRuleType_Goal:
|
||||
return &RNA_BoidRuleGoal;
|
||||
case eBoidRuleType_Avoid:
|
||||
return &RNA_BoidRuleAvoid;
|
||||
case eBoidRuleType_AvoidCollision:
|
||||
return &RNA_BoidRuleAvoidCollision;
|
||||
case eBoidRuleType_FollowLeader:
|
||||
return &RNA_BoidRuleFollowLeader;
|
||||
case eBoidRuleType_AverageSpeed:
|
||||
return &RNA_BoidRuleAverageSpeed;
|
||||
case eBoidRuleType_Fight:
|
||||
return &RNA_BoidRuleFight;
|
||||
default:
|
||||
return &RNA_BoidRule;
|
||||
}
|
||||
}
|
||||
|
||||
static char *rna_BoidRule_path(PointerRNA *ptr)
|
||||
{
|
||||
return BLI_sprintfN("rules[%s]", ((BoidRule*)ptr->data)->name); // XXX not unique
|
||||
}
|
||||
|
||||
static PointerRNA rna_BoidState_active_boid_rule_get(PointerRNA *ptr)
|
||||
{
|
||||
BoidState *state= (BoidState*)ptr->data;
|
||||
BoidRule *rule = (BoidRule*)state->rules.first;
|
||||
|
||||
for(; rule; rule=rule->next) {
|
||||
if(rule->flag & BOIDRULE_CURRENT)
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_BoidRule, rule);
|
||||
}
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_BoidRule, NULL);
|
||||
}
|
||||
static void rna_BoidState_active_boid_rule_index_range(PointerRNA *ptr, int *min, int *max)
|
||||
{
|
||||
BoidState *state= (BoidState*)ptr->data;
|
||||
*min= 0;
|
||||
*max= BLI_countlist(&state->rules)-1;
|
||||
*max= MAX2(0, *max);
|
||||
}
|
||||
|
||||
static int rna_BoidState_active_boid_rule_index_get(PointerRNA *ptr)
|
||||
{
|
||||
BoidState *state= (BoidState*)ptr->data;
|
||||
BoidRule *rule = (BoidRule*)state->rules.first;
|
||||
int i=0;
|
||||
|
||||
for(; rule; rule=rule->next, i++) {
|
||||
if(rule->flag & BOIDRULE_CURRENT)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_BoidState_active_boid_rule_index_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
BoidState *state= (BoidState*)ptr->data;
|
||||
BoidRule *rule = (BoidRule*)state->rules.first;
|
||||
int i=0;
|
||||
|
||||
for(; rule; rule=rule->next, i++) {
|
||||
if(i==value)
|
||||
rule->flag |= BOIDRULE_CURRENT;
|
||||
else
|
||||
rule->flag &= ~BOIDRULE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
static PointerRNA rna_BoidSettings_active_boid_state_get(PointerRNA *ptr)
|
||||
{
|
||||
BoidSettings *boids= (BoidSettings*)ptr->data;
|
||||
BoidState *state = (BoidState*)boids->states.first;
|
||||
|
||||
for(; state; state=state->next) {
|
||||
if(state->flag & BOIDSTATE_CURRENT)
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_BoidState, state);
|
||||
}
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_BoidState, NULL);
|
||||
}
|
||||
static void rna_BoidSettings_active_boid_state_index_range(PointerRNA *ptr, int *min, int *max)
|
||||
{
|
||||
BoidSettings *boids= (BoidSettings*)ptr->data;
|
||||
*min= 0;
|
||||
*max= BLI_countlist(&boids->states)-1;
|
||||
*max= MAX2(0, *max);
|
||||
}
|
||||
|
||||
static int rna_BoidSettings_active_boid_state_index_get(PointerRNA *ptr)
|
||||
{
|
||||
BoidSettings *boids= (BoidSettings*)ptr->data;
|
||||
BoidState *state = (BoidState*)boids->states.first;
|
||||
int i=0;
|
||||
|
||||
for(; state; state=state->next, i++) {
|
||||
if(state->flag & BOIDSTATE_CURRENT)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_BoidSettings_active_boid_state_index_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
BoidSettings *boids= (BoidSettings*)ptr->data;
|
||||
BoidState *state = (BoidState*)boids->states.first;
|
||||
int i=0;
|
||||
|
||||
for(; state; state=state->next, i++) {
|
||||
if(i==value)
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
else
|
||||
state->flag &= ~BOIDSTATE_CURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_boidrule_goal(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleGoal", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Goal", "");
|
||||
RNA_def_struct_sdna(srna, "BoidRuleGoalAvoid");
|
||||
|
||||
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ob");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Goal object.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset_deps");
|
||||
|
||||
prop= RNA_def_property(srna, "predict", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BRULE_GOAL_AVOID_PREDICT);
|
||||
RNA_def_property_ui_text(prop, "Predict", "Predict target movement.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule_avoid(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleAvoid", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Avoid", "");
|
||||
RNA_def_struct_sdna(srna, "BoidRuleGoalAvoid");
|
||||
|
||||
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ob");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Object to avoid.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset_deps");
|
||||
|
||||
prop= RNA_def_property(srna, "predict", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BRULE_GOAL_AVOID_PREDICT);
|
||||
RNA_def_property_ui_text(prop, "Predict", "Predict target movement.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "fear_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Fear factor", "Avoid object if danger from it is above this threshol.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule_avoid_collision(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleAvoidCollision", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Avoid Collision", "");
|
||||
|
||||
prop= RNA_def_property(srna, "boids", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BRULE_ACOLL_WITH_BOIDS);
|
||||
RNA_def_property_ui_text(prop, "Boids", "Avoid collision with other boids.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "deflectors", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BRULE_ACOLL_WITH_DEFLECTORS);
|
||||
RNA_def_property_ui_text(prop, "Deflectors", "Avoid collision with deflector objects.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "look_ahead", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Look ahead", "Time to look ahead in seconds.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule_follow_leader(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleFollowLeader", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Follow Leader", "");
|
||||
|
||||
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ob");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Follow this object instead of a boid.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset_deps");
|
||||
|
||||
prop= RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Distance", "Distance behind leader to follow.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "queue_size", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Queue Size", "How many boids in a line.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "line", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BRULE_LEADER_IN_LINE);
|
||||
RNA_def_property_ui_text(prop, "Line", "Follow leader in a line.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule_average_speed(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleAverageSpeed", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Average Speed", "");
|
||||
|
||||
prop= RNA_def_property(srna, "wander", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Wander", "How fast velocity's direction is randomized.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "level", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Level", "How much velocity's z-component is kept constant.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Speed", "Percentage of maximum speed.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule_fight(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna= RNA_def_struct(brna, "BoidRuleFight", "BoidRule");
|
||||
RNA_def_struct_ui_text(srna, "Fight", "");
|
||||
|
||||
prop= RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Fight Distance", "Attack boids at max this distance.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "flee_distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Flee Distance", "Flee to this distance.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
static void rna_def_boidrule(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* data */
|
||||
srna= RNA_def_struct(brna, "BoidRule", NULL);
|
||||
RNA_def_struct_ui_text(srna , "Boid Rule", "");
|
||||
RNA_def_struct_refine_func(srna, "rna_BoidRule_refine");
|
||||
RNA_def_struct_path_func(srna, "rna_BoidRule_path");
|
||||
|
||||
/* strings */
|
||||
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Boid rule name.");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
/* enums */
|
||||
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, boidrule_type_items);
|
||||
RNA_def_property_ui_text(prop, "Type", "");
|
||||
|
||||
/* flags */
|
||||
prop= RNA_def_property(srna, "in_air", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", BOIDRULE_IN_AIR);
|
||||
RNA_def_property_ui_text(prop, "In Air", "Use rule when boid is flying.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "on_land", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", BOIDRULE_ON_LAND);
|
||||
RNA_def_property_ui_text(prop, "On Land", "Use rule when boid is on land.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
//prop= RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE);
|
||||
//RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Expanded);
|
||||
//RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface.");
|
||||
|
||||
/* types */
|
||||
rna_def_boidrule_goal(brna);
|
||||
rna_def_boidrule_avoid(brna);
|
||||
rna_def_boidrule_avoid_collision(brna);
|
||||
rna_def_boidrule_follow_leader(brna);
|
||||
rna_def_boidrule_average_speed(brna);
|
||||
rna_def_boidrule_fight(brna);
|
||||
}
|
||||
|
||||
static void rna_def_boidstate(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "BoidState", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Boid State", "Boid state for boid physics.");
|
||||
|
||||
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Boid state name.");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
prop= RNA_def_property(srna, "ruleset_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, boidruleset_type_items);
|
||||
RNA_def_property_ui_text(prop, "Rule Evaluation", "How the rules in the list are evaluated.");
|
||||
|
||||
prop= RNA_def_property(srna, "rules", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoidRule");
|
||||
RNA_def_property_ui_text(prop, "Boid Rules", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_boid_rule", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoidRule");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_BoidState_active_boid_rule_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Boid Rule", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_boid_rule_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_funcs(prop, "rna_BoidState_active_boid_rule_index_get", "rna_BoidState_active_boid_rule_index_set", "rna_BoidState_active_boid_rule_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Boid Rule Index", "");
|
||||
|
||||
prop= RNA_def_property(srna, "rule_fuzziness", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Rule Fuzzines", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Volume", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 10.0);
|
||||
RNA_def_property_ui_text(prop, "Falloff", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
static void rna_def_boid_settings(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "BoidSettings", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Boid Settings", "Settings for boid physics.");
|
||||
|
||||
prop= RNA_def_property(srna, "landing_smoothness", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 10.0);
|
||||
RNA_def_property_ui_text(prop, "Landing Smoothness", "How smoothly the boids land.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "banking", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 2.0);
|
||||
RNA_def_property_ui_text(prop, "Banking", "Amount of rotation around velocity vector on turns.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 2.0);
|
||||
RNA_def_property_ui_text(prop, "Height", "Boid height relative to particle size.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
/* states */
|
||||
prop= RNA_def_property(srna, "states", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoidState");
|
||||
RNA_def_property_ui_text(prop, "Boid States", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_boid_state", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoidRule");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_BoidSettings_active_boid_state_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Boid Rule", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_boid_state_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_funcs(prop, "rna_BoidSettings_active_boid_state_index_get", "rna_BoidSettings_active_boid_state_index_set", "rna_BoidSettings_active_boid_state_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Boid State Index", "");
|
||||
|
||||
/* character properties */
|
||||
prop= RNA_def_property(srna, "health", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Health", "Initial boid health when born.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Strength", "Maximum caused damage on attack per second.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "aggression", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Aggression", "Boid will fight this times stronger enemy.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "accuracy", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Accuracy", "Accuracy of attack.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "range", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Range", "The maximum distance from which a boid can attack.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
/* physical properties */
|
||||
prop= RNA_def_property(srna, "air_min_speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Min Air Speed", "Minimum speed in air (relative to maximum speed).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "air_max_speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Max Air Speed", "Maximum speed in air.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "air_max_acc", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Max Air Acceleration", "Maximum acceleration in air (relative to maximum speed).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "air_max_ave", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Max Air Angular Velocity", "Maximum angular velocity in air (relative to 180 degrees).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "air_personal_space", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 10.0);
|
||||
RNA_def_property_ui_text(prop, "Air Personal Space", "Radius of boids personal space in air (% of particle size).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_jump_speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Jump Speed", "Maximum speed for jumping.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_max_speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 100.0);
|
||||
RNA_def_property_ui_text(prop, "Max Land Speed", "Maximum speed on land.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_max_acc", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Max Land Acceleration", "Maximum acceleration on land (relative to maximum speed).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_max_ave", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Max Land Angular Velocity", "Maximum angular velocity on land (relative to 180 degrees).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_personal_space", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 10.0);
|
||||
RNA_def_property_ui_text(prop, "Land Personal Space", "Radius of boids personal space on land (% of particle size).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "land_stick_force", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0, 1000.0);
|
||||
RNA_def_property_ui_text(prop, "Land Stick Force", "How strong a force must be to start effecting a boid on land.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
/* options */
|
||||
prop= RNA_def_property(srna, "allow_flight", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BOID_ALLOW_FLIGHT);
|
||||
RNA_def_property_ui_text(prop, "Allow Flight", "Allow boids to move in air.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "allow_land", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BOID_ALLOW_LAND);
|
||||
RNA_def_property_ui_text(prop, "Allow Land", "Allow boids to move on land.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "allow_climb", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "options", BOID_ALLOW_CLIMB);
|
||||
RNA_def_property_ui_text(prop, "Allow Climbing", "Allow boids to climb goal objects.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Boids_reset");
|
||||
}
|
||||
|
||||
void RNA_def_boid(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_boidrule(brna);
|
||||
rna_def_boidstate(brna);
|
||||
rna_def_boid_settings(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -93,7 +93,7 @@ static void rna_FluidSettings_update_type(bContext *C, PointerRNA *ptr)
|
||||
|
||||
if(ob->type == OB_MESH && !psys) {
|
||||
/* add particle system */
|
||||
part= psys_new_settings("PSys", bmain);
|
||||
part= psys_new_settings("ParticleSettings", bmain);
|
||||
psys= MEM_callocN(sizeof(ParticleSystem), "particle_system");
|
||||
|
||||
part->type= PART_FLUID;
|
||||
|
||||
@@ -117,6 +117,7 @@ void RNA_def_action(struct BlenderRNA *brna);
|
||||
void RNA_def_animation(struct BlenderRNA *brna);
|
||||
void RNA_def_armature(struct BlenderRNA *brna);
|
||||
void RNA_def_actuator(struct BlenderRNA *brna);
|
||||
void RNA_def_boid(struct BlenderRNA *brna);
|
||||
void RNA_def_brush(struct BlenderRNA *brna);
|
||||
void RNA_def_brushclone(struct BlenderRNA *brna);
|
||||
void RNA_def_camera(struct BlenderRNA *brna);
|
||||
|
||||
@@ -284,7 +284,7 @@ static void rna_FieldSettings_surface_update(bContext *C, PointerRNA *ptr)
|
||||
/* add/remove modifier as needed */
|
||||
if(!md) {
|
||||
if(pd && (pd->flag & PFIELD_SURFACE))
|
||||
if(ELEM5(pd->forcefield,PFIELD_HARMONIC,PFIELD_FORCE,PFIELD_HARMONIC,PFIELD_CHARGE,PFIELD_LENNARDJ))
|
||||
if(ELEM6(pd->forcefield,PFIELD_HARMONIC,PFIELD_FORCE,PFIELD_HARMONIC,PFIELD_CHARGE,PFIELD_LENNARDJ,PFIELD_BOID))
|
||||
if(ELEM4(ob->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
|
||||
ED_object_modifier_add(NULL, scene, ob, eModifierType_Surface);
|
||||
}
|
||||
@@ -504,6 +504,7 @@ static void rna_def_field(BlenderRNA *brna)
|
||||
{PFIELD_HARMONIC, "HARMONIC", 0, "Harmonic", ""},
|
||||
{PFIELD_CHARGE, "CHARGE", 0, "Charge", ""},
|
||||
{PFIELD_LENNARDJ, "LENNARDJ", 0, "Lennard-Jones", ""},
|
||||
{PFIELD_BOID, "BOID", 0, "Boid", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem falloff_items[] = {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_types.h"
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
@@ -36,6 +37,7 @@
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_boid_types.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
#include "WM_api.h"
|
||||
@@ -140,13 +142,33 @@ static void rna_Particle_reset(bContext *C, PointerRNA *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Particle_keyed_reset(bContext *C, PointerRNA *ptr)
|
||||
static void rna_Particle_target_reset(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
if(ptr->type==&RNA_KeyedParticleTarget) {
|
||||
if(ptr->type==&RNA_ParticleTarget) {
|
||||
ParticleTarget *pt = (ParticleTarget*)ptr->data;
|
||||
Object *ob = (Object*)ptr->id.data;
|
||||
ParticleSystem *psys = psys_get_current(ob);
|
||||
ParticleSystem *kpsys=NULL, *psys=psys_get_current(ob);
|
||||
int psys_num = BLI_findindex(&ob->particlesystem, psys);
|
||||
|
||||
if(pt->ob==ob || pt->ob==NULL) {
|
||||
kpsys = BLI_findlink(&ob->particlesystem, pt->psys-1);
|
||||
|
||||
if(kpsys)
|
||||
pt->flag |= PTARGET_VALID;
|
||||
else
|
||||
pt->flag &= ~PTARGET_VALID;
|
||||
}
|
||||
else {
|
||||
if(pt->ob)
|
||||
kpsys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
|
||||
|
||||
if(kpsys)
|
||||
pt->flag |= PTARGET_VALID;
|
||||
else
|
||||
pt->flag &= ~PTARGET_VALID;
|
||||
}
|
||||
|
||||
psys->recalc = PSYS_RECALC_RESET;
|
||||
|
||||
@@ -155,11 +177,11 @@ static void rna_Particle_keyed_reset(bContext *C, PointerRNA *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Particle_keyed_redo(bContext *C, PointerRNA *ptr)
|
||||
static void rna_Particle_target_redo(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
if(ptr->type==&RNA_KeyedParticleTarget) {
|
||||
if(ptr->type==&RNA_ParticleTarget) {
|
||||
Object *ob = (Object*)ptr->id.data;
|
||||
ParticleSystem *psys = psys_get_current(ob);
|
||||
|
||||
@@ -235,8 +257,10 @@ static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
|
||||
|
||||
psys->part = (ParticleSettings *)value.data;
|
||||
|
||||
if(psys->part)
|
||||
if(psys->part) {
|
||||
psys->part->id.us++;
|
||||
psys_check_boid_data(psys);
|
||||
}
|
||||
}
|
||||
static void rna_Particle_abspathtime_update(bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
@@ -315,97 +339,100 @@ static float rna_PartSetting_linelenhead_get(struct PointerRNA *ptr)
|
||||
return settings->draw_line[1];
|
||||
}
|
||||
|
||||
static int rna_ParticleSystem_name_length(PointerRNA *ptr)
|
||||
{
|
||||
ParticleSystem *psys= ptr->data;
|
||||
|
||||
if(psys->part)
|
||||
return strlen(psys->part->id.name+2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_ParticleSystem_name_get(PointerRNA *ptr, char *str)
|
||||
{
|
||||
ParticleSystem *psys= ptr->data;
|
||||
|
||||
if(psys->part)
|
||||
strcpy(str, psys->part->id.name+2);
|
||||
else
|
||||
strcpy(str, "");
|
||||
}
|
||||
|
||||
static PointerRNA rna_ParticleSystem_active_keyed_target_get(PointerRNA *ptr)
|
||||
static PointerRNA rna_ParticleSystem_active_particle_target_get(PointerRNA *ptr)
|
||||
{
|
||||
ParticleSystem *psys= (ParticleSystem*)ptr->data;
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
|
||||
for(; kpt; kpt=kpt->next) {
|
||||
if(kpt->flag & KEYED_TARGET_CURRENT)
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, kpt);
|
||||
for(; pt; pt=pt->next) {
|
||||
if(pt->flag & PTARGET_CURRENT)
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_ParticleTarget, pt);
|
||||
}
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, NULL);
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_ParticleTarget, NULL);
|
||||
}
|
||||
static void rna_ParticleSystem_active_keyed_target_index_range(PointerRNA *ptr, int *min, int *max)
|
||||
static void rna_ParticleSystem_active_particle_target_index_range(PointerRNA *ptr, int *min, int *max)
|
||||
{
|
||||
ParticleSystem *psys= (ParticleSystem*)ptr->data;
|
||||
*min= 0;
|
||||
*max= BLI_countlist(&psys->keyed_targets)-1;
|
||||
*max= BLI_countlist(&psys->targets)-1;
|
||||
*max= MAX2(0, *max);
|
||||
}
|
||||
|
||||
static int rna_ParticleSystem_active_keyed_target_index_get(PointerRNA *ptr)
|
||||
static int rna_ParticleSystem_active_particle_target_index_get(PointerRNA *ptr)
|
||||
{
|
||||
ParticleSystem *psys= (ParticleSystem*)ptr->data;
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
int i=0;
|
||||
|
||||
for(; kpt; kpt=kpt->next, i++)
|
||||
if(kpt->flag & KEYED_TARGET_CURRENT)
|
||||
for(; pt; pt=pt->next, i++)
|
||||
if(pt->flag & PTARGET_CURRENT)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_ParticleSystem_active_keyed_target_index_set(struct PointerRNA *ptr, int value)
|
||||
static void rna_ParticleSystem_active_particle_target_index_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
ParticleSystem *psys= (ParticleSystem*)ptr->data;
|
||||
KeyedParticleTarget *kpt = psys->keyed_targets.first;
|
||||
ParticleTarget *pt = psys->targets.first;
|
||||
int i=0;
|
||||
|
||||
for(; kpt; kpt=kpt->next, i++) {
|
||||
for(; pt; pt=pt->next, i++) {
|
||||
if(i==value)
|
||||
kpt->flag |= KEYED_TARGET_CURRENT;
|
||||
pt->flag |= PTARGET_CURRENT;
|
||||
else
|
||||
kpt->flag &= ~KEYED_TARGET_CURRENT;
|
||||
pt->flag &= ~PTARGET_CURRENT;
|
||||
}
|
||||
}
|
||||
static int rna_KeyedParticleTarget_name_length(PointerRNA *ptr)
|
||||
static int rna_ParticleTarget_name_length(PointerRNA *ptr)
|
||||
{
|
||||
KeyedParticleTarget *kpt= ptr->data;
|
||||
ParticleTarget *pt= ptr->data;
|
||||
|
||||
if(kpt->flag & KEYED_TARGET_VALID) {
|
||||
if(kpt->ob)
|
||||
return strlen(kpt->ob->id.name+2) + 4;
|
||||
if(pt->flag & PTARGET_VALID) {
|
||||
ParticleSystem *psys = NULL;
|
||||
|
||||
if(pt->ob)
|
||||
psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
|
||||
else {
|
||||
Object *ob = (Object*) ptr->id.data;
|
||||
psys = BLI_findlink(&ob->particlesystem, pt->psys-1);
|
||||
}
|
||||
|
||||
if(psys) {
|
||||
if(pt->ob)
|
||||
return strlen(pt->ob->id.name+2) + 2 + strlen(psys->name);
|
||||
else
|
||||
return strlen(psys->name);
|
||||
}
|
||||
else
|
||||
return 20;
|
||||
return 15;
|
||||
}
|
||||
else
|
||||
return 15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rna_KeyedParticleTarget_name_get(PointerRNA *ptr, char *str)
|
||||
static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str)
|
||||
{
|
||||
KeyedParticleTarget *kpt= ptr->data;
|
||||
ParticleTarget *pt= ptr->data;
|
||||
|
||||
if(kpt->flag & KEYED_TARGET_VALID) {
|
||||
if(kpt->ob)
|
||||
sprintf(str, "%s: %i", kpt->ob->id.name+2, kpt->psys);
|
||||
if(pt->flag & PTARGET_VALID) {
|
||||
ParticleSystem *psys = NULL;
|
||||
|
||||
if(pt->ob)
|
||||
psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
|
||||
else {
|
||||
Object *ob = (Object*) ptr->id.data;
|
||||
psys = BLI_findlink(&ob->particlesystem, pt->psys-1);
|
||||
}
|
||||
|
||||
if(psys) {
|
||||
if(pt->ob)
|
||||
sprintf(str, "%s: %s", pt->ob->id.name+2, psys->name);
|
||||
else
|
||||
strcpy(str, psys->name);
|
||||
}
|
||||
else
|
||||
sprintf(str, "Particle System: %i", kpt->psys);
|
||||
|
||||
strcpy(str, "Invalid target!");
|
||||
}
|
||||
else
|
||||
strcpy(str, "Invalid target!");
|
||||
@@ -636,10 +663,10 @@ static void rna_def_particle(BlenderRNA *brna)
|
||||
// RNA_def_property_range(prop, lowerLimitf, upperLimitf);
|
||||
RNA_def_property_ui_text(prop, "Die Time", "");
|
||||
|
||||
prop= RNA_def_property(srna, "banking_angle", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "bank");
|
||||
// RNA_def_property_range(prop, lowerLimitf, upperLimitf);
|
||||
RNA_def_property_ui_text(prop, "Banking Angle", "");
|
||||
// prop= RNA_def_property(srna, "banking_angle", PROP_FLOAT, PROP_NONE);
|
||||
// RNA_def_property_float_sdna(prop, NULL, "bank");
|
||||
//// RNA_def_property_range(prop, lowerLimitf, upperLimitf);
|
||||
// RNA_def_property_ui_text(prop, "Banking Angle", "");
|
||||
|
||||
prop= RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
|
||||
// RNA_def_property_range(prop, lowerLimitf, upperLimitf);
|
||||
@@ -1024,10 +1051,10 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
//prop= RNA_def_property(srna, "draw_health", PROP_BOOLEAN, PROP_NONE);
|
||||
//RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH);
|
||||
//RNA_def_property_ui_text(prop, "Health", "Draw boid health");
|
||||
//RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
prop= RNA_def_property(srna, "draw_health", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH);
|
||||
RNA_def_property_ui_text(prop, "Health", "Draw boid health");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "abs_path_time", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_ABS_PATH_TIME);
|
||||
@@ -1149,9 +1176,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
|
||||
//interpolation
|
||||
//TODO: can't find where interpolation is used
|
||||
|
||||
//TODO: is this read only/internal?
|
||||
prop= RNA_def_property(srna, "rotate_from", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "rotfrom");
|
||||
@@ -1173,19 +1197,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Axis", "Which axis to use for offset");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
|
||||
|
||||
/* used?
|
||||
prop= RNA_def_property(srna, "inbetween", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "nbetween");
|
||||
RNA_def_property_range(prop, 0, INT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Inbetween", "");
|
||||
*/
|
||||
|
||||
prop= RNA_def_property(srna, "boid_neighbours", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "boidneighbours");
|
||||
RNA_def_property_range(prop, 1, 10);
|
||||
RNA_def_property_ui_text(prop, "Neighbours", "How many neighbours to consider for each boid");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
/* billboards */
|
||||
prop= RNA_def_property(srna, "billboard_align", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "bb_align");
|
||||
@@ -1421,6 +1432,12 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Acceleration", "Constant acceleration");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "acc[2]");
|
||||
RNA_def_property_range(prop, -200.0f, 200.0f);
|
||||
RNA_def_property_ui_text(prop, "Gravity", "Constant acceleration in global Z axis direction");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "drag_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "dragfac");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
@@ -1619,46 +1636,12 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
/* boids */
|
||||
prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "max_vel");
|
||||
RNA_def_property_range(prop, 0.0f, 200.0f);
|
||||
RNA_def_property_ui_text(prop, "Maximum Velocity", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
prop= RNA_def_property(srna, "boids", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoidSettings");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Boid Settings", "");
|
||||
|
||||
prop= RNA_def_property(srna, "lateral_acceleration_max", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "max_lat_acc");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Lateral Acceleration", "Lateral acceleration % of max velocity");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "tangential_acceleration_max", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "max_tan_acc");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Tangential acceleration", "Tangential acceleration % of max velocity");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "average_velocity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "average_vel");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Average Velocity", "The usual speed % of max velocity");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "banking", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, -10.0f, 10.0f);
|
||||
RNA_def_property_ui_text(prop, "Banking", "Banking of boids on turns (1.0==natural banking)");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "banking_max", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "max_bank");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Maximum Banking", "How much a boid can bank at a single step");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "ground_z", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "groundz");
|
||||
RNA_def_property_range(prop, -100.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Ground Z", "Default Z value");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
/* draw objects & groups */
|
||||
|
||||
prop= RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
|
||||
@@ -1667,13 +1650,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Dupli Group", "Show Objects in this Group in place of particles");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "effector_group", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
|
||||
RNA_def_property_struct_type(prop, "Group");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Effector Group", "Limit effectors to this Group.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "dupli_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "dup_ob");
|
||||
RNA_def_property_struct_type(prop, "Object");
|
||||
@@ -1687,6 +1663,74 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Billboard Object", "Billboards face this object (default is active camera)");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
/* effectors */
|
||||
prop= RNA_def_property(srna, "effector_group", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
|
||||
RNA_def_property_struct_type(prop, "Group");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Effector Group", "Limit effectors to this Group.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_all", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[0]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "All", "All effector's weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_spherical", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[1]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Spherical", "Spherical effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_vortex", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[2]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Vortex", "Vortex effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_magnetic", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[3]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Magnetic", "Magnetic effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_wind", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[4]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Wind", "Wind effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_curveguide", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[5]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Curve Guide", "Curve guide effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_texture", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[6]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Magnetic", "Texture effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_harmonic", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[7]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Harmonic", "Harmonic effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_charge", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[8]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Charge", "Charge effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "eweight_lennardjones", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "effector_weight[9]");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Lennard-Jones", "Lennard-Jones effector weight.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
/* animation here? */
|
||||
rna_def_animdata_common(srna);
|
||||
@@ -1695,17 +1739,25 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
// struct PartDeflect *pd2;
|
||||
}
|
||||
|
||||
static void rna_def_keyed_particle_target(BlenderRNA *brna)
|
||||
static void rna_def_particle_target(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "KeyedParticleTarget", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Keyed Particle Target", "Target particle system for keyed particles.");
|
||||
static EnumPropertyItem mode_items[] = {
|
||||
{PTARGET_MODE_FRIEND, "FRIEND", 0, "Friend", ""},
|
||||
{PTARGET_MODE_NEUTRAL, "NEUTRAL", 0, "Neutral", ""},
|
||||
{PTARGET_MODE_ENEMY, "ENEMY", 0, "Enemy", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
srna = RNA_def_struct(brna, "ParticleTarget", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Particle Target", "Target particle system.");
|
||||
|
||||
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, "rna_KeyedParticleTarget_name_get", "rna_KeyedParticleTarget_name_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "Name", "Keyed particle target name.");
|
||||
RNA_def_property_string_funcs(prop, "rna_ParticleTarget_name_get", "rna_ParticleTarget_name_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "Name", "Particle target name.");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
@@ -1713,32 +1765,36 @@ static void rna_def_keyed_particle_target(BlenderRNA *brna)
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ob");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Target Object", "The object that has the target particle system (empty if same object).");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_target_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "system", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, NULL, "psys");
|
||||
RNA_def_property_range(prop, 1, INT_MAX);
|
||||
RNA_def_property_ui_text(prop, "Target Particle System", "The index of particle system on the target object.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_target_reset");
|
||||
|
||||
prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "time");
|
||||
RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
|
||||
RNA_def_property_ui_text(prop, "Time", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_target_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "duration", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "duration");
|
||||
RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
|
||||
RNA_def_property_ui_text(prop, "Duration", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_target_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "valid", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYED_TARGET_VALID);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTARGET_VALID);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
|
||||
RNA_def_property_ui_text(prop, "Valid", "Keyed particles target is valid.");
|
||||
|
||||
|
||||
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, mode_items);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
|
||||
RNA_def_property_ui_text(prop, "Mode", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_target_reset");
|
||||
|
||||
}
|
||||
static void rna_def_particle_system(BlenderRNA *brna)
|
||||
@@ -1751,9 +1807,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
|
||||
RNA_def_struct_ui_icon(srna, ICON_PARTICLE_DATA);
|
||||
|
||||
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, "rna_ParticleSystem_name_get", "rna_ParticleSystem_name_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "Name", "Particle system name.");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
/* access to particle settings is redirected through functions */
|
||||
@@ -1807,13 +1861,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Reactor Target Particle System", "For reactor systems, index of particle system on the target object.");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
/* boids */
|
||||
//prop= RNA_def_property(srna, "boids_surface_object", PROP_POINTER, PROP_NONE);
|
||||
//RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob");
|
||||
//RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
//RNA_def_property_ui_text(prop, "Boids Surface Object", "For boids physics systems, constrain boids to this object's surface.");
|
||||
//RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
|
||||
|
||||
/* keyed */
|
||||
prop= RNA_def_property(srna, "keyed_timing", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING);
|
||||
@@ -1821,19 +1868,18 @@ static void rna_def_particle_system(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Keyed timing", "Use key times");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "keyed_targets", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "keyed_targets", NULL);
|
||||
RNA_def_property_struct_type(prop, "KeyedParticleTarget");
|
||||
RNA_def_property_ui_text(prop, "Keyed Targets", "Target particle systems for keyed particles");
|
||||
prop= RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ParticleTarget");
|
||||
RNA_def_property_ui_text(prop, "Targets", "Target particle systems.");
|
||||
|
||||
prop= RNA_def_property(srna, "active_keyed_target", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "KeyedParticleTarget");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_ParticleSystem_active_keyed_target_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Particle System", "Active particle system being displayed");
|
||||
prop= RNA_def_property(srna, "active_particle_target", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ParticleTarget");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_ParticleSystem_active_particle_target_get", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Particle Target", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_keyed_target_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_funcs(prop, "rna_ParticleSystem_active_keyed_target_index_get", "rna_ParticleSystem_active_keyed_target_index_set", "rna_ParticleSystem_active_keyed_target_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Particle System Index", "Index of active particle system slot.");
|
||||
prop= RNA_def_property(srna, "active_particle_target_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_funcs(prop, "rna_ParticleSystem_active_particle_target_index_get", "rna_ParticleSystem_active_particle_target_index_set", "rna_ParticleSystem_active_particle_target_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Particle Target Index", "");
|
||||
|
||||
|
||||
/* billboard */
|
||||
@@ -1989,11 +2035,13 @@ static void rna_def_particle_system(BlenderRNA *brna)
|
||||
|
||||
void RNA_def_particle(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_particle_target(brna);
|
||||
|
||||
rna_def_particle_hair_key(brna);
|
||||
rna_def_particle_key(brna);
|
||||
|
||||
rna_def_child_particle(brna);
|
||||
rna_def_particle(brna);
|
||||
rna_def_keyed_particle_target(brna);
|
||||
rna_def_particle_system(brna);
|
||||
rna_def_particle_settings(brna);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user