Blender  V2.93
MOD_array.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) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_utildefines.h"
29 
30 #include "BLI_math.h"
31 
32 #include "BLT_translation.h"
33 
34 #include "DNA_curve_types.h"
35 #include "DNA_defaults.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 
42 #include "BKE_anim_path.h"
43 #include "BKE_context.h"
44 #include "BKE_curve.h"
45 #include "BKE_displist.h"
46 #include "BKE_lib_id.h"
47 #include "BKE_lib_query.h"
48 #include "BKE_mesh.h"
49 #include "BKE_modifier.h"
50 #include "BKE_object_deform.h"
51 #include "BKE_screen.h"
52 
53 #include "UI_interface.h"
54 #include "UI_resources.h"
55 
56 #include "RNA_access.h"
57 
58 #include "MOD_ui_common.h"
59 #include "MOD_util.h"
60 
61 #include "DEG_depsgraph.h"
62 #include "DEG_depsgraph_query.h"
63 
64 static void initData(ModifierData *md)
65 {
67 
69 
71 
72  /* Open the first sub-panel by default,
73  * it corresponds to Relative offset which is enabled too. */
75 }
76 
77 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
78 {
80 
81  walk(userData, ob, (ID **)&amd->start_cap, IDWALK_CB_NOP);
82  walk(userData, ob, (ID **)&amd->end_cap, IDWALK_CB_NOP);
83  walk(userData, ob, (ID **)&amd->curve_ob, IDWALK_CB_NOP);
84  walk(userData, ob, (ID **)&amd->offset_ob, IDWALK_CB_NOP);
85 }
86 
88 {
90  bool need_transform_dependency = false;
91  if (amd->start_cap != NULL) {
93  ctx->node, amd->start_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier Start Cap");
94  }
95  if (amd->end_cap != NULL) {
97  ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap");
98  }
99  if (amd->curve_ob) {
101  ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
103  }
104  if (amd->offset_ob != NULL) {
106  ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
107  need_transform_dependency = true;
108  }
109 
110  if (need_transform_dependency) {
111  DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier");
112  }
113 }
114 
115 BLI_INLINE float sum_v3(const float v[3])
116 {
117  return v[0] + v[1] + v[2];
118 }
119 
120 /* Structure used for sorting vertices, when processing doubles */
121 typedef struct SortVertsElem {
122  int vertex_num; /* The original index of the vertex, prior to sorting */
123  float co[3]; /* Its coordinates */
124  float sum_co; /* sum_v3(co), just so we don't do the sum many times. */
126 
127 static int svert_sum_cmp(const void *e1, const void *e2)
128 {
129  const SortVertsElem *sv1 = e1;
130  const SortVertsElem *sv2 = e2;
131 
132  if (sv1->sum_co > sv2->sum_co) {
133  return 1;
134  }
135  if (sv1->sum_co < sv2->sum_co) {
136  return -1;
137  }
138 
139  return 0;
140 }
141 
143  const MVert *mv,
144  const int i_begin,
145  const int i_end)
146 {
147  int i;
148  for (i = i_begin; i < i_end; i++, sv++, mv++) {
149  sv->vertex_num = i;
150  copy_v3_v3(sv->co, mv->co);
151  sv->sum_co = sum_v3(mv->co);
152  }
153 }
154 
162 static void dm_mvert_map_doubles(int *doubles_map,
163  const MVert *mverts,
164  const int target_start,
165  const int target_num_verts,
166  const int source_start,
167  const int source_num_verts,
168  const float dist)
169 {
170  const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
171  int i_source, i_target, i_target_low_bound, target_end, source_end;
172  SortVertsElem *sorted_verts_target, *sorted_verts_source;
173  SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
174  bool target_scan_completed;
175 
176  target_end = target_start + target_num_verts;
177  source_end = source_start + source_num_verts;
178 
179  /* build array of MVerts to be tested for merging */
180  sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__);
181  sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__);
182 
183  /* Copy target vertices index and cos into SortVertsElem array */
184  svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end);
185 
186  /* Copy source vertices index and cos into SortVertsElem array */
187  svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end);
188 
189  /* sort arrays according to sum of vertex coordinates (sumco) */
190  qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
191  qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
192 
193  sve_target_low_bound = sorted_verts_target;
194  i_target_low_bound = 0;
195  target_scan_completed = false;
196 
197  /* Scan source vertices, in SortVertsElem sorted array, */
198  /* all the while maintaining the lower bound of possible doubles in target vertices */
199  for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts;
200  i_source++, sve_source++) {
201  int best_target_vertex = -1;
202  float best_dist_sq = dist * dist;
203  float sve_source_sumco;
204 
205  /* If source has already been assigned to a target (in an earlier call, with other chunks) */
206  if (doubles_map[sve_source->vertex_num] != -1) {
207  continue;
208  }
209 
210  /* If target fully scanned already, then all remaining source vertices cannot have a double */
211  if (target_scan_completed) {
212  doubles_map[sve_source->vertex_num] = -1;
213  continue;
214  }
215 
216  sve_source_sumco = sum_v3(sve_source->co);
217 
218  /* Skip all target vertices that are more than dist3 lower in terms of sumco */
219  /* and advance the overall lower bound, applicable to all remaining vertices as well. */
220  while ((i_target_low_bound < target_num_verts) &&
221  (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) {
222  i_target_low_bound++;
223  sve_target_low_bound++;
224  }
225  /* If end of target list reached, then no more possible doubles */
226  if (i_target_low_bound >= target_num_verts) {
227  doubles_map[sve_source->vertex_num] = -1;
228  target_scan_completed = true;
229  continue;
230  }
231  /* Test target candidates starting at the low bound of possible doubles,
232  * ordered in terms of sumco. */
233  i_target = i_target_low_bound;
234  sve_target = sve_target_low_bound;
235 
236  /* i_target will scan vertices in the
237  * [v_source_sumco - dist3; v_source_sumco + dist3] range */
238 
239  while ((i_target < target_num_verts) && (sve_target->sum_co <= sve_source_sumco + dist3)) {
240  /* Testing distance for candidate double in target */
241  /* v_target is within dist3 of v_source in terms of sumco; check real distance */
242  float dist_sq;
243  if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) {
244  /* Potential double found */
245  best_dist_sq = dist_sq;
246  best_target_vertex = sve_target->vertex_num;
247 
248  /* If target is already mapped, we only follow that mapping if final target remains
249  * close enough from current vert (otherwise no mapping at all).
250  * Note that if we later find another target closer than this one, then we check it.
251  * But if other potential targets are farther,
252  * then there will be no mapping at all for this source. */
253  while (best_target_vertex != -1 &&
254  !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) {
255  if (compare_len_v3v3(mverts[sve_source->vertex_num].co,
256  mverts[doubles_map[best_target_vertex]].co,
257  dist)) {
258  best_target_vertex = doubles_map[best_target_vertex];
259  }
260  else {
261  best_target_vertex = -1;
262  }
263  }
264  }
265  i_target++;
266  sve_target++;
267  }
268  /* End of candidate scan: if none found then no doubles */
269  doubles_map[sve_source->vertex_num] = best_target_vertex;
270  }
271 
272  MEM_freeN(sorted_verts_source);
273  MEM_freeN(sorted_verts_target);
274 }
275 
277  Mesh *cap_mesh,
278  const float cap_offset[4][4],
279  uint cap_verts_index,
280  uint cap_edges_index,
281  int cap_loops_index,
282  int cap_polys_index,
283  int cap_nverts,
284  int cap_nedges,
285  int cap_nloops,
286  int cap_npolys,
287  int *remap,
288  int remap_len,
289  const bool recalc_normals_later)
290 {
291  int *index_orig;
292  int i;
293  MVert *mv;
294  MEdge *me;
295  MLoop *ml;
296  MPoly *mp;
297 
298  CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts);
299  CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges);
300  CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops);
301  CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys);
302 
303  mv = result->mvert + cap_verts_index;
304 
305  for (i = 0; i < cap_nverts; i++, mv++) {
306  mul_m4_v3(cap_offset, mv->co);
307  /* Reset MVert flags for caps */
308  mv->flag = mv->bweight = 0;
309 
310  /* We have to correct normals too, if we do not tag them as dirty later! */
311  if (!recalc_normals_later) {
312  float no[3];
313  normal_short_to_float_v3(no, mv->no);
314  mul_mat3_m4_v3(cap_offset, no);
315  normalize_v3(no);
316  normal_float_to_short_v3(mv->no, no);
317  }
318  }
319 
320  /* remap the vertex groups if necessary */
321  if (result->dvert != NULL) {
323  &result->dvert[cap_verts_index], cap_nverts, remap, remap_len);
324  }
325 
326  /* adjust cap edge vertex indices */
327  me = result->medge + cap_edges_index;
328  for (i = 0; i < cap_nedges; i++, me++) {
329  me->v1 += cap_verts_index;
330  me->v2 += cap_verts_index;
331  }
332 
333  /* adjust cap poly loopstart indices */
334  mp = result->mpoly + cap_polys_index;
335  for (i = 0; i < cap_npolys; i++, mp++) {
336  mp->loopstart += cap_loops_index;
337  }
338 
339  /* adjust cap loop vertex and edge indices */
340  ml = result->mloop + cap_loops_index;
341  for (i = 0; i < cap_nloops; i++, ml++) {
342  ml->v += cap_verts_index;
343  ml->e += cap_edges_index;
344  }
345 
346  /* set origindex */
347  index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
348  if (index_orig) {
349  copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
350  }
351 
352  index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
353  if (index_orig) {
354  copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
355  }
356 
357  index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
358  if (index_orig) {
359  copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
360  }
361 
362  index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX);
363  if (index_orig) {
364  copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
365  }
366 }
367 
369  const ModifierEvalContext *ctx,
370  Mesh *mesh)
371 {
372  const MVert *src_mvert;
373  MVert *mv, *mv_prev, *result_dm_verts;
374 
375  MEdge *me;
376  MLoop *ml;
377  MPoly *mp;
378  int i, j, c, count;
379  float length = amd->length;
380  /* offset matrix */
381  float offset[4][4];
382  float scale[3];
383  bool offset_has_scale;
384  float current_offset[4][4];
385  float final_offset[4][4];
386  int *full_doubles_map = NULL;
387  int tot_doubles;
388 
389  const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
390  const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge;
391  const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob != NULL);
392 
393  int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
394  int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
395  int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0;
396  int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
397  int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
398 
399  Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL;
400 
401  int *vgroup_start_cap_remap = NULL;
402  int vgroup_start_cap_remap_len = 0;
403  int *vgroup_end_cap_remap = NULL;
404  int vgroup_end_cap_remap_len = 0;
405 
406  chunk_nverts = mesh->totvert;
407  chunk_nedges = mesh->totedge;
408  chunk_nloops = mesh->totloop;
409  chunk_npolys = mesh->totpoly;
410 
411  count = amd->count;
412 
413  Object *start_cap_ob = amd->start_cap;
414  if (start_cap_ob && start_cap_ob != ctx->object) {
415  vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
416  start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
417 
418  start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false);
419  if (start_cap_mesh) {
420  start_cap_nverts = start_cap_mesh->totvert;
421  start_cap_nedges = start_cap_mesh->totedge;
422  start_cap_nloops = start_cap_mesh->totloop;
423  start_cap_npolys = start_cap_mesh->totpoly;
424  }
425  }
426  Object *end_cap_ob = amd->end_cap;
427  if (end_cap_ob && end_cap_ob != ctx->object) {
428  vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
429  end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
430 
431  end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false);
432  if (end_cap_mesh) {
433  end_cap_nverts = end_cap_mesh->totvert;
434  end_cap_nedges = end_cap_mesh->totedge;
435  end_cap_nloops = end_cap_mesh->totloop;
436  end_cap_npolys = end_cap_mesh->totpoly;
437  }
438  }
439 
440  /* Build up offset array, cumulating all settings options */
441 
442  unit_m4(offset);
443  src_mvert = mesh->mvert;
444 
445  if (amd->offset_type & MOD_ARR_OFF_CONST) {
446  add_v3_v3(offset[3], amd->offset);
447  }
448 
449  if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
450  float min[3], max[3];
451  const MVert *src_mv;
452 
453  INIT_MINMAX(min, max);
454  for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
455  minmax_v3v3_v3(min, max, src_mv->co);
456  }
457 
458  for (j = 3; j--;) {
459  offset[3][j] += amd->scale[j] * (max[j] - min[j]);
460  }
461  }
462 
463  if (use_offset_ob) {
464  float obinv[4][4];
465  float result_mat[4][4];
466 
467  if (ctx->object) {
468  invert_m4_m4(obinv, ctx->object->obmat);
469  }
470  else {
471  unit_m4(obinv);
472  }
473 
474  mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat);
475  copy_m4_m4(offset, result_mat);
476  }
477 
478  /* Check if there is some scaling. If scaling, then we will not translate mapping */
479  mat4_to_size(scale, offset);
480  offset_has_scale = !is_one_v3(scale);
481 
482  if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob != NULL) {
483  Object *curve_ob = amd->curve_ob;
484  CurveCache *curve_cache = curve_ob->runtime.curve_cache;
485  if (curve_cache != NULL && curve_cache->anim_path_accum_length != NULL) {
486  float scale_fac = mat4_to_scale(curve_ob->obmat);
487  length = scale_fac * BKE_anim_path_get_length(curve_cache);
488  }
489  }
490 
491  /* About 67 million vertices max seems a decent limit for now. */
492  const size_t max_num_vertices = 1 << 26;
493 
494  /* calculate the maximum number of copies which will fit within the
495  * prescribed length */
497  const float float_epsilon = 1e-6f;
498  bool offset_is_too_small = false;
499  float dist = len_v3(offset[3]);
500 
501  if (dist > float_epsilon) {
502  /* this gives length = first copy start to last copy end
503  * add a tiny offset for floating point rounding errors */
504  count = (length + float_epsilon) / dist + 1;
505 
506  /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated
507  * vertices.
508  */
509  if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts +
510  (size_t)end_cap_nverts) > max_num_vertices) {
511  count = 1;
512  offset_is_too_small = true;
513  }
514  }
515  else {
516  /* if the offset has no translation, just make one copy */
517  count = 1;
518  offset_is_too_small = true;
519  }
520 
521  if (offset_is_too_small) {
523  ctx->object,
524  &amd->modifier,
525  "The offset is too small, we cannot generate the amount of geometry it would require");
526  }
527  }
528  /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated
529  * vertices.
530  */
531  else if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts +
532  (size_t)end_cap_nverts) > max_num_vertices) {
533  count = 1;
535  &amd->modifier,
536  "The amount of copies is too high, we cannot generate the amount of "
537  "geometry it would require");
538  }
539 
540  if (count < 1) {
541  count = 1;
542  }
543 
544  /* The number of verts, edges, loops, polys, before eventually merging doubles */
545  result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts;
546  result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges;
547  result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops;
548  result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;
549 
550  /* Initialize a result dm */
552  mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
553  result_dm_verts = result->mvert;
554 
555  if (use_merge) {
556  /* Will need full_doubles_map for handling merge */
557  full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map");
558  copy_vn_i(full_doubles_map, result_nverts, -1);
559  }
560 
561  /* copy customdata to original geometry */
562  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts);
563  CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges);
564  CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops);
565  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys);
566 
567  /* Subsurf for eg won't have mesh data in the custom data arrays.
568  * now add mvert/medge/mpoly layers. */
569  if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
570  memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
571  }
572  if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
573  memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
574  }
575  if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
576  memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
577  memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
578  }
579 
580  /* Remember first chunk, in case of cap merge */
581  first_chunk_start = 0;
582  first_chunk_nverts = chunk_nverts;
583 
584  unit_m4(current_offset);
585  for (c = 1; c < count; c++) {
586  /* copy customdata to new geometry */
587  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
588  CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges);
589  CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
590  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
591 
592  mv_prev = result_dm_verts;
593  mv = mv_prev + c * chunk_nverts;
594 
595  /* recalculate cumulative offset here */
596  mul_m4_m4m4(current_offset, current_offset, offset);
597 
598  /* apply offset to all new verts */
599  for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
600  mul_m4_v3(current_offset, mv->co);
601 
602  /* We have to correct normals too, if we do not tag them as dirty! */
603  if (!use_recalc_normals) {
604  float no[3];
605  normal_short_to_float_v3(no, mv->no);
606  mul_mat3_m4_v3(current_offset, no);
607  normalize_v3(no);
608  normal_float_to_short_v3(mv->no, no);
609  }
610  }
611 
612  /* adjust edge vertex indices */
613  me = result->medge + c * chunk_nedges;
614  for (i = 0; i < chunk_nedges; i++, me++) {
615  me->v1 += c * chunk_nverts;
616  me->v2 += c * chunk_nverts;
617  }
618 
619  mp = result->mpoly + c * chunk_npolys;
620  for (i = 0; i < chunk_npolys; i++, mp++) {
621  mp->loopstart += c * chunk_nloops;
622  }
623 
624  /* adjust loop vertex and edge indices */
625  ml = result->mloop + c * chunk_nloops;
626  for (i = 0; i < chunk_nloops; i++, ml++) {
627  ml->v += c * chunk_nverts;
628  ml->e += c * chunk_nedges;
629  }
630 
631  /* Handle merge between chunk n and n-1 */
632  if (use_merge && (c >= 1)) {
633  if (!offset_has_scale && (c >= 2)) {
634  /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
635  * ... that is except if scaling makes the distance grow */
636  int k;
637  int this_chunk_index = c * chunk_nverts;
638  int prev_chunk_index = (c - 1) * chunk_nverts;
639  for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
640  int target = full_doubles_map[prev_chunk_index];
641  if (target != -1) {
642  target += chunk_nverts; /* translate mapping */
643  while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) {
644  /* If target is already mapped, we only follow that mapping if final target remains
645  * close enough from current vert (otherwise no mapping at all). */
646  if (compare_len_v3v3(result_dm_verts[this_chunk_index].co,
647  result_dm_verts[full_doubles_map[target]].co,
648  amd->merge_dist)) {
649  target = full_doubles_map[target];
650  }
651  else {
652  target = -1;
653  }
654  }
655  }
656  full_doubles_map[this_chunk_index] = target;
657  }
658  }
659  else {
660  dm_mvert_map_doubles(full_doubles_map,
661  result_dm_verts,
662  (c - 1) * chunk_nverts,
663  chunk_nverts,
664  c * chunk_nverts,
665  chunk_nverts,
666  amd->merge_dist);
667  }
668  }
669  }
670 
671  /* handle UVs */
672  if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
673  const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
674  for (i = 0; i < totuv; i++) {
675  MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i);
676  dmloopuv += chunk_nloops;
677  for (c = 1; c < count; c++) {
678  const float uv_offset[2] = {
679  amd->uv_offset[0] * (float)c,
680  amd->uv_offset[1] * (float)c,
681  };
682  int l_index = chunk_nloops;
683  for (; l_index-- != 0; dmloopuv++) {
684  dmloopuv->uv[0] += uv_offset[0];
685  dmloopuv->uv[1] += uv_offset[1];
686  }
687  }
688  }
689  }
690 
691  last_chunk_start = (count - 1) * chunk_nverts;
692  last_chunk_nverts = chunk_nverts;
693 
694  copy_m4_m4(final_offset, current_offset);
695 
696  if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) {
697  /* Merge first and last copies */
698  dm_mvert_map_doubles(full_doubles_map,
699  result_dm_verts,
700  last_chunk_start,
701  last_chunk_nverts,
702  first_chunk_start,
703  first_chunk_nverts,
704  amd->merge_dist);
705  }
706 
707  /* start capping */
708  if (start_cap_mesh) {
709  float start_offset[4][4];
710  int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
711  invert_m4_m4(start_offset, offset);
713  start_cap_mesh,
714  start_offset,
715  result_nverts - start_cap_nverts - end_cap_nverts,
716  result_nedges - start_cap_nedges - end_cap_nedges,
717  result_nloops - start_cap_nloops - end_cap_nloops,
718  result_npolys - start_cap_npolys - end_cap_npolys,
719  start_cap_nverts,
720  start_cap_nedges,
721  start_cap_nloops,
722  start_cap_npolys,
723  vgroup_start_cap_remap,
724  vgroup_start_cap_remap_len,
725  use_recalc_normals);
726  /* Identify doubles with first chunk */
727  if (use_merge) {
728  dm_mvert_map_doubles(full_doubles_map,
729  result_dm_verts,
730  first_chunk_start,
731  first_chunk_nverts,
732  start_cap_start,
733  start_cap_nverts,
734  amd->merge_dist);
735  }
736  }
737 
738  if (end_cap_mesh) {
739  float end_offset[4][4];
740  int end_cap_start = result_nverts - end_cap_nverts;
741  mul_m4_m4m4(end_offset, current_offset, offset);
743  end_cap_mesh,
744  end_offset,
745  result_nverts - end_cap_nverts,
746  result_nedges - end_cap_nedges,
747  result_nloops - end_cap_nloops,
748  result_npolys - end_cap_npolys,
749  end_cap_nverts,
750  end_cap_nedges,
751  end_cap_nloops,
752  end_cap_npolys,
753  vgroup_end_cap_remap,
754  vgroup_end_cap_remap_len,
755  use_recalc_normals);
756  /* Identify doubles with last chunk */
757  if (use_merge) {
758  dm_mvert_map_doubles(full_doubles_map,
759  result_dm_verts,
760  last_chunk_start,
761  last_chunk_nverts,
762  end_cap_start,
763  end_cap_nverts,
764  amd->merge_dist);
765  }
766  }
767  /* done capping */
768 
769  /* Handle merging */
770  tot_doubles = 0;
771  if (use_merge) {
772  for (i = 0; i < result_nverts; i++) {
773  int new_i = full_doubles_map[i];
774  if (new_i != -1) {
775  /* We have to follow chains of doubles
776  * (merge start/end especially is likely to create some),
777  * those are not supported at all by BKE_mesh_merge_verts! */
778  while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
779  new_i = full_doubles_map[new_i];
780  }
781  if (i == new_i) {
782  full_doubles_map[i] = -1;
783  }
784  else {
785  full_doubles_map[i] = new_i;
786  tot_doubles++;
787  }
788  }
789  }
790  if (tot_doubles > 0) {
792  result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL);
793  }
794  MEM_freeN(full_doubles_map);
795  }
796 
797  /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh!
798  * TODO: we may need to set other dirty flags as well?
799  */
800  if (use_recalc_normals) {
801  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
802  }
803 
804  if (vgroup_start_cap_remap) {
805  MEM_freeN(vgroup_start_cap_remap);
806  }
807  if (vgroup_end_cap_remap) {
808  MEM_freeN(vgroup_end_cap_remap);
809  }
810 
811  return result;
812 }
813 
815 {
817  return arrayModifier_doArray(amd, ctx, mesh);
818 }
819 
820 static bool isDisabled(const struct Scene *UNUSED(scene),
821  ModifierData *md,
822  bool UNUSED(useRenderParams))
823 {
825 
826  /* The object type check is only needed here in case we have a placeholder
827  * object assigned (because the library containing the curve/mesh is missing).
828  *
829  * In other cases it should be impossible to have a type mismatch.
830  */
831 
832  if (amd->curve_ob && amd->curve_ob->type != OB_CURVE) {
833  return true;
834  }
835  if (amd->start_cap && amd->start_cap->type != OB_MESH) {
836  return true;
837  }
838  if (amd->end_cap && amd->end_cap->type != OB_MESH) {
839  return true;
840  }
841 
842  return false;
843 }
844 
845 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
846 {
847  uiLayout *layout = panel->layout;
848 
849  PointerRNA ob_ptr;
851 
852  uiLayoutSetPropSep(layout, true);
853 
854  uiItemR(layout, ptr, "fit_type", 0, NULL, ICON_NONE);
855 
856  int fit_type = RNA_enum_get(ptr, "fit_type");
857  if (fit_type == MOD_ARR_FIXEDCOUNT) {
858  uiItemR(layout, ptr, "count", 0, NULL, ICON_NONE);
859  }
860  else if (fit_type == MOD_ARR_FITLENGTH) {
861  uiItemR(layout, ptr, "fit_length", 0, NULL, ICON_NONE);
862  }
863  else if (fit_type == MOD_ARR_FITCURVE) {
864  uiItemR(layout, ptr, "curve", 0, NULL, ICON_NONE);
865  }
866 
867  modifier_panel_end(layout, ptr);
868 }
869 
870 static void relative_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
871 {
872  uiLayout *layout = panel->layout;
873 
875 
876  uiItemR(layout, ptr, "use_relative_offset", 0, NULL, ICON_NONE);
877 }
878 
879 static void relative_offset_draw(const bContext *UNUSED(C), Panel *panel)
880 {
881  uiLayout *layout = panel->layout;
882 
884 
885  uiLayoutSetPropSep(layout, true);
886 
887  uiLayout *col = uiLayoutColumn(layout, false);
888 
889  uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_relative_offset"));
890  uiItemR(col, ptr, "relative_offset_displace", 0, IFACE_("Factor"), ICON_NONE);
891 }
892 
893 static void constant_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
894 {
895  uiLayout *layout = panel->layout;
896 
898 
899  uiItemR(layout, ptr, "use_constant_offset", 0, NULL, ICON_NONE);
900 }
901 
902 static void constant_offset_draw(const bContext *UNUSED(C), Panel *panel)
903 {
904  uiLayout *layout = panel->layout;
905 
907 
908  uiLayoutSetPropSep(layout, true);
909 
910  uiLayout *col = uiLayoutColumn(layout, false);
911 
912  uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_constant_offset"));
913  uiItemR(col, ptr, "constant_offset_displace", 0, IFACE_("Distance"), ICON_NONE);
914 }
915 
919 static void object_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
920 {
921  uiLayout *layout = panel->layout;
922 
924 
925  uiItemR(layout, ptr, "use_object_offset", 0, NULL, ICON_NONE);
926 }
927 
928 static void object_offset_draw(const bContext *UNUSED(C), Panel *panel)
929 {
930  uiLayout *layout = panel->layout;
931 
933 
934  uiLayoutSetPropSep(layout, true);
935 
936  uiLayout *col = uiLayoutColumn(layout, false);
937 
938  uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_object_offset"));
939  uiItemR(col, ptr, "offset_object", 0, IFACE_("Object"), ICON_NONE);
940 }
941 
942 static void symmetry_panel_header_draw(const bContext *UNUSED(C), Panel *panel)
943 {
944  uiLayout *layout = panel->layout;
945 
947 
948  uiItemR(layout, ptr, "use_merge_vertices", 0, IFACE_("Merge"), ICON_NONE);
949 }
950 
951 static void symmetry_panel_draw(const bContext *UNUSED(C), Panel *panel)
952 {
953  uiLayout *layout = panel->layout;
954 
956 
957  uiLayoutSetPropSep(layout, true);
958 
959  uiLayout *col = uiLayoutColumn(layout, false);
960  uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_merge_vertices"));
961  uiItemR(col, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
962  uiItemR(col, ptr, "use_merge_vertices_cap", 0, IFACE_("First and Last Copies"), ICON_NONE);
963 }
964 
965 static void uv_panel_draw(const bContext *UNUSED(C), Panel *panel)
966 {
967  uiLayout *col;
968  uiLayout *layout = panel->layout;
969 
971 
972  uiLayoutSetPropSep(layout, true);
973 
974  col = uiLayoutColumn(layout, true);
975  uiItemR(col, ptr, "offset_u", UI_ITEM_R_EXPAND, IFACE_("Offset U"), ICON_NONE);
976  uiItemR(col, ptr, "offset_v", UI_ITEM_R_EXPAND, IFACE_("V"), ICON_NONE);
977 }
978 
979 static void caps_panel_draw(const bContext *UNUSED(C), Panel *panel)
980 {
981  uiLayout *col;
982  uiLayout *layout = panel->layout;
983 
985 
986  uiLayoutSetPropSep(layout, true);
987 
988  col = uiLayoutColumn(layout, false);
989  uiItemR(col, ptr, "start_cap", 0, IFACE_("Cap Start"), ICON_NONE);
990  uiItemR(col, ptr, "end_cap", 0, IFACE_("End"), ICON_NONE);
991 }
992 
993 static void panelRegister(ARegionType *region_type)
994 {
996  modifier_subpanel_register(region_type,
997  "relative_offset",
998  "",
1001  panel_type);
1002  modifier_subpanel_register(region_type,
1003  "constant_offset",
1004  "",
1007  panel_type);
1009  region_type, "object_offset", "", object_offset_header_draw, object_offset_draw, panel_type);
1011  region_type, "merge", "", symmetry_panel_header_draw, symmetry_panel_draw, panel_type);
1012  modifier_subpanel_register(region_type, "uv", "UVs", NULL, uv_panel_draw, panel_type);
1013  modifier_subpanel_register(region_type, "caps", "Caps", NULL, caps_panel_draw, panel_type);
1014 }
1015 
1017  /* name */ "Array",
1018  /* structName */ "ArrayModifierData",
1019  /* structSize */ sizeof(ArrayModifierData),
1020  /* srna */ &RNA_ArrayModifier,
1021  /* type */ eModifierTypeType_Constructive,
1025  /* icon */ ICON_MOD_ARRAY,
1026 
1027  /* copyData */ BKE_modifier_copydata_generic,
1028 
1029  /* deformVerts */ NULL,
1030  /* deformMatrices */ NULL,
1031  /* deformVertsEM */ NULL,
1032  /* deformMatricesEM */ NULL,
1033  /* modifyMesh */ modifyMesh,
1034  /* modifyHair */ NULL,
1035  /* modifyGeometrySet */ NULL,
1036  /* modifyVolume */ NULL,
1037 
1038  /* initData */ initData,
1039  /* requiredDataMask */ NULL,
1040  /* freeData */ NULL,
1041  /* isDisabled */ isDisabled,
1042  /* updateDepsgraph */ updateDepsgraph,
1043  /* dependsOnTime */ NULL,
1044  /* dependsOnNormals */ NULL,
1045  /* foreachIDLink */ foreachIDLink,
1046  /* foreachTexLink */ NULL,
1047  /* freeRuntimeData */ NULL,
1048  /* panelRegister */ panelRegister,
1049  /* blendWrite */ NULL,
1050  /* blendRead */ NULL,
1051 };
typedef float(TangentPoint)[2]
float BKE_anim_path_get_length(const struct CurveCache *curve_cache)
int CustomData_number_of_layers(const struct CustomData *data, int type)
bool CustomData_has_layer(const struct CustomData *data, int type)
#define ORIGINDEX_NONE
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void * CustomData_get_layer(const struct CustomData *data, int type)
void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
display list (or rather multi purpose list) stuff.
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:47
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
@ MESH_MERGE_VERTS_DUMP_IF_EQUAL
Definition: BKE_mesh.h:586
struct Mesh * BKE_mesh_merge_verts(struct Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
Definition: mesh_merge.c:239
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
@ eModifierTypeFlag_AcceptsCVs
Definition: BKE_modifier.h:81
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:82
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:92
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:61
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh)
Functions for dealing with objects and deform verts, used by painting and tools.
int * BKE_object_defgroup_index_map_create(struct Object *ob_src, struct Object *ob_dst, int *r_map_len)
void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert, int dvert_len, const int *map, int map_len)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
#define M_SQRT3
Definition: BLI_math_base.h:53
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
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
#define mul_m4_series(...)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2196
void mat4_to_size(float size[3], const float M[4][4])
Definition: math_matrix.c:2145
MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:1020
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void normal_short_to_float_v3(float r[3], const short n[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_one_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:83
#define INIT_MINMAX(min, max)
#define UNUSED(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
@ DAG_EVAL_NEED_CURVE_PATH
Definition: DEG_depsgraph.h:70
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
void DEG_add_special_eval_flag(struct DepsNodeHandle *handle, struct ID *id, uint32_t flag)
#define CD_MASK_NORMAL
@ CD_ORIGINDEX
@ CD_MVERT
@ CD_MLOOPUV
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ MOD_ARR_MERGE
@ MOD_ARR_MERGEFINAL
struct ArrayModifierData ArrayModifierData
@ eModifierType_Array
@ MOD_ARR_OFF_RELATIVE
@ MOD_ARR_OFF_CONST
@ MOD_ARR_OFF_OBJ
@ MOD_ARR_FITCURVE
@ MOD_ARR_FIXEDCOUNT
@ MOD_ARR_FITLENGTH
Object is a sort of wrapper for general info.
@ OB_MESH
@ OB_CURVE
@ UI_PANEL_DATA_EXPAND_ROOT
@ UI_SUBPANEL_DATA_EXPAND_1
Read Guarded memory(de)allocation.
static void uv_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:965
static void constant_offset_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:902
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_array.c:814
static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_begin, const int i_end)
Definition: MOD_array.c:142
static void symmetry_panel_header_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:942
static void relative_offset_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:879
static int svert_sum_cmp(const void *e1, const void *e2)
Definition: MOD_array.c:127
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_array.c:87
static void relative_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:870
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
Definition: MOD_array.c:820
ModifierTypeInfo modifierType_Array
Definition: MOD_array.c:1016
static void constant_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:893
static void object_offset_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:928
static void mesh_merge_transform(Mesh *result, Mesh *cap_mesh, const float cap_offset[4][4], uint cap_verts_index, uint cap_edges_index, int cap_loops_index, int cap_polys_index, int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len, const bool recalc_normals_later)
Definition: MOD_array.c:276
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_array.c:77
struct SortVertsElem SortVertsElem
static Mesh * arrayModifier_doArray(ArrayModifierData *amd, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_array.c:368
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:845
BLI_INLINE float sum_v3(const float v[3])
Definition: MOD_array.c:115
static void initData(ModifierData *md)
Definition: MOD_array.c:64
static void panelRegister(ARegionType *region_type)
Definition: MOD_array.c:993
static void symmetry_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:951
static void caps_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:979
static void dm_mvert_map_doubles(int *doubles_map, const MVert *mverts, const int target_start, const int target_num_verts, const int source_start, const int source_num_verts, const float dist)
Definition: MOD_array.c:162
static void object_offset_header_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_array.c:919
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
StructRNA RNA_ArrayModifier
#define C
Definition: RandGen.cpp:39
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_ITEM_R_EXPAND
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
Scene scene
uint col
int count
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
static unsigned c
Definition: RandGen.cpp:97
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
#define min(a, b)
Definition: sort.c:51
struct Object * start_cap
struct Object * offset_ob
struct Object * curve_ob
struct Object * end_cap
const float * anim_path_accum_length
Definition: BKE_curve.h:58
Definition: DNA_ID.h:273
unsigned int v1
unsigned int v2
unsigned int e
unsigned int v
float co[3]
int64_t cd_dirty_vert
struct MEdge * medge
struct CustomData pdata ldata
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
struct Object * object
Definition: BKE_modifier.h:154
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
struct CurveCache * curve_cache
Object_Runtime runtime
float obmat[4][4]
struct uiLayout * layout
float co[3]
Definition: MOD_array.c:123
float sum_co
Definition: MOD_array.c:124
float max
PointerRNA * ptr
Definition: wm_files.c:3157