diff options
author | Sebastian Parborg <darkdefende@gmail.com> | 2019-08-26 19:34:11 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2019-09-13 11:36:05 +0300 |
commit | 57e55906f04a48a951fbbcfd7c197eef35ad4387 (patch) | |
tree | a4246ffdd501027a37d7329dca05de4d9ed19b15 /source/blender | |
parent | 1c44d08a69eb3e66c7f942d748f549d6b8ca138f (diff) |
Add QuadriFlow remesher
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_mesh_remesh_voxel.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_remesh_voxel.c | 146 | ||||
-rw-r--r-- | source/blender/editors/object/object_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_ops.c | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_remesh.c | 390 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 9 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh.c | 13 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 |
9 files changed, 576 insertions, 3 deletions
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index 089e4de4709..6b275e11cf7 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -39,6 +39,14 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve bool relax_disoriented_triangles); #endif struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size); +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); /* Data reprojection functions */ void BKE_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 4bf2f53f8f7..053e5435925 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -620,6 +620,16 @@ if(WITH_OPENVDB) endif() endif() +if(WITH_QUADRIFLOW) + list(APPEND INC + ../../../intern/quadriflow + ) + list(APPEND LIB + bf_intern_quadriflow + ) + add_definitions(-DWITH_QUADRIFLOW) +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c index a5136311a22..ff7ff947e1d 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c @@ -49,6 +49,10 @@ # include "openvdb_capi.h" #endif +#ifdef WITH_QUADRIFLOW +# include "quadriflow_capi.hpp" +#endif + #ifdef WITH_OPENVDB struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create( Mesh *mesh, struct OpenVDBTransform *transform) @@ -146,6 +150,148 @@ Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *l } #endif +#ifdef WITH_QUADRIFLOW +static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh, + int target_faces, + int seed, + bool preserve_sharp, + bool preserve_boundary, + bool adaptive_scale, + void *update_cb, + void *update_cb_data) +{ + /* Ensure that the triangulated mesh data is up to data */ + BKE_mesh_runtime_looptri_recalc(input_mesh); + const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh); + + /* Gather the required data for export to the internal quadiflow mesh format */ + MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh), + "remesh_looptri"); + BKE_mesh_runtime_verttri_from_looptri( + verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh)); + + unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh); + unsigned int totverts = input_mesh->totvert; + float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts"); + unsigned int *faces = (unsigned int *)MEM_malloc_arrayN( + totfaces * 3, sizeof(unsigned int), "remesh_intput_faces"); + + for (unsigned int i = 0; i < totverts; i++) { + MVert *mvert = &input_mesh->mvert[i]; + verts[i * 3] = mvert->co[0]; + verts[i * 3 + 1] = mvert->co[1]; + verts[i * 3 + 2] = mvert->co[2]; + } + + for (unsigned int i = 0; i < totfaces; i++) { + MVertTri *vt = &verttri[i]; + faces[i * 3] = vt->tri[0]; + faces[i * 3 + 1] = vt->tri[1]; + faces[i * 3 + 2] = vt->tri[2]; + } + + /* Fill out the required input data */ + QuadriflowRemeshData qrd; + + qrd.totfaces = totfaces; + qrd.totverts = totverts; + qrd.verts = verts; + qrd.faces = faces; + qrd.target_faces = target_faces; + + qrd.preserve_sharp = preserve_sharp; + qrd.preserve_boundary = preserve_boundary; + qrd.adaptive_scale = adaptive_scale; + qrd.minimum_cost_flow = 0; + qrd.aggresive_sat = 0; + qrd.rng_seed = seed; + + qrd.out_faces = NULL; + + /* Run the remesher */ + QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data); + + MEM_freeN(verts); + MEM_freeN(faces); + MEM_freeN(verttri); + + if (qrd.out_faces == NULL) { + /* The remeshing was canceled */ + return NULL; + } + + if (qrd.out_totfaces == 0) { + /* Meshing failed */ + MEM_freeN(qrd.out_faces); + MEM_freeN(qrd.out_verts); + return NULL; + } + + /* Construct the new output mesh */ + Mesh *mesh = BKE_mesh_new_nomain( + qrd.out_totverts, 0, 0, (qrd.out_totfaces * 4), qrd.out_totfaces); + + for (int i = 0; i < qrd.out_totverts; i++) { + copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]); + } + + MPoly *mp = mesh->mpoly; + MLoop *ml = mesh->mloop; + for (int i = 0; i < qrd.out_totfaces; i++, mp++, ml += 4) { + mp->loopstart = (int)(ml - mesh->mloop); + mp->totloop = 4; + + ml[0].v = qrd.out_faces[i * 4]; + ml[1].v = qrd.out_faces[i * 4 + 1]; + ml[2].v = qrd.out_faces[i * 4 + 2]; + ml[3].v = qrd.out_faces[i * 4 + 3]; + } + + BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_calc_normals(mesh); + + MEM_freeN(qrd.out_faces); + MEM_freeN(qrd.out_verts); + + return mesh; +} +#endif + +Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh, + int target_faces, + int seed, + bool preserve_sharp, + bool preserve_boundary, + bool adaptive_scale, + void *update_cb, + void *update_cb_data) +{ + Mesh *new_mesh = NULL; +#ifdef WITH_QUADRIFLOW + if (target_faces <= 0) { + target_faces = -1; + } + new_mesh = BKE_mesh_remesh_quadriflow(mesh, + target_faces, + seed, + preserve_sharp, + preserve_boundary, + adaptive_scale, + update_cb, + update_cb_data); +#else + UNUSED_VARS(mesh, + target_faces, + seed, + preserve_sharp, + preserve_boundary, + adaptive_scale, + update_cb, + update_cb_data); +#endif + return new_mesh; +} + Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size) { Mesh *new_mesh = NULL; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 669f3c44644..41205bc8778 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -281,6 +281,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot); /* object_remesh.c */ void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot); +void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot); /* object_transfer_data.c */ void OBJECT_OT_data_transfer(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a1937c40191..f6b08b953a4 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -259,6 +259,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_hide_collection); WM_operatortype_append(OBJECT_OT_voxel_remesh); + WM_operatortype_append(OBJECT_OT_quadriflow_remesh); } void ED_operatormacros_object(void) diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 5f464084a9b..815cc618d4b 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -88,7 +88,6 @@ static bool object_remesh_poll(bContext *C) static int voxel_remesh_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); - Main *bmain = CTX_data_main(C); Mesh *mesh = ob->data; Mesh *new_mesh; @@ -134,7 +133,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -156,3 +154,391 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +enum { + QUADRIFLOW_REMESH_RATIO = 1, + QUADRIFLOW_REMESH_EDGE_LENGTH, + QUADRIFLOW_REMESH_FACES, +}; + +/****************** quadriflow remesh operator *********************/ + +typedef struct QuadriFlowJob { + /* from wmJob */ + struct Object *owner; + short *stop, *do_update; + float *progress; + + int target_faces; + int seed; + bool use_preserve_sharp; + bool use_preserve_boundary; + bool use_mesh_curvature; + + bool preserve_paint_mask; + bool smooth_normals; + + int success; +} QuadriFlowJob; + +static void quadriflow_free_job(void *customdata) +{ + QuadriFlowJob *qj = customdata; + MEM_freeN(qj); +} + +/* called by quadriflowjob, only to check job 'stop' value */ +static int quadriflow_break_job(void *customdata) +{ + QuadriFlowJob *qj = (QuadriFlowJob *)customdata; + // return *(qj->stop); + + /* this is not nice yet, need to make the jobs list template better + * for identifying/acting upon various different jobs */ + /* but for now we'll reuse the render break... */ + bool should_break = (G.is_break); + + if (should_break) { + qj->success = -1; + } + + return should_break; +} + +/* called by oceanbake, wmJob sends notifier */ +static void quadriflow_update_job(void *customdata, float progress, int *cancel) +{ + QuadriFlowJob *qj = customdata; + + if (quadriflow_break_job(qj)) { + *cancel = 1; + } + else { + *cancel = 0; + } + + *(qj->do_update) = true; + *(qj->progress) = progress; +} + +static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress) +{ + QuadriFlowJob *qj = customdata; + + qj->stop = stop; + qj->do_update = do_update; + qj->progress = progress; + qj->success = 1; + + G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ + + Object *ob = qj->owner; + Mesh *mesh = ob->data; + Mesh *new_mesh; + + new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh, + qj->target_faces, + qj->seed, + qj->use_preserve_sharp, + qj->use_preserve_boundary, + qj->use_mesh_curvature, + quadriflow_update_job, + (void *)qj); + + if (!new_mesh) { + *do_update = true; + *stop = 0; + if (qj->success == 1) { + /* This is not a user cancelation event */ + qj->success = 0; + } + return; + } + + if (ob->mode == OB_MODE_SCULPT) { + ED_sculpt_undo_geometry_begin(ob); + } + + Mesh *obj_mesh_copy = NULL; + if (qj->preserve_paint_mask) { + obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0); + CustomData_copy( + &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); + for (int i = 0; i < mesh->totvert; i++) { + copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co); + } + } + + BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); + + if (qj->preserve_paint_mask) { + BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); + BKE_mesh_free(obj_mesh_copy); + } + + if (qj->smooth_normals) { + BKE_mesh_smooth_flag_set(ob->data, true); + } + + if (ob->mode == OB_MODE_SCULPT) { + ED_sculpt_undo_geometry_end(ob); + } + + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + + *do_update = true; + *stop = 0; +} + +static void quadriflow_end_job(void *customdata) +{ + QuadriFlowJob *qj = customdata; + + Object *ob = qj->owner; + + WM_set_locked_interface(G_MAIN->wm.first, false); + + if (qj->success > 0) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!"); + } + else { + if (qj->success == 0) { + WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!"); + } + else { + WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!"); + } + } +} + +static int quadriflow_remesh_exec(bContext *C, wmOperator *op) +{ + QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob"); + + job->owner = CTX_data_active_object(C); + + job->target_faces = RNA_int_get(op->ptr, "target_faces"); + job->seed = RNA_int_get(op->ptr, "seed"); + + job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp"); + job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary"); + + job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature"); + + job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask"); + job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals"); + + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + CTX_data_scene(C), + "QuadriFlow Remesh", + WM_JOB_PROGRESS, + WM_JOB_TYPE_QUADRIFLOW_REMESH); + + WM_jobs_customdata_set(wm_job, job, quadriflow_free_job); + WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA); + WM_jobs_callbacks(wm_job, quadriflow_start_job, NULL, NULL, quadriflow_end_job); + + WM_set_locked_interface(CTX_wm_manager(C), true); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + + return OPERATOR_FINISHED; +} + +static bool quadriflow_check(bContext *C, wmOperator *op) +{ + int mode = RNA_enum_get(op->ptr, "mode"); + + if (mode == QUADRIFLOW_REMESH_EDGE_LENGTH) { + float area = RNA_float_get(op->ptr, "mesh_area"); + if (area < 0.0f) { + Object *ob = CTX_data_active_object(C); + area = BKE_mesh_calc_area(ob->data); + RNA_float_set(op->ptr, "mesh_area", area); + } + int num_faces; + float edge_len = RNA_float_get(op->ptr, "target_edge_length"); + + num_faces = area / (edge_len * edge_len); + RNA_int_set(op->ptr, "target_faces", num_faces); + } + else if (mode == QUADRIFLOW_REMESH_RATIO) { + Object *ob = CTX_data_active_object(C); + Mesh *mesh = ob->data; + + int num_faces; + float ratio = RNA_float_get(op->ptr, "target_ratio"); + + num_faces = mesh->totpoly * ratio; + + RNA_int_set(op->ptr, "target_faces", num_faces); + } + + return true; +} + +/* Hide the target variables if they are not active */ +static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + + if (STRPREFIX(prop_id, "target")) { + int mode = RNA_enum_get(op->ptr, "mode"); + + if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) { + return false; + } + else if (STREQ(prop_id, "target_faces")) { + if (mode != QUADRIFLOW_REMESH_FACES) { + /* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */ + float area = RNA_float_get(op->ptr, "mesh_area"); + if (area < -0.8f) { + area += 0.2f; + /* Make sure we have up to date values from the start */ + RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE); + quadriflow_check((bContext *)C, op); + } + + /* Only disable input */ + RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE); + } + else { + RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE); + } + } + else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) { + return false; + } + } + + return true; +} + +static const EnumPropertyItem mode_type_items[] = { + {QUADRIFLOW_REMESH_RATIO, + "RATIO", + 0, + "Ratio", + "Specify target number of faces relative to the current mesh"}, + {QUADRIFLOW_REMESH_EDGE_LENGTH, + "EDGE", + 0, + "Edge Length", + "Input target edge length in the new mesh"}, + {QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"}, + {0, NULL, 0, NULL, NULL}, +}; + +void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "QuadriFlow Remesh"; + ot->description = + "Create a new quad based mesh using the surface data of the current mesh. All data " + "layers will be lost"; + ot->idname = "OBJECT_OT_quadriflow_remesh"; + + /* api callbacks */ + ot->poll = object_remesh_poll; + ot->poll_property = quadriflow_poll_property; + ot->check = quadriflow_check; + ot->invoke = WM_operator_props_popup_confirm; + ot->exec = quadriflow_remesh_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + + /* properties */ + RNA_def_boolean(ot->srna, + "use_preserve_sharp", + false, + "Preserve Sharp", + "Try to preserve sharp features on the mesh"); + + RNA_def_boolean(ot->srna, + "use_preserve_boundary", + false, + "Preserve Mesh Boundary", + "Try to preserve mesh boundary on the mesh"); + + RNA_def_boolean(ot->srna, + "use_mesh_curvature", + false, + "Use Mesh Curvature", + "Take the mesh curvature into account when remeshing"); + + RNA_def_boolean(ot->srna, + "preserve_paint_mask", + false, + "Preserve Paint Mask", + "Reproject the paint mask onto the new mesh"); + + RNA_def_boolean(ot->srna, + "smooth_normals", + false, + "Smooth Normals", + "Set the output mesh normals to smooth"); + + RNA_def_enum(ot->srna, + "mode", + mode_type_items, + 0, + "Mode", + "How to specify the amount of detail for the new mesh"); + + prop = RNA_def_float(ot->srna, + "target_ratio", + 1, + 0, + FLT_MAX, + "Ratio", + "Relative number of faces compared to the current mesh", + 0.0f, + 1.0f); + + prop = RNA_def_float(ot->srna, + "target_edge_length", + 0.1f, + 0.0000001f, + FLT_MAX, + "Edge Length", + "Target edge length in the new mesh", + 0.00001f, + 1.0f); + + prop = RNA_def_int(ot->srna, + "target_faces", + 1, + 1, + INT_MAX, + "Number of Faces", + "Approximate number of faces (quads) in the new mesh", + 1, + INT_MAX); + + prop = RNA_def_float( + ot->srna, + "mesh_area", + -1.0f, + -FLT_MAX, + FLT_MAX, + "Old Object Face Area", + "This property is only used to cache the object area for later calculations", + 0.0f, + FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + RNA_def_int(ot->srna, + "seed", + 0, + 0, + INT_MAX, + "Seed", + "Random seed to use with the solver. Different seeds will cause the remesher to " + "come up with different quad layouts on the mesh", + 0, + 255); +} diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index cb6991ce67a..070180d0a24 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -193,7 +193,8 @@ typedef struct Mesh { short totcol; float remesh_voxel_size; - char _pad1[4]; + char remesh_mode; + char _pad1[3]; /** Deprecated multiresolution modeling data, only keep for loading old files. */ struct Multires *mr DNA_DEPRECATED; @@ -261,6 +262,12 @@ enum { ME_CDFLAG_EDGE_CREASE = 1 << 2, }; +/* me->remesh_mode */ +enum { + REMESH_VOXEL = 0, + REMESH_QUAD = 1, +}; + /* Subsurf Type */ enum { ME_CC_SUBSURF = 0, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 12cfe157de2..1edf6a6b780 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -55,6 +55,12 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = { + {REMESH_VOXEL, "VOXEL", 0, "Voxel", "Use the voxel remesher"}, + {REMESH_QUAD, "QUAD", 0, "Quad", "Use the quad remesher"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DNA_scene_types.h" @@ -3012,6 +3018,13 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_boolean_default(prop, false); RNA_def_property_ui_text(prop, "Preserve Paint Mask", "Keep the current mask on the new mesh"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + + prop = RNA_def_property(srna, "remesh_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "remesh_mode"); + RNA_def_property_enum_items(prop, rna_enum_mesh_remesh_mode_items); + RNA_def_property_ui_text(prop, "Remesh Mode", ""); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + /* End remesh */ prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index b933448d0bd..455a30b6ff5 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -686,6 +686,7 @@ enum { WM_JOB_TYPE_STUDIOLIGHT, WM_JOB_TYPE_LIGHT_BAKE, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE, + WM_JOB_TYPE_QUADRIFLOW_REMESH, /* add as needed, bake, seq proxy build * if having hard coded values is a problem */ }; |