Blender V4.5
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.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 SNPRINTF(filepath, "//%s.btx", mesh->id.name + 2);
311 RNA_string_set(op->ptr, "filepath", filepath);
312
314
316}
317
319{
320 ot->name = "Multires Save External";
321 ot->description = "Save displacements to an external file";
322 ot->idname = "OBJECT_OT_multires_external_save";
323
324 /* XXX modifier no longer in context after file browser: `ot->poll = multires_poll;`. */
327 ot->poll = multires_poll;
328
329 /* flags */
331
335 FILE_SAVE,
340}
341
343
344/* ------------------------------------------------------------------- */
347
349{
351 Mesh *mesh = static_cast<Mesh *>(ob->data);
352
353 if (!CustomData_external_test(&mesh->corner_data, CD_MDISPS)) {
354 return OPERATOR_CANCELLED;
355 }
356
357 /* XXX don't remove. */
358 CustomData_external_remove(&mesh->corner_data, &mesh->id, CD_MDISPS, mesh->corners_num);
359
360 return OPERATOR_FINISHED;
361}
362
364{
365 ot->name = "Multires Pack External";
366 ot->description = "Pack displacements from an external file";
367 ot->idname = "OBJECT_OT_multires_external_pack";
368
369 ot->poll = multires_poll;
371
372 /* flags */
374}
375
377
378/* ------------------------------------------------------------------- */
381
404
406 wmOperator *op,
407 const wmEvent * /*event*/)
408{
410 return multires_base_apply_exec(C, op);
411 }
412 return OPERATOR_CANCELLED;
413}
414
416{
417 ot->name = "Multires Apply Base";
418 ot->description = "Modify the base mesh to conform to the displaced mesh";
419 ot->idname = "OBJECT_OT_multires_base_apply";
420
421 ot->poll = multires_poll;
424
425 /* flags */
428}
429
431
432/* ------------------------------------------------------------------- */
435
437{
439 Object *object = context_active_object(C);
441 op, object, eModifierType_Multires);
442
443 if (!mmd) {
444 return OPERATOR_CANCELLED;
445 }
446
447 int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
448 if (new_levels == 0) {
449 BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild a lower level");
450 return OPERATOR_CANCELLED;
451 }
452
455
456 return OPERATOR_FINISHED;
457}
458
460 wmOperator *op,
461 const wmEvent * /*event*/)
462{
464 return multires_unsubdivide_exec(C, op);
465 }
466 return OPERATOR_CANCELLED;
467}
468
470{
471 ot->name = "Unsubdivide";
472 ot->description = "Rebuild a lower subdivision level of the current base mesh";
473 ot->idname = "OBJECT_OT_multires_unsubdivide";
474
475 ot->poll = multires_poll;
478
479 /* flags */
482}
483
485
486/* ------------------------------------------------------------------- */
489
491{
493 Object *object = context_active_object(C);
495 op, object, eModifierType_Multires);
496
497 if (!mmd) {
498 return OPERATOR_CANCELLED;
499 }
500
501 int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
502 if (new_levels == 0) {
503 BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild lower levels");
504 return OPERATOR_CANCELLED;
505 }
506
507 BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
508
511
512 return OPERATOR_FINISHED;
513}
514
516 wmOperator *op,
517 const wmEvent * /*event*/)
518{
521 }
522 return OPERATOR_CANCELLED;
523}
524
526{
527 ot->name = "Rebuild Lower Subdivisions";
528 ot->description =
529 "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
530 ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
531
532 ot->poll = multires_poll;
535
536 /* flags */
539}
540
542
543} // 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:872
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:694
MultiresSubdivideModeType
void multiresModifier_base_apply(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
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:2666
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define FILE_MAX
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ 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
#define C
Definition RandGen.cpp:29
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_SAVE
Definition WM_api.hh:1085
@ 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:459
#define NC_OBJECT
Definition WM_types.hh:376
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)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
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)
const char * name
Definition WM_types.hh:1030
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:4225
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)