Blender  V3.3
object_remesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. All rights reserved. */
3 
8 #include <cctype>
9 #include <cfloat>
10 #include <cmath>
11 #include <cstdlib>
12 #include <cstring>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLI_math.h"
17 #include "BLI_string.h"
18 #include "BLI_string_utf8.h"
19 #include "BLI_utildefines.h"
20 
21 #include "DNA_mesh_types.h"
22 #include "DNA_meshdata_types.h"
23 #include "DNA_object_types.h"
24 #include "DNA_userdef_types.h"
25 
26 #include "BLT_translation.h"
27 
28 #include "BKE_context.h"
29 #include "BKE_customdata.h"
30 #include "BKE_global.h"
31 #include "BKE_lib_id.h"
32 #include "BKE_main.h"
33 #include "BKE_mesh.h"
34 #include "BKE_mesh_mirror.h"
35 #include "BKE_mesh_remesh_voxel.h"
36 #include "BKE_mesh_runtime.h"
37 #include "BKE_modifier.h"
38 #include "BKE_object.h"
39 #include "BKE_paint.h"
40 #include "BKE_report.h"
41 #include "BKE_scene.h"
42 #include "BKE_shrinkwrap.h"
43 #include "BKE_unit.h"
44 
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47 
48 #include "ED_mesh.h"
49 #include "ED_object.h"
50 #include "ED_screen.h"
51 #include "ED_sculpt.h"
52 #include "ED_space_api.h"
53 #include "ED_undo.h"
54 #include "ED_view3d.h"
55 
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58 #include "RNA_enum_types.h"
59 
60 #include "GPU_immediate.h"
61 #include "GPU_immediate_util.h"
62 #include "GPU_matrix.h"
63 #include "GPU_state.h"
64 
65 #include "WM_api.h"
66 #include "WM_message.h"
67 #include "WM_toolsystem.h"
68 #include "WM_types.h"
69 
70 #include "UI_interface.h"
71 
72 #include "BLF_api.h"
73 
74 #include "object_intern.h" /* own include */
75 
76 /* TODO(sebpa): unstable, can lead to unrecoverable errors. */
77 // #define USE_MESH_CURVATURE
78 
79 /* -------------------------------------------------------------------- */
84 {
86 
87  if (ob == nullptr || ob->data == nullptr) {
88  return false;
89  }
90 
91  if (ID_IS_LINKED(ob) || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) {
92  CTX_wm_operator_poll_msg_set(C, "The remesher cannot worked on linked or override data");
93  return false;
94  }
95 
96  if (BKE_object_is_in_editmode(ob)) {
97  CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode");
98  return false;
99  }
100 
101  if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
102  CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated");
103  return false;
104  }
105 
106  if (BKE_modifiers_uses_multires(ob)) {
108  C, "The remesher cannot run with a Multires modifier in the modifier stack");
109  return false;
110  }
111 
113 }
114 
116 {
118 
119  Mesh *mesh = static_cast<Mesh *>(ob->data);
120 
121  if (mesh->remesh_voxel_size <= 0.0f) {
122  BKE_report(op->reports, RPT_ERROR, "Voxel remesher cannot run with a voxel size of 0.0");
123  return OPERATOR_CANCELLED;
124  }
125 
126  if (mesh->totpoly == 0) {
127  return OPERATOR_CANCELLED;
128  }
129 
130  /* Output mesh will be all smooth or all flat shading. */
131  const bool smooth_normals = mesh->mpoly[0].flag & ME_SMOOTH;
132 
133  float isovalue = 0.0f;
135  isovalue = mesh->remesh_voxel_size * 0.3f;
136  }
137 
138  Mesh *new_mesh = BKE_mesh_remesh_voxel(
140 
141  if (!new_mesh) {
142  BKE_report(op->reports, RPT_ERROR, "Voxel remesher failed to create mesh");
143  return OPERATOR_CANCELLED;
144  }
145 
146  if (ob->mode == OB_MODE_SCULPT) {
148  }
149 
151  Mesh *mesh_fixed_poles = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
152  BKE_id_free(nullptr, new_mesh);
153  new_mesh = mesh_fixed_poles;
154  }
155 
159  }
160 
163  }
164 
167  }
168 
171  }
172 
176  }
177 
178  BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
179 
180  if (smooth_normals) {
181  BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
182  }
183 
184  if (ob->mode == OB_MODE_SCULPT) {
187  }
188 
192 
193  return OPERATOR_FINISHED;
194 }
195 
197 {
198  /* identifiers */
199  ot->name = "Voxel Remesh";
200  ot->description =
201  "Calculates a new manifold mesh based on the volume of the current mesh. All data layers "
202  "will be lost";
203  ot->idname = "OBJECT_OT_voxel_remesh";
204 
205  /* api callbacks */
208 
210 }
211 
214 /* -------------------------------------------------------------------- */
218 #define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
219 #define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
220 
222  void *draw_handle;
224 
225  float init_mval[2];
226  float slow_mval[2];
227 
228  bool slow_mode;
229 
232  float voxel_size;
233 
234  float preview_plane[4][3];
235 
236  float text_mat[4][4];
237 };
238 
240  const float initial_co[3],
241  const float end_co[3],
242  const float length_co[3],
243  const float spacing)
244 {
245  const float total_len = len_v3v3(initial_co, end_co);
246  const int tot_lines = (int)(total_len / spacing);
247  const int tot_lines_half = (tot_lines / 2) + 1;
248  float spacing_dir[3], lines_start[3];
249  float line_dir[3];
250  sub_v3_v3v3(spacing_dir, end_co, initial_co);
251  normalize_v3(spacing_dir);
252 
253  sub_v3_v3v3(line_dir, length_co, initial_co);
254 
255  if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
256  return;
257  }
258 
259  mid_v3_v3v3(lines_start, initial_co, end_co);
260 
261  immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
262  for (int i = 0; i < tot_lines_half; i++) {
263  float line_start[3];
264  float line_end[3];
265  madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
266  add_v3_v3v3(line_end, line_start, line_dir);
267  immVertex3fv(pos3d, line_start);
268  immVertex3fv(pos3d, line_end);
269  }
270  immEnd();
271 
272  mul_v3_fl(spacing_dir, -1.0f);
273 
274  immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
275  for (int i = 1; i < tot_lines_half; i++) {
276  float line_start[3];
277  float line_end[3];
278  madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
279  add_v3_v3v3(line_end, line_start, line_dir);
280  immVertex3fv(pos3d, line_start);
281  immVertex3fv(pos3d, line_end);
282  }
283  immEnd();
284 }
285 
286 static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
287 {
288  VoxelSizeEditCustomData *cd = static_cast<VoxelSizeEditCustomData *>(arg);
289 
291  GPU_line_smooth(true);
292 
295  GPU_matrix_push();
297 
298  /* Draw Rect */
299  immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
300  GPU_line_width(3.0f);
301 
303  immVertex3fv(pos3d, cd->preview_plane[0]);
304  immVertex3fv(pos3d, cd->preview_plane[1]);
305 
306  immVertex3fv(pos3d, cd->preview_plane[1]);
307  immVertex3fv(pos3d, cd->preview_plane[2]);
308 
309  immVertex3fv(pos3d, cd->preview_plane[2]);
310  immVertex3fv(pos3d, cd->preview_plane[3]);
311 
312  immVertex3fv(pos3d, cd->preview_plane[3]);
313  immVertex3fv(pos3d, cd->preview_plane[0]);
314  immEnd();
315 
316  /* Draw Grid */
317  GPU_line_width(1.0f);
318 
319  const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
320  const int tot_lines = (int)(total_len / cd->voxel_size);
321 
322  /* Smooth-step to reduce the alpha of the grid as the line number increases. */
323  const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
324  const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
325  const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
326  const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
327 
328  immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
330  pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
332  pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
333 
334  /* Draw text */
335  const uiStyle *style = UI_style_get();
336  const uiFontStyle *fstyle = &style->widget;
337  const int fontid = fstyle->uifont_id;
338  float strwidth, strheight;
339  short fstyle_points = fstyle->points;
341  short strdrawlen = 0;
343  UnitSettings *unit = &scene->unit;
346  (double)(cd->voxel_size * unit->scale_length),
347  -3,
349  unit,
350  true);
351  strdrawlen = BLI_strlen_utf8(str);
352 
354 
355  GPU_matrix_push();
357  BLF_size(fontid, 10.0f * fstyle_points, U.dpi);
358  BLF_color3f(fontid, 1.0f, 1.0f, 1.0f);
359  BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
360  BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
361  BLF_draw(fontid, str, strdrawlen);
362  GPU_matrix_pop();
363 
364  GPU_matrix_pop();
365 
367  GPU_line_smooth(false);
368 }
369 
371 {
372  ARegion *region = CTX_wm_region(C);
374 
376 
377  MEM_freeN(op->customdata);
378 
379  ED_workspace_status_text(C, nullptr);
380 }
381 
382 static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
383 {
384  ARegion *region = CTX_wm_region(C);
386  Object *active_object = cd->active_object;
387  Mesh *mesh = (Mesh *)active_object->data;
388 
389  /* Cancel modal operator */
390  if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
391  (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
393  ED_region_tag_redraw(region);
394  return OPERATOR_FINISHED;
395  }
396 
397  /* Finish modal operator */
398  if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
399  (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
400  (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
403  MEM_freeN(op->customdata);
404  ED_region_tag_redraw(region);
405  ED_workspace_status_text(C, nullptr);
406  WM_event_add_notifier(C, NC_GEOM | ND_DATA, nullptr);
407  return OPERATOR_FINISHED;
408  }
409 
410  const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
411 
412  float d = cd->init_mval[0] - mval[0];
413 
414  if (cd->slow_mode) {
415  d = cd->slow_mval[0] - mval[0];
416  }
417 
418  if (event->modifier & KM_CTRL) {
419  /* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
420  * sizes. */
421  /* When the voxel size is slower, it needs more precision. */
422  d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
423  }
424  else {
425  /* Linear mode, enables jumping to any voxel size. */
426  d = d * 0.0005f;
427  }
428  if (cd->slow_mode) {
429  cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
430  }
431  else {
432  cd->voxel_size = cd->init_voxel_size + d;
433  }
434 
435  if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
436  cd->slow_mode = true;
437  copy_v2_v2(cd->slow_mval, mval);
438  cd->slow_voxel_size = cd->voxel_size;
439  }
440  if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
441  cd->slow_mode = false;
442  cd->slow_voxel_size = 0.0f;
443  }
444 
445  cd->voxel_size = clamp_f(cd->voxel_size, 0.0001f, 1.0f);
446 
447  ED_region_tag_redraw(region);
448  return OPERATOR_RUNNING_MODAL;
449 }
450 
451 static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
452 {
453  ARegion *region = CTX_wm_region(C);
454  Object *active_object = CTX_data_active_object(C);
455  Mesh *mesh = (Mesh *)active_object->data;
456 
457  VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>(
458  "Voxel Size Edit OP Custom Data");
459 
460  /* Initial operator Custom Data setup. */
463  cd->active_object = active_object;
464  cd->init_mval[0] = event->mval[0];
465  cd->init_mval[1] = event->mval[1];
466  cd->init_voxel_size = mesh->remesh_voxel_size;
467  cd->voxel_size = mesh->remesh_voxel_size;
468  op->customdata = cd;
469 
470  /* Select the front facing face of the mesh bounding box. */
471  const BoundBox *bb = BKE_mesh_boundbox_get(cd->active_object);
472 
473  /* Indices of the Bounding Box faces. */
474  const int BB_faces[6][4] = {
475  {3, 0, 4, 7},
476  {1, 2, 6, 5},
477  {3, 2, 1, 0},
478  {4, 5, 6, 7},
479  {0, 1, 5, 4},
480  {2, 3, 7, 6},
481  };
482 
483  copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[0][0]]);
484  copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[0][1]]);
485  copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[0][2]]);
486  copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[0][3]]);
487 
489 
490  float mat[3][3];
491  float current_normal[3];
492  float view_normal[3] = {0.0f, 0.0f, 1.0f};
493 
494  /* Calculate the view normal. */
495  invert_m4_m4(active_object->imat, active_object->obmat);
496  copy_m3_m4(mat, rv3d->viewinv);
497  mul_m3_v3(mat, view_normal);
498  copy_m3_m4(mat, active_object->imat);
499  mul_m3_v3(mat, view_normal);
500  normalize_v3(view_normal);
501 
502  normal_tri_v3(current_normal, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
503 
504  float min_dot = dot_v3v3(current_normal, view_normal);
505  float current_dot = 1;
506 
507  /* Check if there is a face that is more aligned towards the view. */
508  for (int i = 0; i < 6; i++) {
510  current_normal, bb->vec[BB_faces[i][0]], bb->vec[BB_faces[i][1]], bb->vec[BB_faces[i][2]]);
511  current_dot = dot_v3v3(current_normal, view_normal);
512 
513  if (current_dot < min_dot) {
514  min_dot = current_dot;
515  copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[i][0]]);
516  copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[i][1]]);
517  copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[i][2]]);
518  copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[i][3]]);
519  }
520  }
521 
522  /* Matrix calculation to position the text in 3D space. */
523  float text_pos[3];
524  float scale_mat[4][4];
525 
526  float d_a[3], d_b[3];
527  float d_a_proj[2], d_b_proj[2];
528  float preview_plane_proj[4][2];
529  const float y_axis_proj[2] = {0.0f, 1.0f};
530 
531  mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
532 
533  /* Project the selected face in the previous step of the Bounding Box. */
534  for (int i = 0; i < 4; i++) {
535  float preview_plane_world_space[3];
536  mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]);
537  ED_view3d_project_v2(region, preview_plane_world_space, preview_plane_proj[i]);
538  }
539 
540  /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
541  sub_v3_v3v3(d_a, cd->preview_plane[1], cd->preview_plane[0]);
542  sub_v3_v3v3(d_b, cd->preview_plane[3], cd->preview_plane[0]);
543  normalize_v3(d_a);
544  normalize_v3(d_b);
545 
546  /* Project the X and Y axis. */
547  sub_v2_v2v2(d_a_proj, preview_plane_proj[1], preview_plane_proj[0]);
548  sub_v2_v2v2(d_b_proj, preview_plane_proj[3], preview_plane_proj[0]);
549  normalize_v2(d_a_proj);
550  normalize_v2(d_b_proj);
551 
552  unit_m4(cd->text_mat);
553 
554  /* Select the axis that is aligned with the view Y axis to use it as the basis Y. */
555  if (fabsf(dot_v2v2(d_a_proj, y_axis_proj)) > fabsf(dot_v2v2(d_b_proj, y_axis_proj))) {
556  copy_v3_v3(cd->text_mat[0], d_b);
557  copy_v3_v3(cd->text_mat[1], d_a);
558 
559  /* Flip the X and Y basis vectors to make sure they always point upwards and to the right. */
560  if (d_b_proj[0] < 0.0f) {
561  mul_v3_fl(cd->text_mat[0], -1.0f);
562  }
563  if (d_a_proj[1] < 0.0f) {
564  mul_v3_fl(cd->text_mat[1], -1.0f);
565  }
566  }
567  else {
568  copy_v3_v3(cd->text_mat[0], d_a);
569  copy_v3_v3(cd->text_mat[1], d_b);
570  if (d_a_proj[0] < 0.0f) {
571  mul_v3_fl(cd->text_mat[0], -1.0f);
572  }
573  if (d_b_proj[1] < 0.0f) {
574  mul_v3_fl(cd->text_mat[1], -1.0f);
575  }
576  }
577 
578  /* Use the Bounding Box face normal as the basis Z. */
579  normal_tri_v3(cd->text_mat[2], cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
580 
581  /* Invert object scale. */
582  float scale[3];
583  mat4_to_size(scale, active_object->obmat);
584  invert_v3(scale);
585  size_to_mat4(scale_mat, scale);
586 
587  mul_m4_m4_pre(cd->text_mat, scale_mat);
588 
589  /* Write the text position into the matrix. */
590  copy_v3_v3(cd->text_mat[3], text_pos);
591 
592  /* Scale the text to constant viewport size. */
593  float text_pos_word_space[3];
594  mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos);
595  const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space);
596  scale_m4_fl(scale_mat, pixelsize * 0.5f);
597  mul_m4_m4_post(cd->text_mat, scale_mat);
598 
600 
601  ED_region_tag_redraw(region);
602 
603  const char *status_str = TIP_(
604  "Move the mouse to change the voxel size. CTRL: Relative Scale, SHIFT: Precision Mode, "
605  "ENTER/LMB: Confirm Size, ESC/RMB: Cancel");
606  ED_workspace_status_text(C, status_str);
607 
608  return OPERATOR_RUNNING_MODAL;
609 }
610 
612 {
614 }
615 
617 {
618  /* identifiers */
619  ot->name = "Edit Voxel Size";
620  ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
621  ot->idname = "OBJECT_OT_voxel_size_edit";
622 
623  /* api callbacks */
628 
630 }
631 
634 /* -------------------------------------------------------------------- */
638 #define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
639 
640 enum {
644 };
645 
647  SYMMETRY_AXES_X = (1 << 0),
648  SYMMETRY_AXES_Y = (1 << 1),
649  SYMMETRY_AXES_Z = (1 << 2),
650 };
651 
653  /* from wmJob */
654  struct Object *owner;
655  short *stop, *do_update;
656  float *progress;
657 
660  int seed;
663 
667 
670 
671  int success;
673 };
674 
676 {
677  /* In this check we count boundary edges as manifold. Additionally, we also
678  * check that the direction of the faces are consistent and doesn't suddenly
679  * flip
680  */
681 
682  bool is_manifold_consistent = true;
683  const MLoop *mloop = mesh->mloop;
684  char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
685  int *edge_vert = (int *)MEM_malloc_arrayN(
686  mesh->totedge, sizeof(uint), "remesh_consistent_check");
687 
688  for (uint i = 0; i < mesh->totedge; i++) {
689  edge_vert[i] = -1;
690  }
691 
692  for (uint loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
693  const MLoop *loop = &mloop[loop_idx];
694  edge_faces[loop->e] += 1;
695  if (edge_faces[loop->e] > 2) {
696  is_manifold_consistent = false;
697  break;
698  }
699 
700  if (edge_vert[loop->e] == -1) {
701  edge_vert[loop->e] = loop->v;
702  }
703  else if (edge_vert[loop->e] == loop->v) {
704  /* Mesh has flips in the surface so it is non consistent */
705  is_manifold_consistent = false;
706  break;
707  }
708  }
709 
710  if (is_manifold_consistent) {
711  for (uint i = 0; i < mesh->totedge; i++) {
712  /* Check for wire edges. */
713  if (edge_faces[i] == 0) {
714  is_manifold_consistent = false;
715  break;
716  }
717  /* Check for zero length edges */
718  MVert *v1 = &mesh->mvert[mesh->medge[i].v1];
719  MVert *v2 = &mesh->mvert[mesh->medge[i].v2];
720  if (compare_v3v3(v1->co, v2->co, 1e-4f)) {
721  is_manifold_consistent = false;
722  break;
723  }
724  }
725  }
726 
727  MEM_freeN(edge_faces);
728  MEM_freeN(edge_vert);
729 
730  return is_manifold_consistent;
731 }
732 
733 static void quadriflow_free_job(void *customdata)
734 {
735  QuadriFlowJob *qj = static_cast<QuadriFlowJob *>(customdata);
736  MEM_freeN(qj);
737 }
738 
739 /* called by quadriflowjob, only to check job 'stop' value */
740 static int quadriflow_break_job(void *customdata)
741 {
742  QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
743  // return *(qj->stop);
744 
745  /* this is not nice yet, need to make the jobs list template better
746  * for identifying/acting upon various different jobs */
747  /* but for now we'll reuse the render break... */
748  bool should_break = (G.is_break);
749 
750  if (should_break) {
751  qj->success = -1;
752  }
753 
754  return should_break;
755 }
756 
758 static void quadriflow_update_job(void *customdata, float progress, int *cancel)
759 {
760  QuadriFlowJob *qj = static_cast<QuadriFlowJob *>(customdata);
761 
762  if (quadriflow_break_job(qj)) {
763  *cancel = 1;
764  }
765  else {
766  *cancel = 0;
767  }
768 
769  *(qj->do_update) = true;
770  *(qj->progress) = progress;
771 }
772 
774 {
775  MirrorModifierData mmd = {{nullptr}};
777 
778  Mesh *mesh_bisect, *mesh_bisect_temp;
779  mesh_bisect = BKE_mesh_copy_for_eval(mesh, false);
780 
781  int axis;
782  float plane_co[3], plane_no[3];
783  zero_v3(plane_co);
784 
785  for (char i = 0; i < 3; i++) {
786  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
787  if (symmetry_axes & symm_it) {
788  axis = i;
789  mmd.flag = 0;
790  mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
791  zero_v3(plane_no);
792  plane_no[axis] = -1.0f;
793  mesh_bisect_temp = mesh_bisect;
795  &mmd, mesh_bisect, axis, plane_co, plane_no);
796  if (mesh_bisect_temp != mesh_bisect) {
797  BKE_id_free(nullptr, mesh_bisect_temp);
798  }
799  }
800  }
801 
802  BKE_id_free(nullptr, mesh);
803 
804  return mesh_bisect;
805 }
806 
808 {
809  MirrorModifierData mmd = {{nullptr}};
811  Mesh *mesh_mirror, *mesh_mirror_temp;
812 
813  mesh_mirror = mesh;
814 
815  int axis;
816 
817  for (char i = 0; i < 3; i++) {
818  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
819  if (symmetry_axes & symm_it) {
820  axis = i;
821  mmd.flag = 0;
822  mmd.flag &= MOD_MIR_AXIS_X << i;
823  mesh_mirror_temp = mesh_mirror;
825  &mmd, ob, mesh_mirror, axis, true);
826  if (mesh_mirror_temp != mesh_mirror) {
827  BKE_id_free(nullptr, mesh_mirror_temp);
828  }
829  }
830  }
831 
832  return mesh_mirror;
833 }
834 
835 static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
836 {
837  QuadriFlowJob *qj = static_cast<QuadriFlowJob *>(customdata);
838 
839  qj->stop = stop;
840  qj->do_update = do_update;
841  qj->progress = progress;
842  qj->success = 1;
843 
844  if (qj->is_nonblocking_job) {
845  G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
846  }
847 
848  Object *ob = qj->owner;
849  Mesh *mesh = static_cast<Mesh *>(ob->data);
850  Mesh *new_mesh;
851  Mesh *bisect_mesh;
852 
853  /* Check if the mesh is manifold. Quadriflow requires manifold meshes */
855  qj->success = -2;
856  return;
857  }
858 
859  /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
860  * freeing the original ID */
861  bisect_mesh = BKE_mesh_copy_for_eval(mesh, false);
862 
863  /* Bisect the input mesh using the paint symmetry settings */
864  bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes);
865 
866  new_mesh = BKE_mesh_remesh_quadriflow(bisect_mesh,
867  qj->target_faces,
868  qj->seed,
869  qj->use_preserve_sharp,
871 #ifdef USE_MESH_CURVATURE
872  qj->use_mesh_curvature,
873 #else
874  false,
875 #endif
877  (void *)qj);
878 
879  BKE_id_free(nullptr, bisect_mesh);
880 
881  if (new_mesh == nullptr) {
882  *do_update = true;
883  *stop = 0;
884  if (qj->success == 1) {
885  /* This is not a user cancellation event. */
886  qj->success = 0;
887  }
888  return;
889  }
890 
891  /* Mirror the Quadriflow result to build the final mesh */
892  new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
893 
894  if (ob->mode == OB_MODE_SCULPT) {
895  ED_sculpt_undo_geometry_begin(ob, "QuadriFlow Remesh");
896  }
897 
898  if (qj->preserve_paint_mask) {
901  }
902 
903  BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
904 
905  if (qj->smooth_normals) {
906  BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
907  }
908 
909  if (ob->mode == OB_MODE_SCULPT) {
912  }
913 
915 
916  *do_update = true;
917  *stop = 0;
918 }
919 
920 static void quadriflow_end_job(void *customdata)
921 {
922  QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
923 
924  Object *ob = qj->owner;
925 
926  if (qj->is_nonblocking_job) {
927  WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
928  }
929 
930  switch (qj->success) {
931  case 1:
933  WM_reportf(RPT_INFO, "QuadriFlow: Remeshing completed");
934  break;
935  case 0:
936  WM_reportf(RPT_ERROR, "QuadriFlow: Remeshing failed");
937  break;
938  case -1:
939  WM_report(RPT_WARNING, "QuadriFlow: Remeshing cancelled");
940  break;
941  case -2:
943  "QuadriFlow: The mesh needs to be manifold and have face normals that point in a "
944  "consistent direction");
945  break;
946  }
947 }
948 
950 {
951  QuadriFlowJob *job = (QuadriFlowJob *)MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
952 
954  job->scene = CTX_data_scene(C);
955 
956  job->target_faces = RNA_int_get(op->ptr, "target_faces");
957  job->seed = RNA_int_get(op->ptr, "seed");
958 
959  job->use_mesh_symmetry = RNA_boolean_get(op->ptr, "use_mesh_symmetry");
960 
961  job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
962  job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
963 
964 #ifdef USE_MESH_CURVATURE
965  job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
966 #endif
967 
968  job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
969  job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
970 
971  /* Update the target face count if symmetry is enabled */
973  if (ob && job->use_mesh_symmetry) {
976  for (char i = 0; i < 3; i++) {
977  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
978  if (job->symmetry_axes & symm_it) {
979  job->target_faces = job->target_faces / 2;
980  }
981  }
982  }
983  else {
984  job->use_mesh_symmetry = false;
985  job->symmetry_axes = (eSymmetryAxes)0;
986  }
987 
988  if (op->flag == 0) {
989  /* This is called directly from the exec operator, this operation is now blocking */
990  job->is_nonblocking_job = false;
991  short stop = 0, do_update = true;
992  float progress;
993  quadriflow_start_job(job, &stop, &do_update, &progress);
994  quadriflow_end_job(job);
995  quadriflow_free_job(job);
996  }
997  else {
998  /* Non blocking call. For when the operator has been called from the GUI. */
999  job->is_nonblocking_job = true;
1000 
1001  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
1002  CTX_wm_window(C),
1003  CTX_data_scene(C),
1004  "QuadriFlow Remesh",
1007 
1009  WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
1010  WM_jobs_callbacks(wm_job, quadriflow_start_job, nullptr, nullptr, quadriflow_end_job);
1011 
1013 
1014  WM_jobs_start(CTX_wm_manager(C), wm_job);
1015  }
1016  return OPERATOR_FINISHED;
1017 }
1018 
1020 {
1021  int mode = RNA_enum_get(op->ptr, "mode");
1022 
1024  float area = RNA_float_get(op->ptr, "mesh_area");
1025  if (area < 0.0f) {
1027  area = BKE_mesh_calc_area(static_cast<const Mesh *>(ob->data));
1028  RNA_float_set(op->ptr, "mesh_area", area);
1029  }
1030  int num_faces;
1031  float edge_len = RNA_float_get(op->ptr, "target_edge_length");
1032 
1033  num_faces = area / (edge_len * edge_len);
1034  RNA_int_set(op->ptr, "target_faces", num_faces);
1035  }
1036  else if (mode == QUADRIFLOW_REMESH_RATIO) {
1038  Mesh *mesh = static_cast<Mesh *>(ob->data);
1039 
1040  int num_faces;
1041  float ratio = RNA_float_get(op->ptr, "target_ratio");
1042 
1043  num_faces = mesh->totpoly * ratio;
1044 
1045  RNA_int_set(op->ptr, "target_faces", num_faces);
1046  }
1047 
1048  return true;
1049 }
1050 
1051 /* Hide the target variables if they are not active */
1052 static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
1053 {
1054  const char *prop_id = RNA_property_identifier(prop);
1055 
1056  if (STRPREFIX(prop_id, "target")) {
1057  int mode = RNA_enum_get(op->ptr, "mode");
1058 
1059  if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
1060  return false;
1061  }
1062  if (STREQ(prop_id, "target_faces")) {
1063  if (mode != QUADRIFLOW_REMESH_FACES) {
1064  /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
1065  float area = RNA_float_get(op->ptr, "mesh_area");
1066  if (area < -0.8f) {
1067  area += 0.2f;
1068  /* Make sure we have up to date values from the start */
1070  quadriflow_check((bContext *)C, op);
1071  }
1072 
1073  /* Only disable input */
1075  }
1076  else {
1078  }
1079  }
1080  else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
1081  return false;
1082  }
1083  }
1084 
1085  return true;
1086 }
1087 
1090  "RATIO",
1091  0,
1092  "Ratio",
1093  "Specify target number of faces relative to the current mesh"},
1095  "EDGE",
1096  0,
1097  "Edge Length",
1098  "Input target edge length in the new mesh"},
1099  {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
1100  {0, nullptr, 0, nullptr, nullptr},
1101 };
1102 
1104 {
1105  /* identifiers */
1106  ot->name = "QuadriFlow Remesh";
1107  ot->description =
1108  "Create a new quad based mesh using the surface data of the current mesh. All data "
1109  "layers will be lost";
1110  ot->idname = "OBJECT_OT_quadriflow_remesh";
1111 
1112  /* api callbacks */
1118 
1120 
1121  PropertyRNA *prop;
1122 
1123  /* properties */
1125  "use_mesh_symmetry",
1126  true,
1127  "Use Mesh Symmetry",
1128  "Generates a symmetrical mesh using the mesh symmetry configuration");
1129 
1131  "use_preserve_sharp",
1132  false,
1133  "Preserve Sharp",
1134  "Try to preserve sharp features on the mesh");
1135 
1137  "use_preserve_boundary",
1138  false,
1139  "Preserve Mesh Boundary",
1140  "Try to preserve mesh boundary on the mesh");
1141 #ifdef USE_MESH_CURVATURE
1143  "use_mesh_curvature",
1144  false,
1145  "Use Mesh Curvature",
1146  "Take the mesh curvature into account when remeshing");
1147 #endif
1149  "preserve_paint_mask",
1150  false,
1151  "Preserve Paint Mask",
1152  "Reproject the paint mask onto the new mesh");
1153 
1155  "smooth_normals",
1156  false,
1157  "Smooth Normals",
1158  "Set the output mesh normals to smooth");
1159 
1160  RNA_def_enum(ot->srna,
1161  "mode",
1164  "Mode",
1165  "How to specify the amount of detail for the new mesh");
1166 
1167  prop = RNA_def_float(ot->srna,
1168  "target_ratio",
1169  1,
1170  0,
1171  FLT_MAX,
1172  "Ratio",
1173  "Relative number of faces compared to the current mesh",
1174  0.0f,
1175  1.0f);
1176 
1177  prop = RNA_def_float(ot->srna,
1178  "target_edge_length",
1179  0.1f,
1180  0.0000001f,
1181  FLT_MAX,
1182  "Edge Length",
1183  "Target edge length in the new mesh",
1184  0.00001f,
1185  1.0f);
1186 
1187  prop = RNA_def_int(ot->srna,
1188  "target_faces",
1189  4000,
1190  1,
1191  INT_MAX,
1192  "Number of Faces",
1193  "Approximate number of faces (quads) in the new mesh",
1194  1,
1195  INT_MAX);
1196 
1197  prop = RNA_def_float(
1198  ot->srna,
1199  "mesh_area",
1200  -1.0f,
1201  -FLT_MAX,
1202  FLT_MAX,
1203  "Old Object Face Area",
1204  "This property is only used to cache the object area for later calculations",
1205  0.0f,
1206  FLT_MAX);
1208 
1209  RNA_def_int(ot->srna,
1210  "seed",
1211  0,
1212  0,
1213  INT_MAX,
1214  "Seed",
1215  "Random seed to use with the solver. Different seeds will cause the remesher to "
1216  "come up with different quad layouts on the mesh",
1217  0,
1218  255);
1219 }
1220 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.cc:2065
#define G_MAIN
Definition: BKE_global.h:267
void BKE_id_free(struct Main *bmain, void *idv)
struct Mesh * BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference)
struct BoundBox * BKE_mesh_boundbox_get(struct Object *ob)
Definition: mesh.cc:1207
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, const struct CustomData_MeshMasks *mask, bool take_ownership)
void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth)
Definition: mesh.cc:1486
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
float BKE_mesh_calc_area(const struct Mesh *me)
struct Mesh * BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorModifierData *mmd, const struct Mesh *mesh, int axis, const float plane_co[3], float plane_no[3])
struct Mesh * BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd, struct Object *ob, const struct Mesh *mesh, int axis, bool use_correct_order_on_merge)
void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source)
struct Mesh * BKE_mesh_remesh_voxel(const struct Mesh *mesh, float voxel_size, float adaptivity, float isovalue)
struct Mesh * BKE_mesh_remesh_quadriflow(const struct Mesh *mesh, int target_faces, int seed, bool preserve_sharp, bool preserve_boundary, bool adaptive_scale, void(*update_cb)(void *, float progress, int *cancel), void *update_cb_data)
void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source)
struct Mesh * BKE_mesh_remesh_voxel_fix_poles(const struct Mesh *mesh)
void BKE_remesh_reproject_vertex_paint(struct Mesh *target, const struct Mesh *source)
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh)
@ BKE_MESH_BATCH_DIRTY_ALL
bool BKE_modifiers_uses_multires(struct Object *ob)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const struct Object *ob)
void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object)
Definition: paint.c:2144
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me, struct Mesh *target_me, struct Object *ob_target)
Definition: shrinkwrap.c:1550
@ B_UNIT_LENGTH
Definition: BKE_unit.h:101
size_t BKE_unit_value_as_string(char *str, int len_max, double value, int prec, int type, const struct UnitSettings *settings, bool pad)
void BLF_width_and_height(int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL()
Definition: blf.c:662
void BLF_color3f(int fontid, float r, float g, float b)
Definition: blf.c:460
void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2)
Definition: blf.c:538
void BLF_size(int fontid, float size, int dpi)
Definition: blf.c:363
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:308
MINLINE float pow2f(float x)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
void mul_m4_m4_pre(float R[4][4], const float A[4][4])
Definition: math_matrix.c:372
void unit_m4(float m[4][4])
Definition: rct.c:1090
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void size_to_mat4(float R[4][4], const float size[3])
Definition: math_matrix.c:2111
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2297
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void mat4_to_size(float size[3], const float M[4][4])
Definition: math_matrix.c:2138
void mul_m4_m4_post(float R[4][4], const float B[4][4])
Definition: math_matrix.c:380
MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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 copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
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 invert_v3(float r[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:237
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])
MINLINE float normalize_v2(float r[2])
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: string_utf8.c:317
unsigned int uint
Definition: BLI_sys_types.h:67
#define STRPREFIX(a, b)
#define UNUSED(x)
#define STREQ(a, b)
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ ME_REMESH_REPROJECT_VOLUME
@ ME_REMESH_REPROJECT_VERTEX_COLORS
@ ME_REMESH_REPROJECT_SCULPT_FACE_SETS
@ ME_REMESH_FIX_POLES
@ ME_REMESH_REPROJECT_PAINT_MASK
@ ME_SMOOTH
@ MOD_MIR_BISECT_AXIS_X
@ MOD_MIR_AXIS_X
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
bool ED_operator_object_active_editable_mesh(struct bContext *C)
Definition: screen_ops.c:413
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name)
Definition: sculpt_undo.c:1833
void ED_sculpt_undo_geometry_end(struct Object *ob)
Definition: sculpt_undo.c:1839
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:62
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:226
bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle)
Definition: spacetypes.c:241
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3])
void ED_view3d_project_v2(const struct ARegion *region, const float world[3], float r_region_co[2])
void immUniformColor4f(float r, float g, float b, float a)
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
_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
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:126
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:224
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:119
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:230
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
void GPU_line_width(float width)
Definition: gpu_state.cc:158
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:75
@ 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.
PropertyFlag
Definition: RNA_types.h:183
@ PROP_EDITABLE
Definition: RNA_types.h:189
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
const struct uiStyle * UI_style_get(void)
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_QUADRIFLOW_REMESH
Definition: WM_api.h:1371
@ KM_PRESS
Definition: WM_types.h:267
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
@ KM_CTRL
Definition: WM_types.h:239
ATTR_WARN_UNUSED_RESULT const BMVert * v2
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
#define str(s)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
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
#define G(x, y, z)
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static int quadriflow_break_job(void *customdata)
static void quadriflow_end_job(void *customdata)
static bool voxel_size_edit_poll(bContext *C)
@ QUADRIFLOW_REMESH_RATIO
@ QUADRIFLOW_REMESH_FACES
@ QUADRIFLOW_REMESH_EDGE_LENGTH
#define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES
static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int voxel_remesh_exec(bContext *C, wmOperator *op)
eSymmetryAxes
@ SYMMETRY_AXES_Y
@ SYMMETRY_AXES_Z
@ SYMMETRY_AXES_X
static void quadriflow_free_job(void *customdata)
static bool object_remesh_poll(bContext *C)
static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
#define VOXEL_SIZE_EDIT_MAX_STR_LEN
static void voxel_size_edit_cancel(bContext *C, wmOperator *op)
static bool mesh_is_manifold_consistent(Mesh *mesh)
static void voxel_size_parallel_lines_draw(uint pos3d, const float initial_co[3], const float end_co[3], const float length_co[3], const float spacing)
static bool quadriflow_check(bContext *C, wmOperator *op)
void OBJECT_OT_voxel_size_edit(wmOperatorType *ot)
static Mesh * remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
static const EnumPropertyItem mode_type_items[]
static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE
static void quadriflow_update_job(void *customdata, float progress, int *cancel)
void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
static Mesh * remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes)
static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
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:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1495
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
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:3597
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:3783
struct ARegionType * type
float co[3]
Definition: bmesh_class.h:87
float vec[8][3]
unsigned int v1
unsigned int v2
unsigned int e
unsigned int v
struct MEdge * medge
float remesh_voxel_adaptivity
char symmetry
struct MVert * mvert
uint16_t flag
float remesh_voxel_size
int totedge
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
float imat[4][4]
float obmat[4][4]
struct SculptSession * sculpt
void * data
struct Object * owner
eSymmetryAxes symmetry_axes
bool use_preserve_boundary
bool preserve_paint_mask
float viewinv[4][4]
struct UnitSettings unit
struct BMesh * bm
Definition: BKE_paint.h:539
uiFontStyle widget
short val
Definition: WM_types.h:680
int mval[2]
Definition: WM_types.h:684
uint8_t modifier
Definition: WM_types.h:693
short type
Definition: WM_types.h:678
Definition: wm_jobs.c:57
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:949
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_report(eReportType type, const char *message)
void WM_reportf(eReportType type, const char *format,...)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
@ RIGHTMOUSE
@ EVT_PADENTER
@ LEFTMOUSE
@ EVT_ESCKEY
@ EVT_LEFTSHIFTKEY
@ EVT_RETKEY
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))