Blender V5.0
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_utf8.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 = mesh->edges().data();
765 bvhtree = mesh->bvh_edges();
766 }
767 else {
768 BKE_id_free(nullptr, mesh);
769 return false;
770 }
771
772 int i;
773 for (i = 0, tpa = target_psys->particles, pa = psys->particles; i < target_psys->totpart;
774 i++, tpa++, pa++)
775 {
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], positions[mf->v1]);
805 copy_v3_v3(v[1], positions[mf->v2]);
806 copy_v3_v3(v[2], positions[mf->v3]);
807 if (mf->v4) {
808 copy_v3_v3(v[3], positions[mf->v4]);
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, nullptr);
823 }
824 }
825 else {
826 edge = &edges[nearest.index];
827
828 tpa->fuv[1] = line_point_factor_v3(nearest.co, positions[edge->x], positions[edge->y]);
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->object_to_world().ptr());
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 {
861 float co_orig[3];
862
863 if (from_global) {
864 mul_v3_m4v3(co_orig, from_ob_imat, key->co);
865 }
866 else {
867 mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
868 }
869 mul_m4_v3(from_mat, co_orig);
870
871 add_v3_v3v3(tkey->co, co_orig, offset);
872
873 mul_m4_v3(imat, tkey->co);
874
875 ekey->flag |= PEK_USE_WCO;
876 }
877
878 edit_point++;
879 }
880 else {
881 for (k = 0, key = pa->hair, tkey = tpa->hair; k < tpa->totkey; k++, key++, tkey++) {
882 float co_orig[3];
883
884 if (from_global) {
885 mul_v3_m4v3(co_orig, from_ob_imat, key->co);
886 }
887 else {
888 mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
889 }
890 mul_m4_v3(from_mat, co_orig);
891
892 add_v3_v3v3(tkey->co, co_orig, offset);
893
894 mul_m4_v3(imat, tkey->co);
895 }
896 }
897 }
898 }
899
900 BKE_id_free(nullptr, mesh);
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
909static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
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->object_to_world().ptr(),
925 ob->object_to_world().ptr(),
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{
938 Scene *scene = CTX_data_scene(C);
940 ParticleSystem *psys = nullptr;
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) {
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) {
961 "No hair connected (cannot 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
977 ot->exec = connect_hair_exec;
978
979 /* flags */
980 /* No REGISTER, redo does not work due to missing update, see #47750. */
981 ot->flag = OPTYPE_UNDO;
982
984 ot->srna, "all", false, "All Hair", "Connect all hair systems to the emitter mesh");
985}
986
987/************************ particle system copy operator *********************/
988
993
994static void copy_particle_edit(Depsgraph *depsgraph,
995 Scene *scene,
996 Object *ob,
997 ParticleSystem *psys,
998 ParticleSystem *psys_from)
999{
1000 PTCacheEdit *edit_from = psys_from->edit, *edit;
1001 ParticleData *pa;
1002 KEY_K;
1003 POINT_P;
1004
1005 if (!edit_from) {
1006 return;
1007 }
1008
1009 edit = static_cast<PTCacheEdit *>(MEM_dupallocN(edit_from));
1010 edit->psys = psys;
1011 psys->edit = edit;
1012
1013 edit->pathcache = nullptr;
1014 edit->mirror_cache = nullptr;
1015 BLI_listbase_clear(&edit->pathcachebufs);
1016
1017 edit->emitter_field = nullptr;
1018 edit->emitter_cosnos = nullptr;
1019
1020 edit->points = static_cast<PTCacheEditPoint *>(MEM_dupallocN(edit_from->points));
1021 pa = psys->particles;
1022 LOOP_POINTS {
1023 HairKey *hkey = pa->hair;
1024
1025 point->keys = static_cast<PTCacheEditKey *>(MEM_dupallocN(point->keys));
1026 LOOP_KEYS {
1027 key->co = hkey->co;
1028 key->time = &hkey->time;
1029 key->flag = hkey->editflag;
1030 if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1031 key->flag |= PEK_USE_WCO;
1032 hkey->editflag |= PEK_USE_WCO;
1033 }
1034
1035 hkey++;
1036 }
1037
1038 pa++;
1039 }
1040 update_world_cos(ob, edit);
1041
1042 recalc_lengths(edit);
1044 PE_update_object(depsgraph, scene, ob, true);
1045}
1046
1048{
1049 ModifierData *md, *md_next;
1050
1051 if (ob_to->type != OB_MESH) {
1052 return;
1053 }
1054 if (!ob_to->data || !ID_IS_EDITABLE(ob_to->data) || ID_IS_OVERRIDE_LIBRARY(ob_to->data)) {
1055 return;
1056 }
1057
1058 for (md = static_cast<ModifierData *>(ob_to->modifiers.first); md; md = md_next) {
1059 md_next = md->next;
1060
1061 /* remove all particle system modifiers as well,
1062 * these need to sync to the particle system list
1063 */
1064 if (ELEM(md->type,
1068 {
1069 BLI_remlink(&ob_to->modifiers, md);
1071 }
1072 }
1073
1075}
1076
1077/* single_psys_from is optional, if nullptr all psys of ob_from are copied */
1079 Scene *scene,
1080 Object *ob_from,
1081 ParticleSystem *single_psys_from,
1082 Object *ob_to,
1083 int space,
1084 bool duplicate_settings)
1085{
1086 Main *bmain = CTX_data_main(C);
1088 ModifierData *md;
1089 ParticleSystem *psys_start = nullptr, *psys, *psys_from;
1090 ParticleSystem **tmp_psys;
1091 CustomData_MeshMasks cdmask = {0};
1092 int i, totpsys;
1093
1094 if (ob_to->type != OB_MESH) {
1095 return false;
1096 }
1097 if (!ob_to->data || !BKE_id_is_editable(bmain, static_cast<const ID *>(ob_to->data))) {
1098 return false;
1099 }
1100
1101/* For remapping we need a valid DM.
1102 * Because the modifiers are appended at the end it's safe to use
1103 * the final DM of the object without particles.
1104 * However, when evaluating the DM all the particle modifiers must be valid,
1105 * i.e. have the psys assigned already.
1106 *
1107 * To break this hen/egg problem we create all psys separately first
1108 * (to collect required customdata masks),
1109 * then create the DM, then add them to the object and make the psys modifiers.
1110 */
1111#define PSYS_FROM_FIRST \
1112 static_cast<ParticleSystem *>( \
1113 (single_psys_from ? single_psys_from : ob_from->particlesystem.first))
1114#define PSYS_FROM_NEXT(cur) (single_psys_from ? nullptr : (cur)->next)
1115 totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
1116
1117 tmp_psys = MEM_malloc_arrayN<ParticleSystem *>(totpsys, "temporary particle system array");
1118
1119 for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), i++) {
1120 psys = BKE_object_copy_particlesystem(psys_from, 0);
1121 tmp_psys[i] = psys;
1122
1123 if (psys_start == nullptr) {
1124 psys_start = psys;
1125 }
1126
1127 psys_emitter_customdata_mask(psys, &cdmask);
1128 }
1129 /* to iterate source and target psys in sync,
1130 * we need to know where the newly added psys start
1131 */
1132 psys_start = totpsys > 0 ? tmp_psys[0] : nullptr;
1133
1134 /* now append psys to the object and make modifiers */
1135 for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys; ++i, psys_from = PSYS_FROM_NEXT(psys_from))
1136 {
1138
1139 psys = tmp_psys[i];
1140
1141 /* append to the object */
1142 BLI_addtail(&ob_to->particlesystem, psys);
1143 psys_unique_name(ob_to, psys, psys->name);
1144
1145 /* add a particle system modifier for each system */
1147 psmd = (ParticleSystemModifierData *)md;
1148 /* push on top of the stack, no use trying to reproduce old stack order */
1149 BLI_addtail(&ob_to->modifiers, md);
1151
1152 SNPRINTF_UTF8(md->name, "ParticleSystem %i", i);
1154
1155 psmd->psys = psys;
1156
1157 if (psys_from->edit) {
1158 copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from);
1159 }
1160
1161 if (duplicate_settings) {
1162 id_us_min(&psys->part->id);
1163 psys->part = (ParticleSettings *)BKE_id_copy(bmain, &psys->part->id);
1164 }
1165 }
1166 MEM_freeN(tmp_psys);
1167
1168 /* NOTE: do this after creating DM copies for all the particle system modifiers,
1169 * the remapping otherwise makes final_dm invalid!
1170 */
1171 for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys;
1172 psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), i++)
1173 {
1174 const float (*from_mat)[4], (*to_mat)[4];
1175
1176 switch (space) {
1178 from_mat = I;
1179 to_mat = I;
1180 break;
1182 from_mat = ob_from->object_to_world().ptr();
1183 to_mat = ob_to->object_to_world().ptr();
1184 break;
1185 default:
1186 /* should not happen */
1187 from_mat = to_mat = nullptr;
1188 BLI_assert(false);
1189 break;
1190 }
1191 if (ob_from != ob_to) {
1193 scene,
1194 ob_from,
1195 psys_from,
1196 ob_to,
1197 psys,
1198 psys->edit,
1199 from_mat,
1200 to_mat,
1201 psys_from->flag & PSYS_GLOBAL_HAIR,
1202 psys->flag & PSYS_GLOBAL_HAIR);
1203 }
1204
1205 /* tag for recalc */
1206 // psys->recalc |= ID_RECALC_PSYS_RESET;
1207 }
1208
1209#undef PSYS_FROM_FIRST
1210#undef PSYS_FROM_NEXT
1211
1215 return true;
1216}
1217
1219{
1220 Object *ob;
1222 return false;
1223 }
1224
1227 return false;
1228 }
1229
1230 return true;
1231}
1232
1234{
1235 const int space = RNA_enum_get(op->ptr, "space");
1236 const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
1237 const bool use_active = RNA_boolean_get(op->ptr, "use_active");
1238 Scene *scene = CTX_data_scene(C);
1240
1241 ParticleSystem *psys_from = nullptr;
1242 if (use_active) {
1243 psys_from = static_cast<ParticleSystem *>(
1244 CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
1245 if (psys_from == nullptr) {
1246 /* Particle System context pointer is only valid in the Properties Editor. */
1247 psys_from = psys_get_current(ob_from);
1248 }
1249 }
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 }
1274
1275 if (changed_tot > 0) {
1277 }
1278
1279 if ((changed_tot == 0 && fail == 0) || fail) {
1280 BKE_reportf(op->reports,
1281 RPT_ERROR,
1282 "Copy particle systems to selected: %d done, %d failed",
1283 changed_tot,
1284 fail);
1285 }
1286
1287 return OPERATOR_FINISHED;
1288}
1289
1291{
1292 static const EnumPropertyItem space_items[] = {
1293 {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
1294 {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
1295 {0, nullptr, 0, nullptr, nullptr},
1296 };
1297
1298 ot->name = "Copy Particle Systems";
1299 ot->description = "Copy particle systems from the active object to selected objects";
1300 ot->idname = "PARTICLE_OT_copy_particle_systems";
1301
1304
1305 /* flags */
1306 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1307
1308 RNA_def_enum(ot->srna,
1309 "space",
1312 "Space",
1313 "Space transform for copying from one object to another");
1314 RNA_def_boolean(ot->srna,
1315 "remove_target_particles",
1316 true,
1317 "Remove Target Particles",
1318 "Remove particle systems on the target objects");
1319 RNA_def_boolean(ot->srna,
1320 "use_active",
1321 false,
1322 "Use Active",
1323 "Use the active particle system from the context");
1324}
1325
1327{
1329 return false;
1330 }
1333 return false;
1334 }
1335 if (ob->mode != OB_MODE_OBJECT) {
1336 CTX_wm_operator_poll_msg_set(C, "Object must be in object mode");
1337 return false;
1338 }
1339 return true;
1340}
1341
1343{
1344 const bool duplicate_settings = RNA_boolean_get(op->ptr, "use_duplicate_settings");
1345 Scene *scene = CTX_data_scene(C);
1347 /* Context pointer is only valid in the Properties Editor. */
1348 ParticleSystem *psys = static_cast<ParticleSystem *>(
1349 CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
1350 if (psys == nullptr) {
1351 psys = psys_get_current(ob);
1352 }
1353
1355 C, scene, ob, psys, ob, PAR_COPY_SPACE_OBJECT, duplicate_settings);
1356 return OPERATOR_FINISHED;
1357}
1358
1360{
1361 ot->name = "Duplicate Particle System";
1362 ot->description = "Duplicate particle system within the active object";
1363 ot->idname = "PARTICLE_OT_duplicate_particle_system";
1364
1367
1368 /* flags */
1369 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1370
1371 RNA_def_boolean(ot->srna,
1372 "use_duplicate_settings",
1373 false,
1374 "Duplicate Settings",
1375 "Duplicate settings as well, so the new particle system uses its own settings");
1376}
1377
1379{
1381 return false;
1382 }
1385 return false;
1386 }
1387 if (ob->mode != OB_MODE_OBJECT) {
1388 CTX_wm_operator_poll_msg_set(C, "Object must be in object mode");
1389 return false;
1390 }
1391 return true;
1392}
1394{
1395 Main *bmain = CTX_data_main(C);
1397 Scene *scene = CTX_data_scene(C);
1398 ViewLayer *view_layer = CTX_data_view_layer(C);
1399
1400 if (!scene || !ob) {
1401 return OPERATOR_CANCELLED;
1402 }
1403
1404 const eObjectMode mode_orig = eObjectMode(ob->mode);
1406 object_remove_particle_system(bmain, scene, ob, psys);
1407 }
1408
1409 /* possible this isn't the active object
1410 * object_remove_particle_system() clears the mode on the last psys
1411 */
1412 if (mode_orig & OB_MODE_PARTICLE_EDIT) {
1413 if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
1414 BKE_view_layer_synced_ensure(scene, view_layer);
1415 if (BKE_view_layer_active_object_get(view_layer) == ob) {
1417 }
1418 }
1419 }
1420
1423
1424 return OPERATOR_FINISHED;
1425}
1426
1428{
1429 ot->name = "Remove All Particle Systems";
1430 ot->description = "Remove all particle system within the active object";
1431 ot->idname = "PARTICLE_OT_particle_system_remove_all";
1432
1435
1436 /* flags */
1437 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1438}
#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)
@ 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:2523
void BKE_id_free(Main *bmain, void *idv)
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:782
@ LIB_ID_COPY_ACTIONS
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_DEFAULT
void id_us_min(ID *id)
Definition lib_id.cc:366
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:2155
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:3900
void psys_check_group_weights(struct ParticleSettings *part)
Definition particle.cc:766
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition particle.cc:3844
void psys_emitter_customdata_mask(struct ParticleSystem *psys, struct CustomData_MeshMasks *r_cddata_masks)
Definition particle.cc:2207
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:3984
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition particle.cc:538
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition particle.cc:668
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition particle.cc:907
#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:1834
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition particle.cc:4088
#define PEK_USE_WCO
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#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)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
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_UTF8(dst, format,...)
#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:1081
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ eModifierType_ParticleSystem
@ eModifierType_Fluid
@ eModifierType_DynamicPaint
eObjectMode
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_OBJECT
@ OB_MESH
@ PTARGET_CURRENT
@ PSYS_GLOBAL_HAIR
@ PART_DUPLIW_CURRENT
@ PART_HAIR
@ 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
#define ND_MODE
Definition WM_types.hh:445
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define ND_PARTICLE
Definition WM_types.hh:465
#define NS_MODE_OBJECT
Definition WM_types.hh:560
#define ND_POINTCACHE
Definition WM_types.hh:466
#define NC_OBJECT
Definition WM_types.hh:379
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
nullptr float
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
#define printf(...)
bool all(VecOp< bool, D >) RET
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 particle_system_remove_all_exec(bContext *C, wmOperator *)
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)
void PARTICLE_OT_particle_system_remove_all(wmOperatorType *ot)
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 bool remove_all_particle_systems_poll(bContext *C)
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:414
void * last
void * first
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237