Cycles: Fix debug compilation after tile stealing commit
[blender.git] / source / blender / editors / object / object_remesh.c
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
20 /** \file
21  * \ingroup edobj
22  */
23
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 /* -------------------------------------------------------------------- */
95 /** \name Voxel Remesh Operator
96  * \{ */
97
98 static bool object_remesh_poll(bContext *C)
99 {
100   Object *ob = CTX_data_active_object(C);
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)) {
122     CTX_wm_operator_poll_msg_set(
123         C, "The remesher cannot run with a Multires modifier in the modifier stack");
124     return false;
125   }
126
127   return ED_operator_object_active_editable_mesh(C);
128 }
129
130 static int voxel_remesh_exec(bContext *C, wmOperator *op)
131 {
132   Object *ob = CTX_data_active_object(C);
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;
143   if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
144     isovalue = mesh->remesh_voxel_size * 0.3f;
145   }
146
147   new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(
148       mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue);
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) {
156     ED_sculpt_undo_geometry_begin(ob, op->type->name);
157   }
158
159   if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
160     new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
161     BKE_mesh_calc_normals(new_mesh);
162   }
163
164   if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
165       mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
166     BKE_mesh_runtime_clear_geometry(mesh);
167   }
168
169   if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
170     BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
171   }
172
173   if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
174     BKE_mesh_remesh_reproject_paint_mask(new_mesh, mesh);
175   }
176
177   if (mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
178     BKE_remesh_reproject_sculpt_face_sets(new_mesh, mesh);
179   }
180
181   if (mesh->flag & ME_REMESH_REPROJECT_VERTEX_COLORS) {
182     BKE_mesh_runtime_clear_geometry(mesh);
183     BKE_remesh_reproject_vertex_paint(new_mesh, mesh);
184   }
185
186   BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
187
188   if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
189     BKE_mesh_smooth_flag_set(ob->data, true);
190   }
191
192   if (ob->mode == OB_MODE_SCULPT) {
193     ED_sculpt_undo_geometry_end(ob);
194   }
195
196   BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
197   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
198   WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
199
200   return OPERATOR_FINISHED;
201 }
202
203 void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
204 {
205   /* identifiers */
206   ot->name = "Voxel Remesh";
207   ot->description =
208       "Calculates a new manifold mesh based on the volume of the current mesh. All data layers "
209       "will be lost";
210   ot->idname = "OBJECT_OT_voxel_remesh";
211
212   /* api callbacks */
213   ot->poll = object_remesh_poll;
214   ot->exec = voxel_remesh_exec;
215
216   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
217 }
218
219 /** \} */
220
221 /* -------------------------------------------------------------------- */
222 /** \name Voxel Size Operator
223  * \{ */
224
225 #define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
226 #define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
227
228 typedef struct VoxelSizeEditCustomData {
229   void *draw_handle;
230   Object *active_object;
231
232   float init_mval[2];
233   float slow_mval[2];
234
235   bool slow_mode;
236
237   float init_voxel_size;
238   float slow_voxel_size;
239   float voxel_size;
240
241   float preview_plane[4][3];
242
243   float text_mat[4][4];
244 } VoxelSizeEditCustomData;
245
246 static void voxel_size_parallel_lines_draw(uint pos3d,
247                                            const float initial_co[3],
248                                            const float end_co[3],
249                                            const float length_co[3],
250                                            const float spacing)
251 {
252   const float total_len = len_v3v3(initial_co, end_co);
253   const int tot_lines = (int)(total_len / spacing);
254   const int tot_lines_half = (tot_lines / 2) + 1;
255   float spacing_dir[3], lines_start[3];
256   float line_dir[3];
257   sub_v3_v3v3(spacing_dir, end_co, initial_co);
258   normalize_v3(spacing_dir);
259
260   sub_v3_v3v3(line_dir, length_co, initial_co);
261
262   if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
263     return;
264   }
265
266   mid_v3_v3v3(lines_start, initial_co, end_co);
267
268   immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
269   for (int i = 0; i < tot_lines_half; i++) {
270     float line_start[3];
271     float line_end[3];
272     madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
273     add_v3_v3v3(line_end, line_start, line_dir);
274     immVertex3fv(pos3d, line_start);
275     immVertex3fv(pos3d, line_end);
276   }
277   immEnd();
278
279   mul_v3_fl(spacing_dir, -1.0f);
280
281   immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
282   for (int i = 1; i < tot_lines_half; i++) {
283     float line_start[3];
284     float line_end[3];
285     madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
286     add_v3_v3v3(line_end, line_start, line_dir);
287     immVertex3fv(pos3d, line_start);
288     immVertex3fv(pos3d, line_end);
289   }
290   immEnd();
291 }
292
293 static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
294 {
295   VoxelSizeEditCustomData *cd = arg;
296
297   GPU_blend(GPU_BLEND_ALPHA);
298   GPU_line_smooth(true);
299
300   uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
301   immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
302   GPU_matrix_push();
303   GPU_matrix_mul(cd->active_object->obmat);
304
305   /* Draw Rect */
306   immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
307   GPU_line_width(3.0f);
308
309   immBegin(GPU_PRIM_LINES, 8);
310   immVertex3fv(pos3d, cd->preview_plane[0]);
311   immVertex3fv(pos3d, cd->preview_plane[1]);
312
313   immVertex3fv(pos3d, cd->preview_plane[1]);
314   immVertex3fv(pos3d, cd->preview_plane[2]);
315
316   immVertex3fv(pos3d, cd->preview_plane[2]);
317   immVertex3fv(pos3d, cd->preview_plane[3]);
318
319   immVertex3fv(pos3d, cd->preview_plane[3]);
320   immVertex3fv(pos3d, cd->preview_plane[0]);
321   immEnd();
322
323   /* Draw Grid */
324   GPU_line_width(1.0f);
325
326   const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
327   const int tot_lines = (int)(total_len / cd->voxel_size);
328
329   /* Smoothstep to reduce the alpha of the grid as the line number increases. */
330   const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
331   const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
332   const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
333   const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
334
335   immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
336   voxel_size_parallel_lines_draw(
337       pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
338   voxel_size_parallel_lines_draw(
339       pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
340
341   /* Draw text */
342   const uiStyle *style = UI_style_get();
343   const uiFontStyle *fstyle = &style->widget;
344   const int fontid = fstyle->uifont_id;
345   float strwidth, strheight;
346   short fstyle_points = fstyle->points;
347   char str[VOXEL_SIZE_EDIT_MAX_STR_LEN];
348   short strdrawlen = 0;
349
350   BLI_snprintf(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, "%.4f", cd->voxel_size);
351   strdrawlen = BLI_strlen_utf8(str);
352
353   immUnbindProgram();
354
355   GPU_matrix_push();
356   GPU_matrix_mul(cd->text_mat);
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
366   GPU_blend(GPU_BLEND_NONE);
367   GPU_line_smooth(false);
368 }
369
370 static void voxel_size_edit_cancel(bContext *C, wmOperator *op)
371 {
372   ARegion *ar = CTX_wm_region(C);
373   VoxelSizeEditCustomData *cd = op->customdata;
374
375   ED_region_draw_cb_exit(ar->type, cd->draw_handle);
376
377   MEM_freeN(op->customdata);
378
379   ED_workspace_status_text(C, NULL);
380 }
381
382 static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
383 {
384   ARegion *ar = CTX_wm_region(C);
385   VoxelSizeEditCustomData *cd = op->customdata;
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)) {
392     voxel_size_edit_cancel(C, op);
393     ED_region_tag_redraw(ar);
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)) {
401     ED_region_draw_cb_exit(ar->type, cd->draw_handle);
402     mesh->remesh_voxel_size = cd->voxel_size;
403     MEM_freeN(op->customdata);
404     ED_region_tag_redraw(ar);
405     ED_workspace_status_text(C, NULL);
406     return OPERATOR_FINISHED;
407   }
408
409   const float mval[2] = {event->mval[0], event->mval[1]};
410
411   float d = cd->init_mval[0] - mval[0];
412
413   if (cd->slow_mode) {
414     d = cd->slow_mval[0] - mval[0];
415   }
416
417   if (event->ctrl) {
418     /* Linear mode, enables jumping to any voxel size. */
419     d = d * 0.0005f;
420   }
421   else {
422     /* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
423      * sizes. */
424     /* When the voxel size is slower, it needs more precision. */
425     d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
426   }
427   if (cd->slow_mode) {
428     cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
429   }
430   else {
431     cd->voxel_size = cd->init_voxel_size + d;
432   }
433
434   if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
435     cd->slow_mode = true;
436     copy_v2_v2(cd->slow_mval, mval);
437     cd->slow_voxel_size = cd->voxel_size;
438   }
439   if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
440     cd->slow_mode = false;
441     cd->slow_voxel_size = 0.0f;
442   }
443
444   cd->voxel_size = clamp_f(cd->voxel_size, 0.0001f, 1.0f);
445
446   ED_region_tag_redraw(ar);
447   return OPERATOR_RUNNING_MODAL;
448 }
449
450 static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
451 {
452   ARegion *ar = CTX_wm_region(C);
453   Object *active_object = CTX_data_active_object(C);
454   Mesh *mesh = (Mesh *)active_object->data;
455
456   VoxelSizeEditCustomData *cd = MEM_callocN(sizeof(VoxelSizeEditCustomData),
457                                             "Voxel Size Edit OP Custom Data");
458
459   /* Initial operator Custom Data setup. */
460   cd->draw_handle = ED_region_draw_cb_activate(
461       ar->type, voxel_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
462   cd->active_object = active_object;
463   cd->init_mval[0] = event->mval[0];
464   cd->init_mval[1] = event->mval[1];
465   cd->init_voxel_size = mesh->remesh_voxel_size;
466   cd->voxel_size = mesh->remesh_voxel_size;
467   op->customdata = cd;
468
469   /* Select the front facing face of the mesh boundig box. */
470   BoundBox *bb = BKE_mesh_boundbox_get(cd->active_object);
471
472   /* Indices of the Bounding Box faces. */
473   const int BB_faces[6][4] = {
474       {3, 0, 4, 7},
475       {1, 2, 6, 5},
476       {3, 2, 1, 0},
477       {4, 5, 6, 7},
478       {0, 1, 5, 4},
479       {2, 3, 7, 6},
480   };
481
482   copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[0][0]]);
483   copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[0][1]]);
484   copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[0][2]]);
485   copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[0][3]]);
486
487   RegionView3D *rv3d = CTX_wm_region_view3d(C);
488
489   float mat[3][3];
490   float current_normal[3];
491   float view_normal[3] = {0.0f, 0.0f, 1.0f};
492
493   /* Calculate the view normal. */
494   invert_m4_m4(active_object->imat, active_object->obmat);
495   copy_m3_m4(mat, rv3d->viewinv);
496   mul_m3_v3(mat, view_normal);
497   copy_m3_m4(mat, active_object->imat);
498   mul_m3_v3(mat, view_normal);
499   normalize_v3(view_normal);
500
501   normal_tri_v3(current_normal, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
502
503   float min_dot = dot_v3v3(current_normal, view_normal);
504   float current_dot = 1;
505
506   /* Check if there is a face that is more aligned towards the view. */
507   for (int i = 0; i < 6; i++) {
508     normal_tri_v3(
509         current_normal, bb->vec[BB_faces[i][0]], bb->vec[BB_faces[i][1]], bb->vec[BB_faces[i][2]]);
510     current_dot = dot_v3v3(current_normal, view_normal);
511
512     if (current_dot < min_dot) {
513       min_dot = current_dot;
514       copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[i][0]]);
515       copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[i][1]]);
516       copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[i][2]]);
517       copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[i][3]]);
518     }
519   }
520
521   /* Matrix calculation to position the text in 3D space. */
522   float text_pos[3];
523   float scale_mat[4][4];
524
525   float d_a[3], d_b[3];
526   float d_a_proj[2], d_b_proj[2];
527   float preview_plane_proj[4][3];
528   const float y_axis_proj[2] = {0.0f, 1.0f};
529
530   mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
531
532   /* Project the selected face in the previous step of the Bounding Box. */
533   for (int i = 0; i < 4; i++) {
534     float preview_plane_world_space[3];
535     mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]);
536     ED_view3d_project(ar, preview_plane_world_space, preview_plane_proj[i]);
537   }
538
539   /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
540   sub_v3_v3v3(d_a, cd->preview_plane[1], cd->preview_plane[0]);
541   sub_v3_v3v3(d_b, cd->preview_plane[3], cd->preview_plane[0]);
542   normalize_v3(d_a);
543   normalize_v3(d_b);
544
545   /* Project the X and Y axis. */
546   sub_v2_v2v2(d_a_proj, preview_plane_proj[1], preview_plane_proj[0]);
547   sub_v2_v2v2(d_b_proj, preview_plane_proj[3], preview_plane_proj[0]);
548   normalize_v2(d_a_proj);
549   normalize_v2(d_b_proj);
550
551   unit_m4(cd->text_mat);
552
553   /* Select the axis that is aligned with the view Y axis to use it as the basis Y. */
554   if (fabsf(dot_v2v2(d_a_proj, y_axis_proj)) > fabsf(dot_v2v2(d_b_proj, y_axis_proj))) {
555     copy_v3_v3(cd->text_mat[0], d_b);
556     copy_v3_v3(cd->text_mat[1], d_a);
557
558     /* Flip the X and Y basis vectors to make sure they always point upwards and to the right. */
559     if (d_b_proj[0] < 0.0f) {
560       mul_v3_fl(cd->text_mat[0], -1.0f);
561     }
562     if (d_a_proj[1] < 0.0f) {
563       mul_v3_fl(cd->text_mat[1], -1.0f);
564     }
565   }
566   else {
567     copy_v3_v3(cd->text_mat[0], d_a);
568     copy_v3_v3(cd->text_mat[1], d_b);
569     if (d_a_proj[0] < 0.0f) {
570       mul_v3_fl(cd->text_mat[0], -1.0f);
571     }
572     if (d_b_proj[1] < 0.0f) {
573       mul_v3_fl(cd->text_mat[1], -1.0f);
574     }
575   }
576
577   /* Use the Bounding Box face normal as the basis Z. */
578   normal_tri_v3(cd->text_mat[2], cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
579
580   /* Write the text position into the matrix. */
581   copy_v3_v3(cd->text_mat[3], text_pos);
582
583   /* Scale the text.  */
584   float text_pos_word_space[3];
585   mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos);
586   const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space);
587   scale_m4_fl(scale_mat, pixelsize * 0.5f);
588   mul_m4_m4_post(cd->text_mat, scale_mat);
589
590   WM_event_add_modal_handler(C, op);
591
592   ED_region_tag_redraw(ar);
593
594   const char *status_str = TIP_(
595       "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
596   ED_workspace_status_text(C, status_str);
597
598   return OPERATOR_RUNNING_MODAL;
599 }
600
601 static bool voxel_size_edit_poll(bContext *C)
602 {
603   return CTX_wm_region_view3d(C) && object_remesh_poll(C);
604 }
605
606 void OBJECT_OT_voxel_size_edit(wmOperatorType *ot)
607 {
608   /* identifiers */
609   ot->name = "Edit Voxel Size";
610   ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
611   ot->idname = "OBJECT_OT_voxel_size_edit";
612
613   /* api callbacks */
614   ot->poll = voxel_size_edit_poll;
615   ot->invoke = voxel_size_edit_invoke;
616   ot->modal = voxel_size_edit_modal;
617   ot->cancel = voxel_size_edit_cancel;
618
619   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
620 }
621
622 /** \} */
623
624 /* -------------------------------------------------------------------- */
625 /** \name Quadriflow Remesh Operator
626  * \{ */
627
628 #define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
629
630 enum {
631   QUADRIFLOW_REMESH_RATIO = 1,
632   QUADRIFLOW_REMESH_EDGE_LENGTH,
633   QUADRIFLOW_REMESH_FACES,
634 };
635
636 typedef enum eSymmetryAxes {
637   SYMMETRY_AXES_X = (1 << 0),
638   SYMMETRY_AXES_Y = (1 << 1),
639   SYMMETRY_AXES_Z = (1 << 2),
640 } eSymmetryAxes;
641
642 typedef struct QuadriFlowJob {
643   /* from wmJob */
644   struct Object *owner;
645   short *stop, *do_update;
646   float *progress;
647
648   int target_faces;
649   int seed;
650   bool use_paint_symmetry;
651   eSymmetryAxes symmetry_axes;
652
653   bool use_preserve_sharp;
654   bool use_preserve_boundary;
655   bool use_mesh_curvature;
656
657   bool preserve_paint_mask;
658   bool smooth_normals;
659
660   int success;
661   bool is_nonblocking_job;
662 } QuadriFlowJob;
663
664 static bool mesh_is_manifold_consistent(Mesh *mesh)
665 {
666   /* In this check we count boundary edges as manifold. Additionally, we also
667    * check that the direction of the faces are consistent and doesn't suddenly
668    * flip
669    */
670
671   bool is_manifold_consistent = true;
672   const MLoop *mloop = mesh->mloop;
673   char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
674   int *edge_vert = (int *)MEM_malloc_arrayN(
675       mesh->totedge, sizeof(uint), "remesh_consistent_check");
676
677   for (uint i = 0; i < mesh->totedge; i++) {
678     edge_vert[i] = -1;
679   }
680
681   for (uint loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
682     const MLoop *loop = &mloop[loop_idx];
683     edge_faces[loop->e] += 1;
684     if (edge_faces[loop->e] > 2) {
685       is_manifold_consistent = false;
686       break;
687     }
688
689     if (edge_vert[loop->e] == -1) {
690       edge_vert[loop->e] = loop->v;
691     }
692     else if (edge_vert[loop->e] == loop->v) {
693       /* Mesh has flips in the surface so it is non consistent */
694       is_manifold_consistent = false;
695       break;
696     }
697   }
698
699   if (is_manifold_consistent) {
700     /* check for wire edges */
701     for (uint i = 0; i < mesh->totedge; i++) {
702       if (edge_faces[i] == 0) {
703         is_manifold_consistent = false;
704         break;
705       }
706     }
707   }
708
709   MEM_freeN(edge_faces);
710   MEM_freeN(edge_vert);
711
712   return is_manifold_consistent;
713 }
714
715 static void quadriflow_free_job(void *customdata)
716 {
717   QuadriFlowJob *qj = customdata;
718   MEM_freeN(qj);
719 }
720
721 /* called by quadriflowjob, only to check job 'stop' value */
722 static int quadriflow_break_job(void *customdata)
723 {
724   QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
725   // return *(qj->stop);
726
727   /* this is not nice yet, need to make the jobs list template better
728    * for identifying/acting upon various different jobs */
729   /* but for now we'll reuse the render break... */
730   bool should_break = (G.is_break);
731
732   if (should_break) {
733     qj->success = -1;
734   }
735
736   return should_break;
737 }
738
739 /* called by oceanbake, wmJob sends notifier */
740 static void quadriflow_update_job(void *customdata, float progress, int *cancel)
741 {
742   QuadriFlowJob *qj = customdata;
743
744   if (quadriflow_break_job(qj)) {
745     *cancel = 1;
746   }
747   else {
748     *cancel = 0;
749   }
750
751   *(qj->do_update) = true;
752   *(qj->progress) = progress;
753 }
754
755 static Mesh *remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes)
756 {
757   MirrorModifierData mmd = {{0}};
758   mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
759
760   Mesh *mesh_bisect, *mesh_bisect_temp;
761   mesh_bisect = BKE_mesh_copy_for_eval(mesh, false);
762
763   int axis;
764   float plane_co[3], plane_no[3];
765   zero_v3(plane_co);
766
767   for (char i = 0; i < 3; i++) {
768     eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
769     if (symmetry_axes & symm_it) {
770       axis = i;
771       mmd.flag = 0;
772       mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
773       zero_v3(plane_no);
774       plane_no[axis] = -1.0f;
775       mesh_bisect_temp = mesh_bisect;
776       mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane(
777           &mmd, mesh_bisect, axis, plane_co, plane_no);
778       if (mesh_bisect_temp != mesh_bisect) {
779         BKE_id_free(NULL, mesh_bisect_temp);
780       }
781     }
782   }
783
784   BKE_id_free(NULL, mesh);
785
786   return mesh_bisect;
787 }
788
789 static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
790 {
791   MirrorModifierData mmd = {{0}};
792   mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
793   Mesh *mesh_mirror, *mesh_mirror_temp;
794
795   mesh_mirror = mesh;
796
797   int axis;
798
799   for (char i = 0; i < 3; i++) {
800     eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
801     if (symmetry_axes & symm_it) {
802       axis = i;
803       mmd.flag = 0;
804       mmd.flag &= MOD_MIR_AXIS_X << i;
805       mesh_mirror_temp = mesh_mirror;
806       mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
807       if (mesh_mirror_temp != mesh_mirror) {
808         BKE_id_free(NULL, mesh_mirror_temp);
809       }
810     }
811   }
812
813   return mesh_mirror;
814 }
815
816 static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
817 {
818   QuadriFlowJob *qj = customdata;
819
820   qj->stop = stop;
821   qj->do_update = do_update;
822   qj->progress = progress;
823   qj->success = 1;
824
825   if (qj->is_nonblocking_job) {
826     G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
827   }
828
829   Object *ob = qj->owner;
830   Mesh *mesh = ob->data;
831   Mesh *new_mesh;
832   Mesh *bisect_mesh;
833
834   /* Check if the mesh is manifold. Quadriflow requires manifold meshes */
835   if (!mesh_is_manifold_consistent(mesh)) {
836     qj->success = -2;
837     return;
838   }
839
840   /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
841    * freeing the original ID */
842   bisect_mesh = BKE_mesh_copy_for_eval(mesh, false);
843
844   /* Bisect the input mesh using the paint symmetry settings */
845   bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes);
846
847   new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(
848       bisect_mesh,
849       qj->target_faces,
850       qj->seed,
851       qj->use_preserve_sharp,
852       (qj->use_preserve_boundary || qj->use_paint_symmetry),
853 #ifdef USE_MESH_CURVATURE
854       qj->use_mesh_curvature,
855 #else
856       false,
857 #endif
858       quadriflow_update_job,
859       (void *)qj);
860
861   BKE_id_free(NULL, bisect_mesh);
862
863   if (new_mesh == NULL) {
864     *do_update = true;
865     *stop = 0;
866     if (qj->success == 1) {
867       /* This is not a user cancellation event. */
868       qj->success = 0;
869     }
870     return;
871   }
872
873   /* Mirror the Quadriflow result to build the final mesh */
874   new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
875
876   if (ob->mode == OB_MODE_SCULPT) {
877     ED_sculpt_undo_geometry_begin(ob, "QuadriFlow Remesh");
878   }
879
880   if (qj->preserve_paint_mask) {
881     BKE_mesh_runtime_clear_geometry(mesh);
882     BKE_mesh_remesh_reproject_paint_mask(new_mesh, mesh);
883   }
884
885   BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
886
887   if (qj->smooth_normals) {
888     if (qj->use_paint_symmetry) {
889       BKE_mesh_calc_normals(ob->data);
890     }
891     BKE_mesh_smooth_flag_set(ob->data, true);
892   }
893
894   if (ob->mode == OB_MODE_SCULPT) {
895     ED_sculpt_undo_geometry_end(ob);
896   }
897
898   BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
899
900   *do_update = true;
901   *stop = 0;
902 }
903
904 static void quadriflow_end_job(void *customdata)
905 {
906   QuadriFlowJob *qj = customdata;
907
908   Object *ob = qj->owner;
909
910   if (qj->is_nonblocking_job) {
911     WM_set_locked_interface(G_MAIN->wm.first, false);
912   }
913
914   switch (qj->success) {
915     case 1:
916       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
917       WM_reportf(RPT_INFO, "QuadriFlow: Remeshing completed");
918       break;
919     case 0:
920       WM_reportf(RPT_ERROR, "QuadriFlow: Remeshing failed");
921       break;
922     case -1:
923       WM_report(RPT_WARNING, "QuadriFlow: Remeshing cancelled");
924       break;
925     case -2:
926       WM_report(RPT_WARNING,
927                 "QuadriFlow: The mesh needs to be manifold and have face normals that point in a "
928                 "consistent direction");
929       break;
930   }
931 }
932
933 static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
934 {
935   QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
936
937   job->owner = CTX_data_active_object(C);
938
939   job->target_faces = RNA_int_get(op->ptr, "target_faces");
940   job->seed = RNA_int_get(op->ptr, "seed");
941
942   job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
943
944   job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
945   job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
946
947 #ifdef USE_MESH_CURVATURE
948   job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
949 #endif
950
951   job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
952   job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
953
954   /* Update the target face count if symmetry is enabled */
955   Object *ob = CTX_data_active_object(C);
956   if (ob && job->use_paint_symmetry) {
957     Mesh *mesh = BKE_mesh_from_object(ob);
958     job->symmetry_axes = (eSymmetryAxes)mesh->symmetry;
959     for (char i = 0; i < 3; i++) {
960       eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
961       if (job->symmetry_axes & symm_it) {
962         job->target_faces = job->target_faces / 2;
963       }
964     }
965   }
966   else {
967     job->use_paint_symmetry = false;
968     job->symmetry_axes = 0;
969   }
970
971   if (op->flag == 0) {
972     /* This is called directly from the exec operator, this operation is now blocking */
973     job->is_nonblocking_job = false;
974     short stop = 0, do_update = true;
975     float progress;
976     quadriflow_start_job(job, &stop, &do_update, &progress);
977     quadriflow_end_job(job);
978     quadriflow_free_job(job);
979   }
980   else {
981     /* Non blocking call. For when the operator has been called from the gui */
982     job->is_nonblocking_job = true;
983
984     wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
985                                 CTX_wm_window(C),
986                                 CTX_data_scene(C),
987                                 "QuadriFlow Remesh",
988                                 WM_JOB_PROGRESS,
989                                 WM_JOB_TYPE_QUADRIFLOW_REMESH);
990
991     WM_jobs_customdata_set(wm_job, job, quadriflow_free_job);
992     WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
993     WM_jobs_callbacks(wm_job, quadriflow_start_job, NULL, NULL, quadriflow_end_job);
994
995     WM_set_locked_interface(CTX_wm_manager(C), true);
996
997     WM_jobs_start(CTX_wm_manager(C), wm_job);
998   }
999   return OPERATOR_FINISHED;
1000 }
1001
1002 static bool quadriflow_check(bContext *C, wmOperator *op)
1003 {
1004   int mode = RNA_enum_get(op->ptr, "mode");
1005
1006   if (mode == QUADRIFLOW_REMESH_EDGE_LENGTH) {
1007     float area = RNA_float_get(op->ptr, "mesh_area");
1008     if (area < 0.0f) {
1009       Object *ob = CTX_data_active_object(C);
1010       area = BKE_mesh_calc_area(ob->data);
1011       RNA_float_set(op->ptr, "mesh_area", area);
1012     }
1013     int num_faces;
1014     float edge_len = RNA_float_get(op->ptr, "target_edge_length");
1015
1016     num_faces = area / (edge_len * edge_len);
1017     RNA_int_set(op->ptr, "target_faces", num_faces);
1018   }
1019   else if (mode == QUADRIFLOW_REMESH_RATIO) {
1020     Object *ob = CTX_data_active_object(C);
1021     Mesh *mesh = ob->data;
1022
1023     int num_faces;
1024     float ratio = RNA_float_get(op->ptr, "target_ratio");
1025
1026     num_faces = mesh->totpoly * ratio;
1027
1028     RNA_int_set(op->ptr, "target_faces", num_faces);
1029   }
1030
1031   return true;
1032 }
1033
1034 /* Hide the target variables if they are not active */
1035 static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
1036 {
1037   const char *prop_id = RNA_property_identifier(prop);
1038
1039   if (STRPREFIX(prop_id, "target")) {
1040     int mode = RNA_enum_get(op->ptr, "mode");
1041
1042     if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
1043       return false;
1044     }
1045     if (STREQ(prop_id, "target_faces")) {
1046       if (mode != QUADRIFLOW_REMESH_FACES) {
1047         /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
1048         float area = RNA_float_get(op->ptr, "mesh_area");
1049         if (area < -0.8f) {
1050           area += 0.2f;
1051           /* Make sure we have up to date values from the start */
1052           RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
1053           quadriflow_check((bContext *)C, op);
1054         }
1055
1056         /* Only disable input */
1057         RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE);
1058       }
1059       else {
1060         RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
1061       }
1062     }
1063     else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
1064       return false;
1065     }
1066   }
1067
1068   return true;
1069 }
1070
1071 static const EnumPropertyItem mode_type_items[] = {
1072     {QUADRIFLOW_REMESH_RATIO,
1073      "RATIO",
1074      0,
1075      "Ratio",
1076      "Specify target number of faces relative to the current mesh"},
1077     {QUADRIFLOW_REMESH_EDGE_LENGTH,
1078      "EDGE",
1079      0,
1080      "Edge Length",
1081      "Input target edge length in the new mesh"},
1082     {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
1083     {0, NULL, 0, NULL, NULL},
1084 };
1085
1086 void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
1087 {
1088   /* identifiers */
1089   ot->name = "QuadriFlow Remesh";
1090   ot->description =
1091       "Create a new quad based mesh using the surface data of the current mesh. All data "
1092       "layers will be lost";
1093   ot->idname = "OBJECT_OT_quadriflow_remesh";
1094
1095   /* api callbacks */
1096   ot->poll = object_remesh_poll;
1097   ot->poll_property = quadriflow_poll_property;
1098   ot->check = quadriflow_check;
1099   ot->invoke = WM_operator_props_popup_confirm;
1100   ot->exec = quadriflow_remesh_exec;
1101
1102   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1103
1104   PropertyRNA *prop;
1105
1106   /* properties */
1107   RNA_def_boolean(ot->srna,
1108                   "use_paint_symmetry",
1109                   true,
1110                   "Use Paint Symmetry",
1111                   "Generates a symmetrical mesh using the paint symmetry configuration");
1112
1113   RNA_def_boolean(ot->srna,
1114                   "use_preserve_sharp",
1115                   false,
1116                   "Preserve Sharp",
1117                   "Try to preserve sharp features on the mesh");
1118
1119   RNA_def_boolean(ot->srna,
1120                   "use_preserve_boundary",
1121                   false,
1122                   "Preserve Mesh Boundary",
1123                   "Try to preserve mesh boundary on the mesh");
1124 #ifdef USE_MESH_CURVATURE
1125   RNA_def_boolean(ot->srna,
1126                   "use_mesh_curvature",
1127                   false,
1128                   "Use Mesh Curvature",
1129                   "Take the mesh curvature into account when remeshing");
1130 #endif
1131   RNA_def_boolean(ot->srna,
1132                   "preserve_paint_mask",
1133                   false,
1134                   "Preserve Paint Mask",
1135                   "Reproject the paint mask onto the new mesh");
1136
1137   RNA_def_boolean(ot->srna,
1138                   "smooth_normals",
1139                   false,
1140                   "Smooth Normals",
1141                   "Set the output mesh normals to smooth");
1142
1143   RNA_def_enum(ot->srna,
1144                "mode",
1145                mode_type_items,
1146                QUADRIFLOW_REMESH_FACES,
1147                "Mode",
1148                "How to specify the amount of detail for the new mesh");
1149
1150   prop = RNA_def_float(ot->srna,
1151                        "target_ratio",
1152                        1,
1153                        0,
1154                        FLT_MAX,
1155                        "Ratio",
1156                        "Relative number of faces compared to the current mesh",
1157                        0.0f,
1158                        1.0f);
1159
1160   prop = RNA_def_float(ot->srna,
1161                        "target_edge_length",
1162                        0.1f,
1163                        0.0000001f,
1164                        FLT_MAX,
1165                        "Edge Length",
1166                        "Target edge length in the new mesh",
1167                        0.00001f,
1168                        1.0f);
1169
1170   prop = RNA_def_int(ot->srna,
1171                      "target_faces",
1172                      4000,
1173                      1,
1174                      INT_MAX,
1175                      "Number of Faces",
1176                      "Approximate number of faces (quads) in the new mesh",
1177                      1,
1178                      INT_MAX);
1179
1180   prop = RNA_def_float(
1181       ot->srna,
1182       "mesh_area",
1183       -1.0f,
1184       -FLT_MAX,
1185       FLT_MAX,
1186       "Old Object Face Area",
1187       "This property is only used to cache the object area for later calculations",
1188       0.0f,
1189       FLT_MAX);
1190   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1191
1192   RNA_def_int(ot->srna,
1193               "seed",
1194               0,
1195               0,
1196               INT_MAX,
1197               "Seed",
1198               "Random seed to use with the solver. Different seeds will cause the remesher to "
1199               "come up with different quad layouts on the mesh",
1200               0,
1201               255);
1202 }
1203
1204 /** \} */