Blender  V3.3
uvedit_islands.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
14 #include "MEM_guardedalloc.h"
15 
16 #include "DNA_meshdata_types.h"
17 #include "DNA_scene_types.h"
18 #include "DNA_space_types.h"
19 
20 #include "BLI_boxpack_2d.h"
21 #include "BLI_convexhull_2d.h"
22 #include "BLI_listbase.h"
23 #include "BLI_math.h"
24 #include "BLI_rect.h"
25 
26 #include "BKE_customdata.h"
27 #include "BKE_editmesh.h"
28 #include "BKE_image.h"
29 
30 #include "DEG_depsgraph.h"
31 
32 #include "ED_uvedit.h" /* Own include. */
33 
34 #include "WM_api.h"
35 #include "WM_types.h"
36 
37 #include "bmesh.h"
38 
39 /* -------------------------------------------------------------------- */
43 static void bm_face_uv_scale_y(BMFace *f, const float scale_y, const int cd_loop_uv_offset)
44 {
45  BMLoop *l_iter;
46  BMLoop *l_first;
47  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
48  do {
49  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
50  luv->uv[1] *= scale_y;
51  } while ((l_iter = l_iter->next) != l_first);
52 }
53 
55  const float offset[2],
56  const float scale[2],
57  const float pivot[2],
58  const int cd_loop_uv_offset)
59 {
60  BMLoop *l_iter;
61  BMLoop *l_first;
62  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
63  do {
64  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
65  for (int i = 0; i < 2; i++) {
66  luv->uv[i] = offset[i] + (((luv->uv[i] - pivot[i]) * scale[i]) + pivot[i]);
67  }
68  } while ((l_iter = l_iter->next) != l_first);
69 }
70 
73 /* -------------------------------------------------------------------- */
78  int faces_len,
79  const uint cd_loop_uv_offset,
80  rctf *r_bounds_rect)
81 {
82  float bounds_min[2], bounds_max[2];
83  INIT_MINMAX2(bounds_min, bounds_max);
84  for (int i = 0; i < faces_len; i++) {
85  BMFace *f = faces[i];
86  BM_face_uv_minmax(f, bounds_min, bounds_max, cd_loop_uv_offset);
87  }
88  r_bounds_rect->xmin = bounds_min[0];
89  r_bounds_rect->ymin = bounds_min[1];
90  r_bounds_rect->xmax = bounds_max[0];
91  r_bounds_rect->ymax = bounds_max[1];
92 }
93 
99  BMFace **faces, int faces_len, const uint cd_loop_uv_offset, int *r_coords_len))[2]
100 {
101  int coords_len_alloc = 0;
102  for (int i = 0; i < faces_len; i++) {
103  BMFace *f = faces[i];
104  BMLoop *l_iter, *l_first;
105  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
106  do {
108  } while ((l_iter = l_iter->next) != l_first);
109  coords_len_alloc += f->len;
110  }
111 
112  float(*coords)[2] = MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__);
113  int coords_len = 0;
114 
115  for (int i = 0; i < faces_len; i++) {
116  BMFace *f = faces[i];
117  BMLoop *l_iter, *l_first;
118  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
119  do {
120  if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
121  /* Already walked over, continue. */
122  continue;
123  }
124 
126  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
127  copy_v2_v2(coords[coords_len++], luv->uv);
128 
129  /* Un tag all connected so we don't add them twice.
130  * Note that we will tag other loops not part of `faces` but this is harmless,
131  * since we're only turning off a tag. */
132  BMVert *v_pivot = l_iter->v;
133  BMEdge *e_first = v_pivot->e;
134  const BMEdge *e = e_first;
135  do {
136  if (e->l != NULL) {
137  const BMLoop *l_radial = e->l;
138  do {
139  if (l_radial->v == l_iter->v) {
140  if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) {
141  const MLoopUV *luv_radial = BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset);
142  if (equals_v2v2(luv->uv, luv_radial->uv)) {
143  /* Don't add this UV when met in another face in `faces`. */
145  }
146  }
147  }
148  } while ((l_radial = l_radial->radial_next) != e->l);
149  }
150  } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first);
151  } while ((l_iter = l_iter->next) != l_first);
152  }
153  coords = MEM_reallocN(coords, sizeof(*coords) * coords_len);
154  *r_coords_len = coords_len;
155  return coords;
156 }
157 
165  int faces_len,
166  int align_to_axis,
167  const uint cd_loop_uv_offset)
168 {
169  /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */
170  int coords_len;
172  faces, faces_len, cd_loop_uv_offset, &coords_len);
173 
174  float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len);
175 
176  if (align_to_axis != -1) {
177  if (angle != 0.0f) {
178  float matrix[2][2];
179  angle_to_mat2(matrix, angle);
180  for (int i = 0; i < coords_len; i++) {
181  mul_m2_v2(matrix, coords[i]);
182  }
183  }
184 
185  float bounds_min[2], bounds_max[2];
186  INIT_MINMAX2(bounds_min, bounds_max);
187  for (int i = 0; i < coords_len; i++) {
188  minmax_v2v2_v2(bounds_min, bounds_max, coords[i]);
189  }
190 
191  float size[2];
192  sub_v2_v2v2(size, bounds_max, bounds_min);
193  if (align_to_axis ? (size[1] < size[0]) : (size[0] < size[1])) {
194  angle += DEG2RAD(90.0);
195  }
196  }
197 
198  MEM_freeN(coords);
199 
200  if (angle != 0.0f) {
201  float matrix[2][2];
202  angle_to_mat2(matrix, angle);
203  for (int i = 0; i < faces_len; i++) {
204  BM_face_uv_transform(faces[i], matrix, cd_loop_uv_offset);
205  }
206  }
207 }
208 
210  int faces_len,
211  const float scale_y,
212  const uint cd_loop_uv_offset)
213 {
214  for (int i = 0; i < faces_len; i++) {
215  BMFace *f = faces[i];
216  bm_face_uv_scale_y(f, scale_y, cd_loop_uv_offset);
217  }
218 }
219 
222 /* -------------------------------------------------------------------- */
226 bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const float coords[2])
227 {
228  const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])};
229  const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
230 
231  if (coords[0] < udim_grid[0] && coords[0] > 0 && coords[1] < udim_grid[1] && coords[1] > 0) {
232  return true;
233  }
234  /* Check if selection lies on a valid UDIM image tile. */
235  if (is_tiled_image) {
236  LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
237  const int tile_index = tile->tile_number - 1001;
238  const int target_x = (tile_index % 10);
239  const int target_y = (tile_index / 10);
240  if (coords_floor[0] == target_x && coords_floor[1] == target_y) {
241  return true;
242  }
243  }
244  }
245  /* Probably not required since UDIM grid checks for 1001. */
246  else if (image && !is_tiled_image) {
247  if (is_zero_v2(coords_floor)) {
248  return true;
249  }
250  }
251 
252  return false;
253 }
254 
259  const float coords[2],
260  float nearest_tile_co[2])
261 {
262  if (BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co) == -1) {
263  zero_v2(nearest_tile_co);
264  }
265  /* Add 0.5 to get tile center coordinates. */
266  float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]};
267  add_v2_fl(nearest_tile_center_co, 0.5f);
268 
269  return len_squared_v2v2(coords, nearest_tile_center_co);
270 }
271 
275 static float uv_nearest_grid_tile_distance(const int udim_grid[2],
276  float coords[2],
277  float nearest_tile_co[2])
278 {
279  const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])};
280 
281  if (coords[0] > udim_grid[0]) {
282  nearest_tile_co[0] = udim_grid[0] - 1;
283  }
284  else if (coords[0] < 0) {
285  nearest_tile_co[0] = 0;
286  }
287  else {
288  nearest_tile_co[0] = coords_floor[0];
289  }
290 
291  if (coords[1] > udim_grid[1]) {
292  nearest_tile_co[1] = udim_grid[1] - 1;
293  }
294  else if (coords[1] < 0) {
295  nearest_tile_co[1] = 0;
296  }
297  else {
298  nearest_tile_co[1] = coords_floor[1];
299  }
300 
301  /* Add 0.5 to get tile center coordinates. */
302  float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]};
303  add_v2_fl(nearest_tile_center_co, 0.5f);
304 
305  return len_squared_v2v2(coords, nearest_tile_center_co);
306 }
307 
310 /* -------------------------------------------------------------------- */
316 struct FaceIsland {
317  struct FaceIsland *next, *prev;
326  float aspect_y;
327 };
328 
331  bool use_seams;
332 };
333 
334 static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, void *user_data)
335 {
336  const struct SharedUVLoopData *data = user_data;
337 
338  if (data->use_seams) {
339  if (BM_elem_flag_test(l_a->e, BM_ELEM_SEAM)) {
340  return false;
341  }
342  }
343 
344  return BM_loop_uv_share_edge_check((BMLoop *)l_a, (BMLoop *)l_b, data->cd_loop_uv_offset);
345 }
346 
351  BMesh *bm,
352  ListBase *island_list,
353  const bool only_selected_faces,
354  const bool only_selected_uvs,
355  const bool use_seams,
356  const float aspect_y,
357  const uint cd_loop_uv_offset)
358 {
359  int island_added = 0;
361 
362  struct SharedUVLoopData user_data = {
363  .cd_loop_uv_offset = cd_loop_uv_offset,
364  .use_seams = use_seams,
365  };
366 
367  int *groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
368 
369  int(*group_index)[2];
370 
371  /* Calculate the tag to use. */
372  uchar hflag_face_test = 0;
373  if (only_selected_faces) {
374  if (only_selected_uvs) {
375  BMFace *f;
376  BMIter iter;
377  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
378  bool value = false;
381  value = true;
382  }
383  BM_elem_flag_set(f, BM_ELEM_TAG, value);
384  }
385  hflag_face_test = BM_ELEM_TAG;
386  }
387  else {
388  hflag_face_test = BM_ELEM_SELECT;
389  }
390  }
391 
392  const int group_len = BM_mesh_calc_face_groups(bm,
393  groups_array,
394  &group_index,
395  NULL,
397  &user_data,
398  hflag_face_test,
399  BM_EDGE);
400 
401  for (int i = 0; i < group_len; i++) {
402  const int faces_start = group_index[i][0];
403  const int faces_len = group_index[i][1];
404  BMFace **faces = MEM_mallocN(sizeof(*faces) * faces_len, __func__);
405 
406  float bounds_min[2], bounds_max[2];
407  INIT_MINMAX2(bounds_min, bounds_max);
408 
409  for (int j = 0; j < faces_len; j++) {
410  faces[j] = BM_face_at_index(bm, groups_array[faces_start + j]);
411  }
412 
413  struct FaceIsland *island = MEM_callocN(sizeof(*island), __func__);
414  island->faces = faces;
415  island->faces_len = faces_len;
417  island->aspect_y = aspect_y;
418  BLI_addtail(island_list, island);
419  island_added += 1;
420  }
421 
422  MEM_freeN(groups_array);
423  MEM_freeN(group_index);
424  return island_added;
425 }
426 
429 /* -------------------------------------------------------------------- */
436  Object **objects,
437  const uint objects_len,
438  const struct UVMapUDIM_Params *udim_params,
439  const struct UVPackIsland_Params *params)
440 {
441  /* Align to the Y axis, could make this configurable. */
442  const int rotate_align_axis = 1;
443  ListBase island_list = {NULL};
444  int island_list_len = 0;
445 
446  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
447  Object *obedit = objects[ob_index];
448  BMEditMesh *em = BKE_editmesh_from_object(obedit);
449  BMesh *bm = em->bm;
450 
452  if (cd_loop_uv_offset == -1) {
453  continue;
454  }
455 
456  float aspect_y = 1.0f;
457  if (params->correct_aspect) {
458  float aspx, aspy;
459  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
460  if (aspx != aspy) {
461  aspect_y = aspx / aspy;
462  }
463  }
464 
465  island_list_len += bm_mesh_calc_uv_islands(scene,
466  bm,
467  &island_list,
468  params->only_selected_faces,
469  params->only_selected_uvs,
470  params->use_seams,
471  aspect_y,
473  }
474 
475  if (island_list_len == 0) {
476  return;
477  }
478 
479  float margin = scene->toolsettings->uvcalc_margin;
480  double area = 0.0f;
481 
482  struct FaceIsland **island_array = MEM_mallocN(sizeof(*island_array) * island_list_len,
483  __func__);
484  BoxPack *boxarray = MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__);
485 
486  int index;
487  /* Coordinates of bounding box containing all selected UVs. */
488  float selection_min_co[2], selection_max_co[2];
489  INIT_MINMAX2(selection_min_co, selection_max_co);
490 
491  LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
492 
493  /* Skip calculation if using specified UDIM option. */
494  if (udim_params && (udim_params->use_target_udim == false)) {
495  float bounds_min[2], bounds_max[2];
496  INIT_MINMAX2(bounds_min, bounds_max);
497  for (int i = 0; i < island->faces_len; i++) {
498  BMFace *f = island->faces[i];
499  BM_face_uv_minmax(f, bounds_min, bounds_max, island->cd_loop_uv_offset);
500  }
501 
502  selection_min_co[0] = MIN2(bounds_min[0], selection_min_co[0]);
503  selection_min_co[1] = MIN2(bounds_min[1], selection_min_co[1]);
504  selection_max_co[0] = MAX2(bounds_max[0], selection_max_co[0]);
505  selection_max_co[1] = MAX2(bounds_max[1], selection_max_co[1]);
506  }
507 
508  if (params->rotate) {
509  if (island->aspect_y != 1.0f) {
511  island->faces, island->faces_len, 1.0f / island->aspect_y, island->cd_loop_uv_offset);
512  }
513 
515  island->faces, island->faces_len, rotate_align_axis, island->cd_loop_uv_offset);
516 
517  if (island->aspect_y != 1.0f) {
519  island->faces, island->faces_len, island->aspect_y, island->cd_loop_uv_offset);
520  }
521  }
522 
524  island->faces, island->faces_len, island->cd_loop_uv_offset, &island->bounds_rect);
525 
526  BoxPack *box = &boxarray[index];
527  box->index = index;
528  box->x = 0.0f;
529  box->y = 0.0f;
530  box->w = BLI_rctf_size_x(&island->bounds_rect);
531  box->h = BLI_rctf_size_y(&island->bounds_rect);
532 
533  island_array[index] = island;
534 
535  if (margin > 0.0f) {
536  area += (double)sqrtf(box->w * box->h);
537  }
538  }
539 
540  /* Center of bounding box containing all selected UVs. */
541  float selection_center[2];
542  if (udim_params && (udim_params->use_target_udim == false)) {
543  selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f;
544  selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
545  }
546 
547  if (margin > 0.0f) {
548  /* Logic matches behavior from #param_pack,
549  * use area so multiply the margin by the area to give
550  * predictable results not dependent on UV scale. */
551  margin = (margin * (float)area) * 0.1f;
552  for (int i = 0; i < island_list_len; i++) {
553  struct FaceIsland *island = island_array[i];
554  BoxPack *box = &boxarray[i];
555 
556  BLI_rctf_pad(&island->bounds_rect, margin, margin);
557  box->w = BLI_rctf_size_x(&island->bounds_rect);
558  box->h = BLI_rctf_size_y(&island->bounds_rect);
559  }
560  }
561 
562  float boxarray_size[2];
563  BLI_box_pack_2d(boxarray, island_list_len, &boxarray_size[0], &boxarray_size[1]);
564 
565  /* Don't change the aspect when scaling. */
566  boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
567 
568  const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]};
569 
570  /* Tile offset. */
571  float base_offset[2] = {0.0f, 0.0f};
572 
573  /* CASE: ignore UDIM. */
574  if (udim_params == NULL) {
575  /* pass */
576  }
577  /* CASE: Active/specified(smart uv project) UDIM. */
578  else if (udim_params->use_target_udim) {
579 
580  /* Calculate offset based on specified_tile_index. */
581  base_offset[0] = (udim_params->target_udim - 1001) % 10;
582  base_offset[1] = (udim_params->target_udim - 1001) / 10;
583  }
584 
585  /* CASE: Closest UDIM. */
586  else {
587  const Image *image = udim_params->image;
588  const int *udim_grid = udim_params->grid_shape;
589  /* Check if selection lies on a valid UDIM grid tile. */
590  bool is_valid_udim = uv_coords_isect_udim(image, udim_grid, selection_center);
591  if (is_valid_udim) {
592  base_offset[0] = floorf(selection_center[0]);
593  base_offset[1] = floorf(selection_center[1]);
594  }
595  /* If selection doesn't lie on any UDIM then find the closest UDIM grid or image tile. */
596  else {
597  float nearest_image_tile_co[2] = {FLT_MAX, FLT_MAX};
598  float nearest_image_tile_dist = FLT_MAX, nearest_grid_tile_dist = FLT_MAX;
599  if (image) {
600  nearest_image_tile_dist = uv_nearest_image_tile_distance(
601  image, selection_center, nearest_image_tile_co);
602  }
603 
604  float nearest_grid_tile_co[2] = {0.0f, 0.0f};
605  nearest_grid_tile_dist = uv_nearest_grid_tile_distance(
606  udim_grid, selection_center, nearest_grid_tile_co);
607 
608  base_offset[0] = (nearest_image_tile_dist < nearest_grid_tile_dist) ?
609  nearest_image_tile_co[0] :
610  nearest_grid_tile_co[0];
611  base_offset[1] = (nearest_image_tile_dist < nearest_grid_tile_dist) ?
612  nearest_image_tile_co[1] :
613  nearest_grid_tile_co[1];
614  }
615  }
616 
617  for (int i = 0; i < island_list_len; i++) {
618  struct FaceIsland *island = island_array[boxarray[i].index];
619  const float pivot[2] = {
620  island->bounds_rect.xmin,
621  island->bounds_rect.ymin,
622  };
623  const float offset[2] = {
624  ((boxarray[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
625  ((boxarray[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
626  };
627  for (int j = 0; j < island->faces_len; j++) {
628  BMFace *efa = island->faces[j];
630  efa, offset, scale, pivot, island->cd_loop_uv_offset);
631  }
632  }
633 
634  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
635  Object *obedit = objects[ob_index];
638  }
639 
640  for (int i = 0; i < island_list_len; i++) {
641  MEM_freeN(island_array[i]->faces);
642  MEM_freeN(island_array[i]);
643  }
644 
645  MEM_freeN(island_array);
646  MEM_freeN(boxarray);
647 }
648 
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
int BKE_image_find_nearest_tile_with_offset(const struct Image *image, const float co[2], float r_uv_offset[2]) ATTR_NONNULL(1
void BLI_box_pack_2d(BoxPack *boxarray, unsigned int len, float *r_tot_x, float *r_tot_y)
Definition: boxpack_2d.c:269
float BLI_convexhull_aabb_fit_points_2d(const float(*points)[2], unsigned int n)
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float max_ff(float a, float b)
void mul_m2_v2(const float M[2][2], float v[2])
Definition: math_matrix.c:785
#define DEG2RAD(_deg)
void angle_to_mat2(float R[2][2], float angle)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
MINLINE void add_v2_fl(float r[2], float f)
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition: rct.c:615
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define INIT_MINMAX2(min, max)
#define MAX2(a, b)
#define MIN2(a, b)
typedef double(DMatrix)[4][4]
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ CD_MLOOPUV
@ IMA_SRC_TILED
bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int cd_loop_uv_offset)
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:625
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
Definition: bmesh_query.c:2094
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop_uv_offset)
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Scene scene
void * user_data
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
const int tile_index
ccl_global const KernelWorkTile * tile
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static char faces[256]
#define floorf(x)
Definition: metal/compat.h:224
#define sqrtf(x)
Definition: metal/compat.h:243
static void area(int d1, int d2, int e1, int e2, float weights[2])
struct BMesh * bm
Definition: BKE_editmesh.h:40
int len
Definition: bmesh_class.h:267
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * next
Definition: bmesh_class.h:233
struct BMEdge * e
Definition: bmesh_class.h:97
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct FaceIsland * prev
uint cd_loop_uv_offset
BMFace ** faces
struct FaceIsland * next
void * data
struct ToolSettings * toolsettings
const struct Image * image
Definition: ED_uvedit.h:309
bool use_target_udim
Definition: ED_uvedit.h:312
int grid_shape[2]
Definition: ED_uvedit.h:311
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces, int faces_len, int align_to_axis, const uint cd_loop_uv_offset)
void ED_uvedit_pack_islands_multi(const Scene *scene, Object **objects, const uint objects_len, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params)
static float uv_nearest_image_tile_distance(const Image *image, const float coords[2], float nearest_tile_co[2])
static void bm_face_uv_scale_y(BMFace *f, const float scale_y, const int cd_loop_uv_offset)
static void bm_face_array_uv_scale_y(BMFace **faces, int faces_len, const float scale_y, const uint cd_loop_uv_offset)
bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const float coords[2])
static float uv_nearest_grid_tile_distance(const int udim_grid[2], float coords[2], float nearest_tile_co[2])
static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, void *user_data)
static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f, const float offset[2], const float scale[2], const float pivot[2], const int cd_loop_uv_offset)
static void bm_face_array_calc_bounds(BMFace **faces, int faces_len, const uint cd_loop_uv_offset, rctf *r_bounds_rect)
static int bm_mesh_calc_uv_islands(const Scene *scene, BMesh *bm, ListBase *island_list, const bool only_selected_faces, const bool only_selected_uvs, const bool use_seams, const float aspect_y, const uint cd_loop_uv_offset)
static float(* bm_face_array_calc_unique_uv_coords(BMFace **faces, int faces_len, const uint cd_loop_uv_offset, int *r_coords_len))[2]
void WM_main_add_notifier(unsigned int type, void *reference)