Blender V4.5
particle_object.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_mesh_types.h"
15#include "DNA_meshdata_types.h"
16#include "DNA_modifier_types.h"
17#include "DNA_scene_types.h"
18
19#include "BLI_listbase.h"
20#include "BLI_math_geom.h"
21#include "BLI_math_matrix.h"
22#include "BLI_math_vector.h"
23#include "BLI_string.h"
24#include "BLI_utildefines.h"
25
26#include "BKE_bvhutils.hh"
27#include "BKE_context.hh"
28#include "BKE_customdata.hh"
29#include "BKE_global.hh"
30#include "BKE_layer.hh"
31#include "BKE_lib_id.hh"
32#include "BKE_library.hh"
33#include "BKE_mesh.hh"
35#include "BKE_modifier.hh"
36#include "BKE_object.hh"
37#include "BKE_particle.h"
38#include "BKE_pointcache.h"
39#include "BKE_report.hh"
40
41#include "DEG_depsgraph.hh"
44
45#include "RNA_access.hh"
46#include "RNA_define.hh"
47#include "RNA_prototypes.hh"
48
49#include "WM_api.hh"
50#include "WM_types.hh"
51
52#include "ED_object.hh"
53#include "ED_particle.hh"
54#include "ED_screen.hh"
55
57
58#include "physics_intern.hh"
59
60static float I[4][4] = {
61 {1.0f, 0.0f, 0.0f, 0.0f},
62 {0.0f, 1.0f, 0.0f, 0.0f},
63 {0.0f, 0.0f, 1.0f, 0.0f},
64 {0.0f, 0.0f, 0.0f, 1.0f},
65};
66
67/********************** particle system slot operators *********************/
68
70{
71 Main *bmain = CTX_data_main(C);
73 Scene *scene = CTX_data_scene(C);
74
75 if (!scene || !ob) {
76 return OPERATOR_CANCELLED;
77 }
78
79 object_add_particle_system(bmain, scene, ob, nullptr);
80
83
84 return OPERATOR_FINISHED;
85}
86
88{
89 /* identifiers */
90 ot->name = "Add Particle System Slot";
91 ot->idname = "OBJECT_OT_particle_system_add";
92 ot->description = "Add a particle system";
93
94 /* API callbacks. */
97
98 /* flags */
100}
101
103{
104 Main *bmain = CTX_data_main(C);
106 Scene *scene = CTX_data_scene(C);
107 ViewLayer *view_layer = CTX_data_view_layer(C);
108 int mode_orig;
109
110 if (!scene || !ob) {
111 return OPERATOR_CANCELLED;
112 }
113
114 mode_orig = ob->mode;
116 object_remove_particle_system(bmain, scene, ob, psys);
117
118 /* possible this isn't the active object
119 * object_remove_particle_system() clears the mode on the last psys
120 */
121 if (mode_orig & OB_MODE_PARTICLE_EDIT) {
122 if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
123 BKE_view_layer_synced_ensure(scene, view_layer);
124 if (BKE_view_layer_active_object_get(view_layer) == ob) {
126 }
127 }
128 }
129
132
133 return OPERATOR_FINISHED;
134}
135
137{
138 /* identifiers */
139 ot->name = "Remove Particle System Slot";
140 ot->idname = "OBJECT_OT_particle_system_remove";
141 ot->description = "Remove the selected particle system";
142
143 /* API callbacks. */
146
147 /* flags */
149}
150
151/********************** new particle settings operator *********************/
152
153static bool psys_poll(bContext *C)
154{
155 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
156 return (ptr.data != nullptr);
157}
158
160{
161 Main *bmain = CTX_data_main(C);
162 ParticleSystem *psys;
163 ParticleSettings *part = nullptr;
164 Object *ob;
166
167 ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
168
169 psys = static_cast<ParticleSystem *>(ptr.data);
170
171 /* add or copy particle setting */
172 if (psys->part) {
173 part = reinterpret_cast<ParticleSettings *>(BKE_id_copy_ex(
174 bmain, &psys->part->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
175 }
176 else {
177 part = BKE_particlesettings_add(bmain, "ParticleSettings");
178 }
179
180 ob = (Object *)ptr.owner_id;
181
182 if (psys->part) {
183 id_us_min(&psys->part->id);
184 }
185
186 psys->part = part;
187
189
192
194
195 return OPERATOR_FINISHED;
196}
197
199{
200 /* identifiers */
201 ot->name = "New Particle Settings";
202 ot->idname = "PARTICLE_OT_new";
203 ot->description = "Add new particle settings";
204
205 /* API callbacks. */
207 ot->poll = psys_poll;
208
209 /* flags */
211}
212
213/********************** keyed particle target operators *********************/
214
216{
217 Main *bmain = CTX_data_main(C);
218 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
219 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
220 Object *ob = (Object *)ptr.owner_id;
221
222 ParticleTarget *pt;
223
224 if (!psys) {
225 return OPERATOR_CANCELLED;
226 }
227
228 pt = static_cast<ParticleTarget *>(psys->targets.first);
229 for (; pt; pt = pt->next) {
230 pt->flag &= ~PTARGET_CURRENT;
231 }
232
233 pt = MEM_callocN<ParticleTarget>("keyed particle target");
234
235 pt->flag |= PTARGET_CURRENT;
236 pt->psys = 1;
237
238 BLI_addtail(&psys->targets, pt);
239
242
244
245 return OPERATOR_FINISHED;
246}
247
249{
250 /* identifiers */
251 ot->name = "New Particle Target";
252 ot->idname = "PARTICLE_OT_new_target";
253 ot->description = "Add a new particle target";
254
255 /* API callbacks. */
257
258 /* flags */
260}
261
263{
264 Main *bmain = CTX_data_main(C);
265 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
266 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
267 Object *ob = (Object *)ptr.owner_id;
268
269 ParticleTarget *pt;
270
271 if (!psys) {
272 return OPERATOR_CANCELLED;
273 }
274
275 pt = static_cast<ParticleTarget *>(psys->targets.first);
276 for (; pt; pt = pt->next) {
277 if (pt->flag & PTARGET_CURRENT) {
278 BLI_remlink(&psys->targets, pt);
279 MEM_freeN(pt);
280 break;
281 }
282 }
283 pt = static_cast<ParticleTarget *>(psys->targets.last);
284
285 if (pt) {
286 pt->flag |= PTARGET_CURRENT;
287 }
288
291
293
294 return OPERATOR_FINISHED;
295}
296
298{
299 /* identifiers */
300 ot->name = "Remove Particle Target";
301 ot->idname = "PARTICLE_OT_target_remove";
302 ot->description = "Remove the selected particle target";
303
304 /* API callbacks. */
306
307 /* flags */
309}
310
311/************************ move up particle target operator *********************/
312
314{
315 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
316 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
317 Object *ob = (Object *)ptr.owner_id;
318 ParticleTarget *pt;
319
320 if (!psys) {
321 return OPERATOR_CANCELLED;
322 }
323
324 pt = static_cast<ParticleTarget *>(psys->targets.first);
325 for (; pt; pt = pt->next) {
326 if (pt->flag & PTARGET_CURRENT && pt->prev) {
327 BLI_remlink(&psys->targets, pt);
328 BLI_insertlinkbefore(&psys->targets, pt->prev, pt);
329
332 break;
333 }
334 }
335
336 return OPERATOR_FINISHED;
337}
338
340{
341 ot->name = "Move Up Target";
342 ot->idname = "PARTICLE_OT_target_move_up";
343 ot->description = "Move particle target up in the list";
344
345 ot->exec = target_move_up_exec;
346
347 /* flags */
349}
350
351/************************ move down particle target operator *********************/
352
354{
355 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
356 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
357 Object *ob = (Object *)ptr.owner_id;
358 ParticleTarget *pt;
359
360 if (!psys) {
361 return OPERATOR_CANCELLED;
362 }
363 pt = static_cast<ParticleTarget *>(psys->targets.first);
364 for (; pt; pt = pt->next) {
365 if (pt->flag & PTARGET_CURRENT && pt->next) {
366 BLI_remlink(&psys->targets, pt);
367 BLI_insertlinkafter(&psys->targets, pt->next, pt);
368
371 break;
372 }
373 }
374
375 return OPERATOR_FINISHED;
376}
377
379{
380 ot->name = "Move Down Target";
381 ot->idname = "PARTICLE_OT_target_move_down";
382 ot->description = "Move particle target down in the list";
383
385
386 /* flags */
388}
389
390/************************ refresh dupli objects *********************/
391
393{
394 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
395 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
396
397 if (!psys) {
398 return OPERATOR_CANCELLED;
399 }
400
404
405 return OPERATOR_FINISHED;
406}
407
409{
410 ot->name = "Refresh Instance Objects";
411 ot->idname = "PARTICLE_OT_dupliob_refresh";
412 ot->description = "Refresh list of instance objects and their weights";
413
414 ot->exec = dupliob_refresh_exec;
415
416 /* flags */
418}
419
420/************************ move up particle dupli-weight operator *********************/
421
423{
424 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
425 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
426 ParticleSettings *part;
427
428 if (!psys) {
429 return OPERATOR_CANCELLED;
430 }
431
432 part = psys->part;
434 if (dw->flag & PART_DUPLIW_CURRENT && dw->prev) {
435 BLI_remlink(&part->instance_weights, dw);
436 BLI_insertlinkbefore(&part->instance_weights, dw->prev, dw);
437
440 break;
441 }
442 }
443
444 return OPERATOR_FINISHED;
445}
446
448{
449 ot->name = "Move Up Instance Object";
450 ot->idname = "PARTICLE_OT_dupliob_move_up";
451 ot->description = "Move instance object up in the list";
452
453 ot->exec = dupliob_move_up_exec;
454
455 /* flags */
457}
458
459/********************** particle dupliweight operators *********************/
460
462{
463 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
464 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
465 ParticleSettings *part;
466
467 if (!psys) {
468 return OPERATOR_CANCELLED;
469 }
470 part = psys->part;
472 if (dw->flag & PART_DUPLIW_CURRENT) {
473 dw->flag &= ~PART_DUPLIW_CURRENT;
474 dw = static_cast<ParticleDupliWeight *>(MEM_dupallocN(dw));
476 BLI_addhead(&part->instance_weights, dw);
477
480 break;
481 }
482 }
483
484 return OPERATOR_FINISHED;
485}
486
488{
489 /* identifiers */
490 ot->name = "Copy Particle Instance Object";
491 ot->idname = "PARTICLE_OT_dupliob_copy";
492 ot->description = "Duplicate the current instance object";
493
494 /* API callbacks. */
496
497 /* flags */
499}
500
502{
503 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
504 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
505 ParticleSettings *part;
506
507 if (!psys) {
508 return OPERATOR_CANCELLED;
509 }
510
511 part = psys->part;
513 if (dw->flag & PART_DUPLIW_CURRENT) {
514 BLI_remlink(&part->instance_weights, dw);
515 MEM_freeN(dw);
516 break;
517 }
518 }
519
521 if (dw) {
523 }
524
527
528 return OPERATOR_FINISHED;
529}
530
532{
533 /* identifiers */
534 ot->name = "Remove Particle Instance Object";
535 ot->idname = "PARTICLE_OT_dupliob_remove";
536 ot->description = "Remove the selected instance object";
537
538 /* API callbacks. */
540
541 /* flags */
543}
544
545/************************ move down particle dupliweight operator *********************/
546
548{
549 PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
550 ParticleSystem *psys = static_cast<ParticleSystem *>(ptr.data);
551 ParticleSettings *part;
552
553 if (!psys) {
554 return OPERATOR_CANCELLED;
555 }
556
557 part = psys->part;
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
586static void disconnect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
587{
588 Object *object_eval = DEG_get_evaluated(depsgraph, ob);
589 ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
590 ParticleSystemModifierData *psmd_eval = psys_get_modifier(object_eval, psys_eval);
591 ParticleEditSettings *pset = PE_settings(scene);
592 ParticleData *pa;
593 PTCacheEdit *edit;
594 PTCacheEditPoint *point;
595 PTCacheEditKey *ekey = nullptr;
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 : nullptr;
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
634 pset->brushtype = PE_BRUSH_COMB;
635 }
636
637 PE_update_object(depsgraph, scene, ob, 0);
638}
639
641{
643 Scene *scene = CTX_data_scene(C);
645 ParticleSystem *psys = nullptr;
646 const bool all = RNA_boolean_get(op->ptr, "all");
647
648 if (!ob) {
649 return OPERATOR_CANCELLED;
650 }
651
652 if (all) {
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
674 ot->exec = disconnect_hair_exec;
675
676 /* flags */
677 /* No REGISTER, redo does not work due to missing update, see #47750. */
678 ot->flag = OPTYPE_UNDO;
679
681 ot->srna, "all", false, "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 */
687static bool remap_hair_emitter(Depsgraph *depsgraph,
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(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 blender::bke::BVHTreeFromMesh bvhtree = {nullptr};
706 const MFace *mface = nullptr, *mf;
707 const blender::int2 *edges = nullptr, *edge;
708 Mesh *mesh, *target_mesh;
709 int numverts;
710 int k;
711 float from_ob_imat[4][4], to_ob_imat[4][4];
712 float from_imat[4][4], to_imat[4][4];
713
714 if (!target_psmd->mesh_final) {
715 return false;
716 }
717 if (!psys->part || psys->part->type != PART_HAIR) {
718 return false;
719 }
720 if (!target_psys->part || target_psys->part->type != PART_HAIR) {
721 return false;
722 }
723
724 edit_point = target_edit ? target_edit->points : nullptr;
725
726 invert_m4_m4(from_ob_imat, ob->object_to_world().ptr());
727 invert_m4_m4(to_ob_imat, target_ob->object_to_world().ptr());
728 invert_m4_m4(from_imat, from_mat);
729 invert_m4_m4(to_imat, to_mat);
730
731 const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
732 !target_psmd->mesh_final->runtime->deformed_only);
733
734 if (use_dm_final_indices || !target_psmd->mesh_original) {
735 mesh = target_psmd->mesh_final;
736 }
737 else {
738 mesh = target_psmd->mesh_original;
739 }
740 target_mesh = target_psmd->mesh_final;
741 if (mesh == nullptr) {
742 return false;
743 }
744 /* don't modify the original vertices */
745 /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
746 mesh = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
747
748 /* BMESH_ONLY, deform dm may not have tessface */
750
751 numverts = mesh->verts_num;
752 blender::MutableSpan<blender::float3> positions = mesh->vert_positions_for_write();
753
754 /* convert to global coordinates */
755 for (int i = 0; i < numverts; i++) {
756 mul_m4_v3(to_mat, positions[i]);
757 }
758
759 if (mesh->totface_legacy != 0) {
760 mface = static_cast<const MFace *>(CustomData_get_layer(&mesh->fdata_legacy, CD_MFACE));
761 bvhtree = mesh->bvh_legacy_faces();
762 }
763 else if (mesh->edges_num != 0) {
764 edges = static_cast<const blender::int2 *>(
766 bvhtree = mesh->bvh_edges();
767 }
768 else {
769 BKE_id_free(nullptr, mesh);
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 {
777 float from_co[3];
778 BVHTreeNearest nearest;
779
780 if (from_global) {
781 mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
782 }
783 else {
784 mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
785 }
786 mul_m4_v3(from_mat, from_co);
787
788 nearest.index = -1;
789 nearest.dist_sq = FLT_MAX;
790
791 BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
792
793 if (nearest.index == -1) {
794 if (G.debug & G_DEBUG) {
795 printf("No nearest point found for hair root!");
796 }
797 continue;
798 }
799
800 if (mface) {
801 float v[4][3];
802
803 mf = &mface[nearest.index];
804
805 copy_v3_v3(v[0], positions[mf->v1]);
806 copy_v3_v3(v[1], positions[mf->v2]);
807 copy_v3_v3(v[2], positions[mf->v3]);
808 if (mf->v4) {
809 copy_v3_v3(v[3], positions[mf->v4]);
810 interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
811 }
812 else {
813 interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
814 }
815 tpa->foffset = 0.0f;
816
817 tpa->num = nearest.index;
818 if (use_dm_final_indices) {
820 }
821 else {
823 target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, nullptr);
824 }
825 }
826 else {
827 edge = &edges[nearest.index];
828
829 tpa->fuv[1] = line_point_factor_v3(nearest.co, positions[edge->x], positions[edge->y]);
830 tpa->fuv[0] = 1.0f - tpa->fuv[1];
831 tpa->fuv[2] = tpa->fuv[3] = 0.0f;
832 tpa->foffset = 0.0f;
833
834 tpa->num = nearest.index;
835 tpa->num_dmcache = -1;
836 }
837
838 /* translate hair keys */
839 {
840 HairKey *key, *tkey;
841 float hairmat[4][4], imat[4][4];
842 float offset[3];
843
844 if (to_global) {
845 copy_m4_m4(imat, target_ob->object_to_world().ptr());
846 }
847 else {
848 /* NOTE: using target_dm here, which is in target_ob object space and has full modifiers.
849 */
850 psys_mat_hair_to_object(target_ob, target_mesh, target_psys->part->from, tpa, hairmat);
851 invert_m4_m4(imat, hairmat);
852 }
853 mul_m4_m4m4(imat, imat, to_imat);
854
855 /* offset in world space */
856 sub_v3_v3v3(offset, nearest.co, from_co);
857
858 if (edit_point) {
859 for (k = 0, key = pa->hair, tkey = tpa->hair, ekey = edit_point->keys; k < tpa->totkey;
860 k++, key++, tkey++, ekey++)
861 {
862 float co_orig[3];
863
864 if (from_global) {
865 mul_v3_m4v3(co_orig, from_ob_imat, key->co);
866 }
867 else {
868 mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
869 }
870 mul_m4_v3(from_mat, co_orig);
871
872 add_v3_v3v3(tkey->co, co_orig, offset);
873
874 mul_m4_v3(imat, tkey->co);
875
876 ekey->flag |= PEK_USE_WCO;
877 }
878
879 edit_point++;
880 }
881 else {
882 for (k = 0, key = pa->hair, tkey = tpa->hair; k < tpa->totkey; k++, key++, tkey++) {
883 float co_orig[3];
884
885 if (from_global) {
886 mul_v3_m4v3(co_orig, from_ob_imat, key->co);
887 }
888 else {
889 mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
890 }
891 mul_m4_v3(from_mat, co_orig);
892
893 add_v3_v3v3(tkey->co, co_orig, offset);
894
895 mul_m4_v3(imat, tkey->co);
896 }
897 }
898 }
899 }
900
901 BKE_id_free(nullptr, mesh);
902
903 psys_free_path_cache(target_psys, target_edit);
904
905 PE_update_object(depsgraph, scene, target_ob, 0);
906
907 return true;
908}
909
910static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
911{
912 bool ok;
913
914 if (!psys) {
915 return false;
916 }
917
919 scene,
920 ob,
921 psys,
922 ob,
923 psys,
924 psys->edit,
925 ob->object_to_world().ptr(),
926 ob->object_to_world().ptr(),
927 psys->flag & PSYS_GLOBAL_HAIR,
928 false);
929 if (ok) {
930 psys->flag &= ~PSYS_GLOBAL_HAIR;
931 }
932
933 return ok;
934}
935
937{
939 Scene *scene = CTX_data_scene(C);
941 ParticleSystem *psys = nullptr;
942 const bool all = RNA_boolean_get(op->ptr, "all");
943 bool any_connected = false;
944
945 if (!ob) {
946 return OPERATOR_CANCELLED;
947 }
948
949 if (all) {
951 any_connected |= connect_hair(depsgraph, scene, ob, psys);
952 }
953 }
954 else {
955 psys = psys_get_current(ob);
956 any_connected |= connect_hair(depsgraph, scene, ob, psys);
957 }
958
959 if (!any_connected) {
962 "No hair connected (can't connect hair if particle system modifier is disabled)");
963 return OPERATOR_CANCELLED;
964 }
965
968
969 return OPERATOR_FINISHED;
970}
971
973{
974 ot->name = "Connect Hair";
975 ot->description = "Connect hair to the emitter mesh";
976 ot->idname = "PARTICLE_OT_connect_hair";
977
978 ot->exec = connect_hair_exec;
979
980 /* flags */
981 /* No REGISTER, redo does not work due to missing update, see #47750. */
982 ot->flag = OPTYPE_UNDO;
983
985 ot->srna, "all", false, "All Hair", "Connect all hair systems to the emitter mesh");
986}
987
988/************************ particle system copy operator *********************/
989
994
995static void copy_particle_edit(Depsgraph *depsgraph,
996 Scene *scene,
997 Object *ob,
998 ParticleSystem *psys,
999 ParticleSystem *psys_from)
1000{
1001 PTCacheEdit *edit_from = psys_from->edit, *edit;
1002 ParticleData *pa;
1003 KEY_K;
1004 POINT_P;
1005
1006 if (!edit_from) {
1007 return;
1008 }
1009
1010 edit = static_cast<PTCacheEdit *>(MEM_dupallocN(edit_from));
1011 edit->psys = psys;
1012 psys->edit = edit;
1013
1014 edit->pathcache = nullptr;
1015 edit->mirror_cache = nullptr;
1016 BLI_listbase_clear(&edit->pathcachebufs);
1017
1018 edit->emitter_field = nullptr;
1019 edit->emitter_cosnos = nullptr;
1020
1021 edit->points = static_cast<PTCacheEditPoint *>(MEM_dupallocN(edit_from->points));
1022 pa = psys->particles;
1023 LOOP_POINTS {
1024 HairKey *hkey = pa->hair;
1025
1026 point->keys = static_cast<PTCacheEditKey *>(MEM_dupallocN(point->keys));
1027 LOOP_KEYS {
1028 key->co = hkey->co;
1029 key->time = &hkey->time;
1030 key->flag = hkey->editflag;
1031 if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1032 key->flag |= PEK_USE_WCO;
1033 hkey->editflag |= PEK_USE_WCO;
1034 }
1035
1036 hkey++;
1037 }
1038
1039 pa++;
1040 }
1041 update_world_cos(ob, edit);
1042
1043 recalc_lengths(edit);
1045 PE_update_object(depsgraph, scene, ob, true);
1046}
1047
1049{
1050 ModifierData *md, *md_next;
1051
1052 if (ob_to->type != OB_MESH) {
1053 return;
1054 }
1055 if (!ob_to->data || !ID_IS_EDITABLE(ob_to->data) || ID_IS_OVERRIDE_LIBRARY(ob_to->data)) {
1056 return;
1057 }
1058
1059 for (md = static_cast<ModifierData *>(ob_to->modifiers.first); md; md = md_next) {
1060 md_next = md->next;
1061
1062 /* remove all particle system modifiers as well,
1063 * these need to sync to the particle system list
1064 */
1065 if (ELEM(md->type,
1069 {
1070 BLI_remlink(&ob_to->modifiers, md);
1072 }
1073 }
1074
1076}
1077
1078/* single_psys_from is optional, if nullptr all psys of ob_from are copied */
1080 Scene *scene,
1081 Object *ob_from,
1082 ParticleSystem *single_psys_from,
1083 Object *ob_to,
1084 int space,
1085 bool duplicate_settings)
1086{
1087 Main *bmain = CTX_data_main(C);
1089 ModifierData *md;
1090 ParticleSystem *psys_start = nullptr, *psys, *psys_from;
1091 ParticleSystem **tmp_psys;
1092 CustomData_MeshMasks cdmask = {0};
1093 int i, totpsys;
1094
1095 if (ob_to->type != OB_MESH) {
1096 return false;
1097 }
1098 if (!ob_to->data || !BKE_id_is_editable(bmain, static_cast<const ID *>(ob_to->data))) {
1099 return false;
1100 }
1101
1102/* For remapping we need a valid DM.
1103 * Because the modifiers are appended at the end it's safe to use
1104 * the final DM of the object without particles.
1105 * However, when evaluating the DM all the particle modifiers must be valid,
1106 * i.e. have the psys assigned already.
1107 *
1108 * To break this hen/egg problem we create all psys separately first
1109 * (to collect required customdata masks),
1110 * then create the DM, then add them to the object and make the psys modifiers.
1111 */
1112#define PSYS_FROM_FIRST \
1113 static_cast<ParticleSystem *>( \
1114 (single_psys_from ? single_psys_from : ob_from->particlesystem.first))
1115#define PSYS_FROM_NEXT(cur) (single_psys_from ? nullptr : (cur)->next)
1116 totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
1117
1118 tmp_psys = MEM_malloc_arrayN<ParticleSystem *>(totpsys, "temporary particle system array");
1119
1120 for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1121 psys = BKE_object_copy_particlesystem(psys_from, 0);
1122 tmp_psys[i] = psys;
1123
1124 if (psys_start == nullptr) {
1125 psys_start = psys;
1126 }
1127
1128 psys_emitter_customdata_mask(psys, &cdmask);
1129 }
1130 /* to iterate source and target psys in sync,
1131 * we need to know where the newly added psys start
1132 */
1133 psys_start = totpsys > 0 ? tmp_psys[0] : nullptr;
1134
1135 /* now append psys to the object and make modifiers */
1136 for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys; ++i, psys_from = PSYS_FROM_NEXT(psys_from))
1137 {
1139
1140 psys = tmp_psys[i];
1141
1142 /* append to the object */
1143 BLI_addtail(&ob_to->particlesystem, psys);
1144 psys_unique_name(ob_to, psys, psys->name);
1145
1146 /* add a particle system modifier for each system */
1148 psmd = (ParticleSystemModifierData *)md;
1149 /* push on top of the stack, no use trying to reproduce old stack order */
1150 BLI_addtail(&ob_to->modifiers, md);
1152
1153 SNPRINTF(md->name, "ParticleSystem %i", i);
1155
1156 psmd->psys = psys;
1157
1158 if (psys_from->edit) {
1159 copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from);
1160 }
1161
1162 if (duplicate_settings) {
1163 id_us_min(&psys->part->id);
1164 psys->part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
1165 }
1166 }
1167 MEM_freeN(tmp_psys);
1168
1169 /* NOTE: do this after creating DM copies for all the particle system modifiers,
1170 * the remapping otherwise makes final_dm invalid!
1171 */
1172 for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
1173 psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++)
1174 {
1175 const float(*from_mat)[4], (*to_mat)[4];
1176
1177 switch (space) {
1179 from_mat = I;
1180 to_mat = I;
1181 break;
1183 from_mat = ob_from->object_to_world().ptr();
1184 to_mat = ob_to->object_to_world().ptr();
1185 break;
1186 default:
1187 /* should not happen */
1188 from_mat = to_mat = nullptr;
1189 BLI_assert(false);
1190 break;
1191 }
1192 if (ob_from != ob_to) {
1194 scene,
1195 ob_from,
1196 psys_from,
1197 ob_to,
1198 psys,
1199 psys->edit,
1200 from_mat,
1201 to_mat,
1202 psys_from->flag & PSYS_GLOBAL_HAIR,
1203 psys->flag & PSYS_GLOBAL_HAIR);
1204 }
1205
1206 /* tag for recalc */
1207 // psys->recalc |= ID_RECALC_PSYS_RESET;
1208 }
1209
1210#undef PSYS_FROM_FIRST
1211#undef PSYS_FROM_NEXT
1212
1216 return true;
1217}
1218
1220{
1221 Object *ob;
1223 return false;
1224 }
1225
1228 return false;
1229 }
1230
1231 return true;
1232}
1233
1235{
1236 const int space = RNA_enum_get(op->ptr, "space");
1237 const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
1238 const bool use_active = RNA_boolean_get(op->ptr, "use_active");
1239 Scene *scene = CTX_data_scene(C);
1241
1242 ParticleSystem *psys_from = nullptr;
1243 if (use_active) {
1244 psys_from = static_cast<ParticleSystem *>(
1245 CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
1246 if (psys_from == nullptr) {
1247 /* Particle System context pointer is only valid in the Properties Editor. */
1248 psys_from = psys_get_current(ob_from);
1249 }
1250 }
1251
1252 int changed_tot = 0;
1253 int fail = 0;
1254
1255 CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects) {
1256 if (ob_from != ob_to) {
1257 bool changed = false;
1258 if (remove_target_particles) {
1260 changed = true;
1261 }
1262 if (copy_particle_systems_to_object(C, scene, ob_from, psys_from, ob_to, space, false)) {
1263 changed = true;
1264 }
1265 else {
1266 fail++;
1267 }
1268
1269 if (changed) {
1270 changed_tot++;
1271 }
1272 }
1273 }
1275
1276 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, nullptr, 0, nullptr, nullptr},
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 */
1307 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1308
1309 RNA_def_enum(ot->srna,
1310 "space",
1313 "Space",
1314 "Space transform for copying from one object to another");
1315 RNA_def_boolean(ot->srna,
1316 "remove_target_particles",
1317 true,
1318 "Remove Target Particles",
1319 "Remove particle systems on the target objects");
1320 RNA_def_boolean(ot->srna,
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 if (ob->mode != OB_MODE_OBJECT) {
1337 CTX_wm_operator_poll_msg_set(C, "Object must be in object mode");
1338 return false;
1339 }
1340 return true;
1341}
1342
1344{
1345 const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
1346 Scene *scene = CTX_data_scene(C);
1348 /* Context pointer is only valid in the Properties Editor. */
1349 ParticleSystem *psys = static_cast<ParticleSystem *>(
1350 CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
1351 if (psys == nullptr) {
1352 psys = psys_get_current(ob);
1353 }
1354
1356 C, scene, ob, psys, ob, PAR_COPY_SPACE_OBJECT, duplicate_settings);
1357 return OPERATOR_FINISHED;
1358}
1359
1361{
1362 ot->name = "Duplicate Particle System";
1363 ot->description = "Duplicate particle system within the active object";
1364 ot->idname = "PARTICLE_OT_duplicate_particle_system";
1365
1368
1369 /* flags */
1370 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1371
1372 RNA_def_boolean(ot->srna,
1373 "use_duplicate_settings",
1374 false,
1375 "Duplicate Settings",
1376 "Duplicate settings as well, so the new particle system uses its own settings");
1377}
#define CTX_DATA_BEGIN(C, Type, instance, member)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
ViewLayer * CTX_data_view_layer(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
@ G_DEBUG
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2503
void BKE_id_free(Main *bmain, void *idv)
@ LIB_ID_COPY_ACTIONS
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_DEFAULT
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:772
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_mesh_tessface_ensure(Mesh *mesh)
void BKE_modifiers_persistent_uid_init(const Object &object, ModifierData &md)
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
void BKE_modifier_free(ModifierData *md)
ModifierData * BKE_modifier_new(int type)
General operations, lookup, etc. for blender objects.
void BKE_object_free_particlesystems(Object *ob)
ParticleSystem * BKE_object_copy_particlesystem(ParticleSystem *psys, int flag)
struct ModifierData * object_add_particle_system(struct Main *bmain, const struct Scene *scene, struct Object *ob, const char *name)
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition particle.cc:2153
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname) ATTR_NONNULL(1
void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition particle.cc:3898
void psys_check_group_weights(struct ParticleSettings *part)
Definition particle.cc:765
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition particle.cc:3842
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition particle.cc:2205
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)
Definition particle.cc:3982
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition particle.cc:537
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition particle.cc:667
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition particle.cc:906
#define DMCACHE_ISCHILD
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.cc:1833
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition particle.cc:4086
#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.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
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])
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
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])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_PSYS_REDO
Definition DNA_ID.h:989
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ CD_PROP_INT32_2D
@ eModifierType_ParticleSystem
@ eModifierType_Fluid
@ eModifierType_DynamicPaint
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_OBJECT
@ OB_MESH
@ PSYS_GLOBAL_HAIR
@ PART_HAIR
@ PTARGET_CURRENT
@ PART_DUPLIW_CURRENT
@ PE_BRUSH_COMB
@ PE_BRUSH_PUFF
@ PE_BRUSH_ADD
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
ParticleEditSettings * PE_settings(Scene *scene)
bool ED_operator_object_active_local_editable(bContext *C)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_MODE
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:375
#define NA_EDITED
Definition WM_types.hh:581
#define ND_PARTICLE
Definition WM_types.hh:462
#define NS_MODE_OBJECT
Definition WM_types.hh:557
#define ND_POINTCACHE
Definition WM_types.hh:463
#define NC_OBJECT
Definition WM_types.hh:376
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
bool all(VecOp< bool, D >) RET
#define printf(...)
#define ID_IS_EDITABLE(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
Object * context_object(const bContext *C)
Object * context_active_object(const bContext *C)
VecBase< int32_t, 2 > int2
#define I
void recalc_emitter_field(Depsgraph *, Object *, 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 bool duplicate_particle_systems_poll(bContext *C)
static wmOperatorStatus new_particle_target_exec(bContext *C, wmOperator *)
void PARTICLE_OT_target_move_up(wmOperatorType *ot)
static wmOperatorStatus dupliob_move_down_exec(bContext *C, wmOperator *)
void PARTICLE_OT_dupliob_copy(wmOperatorType *ot)
void PARTICLE_OT_dupliob_refresh(wmOperatorType *ot)
static wmOperatorStatus dupliob_move_up_exec(bContext *C, wmOperator *)
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 wmOperatorStatus target_move_down_exec(bContext *C, wmOperator *)
void PARTICLE_OT_new(wmOperatorType *ot)
static wmOperatorStatus duplicate_particle_systems_exec(bContext *C, wmOperator *op)
eCopyParticlesSpace
@ PAR_COPY_SPACE_OBJECT
@ PAR_COPY_SPACE_WORLD
void PARTICLE_OT_new_target(wmOperatorType *ot)
static wmOperatorStatus copy_particle_dupliob_exec(bContext *C, wmOperator *)
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
static bool psys_poll(bContext *C)
void PARTICLE_OT_target_remove(wmOperatorType *ot)
static void copy_particle_edit(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
static wmOperatorStatus dupliob_refresh_exec(bContext *C, wmOperator *)
static bool copy_particle_systems_poll(bContext *C)
static wmOperatorStatus copy_particle_systems_exec(bContext *C, wmOperator *op)
void PARTICLE_OT_connect_hair(wmOperatorType *ot)
static wmOperatorStatus remove_particle_target_exec(bContext *C, wmOperator *)
void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
void PARTICLE_OT_dupliob_remove(wmOperatorType *ot)
static wmOperatorStatus target_move_up_exec(bContext *C, wmOperator *)
#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 wmOperatorStatus particle_system_add_exec(bContext *C, wmOperator *)
static wmOperatorStatus remove_particle_dupliob_exec(bContext *C, wmOperator *)
static void remove_particle_systems_from_object(Object *ob_to)
static wmOperatorStatus connect_hair_exec(bContext *C, wmOperator *op)
static wmOperatorStatus disconnect_hair_exec(bContext *C, wmOperator *op)
static wmOperatorStatus new_particle_settings_exec(bContext *C, wmOperator *)
void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot)
#define PSYS_FROM_NEXT(cur)
static wmOperatorStatus particle_system_remove_exec(bContext *C, wmOperator *)
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)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
static const EnumPropertyItem space_items[]
#define FLT_MAX
Definition stdcycles.h:14
float world_co[3]
Definition DNA_ID.h:404
void * last
void * first
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
CustomData fdata_legacy
int totface_legacy
int verts_num
struct ModifierData * next
ustring name
Definition graph/node.h:177
ListBase particlesystem
ListBase modifiers
struct PTCacheEditKey * keys
struct ParticleCacheKey ** pathcache
PTCacheEditPoint * points
struct ParticleSystem * psys
struct ListBase instance_weights
struct ParticleSystem * psys
struct PTCacheEdit * edit
ParticleData * particles
struct ListBase targets
ParticleSettings * part
struct ParticleTarget * prev
struct ParticleTarget * next
void * data
Definition RNA_types.hh:53
BVHTree_NearestPointCallback nearest_callback
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225