Fix syntax for ID keyword.
[blender-staging.git] / source / blender / editors / physics / particle_object.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_meshdata_types.h"
34 #include "DNA_modifier_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_particle_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_windowmanager_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_listbase.h"
42
43 #include "BKE_context.h"
44 #include "BKE_depsgraph.h"
45 #include "BKE_DerivedMesh.h"
46 #include "BKE_cdderivedmesh.h"
47 #include "BKE_global.h"
48 #include "BKE_main.h"
49 #include "BKE_particle.h"
50 #include "BKE_pointcache.h"
51 #include "BKE_utildefines.h"
52
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_particle.h"
60 #include "ED_screen.h"
61
62 #include "physics_intern.h"
63
64 /********************** particle system slot operators *********************/
65
66 static int particle_system_add_exec(bContext *C, wmOperator *op)
67 {
68         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
69         Scene *scene = CTX_data_scene(C);
70
71         if(!scene || !ob)
72                 return OPERATOR_CANCELLED;
73
74         object_add_particle_system(scene, ob, NULL);
75         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
76         
77         return OPERATOR_FINISHED;
78 }
79
80 void OBJECT_OT_particle_system_add(wmOperatorType *ot)
81 {
82         /* identifiers */
83         ot->name= "Add Particle System Slot";
84         ot->idname= "OBJECT_OT_particle_system_add";
85         ot->description="Add a particle system";
86         
87         /* api callbacks */
88         ot->poll= ED_operator_object_active_editable;
89         ot->exec= particle_system_add_exec;
90         
91         /* flags */
92         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
93 }
94
95 static int particle_system_remove_exec(bContext *C, wmOperator *op)
96 {
97         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
98         Scene *scene = CTX_data_scene(C);
99         int mode_orig = ob->mode;
100         if(!scene || !ob)
101                 return OPERATOR_CANCELLED;
102
103         object_remove_particle_system(scene, ob);
104
105         /* possible this isn't the active object
106          * object_remove_particle_system() clears the mode on the last psys
107          * */
108         if(mode_orig & OB_MODE_PARTICLE_EDIT)
109                 if((ob->mode & OB_MODE_PARTICLE_EDIT)==0)
110                         if(scene->basact && scene->basact->object==ob)
111                                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
112
113         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
114         
115         return OPERATOR_FINISHED;
116 }
117
118 void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
119 {
120         /* identifiers */
121         ot->name= "Remove Particle System Slot";
122         ot->idname= "OBJECT_OT_particle_system_remove";
123         ot->description="Remove the selected particle system";
124         
125         /* api callbacks */
126         ot->poll= ED_operator_object_active_editable;
127         ot->exec= particle_system_remove_exec;
128
129         /* flags */
130         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
131 }
132
133 /********************** new particle settings operator *********************/
134
135 static int psys_poll(bContext *C)
136 {
137         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
138         return (ptr.data != NULL);
139 }
140
141 static int new_particle_settings_exec(bContext *C, wmOperator *op)
142 {
143         Scene *scene = CTX_data_scene(C);
144         Main *bmain= CTX_data_main(C);
145         ParticleSystem *psys;
146         ParticleSettings *part = NULL;
147         Object *ob;
148         PointerRNA ptr;
149
150         ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
151
152         psys = ptr.data;
153
154         /* add or copy particle setting */
155         if(psys->part)
156                 part= psys_copy_settings(psys->part);
157         else
158                 part= psys_new_settings("ParticleSettings", bmain);
159
160         ob= ptr.id.data;
161
162         if(psys->part)
163                 psys->part->id.us--;
164
165         psys->part = part;
166
167         psys_check_boid_data(psys);
168
169         DAG_scene_sort(scene);
170         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
171
172         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
173         
174         return OPERATOR_FINISHED;
175 }
176
177 void PARTICLE_OT_new(wmOperatorType *ot)
178 {
179         /* identifiers */
180         ot->name= "New Particle Settings";
181         ot->idname= "PARTICLE_OT_new";
182         ot->description="Add new particle settings";
183         
184         /* api callbacks */
185         ot->exec= new_particle_settings_exec;
186         ot->poll= psys_poll;
187
188         /* flags */
189         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
190 }
191
192 /********************** keyed particle target operators *********************/
193
194 static int new_particle_target_exec(bContext *C, wmOperator *op)
195 {
196         Scene *scene = CTX_data_scene(C);
197         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
198         ParticleSystem *psys= ptr.data;
199         Object *ob = ptr.id.data;
200
201         ParticleTarget *pt;
202
203         if(!psys)
204                 return OPERATOR_CANCELLED;
205
206         pt = psys->targets.first;
207         for(; pt; pt=pt->next)
208                 pt->flag &= ~PTARGET_CURRENT;
209
210         pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");
211
212         pt->flag |= PTARGET_CURRENT;
213         pt->psys = 1;
214
215         BLI_addtail(&psys->targets, pt);
216
217         DAG_scene_sort(scene);
218         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
219
220         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
221         
222         return OPERATOR_FINISHED;
223 }
224
225 void PARTICLE_OT_new_target(wmOperatorType *ot)
226 {
227         /* identifiers */
228         ot->name= "New Particle Target";
229         ot->idname= "PARTICLE_OT_new_target";
230         ot->description="Add a new particle target";
231         
232         /* api callbacks */
233         ot->exec= new_particle_target_exec;
234
235         /* flags */
236         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
237 }
238
239 static int remove_particle_target_exec(bContext *C, wmOperator *op)
240 {
241         Scene *scene = CTX_data_scene(C);
242         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
243         ParticleSystem *psys= ptr.data;
244         Object *ob = ptr.id.data;
245
246         ParticleTarget *pt;
247
248         if(!psys)
249                 return OPERATOR_CANCELLED;
250
251         pt = psys->targets.first;
252         for(; pt; pt=pt->next) {
253                 if(pt->flag & PTARGET_CURRENT) {
254                         BLI_remlink(&psys->targets, pt);
255                         MEM_freeN(pt);
256                         break;
257                 }
258
259         }
260         pt = psys->targets.last;
261
262         if(pt)
263                 pt->flag |= PTARGET_CURRENT;
264
265         DAG_scene_sort(scene);
266         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
267
268         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
269         
270         return OPERATOR_FINISHED;
271 }
272
273 void PARTICLE_OT_target_remove(wmOperatorType *ot)
274 {
275         /* identifiers */
276         ot->name= "Remove Particle Target";
277         ot->idname= "PARTICLE_OT_target_remove";
278         ot->description="Remove the selected particle target";
279         
280         /* api callbacks */
281         ot->exec= remove_particle_target_exec;
282
283         /* flags */
284         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
285 }
286
287 /************************ move up particle target operator *********************/
288
289 static int target_move_up_exec(bContext *C, wmOperator *op)
290 {
291         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
292         ParticleSystem *psys= ptr.data;
293         Object *ob = ptr.id.data;
294         ParticleTarget *pt;
295
296         if(!psys)
297                 return OPERATOR_CANCELLED;
298         
299         pt = psys->targets.first;
300         for(; pt; pt=pt->next) {
301                 if(pt->flag & PTARGET_CURRENT && pt->prev) {
302                         BLI_remlink(&psys->targets, pt);
303                         BLI_insertlink(&psys->targets, pt->prev->prev, pt);
304
305                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
306                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
307                         break;
308                 }
309         }
310         
311         return OPERATOR_FINISHED;
312 }
313
314 void PARTICLE_OT_target_move_up(wmOperatorType *ot)
315 {
316         ot->name= "Move Up Target";
317         ot->idname= "PARTICLE_OT_target_move_up";
318         ot->description= "Move particle target up in the list";
319         
320         ot->exec= target_move_up_exec;
321         
322         /* flags */
323         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
324 }
325
326 /************************ move down particle target operator *********************/
327
328 static int target_move_down_exec(bContext *C, wmOperator *op)
329 {
330         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
331         ParticleSystem *psys= ptr.data;
332         Object *ob = ptr.id.data;
333         ParticleTarget *pt;
334
335         if(!psys)
336                 return OPERATOR_CANCELLED;
337         pt = psys->targets.first;
338         for(; pt; pt=pt->next) {
339                 if(pt->flag & PTARGET_CURRENT && pt->next) {
340                         BLI_remlink(&psys->targets, pt);
341                         BLI_insertlink(&psys->targets, pt->next, pt);
342
343                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
344                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
345                         break;
346                 }
347         }
348         
349         return OPERATOR_FINISHED;
350 }
351
352 void PARTICLE_OT_target_move_down(wmOperatorType *ot)
353 {
354         ot->name= "Move Down Target";
355         ot->idname= "PARTICLE_OT_target_move_down";
356         ot->description= "Move particle target down in the list";
357         
358         ot->exec= target_move_down_exec;
359         
360         /* flags */
361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
362 }
363
364 /************************ move up particle dupliweight operator *********************/
365
366 static int dupliob_move_up_exec(bContext *C, wmOperator *op)
367 {
368         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
369         ParticleSystem *psys= ptr.data;
370         ParticleSettings *part;
371         ParticleDupliWeight *dw;
372
373         if(!psys)
374                 return OPERATOR_CANCELLED;
375
376         part = psys->part;
377         for(dw=part->dupliweights.first; dw; dw=dw->next) {
378                 if(dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
379                         BLI_remlink(&part->dupliweights, dw);
380                         BLI_insertlink(&part->dupliweights, dw->prev->prev, dw);
381
382                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
383                         break;
384                 }
385         }
386         
387         return OPERATOR_FINISHED;
388 }
389
390 void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot)
391 {
392         ot->name= "Move Up Dupli Object";
393         ot->idname= "PARTICLE_OT_dupliob_move_up";
394         ot->description= "Move dupli object up in the list";
395         
396         ot->exec= dupliob_move_up_exec;
397         
398         /* flags */
399         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
400 }
401
402 /********************** particle dupliweight operators *********************/
403
404 static int copy_particle_dupliob_exec(bContext *C, wmOperator *op)
405 {
406         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
407         ParticleSystem *psys= ptr.data;
408         ParticleSettings *part;
409         ParticleDupliWeight *dw;
410
411         if(!psys)
412                 return OPERATOR_CANCELLED;
413         part = psys->part;
414         for(dw=part->dupliweights.first; dw; dw=dw->next) {
415                 if(dw->flag & PART_DUPLIW_CURRENT) {
416                         dw->flag &= ~PART_DUPLIW_CURRENT;
417                         dw = MEM_dupallocN(dw);
418                         dw->flag |= PART_DUPLIW_CURRENT;
419                         BLI_addhead(&part->dupliweights, dw);
420
421                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
422                         break;
423                 }
424         }
425         
426         return OPERATOR_FINISHED;
427 }
428
429 void PARTICLE_OT_dupliob_copy(wmOperatorType *ot)
430 {
431         /* identifiers */
432         ot->name= "Copy Particle Dupliob";
433         ot->idname= "PARTICLE_OT_dupliob_copy";
434         ot->description="Duplicate the current dupliobject";
435         
436         /* api callbacks */
437         ot->exec= copy_particle_dupliob_exec;
438
439         /* flags */
440         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
441 }
442
443 static int remove_particle_dupliob_exec(bContext *C, wmOperator *op)
444 {
445         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
446         ParticleSystem *psys= ptr.data;
447         ParticleSettings *part;
448         ParticleDupliWeight *dw;
449
450         if(!psys)
451                 return OPERATOR_CANCELLED;
452
453         part = psys->part;
454         for(dw=part->dupliweights.first; dw; dw=dw->next) {
455                 if(dw->flag & PART_DUPLIW_CURRENT) {
456                         BLI_remlink(&part->dupliweights, dw);
457                         MEM_freeN(dw);
458                         break;
459                 }
460
461         }
462         dw = part->dupliweights.last;
463
464         if(dw)
465                 dw->flag |= PART_DUPLIW_CURRENT;
466
467         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
468         
469         return OPERATOR_FINISHED;
470 }
471
472 void PARTICLE_OT_dupliob_remove(wmOperatorType *ot)
473 {
474         /* identifiers */
475         ot->name= "Remove Particle Dupliobject";
476         ot->idname= "PARTICLE_OT_dupliob_remove";
477         ot->description="Remove the selected dupliobject";
478         
479         /* api callbacks */
480         ot->exec= remove_particle_dupliob_exec;
481
482         /* flags */
483         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
484 }
485
486 /************************ move down particle dupliweight operator *********************/
487
488 static int dupliob_move_down_exec(bContext *C, wmOperator *op)
489 {
490         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
491         ParticleSystem *psys= ptr.data;
492         ParticleSettings *part;
493         ParticleDupliWeight *dw;
494
495         if(!psys)
496                 return OPERATOR_CANCELLED;
497
498         part = psys->part;
499         for(dw=part->dupliweights.first; dw; dw=dw->next) {
500                 if(dw->flag & PART_DUPLIW_CURRENT && dw->next) {
501                         BLI_remlink(&part->dupliweights, dw);
502                         BLI_insertlink(&part->dupliweights, dw->next, dw);
503
504                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL);
505                         break;
506                 }
507         }
508         
509         return OPERATOR_FINISHED;
510 }
511
512 void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
513 {
514         ot->name= "Move Down Dupli Object";
515         ot->idname= "PARTICLE_OT_dupliob_move_down";
516         ot->description= "Move dupli object down in the list";
517         
518         ot->exec= dupliob_move_down_exec;
519         
520         /* flags */
521         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
522 }
523
524 /************************ connect/disconnect hair operators *********************/
525
526 static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
527 {
528         ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
529         ParticleEditSettings *pset= PE_settings(scene);
530         ParticleData *pa;
531         PTCacheEdit *edit;
532         PTCacheEditPoint *point;
533         PTCacheEditKey *ekey = NULL;
534         HairKey *key;
535         int i, k;
536         float hairmat[4][4];
537
538         if(!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR)
539                 return;
540
541         if(!psys->part || psys->part->type != PART_HAIR)
542                 return;
543         
544         edit = psys->edit;
545         point= edit ? edit->points : NULL;
546
547         for(i=0, pa=psys->particles; i<psys->totpart; i++,pa++) {
548                 if(point) {
549                         ekey = point->keys;
550                         point++;
551                 }
552
553                 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
554
555                 for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
556                         mul_m4_v3(hairmat,key->co);
557                         
558                         if(ekey) {
559                                 ekey->flag &= ~PEK_USE_WCO;
560                                 ekey++;
561                         }
562                 }
563         }
564
565         psys_free_path_cache(psys, psys->edit);
566
567         psys->flag |= PSYS_GLOBAL_HAIR;
568
569         if(ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF))
570                 pset->brushtype = PE_BRUSH_NONE;
571
572         PE_update_object(scene, ob, 0);
573 }
574
575 static int disconnect_hair_exec(bContext *C, wmOperator *op)
576 {
577         Scene *scene= CTX_data_scene(C);
578         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
579         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
580         ParticleSystem *psys= NULL;
581         int all = RNA_boolean_get(op->ptr, "all");
582
583         if(!ob)
584                 return OPERATOR_CANCELLED;
585
586         if(all) {
587                 for(psys=ob->particlesystem.first; psys; psys=psys->next) {
588                         disconnect_hair(scene, ob, psys);
589                 }
590         }
591         else {
592                 psys = ptr.data;
593                 disconnect_hair(scene, ob, psys);
594         }
595
596         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
597
598         return OPERATOR_FINISHED;
599 }
600
601 void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
602 {
603         ot->name= "Disconnect Hair";
604         ot->description= "Disconnect hair from the emitter mesh";
605         ot->idname= "PARTICLE_OT_disconnect_hair";
606         
607         ot->exec= disconnect_hair_exec;
608         
609         /* flags */
610         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
611
612         RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
613 }
614
615 static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
616 {
617         ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
618         ParticleData *pa;
619         PTCacheEdit *edit;
620         PTCacheEditPoint *point;
621         PTCacheEditKey *ekey = NULL;
622         HairKey *key;
623         BVHTreeFromMesh bvhtree;
624         BVHTreeNearest nearest;
625         MFace *mface;
626         DerivedMesh *dm = NULL;
627         int numverts;
628         int i, k;
629         float hairmat[4][4], imat[4][4];
630         float v[4][3], vec[3];
631
632         if(!psys || !psys->part || psys->part->type != PART_HAIR)
633                 return;
634         
635         edit= psys->edit;
636         point=  edit ? edit->points : NULL;
637         
638         if(psmd->dm->deformedOnly)
639                 dm= psmd->dm;
640         else
641                 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
642
643         numverts = dm->getNumVerts (dm);
644
645         memset( &bvhtree, 0, sizeof(bvhtree) );
646
647         /* convert to global coordinates */
648         for (i=0; i<numverts; i++)
649                 mul_m4_v3(ob->obmat, CDDM_get_vert(dm, i)->co);
650
651         bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
652
653         for(i=0, pa= psys->particles; i<psys->totpart; i++,pa++) {
654                 key = pa->hair;
655
656                 nearest.index = -1;
657                 nearest.dist = FLT_MAX;
658
659                 BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
660
661                 if(nearest.index == -1) {
662                         if (G.f & G_DEBUG)
663                                 printf("No nearest point found for hair root!");
664                         continue;
665                 }
666
667                 mface = CDDM_get_face(dm,nearest.index);
668
669                 copy_v3_v3(v[0], CDDM_get_vert(dm,mface->v1)->co);
670                 copy_v3_v3(v[1], CDDM_get_vert(dm,mface->v2)->co);
671                 copy_v3_v3(v[2], CDDM_get_vert(dm,mface->v3)->co);
672                 if(mface->v4) {
673                         copy_v3_v3(v[3], CDDM_get_vert(dm,mface->v4)->co);
674                         interp_weights_poly_v3( pa->fuv,v, 4, nearest.co);
675                 }
676                 else
677                         interp_weights_poly_v3( pa->fuv,v, 3, nearest.co);
678
679                 pa->num = nearest.index;
680                 pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL);
681                 
682                 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
683                 invert_m4_m4(imat,hairmat);
684
685                 VECSUB(vec, nearest.co, key->co);
686
687                 if(point) {
688                         ekey = point->keys;
689                         point++;
690                 }
691
692                 for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
693                         VECADD(key->co, key->co, vec);
694                         mul_m4_v3(imat,key->co);
695
696                         if(ekey) {
697                                 ekey->flag |= PEK_USE_WCO;
698                                 ekey++;
699                         }
700                 }
701         }
702
703         free_bvhtree_from_mesh(&bvhtree);
704         if(!psmd->dm->deformedOnly)
705                 dm->release(dm);
706
707         psys_free_path_cache(psys, psys->edit);
708
709         psys->flag &= ~PSYS_GLOBAL_HAIR;
710
711         PE_update_object(scene, ob, 0);
712 }
713
714 static int connect_hair_exec(bContext *C, wmOperator *op)
715 {
716         Scene *scene= CTX_data_scene(C);
717         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
718         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
719         ParticleSystem *psys= NULL;
720         int all = RNA_boolean_get(op->ptr, "all");
721
722         if(!ob)
723                 return OPERATOR_CANCELLED;
724
725         if(all) {
726                 for(psys=ob->particlesystem.first; psys; psys=psys->next) {
727                         connect_hair(scene, ob, psys);
728                 }
729         }
730         else {
731                 psys = ptr.data;
732                 connect_hair(scene, ob, psys);
733         }
734
735         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
736
737         return OPERATOR_FINISHED;
738 }
739
740 void PARTICLE_OT_connect_hair(wmOperatorType *ot)
741 {
742         ot->name= "Connect Hair";
743         ot->description= "Connect hair to the emitter mesh";
744         ot->idname= "PARTICLE_OT_connect_hair";
745         
746         ot->exec= connect_hair_exec;
747         
748         /* flags */
749         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
750
751         RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
752 }
753