Changeset View
Standalone View
source/blender/editors/object/object_remesh.c
- This file was added.
| /* | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License | |||||
| * as published by the Free Software Foundation; either version 2 | |||||
| * of the License, or (at your option) any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU General Public License | |||||
| * along with this program; if not, write to the Free Software Foundation, | |||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| * | |||||
| * The Original Code is Copyright (C) 2019 by Blender Foundation | |||||
| * All rights reserved. | |||||
| */ | |||||
| /** \file | |||||
| * \ingroup edobj | |||||
| */ | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <math.h> | |||||
| #include <float.h> | |||||
| #include <ctype.h> | |||||
| #include "MEM_guardedalloc.h" | |||||
| #include "BLI_blenlib.h" | |||||
| #include "BLI_math.h" | |||||
| #include "BLI_utildefines.h" | |||||
| #include "DNA_scene_types.h" | |||||
| #include "DNA_object_types.h" | |||||
| #include "DNA_meshdata_types.h" | |||||
| #include "DNA_mesh_types.h" | |||||
| #include "BKE_context.h" | |||||
| #include "BKE_global.h" | |||||
| #include "BKE_main.h" | |||||
| #include "BKE_mesh.h" | |||||
| #include "BKE_object.h" | |||||
| #include "BKE_paint.h" | |||||
| #include "BKE_report.h" | |||||
| #include "BKE_scene.h" | |||||
| #include "BKE_customdata.h" | |||||
| #include "BKE_remesh.h" | |||||
| #include "DEG_depsgraph.h" | |||||
| #include "DEG_depsgraph_build.h" | |||||
| #include "ED_mesh.h" | |||||
| #include "ED_object.h" | |||||
| #include "ED_screen.h" | |||||
| #include "ED_undo.h" | |||||
| #include "RNA_access.h" | |||||
| #include "RNA_define.h" | |||||
| #include "RNA_enum_types.h" | |||||
| #include "WM_api.h" | |||||
| #include "WM_types.h" | |||||
| #include "WM_message.h" | |||||
| #include "WM_toolsystem.h" | |||||
| #include "object_intern.h" // own include | |||||
| #include "sculpt_intern.h" | |||||
brecht: Private header files from other modules should not be used if it can be avoided.
Can whatever… | |||||
| #ifdef WITH_OPENVDB | |||||
| #include "openvdb_capi.h" | |||||
| #endif | |||||
| static bool object_remesh_poll(bContext *C) | |||||
| { | |||||
Not Done Inline ActionsThis segfaults when there is no active object. Same for the other use of ob->whatever below. I have committed a quick fix in 8c0dea72b6791a07100487de556ab352106f7f44, as it breaks the F3 operator search. sybren: This segfaults when there is no active object. Same for the other use of `ob->whatever` below. | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| if (BKE_object_is_in_editmode(ob)) { | |||||
| return false; | |||||
| } | |||||
| return ED_operator_object_active_editable_mesh(C); | |||||
| } | |||||
Not Done Inline Actionsshould this have a return false; in there? sybren: should this have a `return false;` in there? | |||||
| static int voxel_remesh_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| Main *bmain = CTX_data_main(C); | |||||
| ID *data; | |||||
| data = ob->data; | |||||
| if (data && ID_IS_LINKED(data)) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| if (ob->type != OB_MESH) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
brechtUnsubmitted Done Inline ActionsIt's generally not needed to tests things again that were already checked in the poll function, it's guaranteed to run before exec. CTX_wm_operator_poll_msg_set can be used to report the reason the operator is not available ahead of time in the tooltip, rather than when it executes. brecht: It's generally not needed to tests things again that were already checked in the poll function… | |||||
| if (ID_REAL_USERS(data) != 1) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Remesh cannot run on mesh data with multiple users."); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| if (BKE_object_is_in_editmode(ob)) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Remesh cannot run from edit mode."); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| Mesh *mesh = ob->data; | |||||
| Mesh *new_mesh; | |||||
| if (mesh->voxel_size <= 0.0f) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Remesh cannot run with a voxel size of 0.0."); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
Done Inline ActionsThe code currently will not build when WITH_OPENVDB is OFF. To fix that:
brecht: The code currently will not build when `WITH_OPENVDB` is `OFF`.
To fix that:
* Put this chunk… | |||||
| if (ob->mode == OB_MODE_SCULPT) { | |||||
| SculptSession *ss = ob->sculpt; | |||||
| if (ss->bm) { | |||||
| BKE_report(op->reports, RPT_ERROR, "Remesh cannot run with dyntopo activated"); | |||||
brechtUnsubmitted Done Inline ActionsIndentation seems uneven here. brecht: Indentation seems uneven here. | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| sculpt_undo_push_begin("voxel remesh"); | |||||
| sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY); | |||||
| } | |||||
Done Inline ActionsThis should be changed to CD_MASK_MESH, which I believe will fix these messages that we have in the console now: write_customdata error: layer '':7 - can't be written to file brecht: This should be changed to `CD_MASK_MESH`, which I believe will fix these messages that we have… | |||||
| struct OpenVDBLevelSet *level_set; | |||||
| struct OpenVDBTransform *xform = OpenVDBTransform_create(); | |||||
| OpenVDBTransform_create_linear_transform(xform, (double)mesh->voxel_size); | |||||
| level_set = BKE_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform); | |||||
| new_mesh = BKE_remesh_voxel_ovdb_volume_to_mesh_nomain(level_set, 0.0, 0.0, false); | |||||
| OpenVDBLevelSet_free(level_set); | |||||
| OpenVDBTransform_free(xform); | |||||
| Mesh *obj_mesh_copy; | |||||
| if (mesh->flag & ME_REMESH_REPROJECT_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_EVERYTHING, true); | |||||
| if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) { | |||||
| BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); | |||||
| BKE_mesh_free(obj_mesh_copy); | |||||
| } | |||||
| if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) { | |||||
| BKE_mesh_smooth_flag_set(ob, true); | |||||
| } | |||||
| if (ob->mode == OB_MODE_SCULPT) { | |||||
| sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_GEOMETRY); | |||||
| sculpt_undo_push_end(); | |||||
| } | |||||
| 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); | |||||
| BKE_mesh_free(new_mesh); | |||||
brechtUnsubmitted Done Inline ActionsThis can be called right after BKE_mesh_nomain_to_mesh. brecht: This can be called right after `BKE_mesh_nomain_to_mesh`. | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void OBJECT_OT_voxel_remesh(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Voxel remesh"; | |||||
brechtUnsubmitted Done Inline ActionsVoxel remesh -> Voxel Remesh brecht: Voxel remesh -> Voxel Remesh | |||||
| ot->description = "Run OpenVDB voxel remesher on the current object"; | |||||
brechtUnsubmitted Done Inline ActionsThis description could explain better what the operator does and what it is for. Maybe it should also explain that all data layers will be lost. brecht: This description could explain better what the operator does and what it is for. Maybe it… | |||||
| ot->idname = "OBJECT_OT_voxel_remesh"; | |||||
| /* api callbacks */ | |||||
| ot->poll = object_remesh_poll; | |||||
| ot->exec = voxel_remesh_exec; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| } | |||||
Private header files from other modules should not be used if it can be avoided.
Can whatever is used be exposed in ED_sculpt.h instead?