Disconnect/connect hair:
authorJanne Karhu <jhkarh@gmail.com>
Sat, 5 Sep 2009 20:12:08 +0000 (20:12 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sat, 5 Sep 2009 20:12:08 +0000 (20:12 +0000)
- 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.

13 files changed:
release/ui/buttons_particle.py
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/editors/physics/editparticle.c
source/blender/editors/space_buttons/buttons_intern.h
source/blender/editors/space_buttons/buttons_ops.c
source/blender/editors/space_buttons/space_buttons.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesrna/intern/rna_particle.c
source/blender/makesrna/intern/rna_sculpt_paint.c

index f333904..b005145 100644 (file)
@@ -151,6 +151,11 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
                                        row = split.row()
                                        row.enabled = particle_panel_enabled(psys)
                                        row.itemR(part, "hair_step")
+                                       if psys.edited==True:
+                                               if psys.global_hair:
+                                                       layout.itemO("particle.connect_hair")
+                                               else:
+                                                       layout.itemO("particle.disconnect_hair")
                                elif part.type=='REACTOR':
                                        split.enabled = particle_panel_enabled(psys)
                                        split.itemR(psys, "reactor_target_object")
index 9ba3409..b7ab07b 100644 (file)
@@ -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;
index 81eb0b7..0ba2f35 100644 (file)
@@ -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);
index eb570ba..1931b89 100644 (file)
@@ -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;
index bc48d8f..0f5e677 100644 (file)
@@ -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);
index 8ed17ab..0a5a571 100644 (file)
@@ -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);
index 8cdc6b0..60480a9 100644 (file)
@@ -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"
 #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"
 #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)
index 5d1dbe4..385f55b 100644 (file)
@@ -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);
index 25ff124..57e7d89 100644 (file)
@@ -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);
index 2283d36..b6159cf 100644 (file)
@@ -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;  
        
index 0fce959..3f32b70 100644 (file)
@@ -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);
 
index 4a23605..71b953e 100644 (file)
@@ -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");
index 5575b17..ab4b27c 100644 (file)
@@ -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);