Blender V5.0
object_multires_modifier.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "object_intern.hh"
6
7#include "DNA_mesh_types.h"
9#include "DNA_object_types.h"
10#include "DNA_space_types.h"
12
13#include "BKE_context.hh"
14#include "BKE_customdata.hh"
15#include "BKE_main.hh"
16#include "BKE_multires.hh"
17#include "BKE_paint.hh"
18#include "BKE_report.hh"
19
20#include "BLI_path_utils.hh"
21#include "BLI_string_utf8.h"
22
23#include "DEG_depsgraph.hh"
24
25#include "ED_object.hh"
26#include "ED_sculpt.hh"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30#include "RNA_prototypes.hh"
31
32#include "WM_api.hh"
33#include "WM_types.hh"
34
35namespace blender::ed::object {
36
37/* ------------------------------------------------------------------- */
40
42{
43 return edit_modifier_poll_generic(C, &RNA_MultiresModifier, (1 << OB_MESH), true, false);
44}
45
65
75
77{
78 ot->name = "Delete Higher Levels";
79 ot->description = "Deletes the higher resolution mesh, potential loss of detail";
80 ot->idname = "OBJECT_OT_multires_higher_levels_delete";
81
82 ot->poll = multires_poll;
85
86 /* flags */
89}
90
92
93/* ------------------------------------------------------------------- */
96
99 "CATMULL_CLARK",
100 0,
101 "Catmull-Clark",
102 "Create a new level using Catmull-Clark subdivisions"},
104 "SIMPLE",
105 0,
106 "Simple",
107 "Create a new level using simple subdivisions"},
109 "LINEAR",
110 0,
111 "Linear",
112 "Create a new level using linear interpolation of the sculpted displacement"},
113 {0, nullptr, 0, nullptr, nullptr},
114};
115
117{
118 Object *object = context_active_object(C);
120 op, object, eModifierType_Multires);
121
122 if (!mmd) {
123 return OPERATOR_CANCELLED;
124 }
125
127 "mode");
128 multiresModifier_subdivide(object, mmd, subdivide_mode);
129
131
134
135 if (object->mode & OB_MODE_SCULPT) {
136 /* ensure that grid paint mask layer is created */
139 }
140
141 return OPERATOR_FINISHED;
142}
143
145 wmOperator *op,
146 const wmEvent * /*event*/)
147{
149 return multires_subdivide_exec(C, op);
150 }
151 return OPERATOR_CANCELLED;
152}
153
155{
156 ot->name = "Multires Subdivide";
157 ot->description = "Add a new level of subdivision";
158 ot->idname = "OBJECT_OT_multires_subdivide";
159
160 ot->poll = multires_poll;
163
164 /* flags */
167 RNA_def_enum(ot->srna,
168 "mode",
171 "Subdivision Mode",
172 "How the mesh is going to be subdivided to create a new level");
173}
174
176
177/* ------------------------------------------------------------------- */
180
182{
184 Object *ob = context_active_object(C), *secondob = nullptr;
186 op, ob, eModifierType_Multires);
187
188 if (!mmd) {
189 return OPERATOR_CANCELLED;
190 }
191
192 if (mmd->lvl == 0) {
193 BKE_report(op->reports, RPT_ERROR, "Reshape can work only with higher levels of subdivisions");
194 return OPERATOR_CANCELLED;
195 }
196
197 CTX_DATA_BEGIN (C, Object *, selob, selected_editable_objects) {
198 if (selob->type == OB_MESH && selob != ob) {
199 secondob = selob;
200 break;
201 }
202 }
204
205 if (!secondob) {
206 BKE_report(op->reports, RPT_ERROR, "Second selected mesh object required to copy shape from");
207 return OPERATOR_CANCELLED;
208 }
209
210 if (!multiresModifier_reshapeFromObject(depsgraph, mmd, ob, secondob)) {
211 BKE_report(op->reports, RPT_ERROR, "Objects do not have the same number of vertices");
212 return OPERATOR_CANCELLED;
213 }
214
217
218 return OPERATOR_FINISHED;
219}
220
222 wmOperator *op,
223 const wmEvent * /*event*/)
224{
226 return multires_reshape_exec(C, op);
227 }
228 return OPERATOR_CANCELLED;
229}
230
232{
233 ot->name = "Multires Reshape";
234 ot->description = "Copy vertex coordinates from other object";
235 ot->idname = "OBJECT_OT_multires_reshape";
236
237 ot->poll = multires_poll;
238 ot->invoke = multires_reshape_invoke;
240
241 /* flags */
244}
245
247
248/* ------------------------------------------------------------------- */
251
253{
254 Main *bmain = CTX_data_main(C);
256 Mesh *mesh = (ob) ? static_cast<Mesh *>(ob->data) : static_cast<Mesh *>(op->customdata);
257 char filepath[FILE_MAX];
258 const bool relative = RNA_boolean_get(op->ptr, "relative_path");
259
260 if (!mesh) {
261 return OPERATOR_CANCELLED;
262 }
263
264 if (CustomData_external_test(&mesh->corner_data, CD_MDISPS)) {
265 return OPERATOR_CANCELLED;
266 }
267
268 RNA_string_get(op->ptr, "filepath", filepath);
269
270 if (relative) {
271 BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
272 }
273
274 CustomData_external_add(&mesh->corner_data, &mesh->id, CD_MDISPS, mesh->corners_num, filepath);
276 &mesh->corner_data, &mesh->id, CD_MASK_MESH.lmask, mesh->corners_num, 0);
277
278 return OPERATOR_FINISHED;
279}
280
282 wmOperator *op,
283 const wmEvent * /*event*/)
284{
286 Mesh *mesh = static_cast<Mesh *>(ob->data);
287 char filepath[FILE_MAX];
288
290 return OPERATOR_CANCELLED;
291 }
292
294 op, ob, eModifierType_Multires);
295
296 if (!mmd) {
297 return OPERATOR_CANCELLED;
298 }
299
300 if (CustomData_external_test(&mesh->corner_data, CD_MDISPS)) {
301 return OPERATOR_CANCELLED;
302 }
303
304 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
305 return multires_external_save_exec(C, op);
306 }
307
308 op->customdata = mesh;
309
310 /* While a filename need not be UTF8, at this point the constructed name should be UTF8. */
311 SNPRINTF_UTF8(filepath, "//%s.btx", mesh->id.name + 2);
312 RNA_string_set(op->ptr, "filepath", filepath);
313
315
317}
318
320{
321 ot->name = "Multires Save External";
322 ot->description = "Save displacements to an external file";
323 ot->idname = "OBJECT_OT_multires_external_save";
324
325 /* XXX modifier no longer in context after file browser: `ot->poll = multires_poll;`. */
328 ot->poll = multires_poll;
329
330 /* flags */
332
336 FILE_SAVE,
341}
342
344
345/* ------------------------------------------------------------------- */
348
350{
352 Mesh *mesh = static_cast<Mesh *>(ob->data);
353
354 if (!CustomData_external_test(&mesh->corner_data, CD_MDISPS)) {
355 return OPERATOR_CANCELLED;
356 }
357
358 /* XXX don't remove. */
359 CustomData_external_remove(&mesh->corner_data, &mesh->id, CD_MDISPS, mesh->corners_num);
360
361 return OPERATOR_FINISHED;
362}
363
365{
366 ot->name = "Multires Pack External";
367 ot->description = "Pack displacements from an external file";
368 ot->idname = "OBJECT_OT_multires_external_pack";
369
370 ot->poll = multires_poll;
372
373 /* flags */
375}
376
378
379/* ------------------------------------------------------------------- */
382
409
411 wmOperator *op,
412 const wmEvent * /*event*/)
413{
415 return multires_base_apply_exec(C, op);
416 }
417 return OPERATOR_CANCELLED;
418}
419
421{
422 ot->name = "Multires Apply Base";
423 ot->description = "Modify the base mesh to conform to the displaced mesh";
424 ot->idname = "OBJECT_OT_multires_base_apply";
425
426 ot->poll = multires_poll;
429
430 /* flags */
434 ot->srna,
435 "apply_heuristic",
436 true,
437 "Apply Subdivision Heuristic",
438 "Whether or not the final base mesh positions will be slightly altered to account for a new "
439 "subdivision modifier being added");
441}
442
444
445/* ------------------------------------------------------------------- */
448
450{
452 Object *object = context_active_object(C);
454 op, object, eModifierType_Multires);
455
456 if (!mmd) {
457 return OPERATOR_CANCELLED;
458 }
459
460 int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
461 if (new_levels == 0) {
462 BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild a lower level");
463 return OPERATOR_CANCELLED;
464 }
465
468
469 return OPERATOR_FINISHED;
470}
471
473 wmOperator *op,
474 const wmEvent * /*event*/)
475{
477 return multires_unsubdivide_exec(C, op);
478 }
479 return OPERATOR_CANCELLED;
480}
481
483{
484 ot->name = "Unsubdivide";
485 ot->description = "Rebuild a lower subdivision level of the current base mesh";
486 ot->idname = "OBJECT_OT_multires_unsubdivide";
487
488 ot->poll = multires_poll;
491
492 /* flags */
495}
496
498
499/* ------------------------------------------------------------------- */
502
504{
506 Object *object = context_active_object(C);
508 op, object, eModifierType_Multires);
509
510 if (!mmd) {
511 return OPERATOR_CANCELLED;
512 }
513
514 int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
515 if (new_levels == 0) {
516 BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild lower levels");
517 return OPERATOR_CANCELLED;
518 }
519
520 BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
521
524
525 return OPERATOR_FINISHED;
526}
527
529 wmOperator *op,
530 const wmEvent * /*event*/)
531{
534 }
535 return OPERATOR_CANCELLED;
536}
537
539{
540 ot->name = "Rebuild Lower Subdivisions";
541 ot->description =
542 "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
543 ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
544
545 ot->poll = multires_poll;
548
549 /* flags */
552}
553
555
556} // namespace blender::ed::object
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
CustomData interface, see also DNA_customdata_types.h.
void CustomData_external_remove(CustomData *data, ID *id, eCustomDataType type, int totelem)
void CustomData_external_add(CustomData *data, ID *id, eCustomDataType type, int totelem, const char *filepath)
void CustomData_external_write(CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free)
bool CustomData_external_test(CustomData *data, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_MESH
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd, MultiresSubdivideModeType mode)
bool multiresModifier_reshapeFromObject(Depsgraph *depsgraph, MultiresModifierData *mmd, Object *dst, Object *src)
void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *object, int direction)
Definition multires.cc:526
MultiresSubdivideModeType
void multiresModifier_base_apply(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd, ApplyBaseMode mode)
ApplyBaseMode
int multiresModifier_rebuild_subdiv(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd, int rebuild_limit, bool switch_view_to_lower_level)
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2806
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define FILE_MAX
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
#define SNPRINTF_UTF8(dst, format,...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ eModifierType_Multires
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
@ OB_MESH
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_BTX
@ FILE_TYPE_FOLDER
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_SAVE
Definition WM_api.hh:1134
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_MODIFIER
Definition WM_types.hh:462
#define NC_OBJECT
Definition WM_types.hh:379
BPy_StructRNA * depsgraph
void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
bool edit_modifier_invoke_properties(bContext *C, wmOperator *op)
void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
void OBJECT_OT_multires_reshape(wmOperatorType *ot)
bool iter_other(Main *bmain, Object *orig_ob, bool include_orig, bool(*callback)(Object *ob, void *callback_data), void *callback_data)
static wmOperatorStatus multires_external_save_exec(bContext *C, wmOperator *op)
static wmOperatorStatus multires_higher_levels_delete_exec(bContext *C, wmOperator *op)
void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot)
bool multires_update_totlevels(Object *ob, void *totlevel_v)
static wmOperatorStatus multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
static wmOperatorStatus multires_base_apply_exec(bContext *C, wmOperator *op)
bool edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag, bool is_editmode_allowed, bool is_liboverride_allowed)
ModifierData * edit_modifier_property_get(wmOperator *op, Object *ob, int type)
static wmOperatorStatus multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *)
Object * context_active_object(const bContext *C)
void OBJECT_OT_multires_external_save(wmOperatorType *ot)
void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
static wmOperatorStatus multires_reshape_exec(bContext *C, wmOperator *op)
static wmOperatorStatus multires_rebuild_subdiv_invoke(bContext *C, wmOperator *op, const wmEvent *)
static EnumPropertyItem prop_multires_subdivide_mode_type[]
static wmOperatorStatus multires_unsubdivide_exec(bContext *C, wmOperator *op)
static wmOperatorStatus multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus multires_subdivide_exec(bContext *C, wmOperator *op)
static wmOperatorStatus multires_external_save_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OBJECT_OT_multires_external_pack(wmOperatorType *ot)
static wmOperatorStatus multires_external_pack_exec(bContext *C, wmOperator *)
static wmOperatorStatus multires_rebuild_subdiv_exec(bContext *C, wmOperator *op)
static bool multires_poll(bContext *C)
static wmOperatorStatus multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
void edit_modifier_properties(wmOperatorType *ot)
void push_multires_mesh_begin(bContext *C, const char *str)
void push_multires_mesh_end(bContext *C, const char *str)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
const char * name
Definition WM_types.hh:1033
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)