Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanne Karhu <jhkarh@gmail.com>2009-09-06 00:12:08 +0400
committerJanne Karhu <jhkarh@gmail.com>2009-09-06 00:12:08 +0400
commit08b8fc34cfc082d73e657d1c2941662c36bc3514 (patch)
tree221eb2513a3830e8bd51e61ccbb44529afca5f58 /source/blender
parent05c44056dc48bf718475a1e98c9abbd6cc00a535 (diff)
Disconnect/connect hair:
- Moves hair from face-space to global space and back. - Allows for editing of emitter mesh after hair combing. - Disconnect hair before doing topology changing changes in mesh edit mode, connect after changes. - Notes: * The closest location on emitter surface to the hair root is used to connect the hair. * Emitter deflection, sticky roots and add brush don't apply for disconnect hair in particle mode. - Todo for future: * Copy disconnected hair from object to another (when 2.5 has proper copy operators again). * Possible automatic disconnect/connect with topology changing operations in mesh edit mode. Other changes/fixes: - Proper subtypes for some particle mode notifiers. - Particle mode selections didn't draw correctly because of using lighting for the paths.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h1
-rw-r--r--source/blender/blenkernel/intern/particle.c8
-rw-r--r--source/blender/blenkernel/intern/particle_system.c2
-rw-r--r--source/blender/editors/physics/editparticle.c52
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h2
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c218
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c18
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c6
-rw-r--r--source/blender/editors/transform/transform_conversions.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c5
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
12 files changed, 289 insertions, 43 deletions
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 9ba34091064..b7ab07b0f91 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -192,6 +192,7 @@ typedef struct PTCacheUndo {
struct ParticleData *particles;
struct KDTree *emitter_field;
float *emitter_cosnos;
+ int psys_flag;
/* cache stuff */
struct ListBase mem_cache;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 81eb0b79c40..0ba2f357a1f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -418,7 +418,7 @@ void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit)
edit->pathcache= NULL;
edit->totcached= 0;
}
- else {
+ if(psys) {
psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
psys->pathcache= NULL;
psys->totcached= 0;
@@ -2676,7 +2676,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
baked = psys->pointcache->flag & PTCACHE_BAKED;
/* clear out old and create new empty path cache */
- psys_free_path_cache(psys, NULL);
+ psys_free_path_cache(psys, psys->edit);
cache= psys->pathcache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1);
if(psys->soft && psys->softflag & OB_SB_ENABLE) {
@@ -2891,7 +2891,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
if(!cache || edit->totpoint != edit->totcached) {
/* clear out old and create new empty path cache */
- psys_free_path_cache(NULL, edit);
+ psys_free_path_cache(edit->psys, edit);
cache= edit->pathcache= psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps+1);
}
@@ -2946,7 +2946,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
/* non-hair points are allready in global space */
- if(psys)
+ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR))
Mat4MulVecfl(hairmat, result.co);
VECCOPY(ca->co, result.co);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index eb570ba287c..1931b89af38 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -158,7 +158,7 @@ void psys_reset(ParticleSystem *psys, int mode)
psys->totchild= 0;
/* reset path cache */
- psys_free_path_cache(psys, NULL);
+ psys_free_path_cache(psys, psys->edit);
/* reset point cache */
psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID;
diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c
index bc48d8f4f55..0f5e677b912 100644
--- a/source/blender/editors/physics/editparticle.c
+++ b/source/blender/editors/physics/editparticle.c
@@ -555,7 +555,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
Mat4One(mat);
LOOP_VISIBLE_POINTS {
- if(edit->psys) {
+ if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
Mat4Invert(imat,mat);
}
@@ -812,7 +812,7 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
float *vec, *nor, dvec[3], dot, dist_1st;
float hairimat[4][4], hairmat[4][4];
- if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0)
+ if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
return;
psys = edit->psys;
@@ -876,6 +876,9 @@ void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
return;
+ if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
LOOP_EDITED_POINTS {
LOOP_KEYS {
if(k) {
@@ -899,10 +902,10 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
float dv1[3]= {0.0f, 0.0f, 0.0f};
float dv2[3]= {0.0f, 0.0f, 0.0f};
- if(edit==0)
+ if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
return;
- if((pset->flag & PE_KEEP_LENGTHS)==0)
+ if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
return;
LOOP_EDITED_POINTS {
@@ -1057,11 +1060,13 @@ static void update_world_cos(Object *ob, PTCacheEdit *edit)
return;
LOOP_POINTS {
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
+ if(!(psys->flag & PSYS_GLOBAL_HAIR))
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
LOOP_KEYS {
VECCOPY(key->world_co,key->co);
- Mat4MulVecfl(hairmat, key->world_co);
+ if(!(psys->flag & PSYS_GLOBAL_HAIR))
+ Mat4MulVecfl(hairmat, key->world_co);
}
}
}
@@ -1480,7 +1485,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
Mat4One(mat);
LOOP_VISIBLE_POINTS {
- if(edit->psys)
+ if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
if(pset->selectmode==SCE_SELECT_POINT) {
@@ -1777,7 +1782,8 @@ static void rekey_particle(PEData *data, int pa_index)
for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
ekey->co= key->co;
ekey->time= &key->time;
- ekey->flag |= PEK_USE_WCO;
+ if(!(psys->flag & PSYS_GLOBAL_HAIR))
+ ekey->flag |= PEK_USE_WCO;
}
pa->flag &= ~PARS_REKEY;
@@ -2059,7 +2065,9 @@ static void subdivide_particle(PEData *data, int pa_index)
nekey->co= nkey->co;
nekey->time= &nkey->time;
- nekey->flag |= (PEK_SELECT|PEK_USE_WCO);
+ nekey->flag |= PEK_SELECT;
+ if(!(psys->flag & PSYS_GLOBAL_HAIR))
+ nekey->flag |= PEK_USE_WCO;
nekey++;
nkey++;
@@ -2129,6 +2137,9 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
int n, totn, removed, flag, totremoved;
+ if(psys->flag & PSYS_GLOBAL_HAIR)
+ return OPERATOR_CANCELLED;
+
edit= psys->edit;
psmd= psys_get_modifier(ob, psys);
totremoved= 0;
@@ -2400,6 +2411,9 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
int *mirrorfaces;
int rotation, totpart, newtotpart;
+ if(psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
psmd= psys_get_modifier(ob, psys);
mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
@@ -2750,7 +2764,7 @@ static void brush_puff(PEData *data, int point_index)
float mat[4][4], imat[4][4];
float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length;
- if(psys) {
+ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
Mat4Invert(imat,mat);
}
@@ -2849,6 +2863,9 @@ static void brush_add(PEData *data, short number)
DerivedMesh *dm=0;
Mat4Invert(imat,ob->obmat);
+ if(psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
/* painting onto the deformed mesh, could be an option? */
@@ -3070,6 +3087,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
float vec[3], mousef[2];
short mval[2], mvalo[2];
int flip, mouse[2], dx, dy, removed= 0, selected= 0;
+ int lock_root = pset->flag & PE_LOCK_FIRST;
if(!PE_start_edit(edit))
return;
@@ -3093,6 +3111,10 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
mvalo[0]= bedit->lastmouse[0];
mvalo[1]= bedit->lastmouse[1];
+ /* disable locking temporatily for disconnected hair */
+ if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ pset->flag &= ~PE_LOCK_FIRST;
+
if(((pset->brushtype == PE_BRUSH_ADD) ?
(sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
|| bedit->first) {
@@ -3248,6 +3270,8 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
bedit->lastmouse[1]= mouse[1];
bedit->first= 0;
}
+
+ pset->flag |= lock_root;
}
static void brush_edit_exit(bContext *C, wmOperator *op)
@@ -3382,6 +3406,8 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
for(i=0; i<edit->totpoint; i++, pa++)
pa->hair= MEM_dupallocN(pa->hair);
+
+ undo->psys_flag = edit->psys->flag;
}
else {
PTCacheMem *pm;
@@ -3449,6 +3475,8 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
hkey++;
}
}
+
+ psys->flag = undo->psys_flag;
}
else {
PTCacheMem *pm;
@@ -3704,7 +3732,8 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
key->co= hkey->co;
key->time= &hkey->time;
key->flag= hkey->editflag;
- key->flag |= PEK_USE_WCO;
+ if(!(psys->flag & PSYS_GLOBAL_HAIR))
+ key->flag |= PEK_USE_WCO;
hkey++;
}
pa++;
@@ -3828,6 +3857,7 @@ static int clear_edited_exec(bContext *C, wmOperator *op)
psys->free_edit = NULL;
psys->recalc |= PSYS_RECALC_RESET;
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 8ed17ab1fa8..0a5a5714a06 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -85,6 +85,8 @@ void PARTICLE_OT_new_target(struct wmOperatorType *ot);
void PARTICLE_OT_remove_target(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
+void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
+void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 8cdc6b0cd2b..60480a9f165 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -35,6 +35,8 @@
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
@@ -42,8 +44,11 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
+#include "BKE_bvhutils.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_group.h"
#include "BKE_font.h"
#include "BKE_library.h"
@@ -51,11 +56,13 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_world.h"
+#include "BLI_arithb.h"
#include "BLI_editVert.h"
#include "BLI_listbase.h"
@@ -838,6 +845,217 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/************************ connect/disconnect hair operators *********************/
+
+static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
+ ParticleData *pa = psys->particles;
+ PTCacheEdit *edit = psys->edit;
+ PTCacheEditPoint *point = edit ? edit->points : NULL;
+ PTCacheEditKey *ekey = NULL;
+ HairKey *key;
+ int i, k;
+ float hairmat[4][4];
+
+ if(!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
+ if(!psys->part || psys->part->type != PART_HAIR)
+ return;
+
+ for(i=0; i<psys->totpart; i++,pa++) {
+ if(point) {
+ ekey = point->keys;
+ point++;
+ }
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+
+ for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
+ Mat4MulVecfl(hairmat,key->co);
+
+ if(ekey) {
+ ekey->flag &= ~PEK_USE_WCO;
+ ekey++;
+ }
+ }
+ }
+
+ psys_free_path_cache(psys, psys->edit);
+
+ psys->flag |= PSYS_GLOBAL_HAIR;
+
+ PE_update_object(scene, ob, 0);
+}
+
+static int disconnect_hair_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= NULL;
+ int all = RNA_boolean_get(op->ptr, "all");
+
+ if(!ob)
+ return OPERATOR_CANCELLED;
+
+ if(all) {
+ for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+ disconnect_hair(scene, ob, psys);
+ }
+ }
+ else {
+ psys = ptr.data;
+ disconnect_hair(scene, ob, psys);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
+{
+ ot->name= "Disconnect Hair";
+ ot->description= "Disconnect hair from the emitter mesh.";
+ ot->idname= "PARTICLE_OT_disconnect_hair";
+
+ ot->exec= disconnect_hair_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
+}
+
+static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
+ ParticleData *pa = psys->particles;
+ PTCacheEdit *edit = psys->edit;
+ PTCacheEditPoint *point = edit ? edit->points : NULL;
+ PTCacheEditKey *ekey;
+ HairKey *key;
+ BVHTreeFromMesh bvhtree;
+ BVHTreeNearest nearest;
+ MFace *mface;
+ DerivedMesh *dm = CDDM_copy(psmd->dm);
+ int numverts = dm->getNumVerts (dm);
+ int i, k;
+ float hairmat[4][4], imat[4][4];
+ float v[4][3], vec[3];
+
+ if(!psys || !psys->part || psys->part->type != PART_HAIR)
+ return;
+
+ memset( &bvhtree, 0, sizeof(bvhtree) );
+
+ /* convert to global coordinates */
+ for (i=0; i<numverts; i++)
+ Mat4MulVecfl (ob->obmat, CDDM_get_vert(dm, i)->co);
+
+ bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
+
+ for(i=0; i<psys->totpart; i++,pa++) {
+ key = pa->hair;
+
+ nearest.index = -1;
+ nearest.dist = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
+
+ if(nearest.index == -1) {
+ printf("No nearest point found for hair root!");
+ continue;
+ }
+
+ mface = CDDM_get_face(dm,nearest.index);
+
+ VecCopyf(v[0], CDDM_get_vert(dm,mface->v1)->co);
+ VecCopyf(v[1], CDDM_get_vert(dm,mface->v2)->co);
+ VecCopyf(v[2], CDDM_get_vert(dm,mface->v3)->co);
+ if(mface->v4) {
+ VecCopyf(v[3], CDDM_get_vert(dm,mface->v4)->co);
+ MeanValueWeights(v, 4, nearest.co, pa->fuv);
+ }
+ else
+ MeanValueWeights(v, 3, nearest.co, pa->fuv);
+
+ pa->num = nearest.index;
+ pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL);
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ Mat4Invert(imat,hairmat);
+
+ VECSUB(vec, nearest.co, key->co);
+
+ if(point) {
+ ekey = point->keys;
+ point++;
+ }
+
+ for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
+ VECADD(key->co, key->co, vec);
+ Mat4MulVecfl(imat,key->co);
+
+ if(ekey) {
+ ekey->flag |= PEK_USE_WCO;
+ ekey++;
+ }
+ }
+ }
+
+ free_bvhtree_from_mesh(&bvhtree);
+ dm->release(dm);
+
+ psys_free_path_cache(psys, psys->edit);
+
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+
+ PE_update_object(scene, ob, 0);
+}
+
+static int connect_hair_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= NULL;
+ int all = RNA_boolean_get(op->ptr, "all");
+
+ if(!ob)
+ return OPERATOR_CANCELLED;
+
+ if(all) {
+ for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+ connect_hair(scene, ob, psys);
+ }
+ }
+ else {
+ psys = ptr.data;
+ connect_hair(scene, ob, psys);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_connect_hair(wmOperatorType *ot)
+{
+ ot->name= "Connect Hair";
+ ot->description= "Connect hair to the emitter mesh.";
+ ot->idname= "PARTICLE_OT_connect_hair";
+
+ ot->exec= connect_hair_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
+}
+
/********************** render layer operators *********************/
static int render_layer_add_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 5d1dbe47345..385f55b71c1 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -204,6 +204,8 @@ void buttons_operatortypes(void)
WM_operatortype_append(PARTICLE_OT_remove_target);
WM_operatortype_append(PARTICLE_OT_target_move_up);
WM_operatortype_append(PARTICLE_OT_target_move_down);
+ WM_operatortype_append(PARTICLE_OT_connect_hair);
+ WM_operatortype_append(PARTICLE_OT_disconnect_hair);
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 25ff1244254..57e7d897e24 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -3749,7 +3749,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
nosel_col[1]=(float)nosel[1]/255.0f;
nosel_col[2]=(float)nosel[2]/255.0f;
-
/* draw paths */
if(timed) {
glEnable(GL_BLEND);
@@ -3758,24 +3757,16 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
}
glEnableClientState(GL_VERTEX_ARRAY);
-
- /* solid shaded with lighting */
- glEnableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- /* only draw child paths with lighting */
- if(dt > OB_WIRE)
- glEnable(GL_LIGHTING);
-
- /* draw paths without lighting */
cache=edit->pathcache;
for(i=0; i<totpoint; i++){
path = cache[i];
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
- glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
if(timed) {
for(k=0, pcol=pathcol, pkey=path; k<steps; k++, pkey++, pcol+=4){
@@ -3796,9 +3787,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
/* draw edit vertices */
if(pset->selectmode!=SCE_SELECT_PATH){
- glDisableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glDisable(GL_LIGHTING);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
if(pset->selectmode==SCE_SELECT_POINT){
@@ -3810,7 +3798,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
if(!(point->flag & PEP_HIDE))
totkeys += point->totkey;
- if(!edit->psys)
+ if(!(edit->points->keys->flag & PEK_USE_WCO))
pd=pdata=MEM_callocN(totkeys*3*sizeof(float), "particle edit point data");
cd=cdata=MEM_callocN(totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
@@ -3843,7 +3831,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
if(point->flag & PEP_HIDE)
continue;
- if(edit->psys)
+ if(point->keys->flag & PEK_USE_WCO)
glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
else
glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd);
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 2283d36e018..b6159cf4314 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -1760,17 +1760,17 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
case B_SEL_PATH:
ts->particle.selectmode= SCE_SELECT_PATH;
- WM_event_add_notifier(C, NC_OBJECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
ED_undo_push(C, "Selectmode Set: Path");
break;
case B_SEL_POINT:
ts->particle.selectmode = SCE_SELECT_POINT;
- WM_event_add_notifier(C, NC_OBJECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
ED_undo_push(C, "Selectmode Set: Point");
break;
case B_SEL_END:
ts->particle.selectmode = SCE_SELECT_END;
- WM_event_add_notifier(C, NC_OBJECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
ED_undo_push(C, "Selectmode Set: End point");
break;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 0fce9592d1d..3f32b707043 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -1690,11 +1690,11 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if(!(point->flag & PEP_TRANSFORM)) continue;
- if(psys)
+ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR))
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
for(k=0, key=point->keys; k<point->totkey; k++, key++) {
- if(psys) {
+ if(key->flag & PEK_USE_WCO) {
VECCOPY(key->world_co, key->co);
Mat4MulVecfl(mat, key->world_co);
td->loc = key->world_co;
@@ -1714,7 +1714,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
Mat3One(td->smtx);
/* don't allow moving roots */
- if(k==0 && pset->flag & PE_LOCK_FIRST)
+ if(k==0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
td->protectflag |= OB_LOCK_LOC;
td->ob = ob;
@@ -1764,7 +1764,7 @@ void flushTransParticles(TransInfo *t)
for(i=0, point=edit->points; i<edit->totpoint; i++, point++, td++) {
if(!(point->flag & PEP_TRANSFORM)) continue;
- if(psys) {
+ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
Mat4Invert(imat,mat);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 4a23605c717..71b953effdf 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1884,6 +1884,11 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "softflag", OB_SB_ENABLE);
RNA_def_property_ui_text(prop, "Use Soft Body", "Enable use of soft body for hair physics simulation.");
+ prop= RNA_def_property(srna, "global_hair", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_GLOBAL_HAIR);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Global Hair", "Hair keys are in global coordinate space");
+
/* reactor */
prop= RNA_def_property(srna, "reactor_target_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "target_ob");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 5575b170398..ab4b27cea7b 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -107,7 +107,7 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *ptr)
if(!edit)
return;
- psys_free_path_cache(NULL, edit);
+ psys_free_path_cache(edit->psys, edit);
}
static void rna_ParticleEdit_update(bContext *C, PointerRNA *ptr)
@@ -410,7 +410,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop= RNA_def_property(srna, "fade_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_FADE_TIME);
RNA_def_property_ui_text(prop, "Fade Time", "Fade paths and keys further away from current frame.");
- RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_update");
prop= RNA_def_property(srna, "auto_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_AUTO_VELOCITY);
@@ -443,18 +443,18 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop= RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, 10);
RNA_def_property_ui_text(prop, "Steps", "How many steps to draw the path with.");
- RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_redo");
prop= RNA_def_property(srna, "fade_frames", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, 100);
RNA_def_property_ui_text(prop, "Frames", "How many frames to fade.");
- RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_update");
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "edittype");
RNA_def_property_enum_items(prop, edit_type_items);
RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_redo");
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_editable_get", NULL);