diff --git a/release/scripts/ui/buttons_particle.py b/release/scripts/ui/buttons_particle.py index 1a800fc4dfd..81ddab40ec9 100644 --- a/release/scripts/ui/buttons_particle.py +++ b/release/scripts/ui/buttons_particle.py @@ -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) diff --git a/release/scripts/ui/buttons_physics_common.py b/release/scripts/ui/buttons_physics_common.py index b65d092fcfa..17ac1b2bbaa 100644 --- a/release/scripts/ui/buttons_physics_common.py +++ b/release/scripts/ui/buttons_physics_common.py @@ -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") diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 66c8d99959a..e2911a30b25 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -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; diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 83ec7c13946..9a0a724ab9a 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -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 diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index e0259ff10dd..e9285782a1e 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -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); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index bd779935d55..5cd901066f8 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -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; anext) { - oblist[a] = go->ob; - obcopylist[a] = *go->ob; + + if(part->draw & PART_DRAW_COUNT_GR && totgroup) { + dw = part->dupliweights.first; + + for(a=0; anext) { + for(b=0; bcount; b++, a++) { + oblist[a] = dw->ob; + obcopylist[a] = *dw->ob; + } + } + } + else { + go = part->dup_group->gobject.first; + for(a=0; anext) { + 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 diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 76824d3a34a..712fb13cfc0 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -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); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index d9e005811d0..f2526231d50 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -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) { diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 7cc65de827a..9b648e2c05c 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -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: diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 3b47c2f1830..55fb9f45bb3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -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); } } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index f4f5a1364a3..011d5c3f134 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -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); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index d757372f17b..45050127582 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -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; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index bffe4566f74..fa0d5cba604 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -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<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<part->flag & PART_ROT_DYN) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a3a56e9a075..989e2b3fa9e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 1f46446dc2a..c92c0909d3b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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; diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index cef630b6711..1dc08a162b7 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -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) diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index 956f26c478d..3847ec8032a 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -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); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index a62d3d8fd78..ddc5fb9c9b6 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -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) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 0f2a57d881c..0659b5cfd11 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -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; asteps > 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; apathcache; + for(a=0, pa=psys->particles; asteps > 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; aco); - - /* 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; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index e7e785e605b..1376a08eb3e 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -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 - ) */ diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 4c620ae527e..157767e1d13 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -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 diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 022c04240af..404223ab590 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 453b5f9f91a..2c81bda121f 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -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); }