General particle bug fixes + few small goodies

The goodies:
* Curves can be used as normal dynamic effectors too with 
  the new "curve" field shape.
* Group visualization has optional duplication counts for
  each object in the specified group.
* Object & group visualizations, which are done without
  taking the dupliobject's global position into account
  (unless the whole group is used). This is much nicer than
  the previous behavior, but I added a "Use Global Location"
  option for those who want to use it the old way.
* The active particle system's particles are now drawn a 
  with theme coloured outline instead of pure white.
* Added object aligned velocity factors (buttons categorized
  and re-organized too).

Bug fixes:
* Absorption didn't work as the ui toggle button was forgotten.
* Some other force field ui tweaks.
* Crash after adding children and changing trails count.
* Display types "cross" and "axis" crashed.
* Particles weren't drawn with correct coloring.
* Billboards didn't update properly in viewport to camera
  location changes.
* Particle rotation wasn't recreated correctly from point cache.
* Changing particles amount crashed sometimes.
* Some files with child hair crashed on loading.
* Compiler warning fixes.
* Adding boids crashed on frame 1;
This commit is contained in:
Janne Karhu 2009-10-05 13:25:56 +00:00
parent a344977147
commit 3816554cbc
23 changed files with 883 additions and 332 deletions

@ -121,17 +121,19 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
layout.enabled = particle_panel_enabled(psys) and not psys.multiple_caches
row = layout.row()
row.active = part.distribution != 'GRID'
row.itemR(part, "amount")
split = layout.split()
col = split.column(align=True)
col.itemR(part, "start")
col.itemR(part, "end")
if part.type != 'HAIR':
split = layout.split()
col = split.column(align=True)
col.itemR(part, "start")
col.itemR(part, "end")
col = split.column(align=True)
col.itemR(part, "lifetime")
col.itemR(part, "random_lifetime", slider=True)
col = split.column(align=True)
col.itemR(part, "lifetime")
col.itemR(part, "random_lifetime", slider=True)
layout.row().itemL(text="Emit From:")
@ -221,7 +223,7 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
point_cache_ui(self, psys.point_cache, particle_panel_enabled(psys), not psys.hair_dynamics, 0)
class PARTICLE_PT_initial(ParticleButtonsPanel):
class PARTICLE_PT_velocity(ParticleButtonsPanel):
__label__ = "Velocity"
def poll(self, context):
@ -238,48 +240,66 @@ class PARTICLE_PT_initial(ParticleButtonsPanel):
part = psys.settings
layout.enabled = particle_panel_enabled(psys)
layout.row().itemL(text="Direction:")
split = layout.split()
sub = split.column()
sub.itemL(text="Emitter Geometry:")
sub.itemR(part, "normal_factor")
subsub = sub.column(align=True)
subsub.itemR(part, "tangent_factor")
subsub.itemR(part, "tangent_phase", slider=True)
sub = split.column()
sub.itemL(text="Emitter Object")
sub.itemR(part, "object_aligned_factor", text="")
layout.row().itemL(text="Other:")
split = layout.split()
sub = split.column()
if part.emit_from=='PARTICLE':
sub.itemR(part, "particle_factor")
else:
sub.itemR(part, "object_factor", slider=True)
sub = split.column()
sub.itemR(part, "random_factor")
sub.itemR(part, "tangent_factor")
sub.itemR(part, "tangent_phase", slider=True)
sub = split.column()
sub.itemL(text="TODO:")
sub.itemL(text="Object aligned")
sub.itemL(text="direction: X, Y, Z")
#if part.type=='REACTOR':
# sub.itemR(part, "reactor_factor")
# sub.itemR(part, "reaction_shape", slider=True)
if part.type=='REACTOR':
sub.itemR(part, "reactor_factor")
sub.itemR(part, "reaction_shape", slider=True)
class PARTICLE_PT_rotation(ParticleButtonsPanel):
__label__ = "Rotation"
def poll(self, context):
if particle_panel_poll(context):
psys = context.particle_system
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.external
else:
sub.itemL(text="")
return False
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = psys.settings
layout.row().itemL(text="Rotation:")
layout.enabled = particle_panel_enabled(psys)
split = layout.split()
split.itemL(text="Initial Rotation:")
split.itemR(part, "rotation_dynamic")
split = layout.split()
sub = split.column()
sub.itemR(part, "rotation_mode", text="Axis")
split = layout.split()
sub = split.column(align=True)
sub.itemR(part, "rotation_mode", text="")
sub.itemR(part, "random_rotation_factor", slider=True, text="Random")
sub = split.column()
sub.itemR(part, "rotation_dynamic")
sub.itemR(part, "random_rotation_factor", slider=True)
sub = split.column()
sub = split.column(align=True)
sub.itemR(part, "phase_factor", slider=True)
sub.itemR(part, "random_phase_factor", text="Random", slider=True)
layout.row().itemL(text="Angular velocity:")
layout.row().itemL(text="Angular Velocity:")
layout.row().itemR(part, "angular_velocity_mode", expand=True)
split = layout.split()
@ -607,16 +627,37 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
elif part.ren_as == 'OBJECT':
sub.itemR(part, "dupli_object")
sub.itemR(part, "use_global_dupli")
elif part.ren_as == 'GROUP':
sub.itemR(part, "dupli_group")
split = layout.split()
sub = split.column()
sub.itemR(part, "whole_group")
colsub = sub.column()
colsub.active = part.whole_group == False
colsub.itemR(part, "use_group_count")
sub = split.column()
colsub = sub.column()
colsub.active = part.whole_group == False
colsub.itemR(part, "use_global_dupli")
colsub.itemR(part, "rand_group")
if part.use_group_count and not part.whole_group:
row = layout.row()
row.template_list(part, "dupliweights", part, "active_dupliweight_index")
col = row.column()
subrow = col.row()
subcol = subrow.column(align=True)
subcol.itemO("particle.dupliob_move_up", icon='VICON_MOVE_UP', text="")
subcol.itemO("particle.dupliob_move_down", icon='VICON_MOVE_DOWN', text="")
weight = part.active_dupliweight
if weight:
row = layout.row()
row.itemR(weight, "count")
elif part.ren_as == 'BILLBOARD':
sub.itemL(text="Align:")
@ -898,7 +939,8 @@ bpy.types.register(PARTICLE_PT_particles)
bpy.types.register(PARTICLE_PT_hair_dynamics)
bpy.types.register(PARTICLE_PT_cache)
bpy.types.register(PARTICLE_PT_emission)
bpy.types.register(PARTICLE_PT_initial)
bpy.types.register(PARTICLE_PT_velocity)
bpy.types.register(PARTICLE_PT_rotation)
bpy.types.register(PARTICLE_PT_physics)
bpy.types.register(PARTICLE_PT_boidbrain)
bpy.types.register(PARTICLE_PT_render)

@ -78,7 +78,7 @@ def effector_weights_ui(self, weights):
layout.itemS()
flow = layout.column_flow()
flow.itemR(weights, "spherical", slider=True)
flow.itemR(weights, "force", slider=True)
flow.itemR(weights, "vortex", slider=True)
flow.itemR(weights, "magnetic", slider=True)
flow.itemR(weights, "wind", slider=True)
@ -110,7 +110,7 @@ def basic_force_field_settings_ui(self, field):
col.itemR(field, "flow")
elif field.type == 'HARMONIC':
col.itemR(field, "harmonic_damping", text="Damping")
elif field.type == 'VORTEX' and field.shape == 'PLANE':
elif field.type == 'VORTEX' and field.shape != 'POINT':
col.itemR(field, "inflow")
elif field.type == 'DRAG':
col.itemR(field, "quadratic_drag", text="Quadratic")
@ -140,6 +140,7 @@ def basic_force_field_falloff_ui(self, field):
col.itemR(field, "z_direction", text="")
col.itemR(field, "use_min_distance", text="Use Minimum")
col.itemR(field, "use_max_distance", text="Use Maximum")
col.itemR(field, "do_absorption")
col = split.column()
col.itemR(field, "falloff_power", text="Power")

@ -57,6 +57,7 @@ typedef struct BVHTreeFromMesh
/* Vertex array, so that callbacks have instante access to data */
struct MVert *vert;
struct MEdge *edge; /* only used for BVHTreeFromMeshEdges */
struct MFace *face;
/* radius for raycast */
@ -96,6 +97,8 @@ BVHTree* bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct DerivedMes
*/
BVHTree* bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
BVHTree* bvhtree_from_mesh_edges(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
/*
* Frees data allocated by a call to bvhtree_from_mesh_*.
*/
@ -109,6 +112,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
//Using local coordinates
#define BVHTREE_FROM_FACES 0
#define BVHTREE_FROM_VERTICES 1
#define BVHTREE_FROM_EDGES 2
typedef LinkNode* BVHCache;

@ -138,6 +138,7 @@ int get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struc
/* EffectedPoint->flag */
#define PE_WIND_AS_SPEED 1
#define PE_DYNAMIC_ROTATION 2
#define PE_USE_NORMAL_DATA 4
/* EffectorData->flag */
#define PE_VELOCITY_TO_IMPULSE 1

@ -201,6 +201,8 @@ struct Object *psys_get_lattice(struct ParticleSimulationData *sim);
int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
void psys_check_group_weights(struct ParticleSettings *part);
/* free */
void psys_free_settings(struct ParticleSettings *part);
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);

@ -776,6 +776,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
GroupObject *go;
Object *ob=0, **oblist=0, obcopy, *obcopylist=0;
DupliObject *dob;
ParticleDupliWeight *dw;
ParticleSimulationData sim = {scene, par, psys, psys_get_modifier(par, psys)};
ParticleSettings *part;
ParticleData *pa;
@ -783,7 +784,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
ParticleKey state;
ParticleCacheKey *cache;
float ctime, pa_time, scale = 1.0f;
float tmat[4][4], mat[4][4], pamat[4][4], size=0.0;
float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size=0.0;
float (*obmat)[4], (*oldobmat)[4];
int lay, a, b, counter, hair = 0;
int totpart, totchild, totgroup=0, pa_num;
@ -813,6 +814,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
((part->ren_as == PART_DRAW_OB && part->dup_ob) ||
(part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first))) {
psys_check_group_weights(part);
/* if we have a hair particle system, use the path cache */
if(part->type == PART_HAIR) {
if(psys->flag & PSYS_HAIR_DONE)
@ -831,18 +834,37 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
if(part->ren_as==PART_DRAW_GR) {
group_handle_recalc_and_update(scene, par, part->dup_group);
for(go=part->dup_group->gobject.first; go; go=go->next)
totgroup++;
if(part->draw & PART_DRAW_COUNT_GR) {
for(dw=part->dupliweights.first; dw; dw=dw->next)
totgroup += dw->count;
}
else {
for(go=part->dup_group->gobject.first; go; go=go->next)
totgroup++;
}
/* we also copy the actual objects to restore afterwards, since
* where_is_object_time will change the object which breaks transform */
oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list");
go = part->dup_group->gobject.first;
for(a=0; a<totgroup; a++, go=go->next) {
oblist[a] = go->ob;
obcopylist[a] = *go->ob;
if(part->draw & PART_DRAW_COUNT_GR && totgroup) {
dw = part->dupliweights.first;
for(a=0; a<totgroup; dw=dw->next) {
for(b=0; b<dw->count; b++, a++) {
oblist[a] = dw->ob;
obcopylist[a] = *dw->ob;
}
}
}
else {
go = part->dup_group->gobject.first;
for(a=0; a<totgroup; a++, go=go->next) {
oblist[a] = go->ob;
obcopylist[a] = *go->ob;
}
}
}
else {
@ -936,11 +958,18 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
else {
/* to give ipos in object correct offset */
where_is_object_time(scene, ob, ctime-pa_time);
VECCOPY(vec, obmat[3]);
obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
Mat4CpyMat4(mat, pamat);
Mat4MulMat4(tmat, obmat, mat);
Mat4MulFloat3((float *)tmat, size*scale);
if(part->draw & PART_DRAW_GLOBAL_OB)
VECADD(tmat[3], tmat[3], vec);
if(par_space_mat)
Mat4MulMat4(mat, tmat, par_space_mat);
else

@ -73,13 +73,11 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
{
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
BoidSettings *boids = bbd->part->boids;
Object *priority_ob = NULL;
BoidParticle *bpa = pa->boid;
EffectedPoint epoint;
ListBase *effectors = bbd->sim->psys->effectors;
EffectorCache *cur, *eff = NULL;
EffectorData efd, cur_efd;
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 = 0.0f;
int ret = 0;
@ -1051,9 +1049,8 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
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 force[3] = {0.0f, 0.0f, 0.0f};
float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
int p = pa - bbd->sim->psys->particles;
set_boid_values(&val, boids, pa);

@ -479,6 +479,32 @@ static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *r
} while(t2);
}
// Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges.
// userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
static void mesh_edges_nearest_point(void *userdata, int index, const float *co, BVHTreeNearest *nearest)
{
const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
MVert *vert = data->vert;
MEdge *edge = data->edge + index;
float nearest_tmp[3], dist;
float *t0, *t1;
t0 = vert[ edge->v1 ].co;
t1 = vert[ edge->v2 ].co;
PclosestVL3Dfl(nearest_tmp, co, t0, t1);
dist = VecLenf(nearest_tmp, co);
if(dist < nearest->dist)
{
nearest->index = index;
nearest->dist = dist;
VECCOPY(nearest->co, nearest_tmp);
VecSubf(nearest->no, t0, t1);
Normalize(nearest->no);
}
}
/*
* BVH builders
*/
@ -605,6 +631,68 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
}
// Builds a bvh tree.. where nodes are the faces of the given mesh.
BVHTree* bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *mesh, float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhcache_find(&mesh->bvhCache, BVHTREE_FROM_EDGES);
//Not in cache
if(tree == NULL)
{
int i;
int numEdges= mesh->getNumEdges(mesh);
MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
MEdge *edge = mesh->getEdgeDataArray(mesh, CD_MEDGE);
if(vert != NULL && edge != NULL)
{
/* Create a bvh-tree of the given target */
tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis);
if(tree != NULL)
{
for(i = 0; i < numEdges; i++)
{
float co[4][3];
VECCOPY(co[0], vert[ edge[i].v1 ].co);
VECCOPY(co[1], vert[ edge[i].v2 ].co);
BLI_bvhtree_insert(tree, i, co[0], 2);
}
BLI_bvhtree_balance(tree);
//Save on cache for later use
// printf("BVHTree built and saved on cache\n");
bvhcache_insert(&mesh->bvhCache, tree, BVHTREE_FROM_EDGES);
}
}
}
else
{
// printf("BVHTree is already build, using cached tree\n");
}
//Setup BVHTreeFromMesh
memset(data, 0, sizeof(*data));
data->tree = tree;
if(data->tree)
{
data->cached = TRUE;
data->nearest_callback = mesh_edges_nearest_point;
data->raycast_callback = NULL;
data->mesh = mesh;
data->vert = mesh->getVertDataArray(mesh, CD_MVERT);
data->edge = mesh->getEdgeDataArray(mesh, CD_MEDGE);
data->sphere_radius = epsilon;
}
return data->tree;
}
// Frees data allocated by a call to bvhtree_from_mesh_*.
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{

@ -228,6 +228,8 @@ static void precalculate_effector(EffectorCache *eff)
}
else if(eff->pd->shape == PFIELD_SHAPE_SURFACE) {
eff->surmd = (SurfaceModifierData *)modifiers_findByType ( eff->ob, eModifierType_Surface );
if(eff->ob->type == OB_CURVE)
eff->flag |= PE_USE_NORMAL_DATA;
}
else if(eff->psys)
psys_update_particle_tree(eff->psys, eff->scene->r.cfra);
@ -518,7 +520,7 @@ float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *poi
float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f;
float fac, r_fac;
fac = Inpf(efd->nor, efd->vec_to_point);
fac = Inpf(efd->nor, efd->vec_to_point2);
if(eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f)
falloff=0.0f;
@ -691,10 +693,16 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
VecSubf(efd->vec_to_point, point->loc, efd->loc);
efd->distance = VecLength(efd->vec_to_point);
/* for some effectors we need the object center every time */
VecSubf(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
VECCOPY(efd->nor2, eff->ob->obmat[2]);
Normalize(efd->nor2);
if(eff->flag & PE_USE_NORMAL_DATA) {
VECCOPY(efd->vec_to_point2, efd->vec_to_point);
VECCOPY(efd->nor2, efd->nor);
}
else {
/* for some effectors we need the object center every time */
VecSubf(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
VECCOPY(efd->nor2, eff->ob->obmat[2]);
Normalize(efd->nor2);
}
}
return ret;
@ -835,8 +843,7 @@ void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *
switch(pd->forcefield){
case PFIELD_WIND:
Normalize(force);
strength *= (Inpf(force, efd->nor) >= 0.0f ? 1.0f : -1.0f);
VECCOPY(force, efd->nor);
VecMulf(force, strength * efd->falloff);
break;
case PFIELD_FORCE:

@ -6211,7 +6211,8 @@ static void surfaceModifier_freeData(ModifierData *md)
MEM_freeN(surmd->bvhtree);
}
surmd->dm->release(surmd->dm);
if(surmd->dm)
surmd->dm->release(surmd->dm);
if(surmd->x)
MEM_freeN(surmd->x);
@ -6298,7 +6299,10 @@ static void surfaceModifier_deformVerts(
else
surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
bvhtree_from_mesh_faces(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
if(surmd->dm->getNumFaces(surmd->dm))
bvhtree_from_mesh_faces(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
else
bvhtree_from_mesh_edges(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
}
}

@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "DNA_boid_types.h"
#include "DNA_group_types.h"
#include "DNA_particle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -63,6 +64,7 @@
#include "BKE_cloth.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
#include "BKE_utildefines.h"
@ -296,6 +298,60 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys)
return 1;
}
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
GroupObject *go;
int current = 0;
if(part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
/* first remove all weights that don't have an object in the group */
dw = part->dupliweights.first;
while(dw) {
if(!object_in_group(dw->ob, part->dup_group)) {
tdw = dw->next;
BLI_freelinkN(&part->dupliweights, dw);
dw = tdw;
}
else
dw = dw->next;
}
/* then add objects in the group to new list */
go = part->dup_group->gobject.first;
while(go) {
dw = part->dupliweights.first;
while(dw && dw->ob != go->ob)
dw = dw->next;
if(!dw) {
dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
dw->ob = go->ob;
dw->count = 1;
BLI_addtail(&part->dupliweights, dw);
}
go = go->next;
}
dw = part->dupliweights.first;
for(; dw; dw=dw->next) {
if(dw->flag & PART_DUPLIW_CURRENT) {
current = 1;
break;
}
}
if(!current) {
dw = part->dupliweights.first;
if(dw)
dw->flag |= PART_DUPLIW_CURRENT;
}
}
else {
BLI_freelistN(&part->dupliweights);
}
}
/************************************************/
/* Freeing stuff */
/************************************************/
@ -307,6 +363,8 @@ void psys_free_settings(ParticleSettings *part)
if(part->effector_weights)
MEM_freeN(part->effector_weights);
BLI_freelistN(&part->dupliweights);
boid_free_settings(part->boids);
}
@ -439,6 +497,9 @@ void psys_free_pdd(ParticleSystem *psys)
if(psys->pdd->vedata)
MEM_freeN(psys->pdd->vedata);
psys->pdd->vedata = NULL;
psys->pdd->totpoint = 0;
psys->pdd->tot_vec_size = 0;
}
}
/* free everything */
@ -2047,10 +2108,10 @@ static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float
float roughfac;
roughfac=fac*(float)pow((double)t,shape);
VECCOPY(rough,loc);
Vec2Copyf(rough,loc);
rough[0]=-1.0f+2.0f*rough[0];
rough[1]=-1.0f+2.0f*rough[1];
VecMulf(rough,roughfac);
Vec2Mulf(rough,roughfac);
VECADDFAC(state->co,state->co,mat[0],rough[0]);
VECADDFAC(state->co,state->co,mat[1],rough[1]);
@ -3235,6 +3296,9 @@ static void default_particle_settings(ParticleSettings *part)
part->size=0.05;
part->childsize=1.0;
part->rotmode = PART_ROT_VEL;
part->avemode = PART_AVE_SPIN;
part->child_nbr=10;
part->ren_child_nbr=100;
part->childrad=0.2f;
@ -3788,6 +3852,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
ctx.dm = psmd->dm;
ctx.ma = ma;
/* TODO: assign vertex groups */
@ -3856,6 +3921,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
ChildParticle *cpa = NULL;
float cfra;
int totpart = psys->totpart;
float timestep = psys_get_timestep(sim);
/* negative time means "use current time" */
cfra = state->time > 0 ? state->time : bsystem_time(sim->scene, 0, (float)sim->scene->r.cfra, 0.0);
@ -3924,13 +3990,14 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
calc_latt_deform(sim->psys->lattice, state->co,1.0f);
}
else{
if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)
|| pa->prev_state.time <= 0.0f)
copy_particle_key(state, &pa->state, 1);
else if(pa->prev_state.time==state->time)
copy_particle_key(state, &pa->prev_state, 1);
else {
/* let's interpolate to try to be as accurate as possible */
if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) {
if(pa->state.time + 2.0f > state->time && pa->prev_state.time - 2.0f < state->time) {
ParticleKey keys[4];
float dfra, keytime, frs_sec = sim->scene->r.frs_sec;
@ -3949,13 +4016,13 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
keytime = (state->time - keys[1].time) / dfra;
/* convert velocity to timestep size */
VecMulf(keys[1].vel, dfra / frs_sec);
VecMulf(keys[2].vel, dfra / frs_sec);
VecMulf(keys[1].vel, dfra * timestep);
VecMulf(keys[2].vel, dfra * timestep);
psys_interpolate_particle(-1, keys, keytime, state, 1);
/* convert back to real velocity */
VecMulf(state->vel, frs_sec / dfra);
VecMulf(state->vel, 1.0f / (dfra * timestep));
VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime);
QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime);

@ -183,6 +183,8 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
if(totpart && totpart != psys->totpart) {
newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
if(psys->part->phystype == PART_PHYS_BOIDS)
newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles");
if(psys->particles) {
totsaved=MIN2(psys->totpart,totpart);
@ -215,13 +217,12 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
}
psys->particles=newpars;
psys->totpart=totpart;
if(newboids) {
LOOP_PARTICLES
pa->boid = newboids++;
}
psys->totpart=totpart;
}
if(psys->child) {
@ -1660,7 +1661,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
ParticleKey state;
//IpoCurve *icu=0; // XXX old animation system
float fac, phasefac, nor[3]={0,0,0},loc[3],vel[3]={0.0,0.0,0.0},rot[4],q2[4];
float r_vel[3],r_ave[3],r_rot[4],p_vel[3]={0.0,0.0,0.0};
float r_vel[3],r_ave[3],r_rot[4],vec[3],p_vel[3]={0.0,0.0,0.0};
float x_vec[3]={1.0,0.0,0.0}, utan[3]={0.0,1.0,0.0}, vtan[3]={0.0,0.0,1.0}, rot_vec[3]={0.0,0.0,0.0};
float q_phase[4], r_phase;
int p = pa - psys->particles;
@ -1773,7 +1774,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
}
}
if(part->phystype==PART_PHYS_BOIDS) {
if(part->phystype==PART_PHYS_BOIDS && pa->boid) {
BoidParticle *bpa = pa->boid;
float dvec[3], q[4], mat[3][3];
@ -1839,6 +1840,23 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
VECADDFAC(vel,vel,vtan,part->tanfac);
//VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_tan):1.0f));
/* *emitter object orientation */
if(part->ob_vel[0]!=0.0) {
VECCOPY(vec, ob->obmat[0]);
Normalize(vec);
VECADDFAC(vel, vel, vec, part->ob_vel[0]);
}
if(part->ob_vel[1]!=0.0) {
VECCOPY(vec, ob->obmat[1]);
Normalize(vec);
VECADDFAC(vel, vel, vec, part->ob_vel[1]);
}
if(part->ob_vel[2]!=0.0) {
VECCOPY(vec, ob->obmat[2]);
Normalize(vec);
VECADDFAC(vel, vel, vec, part->ob_vel[2]);
}
/* *texture */
/* TODO */
@ -3135,7 +3153,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
ParticleSystem *psys = sim->psys;
ParticleSettings *part=psys->part;
KDTree *tree=0;
//IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system
//IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system
/* Material *ma=give_current_material(sim->ob, part->omat); */
BoidBrainData bbd;
PARTICLE_P;

@ -269,7 +269,7 @@ static void ptcache_read_particle(int index, void *psys_v, void **data, float fr
/* determine rotation from velocity */
if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
vectoquat(pa->state.vel, OB_POSX, OB_POSZ, pa->state.rot);
vectoquat(pa->state.vel, OB_NEGX, OB_POSZ, pa->state.rot);
}
}
static void ptcache_interpolate_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data)
@ -292,6 +292,23 @@ static void ptcache_interpolate_particle(int index, void *psys_v, void **data, f
else
BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
/* determine velocity from previous location */
if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
if(keys[1].time > keys[2].time) {
VecSubf(keys[2].vel, keys[1].co, keys[2].co);
VecMulf(keys[2].vel, (keys[1].time - keys[2].time) / frs_sec);
}
else {
VecSubf(keys[2].vel, keys[2].co, keys[1].co);
VecMulf(keys[2].vel, (keys[2].time - keys[1].time) / frs_sec);
}
}
/* determine rotation from velocity */
if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
vectoquat(keys[2].vel, OB_NEGX, OB_POSZ, keys[2].rot);
}
if(cfra > pa->time)
cfra1 = MAX2(cfra1, pa->time);
@ -301,7 +318,7 @@ static void ptcache_interpolate_particle(int index, void *psys_v, void **data, f
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);
QuatInterpol(pa->state.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
VecMulf(pa->state.vel, frs_sec / dfra);
@ -594,7 +611,8 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
if(psys->part->phystype == PART_PHYS_BOIDS)
pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS);
if(psys->part->rotmode || psys->part->avemode)
if(psys->part->rotmode!=PART_ROT_VEL
|| psys->part->avemode!=PART_AVE_SPIN || psys->part->avefac!=0.0f)
pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION);
if(psys->part->flag & PART_ROT_DYN)

@ -3033,6 +3033,7 @@ static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointC
static void lib_link_particlesettings(FileData *fd, Main *main)
{
ParticleSettings *part;
ParticleDupliWeight *dw;
part= main->particle.first;
while(part) {
@ -3048,6 +3049,10 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
if(part->effector_weights)
part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
dw = part->dupliweights.first;
for(; dw; dw=dw->next)
dw->ob = newlibadr(fd, part->id.lib, dw->ob);
if(part->boids) {
BoidState *state = part->boids->states.first;
BoidRule *rule;
@ -3088,6 +3093,8 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
else
part->effector_weights = BKE_add_effector_weights(part->eff_group);
link_list(fd, &part->dupliweights);
part->boids= newdataadr(fd, part->boids);
if(part->boids) {

@ -610,6 +610,7 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
static void write_particlesettings(WriteData *wd, ListBase *idbase)
{
ParticleSettings *part;
ParticleDupliWeight *dw;
part= idbase->first;
while(part) {
@ -622,6 +623,10 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
dw = part->dupliweights.first;
for(; dw; dw=dw->next)
writestruct(wd, DATA, "ParticleDupliWeight", 1, dw);
if(part->boids && part->phystype == PART_PHYS_BOIDS) {
BoidState *state = part->boids->states.first;

@ -348,6 +348,82 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ move up particle dupliweight operator *********************/
static int dupliob_move_up_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= ptr.data;
ParticleSettings *part;
ParticleDupliWeight *dw;
if(!psys)
return OPERATOR_CANCELLED;
part = psys->part;
for(dw=part->dupliweights.first; dw; dw=dw->next) {
if(dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
BLI_remlink(&part->dupliweights, dw);
BLI_insertlink(&part->dupliweights, dw->prev->prev, dw);
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
break;
}
}
return OPERATOR_FINISHED;
}
void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot)
{
ot->name= "Move Up Dupli Object";
ot->idname= "PARTICLE_OT_dupliob_move_up";
ot->description= "Move dupli object up in the list.";
ot->exec= dupliob_move_up_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ move down particle dupliweight operator *********************/
static int dupliob_move_down_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= ptr.data;
ParticleSettings *part;
ParticleDupliWeight *dw;
if(!psys)
return OPERATOR_CANCELLED;
part = psys->part;
for(dw=part->dupliweights.first; dw; dw=dw->next) {
if(dw->flag & PART_DUPLIW_CURRENT && dw->next) {
BLI_remlink(&part->dupliweights, dw);
BLI_insertlink(&part->dupliweights, dw->next, dw);
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
break;
}
}
return OPERATOR_FINISHED;
}
void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
{
ot->name= "Move Down Dupli Object";
ot->idname= "PARTICLE_OT_dupliob_move_down";
ot->description= "Move dupli object down in the list.";
ot->exec= dupliob_move_down_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ connect/disconnect hair operators *********************/
static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)

@ -77,6 +77,9 @@ void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
/* particle_boids.c */
void BOID_OT_rule_add(struct wmOperatorType *ot);
void BOID_OT_rule_del(struct wmOperatorType *ot);

@ -78,6 +78,9 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_target_move_down);
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
WM_operatortype_append(PARTICLE_OT_dupliob_move_up);
WM_operatortype_append(PARTICLE_OT_dupliob_move_down);
}
static void keymap_particle(wmWindowManager *wm)

@ -3358,7 +3358,30 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
}
/* *********** drawing for particles ************* */
static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
{
/* draw created data arrays */
switch(draw_as){
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
glDrawArrays(GL_LINES, 0, 6*totpoint);
break;
case PART_DRAW_LINE:
glDrawArrays(GL_LINES, 0, 2*totpoint);
break;
case PART_DRAW_BB:
if(ob_dt<=OB_WIRE || select)
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawArrays(GL_QUADS, 0, 4*totpoint);
break;
default:
glDrawArrays(GL_POINTS, 0, totpoint);
break;
}
}
static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd)
{
float vec[3], vec2[3];
@ -3401,7 +3424,7 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
cd[7]=cd[10]=1.0;
cd[13]=cd[12]=cd[15]=cd[16]=0.0;
cd[14]=cd[17]=1.0;
cd+=18;
pdd->cd+=18;
VECCOPY(vec2,state->co);
}
@ -3552,7 +3575,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if(psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART)==0)
return;
if(part->draw_as==PART_DRAW_NOT) return;
if(part->draw_as == PART_DRAW_REND)
draw_as = part->ren_as;
else
draw_as = part->draw_as;
if(draw_as == PART_DRAW_NOT)
return;
/* 2. */
sim.psmd = psmd = psys_get_modifier(ob,psys);
@ -3582,26 +3611,22 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if(v3d->zbuf) glDepthMask(1);
if(select)
cpack(0xFFFFFF);
else if((ma) && (part->draw&PART_DRAW_MAT_COL)) {
if((ma) && (part->draw&PART_DRAW_MAT_COL)) {
glColor3f(ma->r,ma->g,ma->b);
ma_r = ma->r;
ma_g = ma->g;
ma_b = ma->b;
if(pdd) {
pdd->ma_r = &ma_r;
pdd->ma_g = &ma_g;
pdd->ma_b = &ma_b;
}
create_cdata = 1;
}
else
cpack(0);
if(pdd) {
pdd->ma_r = &ma_r;
pdd->ma_g = &ma_g;
pdd->ma_b = &ma_b;
}
timestep= psys_get_timestep(&sim);
if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) {
@ -3612,11 +3637,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
totpart=psys->totpart;
if(part->draw_as==PART_DRAW_REND)
draw_as = part->ren_as;
else
draw_as = part->draw_as;
//if(part->flag&PART_GLOB_TIME)
cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f);
@ -3646,6 +3666,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pixsize*=2.0;
else
pixsize*=part->draw_size;
if(draw_as==PART_DRAW_AXIS)
create_cdata = 1;
break;
case PART_DRAW_OB:
if(part->dup_ob==0)
@ -3693,9 +3716,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
Normalize(imat[1]);
}
if(!create_cdata && pdd && pdd->cdata) {
MEM_freeN(pdd->cdata);
pdd->cdata = pdd->cd = NULL;
}
/* 4. */
if(draw_as && draw_as!=PART_DRAW_PATH) {
if(draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC)==0) {
int tot_vec_size = (totpart + totchild) * 3 * sizeof(float);
int create_ndata = 0;
if(!pdd)
pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData");
@ -3705,37 +3734,36 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
psys_make_temp_pointcache(ob, psys);
}
switch(draw_as) {
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
tot_vec_size *= 6;
if(draw_as != PART_DRAW_CROSS)
create_cdata = 1;
break;
case PART_DRAW_LINE:
tot_vec_size *= 2;
break;
case PART_DRAW_BB:
tot_vec_size *= 4;
create_ndata = 1;
break;
}
if(pdd->tot_vec_size != tot_vec_size)
psys_free_pdd(psys);
if(draw_as!=PART_DRAW_CIRC) {
switch(draw_as) {
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
if(draw_as != PART_DRAW_CROSS || create_cdata)
if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata");
if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata");
break;
case PART_DRAW_LINE:
if(create_cdata)
if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata");
if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata");
break;
case PART_DRAW_BB:
if(create_cdata)
if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata");
if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
if(!pdd->ndata) pdd->ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
break;
default:
if(create_cdata)
if(!pdd->cdata) pdd->cdata=MEM_callocN(tot_vec_size, "particle_cdata");
if(!pdd->vdata) pdd->vdata=MEM_callocN(tot_vec_size, "particle_vdata");
}
}
if(!pdd->vdata)
pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata");
if(create_cdata && !pdd->cdata)
pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata");
if(create_ndata && !pdd->ndata)
pdd->ndata = MEM_callocN(tot_vec_size, "particle_vdata");
if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
if(!pdd->vedata) pdd->vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata");
if(!pdd->vedata)
pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata");
need_v = 1;
}
@ -3744,11 +3772,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pdd->cd= pdd->cdata;
pdd->nd= pdd->ndata;
pdd->tot_vec_size= tot_vec_size;
psys->lattice= psys_get_lattice(&sim);
}
if(draw_as){
psys->lattice= psys_get_lattice(&sim);
if(draw_as!=PART_DRAW_PATH){
/* 5. */
if((pdd->flag & PARTICLE_DRAW_DATA_UPDATED)
&& (pdd->vedata || part->draw & (PART_DRAW_SIZE|PART_DRAW_NUM|PART_DRAW_HEALTH))==0) {
@ -3836,156 +3864,139 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
r_length = PSYS_FRAND(a + 22);
}
if(draw_as!=PART_DRAW_PATH){
drawn = 0;
if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
float length = part->path_end * (1.0 - part->randlength * r_length);
int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
float dt = length / (trail_count ? (float)trail_count : 1.0f);
int i=0;
drawn = 0;
if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
float length = part->path_end * (1.0 - part->randlength * r_length);
int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
float dt = length / (trail_count ? (float)trail_count : 1.0f);
int i=0;
ct+=dt;
for(i=0; i < trail_count; i++, ct += dt) {
if(part->draw & PART_ABS_PATH_TIME) {
if(ct < pa_birthtime || ct > pa_dietime)
continue;
}
else if(ct < 0.0f || ct > 1.0f)
ct+=dt;
for(i=0; i < trail_count; i++, ct += dt) {
if(part->draw & PART_ABS_PATH_TIME) {
if(ct < pa_birthtime || ct > pa_dietime)
continue;
state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
psys_get_particle_on_path(&sim,a,&state,need_v);
if(psys->parent)
Mat4MulVecfl(psys->parent->obmat, state.co);
/* create actiual particle data */
if(draw_as == PART_DRAW_BB) {
bb.size = pa_size;
bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
bb.time = ct;
}
draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, psys->pdd);
totpoint++;
drawn = 1;
}
else if(ct < 0.0f || ct > 1.0f)
continue;
state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
psys_get_particle_on_path(&sim,a,&state,need_v);
if(psys->parent)
Mat4MulVecfl(psys->parent->obmat, state.co);
/* create actiual particle data */
if(draw_as == PART_DRAW_BB) {
bb.size = pa_size;
bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
bb.time = ct;
}
draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, psys->pdd);
totpoint++;
drawn = 1;
}
else
{
state.time=cfra;
if(psys_get_particle_state(&sim,a,&state,0)){
if(psys->parent)
Mat4MulVecfl(psys->parent->obmat, state.co);
}
else
{
state.time=cfra;
if(psys_get_particle_state(&sim,a,&state,0)){
if(psys->parent)
Mat4MulVecfl(psys->parent->obmat, state.co);
/* create actiual particle data */
if(draw_as == PART_DRAW_BB) {
bb.size = pa_size;
bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
bb.time = pa_time;
}
draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, pdd);
totpoint++;
drawn = 1;
/* create actiual particle data */
if(draw_as == PART_DRAW_BB) {
bb.size = pa_size;
bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
bb.time = pa_time;
}
draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, pdd);
totpoint++;
drawn = 1;
}
}
if(drawn) {
/* additional things to draw for each particle */
/* (velocity, size and number) */
if(pdd->vedata){
VECCOPY(pdd->ved,state.co);
pdd->ved+=3;
VECCOPY(vel,state.vel);
VecMulf(vel,timestep);
VECADD(pdd->ved,state.co,vel);
pdd->ved+=3;
totve++;
}
if(drawn) {
/* additional things to draw for each particle */
/* (velocity, size and number) */
if(pdd->vedata){
VECCOPY(pdd->ved,state.co);
pdd->ved+=3;
VECCOPY(vel,state.vel);
VecMulf(vel,timestep);
VECADD(pdd->ved,state.co,vel);
pdd->ved+=3;
if(part->draw & PART_DRAW_SIZE){
setlinestyle(3);
drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
setlinestyle(0);
}
totve++;
}
if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){
val[0]= '\0';
if(part->draw&PART_DRAW_NUM)
sprintf(val, " %i", a);
if(part->draw & PART_DRAW_SIZE){
setlinestyle(3);
drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
setlinestyle(0);
}
if(part->draw&PART_DRAW_NUM && part->draw&PART_DRAW_HEALTH)
sprintf(val, "%s:", val);
if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){
val[0]= '\0';
if(part->draw&PART_DRAW_NUM)
sprintf(val, " %i", a);
if(part->draw&PART_DRAW_HEALTH && a < totpart && part->phystype==PART_PHYS_BOIDS)
sprintf(val, "%s %.2f", val, pa_health);
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 */
view3d_cached_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0);
}
/* in path drawing state.co is the end point */
view3d_cached_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0);
}
}
}
}
/* 6. */
glGetIntegerv(GL_POLYGON_MODE, polygonmode);
glDisableClientState(GL_NORMAL_ARRAY);
glGetIntegerv(GL_POLYGON_MODE, polygonmode);
glDisableClientState(GL_NORMAL_ARRAY);
if(draw_as==PART_DRAW_PATH){
ParticleCacheKey **cache, *path;
float *cd2=0,*cdata2=0;
if(draw_as==PART_DRAW_PATH){
ParticleCacheKey **cache, *path;
float *cd2=0,*cdata2=0;
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
/* setup gl flags */
if(ob_dt > OB_WIRE) {
glEnableClientState(GL_NORMAL_ARRAY);
/* setup gl flags */
if(ob_dt > OB_WIRE) {
glEnableClientState(GL_NORMAL_ARRAY);
if(part->draw&PART_DRAW_MAT_COL)
glEnableClientState(GL_COLOR_ARRAY);
if(part->draw&PART_DRAW_MAT_COL)
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
else {
glDisableClientState(GL_NORMAL_ARRAY);
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
else {
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
UI_ThemeColor(TH_WIRE);
}
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
UI_ThemeColor(TH_WIRE);
}
if(totchild && (part->draw&PART_DRAW_PARENT)==0)
totpart=0;
if(totchild && (part->draw&PART_DRAW_PARENT)==0)
totpart=0;
/* draw actual/parent particles */
cache=psys->pathcache;
for(a=0, pa=psys->particles; a<totpart; a++, pa++){
path=cache[a];
if(path->steps > 0) {
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if(ob_dt > OB_WIRE) {
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
if(part->draw&PART_DRAW_MAT_COL)
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
}
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
}
}
/* draw child particles */
cache=psys->childcache;
for(a=0; a<totchild; a++){
path=cache[a];
/* draw actual/parent particles */
cache=psys->pathcache;
for(a=0, pa=psys->particles; a<totpart; a++, pa++){
path=cache[a];
if(path->steps > 0) {
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if(ob_dt > OB_WIRE) {
@ -3996,85 +4007,103 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
}
}
/* draw child particles */
cache=psys->childcache;
for(a=0; a<totchild; a++){
path=cache[a];
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
/* restore & clean up */
if(ob_dt > OB_WIRE) {
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
if(part->draw&PART_DRAW_MAT_COL)
glDisable(GL_COLOR_ARRAY);
glDisable(GL_COLOR_MATERIAL);
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
}
if(cdata2)
MEM_freeN(cdata2);
cd2=cdata2=0;
glLineWidth(1.0f);
}
else if(draw_as!=PART_DRAW_CIRC){
glDisableClientState(GL_COLOR_ARRAY);
/* setup created data arrays */
if(pdd->vdata){
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, pdd->vdata);
}
else
glDisableClientState(GL_VERTEX_ARRAY);
/* billboards are drawn this way */
if(pdd->ndata && ob_dt>OB_WIRE){
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, pdd->ndata);
glEnable(GL_LIGHTING);
}
else{
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_LIGHTING);
}
if(pdd->cdata){
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
}
/* draw created data arrays */
switch(draw_as){
case PART_DRAW_AXIS:
case PART_DRAW_CROSS:
glDrawArrays(GL_LINES, 0, 6*totpoint);
break;
case PART_DRAW_LINE:
glDrawArrays(GL_LINES, 0, 2*totpoint);
break;
case PART_DRAW_BB:
if(ob_dt<=OB_WIRE)
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glDrawArrays(GL_QUADS, 0, 4*totpoint);
break;
default:
glDrawArrays(GL_POINTS, 0, totpoint);
break;
}
pdd->flag |= PARTICLE_DRAW_DATA_UPDATED;
pdd->totpoint = totpoint;
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
}
if(pdd->vedata){
glDisableClientState(GL_COLOR_ARRAY);
cpack(0xC0C0C0);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
glDrawArrays(GL_LINES, 0, 2*totve);
/* restore & clean up */
if(ob_dt > OB_WIRE) {
if(part->draw&PART_DRAW_MAT_COL)
glDisable(GL_COLOR_ARRAY);
glDisable(GL_COLOR_MATERIAL);
}
glPolygonMode(GL_FRONT, polygonmode[0]);
glPolygonMode(GL_BACK, polygonmode[1]);
if(cdata2)
MEM_freeN(cdata2);
cd2=cdata2=0;
glLineWidth(1.0f);
}
else if(ELEM(draw_as, 0, PART_DRAW_CIRC)==0){
int point_size = 1;
glDisableClientState(GL_COLOR_ARRAY);
/* enable point data array */
if(pdd->vdata){
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, pdd->vdata);
}
else
glDisableClientState(GL_VERTEX_ARRAY);
if(select) {
UI_ThemeColor(TH_ACTIVE);
if(part->draw_size)
glPointSize(part->draw_size + 2);
else
glPointSize(4.0);
glLineWidth(3.0);
draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
}
/* restore from select */
glColor3f(ma_r,ma_g,ma_b);
glPointSize(part->draw_size ? part->draw_size : 2.0);
glLineWidth(1.0);
/* enable other data arrays */
/* billboards are drawn this way */
if(pdd->ndata && ob_dt>OB_WIRE){
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, pdd->ndata);
glEnable(GL_LIGHTING);
}
else{
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_LIGHTING);
}
if(pdd->cdata){
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
}
draw_particle_arrays(draw_as, totpoint, ob_dt, 0);
pdd->flag |= PARTICLE_DRAW_DATA_UPDATED;
pdd->totpoint = totpoint;
}
if(pdd && pdd->vedata){
glDisableClientState(GL_COLOR_ARRAY);
cpack(0xC0C0C0);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
glDrawArrays(GL_LINES, 0, 2*totve);
}
glPolygonMode(GL_FRONT, polygonmode[0]);
glPolygonMode(GL_BACK, polygonmode[1]);
/* 7. */
@ -4087,6 +4116,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
psys->flag &= ~PSYS_DRAWING;
/* draw data can't be saved for billboards as they must update to target changes */
if(draw_as == PART_DRAW_BB) {
psys_free_pdd(psys);
pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
}
if(psys->lattice){
end_latt_deform(psys->lattice);
psys->lattice= NULL;

@ -56,14 +56,14 @@ typedef enum PFieldType {
} PFieldType;
typedef struct PartDeflect {
int flag; /* general settings flag */
short deflect; /* Deflection flag - does mesh deflect particles */
short forcefield; /* Force field type, do the vertices attract / repel particles? */
short flag; /* general settings flag */
short falloff; /* fall-off type */
short shape; /* point, plane or surface */
short tex_mode; /* texture effector */
short kink, kink_axis; /* for curve guide */
short zdir, rt;
short zdir;
/* Main effector values */
float f_strength; /* The strength of the force (+ or - ) */

@ -78,6 +78,13 @@ typedef struct ParticleTarget {
float time, duration;
} ParticleTarget;
typedef struct ParticleDupliWeight {
struct ParticleDupliWeight *next, *prev;
struct Object *ob;
short count;
short flag, rt[2];
} ParticleDupliWeight;
typedef struct ParticleData {
ParticleKey state; /* current global coordinates */
@ -148,6 +155,7 @@ typedef struct ParticleSettings {
/* initial velocity factors */
float normfac, obfac, randfac, partfac, tanfac, tanphase, reactfac;
float ob_vel[3], rt;
float avefac, phasefac, randrotfac, randphasefac;
/* physical properties */
float mass, size, randsize, reactshape;
@ -179,6 +187,7 @@ typedef struct ParticleSettings {
int keyed_loops;
struct Group *dup_group;
struct ListBase dupliweights;
struct Group *eff_group; // deprecated
struct Object *dup_ob;
struct Object *bb_ob;
@ -324,12 +333,12 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
/* part->draw */
#define PART_DRAW_VEL 1
//#define PART_DRAW_PATH_LEN 2
#define PART_DRAW_GLOBAL_OB 2
#define PART_DRAW_SIZE 4
#define PART_DRAW_EMITTER 8 /* render emitter also */
#define PART_DRAW_HEALTH 16
#define PART_ABS_PATH_TIME 32
//#define PART_DRAW_TRAIL 64 /* deprecated */
#define PART_DRAW_COUNT_GR 64
#define PART_DRAW_BB_LOCK 128
#define PART_DRAW_PARENT 256
#define PART_DRAW_NUM 512
@ -444,6 +453,9 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PARS_ALIVE 3
#define PARS_DYING 4
/* ParticleDupliWeight->flag */
#define PART_DUPLIW_CURRENT 1
/* psys->vg */
#define PSYS_TOT_VG 12

@ -45,6 +45,13 @@ EnumPropertyItem effector_shape_items[] = {
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem curve_shape_items[] = {
{PFIELD_SHAPE_POINT, "POINT", 0, "Point", ""},
{PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", ""},
{PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Curve", ""},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem empty_shape_items[] = {
{PFIELD_SHAPE_POINT, "POINT", 0, "Point", ""},
{PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", ""},
@ -59,6 +66,13 @@ EnumPropertyItem vortex_shape_items[] = {
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem curve_vortex_shape_items[] = {
{PFIELD_SHAPE_POINT, "POINT", 0, "Old", ""},
{PFIELD_SHAPE_PLANE, "PLANE", 0, "New", ""},
{PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Curve (New)", ""},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem empty_vortex_shape_items[] = {
{PFIELD_SHAPE_POINT, "POINT", 0, "Old", ""},
{PFIELD_SHAPE_PLANE, "PLANE", 0, "New", ""},
@ -538,9 +552,11 @@ static EnumPropertyItem *rna_Effector_shape_itemf(bContext *C, PointerRNA *ptr,
/* needed for doc generation */
RNA_enum_items_add(&item, &totitem, effector_shape_items);
RNA_enum_items_add(&item, &totitem, curve_shape_items);
RNA_enum_items_add(&item, &totitem, empty_shape_items);
RNA_enum_items_add(&item, &totitem, vortex_shape_items);
RNA_enum_items_add(&item, &totitem, empty_shape_items);
RNA_enum_items_add(&item, &totitem, curve_vortex_shape_items);
RNA_enum_items_add(&item, &totitem, empty_vortex_shape_items);
RNA_enum_item_end(&item, &totitem);
*free= 1;
@ -553,7 +569,13 @@ static EnumPropertyItem *rna_Effector_shape_itemf(bContext *C, PointerRNA *ptr,
ob= (Object*)ptr->id.data;
if(ELEM4(ob->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) {
if(ob->type == OB_CURVE) {
if(ob->pd->forcefield == PFIELD_VORTEX)
return curve_vortex_shape_items;
return curve_shape_items;
}
else if(ELEM3(ob->type, OB_MESH, OB_SURF, OB_FONT)) {
if(ob->pd->forcefield == PFIELD_VORTEX)
return vortex_shape_items;
@ -783,11 +805,11 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "All", "All effector's weight.");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
prop= RNA_def_property(srna, "spherical", PROP_FLOAT, PROP_NONE);
prop= RNA_def_property(srna, "force", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "weight[1]");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Spherical", "Spherical effector weight.");
RNA_def_property_ui_text(prop, "Force", "Force effector weight.");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
prop= RNA_def_property(srna, "vortex", PROP_FLOAT, PROP_NONE);
@ -1113,6 +1135,11 @@ static void rna_def_field(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_DO_ROTATION);
RNA_def_property_ui_text(prop, "Rotation", "Effect particles' dynamic rotation");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop= RNA_def_property(srna, "do_absorption", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_VISIBILITY);
RNA_def_property_ui_text(prop, "Absorption", "Force gets absorbed by collision objects");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* Pointer */

@ -105,6 +105,7 @@ EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_pointcache.h"
#include "BLI_arithb.h"
#include "BLI_listbase.h"
/* property update functions */
static void particle_recalc(bContext *C, PointerRNA *ptr, short flag)
@ -433,6 +434,71 @@ static int rna_ParticleSystem_edited_get(PointerRNA *ptr)
else
return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
static PointerRNA rna_ParticleDupliWeight_active_get(PointerRNA *ptr)
{
ParticleSettings *part= (ParticleSettings*)ptr->id.data;
ParticleDupliWeight *dw = part->dupliweights.first;
for(; dw; dw=dw->next) {
if(dw->flag & PART_DUPLIW_CURRENT)
return rna_pointer_inherit_refine(ptr, &RNA_ParticleDupliWeight, dw);
}
return rna_pointer_inherit_refine(ptr, &RNA_ParticleTarget, NULL);
}
static void rna_ParticleDupliWeight_active_index_range(PointerRNA *ptr, int *min, int *max)
{
ParticleSettings *part= (ParticleSettings*)ptr->id.data;
*min= 0;
*max= BLI_countlist(&part->dupliweights)-1;
*max= MAX2(0, *max);
}
static int rna_ParticleDupliWeight_active_index_get(PointerRNA *ptr)
{
ParticleSettings *part= (ParticleSettings*)ptr->id.data;
ParticleDupliWeight *dw = part->dupliweights.first;
int i=0;
for(; dw; dw=dw->next, i++)
if(dw->flag & PART_DUPLIW_CURRENT)
return i;
return 0;
}
static void rna_ParticleDupliWeight_active_index_set(struct PointerRNA *ptr, int value)
{
ParticleSettings *part= (ParticleSettings*)ptr->id.data;
ParticleDupliWeight *dw = part->dupliweights.first;
int i=0;
for(; dw; dw=dw->next, i++) {
if(i==value)
dw->flag |= PART_DUPLIW_CURRENT;
else
dw->flag &= ~PART_DUPLIW_CURRENT;
}
}
static int rna_ParticleDupliWeight_name_length(PointerRNA *ptr)
{
ParticleDupliWeight *dw= ptr->data;
if(dw->ob)
return strlen(dw->ob->id.name+2) + 7;
else
return 9 + 7;
}
static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str)
{
ParticleDupliWeight *dw= ptr->data;
if(dw->ob)
sprintf(str, "%s: %i", dw->ob->id.name+2, dw->count);
else
strcpy(str, "No object");
}
EnumPropertyItem from_items[] = {
{PART_FROM_VERT, "VERT", 0, "Vertexes", ""},
{PART_FROM_FACE, "FACE", 0, "Faces", ""},
@ -726,6 +792,27 @@ static void rna_def_particle(BlenderRNA *brna)
// short rt2;
}
static void rna_def_particle_dupliweight(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ParticleDupliWeight", NULL);
RNA_def_struct_ui_text(srna, "Particle Dupliobject Weight", "Weight of a particle dupliobject in a group.");
RNA_def_struct_sdna(srna, "ParticleDupliWeight");
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ParticleDupliWeight_name_get", "rna_ParticleDupliWeight_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Particle dupliobject name.");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_struct_name_property(srna, prop);
prop= RNA_def_property(srna, "count", PROP_INT, PROP_UNSIGNED);
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop, "Count", "The number of times this object is repeated with respect to other objects.");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
}
static void rna_def_particle_settings(BlenderRNA *brna)
{
StructRNA *srna;
@ -1069,6 +1156,16 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pick Random", "Pick objects from group randomly");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop= RNA_def_property(srna, "use_group_count", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_COUNT_GR);
RNA_def_property_ui_text(prop, "Use Count", "Use object multiple times in the same group");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop= RNA_def_property(srna, "use_global_dupli", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_GLOBAL_OB);
RNA_def_property_ui_text(prop, "Use Global", "Use object's global coordinates for duplication.");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop= RNA_def_property(srna, "render_adaptive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_ADAPT);
RNA_def_property_ui_text(prop, "Adaptive render", "Draw steps of the particle path");
@ -1374,6 +1471,13 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Reactor", "Let the vector away from the target particles location give the particle a starting speed.");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop= RNA_def_property(srna, "object_aligned_factor", PROP_FLOAT, PROP_VELOCITY);
RNA_def_property_float_sdna(prop, NULL, "ob_vel");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_text(prop, "Object Aligned", "Let the emitter object orientation give the particle a starting speed");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop= RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "avefac");
RNA_def_property_range(prop, -200.0f, 200.0f);
@ -1426,19 +1530,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
/* global physical properties */
prop= RNA_def_property(srna, "acceleration", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "acc");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_text(prop, "Acceleration", "Constant acceleration");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop= RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
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, 0, "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);
@ -1665,6 +1756,19 @@ 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, 0, "rna_Particle_redo");
prop= RNA_def_property(srna, "dupliweights", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
RNA_def_property_ui_text(prop, "Dupli Group Weights", "Weights for all of the objects in the dupli group.");
prop= RNA_def_property(srna, "active_dupliweight", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
RNA_def_property_pointer_funcs(prop, "rna_ParticleDupliWeight_active_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Active Dupli Object", "");
prop= RNA_def_property(srna, "active_dupliweight_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_ParticleDupliWeight_active_index_get", "rna_ParticleDupliWeight_active_index_set", "rna_ParticleDupliWeight_active_index_range");
RNA_def_property_ui_text(prop, "Active Dupli Object Index", "");
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");
@ -2024,6 +2128,7 @@ void RNA_def_particle(BlenderRNA *brna)
rna_def_child_particle(brna);
rna_def_particle(brna);
rna_def_particle_dupliweight(brna);
rna_def_particle_system(brna);
rna_def_particle_settings(brna);
}