Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorSebastian Parborg <darkdefende@gmail.com>2019-08-26 19:34:11 +0300
committerSebastian Parborg <darkdefende@gmail.com>2019-09-13 11:36:05 +0300
commit57e55906f04a48a951fbbcfd7c197eef35ad4387 (patch)
treea4246ffdd501027a37d7329dca05de4d9ed19b15 /source
parent1c44d08a69eb3e66c7f942d748f549d6b8ca138f (diff)
Add QuadriFlow remesher
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h8
-rw-r--r--source/blender/blenkernel/CMakeLists.txt10
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c146
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_remesh.c390
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h9
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c13
-rw-r--r--source/blender/windowmanager/WM_api.h1
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 */
};