Blender  V2.93
particle_object.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_mesh_types.h"
30 #include "DNA_meshdata_types.h"
31 #include "DNA_modifier_types.h"
32 #include "DNA_scene_types.h"
33 
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 #include "BLI_string.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BKE_bvhutils.h"
40 #include "BKE_context.h"
41 #include "BKE_global.h"
42 #include "BKE_lib_id.h"
43 #include "BKE_main.h"
44 #include "BKE_mesh.h"
45 #include "BKE_mesh_runtime.h"
46 #include "BKE_modifier.h"
47 #include "BKE_object.h"
48 #include "BKE_particle.h"
49 #include "BKE_pointcache.h"
50 #include "BKE_report.h"
51 
52 #include "DEG_depsgraph.h"
53 #include "DEG_depsgraph_build.h"
54 #include "DEG_depsgraph_query.h"
55 
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58 
59 #include "WM_api.h"
60 #include "WM_types.h"
61 
62 #include "ED_object.h"
63 #include "ED_particle.h"
64 #include "ED_screen.h"
65 
66 #include "UI_resources.h"
67 
69 
70 #include "physics_intern.h"
71 
72 static float I[4][4] = {
73  {1.0f, 0.0f, 0.0f, 0.0f},
74  {0.0f, 1.0f, 0.0f, 0.0f},
75  {0.0f, 0.0f, 1.0f, 0.0f},
76  {0.0f, 0.0f, 0.0f, 1.0f},
77 };
78 
79 /********************** particle system slot operators *********************/
80 
82 {
83  Main *bmain = CTX_data_main(C);
84  Object *ob = ED_object_context(C);
86 
87  if (!scene || !ob) {
88  return OPERATOR_CANCELLED;
89  }
90 
92 
95 
96  return OPERATOR_FINISHED;
97 }
98 
100 {
101  /* identifiers */
102  ot->name = "Add Particle System Slot";
103  ot->idname = "OBJECT_OT_particle_system_add";
104  ot->description = "Add a particle system";
105 
106  /* api callbacks */
109 
110  /* flags */
112 }
113 
115 {
116  Main *bmain = CTX_data_main(C);
117  Object *ob = ED_object_context(C);
119  ViewLayer *view_layer = CTX_data_view_layer(C);
120  int mode_orig;
121 
122  if (!scene || !ob) {
123  return OPERATOR_CANCELLED;
124  }
125 
126  mode_orig = ob->mode;
128 
129  /* possible this isn't the active object
130  * object_remove_particle_system() clears the mode on the last psys
131  */
132  if (mode_orig & OB_MODE_PARTICLE_EDIT) {
133  if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
134  if (view_layer->basact && view_layer->basact->object == ob) {
136  }
137  }
138  }
139 
142 
143  return OPERATOR_FINISHED;
144 }
145 
147 {
148  /* identifiers */
149  ot->name = "Remove Particle System Slot";
150  ot->idname = "OBJECT_OT_particle_system_remove";
151  ot->description = "Remove the selected particle system";
152 
153  /* api callbacks */
156 
157  /* flags */
159 }
160 
161 /********************** new particle settings operator *********************/
162 
163 static bool psys_poll(bContext *C)
164 {
166  return (ptr.data != NULL);
167 }
168 
170 {
171  Main *bmain = CTX_data_main(C);
172  ParticleSystem *psys;
173  ParticleSettings *part = NULL;
174  Object *ob;
175  PointerRNA ptr;
176 
177  ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
178 
179  psys = ptr.data;
180 
181  /* add or copy particle setting */
182  if (psys->part) {
183  part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
184  }
185  else {
186  part = BKE_particlesettings_add(bmain, "ParticleSettings");
187  }
188 
189  ob = (Object *)ptr.owner_id;
190 
191  if (psys->part) {
192  id_us_min(&psys->part->id);
193  }
194 
195  psys->part = part;
196 
197  psys_check_boid_data(psys);
198 
201 
203 
204  return OPERATOR_FINISHED;
205 }
206 
208 {
209  /* identifiers */
210  ot->name = "New Particle Settings";
211  ot->idname = "PARTICLE_OT_new";
212  ot->description = "Add new particle settings";
213 
214  /* api callbacks */
216  ot->poll = psys_poll;
217 
218  /* flags */
220 }
221 
222 /********************** keyed particle target operators *********************/
223 
225 {
226  Main *bmain = CTX_data_main(C);
228  ParticleSystem *psys = ptr.data;
229  Object *ob = (Object *)ptr.owner_id;
230 
231  ParticleTarget *pt;
232 
233  if (!psys) {
234  return OPERATOR_CANCELLED;
235  }
236 
237  pt = psys->targets.first;
238  for (; pt; pt = pt->next) {
239  pt->flag &= ~PTARGET_CURRENT;
240  }
241 
242  pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");
243 
244  pt->flag |= PTARGET_CURRENT;
245  pt->psys = 1;
246 
247  BLI_addtail(&psys->targets, pt);
248 
251 
253 
254  return OPERATOR_FINISHED;
255 }
256 
258 {
259  /* identifiers */
260  ot->name = "New Particle Target";
261  ot->idname = "PARTICLE_OT_new_target";
262  ot->description = "Add a new particle target";
263 
264  /* api callbacks */
266 
267  /* flags */
269 }
270 
272 {
273  Main *bmain = CTX_data_main(C);
275  ParticleSystem *psys = ptr.data;
276  Object *ob = (Object *)ptr.owner_id;
277 
278  ParticleTarget *pt;
279 
280  if (!psys) {
281  return OPERATOR_CANCELLED;
282  }
283 
284  pt = psys->targets.first;
285  for (; pt; pt = pt->next) {
286  if (pt->flag & PTARGET_CURRENT) {
287  BLI_remlink(&psys->targets, pt);
288  MEM_freeN(pt);
289  break;
290  }
291  }
292  pt = psys->targets.last;
293 
294  if (pt) {
295  pt->flag |= PTARGET_CURRENT;
296  }
297 
300 
302 
303  return OPERATOR_FINISHED;
304 }
305 
307 {
308  /* identifiers */
309  ot->name = "Remove Particle Target";
310  ot->idname = "PARTICLE_OT_target_remove";
311  ot->description = "Remove the selected particle target";
312 
313  /* api callbacks */
315 
316  /* flags */
318 }
319 
320 /************************ move up particle target operator *********************/
321 
323 {
325  ParticleSystem *psys = ptr.data;
326  Object *ob = (Object *)ptr.owner_id;
327  ParticleTarget *pt;
328 
329  if (!psys) {
330  return OPERATOR_CANCELLED;
331  }
332 
333  pt = psys->targets.first;
334  for (; pt; pt = pt->next) {
335  if (pt->flag & PTARGET_CURRENT && pt->prev) {
336  BLI_remlink(&psys->targets, pt);
337  BLI_insertlinkbefore(&psys->targets, pt->prev, pt);
338 
341  break;
342  }
343  }
344 
345  return OPERATOR_FINISHED;
346 }
347 
349 {
350  ot->name = "Move Up Target";
351  ot->idname = "PARTICLE_OT_target_move_up";
352  ot->description = "Move particle target up in the list";
353 
355 
356  /* flags */
358 }
359 
360 /************************ move down particle target operator *********************/
361 
363 {
365  ParticleSystem *psys = ptr.data;
366  Object *ob = (Object *)ptr.owner_id;
367  ParticleTarget *pt;
368 
369  if (!psys) {
370  return OPERATOR_CANCELLED;
371  }
372  pt = psys->targets.first;
373  for (; pt; pt = pt->next) {
374  if (pt->flag & PTARGET_CURRENT && pt->next) {
375  BLI_remlink(&psys->targets, pt);
376  BLI_insertlinkafter(&psys->targets, pt->next, pt);
377 
380  break;
381  }
382  }
383 
384  return OPERATOR_FINISHED;
385 }
386 
388 {
389  ot->name = "Move Down Target";
390  ot->idname = "PARTICLE_OT_target_move_down";
391  ot->description = "Move particle target down in the list";
392 
394 
395  /* flags */
397 }
398 
399 /************************ refresh dupli objects *********************/
400 
402 {
404  ParticleSystem *psys = ptr.data;
405 
406  if (!psys) {
407  return OPERATOR_CANCELLED;
408  }
409 
413 
414  return OPERATOR_FINISHED;
415 }
416 
418 {
419  ot->name = "Refresh Instance Objects";
420  ot->idname = "PARTICLE_OT_dupliob_refresh";
421  ot->description = "Refresh list of instance objects and their weights";
422 
424 
425  /* flags */
427 }
428 
429 /************************ move up particle dupliweight operator *********************/
430 
432 {
434  ParticleSystem *psys = ptr.data;
435  ParticleSettings *part;
437 
438  if (!psys) {
439  return OPERATOR_CANCELLED;
440  }
441 
442  part = psys->part;
443  for (dw = part->instance_weights.first; dw; dw = dw->next) {
444  if (dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
445  BLI_remlink(&part->instance_weights, dw);
446  BLI_insertlinkbefore(&part->instance_weights, dw->prev, dw);
447 
450  break;
451  }
452  }
453 
454  return OPERATOR_FINISHED;
455 }
456 
458 {
459  ot->name = "Move Up Instance Object";
460  ot->idname = "PARTICLE_OT_dupliob_move_up";
461  ot->description = "Move instance object up in the list";
462 
464 
465  /* flags */
467 }
468 
469 /********************** particle dupliweight operators *********************/
470 
472 {
474  ParticleSystem *psys = ptr.data;
475  ParticleSettings *part;
477 
478  if (!psys) {
479  return OPERATOR_CANCELLED;
480  }
481  part = psys->part;
482  for (dw = part->instance_weights.first; dw; dw = dw->next) {
483  if (dw->flag & PART_DUPLIW_CURRENT) {
484  dw->flag &= ~PART_DUPLIW_CURRENT;
485  dw = MEM_dupallocN(dw);
486  dw->flag |= PART_DUPLIW_CURRENT;
487  BLI_addhead(&part->instance_weights, dw);
488 
491  break;
492  }
493  }
494 
495  return OPERATOR_FINISHED;
496 }
497 
499 {
500  /* identifiers */
501  ot->name = "Copy Particle Instance Object";
502  ot->idname = "PARTICLE_OT_dupliob_copy";
503  ot->description = "Duplicate the current instance object";
504 
505  /* api callbacks */
507 
508  /* flags */
510 }
511 
513 {
515  ParticleSystem *psys = ptr.data;
516  ParticleSettings *part;
518 
519  if (!psys) {
520  return OPERATOR_CANCELLED;
521  }
522 
523  part = psys->part;
524  for (dw = part->instance_weights.first; dw; dw = dw->next) {
525  if (dw->flag & PART_DUPLIW_CURRENT) {
526  BLI_remlink(&part->instance_weights, dw);
527  MEM_freeN(dw);
528  break;
529  }
530  }
531  dw = part->instance_weights.last;
532 
533  if (dw) {
534  dw->flag |= PART_DUPLIW_CURRENT;
535  }
536 
539 
540  return OPERATOR_FINISHED;
541 }
542 
544 {
545  /* identifiers */
546  ot->name = "Remove Particle Instance Object";
547  ot->idname = "PARTICLE_OT_dupliob_remove";
548  ot->description = "Remove the selected instance object";
549 
550  /* api callbacks */
552 
553  /* flags */
555 }
556 
557 /************************ move down particle dupliweight operator *********************/
558 
560 {
562  ParticleSystem *psys = ptr.data;
563  ParticleSettings *part;
565 
566  if (!psys) {
567  return OPERATOR_CANCELLED;
568  }
569 
570  part = psys->part;
571  for (dw = part->instance_weights.first; dw; dw = dw->next) {
572  if (dw->flag & PART_DUPLIW_CURRENT && dw->next) {
573  BLI_remlink(&part->instance_weights, dw);
574  BLI_insertlinkafter(&part->instance_weights, dw->next, dw);
575 
578  break;
579  }
580  }
581 
582  return OPERATOR_FINISHED;
583 }
584 
586 {
587  ot->name = "Move Down Instance Object";
588  ot->idname = "PARTICLE_OT_dupliob_move_down";
589  ot->description = "Move instance object down in the list";
590 
592 
593  /* flags */
595 }
596 
597 /************************ connect/disconnect hair operators *********************/
598 
600 {
601  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
602  ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
603  ParticleSystemModifierData *psmd_eval = psys_get_modifier(object_eval, psys_eval);
605  ParticleData *pa;
606  PTCacheEdit *edit;
607  PTCacheEditPoint *point;
608  PTCacheEditKey *ekey = NULL;
609  HairKey *key;
610  int i, k;
611  float hairmat[4][4];
612 
613  if (!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR) {
614  return;
615  }
616 
617  if (!psys->part || psys->part->type != PART_HAIR) {
618  return;
619  }
620 
621  edit = psys->edit;
622  point = edit ? edit->points : NULL;
623 
624  for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
625  if (point) {
626  ekey = point->keys;
627  point++;
628  }
629 
630  psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
631 
632  for (k = 0, key = pa->hair; k < pa->totkey; k++, key++) {
633  mul_m4_v3(hairmat, key->co);
634 
635  if (ekey) {
636  ekey->flag &= ~PEK_USE_WCO;
637  ekey++;
638  }
639  }
640  }
641 
642  psys_free_path_cache(psys, psys->edit);
643 
644  psys->flag |= PSYS_GLOBAL_HAIR;
645 
646  if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF)) {
647  pset->brushtype = PE_BRUSH_COMB;
648  }
649 
651 }
652 
654 {
657  Object *ob = ED_object_context(C);
658  ParticleSystem *psys = NULL;
659  const bool all = RNA_boolean_get(op->ptr, "all");
660 
661  if (!ob) {
662  return OPERATOR_CANCELLED;
663  }
664 
665  if (all) {
666  for (psys = ob->particlesystem.first; psys; psys = psys->next) {
667  disconnect_hair(depsgraph, scene, ob, psys);
668  }
669  }
670  else {
671  psys = psys_get_current(ob);
672  disconnect_hair(depsgraph, scene, ob, psys);
673  }
674 
677 
678  return OPERATOR_FINISHED;
679 }
680 
682 {
683  ot->name = "Disconnect Hair";
684  ot->description = "Disconnect hair from the emitter mesh";
685  ot->idname = "PARTICLE_OT_disconnect_hair";
686 
688 
689  /* flags */
690  /* No REGISTER, redo does not work due to missing update, see T47750. */
691  ot->flag = OPTYPE_UNDO;
692 
694  ot->srna, "all", 0, "All Hair", "Disconnect all hair systems from the emitter mesh");
695 }
696 
697 /* from/to_world_space : whether from/to particles are in world or hair space
698  * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
699  */
701  Scene *scene,
702  Object *ob,
703  ParticleSystem *psys,
704  Object *target_ob,
705  ParticleSystem *target_psys,
706  PTCacheEdit *target_edit,
707  const float from_mat[4][4],
708  const float to_mat[4][4],
709  bool from_global,
710  bool to_global)
711 {
712  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
713  ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
714  ParticleSystemModifierData *target_psmd = psys_get_modifier(object_eval, psys_eval);
715  ParticleData *pa, *tpa;
716  PTCacheEditPoint *edit_point;
717  PTCacheEditKey *ekey;
718  BVHTreeFromMesh bvhtree = {NULL};
719  MFace *mface = NULL, *mf;
720  MEdge *medge = NULL, *me;
721  MVert *mvert;
722  Mesh *mesh, *target_mesh;
723  int numverts;
724  int k;
725  float from_ob_imat[4][4], to_ob_imat[4][4];
726  float from_imat[4][4], to_imat[4][4];
727 
728  if (!target_psmd->mesh_final) {
729  return false;
730  }
731  if (!psys->part || psys->part->type != PART_HAIR) {
732  return false;
733  }
734  if (!target_psys->part || target_psys->part->type != PART_HAIR) {
735  return false;
736  }
737 
738  edit_point = target_edit ? target_edit->points : NULL;
739 
740  invert_m4_m4(from_ob_imat, ob->obmat);
741  invert_m4_m4(to_ob_imat, target_ob->obmat);
742  invert_m4_m4(from_imat, from_mat);
743  invert_m4_m4(to_imat, to_mat);
744 
745  const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
746  !target_psmd->mesh_final->runtime.deformed_only);
747 
748  if (use_dm_final_indices || !target_psmd->mesh_original) {
749  mesh = target_psmd->mesh_final;
750  }
751  else {
752  mesh = target_psmd->mesh_original;
753  }
754  target_mesh = target_psmd->mesh_final;
755  if (mesh == NULL) {
756  return false;
757  }
758  /* don't modify the original vertices */
759  /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
761 
762  /* BMESH_ONLY, deform dm may not have tessface */
764 
765  numverts = mesh->totvert;
766  mvert = mesh->mvert;
767 
768  /* convert to global coordinates */
769  for (int i = 0; i < numverts; i++) {
770  mul_m4_v3(to_mat, mvert[i].co);
771  }
772 
773  if (mesh->totface != 0) {
774  mface = mesh->mface;
776  }
777  else if (mesh->totedge != 0) {
778  medge = mesh->medge;
780  }
781  else {
783  return false;
784  }
785 
786  int i;
787  for (i = 0, tpa = target_psys->particles, pa = psys->particles; i < target_psys->totpart;
788  i++, tpa++, pa++) {
789  float from_co[3];
790  BVHTreeNearest nearest;
791 
792  if (from_global) {
793  mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
794  }
795  else {
796  mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
797  }
798  mul_m4_v3(from_mat, from_co);
799 
800  nearest.index = -1;
801  nearest.dist_sq = FLT_MAX;
802 
803  BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
804 
805  if (nearest.index == -1) {
806  if (G.debug & G_DEBUG) {
807  printf("No nearest point found for hair root!");
808  }
809  continue;
810  }
811 
812  if (mface) {
813  float v[4][3];
814 
815  mf = &mface[nearest.index];
816 
817  copy_v3_v3(v[0], mvert[mf->v1].co);
818  copy_v3_v3(v[1], mvert[mf->v2].co);
819  copy_v3_v3(v[2], mvert[mf->v3].co);
820  if (mf->v4) {
821  copy_v3_v3(v[3], mvert[mf->v4].co);
822  interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
823  }
824  else {
825  interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
826  }
827  tpa->foffset = 0.0f;
828 
829  tpa->num = nearest.index;
830  if (use_dm_final_indices) {
832  }
833  else {
835  target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
836  }
837  }
838  else {
839  me = &medge[nearest.index];
840 
841  tpa->fuv[1] = line_point_factor_v3(nearest.co, mvert[me->v1].co, mvert[me->v2].co);
842  tpa->fuv[0] = 1.0f - tpa->fuv[1];
843  tpa->fuv[2] = tpa->fuv[3] = 0.0f;
844  tpa->foffset = 0.0f;
845 
846  tpa->num = nearest.index;
847  tpa->num_dmcache = -1;
848  }
849 
850  /* translate hair keys */
851  {
852  HairKey *key, *tkey;
853  float hairmat[4][4], imat[4][4];
854  float offset[3];
855 
856  if (to_global) {
857  copy_m4_m4(imat, target_ob->obmat);
858  }
859  else {
860  /* note: using target_dm here, which is in target_ob object space and has full modifiers */
861  psys_mat_hair_to_object(target_ob, target_mesh, target_psys->part->from, tpa, hairmat);
862  invert_m4_m4(imat, hairmat);
863  }
864  mul_m4_m4m4(imat, imat, to_imat);
865 
866  /* offset in world space */
867  sub_v3_v3v3(offset, nearest.co, from_co);
868 
869  if (edit_point) {
870  for (k = 0, key = pa->hair, tkey = tpa->hair, ekey = edit_point->keys; k < tpa->totkey;
871  k++, key++, tkey++, ekey++) {
872  float co_orig[3];
873 
874  if (from_global) {
875  mul_v3_m4v3(co_orig, from_ob_imat, key->co);
876  }
877  else {
878  mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
879  }
880  mul_m4_v3(from_mat, co_orig);
881 
882  add_v3_v3v3(tkey->co, co_orig, offset);
883 
884  mul_m4_v3(imat, tkey->co);
885 
886  ekey->flag |= PEK_USE_WCO;
887  }
888 
889  edit_point++;
890  }
891  else {
892  for (k = 0, key = pa->hair, tkey = tpa->hair; k < tpa->totkey; k++, key++, tkey++) {
893  float co_orig[3];
894 
895  if (from_global) {
896  mul_v3_m4v3(co_orig, from_ob_imat, key->co);
897  }
898  else {
899  mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
900  }
901  mul_m4_v3(from_mat, co_orig);
902 
903  add_v3_v3v3(tkey->co, co_orig, offset);
904 
905  mul_m4_v3(imat, tkey->co);
906  }
907  }
908  }
909  }
910 
911  free_bvhtree_from_mesh(&bvhtree);
913 
914  psys_free_path_cache(target_psys, target_edit);
915 
916  PE_update_object(depsgraph, scene, target_ob, 0);
917 
918  return true;
919 }
920 
922 {
923  bool ok;
924 
925  if (!psys) {
926  return false;
927  }
928 
930  scene,
931  ob,
932  psys,
933  ob,
934  psys,
935  psys->edit,
936  ob->obmat,
937  ob->obmat,
938  psys->flag & PSYS_GLOBAL_HAIR,
939  false);
940  if (ok) {
941  psys->flag &= ~PSYS_GLOBAL_HAIR;
942  }
943 
944  return ok;
945 }
946 
948 {
951  Object *ob = ED_object_context(C);
952  ParticleSystem *psys = NULL;
953  const bool all = RNA_boolean_get(op->ptr, "all");
954  bool any_connected = false;
955 
956  if (!ob) {
957  return OPERATOR_CANCELLED;
958  }
959 
960  if (all) {
961  for (psys = ob->particlesystem.first; psys; psys = psys->next) {
962  any_connected |= connect_hair(depsgraph, scene, ob, psys);
963  }
964  }
965  else {
966  psys = psys_get_current(ob);
967  any_connected |= connect_hair(depsgraph, scene, ob, psys);
968  }
969 
970  if (!any_connected) {
971  BKE_report(op->reports,
972  RPT_WARNING,
973  "No hair connected (can't connect hair if particle system modifier is disabled)");
974  return OPERATOR_CANCELLED;
975  }
976 
979 
980  return OPERATOR_FINISHED;
981 }
982 
984 {
985  ot->name = "Connect Hair";
986  ot->description = "Connect hair to the emitter mesh";
987  ot->idname = "PARTICLE_OT_connect_hair";
988 
990 
991  /* flags */
992  /* No REGISTER, redo does not work due to missing update, see T47750. */
993  ot->flag = OPTYPE_UNDO;
994 
995  RNA_def_boolean(ot->srna, "all", 0, "All Hair", "Connect all hair systems to the emitter mesh");
996 }
997 
998 /************************ particle system copy operator *********************/
999 
1000 typedef enum eCopyParticlesSpace {
1004 
1006  Scene *scene,
1007  Object *ob,
1008  ParticleSystem *psys,
1009  ParticleSystem *psys_from)
1010 {
1011  PTCacheEdit *edit_from = psys_from->edit, *edit;
1012  ParticleData *pa;
1013  KEY_K;
1014  POINT_P;
1015 
1016  if (!edit_from) {
1017  return;
1018  }
1019 
1020  edit = MEM_dupallocN(edit_from);
1021  edit->psys = psys;
1022  psys->edit = edit;
1023 
1024  edit->pathcache = NULL;
1025  BLI_listbase_clear(&edit->pathcachebufs);
1026 
1027  edit->emitter_field = NULL;
1028  edit->emitter_cosnos = NULL;
1029 
1030  edit->points = MEM_dupallocN(edit_from->points);
1031  pa = psys->particles;
1032  LOOP_POINTS {
1033  HairKey *hkey = pa->hair;
1034 
1035  point->keys = MEM_dupallocN(point->keys);
1036  LOOP_KEYS {
1037  key->co = hkey->co;
1038  key->time = &hkey->time;
1039  key->flag = hkey->editflag;
1040  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1041  key->flag |= PEK_USE_WCO;
1042  hkey->editflag |= PEK_USE_WCO;
1043  }
1044 
1045  hkey++;
1046  }
1047 
1048  pa++;
1049  }
1050  update_world_cos(ob, edit);
1051 
1052  recalc_lengths(edit);
1053  recalc_emitter_field(depsgraph, ob, psys);
1054  PE_update_object(depsgraph, scene, ob, true);
1055 }
1056 
1058 {
1059  ModifierData *md, *md_next;
1060 
1061  if (ob_to->type != OB_MESH) {
1062  return;
1063  }
1064  if (!ob_to->data || ID_IS_LINKED(ob_to->data)) {
1065  return;
1066  }
1067 
1068  for (md = ob_to->modifiers.first; md; md = md_next) {
1069  md_next = md->next;
1070 
1071  /* remove all particle system modifiers as well,
1072  * these need to sync to the particle system list
1073  */
1074  if (ELEM(md->type,
1078  BLI_remlink(&ob_to->modifiers, md);
1079  BKE_modifier_free(md);
1080  }
1081  }
1082 
1084 }
1085 
1086 /* single_psys_from is optional, if NULL all psys of ob_from are copied */
1088  Scene *scene,
1089  Object *ob_from,
1090  ParticleSystem *single_psys_from,
1091  Object *ob_to,
1092  int space,
1093  bool duplicate_settings)
1094 {
1095  Main *bmain = CTX_data_main(C);
1097  ModifierData *md;
1098  ParticleSystem *psys_start = NULL, *psys, *psys_from;
1099  ParticleSystem **tmp_psys;
1100  CustomData_MeshMasks cdmask = {0};
1101  int i, totpsys;
1102 
1103  if (ob_to->type != OB_MESH) {
1104  return false;
1105  }
1106  if (!ob_to->data || ID_IS_LINKED(ob_to->data)) {
1107  return false;
1108  }
1109 
1110 /* For remapping we need a valid DM.
1111  * Because the modifiers are appended at the end it's safe to use
1112  * the final DM of the object without particles.
1113  * However, when evaluating the DM all the particle modifiers must be valid,
1114  * i.e. have the psys assigned already.
1115  *
1116  * To break this hen/egg problem we create all psys separately first
1117  * (to collect required customdata masks),
1118  * then create the DM, then add them to the object and make the psys modifiers.
1119  */
1120 #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
1121 #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
1122  totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
1123 
1124  tmp_psys = MEM_mallocN(sizeof(ParticleSystem *) * totpsys, "temporary particle system array");
1125 
1126  for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1127  psys = BKE_object_copy_particlesystem(psys_from, 0);
1128  tmp_psys[i] = psys;
1129 
1130  if (psys_start == NULL) {
1131  psys_start = psys;
1132  }
1133 
1134  psys_emitter_customdata_mask(psys, &cdmask);
1135  }
1136  /* to iterate source and target psys in sync,
1137  * we need to know where the newly added psys start
1138  */
1139  psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
1140 
1141  /* now append psys to the object and make modifiers */
1142  for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys;
1143  ++i, psys_from = PSYS_FROM_NEXT(psys_from)) {
1145 
1146  psys = tmp_psys[i];
1147 
1148  /* append to the object */
1149  BLI_addtail(&ob_to->particlesystem, psys);
1150  psys_unique_name(ob_to, psys, psys->name);
1151 
1152  /* add a particle system modifier for each system */
1154  psmd = (ParticleSystemModifierData *)md;
1155  /* push on top of the stack, no use trying to reproduce old stack order */
1156  BLI_addtail(&ob_to->modifiers, md);
1157 
1158  BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
1160 
1161  psmd->psys = psys;
1162 
1163  if (psys_from->edit) {
1164  copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from);
1165  }
1166 
1167  if (duplicate_settings) {
1168  id_us_min(&psys->part->id);
1169  psys->part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
1170  }
1171  }
1172  MEM_freeN(tmp_psys);
1173 
1174  /* note: do this after creating DM copies for all the particle system modifiers,
1175  * the remapping otherwise makes final_dm invalid!
1176  */
1177  for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
1178  psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1179  float(*from_mat)[4], (*to_mat)[4];
1180 
1181  switch (space) {
1182  case PAR_COPY_SPACE_OBJECT:
1183  from_mat = I;
1184  to_mat = I;
1185  break;
1186  case PAR_COPY_SPACE_WORLD:
1187  from_mat = ob_from->obmat;
1188  to_mat = ob_to->obmat;
1189  break;
1190  default:
1191  /* should not happen */
1192  from_mat = to_mat = NULL;
1193  BLI_assert(false);
1194  break;
1195  }
1196  if (ob_from != ob_to) {
1198  scene,
1199  ob_from,
1200  psys_from,
1201  ob_to,
1202  psys,
1203  psys->edit,
1204  from_mat,
1205  to_mat,
1206  psys_from->flag & PSYS_GLOBAL_HAIR,
1207  psys->flag & PSYS_GLOBAL_HAIR);
1208  }
1209 
1210  /* tag for recalc */
1211  // psys->recalc |= ID_RECALC_PSYS_RESET;
1212  }
1213 
1214 #undef PSYS_FROM_FIRST
1215 #undef PSYS_FROM_NEXT
1216 
1217  if (duplicate_settings) {
1218  DEG_relations_tag_update(bmain);
1219  }
1222  return true;
1223 }
1224 
1226 {
1227  Object *ob;
1229  return false;
1230  }
1231 
1234  return false;
1235  }
1236 
1237  return true;
1238 }
1239 
1241 {
1242  const int space = RNA_enum_get(op->ptr, "space");
1243  const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
1244  const bool use_active = RNA_boolean_get(op->ptr, "use_active");
1246  Object *ob_from = ED_object_active_context(C);
1247  ParticleSystem *psys_from =
1248  use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data :
1249  NULL;
1250 
1251  int changed_tot = 0;
1252  int fail = 0;
1253 
1254  CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects) {
1255  if (ob_from != ob_to) {
1256  bool changed = false;
1257  if (remove_target_particles) {
1259  changed = true;
1260  }
1261  if (copy_particle_systems_to_object(C, scene, ob_from, psys_from, ob_to, space, false)) {
1262  changed = true;
1263  }
1264  else {
1265  fail++;
1266  }
1267 
1268  if (changed) {
1269  changed_tot++;
1270  }
1271  }
1272  }
1273  CTX_DATA_END;
1274 
1275  if (changed_tot > 0) {
1278  }
1279 
1280  if ((changed_tot == 0 && fail == 0) || fail) {
1281  BKE_reportf(op->reports,
1282  RPT_ERROR,
1283  "Copy particle systems to selected: %d done, %d failed",
1284  changed_tot,
1285  fail);
1286  }
1287 
1288  return OPERATOR_FINISHED;
1289 }
1290 
1292 {
1293  static const EnumPropertyItem space_items[] = {
1294  {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
1295  {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
1296  {0, NULL, 0, NULL, NULL},
1297  };
1298 
1299  ot->name = "Copy Particle Systems";
1300  ot->description = "Copy particle systems from the active object to selected objects";
1301  ot->idname = "PARTICLE_OT_copy_particle_systems";
1302 
1305 
1306  /* flags */
1308 
1309  RNA_def_enum(ot->srna,
1310  "space",
1311  space_items,
1313  "Space",
1314  "Space transform for copying from one object to another");
1316  "remove_target_particles",
1317  true,
1318  "Remove Target Particles",
1319  "Remove particle systems on the target objects");
1321  "use_active",
1322  false,
1323  "Use Active",
1324  "Use the active particle system from the context");
1325 }
1326 
1328 {
1330  return false;
1331  }
1334  return false;
1335  }
1336  return true;
1337 }
1338 
1340 {
1341  const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
1344  /* Context pointer is only valid in the Properties Editor. */
1345  ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
1346  if (psys == NULL) {
1347  psys = psys_get_current(ob);
1348  }
1349 
1351  C, scene, ob, psys, ob, PAR_COPY_SPACE_OBJECT, duplicate_settings);
1352  return OPERATOR_FINISHED;
1353 }
1354 
1356 {
1357  ot->name = "Duplicate Particle System";
1358  ot->description = "Duplicate particle system within the active object";
1359  ot->idname = "PARTICLE_OT_duplicate_particle_system";
1360 
1363 
1364  /* flags */
1366 
1368  "use_duplicate_settings",
1369  false,
1370  "Duplicate Settings",
1371  "Duplicate settings as well, so the new particle system uses its own settings");
1372 }
typedef float(TangentPoint)[2]
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, const BVHCacheType bvh_cache_type, const int tree_type)
Definition: bvhutils.c:1413
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.c:1701
@ BVHTREE_FROM_EDGES
Definition: BKE_bvhutils.h:91
@ BVHTREE_FROM_FACES
Definition: BKE_bvhutils.h:92
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
Definition: context.c:456
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1401
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
#define CTX_DATA_END
Definition: BKE_context.h:260
@ G_DEBUG
Definition: BKE_global.h:133
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
void id_us_min(struct ID *id)
Definition: lib_id.c:297
@ LIB_ID_COPY_LOCALIZE
Definition: BKE_lib_id.h:145
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag)
void BKE_id_free(struct Main *bmain, void *idv)
void BKE_mesh_tessface_ensure(struct Mesh *mesh)
Definition: mesh.c:1560
void BKE_modifier_free(struct ModifierData *md)
struct ModifierData * BKE_modifier_new(int type)
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md)
General operations, lookup, etc. for blender objects.
struct ParticleSystem * BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag)
Definition: object.c:2349
void BKE_object_free_particlesystems(struct Object *ob)
Definition: object.c:1172
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition: particle.c:749
void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition: particle.c:3909
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition: particle.c:4086
void psys_check_group_weights(struct ParticleSettings *part)
Definition: particle.c:845
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
void object_remove_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob)
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname)
int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex, const float fw[4], struct LinkNode **poly_nodes)
Definition: particle.c:1913
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition: particle.c:2251
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition: particle.c:645
void psys_check_boid_data(struct ParticleSystem *psys)
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2201
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition: particle.c:986
#define DMCACHE_ISCHILD
Definition: BKE_particle.h:607
struct ModifierData * object_add_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob, const char *name)
Definition: particle.c:3975
#define PEK_USE_WCO
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1654
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3])
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3449
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_graph_tag_relations_update(struct Depsgraph *graph)
void DEG_relations_tag_update(struct Main *bmain)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_PSYS_REDO
Definition: DNA_ID.h:618
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
@ eModifierType_ParticleSystem
@ eModifierType_Fluid
@ eModifierType_DynamicPaint
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
#define PTARGET_CURRENT
#define PSYS_GLOBAL_HAIR
#define PART_DUPLIW_CURRENT
@ PART_HAIR
#define PE_BRUSH_PUFF
#define PE_BRUSH_ADD
#define PE_BRUSH_COMB
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
struct Object * ED_object_context(const struct bContext *C)
struct Object * ED_object_active_context(const struct bContext *C)
struct ParticleEditSettings * PE_settings(struct Scene *scene)
void PE_update_object(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int useflag)
bool ED_operator_object_active_local_editable(struct bContext *C)
Definition: screen_ops.c:378
Read Guarded memory(de)allocation.
StructRNA RNA_ParticleSystem
#define C
Definition: RandGen.cpp:39
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_MODE
Definition: WM_types.h:345
#define NC_SCENE
Definition: WM_types.h:279
#define NA_EDITED
Definition: WM_types.h:462
#define ND_PARTICLE
Definition: WM_types.h:366
#define NS_MODE_OBJECT
Definition: WM_types.h:441
#define ND_POINTCACHE
Definition: WM_types.h:367
#define NC_OBJECT
Definition: WM_types.h:280
ATTR_WARN_UNUSED_RESULT const BMVert * v
Scene scene
const Depsgraph * depsgraph
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
void update_world_cos(Object *ob, PTCacheEdit *edit)
void recalc_lengths(PTCacheEdit *edit)
#define POINT_P
#define LOOP_KEYS
#define KEY_K
#define LOOP_POINTS
static void disconnect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
static int connect_hair_exec(bContext *C, wmOperator *op)
static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
static bool duplicate_particle_systems_poll(bContext *C)
static int copy_particle_systems_exec(bContext *C, wmOperator *op)
void PARTICLE_OT_target_move_up(wmOperatorType *ot)
void PARTICLE_OT_dupliob_copy(wmOperatorType *ot)
void PARTICLE_OT_dupliob_refresh(wmOperatorType *ot)
static bool remap_hair_emitter(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, const float from_mat[4][4], const float to_mat[4][4], bool from_global, bool to_global)
static int copy_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
static float I[4][4]
static int remove_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_new(wmOperatorType *ot)
eCopyParticlesSpace
@ PAR_COPY_SPACE_OBJECT
@ PAR_COPY_SPACE_WORLD
void PARTICLE_OT_new_target(wmOperatorType *ot)
static int target_move_down_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
static int target_move_up_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
static bool psys_poll(bContext *C)
static int remove_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_target_remove(wmOperatorType *ot)
static void copy_particle_edit(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
static bool copy_particle_systems_poll(bContext *C)
void PARTICLE_OT_connect_hair(wmOperatorType *ot)
void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
void PARTICLE_OT_dupliob_remove(wmOperatorType *ot)
#define PSYS_FROM_FIRST
static bool copy_particle_systems_to_object(const bContext *C, Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space, bool duplicate_settings)
static int new_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op))
static void remove_particle_systems_from_object(Object *ob_to)
static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
static int disconnect_hair_exec(bContext *C, wmOperator *op)
static int duplicate_particle_systems_exec(bContext *C, wmOperator *op)
static int dupliob_refresh_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot)
#define PSYS_FROM_NEXT(cur)
static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op))
static int dupliob_move_down_exec(bContext *C, wmOperator *UNUSED(op))
void OBJECT_OT_particle_system_add(wmOperatorType *ot)
void PARTICLE_OT_target_move_down(wmOperatorType *ot)
void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot)
static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
static const EnumPropertyItem space_items[]
struct BVHTree * tree
Definition: BKE_bvhutils.h:66
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:69
float co[3]
Definition: BLI_kdopbvh.h:59
struct Object * object
float co[3]
float world_co[3]
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
float co[3]
Definition: BKE_main.h:116
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
int totface
Mesh_Runtime runtime
struct MFace * mface
struct ModifierData * next
ustring name
Definition: node.h:174
ListBase particlesystem
ListBase modifiers
float obmat[4][4]
void * data
struct PTCacheEditKey * keys
struct ParticleCacheKey ** pathcache
PTCacheEditPoint * points
struct ParticleDupliWeight * prev
struct ParticleDupliWeight * next
struct ListBase instance_weights
struct ParticleSystem * psys
struct PTCacheEdit * edit
ParticleData * particles
struct ListBase targets
ParticleSettings * part
struct ParticleSystem * next
void * data
Definition: RNA_types.h:52
struct ID * owner_id
Definition: RNA_types.h:50
struct Base * basact
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
__forceinline bool all(const avxb &b)
Definition: util_avxb.h:214
#define G(x, y, z)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156