Blender  V2.93
object_remesh.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) 2019 by Blender Foundation
17  * All rights reserved.
18  */
19 
24 #include <ctype.h>
25 #include <float.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_math.h"
34 #include "BLI_utildefines.h"
35 
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_userdef_types.h"
41 
42 #include "BLT_translation.h"
43 
44 #include "BKE_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_global.h"
47 #include "BKE_lib_id.h"
48 #include "BKE_main.h"
49 #include "BKE_mesh.h"
50 #include "BKE_mesh_mirror.h"
51 #include "BKE_mesh_remesh_voxel.h"
52 #include "BKE_mesh_runtime.h"
53 #include "BKE_modifier.h"
54 #include "BKE_object.h"
55 #include "BKE_paint.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_shrinkwrap.h"
59 
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_build.h"
62 
63 #include "ED_mesh.h"
64 #include "ED_object.h"
65 #include "ED_screen.h"
66 #include "ED_sculpt.h"
67 #include "ED_space_api.h"
68 #include "ED_undo.h"
69 #include "ED_view3d.h"
70 
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73 #include "RNA_enum_types.h"
74 
75 #include "GPU_immediate.h"
76 #include "GPU_immediate_util.h"
77 #include "GPU_matrix.h"
78 #include "GPU_state.h"
79 
80 #include "WM_api.h"
81 #include "WM_message.h"
82 #include "WM_toolsystem.h"
83 #include "WM_types.h"
84 
85 #include "UI_interface.h"
86 
87 #include "BLF_api.h"
88 
89 #include "object_intern.h" /* own include */
90 
91 /* TODO(sebpa): unstable, can lead to unrecoverable errors. */
92 // #define USE_MESH_CURVATURE
93 
94 /* -------------------------------------------------------------------- */
99 {
101 
102  if (ob == NULL || ob->data == NULL) {
103  return false;
104  }
105 
106  if (ID_IS_LINKED(ob) || ID_IS_LINKED(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) {
107  CTX_wm_operator_poll_msg_set(C, "The remesher cannot worked on linked or override data");
108  return false;
109  }
110 
111  if (BKE_object_is_in_editmode(ob)) {
112  CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode");
113  return false;
114  }
115 
116  if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
117  CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated");
118  return false;
119  }
120 
121  if (BKE_modifiers_uses_multires(ob)) {
123  C, "The remesher cannot run with a Multires modifier in the modifier stack");
124  return false;
125  }
126 
128 }
129 
131 {
133 
134  Mesh *mesh = ob->data;
135  Mesh *new_mesh;
136 
137  if (mesh->remesh_voxel_size <= 0.0f) {
138  BKE_report(op->reports, RPT_ERROR, "Voxel remesher cannot run with a voxel size of 0.0");
139  return OPERATOR_CANCELLED;
140  }
141 
142  float isovalue = 0.0f;
144  isovalue = mesh->remesh_voxel_size * 0.3f;
145  }
146 
149 
150  if (!new_mesh) {
151  BKE_report(op->reports, RPT_ERROR, "Voxel remesher failed to create mesh");
152  return OPERATOR_CANCELLED;
153  }
154 
155  if (ob->mode == OB_MODE_SCULPT) {
157  }
158 
160  new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
161  BKE_mesh_calc_normals(new_mesh);
162  }
163 
167  }
168 
171  }
172 
175  }
176 
179  }
180 
184  }
185 
186  BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
187 
189  BKE_mesh_smooth_flag_set(ob->data, true);
190  }
191 
192  if (ob->mode == OB_MODE_SCULPT) {
195  }
196 
200 
201  return OPERATOR_FINISHED;
202 }
203 
205 {
206  /* identifiers */
207  ot->name = "Voxel Remesh";
208  ot->description =
209  "Calculates a new manifold mesh based on the volume of the current mesh. All data layers "
210  "will be lost";
211  ot->idname = "OBJECT_OT_voxel_remesh";
212 
213  /* api callbacks */
216 
218 }
219 
222 /* -------------------------------------------------------------------- */
226 #define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
227 #define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
228 
229 typedef struct VoxelSizeEditCustomData {
230  void *draw_handle;
232 
233  float init_mval[2];
234  float slow_mval[2];
235 
236  bool slow_mode;
237 
240  float voxel_size;
241 
242  float preview_plane[4][3];
243 
244  float text_mat[4][4];
246 
248  const float initial_co[3],
249  const float end_co[3],
250  const float length_co[3],
251  const float spacing)
252 {
253  const float total_len = len_v3v3(initial_co, end_co);
254  const int tot_lines = (int)(total_len / spacing);
255  const int tot_lines_half = (tot_lines / 2) + 1;
256  float spacing_dir[3], lines_start[3];
257  float line_dir[3];
258  sub_v3_v3v3(spacing_dir, end_co, initial_co);
259  normalize_v3(spacing_dir);
260 
261  sub_v3_v3v3(line_dir, length_co, initial_co);
262 
263  if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
264  return;
265  }
266 
267  mid_v3_v3v3(lines_start, initial_co, end_co);
268 
269  immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
270  for (int i = 0; i < tot_lines_half; i++) {
271  float line_start[3];
272  float line_end[3];
273  madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
274  add_v3_v3v3(line_end, line_start, line_dir);
275  immVertex3fv(pos3d, line_start);
276  immVertex3fv(pos3d, line_end);
277  }
278  immEnd();
279 
280  mul_v3_fl(spacing_dir, -1.0f);
281 
282  immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
283  for (int i = 1; i < tot_lines_half; i++) {
284  float line_start[3];
285  float line_end[3];
286  madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
287  add_v3_v3v3(line_end, line_start, line_dir);
288  immVertex3fv(pos3d, line_start);
289  immVertex3fv(pos3d, line_end);
290  }
291  immEnd();
292 }
293 
294 static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
295 {
296  VoxelSizeEditCustomData *cd = arg;
297 
299  GPU_line_smooth(true);
300 
303  GPU_matrix_push();
305 
306  /* Draw Rect */
307  immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
308  GPU_line_width(3.0f);
309 
311  immVertex3fv(pos3d, cd->preview_plane[0]);
312  immVertex3fv(pos3d, cd->preview_plane[1]);
313 
314  immVertex3fv(pos3d, cd->preview_plane[1]);
315  immVertex3fv(pos3d, cd->preview_plane[2]);
316 
317  immVertex3fv(pos3d, cd->preview_plane[2]);
318  immVertex3fv(pos3d, cd->preview_plane[3]);
319 
320  immVertex3fv(pos3d, cd->preview_plane[3]);
321  immVertex3fv(pos3d, cd->preview_plane[0]);
322  immEnd();
323 
324  /* Draw Grid */
325  GPU_line_width(1.0f);
326 
327  const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
328  const int tot_lines = (int)(total_len / cd->voxel_size);
329 
330  /* Smooth-step to reduce the alpha of the grid as the line number increases. */
331  const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
332  const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
333  const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
334  const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
335 
336  immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
338  pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
340  pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
341 
342  /* Draw text */
343  const uiStyle *style = UI_style_get();
344  const uiFontStyle *fstyle = &style->widget;
345  const int fontid = fstyle->uifont_id;
346  float strwidth, strheight;
347  short fstyle_points = fstyle->points;
349  short strdrawlen = 0;
350 
352  strdrawlen = BLI_strlen_utf8(str);
353 
355 
356  GPU_matrix_push();
358  BLF_size(fontid, 10.0f * fstyle_points, U.dpi);
359  BLF_color3f(fontid, 1.0f, 1.0f, 1.0f);
360  BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
361  BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
362  BLF_draw(fontid, str, strdrawlen);
363  GPU_matrix_pop();
364 
365  GPU_matrix_pop();
366 
368  GPU_line_smooth(false);
369 }
370 
372 {
373  ARegion *region = CTX_wm_region(C);
375 
377 
378  MEM_freeN(op->customdata);
379 
381 }
382 
383 static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
384 {
385  ARegion *region = CTX_wm_region(C);
387  Object *active_object = cd->active_object;
388  Mesh *mesh = (Mesh *)active_object->data;
389 
390  /* Cancel modal operator */
391  if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
392  (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
394  ED_region_tag_redraw(region);
395  return OPERATOR_FINISHED;
396  }
397 
398  /* Finish modal operator */
399  if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
400  (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
401  (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
404  MEM_freeN(op->customdata);
405  ED_region_tag_redraw(region);
407  return OPERATOR_FINISHED;
408  }
409 
410  const float mval[2] = {event->mval[0], 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->ctrl) {
419  /* Linear mode, enables jumping to any voxel size. */
420  d = d * 0.0005f;
421  }
422  else {
423  /* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
424  * sizes. */
425  /* When the voxel size is slower, it needs more precision. */
426  d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
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 
458  "Voxel Size Edit OP Custom Data");
459 
460  /* Initial operator Custom Data setup. */
461  cd->draw_handle = ED_region_draw_cb_activate(
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  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][3];
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(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  /* Write the text position into the matrix. */
582  copy_v3_v3(cd->text_mat[3], text_pos);
583 
584  /* Scale the text. */
585  float text_pos_word_space[3];
586  mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos);
587  const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space);
588  scale_m4_fl(scale_mat, pixelsize * 0.5f);
589  mul_m4_m4_post(cd->text_mat, scale_mat);
590 
592 
593  ED_region_tag_redraw(region);
594 
595  const char *status_str = TIP_(
596  "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
597  ED_workspace_status_text(C, status_str);
598 
599  return OPERATOR_RUNNING_MODAL;
600 }
601 
603 {
605 }
606 
608 {
609  /* identifiers */
610  ot->name = "Edit Voxel Size";
611  ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
612  ot->idname = "OBJECT_OT_voxel_size_edit";
613 
614  /* api callbacks */
619 
621 }
622 
625 /* -------------------------------------------------------------------- */
629 #define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
630 
631 enum {
635 };
636 
637 typedef enum eSymmetryAxes {
638  SYMMETRY_AXES_X = (1 << 0),
639  SYMMETRY_AXES_Y = (1 << 1),
640  SYMMETRY_AXES_Z = (1 << 2),
642 
643 typedef struct QuadriFlowJob {
644  /* from wmJob */
645  struct Object *owner;
646  short *stop, *do_update;
647  float *progress;
648 
651  int seed;
654 
658 
661 
662  int success;
665 
667 {
668  /* In this check we count boundary edges as manifold. Additionally, we also
669  * check that the direction of the faces are consistent and doesn't suddenly
670  * flip
671  */
672 
673  bool is_manifold_consistent = true;
674  const MLoop *mloop = mesh->mloop;
675  char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
676  int *edge_vert = (int *)MEM_malloc_arrayN(
677  mesh->totedge, sizeof(uint), "remesh_consistent_check");
678 
679  for (uint i = 0; i < mesh->totedge; i++) {
680  edge_vert[i] = -1;
681  }
682 
683  for (uint loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
684  const MLoop *loop = &mloop[loop_idx];
685  edge_faces[loop->e] += 1;
686  if (edge_faces[loop->e] > 2) {
687  is_manifold_consistent = false;
688  break;
689  }
690 
691  if (edge_vert[loop->e] == -1) {
692  edge_vert[loop->e] = loop->v;
693  }
694  else if (edge_vert[loop->e] == loop->v) {
695  /* Mesh has flips in the surface so it is non consistent */
696  is_manifold_consistent = false;
697  break;
698  }
699  }
700 
701  if (is_manifold_consistent) {
702  for (uint i = 0; i < mesh->totedge; i++) {
703  /* Check for wire edges. */
704  if (edge_faces[i] == 0) {
705  is_manifold_consistent = false;
706  break;
707  }
708  /* Check for zero length edges */
709  MVert *v1 = &mesh->mvert[mesh->medge[i].v1];
710  MVert *v2 = &mesh->mvert[mesh->medge[i].v2];
711  if (compare_v3v3(v1->co, v2->co, 1e-4f)) {
712  is_manifold_consistent = false;
713  break;
714  }
715  }
716  }
717 
718  MEM_freeN(edge_faces);
719  MEM_freeN(edge_vert);
720 
721  return is_manifold_consistent;
722 }
723 
724 static void quadriflow_free_job(void *customdata)
725 {
726  QuadriFlowJob *qj = customdata;
727  MEM_freeN(qj);
728 }
729 
730 /* called by quadriflowjob, only to check job 'stop' value */
731 static int quadriflow_break_job(void *customdata)
732 {
733  QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
734  // return *(qj->stop);
735 
736  /* this is not nice yet, need to make the jobs list template better
737  * for identifying/acting upon various different jobs */
738  /* but for now we'll reuse the render break... */
739  bool should_break = (G.is_break);
740 
741  if (should_break) {
742  qj->success = -1;
743  }
744 
745  return should_break;
746 }
747 
749 static void quadriflow_update_job(void *customdata, float progress, int *cancel)
750 {
751  QuadriFlowJob *qj = customdata;
752 
753  if (quadriflow_break_job(qj)) {
754  *cancel = 1;
755  }
756  else {
757  *cancel = 0;
758  }
759 
760  *(qj->do_update) = true;
761  *(qj->progress) = progress;
762 }
763 
765 {
766  MirrorModifierData mmd = {{0}};
768 
769  Mesh *mesh_bisect, *mesh_bisect_temp;
770  mesh_bisect = BKE_mesh_copy_for_eval(mesh, false);
771 
772  int axis;
773  float plane_co[3], plane_no[3];
774  zero_v3(plane_co);
775 
776  for (char i = 0; i < 3; i++) {
777  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
778  if (symmetry_axes & symm_it) {
779  axis = i;
780  mmd.flag = 0;
781  mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
782  zero_v3(plane_no);
783  plane_no[axis] = -1.0f;
784  mesh_bisect_temp = mesh_bisect;
786  &mmd, mesh_bisect, axis, plane_co, plane_no);
787  if (mesh_bisect_temp != mesh_bisect) {
788  BKE_id_free(NULL, mesh_bisect_temp);
789  }
790  }
791  }
792 
794 
795  return mesh_bisect;
796 }
797 
799 {
800  MirrorModifierData mmd = {{0}};
802  Mesh *mesh_mirror, *mesh_mirror_temp;
803 
804  mesh_mirror = mesh;
805 
806  int axis;
807 
808  for (char i = 0; i < 3; i++) {
809  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
810  if (symmetry_axes & symm_it) {
811  axis = i;
812  mmd.flag = 0;
813  mmd.flag &= MOD_MIR_AXIS_X << i;
814  mesh_mirror_temp = mesh_mirror;
815  mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(&mmd, ob, mesh_mirror, axis);
816  if (mesh_mirror_temp != mesh_mirror) {
817  BKE_id_free(NULL, mesh_mirror_temp);
818  }
819  }
820  }
821 
822  return mesh_mirror;
823 }
824 
825 static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
826 {
827  QuadriFlowJob *qj = customdata;
828 
829  qj->stop = stop;
830  qj->do_update = do_update;
831  qj->progress = progress;
832  qj->success = 1;
833 
834  if (qj->is_nonblocking_job) {
835  G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
836  }
837 
838  Object *ob = qj->owner;
839  Mesh *mesh = ob->data;
840  Mesh *new_mesh;
841  Mesh *bisect_mesh;
842 
843  /* Check if the mesh is manifold. Quadriflow requires manifold meshes */
845  qj->success = -2;
846  return;
847  }
848 
849  /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
850  * freeing the original ID */
851  bisect_mesh = BKE_mesh_copy_for_eval(mesh, false);
852 
853  /* Bisect the input mesh using the paint symmetry settings */
854  bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes);
855 
857  bisect_mesh,
858  qj->target_faces,
859  qj->seed,
860  qj->use_preserve_sharp,
862 #ifdef USE_MESH_CURVATURE
863  qj->use_mesh_curvature,
864 #else
865  false,
866 #endif
868  (void *)qj);
869 
870  BKE_id_free(NULL, bisect_mesh);
871 
872  if (new_mesh == NULL) {
873  *do_update = true;
874  *stop = 0;
875  if (qj->success == 1) {
876  /* This is not a user cancellation event. */
877  qj->success = 0;
878  }
879  return;
880  }
881 
882  /* Mirror the Quadriflow result to build the final mesh */
883  new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
884 
885  if (ob->mode == OB_MODE_SCULPT) {
886  ED_sculpt_undo_geometry_begin(ob, "QuadriFlow Remesh");
887  }
888 
889  if (qj->preserve_paint_mask) {
892  }
893 
894  BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
895 
896  if (qj->smooth_normals) {
897  if (qj->use_mesh_symmetry) {
899  }
900  BKE_mesh_smooth_flag_set(ob->data, true);
901  }
902 
903  if (ob->mode == OB_MODE_SCULPT) {
906  }
907 
909 
910  *do_update = true;
911  *stop = 0;
912 }
913 
914 static void quadriflow_end_job(void *customdata)
915 {
916  QuadriFlowJob *qj = customdata;
917 
918  Object *ob = qj->owner;
919 
920  if (qj->is_nonblocking_job) {
921  WM_set_locked_interface(G_MAIN->wm.first, false);
922  }
923 
924  switch (qj->success) {
925  case 1:
927  WM_reportf(RPT_INFO, "QuadriFlow: Remeshing completed");
928  break;
929  case 0:
930  WM_reportf(RPT_ERROR, "QuadriFlow: Remeshing failed");
931  break;
932  case -1:
933  WM_report(RPT_WARNING, "QuadriFlow: Remeshing cancelled");
934  break;
935  case -2:
937  "QuadriFlow: The mesh needs to be manifold and have face normals that point in a "
938  "consistent direction");
939  break;
940  }
941 }
942 
944 {
945  QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
946 
948  job->scene = CTX_data_scene(C);
949 
950  job->target_faces = RNA_int_get(op->ptr, "target_faces");
951  job->seed = RNA_int_get(op->ptr, "seed");
952 
953  job->use_mesh_symmetry = RNA_boolean_get(op->ptr, "use_mesh_symmetry");
954 
955  job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
956  job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
957 
958 #ifdef USE_MESH_CURVATURE
959  job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
960 #endif
961 
962  job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
963  job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
964 
965  /* Update the target face count if symmetry is enabled */
967  if (ob && job->use_mesh_symmetry) {
970  for (char i = 0; i < 3; i++) {
971  eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
972  if (job->symmetry_axes & symm_it) {
973  job->target_faces = job->target_faces / 2;
974  }
975  }
976  }
977  else {
978  job->use_mesh_symmetry = false;
979  job->symmetry_axes = 0;
980  }
981 
982  if (op->flag == 0) {
983  /* This is called directly from the exec operator, this operation is now blocking */
984  job->is_nonblocking_job = false;
985  short stop = 0, do_update = true;
986  float progress;
987  quadriflow_start_job(job, &stop, &do_update, &progress);
988  quadriflow_end_job(job);
989  quadriflow_free_job(job);
990  }
991  else {
992  /* Non blocking call. For when the operator has been called from the GUI. */
993  job->is_nonblocking_job = true;
994 
995  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
996  CTX_wm_window(C),
997  CTX_data_scene(C),
998  "QuadriFlow Remesh",
1001 
1003  WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
1005 
1007 
1008  WM_jobs_start(CTX_wm_manager(C), wm_job);
1009  }
1010  return OPERATOR_FINISHED;
1011 }
1012 
1014 {
1015  int mode = RNA_enum_get(op->ptr, "mode");
1016 
1018  float area = RNA_float_get(op->ptr, "mesh_area");
1019  if (area < 0.0f) {
1021  area = BKE_mesh_calc_area(ob->data);
1022  RNA_float_set(op->ptr, "mesh_area", area);
1023  }
1024  int num_faces;
1025  float edge_len = RNA_float_get(op->ptr, "target_edge_length");
1026 
1027  num_faces = area / (edge_len * edge_len);
1028  RNA_int_set(op->ptr, "target_faces", num_faces);
1029  }
1030  else if (mode == QUADRIFLOW_REMESH_RATIO) {
1032  Mesh *mesh = ob->data;
1033 
1034  int num_faces;
1035  float ratio = RNA_float_get(op->ptr, "target_ratio");
1036 
1037  num_faces = mesh->totpoly * ratio;
1038 
1039  RNA_int_set(op->ptr, "target_faces", num_faces);
1040  }
1041 
1042  return true;
1043 }
1044 
1045 /* Hide the target variables if they are not active */
1046 static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
1047 {
1048  const char *prop_id = RNA_property_identifier(prop);
1049 
1050  if (STRPREFIX(prop_id, "target")) {
1051  int mode = RNA_enum_get(op->ptr, "mode");
1052 
1053  if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
1054  return false;
1055  }
1056  if (STREQ(prop_id, "target_faces")) {
1057  if (mode != QUADRIFLOW_REMESH_FACES) {
1058  /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
1059  float area = RNA_float_get(op->ptr, "mesh_area");
1060  if (area < -0.8f) {
1061  area += 0.2f;
1062  /* Make sure we have up to date values from the start */
1064  quadriflow_check((bContext *)C, op);
1065  }
1066 
1067  /* Only disable input */
1069  }
1070  else {
1072  }
1073  }
1074  else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
1075  return false;
1076  }
1077  }
1078 
1079  return true;
1080 }
1081 
1084  "RATIO",
1085  0,
1086  "Ratio",
1087  "Specify target number of faces relative to the current mesh"},
1089  "EDGE",
1090  0,
1091  "Edge Length",
1092  "Input target edge length in the new mesh"},
1093  {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
1094  {0, NULL, 0, NULL, NULL},
1095 };
1096 
1098 {
1099  /* identifiers */
1100  ot->name = "QuadriFlow Remesh";
1101  ot->description =
1102  "Create a new quad based mesh using the surface data of the current mesh. All data "
1103  "layers will be lost";
1104  ot->idname = "OBJECT_OT_quadriflow_remesh";
1105 
1106  /* api callbacks */
1112 
1114 
1115  PropertyRNA *prop;
1116 
1117  /* properties */
1119  "use_mesh_symmetry",
1120  true,
1121  "Use Mesh Symmetry",
1122  "Generates a symmetrical mesh using the mesh symmetry configuration");
1123 
1125  "use_preserve_sharp",
1126  false,
1127  "Preserve Sharp",
1128  "Try to preserve sharp features on the mesh");
1129 
1131  "use_preserve_boundary",
1132  false,
1133  "Preserve Mesh Boundary",
1134  "Try to preserve mesh boundary on the mesh");
1135 #ifdef USE_MESH_CURVATURE
1137  "use_mesh_curvature",
1138  false,
1139  "Use Mesh Curvature",
1140  "Take the mesh curvature into account when remeshing");
1141 #endif
1143  "preserve_paint_mask",
1144  false,
1145  "Preserve Paint Mask",
1146  "Reproject the paint mask onto the new mesh");
1147 
1149  "smooth_normals",
1150  false,
1151  "Smooth Normals",
1152  "Set the output mesh normals to smooth");
1153 
1154  RNA_def_enum(ot->srna,
1155  "mode",
1158  "Mode",
1159  "How to specify the amount of detail for the new mesh");
1160 
1161  prop = RNA_def_float(ot->srna,
1162  "target_ratio",
1163  1,
1164  0,
1165  FLT_MAX,
1166  "Ratio",
1167  "Relative number of faces compared to the current mesh",
1168  0.0f,
1169  1.0f);
1170 
1171  prop = RNA_def_float(ot->srna,
1172  "target_edge_length",
1173  0.1f,
1174  0.0000001f,
1175  FLT_MAX,
1176  "Edge Length",
1177  "Target edge length in the new mesh",
1178  0.00001f,
1179  1.0f);
1180 
1181  prop = RNA_def_int(ot->srna,
1182  "target_faces",
1183  4000,
1184  1,
1185  INT_MAX,
1186  "Number of Faces",
1187  "Approximate number of faces (quads) in the new mesh",
1188  1,
1189  INT_MAX);
1190 
1191  prop = RNA_def_float(
1192  ot->srna,
1193  "mesh_area",
1194  -1.0f,
1195  -FLT_MAX,
1196  FLT_MAX,
1197  "Old Object Face Area",
1198  "This property is only used to cache the object area for later calculations",
1199  0.0f,
1200  FLT_MAX);
1202 
1203  RNA_def_int(ot->srna,
1204  "seed",
1205  0,
1206  0,
1207  INT_MAX,
1208  "Seed",
1209  "Random seed to use with the solver. Different seeds will cause the remesher to "
1210  "come up with different quad layouts on the mesh",
1211  0,
1212  255);
1213 }
1214 
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.c:1933
#define G_MAIN
Definition: BKE_global.h:232
void BKE_id_free(struct Main *bmain, void *idv)
struct BoundBox * BKE_mesh_boundbox_get(struct Object *ob)
Definition: mesh.c:1055
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.c:1271
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)
struct Mesh * BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
Definition: mesh.c:995
void BKE_mesh_calc_normals(struct Mesh *me)
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
Definition: mesh_runtime.c:251
void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth)
Definition: mesh.c:1392
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, const int axis)
void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source)
void BKE_remesh_reproject_vertex_paint(struct Mesh *target, struct Mesh *source)
struct Mesh * BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh, int target_faces, int seed, bool preserve_sharp, bool preserve_boundary, bool adaptive_scale, void *update_cb, void *update_cb_data)
struct Mesh * BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size, float adaptivity, float isovalue)
struct Mesh * BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source)
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh)
Definition: mesh_runtime.c:226
@ 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:2057
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me, struct Mesh *target_me, struct Object *ob_target)
Definition: shrinkwrap.c:1541
void BLF_color3f(int fontid, float r, float g, float b)
Definition: blf.c:464
void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL()
Definition: blf.c:698
void BLF_draw(int fontid, const char *str, size_t len) ATTR_NONNULL(2)
Definition: blf.c:542
void BLF_size(int fontid, int size, int dpi)
Definition: blf.c:367
void BLF_position(int fontid, float x, float y, float z)
Definition: blf.c:312
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:51
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
void unit_m4(float m[4][4])
Definition: rct.c:1140
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2309
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void mul_m4_m4_post(float R[4][4], const float B[4][4])
Definition: math_matrix.c:383
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) 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 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:270
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v2(float r[2])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL()
Definition: string_utf8.c:357
unsigned int uint
Definition: BLI_sys_types.h:83
#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:611
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:445
@ ME_REMESH_REPROJECT_VOLUME
@ ME_REMESH_REPROJECT_VERTEX_COLORS
@ ME_REMESH_REPROJECT_SCULPT_FACE_SETS
@ ME_REMESH_FIX_POLES
@ ME_REMESH_SMOOTH_NORMALS
@ ME_REMESH_REPROJECT_PAINT_MASK
@ 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:384
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:840
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name)
Definition: sculpt_undo.c:1591
void ED_sculpt_undo_geometry_end(struct Object *ob)
Definition: sculpt_undo.c:1597
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:66
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:238
void ED_region_draw_cb_exit(struct ARegionType *, void *)
Definition: spacetypes.c:253
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3])
void ED_view3d_project(const struct ARegion *region, const float world[3], float r_region_co[3])
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:142
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:223
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:135
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:200
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
void GPU_line_width(float width)
Definition: gpu_state.cc:173
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:85
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ PROP_EDITABLE
Definition: RNA_types.h:175
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
const struct uiStyle * UI_style_get(void)
@ WM_JOB_TYPE_QUADRIFLOW_REMESH
Definition: WM_api.h:756
@ WM_JOB_PROGRESS
Definition: WM_api.h:726
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define KM_PRESS
Definition: WM_types.h:242
#define KM_RELEASE
Definition: WM_types.h:243
ATTR_WARN_UNUSED_RESULT const BMVert * v2
unsigned int U
Definition: btGjkEpa3.h:78
#define str(s)
#define fabsf(x)
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
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
static void area(int d1, int d2, int e1, int e2, float weights[2])
struct QuadriFlowJob QuadriFlowJob
static int quadriflow_break_job(void *customdata)
struct VoxelSizeEditCustomData VoxelSizeEditCustomData
static void quadriflow_end_job(void *customdata)
static bool voxel_size_edit_poll(bContext *C)
#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)
Definition: object_remesh.c:98
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 const EnumPropertyItem mode_type_items[]
static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
@ QUADRIFLOW_REMESH_RATIO
@ QUADRIFLOW_REMESH_FACES
@ QUADRIFLOW_REMESH_EDGE_LENGTH
#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:1145
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
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
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1517
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
struct ARegionType * type
float co[3]
Definition: bmesh_class.h:99
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
float remesh_voxel_size
int totedge
short flag
struct MLoop * mloop
int totpoly
int totloop
float imat[4][4]
float obmat[4][4]
struct SculptSession * sculpt
void * data
bool use_preserve_sharp
bool use_mesh_symmetry
bool is_nonblocking_job
struct Object * owner
eSymmetryAxes symmetry_axes
bool use_preserve_boundary
bool use_mesh_curvature
bool preserve_paint_mask
short * do_update
float * progress
float viewinv[4][4]
struct BMesh * bm
Definition: BKE_paint.h:493
uiFontStyle widget
short ctrl
Definition: WM_types.h:618
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
Definition: wm_jobs.c:73
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:782
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:744
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
#define G(x, y, z)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_report(ReportType type, const char *message)
void WM_reportf(ReportType 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:3156
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:450
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:196
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:372
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:344
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:360
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))