Blender  V3.3
particle_object.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation. All rights reserved. */
3 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_mesh_types.h"
14 #include "DNA_meshdata_types.h"
15 #include "DNA_modifier_types.h"
16 #include "DNA_scene_types.h"
17 
18 #include "BLI_listbase.h"
19 #include "BLI_math.h"
20 #include "BLI_string.h"
21 #include "BLI_utildefines.h"
22 
23 #include "BKE_bvhutils.h"
24 #include "BKE_context.h"
25 #include "BKE_global.h"
26 #include "BKE_lib_id.h"
27 #include "BKE_main.h"
28 #include "BKE_mesh.h"
30 #include "BKE_mesh_runtime.h"
31 #include "BKE_modifier.h"
32 #include "BKE_object.h"
33 #include "BKE_particle.h"
34 #include "BKE_pointcache.h"
35 #include "BKE_report.h"
36 
37 #include "DEG_depsgraph.h"
38 #include "DEG_depsgraph_build.h"
39 #include "DEG_depsgraph_query.h"
40 
41 #include "RNA_access.h"
42 #include "RNA_define.h"
43 #include "RNA_prototypes.h"
44 
45 #include "WM_api.h"
46 #include "WM_types.h"
47 
48 #include "ED_object.h"
49 #include "ED_particle.h"
50 #include "ED_screen.h"
51 
52 #include "UI_resources.h"
53 
55 
56 #include "physics_intern.h"
57 
58 static float I[4][4] = {
59  {1.0f, 0.0f, 0.0f, 0.0f},
60  {0.0f, 1.0f, 0.0f, 0.0f},
61  {0.0f, 0.0f, 1.0f, 0.0f},
62  {0.0f, 0.0f, 0.0f, 1.0f},
63 };
64 
65 /********************** particle system slot operators *********************/
66 
68 {
69  Main *bmain = CTX_data_main(C);
70  Object *ob = ED_object_context(C);
72 
73  if (!scene || !ob) {
74  return OPERATOR_CANCELLED;
75  }
76 
78 
81 
82  return OPERATOR_FINISHED;
83 }
84 
86 {
87  /* identifiers */
88  ot->name = "Add Particle System Slot";
89  ot->idname = "OBJECT_OT_particle_system_add";
90  ot->description = "Add a particle system";
91 
92  /* api callbacks */
95 
96  /* flags */
98 }
99 
101 {
102  Main *bmain = CTX_data_main(C);
103  Object *ob = ED_object_context(C);
105  ViewLayer *view_layer = CTX_data_view_layer(C);
106  int mode_orig;
107 
108  if (!scene || !ob) {
109  return OPERATOR_CANCELLED;
110  }
111 
112  mode_orig = ob->mode;
113  ParticleSystem *psys = psys_get_current(ob);
114  object_remove_particle_system(bmain, scene, ob, psys);
115 
116  /* possible this isn't the active object
117  * object_remove_particle_system() clears the mode on the last psys
118  */
119  if (mode_orig & OB_MODE_PARTICLE_EDIT) {
120  if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
121  if (view_layer->basact && view_layer->basact->object == ob) {
123  }
124  }
125  }
126 
129 
130  return OPERATOR_FINISHED;
131 }
132 
134 {
135  /* identifiers */
136  ot->name = "Remove Particle System Slot";
137  ot->idname = "OBJECT_OT_particle_system_remove";
138  ot->description = "Remove the selected particle system";
139 
140  /* api callbacks */
143 
144  /* flags */
146 }
147 
148 /********************** new particle settings operator *********************/
149 
150 static bool psys_poll(bContext *C)
151 {
152  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
153  return (ptr.data != NULL);
154 }
155 
157 {
158  Main *bmain = CTX_data_main(C);
159  ParticleSystem *psys;
160  ParticleSettings *part = NULL;
161  Object *ob;
162  PointerRNA ptr;
163 
164  ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
165 
166  psys = ptr.data;
167 
168  /* add or copy particle setting */
169  if (psys->part) {
170  part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
171  }
172  else {
173  part = BKE_particlesettings_add(bmain, "ParticleSettings");
174  }
175 
176  ob = (Object *)ptr.owner_id;
177 
178  if (psys->part) {
179  id_us_min(&psys->part->id);
180  }
181 
182  psys->part = part;
183 
184  psys_check_boid_data(psys);
185 
188 
190 
191  return OPERATOR_FINISHED;
192 }
193 
195 {
196  /* identifiers */
197  ot->name = "New Particle Settings";
198  ot->idname = "PARTICLE_OT_new";
199  ot->description = "Add new particle settings";
200 
201  /* api callbacks */
203  ot->poll = psys_poll;
204 
205  /* flags */
207 }
208 
209 /********************** keyed particle target operators *********************/
210 
212 {
213  Main *bmain = CTX_data_main(C);
214  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
215  ParticleSystem *psys = ptr.data;
216  Object *ob = (Object *)ptr.owner_id;
217 
218  ParticleTarget *pt;
219 
220  if (!psys) {
221  return OPERATOR_CANCELLED;
222  }
223 
224  pt = psys->targets.first;
225  for (; pt; pt = pt->next) {
226  pt->flag &= ~PTARGET_CURRENT;
227  }
228 
229  pt = MEM_callocN(sizeof(ParticleTarget), "keyed particle target");
230 
231  pt->flag |= PTARGET_CURRENT;
232  pt->psys = 1;
233 
234  BLI_addtail(&psys->targets, pt);
235 
238 
240 
241  return OPERATOR_FINISHED;
242 }
243 
245 {
246  /* identifiers */
247  ot->name = "New Particle Target";
248  ot->idname = "PARTICLE_OT_new_target";
249  ot->description = "Add a new particle target";
250 
251  /* api callbacks */
253 
254  /* flags */
256 }
257 
259 {
260  Main *bmain = CTX_data_main(C);
261  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
262  ParticleSystem *psys = ptr.data;
263  Object *ob = (Object *)ptr.owner_id;
264 
265  ParticleTarget *pt;
266 
267  if (!psys) {
268  return OPERATOR_CANCELLED;
269  }
270 
271  pt = psys->targets.first;
272  for (; pt; pt = pt->next) {
273  if (pt->flag & PTARGET_CURRENT) {
274  BLI_remlink(&psys->targets, pt);
275  MEM_freeN(pt);
276  break;
277  }
278  }
279  pt = psys->targets.last;
280 
281  if (pt) {
282  pt->flag |= PTARGET_CURRENT;
283  }
284 
287 
289 
290  return OPERATOR_FINISHED;
291 }
292 
294 {
295  /* identifiers */
296  ot->name = "Remove Particle Target";
297  ot->idname = "PARTICLE_OT_target_remove";
298  ot->description = "Remove the selected particle target";
299 
300  /* api callbacks */
302 
303  /* flags */
305 }
306 
307 /************************ move up particle target operator *********************/
308 
310 {
311  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
312  ParticleSystem *psys = ptr.data;
313  Object *ob = (Object *)ptr.owner_id;
314  ParticleTarget *pt;
315 
316  if (!psys) {
317  return OPERATOR_CANCELLED;
318  }
319 
320  pt = psys->targets.first;
321  for (; pt; pt = pt->next) {
322  if (pt->flag & PTARGET_CURRENT && pt->prev) {
323  BLI_remlink(&psys->targets, pt);
324  BLI_insertlinkbefore(&psys->targets, pt->prev, pt);
325 
328  break;
329  }
330  }
331 
332  return OPERATOR_FINISHED;
333 }
334 
336 {
337  ot->name = "Move Up Target";
338  ot->idname = "PARTICLE_OT_target_move_up";
339  ot->description = "Move particle target up in the list";
340 
342 
343  /* flags */
345 }
346 
347 /************************ move down particle target operator *********************/
348 
350 {
351  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
352  ParticleSystem *psys = ptr.data;
353  Object *ob = (Object *)ptr.owner_id;
354  ParticleTarget *pt;
355 
356  if (!psys) {
357  return OPERATOR_CANCELLED;
358  }
359  pt = psys->targets.first;
360  for (; pt; pt = pt->next) {
361  if (pt->flag & PTARGET_CURRENT && pt->next) {
362  BLI_remlink(&psys->targets, pt);
363  BLI_insertlinkafter(&psys->targets, pt->next, pt);
364 
367  break;
368  }
369  }
370 
371  return OPERATOR_FINISHED;
372 }
373 
375 {
376  ot->name = "Move Down Target";
377  ot->idname = "PARTICLE_OT_target_move_down";
378  ot->description = "Move particle target down in the list";
379 
381 
382  /* flags */
384 }
385 
386 /************************ refresh dupli objects *********************/
387 
389 {
390  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
391  ParticleSystem *psys = ptr.data;
392 
393  if (!psys) {
394  return OPERATOR_CANCELLED;
395  }
396 
400 
401  return OPERATOR_FINISHED;
402 }
403 
405 {
406  ot->name = "Refresh Instance Objects";
407  ot->idname = "PARTICLE_OT_dupliob_refresh";
408  ot->description = "Refresh list of instance objects and their weights";
409 
411 
412  /* flags */
414 }
415 
416 /************************ move up particle dupliweight operator *********************/
417 
419 {
420  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
421  ParticleSystem *psys = ptr.data;
422  ParticleSettings *part;
424 
425  if (!psys) {
426  return OPERATOR_CANCELLED;
427  }
428 
429  part = psys->part;
430  for (dw = part->instance_weights.first; dw; dw = dw->next) {
431  if (dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
432  BLI_remlink(&part->instance_weights, dw);
433  BLI_insertlinkbefore(&part->instance_weights, dw->prev, dw);
434 
437  break;
438  }
439  }
440 
441  return OPERATOR_FINISHED;
442 }
443 
445 {
446  ot->name = "Move Up Instance Object";
447  ot->idname = "PARTICLE_OT_dupliob_move_up";
448  ot->description = "Move instance object up in the list";
449 
451 
452  /* flags */
454 }
455 
456 /********************** particle dupliweight operators *********************/
457 
459 {
460  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
461  ParticleSystem *psys = ptr.data;
462  ParticleSettings *part;
464 
465  if (!psys) {
466  return OPERATOR_CANCELLED;
467  }
468  part = psys->part;
469  for (dw = part->instance_weights.first; dw; dw = dw->next) {
470  if (dw->flag & PART_DUPLIW_CURRENT) {
471  dw->flag &= ~PART_DUPLIW_CURRENT;
472  dw = MEM_dupallocN(dw);
473  dw->flag |= PART_DUPLIW_CURRENT;
474  BLI_addhead(&part->instance_weights, dw);
475 
478  break;
479  }
480  }
481 
482  return OPERATOR_FINISHED;
483 }
484 
486 {
487  /* identifiers */
488  ot->name = "Copy Particle Instance Object";
489  ot->idname = "PARTICLE_OT_dupliob_copy";
490  ot->description = "Duplicate the current instance object";
491 
492  /* api callbacks */
494 
495  /* flags */
497 }
498 
500 {
501  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
502  ParticleSystem *psys = ptr.data;
503  ParticleSettings *part;
505 
506  if (!psys) {
507  return OPERATOR_CANCELLED;
508  }
509 
510  part = psys->part;
511  for (dw = part->instance_weights.first; dw; dw = dw->next) {
512  if (dw->flag & PART_DUPLIW_CURRENT) {
513  BLI_remlink(&part->instance_weights, dw);
514  MEM_freeN(dw);
515  break;
516  }
517  }
518  dw = part->instance_weights.last;
519 
520  if (dw) {
521  dw->flag |= PART_DUPLIW_CURRENT;
522  }
523 
526 
527  return OPERATOR_FINISHED;
528 }
529 
531 {
532  /* identifiers */
533  ot->name = "Remove Particle Instance Object";
534  ot->idname = "PARTICLE_OT_dupliob_remove";
535  ot->description = "Remove the selected instance object";
536 
537  /* api callbacks */
539 
540  /* flags */
542 }
543 
544 /************************ move down particle dupliweight operator *********************/
545 
547 {
548  PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
549  ParticleSystem *psys = ptr.data;
550  ParticleSettings *part;
552 
553  if (!psys) {
554  return OPERATOR_CANCELLED;
555  }
556 
557  part = psys->part;
558  for (dw = part->instance_weights.first; dw; dw = dw->next) {
559  if (dw->flag & PART_DUPLIW_CURRENT && dw->next) {
560  BLI_remlink(&part->instance_weights, dw);
561  BLI_insertlinkafter(&part->instance_weights, dw->next, dw);
562 
565  break;
566  }
567  }
568 
569  return OPERATOR_FINISHED;
570 }
571 
573 {
574  ot->name = "Move Down Instance Object";
575  ot->idname = "PARTICLE_OT_dupliob_move_down";
576  ot->description = "Move instance object down in the list";
577 
579 
580  /* flags */
582 }
583 
584 /************************ connect/disconnect hair operators *********************/
585 
587 {
588  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
589  ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
590  ParticleSystemModifierData *psmd_eval = psys_get_modifier(object_eval, psys_eval);
592  ParticleData *pa;
593  PTCacheEdit *edit;
595  PTCacheEditKey *ekey = NULL;
596  HairKey *key;
597  int i, k;
598  float hairmat[4][4];
599 
600  if (!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR) {
601  return;
602  }
603 
604  if (!psys->part || psys->part->type != PART_HAIR) {
605  return;
606  }
607 
608  edit = psys->edit;
609  point = edit ? edit->points : NULL;
610 
611  for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
612  if (point) {
613  ekey = point->keys;
614  point++;
615  }
616 
617  psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
618 
619  for (k = 0, key = pa->hair; k < pa->totkey; k++, key++) {
620  mul_m4_v3(hairmat, key->co);
621 
622  if (ekey) {
623  ekey->flag &= ~PEK_USE_WCO;
624  ekey++;
625  }
626  }
627  }
628 
629  psys_free_path_cache(psys, psys->edit);
630 
631  psys->flag |= PSYS_GLOBAL_HAIR;
632 
633  if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF)) {
634  pset->brushtype = PE_BRUSH_COMB;
635  }
636 
638 }
639 
641 {
644  Object *ob = ED_object_context(C);
645  ParticleSystem *psys = NULL;
646  const bool all = RNA_boolean_get(op->ptr, "all");
647 
648  if (!ob) {
649  return OPERATOR_CANCELLED;
650  }
651 
652  if (all) {
653  for (psys = ob->particlesystem.first; psys; psys = psys->next) {
654  disconnect_hair(depsgraph, scene, ob, psys);
655  }
656  }
657  else {
658  psys = psys_get_current(ob);
659  disconnect_hair(depsgraph, scene, ob, psys);
660  }
661 
664 
665  return OPERATOR_FINISHED;
666 }
667 
669 {
670  ot->name = "Disconnect Hair";
671  ot->description = "Disconnect hair from the emitter mesh";
672  ot->idname = "PARTICLE_OT_disconnect_hair";
673 
675 
676  /* flags */
677  /* No REGISTER, redo does not work due to missing update, see T47750. */
678  ot->flag = OPTYPE_UNDO;
679 
681  ot->srna, "all", 0, "All Hair", "Disconnect all hair systems from the emitter mesh");
682 }
683 
684 /* from/to_world_space : whether from/to particles are in world or hair space
685  * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
686  */
688  Scene *scene,
689  Object *ob,
690  ParticleSystem *psys,
691  Object *target_ob,
692  ParticleSystem *target_psys,
693  PTCacheEdit *target_edit,
694  const float from_mat[4][4],
695  const float to_mat[4][4],
696  bool from_global,
697  bool to_global)
698 {
699  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
700  ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
701  ParticleSystemModifierData *target_psmd = psys_get_modifier(object_eval, psys_eval);
702  ParticleData *pa, *tpa;
703  PTCacheEditPoint *edit_point;
704  PTCacheEditKey *ekey;
705  BVHTreeFromMesh bvhtree = {NULL};
706  MFace *mface = NULL, *mf;
707  MEdge *medge = NULL, *me;
708  MVert *mvert;
709  Mesh *mesh, *target_mesh;
710  int numverts;
711  int k;
712  float from_ob_imat[4][4], to_ob_imat[4][4];
713  float from_imat[4][4], to_imat[4][4];
714 
715  if (!target_psmd->mesh_final) {
716  return false;
717  }
718  if (!psys->part || psys->part->type != PART_HAIR) {
719  return false;
720  }
721  if (!target_psys->part || target_psys->part->type != PART_HAIR) {
722  return false;
723  }
724 
725  edit_point = target_edit ? target_edit->points : NULL;
726 
727  invert_m4_m4(from_ob_imat, ob->obmat);
728  invert_m4_m4(to_ob_imat, target_ob->obmat);
729  invert_m4_m4(from_imat, from_mat);
730  invert_m4_m4(to_imat, to_mat);
731 
732  const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
733  !target_psmd->mesh_final->runtime.deformed_only);
734 
735  if (use_dm_final_indices || !target_psmd->mesh_original) {
736  mesh = target_psmd->mesh_final;
737  }
738  else {
739  mesh = target_psmd->mesh_original;
740  }
741  target_mesh = target_psmd->mesh_final;
742  if (mesh == NULL) {
743  return false;
744  }
745  /* don't modify the original vertices */
746  /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
748 
749  /* BMESH_ONLY, deform dm may not have tessface */
751 
752  numverts = mesh->totvert;
753  mvert = mesh->mvert;
754 
755  /* convert to global coordinates */
756  for (int i = 0; i < numverts; i++) {
757  mul_m4_v3(to_mat, mvert[i].co);
758  }
759 
760  if (mesh->totface != 0) {
761  mface = mesh->mface;
763  }
764  else if (mesh->totedge != 0) {
765  medge = mesh->medge;
767  }
768  else {
770  return false;
771  }
772 
773  int i;
774  for (i = 0, tpa = target_psys->particles, pa = psys->particles; i < target_psys->totpart;
775  i++, tpa++, pa++) {
776  float from_co[3];
777  BVHTreeNearest nearest;
778 
779  if (from_global) {
780  mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
781  }
782  else {
783  mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
784  }
785  mul_m4_v3(from_mat, from_co);
786 
787  nearest.index = -1;
788  nearest.dist_sq = FLT_MAX;
789 
790  BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
791 
792  if (nearest.index == -1) {
793  if (G.debug & G_DEBUG) {
794  printf("No nearest point found for hair root!");
795  }
796  continue;
797  }
798 
799  if (mface) {
800  float v[4][3];
801 
802  mf = &mface[nearest.index];
803 
804  copy_v3_v3(v[0], mvert[mf->v1].co);
805  copy_v3_v3(v[1], mvert[mf->v2].co);
806  copy_v3_v3(v[2], mvert[mf->v3].co);
807  if (mf->v4) {
808  copy_v3_v3(v[3], mvert[mf->v4].co);
809  interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
810  }
811  else {
812  interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
813  }
814  tpa->foffset = 0.0f;
815 
816  tpa->num = nearest.index;
817  if (use_dm_final_indices) {
819  }
820  else {
822  target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
823  }
824  }
825  else {
826  me = &medge[nearest.index];
827 
828  tpa->fuv[1] = line_point_factor_v3(nearest.co, mvert[me->v1].co, mvert[me->v2].co);
829  tpa->fuv[0] = 1.0f - tpa->fuv[1];
830  tpa->fuv[2] = tpa->fuv[3] = 0.0f;
831  tpa->foffset = 0.0f;
832 
833  tpa->num = nearest.index;
834  tpa->num_dmcache = -1;
835  }
836 
837  /* translate hair keys */
838  {
839  HairKey *key, *tkey;
840  float hairmat[4][4], imat[4][4];
841  float offset[3];
842 
843  if (to_global) {
844  copy_m4_m4(imat, target_ob->obmat);
845  }
846  else {
847  /* NOTE: using target_dm here, which is in target_ob object space and has full modifiers.
848  */
849  psys_mat_hair_to_object(target_ob, target_mesh, target_psys->part->from, tpa, hairmat);
850  invert_m4_m4(imat, hairmat);
851  }
852  mul_m4_m4m4(imat, imat, to_imat);
853 
854  /* offset in world space */
855  sub_v3_v3v3(offset, nearest.co, from_co);
856 
857  if (edit_point) {
858  for (k = 0, key = pa->hair, tkey = tpa->hair, ekey = edit_point->keys; k < tpa->totkey;
859  k++, key++, tkey++, ekey++) {
860  float co_orig[3];
861 
862  if (from_global) {
863  mul_v3_m4v3(co_orig, from_ob_imat, key->co);
864  }
865  else {
866  mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
867  }
868  mul_m4_v3(from_mat, co_orig);
869 
870  add_v3_v3v3(tkey->co, co_orig, offset);
871 
872  mul_m4_v3(imat, tkey->co);
873 
874  ekey->flag |= PEK_USE_WCO;
875  }
876 
877  edit_point++;
878  }
879  else {
880  for (k = 0, key = pa->hair, tkey = tpa->hair; k < tpa->totkey; k++, key++, tkey++) {
881  float co_orig[3];
882 
883  if (from_global) {
884  mul_v3_m4v3(co_orig, from_ob_imat, key->co);
885  }
886  else {
887  mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
888  }
889  mul_m4_v3(from_mat, co_orig);
890 
891  add_v3_v3v3(tkey->co, co_orig, offset);
892 
893  mul_m4_v3(imat, tkey->co);
894  }
895  }
896  }
897  }
898 
899  free_bvhtree_from_mesh(&bvhtree);
901 
902  psys_free_path_cache(target_psys, target_edit);
903 
904  PE_update_object(depsgraph, scene, target_ob, 0);
905 
906  return true;
907 }
908 
910 {
911  bool ok;
912 
913  if (!psys) {
914  return false;
915  }
916 
918  scene,
919  ob,
920  psys,
921  ob,
922  psys,
923  psys->edit,
924  ob->obmat,
925  ob->obmat,
926  psys->flag & PSYS_GLOBAL_HAIR,
927  false);
928  if (ok) {
929  psys->flag &= ~PSYS_GLOBAL_HAIR;
930  }
931 
932  return ok;
933 }
934 
936 {
939  Object *ob = ED_object_context(C);
940  ParticleSystem *psys = NULL;
941  const bool all = RNA_boolean_get(op->ptr, "all");
942  bool any_connected = false;
943 
944  if (!ob) {
945  return OPERATOR_CANCELLED;
946  }
947 
948  if (all) {
949  for (psys = ob->particlesystem.first; psys; psys = psys->next) {
950  any_connected |= connect_hair(depsgraph, scene, ob, psys);
951  }
952  }
953  else {
954  psys = psys_get_current(ob);
955  any_connected |= connect_hair(depsgraph, scene, ob, psys);
956  }
957 
958  if (!any_connected) {
959  BKE_report(op->reports,
960  RPT_WARNING,
961  "No hair connected (can't connect hair if particle system modifier is disabled)");
962  return OPERATOR_CANCELLED;
963  }
964 
967 
968  return OPERATOR_FINISHED;
969 }
970 
972 {
973  ot->name = "Connect Hair";
974  ot->description = "Connect hair to the emitter mesh";
975  ot->idname = "PARTICLE_OT_connect_hair";
976 
978 
979  /* flags */
980  /* No REGISTER, redo does not work due to missing update, see T47750. */
981  ot->flag = OPTYPE_UNDO;
982 
983  RNA_def_boolean(ot->srna, "all", 0, "All Hair", "Connect all hair systems to the emitter mesh");
984 }
985 
986 /************************ particle system copy operator *********************/
987 
988 typedef enum eCopyParticlesSpace {
992 
994  Scene *scene,
995  Object *ob,
996  ParticleSystem *psys,
997  ParticleSystem *psys_from)
998 {
999  PTCacheEdit *edit_from = psys_from->edit, *edit;
1000  ParticleData *pa;
1001  KEY_K;
1002  POINT_P;
1003 
1004  if (!edit_from) {
1005  return;
1006  }
1007 
1008  edit = MEM_dupallocN(edit_from);
1009  edit->psys = psys;
1010  psys->edit = edit;
1011 
1012  edit->pathcache = NULL;
1013  BLI_listbase_clear(&edit->pathcachebufs);
1014 
1015  edit->emitter_field = NULL;
1016  edit->emitter_cosnos = NULL;
1017 
1018  edit->points = MEM_dupallocN(edit_from->points);
1019  pa = psys->particles;
1020  LOOP_POINTS {
1021  HairKey *hkey = pa->hair;
1022 
1023  point->keys = MEM_dupallocN(point->keys);
1024  LOOP_KEYS {
1025  key->co = hkey->co;
1026  key->time = &hkey->time;
1027  key->flag = hkey->editflag;
1028  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1029  key->flag |= PEK_USE_WCO;
1030  hkey->editflag |= PEK_USE_WCO;
1031  }
1032 
1033  hkey++;
1034  }
1035 
1036  pa++;
1037  }
1038  update_world_cos(ob, edit);
1039 
1040  recalc_lengths(edit);
1041  recalc_emitter_field(depsgraph, ob, psys);
1042  PE_update_object(depsgraph, scene, ob, true);
1043 }
1044 
1046 {
1047  ModifierData *md, *md_next;
1048 
1049  if (ob_to->type != OB_MESH) {
1050  return;
1051  }
1052  if (!ob_to->data || ID_IS_LINKED(ob_to->data) || ID_IS_OVERRIDE_LIBRARY(ob_to->data)) {
1053  return;
1054  }
1055 
1056  for (md = ob_to->modifiers.first; md; md = md_next) {
1057  md_next = md->next;
1058 
1059  /* remove all particle system modifiers as well,
1060  * these need to sync to the particle system list
1061  */
1062  if (ELEM(md->type,
1066  BLI_remlink(&ob_to->modifiers, md);
1067  BKE_modifier_free(md);
1068  }
1069  }
1070 
1072 }
1073 
1074 /* single_psys_from is optional, if NULL all psys of ob_from are copied */
1076  Scene *scene,
1077  Object *ob_from,
1078  ParticleSystem *single_psys_from,
1079  Object *ob_to,
1080  int space,
1081  bool duplicate_settings)
1082 {
1083  Main *bmain = CTX_data_main(C);
1085  ModifierData *md;
1086  ParticleSystem *psys_start = NULL, *psys, *psys_from;
1087  ParticleSystem **tmp_psys;
1088  CustomData_MeshMasks cdmask = {0};
1089  int i, totpsys;
1090 
1091  if (ob_to->type != OB_MESH) {
1092  return false;
1093  }
1094  if (!ob_to->data || !BKE_id_is_editable(bmain, ob_to->data)) {
1095  return false;
1096  }
1097 
1098 /* For remapping we need a valid DM.
1099  * Because the modifiers are appended at the end it's safe to use
1100  * the final DM of the object without particles.
1101  * However, when evaluating the DM all the particle modifiers must be valid,
1102  * i.e. have the psys assigned already.
1103  *
1104  * To break this hen/egg problem we create all psys separately first
1105  * (to collect required customdata masks),
1106  * then create the DM, then add them to the object and make the psys modifiers.
1107  */
1108 #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
1109 #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
1110  totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
1111 
1112  tmp_psys = MEM_mallocN(sizeof(ParticleSystem *) * totpsys, "temporary particle system array");
1113 
1114  for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1115  psys = BKE_object_copy_particlesystem(psys_from, 0);
1116  tmp_psys[i] = psys;
1117 
1118  if (psys_start == NULL) {
1119  psys_start = psys;
1120  }
1121 
1122  psys_emitter_customdata_mask(psys, &cdmask);
1123  }
1124  /* to iterate source and target psys in sync,
1125  * we need to know where the newly added psys start
1126  */
1127  psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
1128 
1129  /* now append psys to the object and make modifiers */
1130  for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys;
1131  ++i, psys_from = PSYS_FROM_NEXT(psys_from)) {
1133 
1134  psys = tmp_psys[i];
1135 
1136  /* append to the object */
1137  BLI_addtail(&ob_to->particlesystem, psys);
1138  psys_unique_name(ob_to, psys, psys->name);
1139 
1140  /* add a particle system modifier for each system */
1142  psmd = (ParticleSystemModifierData *)md;
1143  /* push on top of the stack, no use trying to reproduce old stack order */
1144  BLI_addtail(&ob_to->modifiers, md);
1145 
1146  BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
1148 
1149  psmd->psys = psys;
1150 
1151  if (psys_from->edit) {
1152  copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from);
1153  }
1154 
1155  if (duplicate_settings) {
1156  id_us_min(&psys->part->id);
1157  psys->part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
1158  }
1159  }
1160  MEM_freeN(tmp_psys);
1161 
1162  /* NOTE: do this after creating DM copies for all the particle system modifiers,
1163  * the remapping otherwise makes final_dm invalid!
1164  */
1165  for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
1166  psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1167  float(*from_mat)[4], (*to_mat)[4];
1168 
1169  switch (space) {
1170  case PAR_COPY_SPACE_OBJECT:
1171  from_mat = I;
1172  to_mat = I;
1173  break;
1174  case PAR_COPY_SPACE_WORLD:
1175  from_mat = ob_from->obmat;
1176  to_mat = ob_to->obmat;
1177  break;
1178  default:
1179  /* should not happen */
1180  from_mat = to_mat = NULL;
1181  BLI_assert(false);
1182  break;
1183  }
1184  if (ob_from != ob_to) {
1186  scene,
1187  ob_from,
1188  psys_from,
1189  ob_to,
1190  psys,
1191  psys->edit,
1192  from_mat,
1193  to_mat,
1194  psys_from->flag & PSYS_GLOBAL_HAIR,
1195  psys->flag & PSYS_GLOBAL_HAIR);
1196  }
1197 
1198  /* tag for recalc */
1199  // psys->recalc |= ID_RECALC_PSYS_RESET;
1200  }
1201 
1202 #undef PSYS_FROM_FIRST
1203 #undef PSYS_FROM_NEXT
1204 
1205  if (duplicate_settings) {
1206  DEG_relations_tag_update(bmain);
1207  }
1210  return true;
1211 }
1212 
1214 {
1215  Object *ob;
1217  return false;
1218  }
1219 
1222  return false;
1223  }
1224 
1225  return true;
1226 }
1227 
1229 {
1230  const int space = RNA_enum_get(op->ptr, "space");
1231  const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
1232  const bool use_active = RNA_boolean_get(op->ptr, "use_active");
1234  Object *ob_from = ED_object_active_context(C);
1235 
1236  ParticleSystem *psys_from = NULL;
1237  if (use_active) {
1238  psys_from = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
1239  if (psys_from == NULL) {
1240  /* Particle System context pointer is only valid in the Properties Editor. */
1241  psys_from = psys_get_current(ob_from);
1242  }
1243  }
1244 
1245  int changed_tot = 0;
1246  int fail = 0;
1247 
1248  CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects) {
1249  if (ob_from != ob_to) {
1250  bool changed = false;
1251  if (remove_target_particles) {
1253  changed = true;
1254  }
1255  if (copy_particle_systems_to_object(C, scene, ob_from, psys_from, ob_to, space, false)) {
1256  changed = true;
1257  }
1258  else {
1259  fail++;
1260  }
1261 
1262  if (changed) {
1263  changed_tot++;
1264  }
1265  }
1266  }
1267  CTX_DATA_END;
1268 
1269  if (changed_tot > 0) {
1272  }
1273 
1274  if ((changed_tot == 0 && fail == 0) || fail) {
1275  BKE_reportf(op->reports,
1276  RPT_ERROR,
1277  "Copy particle systems to selected: %d done, %d failed",
1278  changed_tot,
1279  fail);
1280  }
1281 
1282  return OPERATOR_FINISHED;
1283 }
1284 
1286 {
1287  static const EnumPropertyItem space_items[] = {
1288  {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
1289  {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
1290  {0, NULL, 0, NULL, NULL},
1291  };
1292 
1293  ot->name = "Copy Particle Systems";
1294  ot->description = "Copy particle systems from the active object to selected objects";
1295  ot->idname = "PARTICLE_OT_copy_particle_systems";
1296 
1299 
1300  /* flags */
1302 
1303  RNA_def_enum(ot->srna,
1304  "space",
1305  space_items,
1307  "Space",
1308  "Space transform for copying from one object to another");
1310  "remove_target_particles",
1311  true,
1312  "Remove Target Particles",
1313  "Remove particle systems on the target objects");
1315  "use_active",
1316  false,
1317  "Use Active",
1318  "Use the active particle system from the context");
1319 }
1320 
1322 {
1324  return false;
1325  }
1328  return false;
1329  }
1330  return true;
1331 }
1332 
1334 {
1335  const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
1338  /* Context pointer is only valid in the Properties Editor. */
1339  ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
1340  if (psys == NULL) {
1341  psys = psys_get_current(ob);
1342  }
1343 
1345  C, scene, ob, psys, ob, PAR_COPY_SPACE_OBJECT, duplicate_settings);
1346  return OPERATOR_FINISHED;
1347 }
1348 
1350 {
1351  ot->name = "Duplicate Particle System";
1352  ot->description = "Duplicate particle system within the active object";
1353  ot->idname = "PARTICLE_OT_duplicate_particle_system";
1354 
1357 
1358  /* flags */
1360 
1362  "use_duplicate_settings",
1363  false,
1364  "Duplicate Settings",
1365  "Duplicate settings as well, so the new particle system uses its own settings");
1366 }
typedef float(TangentPoint)[2]
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_EDGES
Definition: BKE_bvhutils.h:71
@ BVHTREE_FROM_FACES
Definition: BKE_bvhutils.h:72
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
Definition: context.c:473
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
#define CTX_DATA_END
Definition: BKE_context.h:278
@ G_DEBUG
Definition: BKE_global.h:174
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
@ LIB_ID_COPY_LOCALIZE
Definition: BKE_lib_id.h:187
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag)
bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id)
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void BKE_id_free(struct Main *bmain, void *idv)
void BKE_mesh_tessface_ensure(struct Mesh *mesh)
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.
void BKE_object_free_particlesystems(struct Object *ob)
Definition: object.cc:1261
struct ParticleSystem * BKE_object_copy_particlesystem(struct ParticleSystem *psys, int flag)
Definition: object.cc:2379
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition: particle.c:761
void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition: particle.c:3935
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition: particle.c:4115
void psys_check_group_weights(struct ParticleSettings *part)
Definition: particle.c:857
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname)
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition: particle.c:2283
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition: particle.c:634
void psys_check_boid_data(struct ParticleSystem *psys)
void object_remove_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys)
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2230
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition: particle.c:997
#define DMCACHE_ISCHILD
Definition: BKE_particle.h:673
int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
Definition: particle.c:1923
struct ModifierData * object_add_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob, const char *name)
Definition: particle.c:4002
#define PEK_USE_WCO
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1616
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3254
void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
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:35
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:798
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ eModifierType_ParticleSystem
@ eModifierType_Fluid
@ eModifierType_DynamicPaint
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
#define PTARGET_CURRENT
@ PART_HAIR
#define PSYS_GLOBAL_HAIR
#define PART_DUPLIW_CURRENT
#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:407
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_MODE
Definition: WM_types.h:393
#define NC_SCENE
Definition: WM_types.h:328
#define NA_EDITED
Definition: WM_types.h:523
#define ND_PARTICLE
Definition: WM_types.h:414
#define NS_MODE_OBJECT
Definition: WM_types.h:501
#define ND_POINTCACHE
Definition: WM_types.h:415
#define NC_OBJECT
Definition: WM_types.h:329
__forceinline bool all(const avxb &b)
Definition: avxb.h:201
ATTR_WARN_UNUSED_RESULT const BMVert * v
Scene scene
const Depsgraph * depsgraph
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
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:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
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:3783
static const EnumPropertyItem space_items[]
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:53
float co[3]
Definition: BLI_kdopbvh.h:43
struct Object * object
float co[3]
float world_co[3]
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
float co[3]
Definition: BKE_main.h:121
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
int totface
Mesh_Runtime runtime
struct MFace * mface
struct ModifierData * next
ustring name
Definition: graph/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:38
struct ID * owner_id
Definition: RNA_types.h:36
struct Base * basact
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
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:3480
wmOperatorType * ot
Definition: wm_files.c:3479