Blender  V2.93
particle_edit.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 by Janne Karhu.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 #include "DNA_view3d_types.h"
36 
37 #include "BLI_kdtree.h"
38 #include "BLI_lasso_2d.h"
39 #include "BLI_listbase.h"
40 #include "BLI_math.h"
41 #include "BLI_rand.h"
42 #include "BLI_rect.h"
43 #include "BLI_task.h"
44 #include "BLI_utildefines.h"
45 
46 #include "BKE_bvhutils.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_main.h"
50 #include "BKE_mesh.h"
51 #include "BKE_mesh_runtime.h"
52 #include "BKE_modifier.h"
53 #include "BKE_object.h"
54 #include "BKE_particle.h"
55 #include "BKE_pointcache.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 
59 #include "DEG_depsgraph.h"
60 
61 #include "ED_mesh.h"
62 #include "ED_object.h"
63 #include "ED_particle.h"
64 #include "ED_physics.h"
65 #include "ED_screen.h"
66 #include "ED_select_utils.h"
67 #include "ED_view3d.h"
68 
69 #include "GPU_immediate.h"
70 #include "GPU_immediate_util.h"
71 #include "GPU_state.h"
72 
73 #include "UI_resources.h"
74 
75 #include "WM_api.h"
76 #include "WM_message.h"
77 #include "WM_toolsystem.h"
78 #include "WM_types.h"
79 
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82 
83 #include "DEG_depsgraph_query.h"
84 
85 #include "PIL_time_utildefines.h"
86 
87 #include "physics_intern.h"
88 
90 
91 /* -------------------------------------------------------------------- */
96 {
100 
101  if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
102  return false;
103  }
104 
106  if (edit == NULL) {
107  return false;
108  }
109  if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) {
110  return false;
111  }
112 
113  return true;
114 }
115 
117 {
121 
122  if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
123  return false;
124  }
125 
127  if (edit == NULL || edit->psys == NULL) {
128  return false;
129  }
130  if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) {
131  return false;
132  }
133 
134  return true;
135 }
136 
138 {
140  ARegion *region = CTX_wm_region(C);
141 
142  return (PE_poll(C) && (area && area->spacetype == SPACE_VIEW3D) &&
143  (region && region->regiontype == RGN_TYPE_WINDOW));
144 }
145 
147 {
148  POINT_P;
149 
150  if (edit == 0) {
151  return;
152  }
153 
154  if (edit->points) {
155  LOOP_POINTS {
156  if (point->keys) {
157  MEM_freeN(point->keys);
158  }
159  }
160 
161  MEM_freeN(edit->points);
162  }
163 
164  if (edit->mirror_cache) {
165  MEM_freeN(edit->mirror_cache);
166  }
167 
168  if (edit->emitter_cosnos) {
169  MEM_freeN(edit->emitter_cosnos);
170  edit->emitter_cosnos = 0;
171  }
172 
173  if (edit->emitter_field) {
174  BLI_kdtree_3d_free(edit->emitter_field);
175  edit->emitter_field = 0;
176  }
177 
178  psys_free_path_cache(edit->psys, edit);
179 
180  MEM_freeN(edit);
181 }
182 
184  Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
185 {
186  Object *ob = OBACT(view_layer);
188  ParticleSystem *psys;
189  ParticleSystemModifierData *psmd_eval = NULL;
190  POINT_P;
191  KEY_K;
192  float co[3], mat[4][4];
193  int ok = 0;
194 
195  if (!edit) {
196  return ok;
197  }
198 
199  if ((psys = edit->psys)) {
200  psmd_eval = edit->psmd_eval;
201  }
202  else {
203  unit_m4(mat);
204  }
205 
207  if (psys) {
209  ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
210  }
211 
213  copy_v3_v3(co, key->co);
214  mul_m4_v3(mat, co);
215  DO_MINMAX(co, min, max);
216  ok = 1;
217  }
218  }
219 
220  if (!ok) {
221  BKE_object_minmax(ob, min, max, true);
222  ok = 1;
223  }
224 
225  return ok;
226 }
227 
230 /* -------------------------------------------------------------------- */
235 {
236  if (edit) {
237  edit->edited = 1;
238  if (edit->psys) {
239  edit->psys->flag |= PSYS_EDITED;
240  }
241  return 1;
242  }
243 
244  return 0;
245 }
246 
248 {
250 }
251 
252 static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *brush)
253 {
254 #if 0 /* TODO: Here we can enable unified brush size, needs more work. */
256  float size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
257 #endif
258 
259  return brush->size;
260 }
261 
263 {
264  if (psys->part && psys->part->type == PART_HAIR) {
265  if ((psys->flag & PSYS_HAIR_DYNAMICS) != 0 && (psys->pointcache->flag & PTCACHE_BAKED) != 0) {
266  return psys->pointcache->edit;
267  }
268  return psys->edit;
269  }
270  if (psys->pointcache->flag & PTCACHE_BAKED) {
271  return psys->pointcache->edit;
272  }
273  return NULL;
274 }
275 
276 /* NOTE: Similar to creation of edit, but only updates pointers in the
277  * existing struct.
278  */
280 {
281  ParticleSystem *psys = edit->psys;
282  ParticleData *pa = psys->particles;
283  for (int p = 0; p < edit->totpoint; p++) {
284  PTCacheEditPoint *point = &edit->points[p];
285  HairKey *hair_key = pa->hair;
286  for (int k = 0; k < point->totkey; k++) {
287  PTCacheEditKey *key = &point->keys[k];
288  key->co = hair_key->co;
289  key->time = &hair_key->time;
290  key->flag = hair_key->editflag;
291  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
292  key->flag |= PEK_USE_WCO;
293  hair_key->editflag |= PEK_USE_WCO;
294  }
295  hair_key++;
296  }
297  pa++;
298  }
299 }
300 
301 /* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
302  *
303  * note: this function runs on poll, therefore it can runs many times a second
304  * keep it fast! */
306 {
308  PTCacheEdit *edit = NULL;
309  ListBase pidlist;
310  PTCacheID *pid;
311 
312  if (pset == NULL || ob == NULL) {
313  return NULL;
314  }
315 
316  pset->scene = scene;
317  pset->object = ob;
318 
319  BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
320 
321  /* in the case of only one editable thing, set pset->edittype accordingly */
322  if (BLI_listbase_is_single(&pidlist)) {
323  pid = pidlist.first;
324  switch (pid->type) {
326  pset->edittype = PE_TYPE_PARTICLES;
327  break;
329  pset->edittype = PE_TYPE_SOFTBODY;
330  break;
331  case PTCACHE_TYPE_CLOTH:
332  pset->edittype = PE_TYPE_CLOTH;
333  break;
334  }
335  }
336 
337  for (pid = pidlist.first; pid; pid = pid->next) {
338  if (pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
339  ParticleSystem *psys = pid->calldata;
340 
341  if (psys->flag & PSYS_CURRENT) {
342  if (psys->part && psys->part->type == PART_HAIR) {
343  if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
344  if (create && !psys->pointcache->edit) {
346  }
347  edit = pid->cache->edit;
348  }
349  else {
350  if (create && !psys->edit) {
351  if (psys->flag & PSYS_HAIR_DONE) {
353  }
354  }
355  edit = psys->edit;
356  }
357  }
358  else {
359  if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
360  PE_create_particle_edit(depsgraph, scene, ob, pid->cache, psys);
361  }
362  edit = pid->cache->edit;
363  }
364 
365  break;
366  }
367  }
368  else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
369  if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
370  pset->flag |= PE_FADE_TIME;
371  // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
373  }
374  edit = pid->cache->edit;
375  break;
376  }
377  else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
378  if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
379  pset->flag |= PE_FADE_TIME;
380  // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
382  }
383  edit = pid->cache->edit;
384  break;
385  }
386  }
387 
388  /* Don't consider inactive or render dependency graphs, since they might be evaluated for a
389  * different number of children. or have different pointer to evaluated particle system or
390  * modifier which will also cause troubles. */
391  if (edit && DEG_is_active(depsgraph)) {
392  edit->pid = *pid;
394  if (edit->psys != NULL && edit->psys_eval != NULL) {
395  psys_copy_particles(edit->psys, edit->psys_eval);
397  }
399  }
400  }
401 
402  BLI_freelistN(&pidlist);
403 
404  return edit;
405 }
406 
408 {
409  return pe_get_current(depsgraph, scene, ob, false);
410 }
411 
413 {
414  return pe_get_current(depsgraph, scene, ob, true);
415 }
416 
418 {
419  if (ob->mode == OB_MODE_PARTICLE_EDIT) {
421  }
422 }
423 
424 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
425 {
427  POINT_P;
428  KEY_K;
429 
430  if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
431  LOOP_POINTS {
432  LOOP_KEYS {
433  if (fabsf(cfra - *key->time) < pset->fade_frames) {
434  key->flag &= ~PEK_HIDE;
435  }
436  else {
437  key->flag |= PEK_HIDE;
438  // key->flag &= ~PEK_SELECT;
439  }
440  }
441  }
442  }
443  else {
444  LOOP_POINTS {
445  LOOP_KEYS {
446  key->flag &= ~PEK_HIDE;
447  }
448  }
449  }
450 }
451 
452 static int pe_x_mirror(Object *ob)
453 {
454  if (ob->type == OB_MESH) {
455  return (((Mesh *)ob->data)->symmetry & ME_SYMMETRY_X);
456  }
457 
458  return 0;
459 }
460 
463 /* -------------------------------------------------------------------- */
467 typedef struct PEData {
469 
479 
481 
482  const int *mval;
483  const rcti *rect;
484  float rad;
485  float dval;
486  int select;
488 
489  float *dvec;
490  float combfac;
491  float pufffac;
492  float cutfac;
493  float smoothfac;
494  float weightfac;
495  float growfac;
496  int totrekey;
497 
498  int invert;
499  int tot;
500  float vec[3];
501 
506 
508 {
509  memset(data, 0, sizeof(*data));
510 
511  data->context = C;
512  data->bmain = CTX_data_main(C);
513  data->scene = CTX_data_scene(C);
514  data->view_layer = CTX_data_view_layer(C);
517  data->edit = PE_get_current(data->depsgraph, data->scene, data->ob);
518 }
519 
521 {
522  PE_set_data(C, data);
523 
524  ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph);
525 
526  if (!XRAY_ENABLED(data->vc.v3d)) {
527  if (!(data->vc.v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN)) {
528  ED_view3d_depth_override(data->depsgraph,
529  data->vc.region,
530  data->vc.v3d,
531  data->vc.obact,
533  true);
534  }
535  }
536 }
537 
538 static bool PE_create_shape_tree(PEData *data, Object *shapeob)
539 {
540  Object *shapeob_eval = DEG_get_evaluated_object(data->depsgraph, shapeob);
541  Mesh *mesh = BKE_object_get_evaluated_mesh(shapeob_eval);
542 
543  memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
544 
545  if (!mesh) {
546  return false;
547  }
548 
549  return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRI, 4) != NULL);
550 }
551 
553 {
554  free_bvhtree_from_mesh(&data->shape_bvh);
555 }
556 
558 {
559  uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
560  rng_seed ^= POINTER_AS_UINT(data->ob);
561  rng_seed ^= POINTER_AS_UINT(data->edit);
562  data->rng = BLI_rng_new(rng_seed);
563 }
564 
566 {
567  if (data->rng != NULL) {
568  BLI_rng_free(data->rng);
569  data->rng = NULL;
570  }
571 }
572 
575 /* -------------------------------------------------------------------- */
579 static bool key_test_depth(const PEData *data, const float co[3], const int screen_co[2])
580 {
581  View3D *v3d = data->vc.v3d;
582  ViewDepths *vd = data->vc.rv3d->depths;
583  float depth;
584 
585  /* nothing to do */
586  if (XRAY_ENABLED(v3d)) {
587  return true;
588  }
589 
590  /* used to calculate here but all callers have the screen_co already, so pass as arg */
591 #if 0
592  if (ED_view3d_project_int_global(data->vc.region,
593  co,
594  screen_co,
597  return 0;
598  }
599 #endif
600 
601  /* check if screen_co is within bounds because brush_cut uses out of screen coords */
602  if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
603  BLI_assert(vd && vd->depths);
604  /* we know its not clipped */
605  depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
606  }
607  else {
608  return 0;
609  }
610 
611  float win[3];
612  ED_view3d_project(data->vc.region, co, win);
613 
614  if (win[2] - 0.00001f > depth) {
615  return 0;
616  }
617  return 1;
618 }
619 
620 static bool key_inside_circle(const PEData *data, float rad, const float co[3], float *distance)
621 {
622  float dx, dy, dist;
623  int screen_co[2];
624 
625  /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
626  if (ED_view3d_project_int_global(data->vc.region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) !=
627  V3D_PROJ_RET_OK) {
628  return 0;
629  }
630 
631  dx = data->mval[0] - screen_co[0];
632  dy = data->mval[1] - screen_co[1];
633  dist = sqrtf(dx * dx + dy * dy);
634 
635  if (dist > rad) {
636  return 0;
637  }
638 
639  if (key_test_depth(data, co, screen_co)) {
640  if (distance) {
641  *distance = dist;
642  }
643 
644  return 1;
645  }
646 
647  return 0;
648 }
649 
650 static bool key_inside_rect(PEData *data, const float co[3])
651 {
652  int screen_co[2];
653 
654  if (ED_view3d_project_int_global(data->vc.region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) !=
655  V3D_PROJ_RET_OK) {
656  return 0;
657  }
658 
659  if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax &&
660  screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax) {
661  return key_test_depth(data, co, screen_co);
662  }
663 
664  return 0;
665 }
666 
667 static bool key_inside_test(PEData *data, const float co[3])
668 {
669  if (data->mval) {
670  return key_inside_circle(data, data->rad, co, NULL);
671  }
672  return key_inside_rect(data, co);
673 }
674 
676 {
677  KEY_K;
678 
679  if (point->flag & PEP_HIDE) {
680  return 0;
681  }
682 
684  return 1;
685  }
686 
687  return 0;
688 }
689 
692 /* -------------------------------------------------------------------- */
696 typedef void (*ForPointFunc)(PEData *data, int point_index);
697 typedef void (*ForHitPointFunc)(PEData *data, int point_index, float mouse_distance);
698 
699 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside);
700 
701 typedef void (*ForKeyMatFunc)(PEData *data,
702  const float mat[4][4],
703  const float imat[4][4],
704  int point_index,
705  int key_index,
706  PTCacheEditKey *key);
707 typedef void (*ForHitKeyMatFunc)(PEData *data,
708  float mat[4][4],
709  float imat[4][4],
710  int point_index,
711  int key_index,
712  PTCacheEditKey *key,
713  float mouse_distance);
714 
716  PSEL_NEAREST = (1 << 0),
717  PSEL_ALL_KEYS = (1 << 1),
718 };
719 
720 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum eParticleSelectFlag flag)
721 {
722  ParticleEditSettings *pset = PE_settings(data->scene);
723  PTCacheEdit *edit = data->edit;
724  POINT_P;
725  KEY_K;
726  int nearest_point, nearest_key;
727  float dist = data->rad;
728 
729  /* in path select mode we have no keys */
730  if (pset->selectmode == SCE_SELECT_PATH) {
731  return;
732  }
733 
734  nearest_point = -1;
735  nearest_key = -1;
736 
738  if (pset->selectmode == SCE_SELECT_END) {
739  if (point->totkey) {
740  /* only do end keys */
741  key = point->keys + point->totkey - 1;
742 
743  if (flag & PSEL_NEAREST) {
744  if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
745  nearest_point = p;
746  nearest_key = point->totkey - 1;
747  }
748  }
749  else {
750  const bool is_inside = key_inside_test(data, KEY_WCO);
751  if (is_inside || (flag & PSEL_ALL_KEYS)) {
752  func(data, p, point->totkey - 1, is_inside);
753  }
754  }
755  }
756  }
757  else {
758  /* do all keys */
760  if (flag & PSEL_NEAREST) {
761  if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
762  nearest_point = p;
763  nearest_key = k;
764  }
765  }
766  else {
767  const bool is_inside = key_inside_test(data, KEY_WCO);
768  if (is_inside || (flag & PSEL_ALL_KEYS)) {
769  func(data, p, k, is_inside);
770  }
771  }
772  }
773  }
774  }
775 
776  /* do nearest only */
777  if (flag & PSEL_NEAREST) {
778  if (nearest_point != -1) {
779  func(data, nearest_point, nearest_key, true);
780  }
781  }
782 }
783 
784 static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int selected)
785 {
786  ParticleEditSettings *pset = PE_settings(data->scene);
787  PTCacheEdit *edit = data->edit;
788  POINT_P;
789  KEY_K;
790 
791  /* all is selected in path mode */
792  if (pset->selectmode == SCE_SELECT_PATH) {
793  selected = 0;
794  }
795 
797  if (pset->selectmode == SCE_SELECT_END) {
798  if (point->totkey) {
799  /* only do end keys */
800  key = point->keys + point->totkey - 1;
801 
802  if (selected == 0 || key->flag & PEK_SELECT) {
803  float mouse_distance;
804  if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
805  func(data, p, mouse_distance);
806  }
807  }
808  }
809  }
810  else {
811  /* do all keys */
813  if (selected == 0 || key->flag & PEK_SELECT) {
814  float mouse_distance;
815  if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
816  func(data, p, mouse_distance);
817  break;
818  }
819  }
820  }
821  }
822  }
823 }
824 
825 typedef struct KeyIterData {
828  int selected;
831 
832 static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
833  const int iter,
834  const TaskParallelTLS *__restrict UNUSED(tls))
835 {
836  KeyIterData *iter_data = (KeyIterData *)iter_data_v;
837  PEData *data = iter_data->data;
838  PTCacheEdit *edit = data->edit;
839  PTCacheEditPoint *point = &edit->points[iter];
840  if (point->flag & PEP_HIDE) {
841  return;
842  }
843  ParticleSystem *psys = edit->psys;
844  ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
845  ParticleEditSettings *pset = PE_settings(data->scene);
846  const int selected = iter_data->selected;
847  float mat[4][4], imat[4][4];
848  unit_m4(mat);
849  unit_m4(imat);
850  if (pset->selectmode == SCE_SELECT_END) {
851  if (point->totkey) {
852  /* only do end keys */
853  PTCacheEditKey *key = point->keys + point->totkey - 1;
854 
855  if (selected == 0 || key->flag & PEK_SELECT) {
856  float mouse_distance;
857  if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
858  if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
860  data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
861  invert_m4_m4(imat, mat);
862  }
863  iter_data->func(data, mat, imat, iter, point->totkey - 1, key, mouse_distance);
864  }
865  }
866  }
867  }
868  else {
869  /* do all keys */
870  PTCacheEditKey *key;
871  int k;
873  if (selected == 0 || key->flag & PEK_SELECT) {
874  float mouse_distance;
875  if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
876  if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
878  data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
879  invert_m4_m4(imat, mat);
880  }
881  iter_data->func(data, mat, imat, iter, k, key, mouse_distance);
882  }
883  }
884  }
885  }
886 }
887 
888 static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selected)
889 {
890  PTCacheEdit *edit = data->edit;
891  ParticleEditSettings *pset = PE_settings(data->scene);
892  /* all is selected in path mode */
893  if (pset->selectmode == SCE_SELECT_PATH) {
894  selected = 0;
895  }
896 
897  KeyIterData iter_data;
898  iter_data.data = data;
899  iter_data.edit = edit;
900  iter_data.selected = selected;
901  iter_data.func = func;
902 
903  TaskParallelSettings settings;
905  BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
906 }
907 
909 {
910  PTCacheEdit *edit = data->edit;
911  POINT_P;
912 
914  func(data, p);
915  }
916 }
917 
919 {
920  PTCacheEdit *edit = data->edit;
921  POINT_P;
922  KEY_K;
923 
926  func(data, p, k, true);
927  }
928  }
929 }
930 
932 {
933  PTCacheEdit *edit = data->edit;
934  POINT_P;
935 
936  LOOP_POINTS {
937  func(data, p);
938  }
939 }
940 
942 {
944  POINT_P;
945  KEY_K;
946  int sel = 0;
947 
949  if (pset->selectmode == SCE_SELECT_POINT) {
951  sel++;
952  }
953  }
954  else if (pset->selectmode == SCE_SELECT_END) {
955  if (point->totkey) {
956  key = point->keys + point->totkey - 1;
957  if (key->flag & PEK_SELECT) {
958  sel++;
959  }
960  }
961  }
962  }
963 
964  return sel;
965 }
966 
969 /* -------------------------------------------------------------------- */
974 {
975  PTCacheEdit *edit;
976  ParticleSystemModifierData *psmd_eval;
977  KDTree_3d *tree;
978  KDTreeNearest_3d nearest;
979  HairKey *key;
980  PARTICLE_P;
981  float mat[4][4], co[3];
982  int index, totpart;
983 
984  edit = psys->edit;
985  psmd_eval = edit->psmd_eval;
986  totpart = psys->totpart;
987 
988  if (!psmd_eval->mesh_final) {
989  return;
990  }
991 
992  tree = BLI_kdtree_3d_new(totpart);
993 
994  /* insert particles into kd tree */
996  {
997  key = pa->hair;
998  psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
999  copy_v3_v3(co, key->co);
1000  mul_m4_v3(mat, co);
1001  BLI_kdtree_3d_insert(tree, p, co);
1002  }
1003 
1004  BLI_kdtree_3d_balance(tree);
1005 
1006  /* lookup particles and set in mirror cache */
1007  if (!edit->mirror_cache) {
1008  edit->mirror_cache = MEM_callocN(sizeof(int) * totpart, "PE mirror cache");
1009  }
1010 
1012  {
1013  key = pa->hair;
1014  psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
1015  copy_v3_v3(co, key->co);
1016  mul_m4_v3(mat, co);
1017  co[0] = -co[0];
1018 
1019  index = BLI_kdtree_3d_find_nearest(tree, co, &nearest);
1020 
1021  /* this needs a custom threshold still, duplicated for editmode mirror */
1022  if (index != -1 && index != p && (nearest.dist <= 0.0002f)) {
1023  edit->mirror_cache[p] = index;
1024  }
1025  else {
1026  edit->mirror_cache[p] = -1;
1027  }
1028  }
1029 
1030  /* make sure mirrors are in two directions */
1032  {
1033  if (edit->mirror_cache[p]) {
1034  index = edit->mirror_cache[p];
1035  if (edit->mirror_cache[index] != p) {
1036  edit->mirror_cache[p] = -1;
1037  }
1038  }
1039  }
1040 
1041  BLI_kdtree_3d_free(tree);
1042 }
1043 
1045  Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
1046 {
1047  HairKey *hkey, *mhkey;
1048  PTCacheEditPoint *point, *mpoint;
1049  PTCacheEditKey *key, *mkey;
1050  PTCacheEdit *edit;
1051  float mat[4][4], mmat[4][4], immat[4][4];
1052  int i, mi, k;
1053 
1054  edit = psys->edit;
1055  i = pa - psys->particles;
1056 
1057  /* find mirrored particle if needed */
1058  if (!mpa) {
1059  if (!edit->mirror_cache) {
1060  PE_update_mirror_cache(ob, psys);
1061  }
1062 
1063  if (!edit->mirror_cache) {
1064  return; /* something went wrong! */
1065  }
1066 
1067  mi = edit->mirror_cache[i];
1068  if (mi == -1) {
1069  return;
1070  }
1071  mpa = psys->particles + mi;
1072  }
1073  else {
1074  mi = mpa - psys->particles;
1075  }
1076 
1077  point = edit->points + i;
1078  mpoint = edit->points + mi;
1079 
1080  /* make sure they have the same amount of keys */
1081  if (pa->totkey != mpa->totkey) {
1082  if (mpa->hair) {
1083  MEM_freeN(mpa->hair);
1084  }
1085  if (mpoint->keys) {
1086  MEM_freeN(mpoint->keys);
1087  }
1088 
1089  mpa->hair = MEM_dupallocN(pa->hair);
1090  mpa->totkey = pa->totkey;
1091  mpoint->keys = MEM_dupallocN(point->keys);
1092  mpoint->totkey = point->totkey;
1093 
1094  mhkey = mpa->hair;
1095  mkey = mpoint->keys;
1096  for (k = 0; k < mpa->totkey; k++, mkey++, mhkey++) {
1097  mkey->co = mhkey->co;
1098  mkey->time = &mhkey->time;
1099  mkey->flag &= ~PEK_SELECT;
1100  }
1101  }
1102 
1103  /* mirror positions and tags */
1104  psys_mat_hair_to_orco(ob, mesh, psys->part->from, pa, mat);
1105  psys_mat_hair_to_orco(ob, mesh, psys->part->from, mpa, mmat);
1106  invert_m4_m4(immat, mmat);
1107 
1108  hkey = pa->hair;
1109  mhkey = mpa->hair;
1110  key = point->keys;
1111  mkey = mpoint->keys;
1112  for (k = 0; k < pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
1113  copy_v3_v3(mhkey->co, hkey->co);
1114  mul_m4_v3(mat, mhkey->co);
1115  mhkey->co[0] = -mhkey->co[0];
1116  mul_m4_v3(immat, mhkey->co);
1117 
1118  if (key->flag & PEK_TAG) {
1119  mkey->flag |= PEK_TAG;
1120  }
1121 
1122  mkey->length = key->length;
1123  }
1124 
1125  if (point->flag & PEP_TAG) {
1126  mpoint->flag |= PEP_TAG;
1127  }
1128  if (point->flag & PEP_EDIT_RECALC) {
1129  mpoint->flag |= PEP_EDIT_RECALC;
1130  }
1131 }
1132 
1133 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
1134 {
1135  PTCacheEdit *edit;
1136  ParticleSystemModifierData *psmd_eval;
1137  POINT_P;
1138 
1139  if (!psys) {
1140  return;
1141  }
1142 
1143  edit = psys->edit;
1144  psmd_eval = edit->psmd_eval;
1145 
1146  if (psmd_eval == NULL || psmd_eval->mesh_final == NULL) {
1147  return;
1148  }
1149 
1150  if (!edit->mirror_cache) {
1151  PE_update_mirror_cache(ob, psys);
1152  }
1153 
1154  if (!edit->mirror_cache) {
1155  return; /* something went wrong */
1156  }
1157 
1158  /* we delay settings the PARS_EDIT_RECALC for mirrored particles
1159  * to avoid doing mirror twice */
1160  LOOP_POINTS {
1161  if (point->flag & PEP_EDIT_RECALC) {
1162  PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
1163 
1164  if (edit->mirror_cache[p] != -1) {
1165  edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
1166  }
1167  }
1168  }
1169 
1170  LOOP_POINTS {
1171  if (point->flag & PEP_EDIT_RECALC) {
1172  if (edit->mirror_cache[p] != -1) {
1173  edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
1174  }
1175  }
1176  }
1177 }
1178 
1181 /* -------------------------------------------------------------------- */
1185 typedef struct DeflectEmitterIter {
1189  float dist;
1192 
1193 static void deflect_emitter_iter(void *__restrict iter_data_v,
1194  const int iter,
1195  const TaskParallelTLS *__restrict UNUSED(tls))
1196 {
1197  DeflectEmitterIter *iter_data = (DeflectEmitterIter *)iter_data_v;
1198  PTCacheEdit *edit = iter_data->edit;
1199  PTCacheEditPoint *point = &edit->points[iter];
1200  if ((point->flag & PEP_EDIT_RECALC) == 0) {
1201  return;
1202  }
1203  Object *object = iter_data->object;
1204  ParticleSystem *psys = iter_data->psys;
1205  ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
1206  PTCacheEditKey *key;
1207  int k;
1208  float hairimat[4][4], hairmat[4][4];
1209  int index;
1210  float *vec, *nor, dvec[3], dot, dist_1st = 0.0f;
1211  const float dist = iter_data->dist;
1212  const float emitterdist = iter_data->emitterdist;
1214  object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
1215 
1216  LOOP_KEYS {
1217  mul_m4_v3(hairmat, key->co);
1218  }
1219 
1220  LOOP_KEYS {
1221  if (k == 0) {
1222  dist_1st = len_v3v3((key + 1)->co, key->co);
1223  dist_1st *= dist * emitterdist;
1224  }
1225  else {
1226  index = BLI_kdtree_3d_find_nearest(edit->emitter_field, key->co, NULL);
1227 
1228  vec = edit->emitter_cosnos + index * 6;
1229  nor = vec + 3;
1230 
1231  sub_v3_v3v3(dvec, key->co, vec);
1232 
1233  dot = dot_v3v3(dvec, nor);
1234  copy_v3_v3(dvec, nor);
1235 
1236  if (dot > 0.0f) {
1237  if (dot < dist_1st) {
1238  normalize_v3(dvec);
1239  mul_v3_fl(dvec, dist_1st - dot);
1240  add_v3_v3(key->co, dvec);
1241  }
1242  }
1243  else {
1244  normalize_v3(dvec);
1245  mul_v3_fl(dvec, dist_1st - dot);
1246  add_v3_v3(key->co, dvec);
1247  }
1248  if (k == 1) {
1249  dist_1st *= 1.3333f;
1250  }
1251  }
1252  }
1253 
1254  invert_m4_m4(hairimat, hairmat);
1255 
1256  LOOP_KEYS {
1257  mul_m4_v3(hairimat, key->co);
1258  }
1259 }
1260 
1261 /* tries to stop edited particles from going through the emitter's surface */
1263 {
1265  ParticleSystem *psys;
1266  const float dist = ED_view3d_select_dist_px() * 0.01f;
1267 
1268  if (edit == NULL || edit->psys == NULL || (pset->flag & PE_DEFLECT_EMITTER) == 0 ||
1269  (edit->psys->flag & PSYS_GLOBAL_HAIR)) {
1270  return;
1271  }
1272 
1273  psys = edit->psys;
1274 
1275  if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) {
1276  return;
1277  }
1278 
1279  DeflectEmitterIter iter_data;
1280  iter_data.object = ob;
1281  iter_data.psys = psys;
1282  iter_data.edit = edit;
1283  iter_data.dist = dist;
1284  iter_data.emitterdist = pset->emitterdist;
1285 
1286  TaskParallelSettings settings;
1288  BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
1289 }
1290 
1291 typedef struct ApplyLengthsIterData {
1294 
1295 static void apply_lengths_iter(void *__restrict iter_data_v,
1296  const int iter,
1297  const TaskParallelTLS *__restrict UNUSED(tls))
1298 {
1299  ApplyLengthsIterData *iter_data = (ApplyLengthsIterData *)iter_data_v;
1300  PTCacheEdit *edit = iter_data->edit;
1301  PTCacheEditPoint *point = &edit->points[iter];
1302  if ((point->flag & PEP_EDIT_RECALC) == 0) {
1303  return;
1304  }
1305  PTCacheEditKey *key;
1306  int k;
1307  LOOP_KEYS {
1308  if (k) {
1309  float dv1[3];
1310  sub_v3_v3v3(dv1, key->co, (key - 1)->co);
1311  normalize_v3(dv1);
1312  mul_v3_fl(dv1, (key - 1)->length);
1313  add_v3_v3v3(key->co, (key - 1)->co, dv1);
1314  }
1315  }
1316 }
1317 
1318 /* force set distances between neighboring keys */
1320 {
1322 
1323  if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0) {
1324  return;
1325  }
1326 
1327  if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
1328  return;
1329  }
1330 
1331  ApplyLengthsIterData iter_data;
1332  iter_data.edit = edit;
1333 
1334  TaskParallelSettings settings;
1336  BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
1337 }
1338 
1339 typedef struct IterateLengthsIterData {
1343 
1344 static void iterate_lengths_iter(void *__restrict iter_data_v,
1345  const int iter,
1346  const TaskParallelTLS *__restrict UNUSED(tls))
1347 {
1348  IterateLengthsIterData *iter_data = (IterateLengthsIterData *)iter_data_v;
1349  PTCacheEdit *edit = iter_data->edit;
1350  PTCacheEditPoint *point = &edit->points[iter];
1351  if ((point->flag & PEP_EDIT_RECALC) == 0) {
1352  return;
1353  }
1354  ParticleEditSettings *pset = iter_data->pset;
1355  float tlen;
1356  float dv0[3] = {0.0f, 0.0f, 0.0f};
1357  float dv1[3] = {0.0f, 0.0f, 0.0f};
1358  float dv2[3] = {0.0f, 0.0f, 0.0f};
1359  for (int j = 1; j < point->totkey; j++) {
1360  PTCacheEditKey *key;
1361  int k;
1362  float mul = 1.0f / (float)point->totkey;
1363  if (pset->flag & PE_LOCK_FIRST) {
1364  key = point->keys + 1;
1365  k = 1;
1366  dv1[0] = dv1[1] = dv1[2] = 0.0;
1367  }
1368  else {
1369  key = point->keys;
1370  k = 0;
1371  dv0[0] = dv0[1] = dv0[2] = 0.0;
1372  }
1373 
1374  for (; k < point->totkey; k++, key++) {
1375  if (k) {
1376  sub_v3_v3v3(dv0, (key - 1)->co, key->co);
1377  tlen = normalize_v3(dv0);
1378  mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
1379  }
1380  if (k < point->totkey - 1) {
1381  sub_v3_v3v3(dv2, (key + 1)->co, key->co);
1382  tlen = normalize_v3(dv2);
1383  mul_v3_fl(dv2, mul * (tlen - key->length));
1384  }
1385  if (k) {
1386  add_v3_v3((key - 1)->co, dv1);
1387  }
1388  add_v3_v3v3(dv1, dv0, dv2);
1389  }
1390  }
1391 }
1392 
1393 /* try to find a nice solution to keep distances between neighboring keys */
1395 {
1397  if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0) {
1398  return;
1399  }
1400  if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
1401  return;
1402  }
1403 
1404  IterateLengthsIterData iter_data;
1405  iter_data.edit = edit;
1406  iter_data.pset = pset;
1407 
1408  TaskParallelSettings settings;
1410  BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
1411 }
1412 
1413 /* set current distances to be kept between neighboring keys */
1415 {
1416  POINT_P;
1417  KEY_K;
1418 
1419  if (edit == 0) {
1420  return;
1421  }
1422 
1424  key = point->keys;
1425  for (k = 0; k < point->totkey - 1; k++, key++) {
1426  key->length = len_v3v3(key->co, (key + 1)->co);
1427  }
1428  }
1429 }
1430 
1431 /* calculate a tree for finding nearest emitter's vertice */
1433 {
1434  PTCacheEdit *edit = psys->edit;
1435  Mesh *mesh = edit->psmd_eval->mesh_final;
1436  float *vec, *nor;
1437  int i, totface /*, totvert*/;
1438 
1439  if (!mesh) {
1440  return;
1441  }
1442 
1443  if (edit->emitter_cosnos) {
1444  MEM_freeN(edit->emitter_cosnos);
1445  }
1446 
1447  BLI_kdtree_3d_free(edit->emitter_field);
1448 
1449  totface = mesh->totface;
1450  /*totvert=dm->getNumVerts(dm);*/ /*UNUSED*/
1451 
1452  edit->emitter_cosnos = MEM_callocN(sizeof(float[6]) * totface, "emitter cosnos");
1453 
1454  edit->emitter_field = BLI_kdtree_3d_new(totface);
1455 
1456  vec = edit->emitter_cosnos;
1457  nor = vec + 3;
1458 
1459  for (i = 0; i < totface; i++, vec += 6, nor += 6) {
1460  MFace *mface = &mesh->mface[i];
1461  MVert *mvert;
1462 
1463  mvert = &mesh->mvert[mface->v1];
1464  copy_v3_v3(vec, mvert->co);
1465  copy_v3fl_v3s(nor, mvert->no);
1466 
1467  mvert = &mesh->mvert[mface->v2];
1468  add_v3_v3v3(vec, vec, mvert->co);
1469  add_v3fl_v3fl_v3s(nor, nor, mvert->no);
1470 
1471  mvert = &mesh->mvert[mface->v3];
1472  add_v3_v3v3(vec, vec, mvert->co);
1473  add_v3fl_v3fl_v3s(nor, nor, mvert->no);
1474 
1475  if (mface->v4) {
1476  mvert = &mesh->mvert[mface->v4];
1477  add_v3_v3v3(vec, vec, mvert->co);
1478  add_v3fl_v3fl_v3s(nor, nor, mvert->no);
1479 
1480  mul_v3_fl(vec, 0.25);
1481  }
1482  else {
1483  mul_v3_fl(vec, 1.0f / 3.0f);
1484  }
1485 
1486  normalize_v3(nor);
1487 
1488  BLI_kdtree_3d_insert(edit->emitter_field, i, vec);
1489  }
1490 
1491  BLI_kdtree_3d_balance(edit->emitter_field);
1492 }
1493 
1494 static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
1495 {
1496  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
1497  HairKey *hkey;
1498  POINT_P;
1499  KEY_K;
1500 
1501  /* flag all particles to be updated if not using flag */
1502  if (!useflag) {
1503  LOOP_POINTS {
1504  point->flag |= PEP_EDIT_RECALC;
1505  }
1506  }
1507 
1508  /* flush edit key flag to hair key flag to preserve selection
1509  * on save */
1510  if (edit->psys) {
1511  LOOP_POINTS {
1512  hkey = edit->psys->particles[p].hair;
1513  LOOP_KEYS {
1514  hkey->editflag = key->flag;
1515  hkey++;
1516  }
1517  }
1518  }
1519 
1520  psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
1521 
1522  /* disable update flag */
1523  LOOP_POINTS {
1524  point->flag &= ~PEP_EDIT_RECALC;
1525  }
1526 
1528 }
1529 
1531 {
1532  ParticleSystem *psys = edit->psys;
1533  ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
1534  POINT_P;
1535  KEY_K;
1536  float hairmat[4][4];
1537 
1538  if (psys == 0 || psys->edit == 0 || psmd_eval == NULL || psmd_eval->mesh_final == NULL) {
1539  return;
1540  }
1541 
1542  LOOP_POINTS {
1543  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1545  ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
1546  }
1547 
1548  LOOP_KEYS {
1549  copy_v3_v3(key->world_co, key->co);
1550  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
1551  mul_m4_v3(hairmat, key->world_co);
1552  }
1553  }
1554  }
1555 }
1556 static void update_velocities(PTCacheEdit *edit)
1557 {
1558  /*TODO: get frs_sec properly */
1559  float vec1[3], vec2[3], frs_sec, dfra;
1560  POINT_P;
1561  KEY_K;
1562 
1563  /* hair doesn't use velocities */
1564  if (edit->psys || !edit->points || !edit->points->keys->vel) {
1565  return;
1566  }
1567 
1568  frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1569 
1571  LOOP_KEYS {
1572  if (k == 0) {
1573  dfra = *(key + 1)->time - *key->time;
1574 
1575  if (dfra <= 0.0f) {
1576  continue;
1577  }
1578 
1579  sub_v3_v3v3(key->vel, (key + 1)->co, key->co);
1580 
1581  if (point->totkey > 2) {
1582  sub_v3_v3v3(vec1, (key + 1)->co, (key + 2)->co);
1583  project_v3_v3v3(vec2, vec1, key->vel);
1584  sub_v3_v3v3(vec2, vec1, vec2);
1585  madd_v3_v3fl(key->vel, vec2, 0.5f);
1586  }
1587  }
1588  else if (k == point->totkey - 1) {
1589  dfra = *key->time - *(key - 1)->time;
1590 
1591  if (dfra <= 0.0f) {
1592  continue;
1593  }
1594 
1595  sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
1596 
1597  if (point->totkey > 2) {
1598  sub_v3_v3v3(vec1, (key - 2)->co, (key - 1)->co);
1599  project_v3_v3v3(vec2, vec1, key->vel);
1600  sub_v3_v3v3(vec2, vec1, vec2);
1601  madd_v3_v3fl(key->vel, vec2, 0.5f);
1602  }
1603  }
1604  else {
1605  dfra = *(key + 1)->time - *(key - 1)->time;
1606 
1607  if (dfra <= 0.0f) {
1608  continue;
1609  }
1610 
1611  sub_v3_v3v3(key->vel, (key + 1)->co, (key - 1)->co);
1612  }
1613  mul_v3_fl(key->vel, frs_sec / dfra);
1614  }
1615  }
1616 }
1617 
1619 {
1620  /* use this to do partial particle updates, not usable when adding or
1621  * removing, then a full redo is necessary and calling this may crash */
1623  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
1624  POINT_P;
1625 
1626  if (!edit) {
1627  return;
1628  }
1629 
1630  /* flag all particles to be updated if not using flag */
1631  if (!useflag) {
1632  LOOP_POINTS {
1633  point->flag |= PEP_EDIT_RECALC;
1634  }
1635  }
1636 
1637  /* do post process on particle edit keys */
1638  pe_iterate_lengths(scene, edit);
1639  pe_deflect_emitter(scene, ob, edit);
1640  PE_apply_lengths(scene, edit);
1641  if (pe_x_mirror(ob)) {
1642  PE_apply_mirror(ob, edit->psys);
1643  }
1644  if (edit->psys) {
1645  update_world_cos(ob, edit);
1646  }
1647  if (pset->flag & PE_AUTO_VELOCITY) {
1648  update_velocities(edit);
1649  }
1650 
1651  /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
1652  * and flagging with PEK_HIDE will prevent selection. This might get restored once this is
1653  * supported in drawing (but doesn't make much sense for hair anyways). */
1654  if (edit->psys && edit->psys->part->type == PART_EMITTER) {
1655  PE_hide_keys_time(scene, edit, CFRA);
1656  }
1657 
1658  /* regenerate path caches */
1659  psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
1660 
1661  /* disable update flag */
1662  LOOP_POINTS {
1663  point->flag &= ~PEP_EDIT_RECALC;
1664  }
1665 
1666  if (edit->psys) {
1667  edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1668  }
1669 }
1670 
1673 /* -------------------------------------------------------------------- */
1677 /*-----selection callbacks-----*/
1678 
1679 static void select_key(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
1680 {
1681  PTCacheEdit *edit = data->edit;
1682  PTCacheEditPoint *point = edit->points + point_index;
1683  PTCacheEditKey *key = point->keys + key_index;
1684 
1685  if (data->select) {
1686  key->flag |= PEK_SELECT;
1687  }
1688  else {
1689  key->flag &= ~PEK_SELECT;
1690  }
1691 
1692  point->flag |= PEP_EDIT_RECALC;
1693  data->is_changed = true;
1694 }
1695 
1696 static void select_key_op(PEData *data, int point_index, int key_index, bool is_inside)
1697 {
1698  PTCacheEdit *edit = data->edit;
1699  PTCacheEditPoint *point = edit->points + point_index;
1700  PTCacheEditKey *key = point->keys + key_index;
1701  const bool is_select = key->flag & PEK_SELECT;
1702  const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
1703  if (sel_op_result != -1) {
1704  SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
1705  point->flag |= PEP_EDIT_RECALC;
1706  data->is_changed = true;
1707  }
1708 }
1709 
1710 static void select_keys(PEData *data,
1711  int point_index,
1712  int UNUSED(key_index),
1713  bool UNUSED(is_inside))
1714 {
1715  PTCacheEdit *edit = data->edit;
1716  PTCacheEditPoint *point = edit->points + point_index;
1717  KEY_K;
1718 
1719  LOOP_KEYS {
1720  if (data->select) {
1721  key->flag |= PEK_SELECT;
1722  }
1723  else {
1724  key->flag &= ~PEK_SELECT;
1725  }
1726  }
1727 
1728  point->flag |= PEP_EDIT_RECALC;
1729 }
1730 
1731 static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
1732 {
1733  PTCacheEdit *edit = data->edit;
1734  PTCacheEditPoint *point = edit->points + point_index;
1735  PTCacheEditKey *key = point->keys + key_index;
1736 
1737  if ((key->flag & PEK_SELECT) == 0) {
1738  key->flag |= PEK_SELECT;
1739  point->flag |= PEP_EDIT_RECALC;
1740  data->is_changed = true;
1741  }
1742 }
1743 
1745  int point_index,
1746  int key_index,
1747  bool UNUSED(is_inside))
1748 {
1749  PTCacheEdit *edit = data->edit;
1750  PTCacheEditPoint *point = edit->points + point_index;
1751  PTCacheEditKey *key = point->keys + key_index;
1752 
1753  if ((key->flag & PEK_SELECT) != 0) {
1754  key->flag &= ~PEK_SELECT;
1755  point->flag |= PEP_EDIT_RECALC;
1756  data->is_changed = true;
1757  }
1758 }
1759 
1760 static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
1761 {
1762  PTCacheEdit *edit = data->edit;
1763  PTCacheEditPoint *point = edit->points + point_index;
1764  PTCacheEditKey *key = point->keys + key_index;
1765 
1766  key->flag ^= PEK_SELECT;
1767  point->flag |= PEP_EDIT_RECALC;
1768  data->is_changed = true;
1769 }
1770 
1773 /* -------------------------------------------------------------------- */
1777 static bool select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, int action)
1778 {
1779  bool changed = false;
1780  switch (action) {
1781  case SEL_SELECT:
1782  if ((key->flag & PEK_SELECT) == 0) {
1783  key->flag |= PEK_SELECT;
1784  point->flag |= PEP_EDIT_RECALC;
1785  changed = true;
1786  }
1787  break;
1788  case SEL_DESELECT:
1789  if (key->flag & PEK_SELECT) {
1790  key->flag &= ~PEK_SELECT;
1791  point->flag |= PEP_EDIT_RECALC;
1792  changed = true;
1793  }
1794  break;
1795  case SEL_INVERT:
1796  if ((key->flag & PEK_SELECT) == 0) {
1797  key->flag |= PEK_SELECT;
1798  point->flag |= PEP_EDIT_RECALC;
1799  changed = true;
1800  }
1801  else {
1802  key->flag &= ~PEK_SELECT;
1803  point->flag |= PEP_EDIT_RECALC;
1804  changed = true;
1805  }
1806  break;
1807  }
1808  return changed;
1809 }
1810 
1812 {
1816  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
1817  POINT_P;
1818  KEY_K;
1819  int action = RNA_enum_get(op->ptr, "action");
1820 
1821  if (action == SEL_TOGGLE) {
1822  action = SEL_SELECT;
1825  action = SEL_DESELECT;
1826  break;
1827  }
1828 
1829  if (action == SEL_DESELECT) {
1830  break;
1831  }
1832  }
1833  }
1834 
1835  bool changed = false;
1838  changed |= select_action_apply(point, key, action);
1839  }
1840  }
1841 
1842  if (changed) {
1845  }
1846  return OPERATOR_FINISHED;
1847 }
1848 
1850 {
1851  /* identifiers */
1852  ot->name = "(De)select All";
1853  ot->idname = "PARTICLE_OT_select_all";
1854  ot->description = "(De)select all particles' keys";
1855 
1856  /* api callbacks */
1858  ot->poll = PE_poll;
1859 
1860  /* flags */
1862 
1864 }
1865 
1868 /* -------------------------------------------------------------------- */
1872 bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
1873 {
1874  PEData data;
1877  POINT_P;
1878  KEY_K;
1879 
1881 
1882  PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
1883 
1884  if (!PE_start_edit(edit)) {
1885  return false;
1886  }
1887 
1888  if (!extend && !deselect && !toggle) {
1891  key->flag &= ~PEK_SELECT;
1892  point->flag |= PEP_EDIT_RECALC;
1893  }
1894  }
1895  }
1896 
1897  data.mval = mval;
1899 
1900  /* 1 = nearest only */
1901  if (extend) {
1903  }
1904  else if (deselect) {
1906  }
1907  else {
1909  }
1910 
1911  if (data.is_changed) {
1912  PE_update_selection(data.depsgraph, scene, ob, 1);
1914  }
1915 
1916  return true;
1917 }
1918 
1921 /* -------------------------------------------------------------------- */
1925 static void select_root(PEData *data, int point_index)
1926 {
1927  PTCacheEditPoint *point = data->edit->points + point_index;
1928  PTCacheEditKey *key = point->keys;
1929 
1930  if (point->flag & PEP_HIDE) {
1931  return;
1932  }
1933 
1934  if (data->select_action != SEL_TOGGLE) {
1935  data->is_changed = select_action_apply(point, key, data->select_action);
1936  }
1937  else if (key->flag & PEK_SELECT) {
1938  data->select_toggle_action = SEL_DESELECT;
1939  }
1940 }
1941 
1943 {
1944  PEData data;
1945  int action = RNA_enum_get(op->ptr, "action");
1946 
1947  PE_set_data(C, &data);
1948 
1949  if (action == SEL_TOGGLE) {
1950  data.select_action = SEL_TOGGLE;
1951  data.select_toggle_action = SEL_SELECT;
1952 
1954 
1955  action = data.select_toggle_action;
1956  }
1957 
1958  data.select_action = action;
1960 
1961  if (data.is_changed) {
1962  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
1964  }
1965  return OPERATOR_FINISHED;
1966 }
1967 
1969 {
1970  /* identifiers */
1971  ot->name = "Select Roots";
1972  ot->idname = "PARTICLE_OT_select_roots";
1973  ot->description = "Select roots of all visible particles";
1974 
1975  /* api callbacks */
1977  ot->poll = PE_poll;
1978 
1979  /* flags */
1981 
1982  /* properties */
1984 }
1985 
1988 /* -------------------------------------------------------------------- */
1992 static void select_tip(PEData *data, int point_index)
1993 {
1994  PTCacheEditPoint *point = data->edit->points + point_index;
1995  PTCacheEditKey *key;
1996 
1997  if (point->totkey == 0) {
1998  return;
1999  }
2000 
2001  key = &point->keys[point->totkey - 1];
2002 
2003  if (point->flag & PEP_HIDE) {
2004  return;
2005  }
2006 
2007  if (data->select_action != SEL_TOGGLE) {
2008  data->is_changed = select_action_apply(point, key, data->select_action);
2009  }
2010  else if (key->flag & PEK_SELECT) {
2011  data->select_toggle_action = SEL_DESELECT;
2012  }
2013 }
2014 
2016 {
2017  PEData data;
2018  int action = RNA_enum_get(op->ptr, "action");
2019 
2020  PE_set_data(C, &data);
2021 
2022  if (action == SEL_TOGGLE) {
2023  data.select_action = SEL_TOGGLE;
2024  data.select_toggle_action = SEL_SELECT;
2025 
2027 
2028  action = data.select_toggle_action;
2029  }
2030 
2031  data.select_action = action;
2033 
2034  if (data.is_changed) {
2035  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2037 
2038  return OPERATOR_FINISHED;
2039  }
2040  return OPERATOR_CANCELLED;
2041 }
2042 
2044 {
2045  /* identifiers */
2046  ot->name = "Select Tips";
2047  ot->idname = "PARTICLE_OT_select_tips";
2048  ot->description = "Select tips of all visible particles";
2049 
2050  /* api callbacks */
2052  ot->poll = PE_poll;
2053 
2054  /* flags */
2056 
2057  /* properties */
2059 }
2060 
2063 /* -------------------------------------------------------------------- */
2068 
2070  {RAN_HAIR, "HAIR", 0, "Hair", ""},
2071  {RAN_POINTS, "POINTS", 0, "Points", ""},
2072  {0, NULL, 0, NULL, NULL},
2073 };
2074 
2076 {
2077  PEData data;
2078  int type;
2079 
2080  /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
2081  PTCacheEdit *edit;
2082  PTCacheEditPoint *point;
2083  PTCacheEditKey *key;
2084  int p;
2085  int k;
2086 
2087  const float randfac = RNA_float_get(op->ptr, "ratio");
2089  const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
2090  RNG *rng;
2091 
2092  type = RNA_enum_get(op->ptr, "type");
2093 
2094  PE_set_data(C, &data);
2095  data.select_action = SEL_SELECT;
2096  edit = PE_get_current(data.depsgraph, data.scene, data.ob);
2097 
2098  rng = BLI_rng_new_srandom(seed);
2099 
2100  switch (type) {
2101  case RAN_HAIR:
2103  int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
2104  LOOP_KEYS {
2105  data.is_changed |= select_action_apply(point, key, flag);
2106  }
2107  }
2108  break;
2109  case RAN_POINTS:
2112  int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
2113  data.is_changed |= select_action_apply(point, key, flag);
2114  }
2115  }
2116  break;
2117  }
2118 
2119  BLI_rng_free(rng);
2120 
2121  if (data.is_changed) {
2122  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2124  }
2125  return OPERATOR_FINISHED;
2126 }
2127 
2129 {
2130  /* identifiers */
2131  ot->name = "Select Random";
2132  ot->idname = "PARTICLE_OT_select_random";
2133  ot->description = "Select a randomly distributed set of hair or points";
2134 
2135  /* api callbacks */
2137  ot->poll = PE_poll;
2138 
2139  /* flags */
2141 
2142  /* properties */
2144  ot->prop = RNA_def_enum(ot->srna,
2145  "type",
2147  RAN_HAIR,
2148  "Type",
2149  "Select either hair or points");
2150 }
2151 
2154 /* -------------------------------------------------------------------- */
2159 {
2160  PEData data;
2161  PE_set_data(C, &data);
2162  data.select = true;
2163 
2165 
2166  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2168 
2169  return OPERATOR_FINISHED;
2170 }
2171 
2173 {
2174  /* identifiers */
2175  ot->name = "Select Linked All";
2176  ot->idname = "PARTICLE_OT_select_linked";
2177  ot->description = "Select all keys linked to already selected ones";
2178 
2179  /* api callbacks */
2181  ot->poll = PE_poll;
2182 
2183  /* flags */
2185 
2186  /* properties */
2187 }
2188 
2190 {
2191  PEData data;
2192  int mval[2];
2193  int location[2];
2194 
2195  RNA_int_get_array(op->ptr, "location", location);
2196  mval[0] = location[0];
2197  mval[1] = location[1];
2198 
2200  data.mval = mval;
2201  data.rad = 75.0f;
2202  data.select = !RNA_boolean_get(op->ptr, "deselect");
2203 
2205  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2207 
2208  return OPERATOR_FINISHED;
2209 }
2210 
2211 static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2212 {
2213  RNA_int_set_array(op->ptr, "location", event->mval);
2214  return select_linked_pick_exec(C, op);
2215 }
2216 
2218 {
2219  /* identifiers */
2220  ot->name = "Select Linked";
2221  ot->idname = "PARTICLE_OT_select_linked_pick";
2222  ot->description = "Select nearest particle from mouse pointer";
2223 
2224  /* api callbacks */
2227  ot->poll = PE_poll_view3d;
2228 
2229  /* flags */
2231 
2232  /* properties */
2234  ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
2235  RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
2236 }
2237 
2240 /* -------------------------------------------------------------------- */
2245 {
2246  bool changed = false;
2247  POINT_P;
2248  KEY_K;
2249 
2252  if ((key->flag & PEK_SELECT) != 0) {
2253  key->flag &= ~PEK_SELECT;
2254  point->flag |= PEP_EDIT_RECALC;
2255  changed = true;
2256  }
2257  }
2258  }
2259  return changed;
2260 }
2261 
2263 {
2267  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2268  if (!PE_start_edit(edit)) {
2269  return false;
2270  }
2271  return PE_deselect_all_visible_ex(edit);
2272 }
2273 
2274 bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
2275 {
2279  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2280  PEData data;
2281 
2282  if (!PE_start_edit(edit)) {
2283  return false;
2284  }
2285 
2287  data.rect = rect;
2288  data.sel_op = sel_op;
2289 
2290  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
2291  data.is_changed = PE_deselect_all_visible_ex(edit);
2292  }
2293 
2294  if (BLI_rcti_is_empty(rect)) {
2295  /* pass */
2296  }
2297  else {
2299  }
2300 
2301  if (data.is_changed) {
2302  PE_update_selection(data.depsgraph, scene, ob, 1);
2304  }
2305  return data.is_changed;
2306 }
2307 
2310 /* -------------------------------------------------------------------- */
2314 bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
2315 {
2320  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2321  PEData data;
2322 
2323  if (!PE_start_edit(edit)) {
2324  return false;
2325  }
2326 
2327  const bool select = (sel_op != SEL_OP_SUB);
2328 
2330  data.mval = mval;
2331  data.rad = rad;
2332  data.select = select;
2333 
2334  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
2335  data.is_changed = PE_deselect_all_visible_ex(edit);
2336  }
2338  if (data.is_changed) {
2339  PE_update_selection(data.depsgraph, scene, ob, 1);
2341  }
2342  return data.is_changed;
2343 }
2344 
2347 /* -------------------------------------------------------------------- */
2351 int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op)
2352 {
2356  ARegion *region = CTX_wm_region(C);
2358  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2359  POINT_P;
2360  KEY_K;
2361  float co[3], mat[4][4];
2362  int screen_co[2];
2363 
2364  PEData data;
2365 
2366  unit_m4(mat);
2367 
2368  if (!PE_start_edit(edit)) {
2369  return OPERATOR_CANCELLED;
2370  }
2371 
2372  /* only for depths */
2374 
2375  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
2376  data.is_changed |= PE_deselect_all_visible_ex(edit);
2377  }
2378 
2379  ParticleSystem *psys = edit->psys;
2380  ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
2382  if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
2384  ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
2385  }
2386 
2387  if (pset->selectmode == SCE_SELECT_POINT) {
2389  copy_v3_v3(co, key->co);
2390  mul_m4_v3(mat, co);
2391  const bool is_select = key->flag & PEK_SELECT;
2392  const bool is_inside =
2393  ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
2394  V3D_PROJ_RET_OK) &&
2396  mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
2397  key_test_depth(&data, co, screen_co));
2398  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
2399  if (sel_op_result != -1) {
2400  SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
2401  point->flag |= PEP_EDIT_RECALC;
2402  data.is_changed = true;
2403  }
2404  }
2405  }
2406  else if (pset->selectmode == SCE_SELECT_END) {
2407  if (point->totkey) {
2408  key = point->keys + point->totkey - 1;
2409  copy_v3_v3(co, key->co);
2410  mul_m4_v3(mat, co);
2411  const bool is_select = key->flag & PEK_SELECT;
2412  const bool is_inside =
2413  ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
2414  V3D_PROJ_RET_OK) &&
2416  mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
2417  key_test_depth(&data, co, screen_co));
2418  const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
2419  if (sel_op_result != -1) {
2420  SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
2421  point->flag |= PEP_EDIT_RECALC;
2422  data.is_changed = true;
2423  }
2424  }
2425  }
2426  }
2427 
2428  if (data.is_changed) {
2429  PE_update_selection(data.depsgraph, scene, ob, 1);
2431  return OPERATOR_FINISHED;
2432  }
2433  return OPERATOR_CANCELLED;
2434 }
2435 
2438 /* -------------------------------------------------------------------- */
2442 static int hide_exec(bContext *C, wmOperator *op)
2443 {
2447 
2448  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2449  POINT_P;
2450  KEY_K;
2451 
2452  if (RNA_boolean_get(op->ptr, "unselected")) {
2454  point->flag |= PEP_HIDE;
2455  point->flag |= PEP_EDIT_RECALC;
2456 
2457  LOOP_KEYS {
2458  key->flag &= ~PEK_SELECT;
2459  }
2460  }
2461  }
2462  else {
2464  point->flag |= PEP_HIDE;
2465  point->flag |= PEP_EDIT_RECALC;
2466 
2467  LOOP_KEYS {
2468  key->flag &= ~PEK_SELECT;
2469  }
2470  }
2471  }
2472 
2475 
2476  return OPERATOR_FINISHED;
2477 }
2478 
2480 {
2481  /* identifiers */
2482  ot->name = "Hide Selected";
2483  ot->idname = "PARTICLE_OT_hide";
2484  ot->description = "Hide selected particles";
2485 
2486  /* api callbacks */
2487  ot->exec = hide_exec;
2488  ot->poll = PE_poll;
2489 
2490  /* flags */
2492 
2493  /* props */
2494  RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
2495 }
2496 
2499 /* -------------------------------------------------------------------- */
2504 {
2508  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2509  const bool select = RNA_boolean_get(op->ptr, "select");
2510  POINT_P;
2511  KEY_K;
2512 
2513  LOOP_POINTS {
2514  if (point->flag & PEP_HIDE) {
2515  point->flag &= ~PEP_HIDE;
2516  point->flag |= PEP_EDIT_RECALC;
2517 
2518  LOOP_KEYS {
2519  SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
2520  }
2521  }
2522  }
2523 
2526 
2527  return OPERATOR_FINISHED;
2528 }
2529 
2531 {
2532  /* identifiers */
2533  ot->name = "Reveal";
2534  ot->idname = "PARTICLE_OT_reveal";
2535  ot->description = "Show hidden particles";
2536 
2537  /* api callbacks */
2538  ot->exec = reveal_exec;
2539  ot->poll = PE_poll;
2540 
2541  /* flags */
2543 
2544  /* props */
2545  RNA_def_boolean(ot->srna, "select", true, "Select", "");
2546 }
2547 
2550 /* -------------------------------------------------------------------- */
2554 static void select_less_keys(PEData *data, int point_index)
2555 {
2556  PTCacheEdit *edit = data->edit;
2557  PTCacheEditPoint *point = edit->points + point_index;
2558  KEY_K;
2559 
2561  if (k == 0) {
2562  if (((key + 1)->flag & PEK_SELECT) == 0) {
2563  key->flag |= PEK_TAG;
2564  }
2565  }
2566  else if (k == point->totkey - 1) {
2567  if (((key - 1)->flag & PEK_SELECT) == 0) {
2568  key->flag |= PEK_TAG;
2569  }
2570  }
2571  else {
2572  if ((((key - 1)->flag & (key + 1)->flag) & PEK_SELECT) == 0) {
2573  key->flag |= PEK_TAG;
2574  }
2575  }
2576  }
2577 
2578  LOOP_KEYS {
2579  if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
2580  key->flag &= ~(PEK_TAG | PEK_SELECT);
2581  point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2582  data->is_changed = true;
2583  }
2584  }
2585 }
2586 
2588 {
2589  PEData data;
2590 
2591  PE_set_data(C, &data);
2593 
2594  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2596 
2597  return OPERATOR_FINISHED;
2598 }
2599 
2601 {
2602  /* identifiers */
2603  ot->name = "Select Less";
2604  ot->idname = "PARTICLE_OT_select_less";
2605  ot->description = "Deselect boundary selected keys of each particle";
2606 
2607  /* api callbacks */
2609  ot->poll = PE_poll;
2610 
2611  /* flags */
2613 }
2614 
2617 /* -------------------------------------------------------------------- */
2621 static void select_more_keys(PEData *data, int point_index)
2622 {
2623  PTCacheEdit *edit = data->edit;
2624  PTCacheEditPoint *point = edit->points + point_index;
2625  KEY_K;
2626 
2627  LOOP_KEYS {
2628  if (key->flag & PEK_SELECT) {
2629  continue;
2630  }
2631 
2632  if (k == 0) {
2633  if ((key + 1)->flag & PEK_SELECT) {
2634  key->flag |= PEK_TAG;
2635  }
2636  }
2637  else if (k == point->totkey - 1) {
2638  if ((key - 1)->flag & PEK_SELECT) {
2639  key->flag |= PEK_TAG;
2640  }
2641  }
2642  else {
2643  if (((key - 1)->flag | (key + 1)->flag) & PEK_SELECT) {
2644  key->flag |= PEK_TAG;
2645  }
2646  }
2647  }
2648 
2649  LOOP_KEYS {
2650  if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
2651  key->flag &= ~PEK_TAG;
2652  key->flag |= PEK_SELECT;
2653  point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2654  data->is_changed = true;
2655  }
2656  }
2657 }
2658 
2660 {
2661  PEData data;
2662 
2663  PE_set_data(C, &data);
2665 
2666  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
2668 
2669  return OPERATOR_FINISHED;
2670 }
2671 
2673 {
2674  /* identifiers */
2675  ot->name = "Select More";
2676  ot->idname = "PARTICLE_OT_select_more";
2677  ot->description = "Select keys linked to boundary selected keys of each particle";
2678 
2679  /* api callbacks */
2681  ot->poll = PE_poll;
2682 
2683  /* flags */
2685 }
2686 
2689 /* -------------------------------------------------------------------- */
2693 static void rekey_particle(PEData *data, int pa_index)
2694 {
2695  PTCacheEdit *edit = data->edit;
2696  ParticleSystem *psys = edit->psys;
2697  ParticleSimulationData sim = {0};
2698  ParticleData *pa = psys->particles + pa_index;
2699  PTCacheEditPoint *point = edit->points + pa_index;
2701  HairKey *key, *new_keys, *okey;
2702  PTCacheEditKey *ekey;
2703  float dval, sta, end;
2704  int k;
2705 
2706  sim.depsgraph = data->depsgraph;
2707  sim.scene = data->scene;
2708  sim.ob = data->ob;
2709  sim.psys = edit->psys;
2710 
2711  pa->flag |= PARS_REKEY;
2712 
2713  key = new_keys = MEM_callocN(data->totrekey * sizeof(HairKey), "Hair re-key keys");
2714 
2715  okey = pa->hair;
2716  /* root and tip stay the same */
2717  copy_v3_v3(key->co, okey->co);
2718  copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
2719 
2720  sta = key->time = okey->time;
2721  end = (key + data->totrekey - 1)->time = (okey + pa->totkey - 1)->time;
2722  dval = (end - sta) / (float)(data->totrekey - 1);
2723 
2724  /* interpolate new keys from old ones */
2725  for (k = 1, key++; k < data->totrekey - 1; k++, key++) {
2726  state.time = (float)k / (float)(data->totrekey - 1);
2727  psys_get_particle_on_path(&sim, pa_index, &state, 0);
2728  copy_v3_v3(key->co, state.co);
2729  key->time = sta + k * dval;
2730  }
2731 
2732  /* replace keys */
2733  if (pa->hair) {
2734  MEM_freeN(pa->hair);
2735  }
2736  pa->hair = new_keys;
2737 
2738  point->totkey = pa->totkey = data->totrekey;
2739 
2740  if (point->keys) {
2741  MEM_freeN(point->keys);
2742  }
2743  ekey = point->keys = MEM_callocN(pa->totkey * sizeof(PTCacheEditKey), "Hair re-key edit keys");
2744 
2745  for (k = 0, key = pa->hair; k < pa->totkey; k++, key++, ekey++) {
2746  ekey->co = key->co;
2747  ekey->time = &key->time;
2748  ekey->flag |= PEK_SELECT;
2749  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
2750  ekey->flag |= PEK_USE_WCO;
2751  }
2752  }
2753 
2754  pa->flag &= ~PARS_REKEY;
2755  point->flag |= PEP_EDIT_RECALC;
2756 }
2757 
2758 static int rekey_exec(bContext *C, wmOperator *op)
2759 {
2760  PEData data;
2761 
2762  PE_set_data(C, &data);
2763 
2764  data.dval = 1.0f / (float)(data.totrekey - 1);
2765  data.totrekey = RNA_int_get(op->ptr, "keys_number");
2766 
2768 
2769  recalc_lengths(data.edit);
2770  PE_update_object(data.depsgraph, data.scene, data.ob, 1);
2772 
2773  return OPERATOR_FINISHED;
2774 }
2775 
2777 {
2778  /* identifiers */
2779  ot->name = "Rekey";
2780  ot->idname = "PARTICLE_OT_rekey";
2781  ot->description = "Change the number of keys of selected particles (root and tip keys included)";
2782 
2783  /* api callbacks */
2784  ot->exec = rekey_exec;
2786  ot->poll = PE_hair_poll;
2787 
2788  /* flags */
2790 
2791  /* properties */
2792  RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
2793 }
2794 
2796  const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
2797 {
2799  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
2800  ParticleSystem *psys;
2801  ParticleSimulationData sim = {0};
2802  ParticleData *pa;
2804  HairKey *new_keys, *key;
2805  PTCacheEditKey *ekey;
2806  int k;
2807 
2808  if (!edit || !edit->psys) {
2809  return;
2810  }
2811 
2812  psys = edit->psys;
2813 
2814  sim.depsgraph = depsgraph;
2815  sim.scene = scene;
2816  sim.ob = ob;
2817  sim.psys = psys;
2818 
2819  pa = psys->particles + pa_index;
2820 
2821  pa->flag |= PARS_REKEY;
2822 
2823  key = new_keys = MEM_dupallocN(pa->hair);
2824 
2825  /* interpolate new keys from old ones (roots stay the same) */
2826  for (k = 1, key++; k < pa->totkey; k++, key++) {
2827  state.time = path_time * (float)k / (float)(pa->totkey - 1);
2828  psys_get_particle_on_path(&sim, pa_index, &state, 0);
2829  copy_v3_v3(key->co, state.co);
2830  }
2831 
2832  /* replace hair keys */
2833  if (pa->hair) {
2834  MEM_freeN(pa->hair);
2835  }
2836  pa->hair = new_keys;
2837 
2838  /* update edit pointers */
2839  for (k = 0, key = pa->hair, ekey = edit->points[pa_index].keys; k < pa->totkey;
2840  k++, key++, ekey++) {
2841  ekey->co = key->co;
2842  ekey->time = &key->time;
2843  }
2844 
2845  pa->flag &= ~PARS_REKEY;
2846 }
2847 
2850 /* -------------------------------------------------------------------- */
2854 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
2855 {
2856  PTCacheEdit *edit = psys->edit;
2857  ParticleData *pa, *npa = 0, *new_pars = 0;
2858  POINT_P;
2859  PTCacheEditPoint *npoint = 0, *new_points = 0;
2860  ParticleSystemModifierData *psmd_eval;
2861  int i, new_totpart = psys->totpart, removed = 0;
2862 
2863  if (mirror) {
2864  /* mirror tags */
2865  psmd_eval = edit->psmd_eval;
2866 
2868  PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
2869  }
2870  }
2871 
2873  new_totpart--;
2874  removed++;
2875  }
2876 
2877  if (new_totpart != psys->totpart) {
2878  if (new_totpart) {
2879  npa = new_pars = MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2880  npoint = new_points = MEM_callocN(new_totpart * sizeof(PTCacheEditPoint),
2881  "PTCacheEditKey array");
2882 
2883  if (ELEM(NULL, new_pars, new_points)) {
2884  /* allocation error! */
2885  if (new_pars) {
2886  MEM_freeN(new_pars);
2887  }
2888  if (new_points) {
2889  MEM_freeN(new_points);
2890  }
2891  return 0;
2892  }
2893  }
2894 
2895  pa = psys->particles;
2896  point = edit->points;
2897  for (i = 0; i < psys->totpart; i++, pa++, point++) {
2898  if (point->flag & PEP_TAG) {
2899  if (point->keys) {
2900  MEM_freeN(point->keys);
2901  }
2902  if (pa->hair) {
2903  MEM_freeN(pa->hair);
2904  }
2905  }
2906  else {
2907  memcpy(npa, pa, sizeof(ParticleData));
2908  memcpy(npoint, point, sizeof(PTCacheEditPoint));
2909  npa++;
2910  npoint++;
2911  }
2912  }
2913 
2914  if (psys->particles) {
2915  MEM_freeN(psys->particles);
2916  }
2917  psys->particles = new_pars;
2918 
2919  if (edit->points) {
2920  MEM_freeN(edit->points);
2921  }
2922  edit->points = new_points;
2923 
2924  if (edit->mirror_cache) {
2925  MEM_freeN(edit->mirror_cache);
2926  edit->mirror_cache = NULL;
2927  }
2928 
2929  if (psys->child) {
2930  MEM_freeN(psys->child);
2931  psys->child = NULL;
2932  psys->totchild = 0;
2933  }
2934 
2935  edit->totpoint = psys->totpart = new_totpart;
2936  }
2937 
2938  return removed;
2939 }
2940 
2942 {
2943  PTCacheEdit *edit = psys->edit;
2944  ParticleData *pa;
2945  HairKey *hkey, *nhkey, *new_hkeys = 0;
2946  POINT_P;
2947  KEY_K;
2948  PTCacheEditKey *nkey, *new_keys;
2949  short new_totkey;
2950 
2951  if (pe_x_mirror(ob)) {
2952  /* mirror key tags */
2956 
2957  LOOP_POINTS {
2959  PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
2960  break;
2961  }
2962  }
2963  }
2964 
2965  LOOP_POINTS {
2966  new_totkey = point->totkey;
2968  new_totkey--;
2969  }
2970  /* we can't have elements with less than two keys*/
2971  if (new_totkey < 2) {
2972  point->flag |= PEP_TAG;
2973  }
2974  }
2975  remove_tagged_particles(ob, psys, pe_x_mirror(ob));
2976 
2977  LOOP_POINTS {
2978  pa = psys->particles + p;
2979  new_totkey = pa->totkey;
2980 
2982  new_totkey--;
2983  }
2984 
2985  if (new_totkey != pa->totkey) {
2986  nhkey = new_hkeys = MEM_callocN(new_totkey * sizeof(HairKey), "HairKeys");
2987  nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
2988 
2989  hkey = pa->hair;
2990  LOOP_KEYS {
2991  while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2992  key++;
2993  hkey++;
2994  }
2995 
2996  if (hkey < pa->hair + pa->totkey) {
2997  copy_v3_v3(nhkey->co, hkey->co);
2998  nhkey->editflag = hkey->editflag;
2999  nhkey->time = hkey->time;
3000  nhkey->weight = hkey->weight;
3001 
3002  nkey->co = nhkey->co;
3003  nkey->time = &nhkey->time;
3004  /* these can be copied from old edit keys */
3005  nkey->flag = key->flag;
3006  nkey->ftime = key->ftime;
3007  nkey->length = key->length;
3008  copy_v3_v3(nkey->world_co, key->world_co);
3009  }
3010  nkey++;
3011  nhkey++;
3012  hkey++;
3013  }
3014 
3015  if (pa->hair) {
3016  MEM_freeN(pa->hair);
3017  }
3018 
3019  if (point->keys) {
3020  MEM_freeN(point->keys);
3021  }
3022 
3023  pa->hair = new_hkeys;
3024  point->keys = new_keys;
3025 
3026  point->totkey = pa->totkey = new_totkey;
3027 
3028  /* flag for recalculating length */
3029  point->flag |= PEP_EDIT_RECALC;
3030  }
3031  }
3032 }
3033 
3036 /* -------------------------------------------------------------------- */
3040 /* works like normal edit mode subdivide, inserts keys between neighboring selected keys */
3041 static void subdivide_particle(PEData *data, int pa_index)
3042 {
3043  PTCacheEdit *edit = data->edit;
3044  ParticleSystem *psys = edit->psys;
3045  ParticleSimulationData sim = {0};
3046  ParticleData *pa = psys->particles + pa_index;
3047  PTCacheEditPoint *point = edit->points + pa_index;
3049  HairKey *key, *nkey, *new_keys;
3050  PTCacheEditKey *ekey, *nekey, *new_ekeys;
3051 
3052  int k;
3053  short totnewkey = 0;
3054  float endtime;
3055 
3056  sim.depsgraph = data->depsgraph;
3057  sim.scene = data->scene;
3058  sim.ob = data->ob;
3059  sim.psys = edit->psys;
3060 
3061  for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, ekey++) {
3062  if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT) {
3063  totnewkey++;
3064  }
3065  }
3066 
3067  if (totnewkey == 0) {
3068  return;
3069  }
3070 
3071  pa->flag |= PARS_REKEY;
3072 
3073  nkey = new_keys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(HairKey)),
3074  "Hair subdivide keys");
3075  nekey = new_ekeys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(PTCacheEditKey)),
3076  "Hair subdivide edit keys");
3077 
3078  key = pa->hair;
3079  endtime = key[pa->totkey - 1].time;
3080 
3081  for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, key++, ekey++) {
3082 
3083  memcpy(nkey, key, sizeof(HairKey));
3084  memcpy(nekey, ekey, sizeof(PTCacheEditKey));
3085 
3086  nekey->co = nkey->co;
3087  nekey->time = &nkey->time;
3088 
3089  nkey++;
3090  nekey++;
3091 
3092  if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT) {
3093  nkey->time = (key->time + (key + 1)->time) * 0.5f;
3094  state.time = (endtime != 0.0f) ? nkey->time / endtime : 0.0f;
3095  psys_get_particle_on_path(&sim, pa_index, &state, 0);
3096  copy_v3_v3(nkey->co, state.co);
3097 
3098  nekey->co = nkey->co;
3099  nekey->time = &nkey->time;
3100  nekey->flag |= PEK_SELECT;
3101  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
3102  nekey->flag |= PEK_USE_WCO;
3103  }
3104 
3105  nekey++;
3106  nkey++;
3107  }
3108  }
3109  /*tip still not copied*/
3110  memcpy(nkey, key, sizeof(HairKey));
3111  memcpy(nekey, ekey, sizeof(PTCacheEditKey));
3112 
3113  nekey->co = nkey->co;
3114  nekey->time = &nkey->time;
3115 
3116  if (pa->hair) {
3117  MEM_freeN(pa->hair);
3118  }
3119  pa->hair = new_keys;
3120 
3121  if (point->keys) {
3122  MEM_freeN(point->keys);
3123  }
3124  point->keys = new_ekeys;
3125 
3126  point->totkey = pa->totkey = pa->totkey + totnewkey;
3127  point->flag |= PEP_EDIT_RECALC;
3128  pa->flag &= ~PARS_REKEY;
3129 }
3130 
3132 {
3133  PEData data;
3134 
3135  PE_set_data(C, &data);
3137 
3138  recalc_lengths(data.edit);
3139  PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
3140  PE_update_object(data.depsgraph, data.scene, data.ob, 1);
3143 
3144  return OPERATOR_FINISHED;
3145 }
3146 
3148 {
3149  /* identifiers */
3150  ot->name = "Subdivide";
3151  ot->idname = "PARTICLE_OT_subdivide";
3152  ot->description = "Subdivide selected particles segments (adds keys)";
3153 
3154  /* api callbacks */
3155  ot->exec = subdivide_exec;
3156  ot->poll = PE_hair_poll;
3157 
3158  /* flags */
3160 }
3161 
3164 /* -------------------------------------------------------------------- */
3169 {
3173  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
3174  ParticleSystem *psys = edit->psys;
3175  ParticleSystemModifierData *psmd_eval;
3176  KDTree_3d *tree;
3177  KDTreeNearest_3d nearest[10];
3178  POINT_P;
3179  float mat[4][4], co[3], threshold = RNA_float_get(op->ptr, "threshold");
3180  int n, totn, removed, totremoved;
3181 
3182  if (psys->flag & PSYS_GLOBAL_HAIR) {
3183  return OPERATOR_CANCELLED;
3184  }
3185 
3186  edit = psys->edit;
3187  psmd_eval = edit->psmd_eval;
3188  totremoved = 0;
3189 
3190  do {
3191  removed = 0;
3192 
3193  tree = BLI_kdtree_3d_new(psys->totpart);
3194 
3195  /* insert particles into kd tree */
3198  ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
3199  copy_v3_v3(co, point->keys->co);
3200  mul_m4_v3(mat, co);
3201  BLI_kdtree_3d_insert(tree, p, co);
3202  }
3203 
3204  BLI_kdtree_3d_balance(tree);
3205 
3206  /* tag particles to be removed */
3209  ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
3210  copy_v3_v3(co, point->keys->co);
3211  mul_m4_v3(mat, co);
3212 
3213  totn = BLI_kdtree_3d_find_nearest_n(tree, co, nearest, 10);
3214 
3215  for (n = 0; n < totn; n++) {
3216  /* this needs a custom threshold still */
3217  if (nearest[n].index > p && nearest[n].dist < threshold) {
3218  if (!(point->flag & PEP_TAG)) {
3219  point->flag |= PEP_TAG;
3220  removed++;
3221  }
3222  }
3223  }
3224  }
3225 
3226  BLI_kdtree_3d_free(tree);
3227 
3228  /* remove tagged particles - don't do mirror here! */
3229  remove_tagged_particles(ob, psys, 0);
3230  totremoved += removed;
3231  } while (removed);
3232 
3233  if (totremoved == 0) {
3234  return OPERATOR_CANCELLED;
3235  }
3236 
3237  BKE_reportf(op->reports, RPT_INFO, "Removed %d double particle(s)", totremoved);
3238 
3241 
3242  return OPERATOR_FINISHED;
3243 }
3244 
3246 {
3247  /* identifiers */
3248  ot->name = "Remove Doubles";
3249  ot->idname = "PARTICLE_OT_remove_doubles";
3250  ot->description = "Remove selected particles close enough of others";
3251 
3252  /* api callbacks */
3254  ot->poll = PE_hair_poll;
3255 
3256  /* flags */
3258 
3259  /* properties */
3261  "threshold",
3262  0.0002f,
3263  0.0f,
3264  FLT_MAX,
3265  "Merge Distance",
3266  "Threshold distance within which particles are removed",
3267  0.00001f,
3268  0.1f);
3269 }
3270 
3272 {
3277  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
3278  ParticleSystem *psys = edit->psys;
3279  POINT_P;
3280  KEY_K;
3281  HairKey *hkey;
3282  float weight;
3283  ParticleBrushData *brush = &pset->brush[pset->brushtype];
3284  float factor = RNA_float_get(op->ptr, "factor");
3285 
3286  weight = brush->strength;
3287  edit = psys->edit;
3288 
3290  ParticleData *pa = psys->particles + p;
3291 
3293  hkey = pa->hair + k;
3294  hkey->weight = interpf(weight, hkey->weight, factor);
3295  }
3296  }
3297 
3300 
3301  return OPERATOR_FINISHED;
3302 }
3303 
3305 {
3306  /* identifiers */
3307  ot->name = "Weight Set";
3308  ot->idname = "PARTICLE_OT_weight_set";
3309  ot->description = "Set the weight of selected keys";
3310 
3311  /* api callbacks */
3312  ot->exec = weight_set_exec;
3313  ot->poll = PE_hair_poll;
3314 
3315  /* flags */
3317 
3319  "factor",
3320  1,
3321  0,
3322  1,
3323  "Factor",
3324  "Interpolation factor between current brush weight, and keys' weights",
3325  0,
3326  1);
3327 }
3328 
3331 /* -------------------------------------------------------------------- */
3335 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
3336 {
3339  ParticleBrushData *brush;
3340 
3342  return;
3343  }
3344 
3345  brush = &pset->brush[pset->brushtype];
3346 
3347  if (brush) {
3350 
3351  immUniformColor4ub(255, 255, 255, 128);
3352 
3353  GPU_line_smooth(true);
3355 
3356  imm_draw_circle_wire_2d(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
3357 
3359  GPU_line_smooth(false);
3360 
3361  immUnbindProgram();
3362  }
3363 }
3364 
3365 static void toggle_particle_cursor(Scene *scene, bool enable)
3366 {
3368 
3369  if (pset->paintcursor && !enable) {
3371  pset->paintcursor = NULL;
3372  }
3373  else if (enable) {
3376  }
3377 }
3378 
3381 /* -------------------------------------------------------------------- */
3386 
3388  {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
3389  {DEL_KEY, "KEY", 0, "Key", ""},
3390  {0, NULL, 0, NULL, NULL},
3391 };
3392 
3393 static void set_delete_particle(PEData *data, int pa_index)
3394 {
3395  PTCacheEdit *edit = data->edit;
3396 
3397  edit->points[pa_index].flag |= PEP_TAG;
3398 }
3399 
3401  int pa_index,
3402  int key_index,
3403  bool UNUSED(is_inside))
3404 {
3405  PTCacheEdit *edit = data->edit;
3406 
3407  edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
3408 }
3409 
3411 {
3412  PEData data;
3413  int type = RNA_enum_get(op->ptr, "type");
3414 
3415  PE_set_data(C, &data);
3416 
3417  if (type == DEL_KEY) {
3419  remove_tagged_keys(data.depsgraph, data.ob, data.edit->psys);
3420  recalc_lengths(data.edit);
3421  }
3422  else if (type == DEL_PARTICLE) {
3424  remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
3425  recalc_lengths(data.edit);
3426  }
3427 
3431 
3432  return OPERATOR_FINISHED;
3433 }
3434 
3436 {
3437  /* identifiers */
3438  ot->name = "Delete";
3439  ot->idname = "PARTICLE_OT_delete";
3440  ot->description = "Delete selected particles or keys";
3441 
3442  /* api callbacks */
3443  ot->exec = delete_exec;
3445  ot->poll = PE_hair_poll;
3446 
3447  /* flags */
3449 
3450  /* properties */
3451  ot->prop = RNA_def_enum(ot->srna,
3452  "type",
3454  DEL_PARTICLE,
3455  "Type",
3456  "Delete a full particle or only keys");
3457 }
3458 
3461 /* -------------------------------------------------------------------- */
3465 static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
3466 {
3467  Mesh *me = (Mesh *)(ob->data);
3468  ParticleSystemModifierData *psmd_eval;
3469  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
3470  ParticleSystem *psys = edit->psys;
3471  ParticleData *pa, *newpa, *new_pars;
3472  PTCacheEditPoint *newpoint, *new_points;
3473  POINT_P;
3474  KEY_K;
3475  HairKey *hkey;
3476  int *mirrorfaces = NULL;
3477  int rotation, totpart, newtotpart;
3478 
3479  if (psys->flag & PSYS_GLOBAL_HAIR) {
3480  return;
3481  }
3482 
3483  psmd_eval = edit->psmd_eval;
3484  if (!psmd_eval->mesh_final) {
3485  return;
3486  }
3487 
3488  const bool use_dm_final_indices = (psys->part->use_modifier_stack &&
3489  !psmd_eval->mesh_final->runtime.deformed_only);
3490 
3491  /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
3493 
3494  /* NOTE: In case psys uses Mesh tessface indices, we mirror final Mesh itself, not orig mesh.
3495  * Avoids an (impossible) mesh -> orig -> mesh tessface indices conversion. */
3496  mirrorfaces = mesh_get_x_mirror_faces(
3497  ob, NULL, use_dm_final_indices ? psmd_eval->mesh_final : NULL);
3498 
3499  if (!edit->mirror_cache) {
3500  PE_update_mirror_cache(ob, psys);
3501  }
3502 
3503  totpart = psys->totpart;
3504  newtotpart = psys->totpart;
3506  pa = psys->particles + p;
3507 
3508  if (!tagged) {
3509  if (point_is_selected(point)) {
3510  if (edit->mirror_cache[p] != -1) {
3511  /* already has a mirror, don't need to duplicate */
3512  PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, NULL);
3513  continue;
3514  }
3515  point->flag |= PEP_TAG;
3516  }
3517  }
3518 
3519  if ((point->flag & PEP_TAG) && mirrorfaces[pa->num * 2] != -1) {
3520  newtotpart++;
3521  }
3522  }
3523 
3524  if (newtotpart != psys->totpart) {
3525  MFace *mtessface = use_dm_final_indices ? psmd_eval->mesh_final->mface : me->mface;
3526 
3527  /* allocate new arrays and copy existing */
3528  new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
3529  new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
3530 
3531  if (psys->particles) {
3532  memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
3533  MEM_freeN(psys->particles);
3534  }
3535  psys->particles = new_pars;
3536 
3537  if (edit->points) {
3538  memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
3539  MEM_freeN(edit->points);
3540  }
3541  edit->points = new_points;
3542 
3543  if (edit->mirror_cache) {
3544  MEM_freeN(edit->mirror_cache);
3545  edit->mirror_cache = NULL;
3546  }
3547 
3548  edit->totpoint = psys->totpart = newtotpart;
3549 
3550  /* create new elements */
3551  newpa = psys->particles + totpart;
3552  newpoint = edit->points + totpart;
3553 
3554  for (p = 0, point = edit->points; p < totpart; p++, point++) {
3555  pa = psys->particles + p;
3556  const int pa_num = pa->num;
3557 
3558  if (point->flag & PEP_HIDE) {
3559  continue;
3560  }
3561 
3562  if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1) {
3563  continue;
3564  }
3565 
3566  /* duplicate */
3567  *newpa = *pa;
3568  *newpoint = *point;
3569  if (pa->hair) {
3570  newpa->hair = MEM_dupallocN(pa->hair);
3571  }
3572  if (point->keys) {
3573  newpoint->keys = MEM_dupallocN(point->keys);
3574  }
3575 
3576  /* rotate weights according to vertex index rotation */
3577  rotation = mirrorfaces[pa_num * 2 + 1];
3578  newpa->fuv[0] = pa->fuv[2];
3579  newpa->fuv[1] = pa->fuv[1];
3580  newpa->fuv[2] = pa->fuv[0];
3581  newpa->fuv[3] = pa->fuv[3];
3582  while (rotation--) {
3583  if (mtessface[pa_num].v4) {
3584  SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
3585  }
3586  else {
3587  SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
3588  }
3589  }
3590 
3591  /* assign face index */
3592  /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror,
3593  * same as DMCACHE_NOTFOUND. */
3594  newpa->num = mirrorfaces[pa_num * 2];
3595 
3596  if (use_dm_final_indices) {
3597  newpa->num_dmcache = DMCACHE_ISCHILD;
3598  }
3599  else {
3601  psmd_eval->mesh_final, psmd_eval->mesh_original, newpa->num, newpa->fuv, NULL);
3602  }
3603 
3604  /* update edit key pointers */
3605  key = newpoint->keys;
3606  for (k = 0, hkey = newpa->hair; k < newpa->totkey; k++, hkey++, key++) {
3607  key->co = hkey->co;
3608  key->time = &hkey->time;
3609  }
3610 
3611  /* map key positions as mirror over x axis */
3612  PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, newpa);
3613 
3614  newpa++;
3615  newpoint++;
3616  }
3617  }
3618 
3619  LOOP_POINTS {
3620  point->flag &= ~PEP_TAG;
3621  }
3622 
3623  MEM_freeN(mirrorfaces);
3624 }
3625 
3627 {
3631  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
3632 
3633  PE_mirror_x(depsgraph, scene, ob, 0);
3634 
3635  update_world_cos(ob, edit);
3636  psys_free_path_cache(NULL, edit);
3637 
3641 
3642  return OPERATOR_FINISHED;
3643 }
3644 
3645 static bool mirror_poll(bContext *C)
3646 {
3647  if (!PE_hair_poll(C)) {
3648  return false;
3649  }
3650 
3654  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
3655 
3656  /* The operator only works for hairs emitted from faces. */
3657  return edit->psys->part->from == PART_FROM_FACE;
3658 }
3659 
3661 {
3662  /* identifiers */
3663  ot->name = "Mirror";
3664  ot->idname = "PARTICLE_OT_mirror";
3665  ot->description = "Duplicate and mirror the selected particles along the local X axis";
3666 
3667  /* api callbacks */
3668  ot->exec = mirror_exec;
3669  ot->poll = mirror_poll;
3670 
3671  /* flags */
3673 }
3674 
3677 /* -------------------------------------------------------------------- */
3681 static void brush_comb(PEData *data,
3682  float UNUSED(mat[4][4]),
3683  float imat[4][4],
3684  int point_index,
3685  int key_index,
3686  PTCacheEditKey *key,
3687  float mouse_distance)
3688 {
3689  ParticleEditSettings *pset = PE_settings(data->scene);
3690  float cvec[3], fac;
3691 
3692  if (pset->flag & PE_LOCK_FIRST && key_index == 0) {
3693  return;
3694  }
3695 
3696  fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->combfac);
3697 
3698  copy_v3_v3(cvec, data->dvec);
3699  mul_mat3_m4_v3(imat, cvec);
3700  mul_v3_fl(cvec, fac);
3701  add_v3_v3(key->co, cvec);
3702 
3703  (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3704 }
3705 
3706 static void brush_cut(PEData *data, int pa_index)
3707 {
3708  PTCacheEdit *edit = data->edit;
3709  ARegion *region = data->vc.region;
3710  Object *ob = data->ob;
3711  ParticleEditSettings *pset = PE_settings(data->scene);
3712  ParticleCacheKey *key = edit->pathcache[pa_index];
3713  float rad2, cut_time = 1.0;
3714  float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
3715  int k, cut, keys = (int)pow(2.0, (double)pset->draw_step);
3716  int screen_co[2];
3717 
3718  BLI_assert(data->rng != NULL);
3719  /* blunt scissors */
3720  if (BLI_rng_get_float(data->rng) > data->cutfac) {
3721  return;
3722  }
3723 
3724  /* don't cut hidden */
3725  if (edit->points[pa_index].flag & PEP_HIDE) {
3726  return;
3727  }
3728 
3729  if (ED_view3d_project_int_global(region, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) !=
3730  V3D_PROJ_RET_OK) {
3731  return;
3732  }
3733 
3734  rad2 = data->rad * data->rad;
3735 
3736  cut = 0;
3737 
3738  x0 = (float)screen_co[0];
3739  x1 = (float)screen_co[1];
3740 
3741  o0 = (float)data->mval[0];
3742  o1 = (float)data->mval[1];
3743 
3744  xo0 = x0 - o0;
3745  xo1 = x1 - o1;
3746 
3747  /* check if root is inside circle */
3748  if (xo0 * xo0 + xo1 * xo1 < rad2 && key_test_depth(data, key->co, screen_co)) {
3749  cut_time = -1.0f;
3750  cut = 1;
3751  }
3752  else {
3753  /* calculate path time closest to root that was inside the circle */
3754  for (k = 1, key++; k <= keys; k++, key++) {
3755 
3756  if ((ED_view3d_project_int_global(region, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) !=
3757  V3D_PROJ_RET_OK) ||
3758  key_test_depth(data, key->co, screen_co) == 0) {
3759  x0 = (float)screen_co[0];
3760  x1 = (float)screen_co[1];
3761 
3762  xo0 = x0 - o0;
3763  xo1 = x1 - o1;
3764  continue;
3765  }
3766 
3767  v0 = (float)screen_co[0] - x0;
3768  v1 = (float)screen_co[1] - x1;
3769 
3770  dv = v0 * v0 + v1 * v1;
3771 
3772  d = (v0 * xo1 - v1 * xo0);
3773 
3774  d = dv * rad2 - d * d;
3775 
3776  if (d > 0.0f) {
3777  d = sqrtf(d);
3778 
3779  cut_time = -(v0 * xo0 + v1 * xo1 + d);
3780 
3781  if (cut_time > 0.0f) {
3782  cut_time /= dv;
3783 
3784  if (cut_time < 1.0f) {
3785  cut_time += (float)(k - 1);
3786  cut_time /= (float)keys;
3787  cut = 1;
3788  break;
3789  }
3790  }
3791  }
3792 
3793  x0 = (float)screen_co[0];
3794  x1 = (float)screen_co[1];
3795 
3796  xo0 = x0 - o0;
3797  xo1 = x1 - o1;
3798  }
3799  }
3800 
3801  if (cut) {
3802  if (cut_time < 0.0f) {
3803  edit->points[pa_index].flag |= PEP_TAG;
3804  }
3805  else {
3806  rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
3807  edit->points[pa_index].flag |= PEP_EDIT_RECALC;
3808  }
3809  }
3810 }
3811 
3812 static void brush_length(PEData *data, int point_index, float UNUSED(mouse_distance))
3813 {
3814  PTCacheEdit *edit = data->edit;
3815  PTCacheEditPoint *point = edit->points + point_index;
3816  KEY_K;
3817  float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
3818 
3819  LOOP_KEYS {
3820  if (k == 0) {
3821  copy_v3_v3(pvec, key->co);
3822  }
3823  else {
3824  sub_v3_v3v3(dvec, key->co, pvec);
3825  copy_v3_v3(pvec, key->co);
3826  mul_v3_fl(dvec, data->growfac);
3827  add_v3_v3v3(key->co, (key - 1)->co, dvec);
3828  }
3829  }
3830 
3831  point->flag |= PEP_EDIT_RECALC;
3832 }
3833 
3834 static void brush_puff(PEData *data, int point_index, float mouse_distance)
3835 {
3836  PTCacheEdit *edit = data->edit;
3837  ParticleSystem *psys = edit->psys;
3838  PTCacheEditPoint *point = edit->points + point_index;
3839  KEY_K;
3840  float mat[4][4], imat[4][4];
3841 
3842  float onor_prev[3]; /* previous normal (particle-space) */
3843  float ofs_prev[3]; /* accumulate offset for puff_volume (particle-space) */
3844  float co_root[3], no_root[3]; /* root location and normal (global-space) */
3845  float co_prev[3], co[3]; /* track key coords as we loop (global-space) */
3846  float fac = 0.0f, length_accum = 0.0f;
3847  bool puff_volume = false;
3848  bool changed = false;
3849 
3850  zero_v3(ofs_prev);
3851 
3852  {
3853  ParticleEditSettings *pset = PE_settings(data->scene);
3854  ParticleBrushData *brush = &pset->brush[pset->brushtype];
3855  puff_volume = (brush->flag & PE_BRUSH_DATA_PUFF_VOLUME) != 0;
3856  }
3857 
3858  if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
3860  data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat);
3861  invert_m4_m4(imat, mat);
3862  }
3863  else {
3864  unit_m4(mat);
3865  unit_m4(imat);
3866  }
3867 
3868  LOOP_KEYS {
3869  float kco[3];
3870 
3871  if (k == 0) {
3872  /* find root coordinate and normal on emitter */
3873  copy_v3_v3(co, key->co);
3874  mul_m4_v3(mat, co);
3875 
3876  /* use 'kco' as the object space version of worldspace 'co',
3877  * ob->imat is set before calling */
3878  mul_v3_m4v3(kco, data->ob->imat, co);
3879 
3880  point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
3881  if (point_index == -1) {
3882  return;
3883  }
3884 
3885  copy_v3_v3(co_root, co);
3886  copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]);
3887  mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */
3888  normalize_v3(no_root);
3889 
3890  if (puff_volume) {
3891  copy_v3_v3(onor_prev, no_root);
3892  mul_mat3_m4_v3(imat, onor_prev); /* global-space into particle space */
3893  normalize_v3(onor_prev);
3894  }
3895 
3896  fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->pufffac);
3897  fac *= 0.025f;
3898  if (data->invert) {
3899  fac = -fac;
3900  }
3901  }
3902  else {
3903  /* Compute position as if hair was standing up straight. */
3904  float length;
3905  copy_v3_v3(co_prev, co);
3906  copy_v3_v3(co, key->co);
3907  mul_m4_v3(mat, co);
3908  length = len_v3v3(co_prev, co);
3909  length_accum += length;
3910 
3911  if ((data->select == 0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
3912  float dco[3]; /* delta temp var */
3913 
3914  madd_v3_v3v3fl(kco, co_root, no_root, length_accum);
3915 
3916  /* blend between the current and straight position */
3917  sub_v3_v3v3(dco, kco, co);
3918  madd_v3_v3fl(co, dco, fac);
3919  /* keep the same distance from the root or we get glitches T35406. */
3920  dist_ensure_v3_v3fl(co, co_root, length_accum);
3921 
3922  /* re-use dco to compare before and after translation and add to the offset */
3923  copy_v3_v3(dco, key->co);
3924 
3925  mul_v3_m4v3(key->co, imat, co);
3926 
3927  if (puff_volume) {
3928  /* accumulate the total distance moved to apply to unselected
3929  * keys that come after */
3930  sub_v3_v3v3(ofs_prev, key->co, dco);
3931  }
3932  changed = true;
3933  }
3934  else {
3935 
3936  if (puff_volume) {
3937 #if 0
3938  /* this is simple but looks bad, adds annoying kinks */
3939  add_v3_v3(key->co, ofs);
3940 #else
3941  /* translate (not rotate) the rest of the hair if its not selected */
3942  {
3943 /* NOLINTNEXTLINE: readability-redundant-preprocessor */
3944 # if 0 /* kindof works but looks worse than what's below */
3945 
3946  /* Move the unselected point on a vector based on the
3947  * hair direction and the offset */
3948  float c1[3], c2[3];
3949  sub_v3_v3v3(dco, lastco, co);
3950  mul_mat3_m4_v3(imat, dco); /* into particle space */
3951 
3952  /* move the point along a vector perpendicular to the
3953  * hairs direction, reduces odd kinks, */
3954  cross_v3_v3v3(c1, ofs, dco);
3955  cross_v3_v3v3(c2, c1, dco);
3956  normalize_v3(c2);
3957  mul_v3_fl(c2, len_v3(ofs));
3958  add_v3_v3(key->co, c2);
3959 # else
3960  /* Move the unselected point on a vector based on the
3961  * the normal of the closest geometry */
3962  float oco[3], onor[3];
3963  copy_v3_v3(oco, key->co);
3964  mul_m4_v3(mat, oco);
3965 
3966  /* use 'kco' as the object space version of worldspace 'co',
3967  * ob->imat is set before calling */
3968  mul_v3_m4v3(kco, data->ob->imat, oco);
3969 
3970  point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
3971  if (point_index != -1) {
3972  copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]);
3973  mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
3974  mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
3975  normalize_v3(onor);
3976  }
3977  else {
3978  copy_v3_v3(onor, onor_prev);
3979  }
3980 
3981  if (!is_zero_v3(ofs_prev)) {
3982  mul_v3_fl(onor, len_v3(ofs_prev));
3983 
3984  add_v3_v3(key->co, onor);
3985  }
3986 
3987  copy_v3_v3(onor_prev, onor);
3988 # endif
3989  }
3990 #endif
3991  }
3992  }
3993  }
3994  }
3995 
3996  if (changed) {
3997  point->flag |= PEP_EDIT_RECALC;
3998  }
3999 }
4000 
4002  float UNUSED(mat[4][4]),
4003  float UNUSED(imat[4][4]),
4004  int point_index,
4005  int key_index,
4006  PTCacheEditKey *UNUSED(key),
4007  float UNUSED(mouse_distance))
4008 {
4009  /* roots have full weight always */
4010  if (key_index) {
4011  PTCacheEdit *edit = data->edit;
4012  ParticleSystem *psys = edit->psys;
4013 
4014  ParticleData *pa = psys->particles + point_index;
4015  pa->hair[key_index].weight = data->weightfac;
4016 
4017  (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
4018  }
4019 }
4020 
4022  float mat[4][4],
4023  float UNUSED(imat[4][4]),
4024  int UNUSED(point_index),
4025  int key_index,
4026  PTCacheEditKey *key,
4027  float UNUSED(mouse_distance))
4028 {
4029  if (key_index) {
4030  float dvec[3];
4031 
4032  sub_v3_v3v3(dvec, key->co, (key - 1)->co);
4033  mul_mat3_m4_v3(mat, dvec);
4034  add_v3_v3(data->vec, dvec);
4035  data->tot++;
4036  }
4037 }
4038 
4040  float UNUSED(mat[4][4]),
4041  float imat[4][4],
4042  int point_index,
4043  int key_index,
4044  PTCacheEditKey *key,
4045  float UNUSED(mouse_distance))
4046 {
4047  float vec[3], dvec[3];
4048 
4049  if (key_index) {
4050  copy_v3_v3(vec, data->vec);
4051  mul_mat3_m4_v3(imat, vec);
4052 
4053  sub_v3_v3v3(dvec, key->co, (key - 1)->co);
4054 
4055  sub_v3_v3v3(dvec, vec, dvec);
4056  mul_v3_fl(dvec, data->smoothfac);
4057 
4058  add_v3_v3(key->co, dvec);
4059  }
4060 
4061  (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
4062 }
4063 
4064 /* convert from triangle barycentric weights to quad mean value weights */
4066  const float v1[3], const float v2[3], const float v3[3], const float v4[3], float w[4])
4067 {
4068  float co[3], vert[4][3];
4069 
4070  copy_v3_v3(vert[0], v1);
4071  copy_v3_v3(vert[1], v2);
4072  copy_v3_v3(vert[2], v3);
4073  copy_v3_v3(vert[3], v4);
4074 
4075  co[0] = v1[0] * w[0] + v2[0] * w[1] + v3[0] * w[2] + v4[0] * w[3];
4076  co[1] = v1[1] * w[0] + v2[1] * w[1] + v3[1] * w[2] + v4[1] * w[3];
4077  co[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2] + v4[2] * w[3];
4078 
4079  interp_weights_poly_v3(w, vert, 4, co);
4080 }
4081 
4084  Scene *UNUSED(scene),
4085  Object *ob,
4086  Mesh *mesh,
4087  float *vert_cos,
4088  const float co1[3],
4089  const float co2[3],
4090  float *min_d,
4091  int *min_face,
4092  float *min_w,
4093  float *face_minmax,
4094  float *pa_minmax,
4095  float radius,
4096  float *ipoint)
4097 {
4098  MFace *mface = NULL;
4099  MVert *mvert = NULL;
4100  int i, totface, intersect = 0;
4101  float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3], p_max[3];
4102  float cur_ipoint[3];
4103 
4104  if (mesh == NULL) {
4105  psys_disable_all(ob);
4106 
4107  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
4108  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
4109 
4110  mesh = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
4111  if (mesh == NULL) {
4112  mesh = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
4113  }
4114 
4115  psys_enable_all(ob);
4116 
4117  if (mesh == NULL) {
4118  return 0;
4119  }
4120  }
4121 
4122  /* BMESH_ONLY, deform dm may not have tessface */
4124 
4125  if (pa_minmax == 0) {
4126  INIT_MINMAX(p_min, p_max);
4127  minmax_v3v3_v3(p_min, p_max, co1);
4128  minmax_v3v3_v3(p_min, p_max, co2);
4129  }
4130  else {
4131  copy_v3_v3(p_min, pa_minmax);
4132  copy_v3_v3(p_max, pa_minmax + 3);
4133  }
4134 
4135  totface = mesh->totface;
4136  mface = mesh->mface;
4137  mvert = mesh->mvert;
4138 
4139  /* lets intersect the faces */
4140  for (i = 0; i < totface; i++, mface++) {
4141  if (vert_cos) {
4142  copy_v3_v3(v1, vert_cos + 3 * mface->v1);
4143  copy_v3_v3(v2, vert_cos + 3 * mface->v2);
4144  copy_v3_v3(v3, vert_cos + 3 * mface->v3);
4145  if (mface->v4) {
4146  copy_v3_v3(v4, vert_cos + 3 * mface->v4);
4147  }
4148  }
4149  else {
4150  copy_v3_v3(v1, mvert[mface->v1].co);
4151  copy_v3_v3(v2, mvert[mface->v2].co);
4152  copy_v3_v3(v3, mvert[mface->v3].co);
4153  if (mface->v4) {
4154  copy_v3_v3(v4, mvert[mface->v4].co);
4155  }
4156  }
4157 
4158  if (face_minmax == 0) {
4159  INIT_MINMAX(min, max);
4160  DO_MINMAX(v1, min, max);
4161  DO_MINMAX(v2, min, max);
4162  DO_MINMAX(v3, min, max);
4163  if (mface->v4) {
4164  DO_MINMAX(v4, min, max);
4165  }
4166  if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0) {
4167  continue;
4168  }
4169  }
4170  else {
4171  copy_v3_v3(min, face_minmax + 6 * i);
4172  copy_v3_v3(max, face_minmax + 6 * i + 3);
4173  if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0) {
4174  continue;
4175  }
4176  }
4177 
4178  if (radius > 0.0f) {
4179  if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v2, v3, v1, &cur_d, cur_ipoint)) {
4180  if (cur_d < *min_d) {
4181  *min_d = cur_d;
4182  copy_v3_v3(ipoint, cur_ipoint);
4183  *min_face = i;
4184  intersect = 1;
4185  }
4186  }
4187  if (mface->v4) {
4188  if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v4, v1, v3, &cur_d, cur_ipoint)) {
4189  if (cur_d < *min_d) {
4190  *min_d = cur_d;
4191  copy_v3_v3(ipoint, cur_ipoint);
4192  *min_face = i;
4193  intersect = 1;
4194  }
4195  }
4196  }
4197  }
4198  else {
4199  if (isect_line_segment_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)) {
4200  if (cur_d < *min_d) {
4201  *min_d = cur_d;
4202  min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
4203  min_w[1] = cur_uv[0];
4204  min_w[2] = cur_uv[1];
4205  min_w[3] = 0.0f;
4206  if (mface->v4) {
4207  intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
4208  }
4209  *min_face = i;
4210  intersect = 1;
4211  }
4212  }
4213  if (mface->v4) {
4214  if (isect_line_segment_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)) {
4215  if (cur_d < *min_d) {
4216  *min_d = cur_d;
4217  min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
4218  min_w[1] = 0.0f;
4219  min_w[2] = cur_uv[0];
4220  min_w[3] = cur_uv[1];
4221  intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
4222  *min_face = i;
4223  intersect = 1;
4224  }
4225  }
4226  }
4227  }
4228  }
4229  return intersect;
4230 }
4231 
4232 typedef struct BrushAddCountIterData {
4238  int number;
4239  short size;
4240  float imat[4][4];
4243 
4248 
4249 static void brush_add_count_iter(void *__restrict iter_data_v,
4250  const int iter,
4251  const TaskParallelTLS *__restrict tls_v)
4252 {
4253  BrushAddCountIterData *iter_data = (BrushAddCountIterData *)iter_data_v;
4254  Depsgraph *depsgraph = iter_data->depsgraph;
4255  PEData *data = iter_data->data;
4256  PTCacheEdit *edit = data->edit;
4257  ParticleSystem *psys = edit->psys;
4258  ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
4259  ParticleData *add_pars = iter_data->add_pars;
4260  BrushAddCountIterTLSData *tls = tls_v->userdata_chunk;
4261  const int number = iter_data->number;
4262  const short size = iter_data->size;
4263  const int size2 = size * size;
4264  float dmx, dmy;
4265  if (number > 1) {
4266  dmx = size;
4267  dmy = size;
4268  if (tls->rng == NULL) {
4269  tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] +
4271  }
4272  /* rejection sampling to get points in circle */
4273  while (dmx * dmx + dmy * dmy > size2) {
4274  dmx = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
4275  dmy = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
4276  }
4277  }
4278  else {
4279  dmx = 0.0f;
4280  dmy = 0.0f;
4281  }
4282 
4283  float mco[2];
4284  mco[0] = data->mval[0] + dmx;
4285  mco[1] = data->mval[1] + dmy;
4286 
4287  float co1[3], co2[3];
4288  ED_view3d_win_to_segment_clipped(depsgraph, data->vc.region, data->vc.v3d, mco, co1, co2, true);
4289 
4290  mul_m4_v3(iter_data->imat, co1);
4291  mul_m4_v3(iter_data->imat, co2);
4292  float min_d = 2.0;
4293 
4294  /* warning, returns the derived mesh face */
4295  BLI_assert(iter_data->mesh != NULL);
4297  iter_data->scene,
4298  iter_data->object,
4299  iter_data->mesh,
4300  0,
4301  co1,
4302  co2,
4303  &min_d,
4304  &add_pars[iter].num_dmcache,
4305  add_pars[iter].fuv,
4306  0,
4307  0,
4308  0,
4309  0)) {
4310  if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
4311  add_pars[iter].num = add_pars[iter].num_dmcache;
4312  add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
4313  }
4314  else if (iter_data->mesh == psmd_eval->mesh_original) {
4315  /* Final DM is not same topology as orig mesh,
4316  * we have to map num_dmcache to real final dm. */
4317  add_pars[iter].num = add_pars[iter].num_dmcache;
4318  add_pars[iter].num_dmcache = psys_particle_dm_face_lookup(psmd_eval->mesh_final,
4319  psmd_eval->mesh_original,
4320  add_pars[iter].num,
4321  add_pars[iter].fuv,
4322  NULL);
4323  }
4324  else {
4325  add_pars[iter].num = add_pars[iter].num_dmcache;
4326  }
4327  if (add_pars[iter].num != DMCACHE_NOTFOUND) {
4328  tls->num_added++;
4329  }
4330  }
4331 }
4332 
4333 static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata),
4334  void *__restrict join_v,
4335  void *__restrict chunk_v)
4336 {
4339  join->num_added += tls->num_added;
4340 }
4341 
4342 static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v),
4343  void *__restrict chunk_v)
4344 {
4346  if (tls->rng != NULL) {
4347  BLI_rng_free(tls->rng);
4348  }
4349 }
4350 
4351 static int brush_add(const bContext *C, PEData *data, short number)
4352 {
4354  Scene *scene = data->scene;
4355  Object *ob = data->ob;
4356  Mesh *mesh;
4357  PTCacheEdit *edit = data->edit;
4358  ParticleSystem *psys = edit->psys;
4359  ParticleData *add_pars;
4360  ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
4361  ParticleSimulationData sim = {0};
4363  int i, k, n = 0, totpart = psys->totpart;
4364  float co1[3], imat[4][4];
4365  float framestep, timestep;
4366  short size = pset->brush[PE_BRUSH_ADD].size;
4367  RNG *rng;
4368 
4369  invert_m4_m4(imat, ob->obmat);
4370 
4371  if (psys->flag & PSYS_GLOBAL_HAIR) {
4372  return 0;
4373  }
4374 
4375  add_pars = MEM_callocN(number * sizeof(ParticleData), "ParticleData add");
4376 
4377  rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1]);
4378 
4379  sim.depsgraph = depsgraph;
4380  sim.scene = scene;
4381  sim.ob = ob;
4382  sim.psys = psys;
4383  sim.psmd = psmd_eval;
4384 
4385  timestep = psys_get_timestep(&sim);
4386 
4387  if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
4388  mesh = psmd_eval->mesh_final;
4389  }
4390  else {
4391  mesh = psmd_eval->mesh_original;
4392  }
4393  BLI_assert(mesh);
4394 
4395  /* Calculate positions of new particles to add, based on brush intersection
4396  * with object. New particle data is assigned to a corresponding to check
4397  * index element of add_pars array. This means, that add_pars is a sparse
4398  * array.
4399  */
4400  BrushAddCountIterData iter_data;
4401  iter_data.depsgraph = depsgraph;
4402  iter_data.scene = scene;
4403  iter_data.object = ob;
4404  iter_data.mesh = mesh;
4405  iter_data.data = data;
4406  iter_data.number = number;
4407  iter_data.size = size;
4408  iter_data.add_pars = add_pars;
4409  copy_m4_m4(iter_data.imat, imat);
4410 
4412 
4413  TaskParallelSettings settings;
4415  settings.userdata_chunk = &tls;
4416  settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
4419  BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
4420 
4421  /* Convert add_parse to a dense array, where all new particles are in the
4422  * beginning of the array.
4423  */
4424  n = tls.num_added;
4425  for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
4426  if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
4427  continue;
4428  }
4429  if (new_index != current_iter) {
4430  new_index++;
4431  continue;
4432  }
4433  memcpy(add_pars + new_index, add_pars + current_iter, sizeof(ParticleData));
4434  new_index++;
4435  }
4436 
4437  /* TODO(sergey): Consider multi-threading this part as well. */
4438  if (n) {
4439  int newtotpart = totpart + n;
4440  float hairmat[4][4], cur_co[3];
4441  KDTree_3d *tree = 0;
4442  ParticleData *pa,
4443  *new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
4444  PTCacheEditPoint *point, *new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint),
4445  "PTCacheEditPoint array new");
4446  PTCacheEditKey *key;
4447  HairKey *hkey;
4448 
4449  /* save existing elements */
4450  memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
4451  memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
4452 
4453  /* change old arrays to new ones */
4454  if (psys->particles) {
4455  MEM_freeN(psys->particles);
4456  }
4457  psys->particles = new_pars;
4458 
4459  if (edit->points) {
4460  MEM_freeN(edit->points);
4461  }
4462  edit->points = new_points;
4463 
4464  if (edit->mirror_cache) {
4465  MEM_freeN(edit->mirror_cache);
4466  edit->mirror_cache = NULL;
4467  }
4468 
4469  /* create tree for interpolation */
4470  if (pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
4471  tree = BLI_kdtree_3d_new(psys->totpart);
4472 
4473  for (i = 0, pa = psys->particles; i < totpart; i++, pa++) {
4474  psys_particle_on_dm(psmd_eval->mesh_final,
4475  psys->part->from,
4476  pa->num,
4477  pa->num_dmcache,
4478  pa->fuv,
4479  pa->foffset,
4480  cur_co,
4481  0,
4482  0,
4483  0,
4484  0);
4485  BLI_kdtree_3d_insert(tree, i, cur_co);
4486  }
4487 
4488  BLI_kdtree_3d_balance(tree);
4489  }
4490 
4491  edit->totpoint = psys->totpart = newtotpart;
4492 
4493  /* create new elements */
4494  pa = psys->particles + totpart;
4495  point = edit->points + totpart;
4496 
4497  for (i = totpart; i < newtotpart; i++, pa++, point++) {
4498  memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
4499  pa->hair = MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
4500  key = point->keys = MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey),
4501  "PTCacheEditKey add");
4502  point->totkey = pa->totkey = pset->totaddkey;
4503 
4504  for (k = 0, hkey = pa->hair; k < pa->totkey; k++, hkey++, key++) {
4505  key->co = hkey->co;
4506  key->time = &hkey->time;
4507 
4508  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
4509  key->flag |= PEK_USE_WCO;
4510  }
4511  }
4512 
4513  pa->size = 1.0f;
4514  init_particle(&sim, pa);
4515  reset_particle(&sim, pa, 0.0, 1.0);
4516  point->flag |= PEP_EDIT_RECALC;
4517  if (pe_x_mirror(ob)) {
4518  point->flag |= PEP_TAG; /* signal for duplicate */
4519  }
4520 
4521  framestep = pa->lifetime / (float)(pset->totaddkey - 1);
4522 
4523  if (tree) {
4524  ParticleData *ppa;
4525  HairKey *thkey;
4526  ParticleKey key3[3];
4527  KDTreeNearest_3d ptn[3];
4528  int w, maxw;
4529  float maxd, totw = 0.0, weight[3];
4530 
4531  psys_particle_on_dm(psmd_eval->mesh_final,
4532  psys->part->from,
4533  pa->num,
4534  pa->num_dmcache,
4535  pa->fuv,
4536  pa->foffset,
4537  co1,
4538  0,
4539  0,
4540  0,
4541  0);
4542  maxw = BLI_kdtree_3d_find_nearest_n(tree, co1, ptn, 3);
4543 
4544  maxd = ptn[maxw - 1].dist;
4545 
4546  for (w = 0; w < maxw; w++) {
4547  weight[w] = (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
4548  totw += weight[w];
4549  }
4550  for (; w < 3; w++) {
4551  weight[w] = 0.0f;
4552  }
4553 
4554  if (totw > 0.0f) {
4555  for (w = 0; w < maxw; w++) {
4556  weight[w] /= totw;
4557  }
4558  }
4559  else {
4560  for (w = 0; w < maxw; w++) {
4561  weight[w] = 1.0f / maxw;
4562  }
4563  }
4564 
4565  ppa = psys->particles + ptn[0].index;
4566 
4567  for (k = 0; k < pset->totaddkey; k++) {
4568  thkey = (HairKey *)pa->hair + k;
4569  thkey->time = pa->time + k * framestep;
4570 
4571  key3[0].time = thkey->time / 100.0f;
4572  psys_get_particle_on_path(&sim, ptn[0].index, key3, 0);
4573  mul_v3_fl(key3[0].co, weight[0]);
4574 
4575  /* TODO: interpolating the weight would be nicer */
4576  thkey->weight = (ppa->hair + MIN2(k, ppa->totkey - 1))->weight;
4577 
4578  if (maxw > 1) {
4579  key3[1].time = key3[0].time;
4580  psys_get_particle_on_path(&sim, ptn[1].index, &key3[1], 0);
4581  mul_v3_fl(key3[1].co, weight[1]);
4582  add_v3_v3(key3[0].co, key3[1].co);
4583 
4584  if (maxw > 2) {
4585  key3[2].time = key3[0].time;
4586  psys_get_particle_on_path(&sim, ptn[2].index, &key3[2], 0);
4587  mul_v3_fl(key3[2].co, weight[2]);
4588  add_v3_v3(key3[0].co, key3[2].co);
4589  }
4590  }
4591 
4592  if (k == 0) {
4593  sub_v3_v3v3(co1, pa->state.co, key3[0].co);
4594  }
4595 
4596  add_v3_v3v3(thkey->co, key3[0].co, co1);
4597 
4598  thkey->time = key3[0].time;
4599  }
4600  }
4601  else {
4602  for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
4603  madd_v3_v3v3fl(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
4604  hkey->time += k * framestep;
4605  hkey->weight = 1.0f - (float)k / (float)(pset->totaddkey - 1);
4606  }
4607  }
4608  for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
4609  psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
4610  invert_m4_m4(imat, hairmat);
4611  mul_m4_v3(imat, hkey->co);
4612  }
4613  }
4614 
4615  if (tree) {
4616  BLI_kdtree_3d_free(tree);
4617  }
4618  }
4619 
4620  MEM_freeN(add_pars);
4621 
4622  BLI_rng_free(rng);
4623 
4624  return n;
4625 }
4626 
4629 /* -------------------------------------------------------------------- */
4633 typedef struct BrushEdit {
4638 
4639  int first;
4640  int lastmouse[2];
4641  float zfac;
4642 
4643  /* optional cached view settings to avoid setting on every mousemove */
4646 
4648 {
4651  ViewLayer *view_layer = CTX_data_view_layer(C);
4653  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
4654  ARegion *region = CTX_wm_region(C);
4655  BrushEdit *bedit;
4656  float min[3], max[3];
4657 
4659  return 0;
4660  }
4661 
4662  /* set the 'distance factor' for grabbing (used in comb etc) */
4663  INIT_MINMAX(min, max);
4664  PE_minmax(depsgraph, scene, view_layer, min, max);
4665  mid_v3_v3v3(min, min, max);
4666 
4667  bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
4668  bedit->first = 1;
4669  op->customdata = bedit;
4670 
4671  bedit->scene = scene;
4672  bedit->view_layer = view_layer;
4673  bedit->ob = ob;
4674  bedit->edit = edit;
4675 
4676  bedit->zfac = ED_view3d_calc_zfac(region->regiondata, min, NULL);
4677 
4678  /* cache view depths and settings for re-use */
4679  PE_set_view3d_data(C, &bedit->data);
4681 
4682  return 1;
4683 }
4684 
4685 static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
4686 {
4687  BrushEdit *bedit = op->customdata;
4689  Scene *scene = bedit->scene;
4690  Object *ob = bedit->ob;
4691  PTCacheEdit *edit = bedit->edit;
4693  ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
4694  ParticleBrushData *brush = &pset->brush[pset->brushtype];
4695  ARegion *region = CTX_wm_region(C);
4696  float vec[3], mousef[2];
4697  int mval[2];
4698  int flip, mouse[2], removed = 0, added = 0, selected = 0, tot_steps = 1, step = 1;
4699  float dx, dy, dmax;
4700  int lock_root = pset->flag & PE_LOCK_FIRST;
4701 
4702  if (!PE_start_edit(edit)) {
4703  return;
4704  }
4705 
4706  RNA_float_get_array(itemptr, "mouse", mousef);
4707  mouse[0] = mousef[0];
4708  mouse[1] = mousef[1];
4709  flip = RNA_boolean_get(itemptr, "pen_flip");
4710 
4711  if (bedit->first) {
4712  bedit->lastmouse[0] = mouse[0];
4713  bedit->lastmouse[1] = mouse[1];
4714  }
4715 
4716  dx = mouse[0] - bedit->lastmouse[0];
4717  dy = mouse[1] - bedit->lastmouse[1];
4718 
4719  mval[0] = mouse[0];
4720  mval[1] = mouse[1];
4721 
4722  /* Disable locking temporarily for disconnected hair. */
4723  if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
4724  pset->flag &= ~PE_LOCK_FIRST;
4725  }
4726 
4727  if (((pset->brushtype == PE_BRUSH_ADD) ?
4728  (sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) :
4729  (dx != 0 || dy != 0)) ||
4730  bedit->first) {
4731  PEData data = bedit->data;
4732  data.context = C; /* TODO(mai): why isn't this set in bedit->data? */
4733 
4735  selected = (short)count_selected_keys(scene, edit);
4736 
4737  dmax = max_ff(fabsf(dx), fabsf(dy));
4738  tot_steps = dmax / (0.2f * pe_brush_size_get(scene, brush)) + 1;
4739 
4740  dx /= (float)tot_steps;
4741  dy /= (float)tot_steps;
4742 
4743  for (step = 1; step <= tot_steps; step++) {
4744  mval[0] = bedit->lastmouse[0] + step * dx;
4745  mval[1] = bedit->lastmouse[1] + step * dy;
4746 
4747  switch (pset->brushtype) {
4748  case PE_BRUSH_COMB: {
4749  const float mval_f[2] = {dx, dy};
4750  data.mval = mval;
4751  data.rad = pe_brush_size_get(scene, brush);
4752 
4753  data.combfac = (brush->strength - 0.5f) * 2.0f;
4754  if (data.combfac < 0.0f) {
4755  data.combfac = 1.0f - 9.0f * data.combfac;
4756  }
4757  else {
4758  data.combfac = 1.0f - data.combfac;
4759  }
4760 
4761  invert_m4_m4(ob->imat, ob->obmat);
4762 
4763  ED_view3d_win_to_delta(region, mval_f, vec, bedit->zfac);
4764  data.dvec = vec;
4765 
4766  foreach_mouse_hit_key(&data, brush_comb, selected);
4767  break;
4768  }
4769  case PE_BRUSH_CUT: {
4770  if (edit->psys && edit->pathcache) {
4771  data.mval = mval;
4772  data.rad = pe_brush_size_get(scene, brush);
4773  data.cutfac = brush->strength;
4774 
4775  if (selected) {
4777  }
4778  else {
4780  }
4781 
4782  removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
4783  if (pset->flag & PE_KEEP_LENGTHS) {
4784  recalc_lengths(edit);
4785  }
4786  }
4787  else {
4788  removed = 0;
4789  }
4790 
4791  break;
4792  }
4793  case PE_BRUSH_LENGTH: {
4794  data.mval = mval;
4795 
4796  data.rad = pe_brush_size_get(scene, brush);
4797  data.growfac = brush->strength / 50.0f;
4798 
4799  if (brush->invert ^ flip) {
4800  data.growfac = 1.0f - data.growfac;
4801  }
4802  else {
4803  data.growfac = 1.0f + data.growfac;
4804  }
4805 
4807 
4808  if (pset->flag & PE_KEEP_LENGTHS) {
4809  recalc_lengths(edit);
4810  }
4811  break;
4812  }
4813  case PE_BRUSH_PUFF: {
4814  if (edit->psys) {
4815  data.mesh = psmd_eval->mesh_final;
4816  data.mval = mval;
4817  data.rad = pe_brush_size_get(scene, brush);
4818  data.select = selected;
4819 
4820  data.pufffac = (brush->strength - 0.5f) * 2.0f;
4821  if (data.pufffac < 0.0f) {
4822  data.pufffac = 1.0f - 9.0f * data.pufffac;
4823  }
4824  else {
4825  data.pufffac = 1.0f - data.pufffac;
4826  }
4827 
4828  data.invert = (brush->invert ^ flip);
4829  invert_m4_m4(ob->imat, ob->obmat);
4830 
4832  }
4833  break;
4834  }
4835  case PE_BRUSH_ADD: {
4836  if (edit->psys && edit->psys->part->from == PART_FROM_FACE) {
4837  data.mval = mval;
4838 
4839  added = brush_add(C, &data, brush->count);
4840 
4841  if (pset->flag & PE_KEEP_LENGTHS) {
4842  recalc_lengths(edit);
4843  }
4844  }
4845  else {
4846  added = 0;
4847  }
4848  break;
4849  }
4850  case PE_BRUSH_SMOOTH: {
4851  data.mval = mval;
4852  data.rad = pe_brush_size_get(scene, brush);
4853 
4854  data.vec[0] = data.vec[1] = data.vec[2] = 0.0f;
4855  data.tot = 0;
4856 
4857  data.smoothfac = brush->strength;
4858 
4859  invert_m4_m4(ob->imat, ob->obmat);
4860 
4862 
4863  if (data.tot) {
4864  mul_v3_fl(data.vec, 1.0f / (float)data.tot);
4866  }
4867 
4868  break;
4869  }
4870  case PE_BRUSH_WEIGHT: {
4871  if (edit->psys) {
4872  data.mesh = psmd_eval->mesh_final;
4873  data.mval = mval;
4874  data.rad = pe_brush_size_get(scene, brush);
4875 
4876  data.weightfac = brush->strength; /* note that this will never be zero */
4877 
4879  }
4880 
4881  break;
4882  }
4883  }
4884  if ((pset->flag & PE_KEEP_LENGTHS) == 0) {
4885  recalc_lengths(edit);
4886  }
4887 
4888  if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
4889  if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) {
4890  PE_mirror_x(depsgraph, scene, ob, 1);
4891  }
4892 
4893  update_world_cos(ob, edit);
4894  psys_free_path_cache(NULL, edit);
4896  }
4897  else {
4898  PE_update_object(depsgraph, scene, ob, 1);
4899  }
4900  }
4901 
4902  if (edit->psys) {
4906  }
4907  else {
4910  }
4911 
4912  bedit->lastmouse[0] = mouse[0];
4913  bedit->lastmouse[1] = mouse[1];
4914  bedit->first = 0;
4915  }
4916 
4917  pset->flag |= lock_root;
4918 }
4919 
4920 static void brush_edit_exit(wmOperator *op)
4921 {
4922  BrushEdit *bedit = op->customdata;
4923 
4924  PE_free_random_generator(&bedit->data);
4925  MEM_freeN(bedit);
4926 }
4927 
4929 {
4930  if (!brush_edit_init(C, op)) {
4931  return OPERATOR_CANCELLED;
4932  }
4933 
4934  RNA_BEGIN (op->ptr, itemptr, "stroke") {
4935  brush_edit_apply(C, op, &itemptr);
4936  }
4937  RNA_END;
4938 
4939  brush_edit_exit(op);
4940 
4941  return OPERATOR_FINISHED;
4942 }
4943 
4944 static void brush_edit_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
4945 {
4946  PointerRNA itemptr;
4947  float mouse[2];
4948 
4949  copy_v2fl_v2i(mouse, event->mval);
4950 
4951  /* fill in stroke */
4952  RNA_collection_add(op->ptr, "stroke", &itemptr);
4953 
4954  RNA_float_set_array(&itemptr, "mouse", mouse);
4955  RNA_boolean_set(&itemptr, "pen_flip", event->shift != false); /* XXX hardcoded */
4956 
4957  /* apply */
4958  brush_edit_apply(C, op, &itemptr);
4959 }
4960 
4961 static int brush_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
4962 {
4963  if (!brush_edit_init(C, op)) {
4964  return OPERATOR_CANCELLED;
4965  }
4966 
4967  brush_edit_apply_event(C, op, event);
4968 
4970 
4971  return OPERATOR_RUNNING_MODAL;
4972 }
4973 
4974 static int brush_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
4975 {
4976  switch (event->type) {
4977  case LEFTMOUSE:
4978  case MIDDLEMOUSE:
4979  case RIGHTMOUSE: /* XXX hardcoded */
4980  if (event->val == KM_RELEASE) {
4981  brush_edit_exit(op);
4982  return OPERATOR_FINISHED;
4983  }
4984  break;
4985  case MOUSEMOVE:
4986  brush_edit_apply_event(C, op, event);
4987  break;
4988  }
4989 
4990  return OPERATOR_RUNNING_MODAL;
4991 }
4992 
4994 {
4995  brush_edit_exit(op);
4996 }
4997 
4999 {
5000  /* identifiers */
5001  ot->name = "Brush Edit";
5002  ot->idname = "PARTICLE_OT_brush_edit";
5003  ot->description = "Apply a stroke of brush to the particles";
5004 
5005  /* api callbacks */
5006  ot->exec = brush_edit_exec;
5010  ot->poll = PE_poll_view3d;
5011 
5012  /* flags */
5014 
5015  /* properties */
5016  PropertyRNA *prop;
5017  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
5019 }
5020 
5023 /* -------------------------------------------------------------------- */
5028 {
5029  if (PE_hair_poll(C)) {
5032 
5033  if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
5034  return true;
5035  }
5036  }
5037 
5038  return false;
5039 }
5040 
5041 typedef struct PointInsideBVH {
5045 
5046 static void point_inside_bvh_cb(void *userdata,
5047  int index,
5048  const BVHTreeRay *ray,
5049  BVHTreeRayHit *hit)
5050 {
5051  PointInsideBVH *data = userdata;
5052 
5053  data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
5054 
5055  if (hit->index != -1) {
5056  ++data->num_hits;
5057  }
5058 }
5059 
5060 /* true if the point is inside the shape mesh */
5062 {
5063  BVHTreeFromMesh *shape_bvh = &data->shape_bvh;
5064  const float dir[3] = {1.0f, 0.0f, 0.0f};
5065  PointInsideBVH userdata;
5066 
5067  userdata.bvhdata = data->shape_bvh;
5068  userdata.num_hits = 0;
5069 
5070  float co_shape[3];
5071  mul_v3_m4v3(co_shape, pset->shape_object->imat, key->co);
5072 
5074  shape_bvh->tree, co_shape, dir, 0.0f, BVH_RAYCAST_DIST_MAX, point_inside_bvh_cb, &userdata);
5075 
5076  /* for any point inside a watertight mesh the number of hits is uneven */
5077  return (userdata.num_hits % 2) == 1;
5078 }
5079 
5080 static void shape_cut(PEData *data, int pa_index)
5081 {
5082  PTCacheEdit *edit = data->edit;
5083  Object *ob = data->ob;
5084  ParticleEditSettings *pset = PE_settings(data->scene);
5085  ParticleCacheKey *key;
5086 
5087  bool cut;
5088  float cut_time = 1.0;
5089  int k, totkeys = 1 << pset->draw_step;
5090 
5091  /* don't cut hidden */
5092  if (edit->points[pa_index].flag & PEP_HIDE) {
5093  return;
5094  }
5095 
5096  cut = false;
5097 
5098  /* check if root is inside the cut shape */
5099  key = edit->pathcache[pa_index];
5100  if (!shape_cut_test_point(data, pset, key)) {
5101  cut_time = -1.0f;
5102  cut = true;
5103  }
5104  else {
5105  for (k = 0; k < totkeys; k++, key++) {
5106  BVHTreeRayHit hit;
5107 
5108  float co_curr_shape[3], co_next_shape[3];
5109  float dir_shape[3];
5110  float len_shape;
5111 
5112  mul_v3_m4v3(co_curr_shape, pset->shape_object->imat, key->co);
5113  mul_v3_m4v3(co_next_shape, pset->shape_object->imat, (key + 1)->co);
5114 
5115  sub_v3_v3v3(dir_shape, co_next_shape, co_curr_shape);
5116  len_shape = normalize_v3(dir_shape);
5117 
5118  memset(&hit, 0, sizeof(hit));
5119  hit.index = -1;
5120  hit.dist = len_shape;
5121  BLI_bvhtree_ray_cast(data->shape_bvh.tree,
5122  co_curr_shape,
5123  dir_shape,
5124  0.0f,
5125  &hit,
5126  data->shape_bvh.raycast_callback,
5127  &data->shape_bvh);
5128  if (hit.index >= 0) {
5129  if (hit.dist < len_shape) {
5130  cut_time = ((hit.dist / len_shape) + (float)k) / (float)totkeys;
5131  cut = true;
5132  break;
5133  }
5134  }
5135  }
5136  }
5137 
5138  if (cut) {
5139  if (cut_time < 0.0f) {
5140  edit->points[pa_index].flag |= PEP_TAG;
5141  }
5142  else {
5143  rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
5144  edit->points[pa_index].flag |= PEP_EDIT_RECALC;
5145  }
5146  }
5147 }
5148 
5150 {
5155  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
5156  Object *shapeob = pset->shape_object;
5157  int selected = count_selected_keys(scene, edit);
5158  int lock_root = pset->flag & PE_LOCK_FIRST;
5159 
5160  if (!PE_start_edit(edit)) {
5161  return OPERATOR_CANCELLED;
5162  }
5163 
5164  /* Disable locking temporarily for disconnected hair. */
5165  if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
5166  pset->flag &= ~PE_LOCK_FIRST;
5167  }
5168 
5169  if (edit->psys && edit->pathcache) {
5170  PEData data;
5171  int removed;
5172 
5173  PE_set_data(C, &data);
5174  if (!PE_create_shape_tree(&data, shapeob)) {
5175  /* shapeob may not have faces... */
5176  return OPERATOR_CANCELLED;
5177  }
5178 
5179  if (selected) {
5181  }
5182  else {
5184  }
5185 
5186  removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
5187  recalc_lengths(edit);
5188 
5189  if (removed) {
5190  update_world_cos(ob, edit);
5191  psys_free_path_cache(NULL, edit);
5193  }
5194  else {
5195  PE_update_object(data.depsgraph, scene, ob, 1);
5196  }
5197 
5198  if (edit->psys) {
5202  }
5203  else {
5206  }
5207 
5209  }
5210 
5211  pset->flag |= lock_root;
5212 
5213  return OPERATOR_FINISHED;
5214 }
5215 
5217 {
5218  /* identifiers */
5219  ot->name = "Shape Cut";
5220  ot->idname = "PARTICLE_OT_shape_cut";
5221  ot->description = "Cut hair to conform to the set shape object";
5222 
5223  /* api callbacks */
5224  ot->exec = shape_cut_exec;
5225  ot->poll = shape_cut_poll;
5226 
5227  /* flags */
5229 }
5230 
5233 /* -------------------------------------------------------------------- */
5237 /* initialize needed data for bake edit */
5240 {
5241  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
5242  PTCacheEdit *edit;
5243  ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
5244  ParticleSystemModifierData *psmd_eval = NULL;
5245  POINT_P;
5246  KEY_K;
5247  ParticleData *pa = NULL;
5248  HairKey *hkey;
5249  int totpoint;
5250 
5251  if (psmd != NULL) {
5253  psmd->modifier.name);
5254  }
5255 
5256  /* no psmd->dm happens in case particle system modifier is not enabled */
5257  if (!(psys && psmd && psmd_eval->mesh_final) && !cache) {
5258  return;
5259  }
5260 
5261  if (cache && cache->flag & PTCACHE_DISK_CACHE) {
5262  return;
5263  }
5264 
5265  if (psys == NULL && (cache && BLI_listbase_is_empty(&cache->mem_cache))) {
5266  return;
5267  }
5268 
5269  edit = (psys) ? psys->edit : cache->edit;
5270 
5271  if (!edit) {
5272  ParticleSystem *psys_eval = NULL;
5273  if (psys) {
5274  psys_eval = psys_eval_get(depsgraph, ob, psys);
5275  psys_copy_particles(psys, psys_eval);
5276  }
5277 
5278  totpoint = psys ? psys->totpart : (int)((PTCacheMem *)cache->mem_cache.first)->totpoint;
5279 
5280  edit = MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
5281  edit->points = MEM_callocN(totpoint * sizeof(PTCacheEditPoint), "PTCacheEditPoints");
5282  edit->totpoint = totpoint;
5283 
5284  if (psys && !cache) {
5285  edit->psmd = psmd;
5286  edit->psmd_eval = psmd_eval;
5287  psys->edit = edit;
5288  edit->psys = psys;
5289  edit->psys_eval = psys_eval;
5290 
5292 
5293  edit->pathcache = NULL;
5295 
5296  pa = psys->particles;
5297  LOOP_POINTS {
5298  point->totkey = pa->totkey;
5299  point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
5300  point->flag |= PEP_EDIT_RECALC;
5301 
5302  hkey = pa->hair;
5303  LOOP_KEYS {
5304  key->co = hkey->co;
5305  key->time = &hkey->time;
5306  key->flag = hkey->editflag;
5307  if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
5308  key->flag |= PEK_USE_WCO;
5309  hkey->editflag |= PEK_USE_WCO;
5310  }
5311 
5312  hkey++;
5313  }
5314  pa++;
5315  }
5316  update_world_cos(ob, edit);
5317  }
5318  else {
5319  PTCacheMem *pm;
5320  int totframe = 0;
5321 
5322  cache->edit = edit;
5324  edit->psys = NULL;
5325 
5326  for (pm = cache->mem_cache.first; pm; pm = pm->next) {
5327  totframe++;
5328  }
5329 
5330  for (pm = cache->mem_cache.first; pm; pm = pm->next) {
5331  LOOP_POINTS {
5332  void *cur[BPHYS_TOT_DATA];
5333  if (BKE_ptcache_mem_pointers_seek(p, pm, cur) == 0) {
5334  continue;
5335  }
5336 
5337  if (!point->totkey) {
5338  key = point->keys = MEM_callocN(totframe * sizeof(PTCacheEditKey), "ParticleEditKeys");
5339  point->flag |= PEP_EDIT_RECALC;
5340  }
5341  else {
5342  key = point->keys + point->totkey;
5343  }
5344 
5345  key->co = cur[BPHYS_DATA_LOCATION];
5346  key->vel = cur[BPHYS_DATA_VELOCITY];
5347  key->rot = cur[BPHYS_DATA_ROTATION];
5348  key->ftime = (float)pm->frame;
5349  key->time = &key->ftime;
5351 
5352  point->totkey++;
5353  }
5354  }
5355  psys = NULL;
5356  }
5357 
5358  recalc_lengths(edit);
5359  if (psys && !cache) {
5360  recalc_emitter_field(depsgraph, ob, psys);
5361  }
5362 
5363  PE_update_object(depsgraph, scene, ob, 1);
5364  }
5365 }
5366 
5368 {
5370 
5371  if (ob == NULL || ob->type != OB_MESH) {
5372  return 0;
5373  }
5374  if (!ob->data || ID_IS_LINKED(ob->data)) {
5375  return 0;
5376  }
5377 
5379 }
5380 
5381 static void free_all_psys_edit(Object *object)
5382 {
5383  for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
5384  if (psys->edit != NULL) {
5385  BLI_assert(psys->free_edit != NULL);
5386  psys->free_edit(psys->edit);
5387  psys->free_edit = NULL;
5388  psys->edit = NULL;
5389  }
5390  }
5391 }
5392 
5394 {
5397 }
5398 
5400 {
5401  /* Needed so #ParticleSystemModifierData.mesh_final is set. */
5403 
5404  PTCacheEdit *edit;
5405 
5406  ob->mode |= OB_MODE_PARTICLE_EDIT;
5407 
5408  edit = PE_create_current(depsgraph, scene, ob);
5409 
5410  /* Mesh may have changed since last entering editmode.
5411  * note, this may have run before if the edit data was just created,
5412  * so could avoid this and speed up a little. */
5413  if (edit && edit->psys) {
5414  /* Make sure pointer to the evaluated modifier data is up to date,
5415  * with possible changes applied when object was outside of the
5416  * edit mode. */
5417  Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
5419  object_eval, edit->psmd->modifier.name);
5420  recalc_emitter_field(depsgraph, ob, edit->psys);
5421  }
5422 
5426 }
5427 
5429 {
5434 }
5435 
5437 {
5438  ob->mode &= ~OB_MODE_PARTICLE_EDIT;
5439  toggle_particle_cursor(scene, false);
5440  free_all_psys_edit(ob);
5441 
5444 }
5445 
5447 {
5451 }
5452 
5454 {
5455  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
5458  const int mode_flag = OB_MODE_PARTICLE_EDIT;
5459  const bool is_mode_set = (ob->mode & mode_flag) != 0;
5460 
5461  if (!is_mode_set) {
5462  if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
5463  return OPERATOR_CANCELLED;
5464  }
5465  }
5466 
5467  if (!is_mode_set) {
5470  }
5471  else {
5473  }
5474 
5475  WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
5476 
5478 
5479  return OPERATOR_FINISHED;
5480 }
5481 
5483 {
5484  /* identifiers */
5485  ot->name = "Particle Edit Toggle";
5486  ot->idname = "PARTICLE_OT_particle_edit_toggle";
5487  ot->description = "Toggle particle edit mode";
5488 
5489  /* api callbacks */
5492 
5493  /* flags */
5495 }
5496 
5499 /* -------------------------------------------------------------------- */
5504 {
5506  ParticleSystem *psys = psys_get_current(ob);
5507 
5508  if (psys->edit) {
5509  if (psys->edit->edited || 1) {
5510  PE_free_ptcache_edit(psys->edit);
5511 
5512  psys->edit = NULL;
5513  psys->free_edit = NULL;
5514 
5515  psys->recalc |= ID_RECALC_PSYS_RESET;
5516  psys->flag &= ~PSYS_GLOBAL_HAIR;
5517  psys->flag &= ~PSYS_EDITED;
5518 
5523  }
5524  }
5525  else { /* some operation might have protected hair from editing so let's clear the flag */
5526  psys->recalc |= ID_RECALC_PSYS_RESET;
5527  psys->flag &= ~PSYS_GLOBAL_HAIR;
5528  psys->flag &= ~PSYS_EDITED;
5531  }
5532 
5533  return OPERATOR_FINISHED;
5534 }
5535 
5537 {
5538  /* identifiers */
5539  ot->name = "Clear Edited";
5540  ot->idname = "PARTICLE_OT_edited_clear";
5541  ot->description = "Undo all edition performed on the particle system";
5542 
5543  /* api callbacks */
5546 
5547  /* flags */
5549 }
5550 
5553 /* -------------------------------------------------------------------- */
5558 {
5559  float length = 0.0f;
5560  KEY_K;
5561  LOOP_KEYS {
5562  if (k > 0) {
5563  length += len_v3v3((key - 1)->co, key->co);
5564  }
5565  }
5566  return length;
5567 }
5568 
5570 {
5571  int num_selected = 0;
5572  float total_length = 0;
5573  POINT_P;
5575  total_length += calculate_point_length(point);
5576  num_selected++;
5577  }
5578  if (num_selected == 0) {
5579  return 0.0f;
5580  }
5581  return total_length / num_selected;
5582 }
5583 
5584 static void scale_point_factor(PTCacheEditPoint *point, float factor)
5585 {
5586  float orig_prev_co[3], prev_co[3];
5587  KEY_K;
5588  LOOP_KEYS {
5589  if (k == 0) {
5590  copy_v3_v3(orig_prev_co, key->co);
5591  copy_v3_v3(prev_co, key->co);
5592  }
5593  else {
5594  float new_co[3];
5595  float delta[3];
5596 
5597  sub_v3_v3v3(delta, key->co, orig_prev_co);
5598  mul_v3_fl(delta, factor);
5599  add_v3_v3v3(new_co, prev_co, delta);
5600 
5601  copy_v3_v3(orig_prev_co, key->co);
5602  copy_v3_v3(key->co, new_co);
5603  copy_v3_v3(prev_co, key->co);
5604  }
5605  }
5606  point->flag |= PEP_EDIT_RECALC;
5607 }
5608 
5610 {
5611  const float point_length = calculate_point_length(point);
5612  if (point_length != 0.0f) {
5613  const float factor = length / point_length;
5614  scale_point_factor(point, factor);
5615  }
5616 }
5617 
5618 static void scale_points_to_length(PTCacheEdit *edit, float length)
5619 {
5620  POINT_P;
5622  scale_point_to_length(point, length);
5623  }
5624  recalc_lengths(edit);
5625 }
5626 
5628 {
5632 
5633  PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
5634  float average_length = calculate_average_length(edit);
5635 
5636  if (average_length == 0.0f) {
5637  return OPERATOR_CANCELLED;
5638  }
5639  scale_points_to_length(edit, average_length);
5640 
5641  PE_update_object(depsgraph, scene, ob, 1);
5642  if (edit->psys) {
5644  }
5645  else {
5648  }
5649 
5650  return OPERATOR_FINISHED;
5651 }
5652 
5654 {
5655  /* identifiers */
5656  ot->name = "Unify Length";
5657  ot->idname = "PARTICLE_OT_unify_length";
5658  ot->description = "Make selected hair the same length";
5659 
5660  /* api callbacks */
5662  ot->poll = PE_poll_view3d;
5663 
5664  /* flags */
5666 }
5667 
typedef float(TangentPoint)[2]
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, const BVHCacheType bvh_cache_type, const int tree_type)
Definition: bvhutils.c:1413
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.c:1701
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:93
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:746
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1401
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
const CustomData_MeshMasks CD_MASK_BAREMESH
Definition: customdata.c:1919
#define G_MAIN
Definition: BKE_global.h:232
void BKE_mesh_tessface_ensure(struct Mesh *mesh)
Definition: mesh.c:1560
struct Mesh * mesh_get_eval_deform(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
struct Mesh * mesh_get_eval_final(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
struct ModifierData * BKE_modifier_get_evaluated(struct Depsgraph *depsgraph, struct Object *object, struct ModifierData *md)
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
struct ModifierData * BKE_modifiers_findby_name(const struct Object *ob, const char *name)
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_evaluated_mesh(struct Object *object)
Definition: object.c:4459
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
Definition: object.c:3964
struct ParticleSystem * psys_eval_get(struct Depsgraph *depsgraph, struct Object *object, struct ParticleSystem *psys)
Definition: particle.c:749
void psys_cache_edit_paths(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params)
Definition: particle.c:3686
#define DMCACHE_NOTFOUND
Definition: BKE_particle.h:606
void psys_mat_hair_to_orco(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition: particle.c:3884
void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, const bool vel)
Definition: particle.c:4585
void psys_disable_all(struct Object *ob)
Definition: particle.c:724
void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
Definition: particle.c:3909
void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra)
void psys_reset(struct ParticleSystem *psys, int mode)
void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4])
float psys_get_timestep(struct ParticleSimulationData *sim)
Definition: particle.c:4459
void psys_particle_on_dm(struct Mesh *mesh_final, int from, int index, int index_dmcache, const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], float orco[3])
Definition: particle.c:2095
int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex, const float fw[4], struct LinkNode **poly_nodes)
Definition: particle.c:1913
void psys_enable_all(struct Object *ob)
Definition: particle.c:732
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition: particle.c:645
#define LOOP_PARTICLES
Definition: BKE_particle.h:69
void init_particle(struct ParticleSimulationData *sim, struct ParticleData *pa)
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2201
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit)
Definition: particle.c:986
#define DMCACHE_ISCHILD
Definition: BKE_particle.h:607
void BKE_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode)
Definition: particle.c:5243
#define PSYS_RESET_DEPSGRAPH
Definition: BKE_particle.h:601
void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src)
Definition: particle.c:1149
#define PARTICLE_P
Definition: BKE_particle.h:66
@ BKE_PARTICLE_BATCH_DIRTY_ALL
Definition: BKE_particle.h:620
void BKE_ptcache_mem_pointers_incr(void *cur[BPHYS_TOT_DATA])
Definition: pointcache.c:1792
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis)
Definition: pointcache.c:1278
#define PTCACHE_VEL_PER_SEC
#define PEK_HIDE
#define PEP_EDIT_RECALC
@ PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL
#define PTCACHE_TYPE_CLOTH
#define PEP_HIDE
int BKE_ptcache_mem_pointers_seek(int point_index, struct PTCacheMem *pm, void *cur[BPHYS_TOT_DATA])
Definition: pointcache.c:1802
#define PTCACHE_TYPE_PARTICLES
#define PTCACHE_TYPE_SOFTBODY
#define PEP_TAG
#define PEK_SELECT
#define PEK_USE_WCO
#define PEK_TAG
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain)
Definition: scene.c:2718
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BVH_RAYCAST_DIST_MAX
Definition: BLI_kdopbvh.h:105
void BLI_bvhtree_ray_cast_all(BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:2066
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1984
A kd-tree for nearest neighbor search.
bool BLI_lasso_is_point_inside(const int mcoords[][2], const unsigned int mcoords_len, const int sx, const int sy, const int error_value)
Definition: lasso_2d.c:54
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:120
MINLINE float max_ff(float a, float b)
MINLINE float interpf(float a, float b, float t)
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius, const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float ipoint[3])
Definition: math_geom.c:2788
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3])
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3])
Definition: math_geom.c:3226
bool isect_line_segment_tri_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
Definition: math_geom.c:1645
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
MINLINE void copy_v3fl_v3s(float r[3], const short a[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:1020
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3])
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
Definition: math_vector.c:674
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
Definition: math_vector.c:1068
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:76
struct RNG * BLI_rng_new(unsigned int seed)
Definition: rand.cc:54
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition: rand.cc:64
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
bool BLI_rcti_is_empty(const struct rcti *rect)
unsigned int uint
Definition: BLI_sys_types.h:83
void BLI_task_parallel_range(const int start, const int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:110
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls)
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:231
#define SHIFT4(type, a, b, c, d)
#define INIT_MINMAX(min, max)
#define DO_MINMAX(vec, min, max)
#define POINTER_AS_UINT(i)
#define SHIFT3(type, a, b, c)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define MIN2(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:331
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ ID_RECALC_PSYS_REDO
Definition: DNA_ID.h:618
@ ID_RECALC_PSYS_RESET
Definition: DNA_ID.h:620
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
@ ME_SYMMETRY_X
@ eModifierType_Cloth
@ eModifierType_Softbody
@ OB_MODE_PARTICLE_EDIT
@ OB_MESH
#define PART_FROM_FACE
#define PSYS_HAIR_DYNAMICS
#define PSYS_CURRENT
#define PSYS_GLOBAL_HAIR
#define PSYS_EDITED
#define PSYS_HAIR_UPDATED
@ PART_EMITTER
@ PART_HAIR
#define PSYS_HAIR_DONE
#define PARS_REKEY
#define BPHYS_DATA_LOCATION
#define PTCACHE_DISK_CACHE
#define BPHYS_DATA_VELOCITY
#define PTCACHE_BAKED
#define BPHYS_DATA_ROTATION
#define BPHYS_TOT_DATA
#define PE_TYPE_CLOTH
#define PE_BRUSH_PUFF
#define PE_BRUSH_DATA_PUFF_VOLUME
#define PE_TYPE_SOFTBODY
#define PE_BRUSH_ADD
#define SCE_SELECT_PATH
@ UNIFIED_PAINT_SIZE
#define CFRA
#define PE_KEEP_LENGTHS
#define PE_DEFLECT_EMITTER
#define SCE_SELECT_END
#define PE_BRUSH_CUT
#define PE_INTERPOLATE_ADDED
#define OBACT(_view_layer)
#define SCE_SELECT_POINT
#define PE_LOCK_FIRST
#define PE_FADE_TIME
#define PE_BRUSH_WEIGHT
#define PE_TYPE_PARTICLES
#define PE_BRUSH_LENGTH
#define PE_BRUSH_COMB
#define PE_BRUSH_SMOOTH
#define PE_AUTO_VELOCITY
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ V3D_RUNTIME_DEPTHBUF_OVERRIDDEN
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
int * mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval)
Definition: meshtools.c:1144
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports)
Definition: object_modes.c:165
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside)
Definition: select_utils.c:53
eSelectOp
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip)
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region, const float co[3], int r_co[2], const eV3DProjTest flag)
#define XRAY_ENABLED(v3d)
Definition: ED_view3d.h:710
@ V3D_PROJ_TEST_CLIP_NEAR
Definition: ED_view3d.h:196
@ V3D_PROJ_TEST_CLIP_WIN
Definition: ED_view3d.h:195
@ V3D_PROJ_TEST_CLIP_BB
Definition: ED_view3d.h:194
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
void ED_view3d_win_to_delta(const struct ARegion *region, const float mval[2], float out[3], const float zfac)
void ED_view3d_project(const struct ARegion *region, const float world[3], float r_region_co[3])
#define IS_CLIPPED
Definition: ED_view3d.h:172
@ V3D_DEPTH_OBJECT_ONLY
Definition: ED_view3d.h:150
void ED_view3d_depth_override(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obact, eV3DDepthOverrideMode mode, bool update_cache)
Definition: view3d_draw.c:2331
void view3d_operator_needs_opengl(const struct bContext *C)
float ED_view3d_select_dist_px(void)
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip)
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat(void)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:171
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:85
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
Utility defines for timing/benchmarks.
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:1248
StructRNA RNA_OperatorStrokeElement
#define RNA_END
Definition: RNA_access.h:1255
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NS_MODE_PARTICLE
Definition: WM_types.h:451
#define ND_MODE
Definition: WM_types.h:345
#define NC_SCENE
Definition: WM_types.h:279
#define ND_MODIFIER
Definition: WM_types.h:363
#define NA_EDITED
Definition: WM_types.h:462
#define ND_PARTICLE
Definition: WM_types.h:366
#define NS_MODE_OBJECT
Definition: WM_types.h:441
#define NC_OBJECT
Definition: WM_types.h:280
#define NA_SELECTED
Definition: WM_types.h:467
#define KM_RELEASE
Definition: WM_types.h:243
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
static void mul(btAlignedObjectArray< T > &items, const Q &value)
static unsigned long seed
Definition: btSoftBody.h:39
double time
Scene scene
const Depsgraph * depsgraph
void * tree
static bool is_inside(int x, int y, int cols, int rows)
Definition: filesel.c:663
uint pos
uint nor
#define UINT_MAX
Definition: hash_md5.c:58
#define fabsf(x)
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong state[N]
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Definition: rall1d.h:359
static void area(int d1, int d2, int e1, int e2, float weights[2])
static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
static void free_all_psys_edit(Object *object)
static void PE_set_data(bContext *C, PEData *data)
eParticleSelectFlag
@ PSEL_NEAREST
@ PSEL_ALL_KEYS
static int hide_exec(bContext *C, wmOperator *op)
static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
static void brush_edit_exit(wmOperator *op)
static const EnumPropertyItem select_random_type_items[]
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
static int brush_edit_init(bContext *C, wmOperator *op)
struct BrushAddCountIterData BrushAddCountIterData
static bool key_inside_rect(PEData *data, const float co[3])
static int select_random_exec(bContext *C, wmOperator *op)
bool ED_object_particle_edit_mode_supported(const Object *ob)
bool PE_hair_poll(bContext *C)
static int pe_x_mirror(Object *ob)
void PARTICLE_OT_select_roots(wmOperatorType *ot)
static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
static void select_keys(PEData *data, int point_index, int UNUSED(key_index), bool UNUSED(is_inside))
bool PE_poll(bContext *C)
Definition: particle_edit.c:95
int PE_minmax(Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
static bool key_inside_circle(const PEData *data, float rad, const float co[3], float *distance)
static bool key_test_depth(const PEData *data, const float co[3], const int screen_co[2])
static void scale_point_to_length(PTCacheEditPoint *point, float length)
static void set_delete_particle_key(PEData *data, int pa_index, int key_index, bool UNUSED(is_inside))
PTCacheEdit * PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
static int brush_add(const bContext *C, PEData *data, short number)
void PARTICLE_OT_unify_length(struct wmOperatorType *ot)
void PARTICLE_OT_weight_set(wmOperatorType *ot)
void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
struct KeyIterData KeyIterData
static void set_delete_particle(PEData *data, int pa_index)
void PARTICLE_OT_shape_cut(wmOperatorType *ot)
static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata), void *__restrict join_v, void *__restrict chunk_v)
static int remove_doubles_exec(bContext *C, wmOperator *op)
void ED_object_particle_edit_mode_exit_ex(Scene *scene, Object *ob)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void PE_current_changed(Depsgraph *depsgraph, Scene *scene, Object *ob)
static void brush_smooth_do(PEData *data, float UNUSED(mat[4][4]), float imat[4][4], int point_index, int key_index, PTCacheEditKey *key, float UNUSED(mouse_distance))
static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int selected)
struct PointInsideBVH PointInsideBVH
static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
static void PE_set_view3d_data(bContext *C, PEData *data)
static float calculate_point_length(PTCacheEditPoint *point)
static void foreach_selected_key(PEData *data, ForKeyFunc func)
void PARTICLE_OT_delete(wmOperatorType *ot)
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static bool shape_cut_test_point(PEData *data, ParticleEditSettings *pset, ParticleCacheKey *key)
static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
static void select_tip(PEData *data, int point_index)
void PARTICLE_OT_select_less(wmOperatorType *ot)
void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
void(* ForHitPointFunc)(PEData *data, int point_index, float mouse_distance)
static void PE_create_random_generator(PEData *data)
void PARTICLE_OT_edited_clear(wmOperatorType *ot)
static bool shape_cut_poll(bContext *C)
static void select_more_keys(PEData *data, int point_index)
@ DEL_KEY
@ DEL_PARTICLE
void PARTICLE_OT_mirror(wmOperatorType *ot)
static bool point_is_selected(PTCacheEditPoint *point)
static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *brush)
static void BKE_brush_weight_get(PEData *data, float UNUSED(mat[4][4]), float UNUSED(imat[4][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key), float UNUSED(mouse_distance))
void ED_object_particle_edit_mode_enter(bContext *C)
static void pe_update_hair_particle_edit_pointers(PTCacheEdit *edit)
static int brush_edit_exec(bContext *C, wmOperator *op)
static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum eParticleSelectFlag flag)
static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_select_random(wmOperatorType *ot)
static void deselect_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
bool PE_poll_view3d(bContext *C)
static void iterate_lengths_iter(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
static float calculate_average_length(PTCacheEdit *edit)
static void update_velocities(PTCacheEdit *edit)
void PARTICLE_OT_select_linked(wmOperatorType *ot)
void PARTICLE_OT_reveal(wmOperatorType *ot)
static bool key_inside_test(PEData *data, const float co[3])
void PE_free_ptcache_edit(PTCacheEdit *edit)
static void foreach_point(PEData *data, ForPointFunc func)
static bool mirror_poll(bContext *C)
void PARTICLE_OT_subdivide(wmOperatorType *ot)
static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
static void brush_comb(PEData *data, float UNUSED(mat[4][4]), float imat[4][4], int point_index, int key_index, PTCacheEditKey *key, float mouse_distance)
void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
void PE_create_particle_edit(Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
struct BrushEdit BrushEdit
static void brush_puff(PEData *data, int point_index, float mouse_distance)
static bool PE_create_shape_tree(PEData *data, Object *shapeob)
void update_world_cos(Object *ob, PTCacheEdit *edit)
static int select_linked_pick_exec(bContext *C, wmOperator *op)
static void brush_smooth_get(PEData *data, float mat[4][4], float UNUSED(imat[4][4]), int UNUSED(point_index), int key_index, PTCacheEditKey *key, float UNUSED(mouse_distance))
static PTCacheEdit * pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob, bool create)
void PARTICLE_OT_select_more(wmOperatorType *ot)
static int reveal_exec(bContext *C, wmOperator *op)
bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
void PARTICLE_OT_rekey(wmOperatorType *ot)
static int rekey_exec(bContext *C, wmOperator *op)
static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
static int particle_intersect_mesh(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Mesh *mesh, float *vert_cos, const float co1[3], const float co2[3], float *min_d, int *min_face, float *min_w, float *face_minmax, float *pa_minmax, float radius, float *ipoint)
static void rekey_particle(PEData *data, int pa_index)
static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
static void PE_free_shape_tree(PEData *data)
static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
static const EnumPropertyItem delete_type_items[]
static int brush_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void subdivide_particle(PEData *data, int pa_index)
void PARTICLE_OT_select_all(wmOperatorType *ot)
struct PEData PEData
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
void recalc_lengths(PTCacheEdit *edit)
static int select_roots_exec(bContext *C, wmOperator *op)
struct IterateLengthsIterData IterateLengthsIterData
ParticleEditSettings * PE_settings(Scene *scene)
void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
static void deflect_emitter_iter(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
static void brush_add_count_iter(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict tls_v)
static void select_key(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
void PARTICLE_OT_select_tips(wmOperatorType *ot)
static void select_less_keys(PEData *data, int point_index)
static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
void ED_object_particle_edit_mode_exit(bContext *C)
static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
void(* ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside)
int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op)
static int brush_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
static void toggle_particle_cursor(Scene *scene, bool enable)
static bool select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, int action)
struct DeflectEmitterIter DeflectEmitterIter
static void shape_cut(PEData *data, int pa_index)
int PE_start_edit(PTCacheEdit *edit)
static int delete_exec(bContext *C, wmOperator *op)
static void brush_length(PEData *data, int point_index, float UNUSED(mouse_distance))
static int weight_set_exec(bContext *C, wmOperator *op)
PTCacheEdit * PE_get_current_from_psys(ParticleSystem *psys)
static void scale_points_to_length(PTCacheEdit *edit, float length)
static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
static void brush_edit_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
struct ApplyLengthsIterData ApplyLengthsIterData
static void select_root(PEData *data, int point_index)
@ RAN_HAIR
@ RAN_POINTS
static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selected)
PTCacheEdit * PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
static void scale_point_factor(PTCacheEditPoint *point, float factor)
static void brush_edit_cancel(bContext *UNUSED(C), wmOperator *op)
void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
static bool particle_edit_toggle_poll(bContext *C)
static void brush_cut(PEData *data, int pa_index)
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys)
bool PE_deselect_all_visible(bContext *C)
static void PE_mirror_particle(Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
static int pe_select_all_exec(bContext *C, wmOperator *op)
void(* ForKeyMatFunc)(PEData *data, const float mat[4][4], const float imat[4][4], int point_index, int key_index, PTCacheEditKey *key)
void(* ForHitKeyMatFunc)(PEData *data, float mat[4][4], float imat[4][4], int point_index, int key_index, PTCacheEditKey *key, float mouse_distance)
static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
void PARTICLE_OT_hide(wmOperatorType *ot)
void PARTICLE_OT_select_linked_pick(wmOperatorType *ot)
static void select_key_op(PEData *data, int point_index, int key_index, bool is_inside)
static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v), void *__restrict chunk_v)
void(* ForPointFunc)(PEData *data, int point_index)
static void apply_lengths_iter(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
static void PE_free_random_generator(PEData *data)
static int select_tips_exec(bContext *C, wmOperator *op)
static void intersect_dm_quad_weights(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float w[4])
static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
static void foreach_selected_point(PEData *data, ForPointFunc func)
void PARTICLE_OT_brush_edit(wmOperatorType *ot)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
struct BrushAddCountIterTLSData BrushAddCountIterTLSData
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
#define KEY_WCO
#define LOOP_TAGGED_KEYS
#define LOOP_UNSELECTED_POINTS
#define LOOP_SELECTED_POINTS
#define POINT_P
#define LOOP_KEYS
#define LOOP_SELECTED_KEYS
#define KEY_K
#define LOOP_TAGGED_POINTS
#define LOOP_EDITED_POINTS
#define LOOP_VISIBLE_KEYS
#define LOOP_POINTS
#define LOOP_VISIBLE_POINTS
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
Definition: rna_access.c:6343
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
Definition: rna_access.c:6331
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
Definition: rna_access.c:6610
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4210
PropertyRNA * RNA_def_int_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const int *default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3611
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
#define min(a, b)
Definition: sort.c:51
void * regiondata
short regiontype
struct BVHTree * tree
Definition: BKE_bvhutils.h:66
ParticleData * add_pars
int lastmouse[2]
ViewLayer * view_layer
PTCacheEdit * edit
Object * ob
Scene * scene
PTCacheEdit * edit
ParticleSystem * psys
float co[3]
ParticleEditSettings * pset
ForHitKeyMatFunc func
PEData * data
PTCacheEdit * edit
void * first
Definition: DNA_listBase.h:47
unsigned int v2
unsigned int v1
unsigned int v4
unsigned int v3
float co[3]
short no[3]
Definition: BKE_main.h:116
struct MVert * mvert
int totface
Mesh_Runtime runtime
struct MFace * mface
ListBase particlesystem
float imat[4][4]
float obmat[4][4]
void * data
ViewContext vc
float pufffac
RNG * rng
float combfac
Depsgraph * depsgraph
float * dvec
eSelectOp sel_op
float weightfac
int totrekey
float vec[3]
bool is_changed
const rcti * rect
const int * mval
float rad
float cutfac
PTCacheEdit * edit
int select_action
Scene * scene
int select
BVHTreeFromMesh shape_bvh
Mesh * mesh
int select_toggle_action
int invert
ViewLayer * view_layer
Object * ob
float smoothfac
const bContext * context
Main * bmain
float growfac
float dval
struct PTCacheEditKey * keys
ListBase pathcachebufs
struct ParticleSystemModifierData * psmd
struct ParticleCacheKey ** pathcache
float * emitter_cosnos
int * mirror_cache
PTCacheEditPoint * points
struct ParticleSystem * psys
struct ParticleSystemModifierData * psmd_eval
struct KDTree_3d * emitter_field
struct PTCacheID pid
struct ParticleSystem * psys_eval
void * calldata
unsigned int type
unsigned int flag
struct PTCacheID * next
struct PointCache * cache
unsigned int frame
struct PTCacheMem * next
ParticleKey state
ParticleBrushData brush[7]
struct Object * shape_object
struct Object * object
struct Scene * scene
struct Depsgraph * depsgraph
Definition: BKE_particle.h:87
struct ParticleSystemModifierData * psmd
Definition: BKE_particle.h:91
struct Scene * scene
Definition: BKE_particle.h:88
struct ParticleSystem * psys
Definition: BKE_particle.h:90
struct Object * ob
Definition: BKE_particle.h:89
ChildParticle * child
struct PTCacheEdit * edit
ParticleData * particles
ParticleSettings * part
struct PointCache * pointcache
void(* free_edit)(struct PTCacheEdit *edit)
struct ListBase mem_cache
struct PTCacheEdit * edit
void(* free_edit)(struct PTCacheEdit *edit)
BVHTreeFromMesh bvhdata
Definition: rand.cc:48
struct ToolSettings * toolsettings
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:158
TaskParallelFreeFunc func_free
Definition: BLI_task.h:160
size_t userdata_chunk_size
Definition: BLI_task.h:150
struct UnifiedPaintSettings unified_paint_settings
struct ParticleEditSettings particle
unsigned short w
Definition: ED_view3d.h:89
float * depths
Definition: ED_view3d.h:91
unsigned short h
Definition: ED_view3d.h:89
short shift
Definition: WM_types.h:618
short val
Definition: WM_types.h:579
int mval[2]
Definition: WM_types.h:583
short type
Definition: WM_types.h:577
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
long int PIL_check_seconds_timer_i(void)
Definition: time.c:90
float max
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b)
ccl_device_inline float distance(const float2 &a, const float2 &b)
ccl_device_inline float dot(const float2 &a, const float2 &b)
#define G(x, y, z)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
wmOperatorType * ot
Definition: wm_files.c:3156
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op)
void WM_operator_properties_select_action(wmOperatorType *ot, int default_action, bool hide_gui)
void WM_operator_properties_select_random(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
bool WM_paint_cursor_end(wmPaintCursor *handle)
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
void WM_toolsystem_update_from_context_view3d(bContext *C)