diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/object | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/object')
24 files changed, 20784 insertions, 19684 deletions
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 75d2fada7f3..8ef0d85bcfd 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -16,72 +16,72 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../bmesh - ../../depsgraph - ../../gpu - ../../ikplugin - ../../imbuf - ../../makesdna - ../../makesrna - ../../modifiers - ../../gpencil_modifiers - ../../shader_fx - ../../python - ../../render/extern/include - ../../windowmanager - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../gpu + ../../ikplugin + ../../imbuf + ../../makesdna + ../../makesrna + ../../modifiers + ../../gpencil_modifiers + ../../shader_fx + ../../python + ../../render/extern/include + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - object_add.c - object_bake.c - object_bake_api.c - object_collection.c - object_constraint.c - object_data_transfer.c - object_edit.c - object_facemap_ops.c - object_gpencil_modifier.c - object_hook.c - object_modes.c - object_modifier.c - object_ops.c - object_random.c - object_relations.c - object_select.c - object_shader_fx.c - object_shapekey.c - object_transform.c - object_utils.c - object_vgroup.c - object_warp.c + object_add.c + object_bake.c + object_bake_api.c + object_collection.c + object_constraint.c + object_data_transfer.c + object_edit.c + object_facemap_ops.c + object_gpencil_modifier.c + object_hook.c + object_modes.c + object_modifier.c + object_ops.c + object_random.c + object_relations.c + object_select.c + object_shader_fx.c + object_shapekey.c + object_transform.c + object_utils.c + object_vgroup.c + object_warp.c - object_intern.h + object_intern.h ) set(LIB - bf_blenkernel - bf_blenlib - bf_render + bf_blenkernel + bf_blenlib + bf_render ) add_definitions(${GL_DEFINITIONS}) if(WITH_PYTHON) - add_definitions(-DWITH_PYTHON) + add_definitions(-DWITH_PYTHON) endif() if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9269c25f54b..c050b579aa6 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -118,357 +117,392 @@ * kept here because of linking order. * Icons are only defined here */ const EnumPropertyItem rna_enum_light_type_items[] = { - {LA_LOCAL, "POINT", ICON_LIGHT_POINT, "Point", "Omnidirectional point light source"}, - {LA_SUN, "SUN", ICON_LIGHT_SUN, "Sun", "Constant direction parallel ray light source"}, - {LA_SPOT, "SPOT", ICON_LIGHT_SPOT, "Spot", "Directional cone light source"}, - {LA_AREA, "AREA", ICON_LIGHT_AREA, "Area", "Directional area light source"}, - {0, NULL, 0, NULL, NULL}, + {LA_LOCAL, "POINT", ICON_LIGHT_POINT, "Point", "Omnidirectional point light source"}, + {LA_SUN, "SUN", ICON_LIGHT_SUN, "Sun", "Constant direction parallel ray light source"}, + {LA_SPOT, "SPOT", ICON_LIGHT_SPOT, "Spot", "Directional cone light source"}, + {LA_AREA, "AREA", ICON_LIGHT_AREA, "Area", "Directional area light source"}, + {0, NULL, 0, NULL, NULL}, }; /* copy from rna_object_force.c */ static const EnumPropertyItem field_type_items[] = { - {PFIELD_FORCE, "FORCE", ICON_FORCE_FORCE, "Force", ""}, - {PFIELD_WIND, "WIND", ICON_FORCE_WIND, "Wind", ""}, - {PFIELD_VORTEX, "VORTEX", ICON_FORCE_VORTEX, "Vortex", ""}, - {PFIELD_MAGNET, "MAGNET", ICON_FORCE_MAGNETIC, "Magnetic", ""}, - {PFIELD_HARMONIC, "HARMONIC", ICON_FORCE_HARMONIC, "Harmonic", ""}, - {PFIELD_CHARGE, "CHARGE", ICON_FORCE_CHARGE, "Charge", ""}, - {PFIELD_LENNARDJ, "LENNARDJ", ICON_FORCE_LENNARDJONES, "Lennard-Jones", ""}, - {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", ""}, - {PFIELD_GUIDE, "GUIDE", ICON_FORCE_CURVE, "Curve Guide", ""}, - {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""}, - {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""}, - {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""}, - {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""}, - {0, NULL, 0, NULL, NULL}, + {PFIELD_FORCE, "FORCE", ICON_FORCE_FORCE, "Force", ""}, + {PFIELD_WIND, "WIND", ICON_FORCE_WIND, "Wind", ""}, + {PFIELD_VORTEX, "VORTEX", ICON_FORCE_VORTEX, "Vortex", ""}, + {PFIELD_MAGNET, "MAGNET", ICON_FORCE_MAGNETIC, "Magnetic", ""}, + {PFIELD_HARMONIC, "HARMONIC", ICON_FORCE_HARMONIC, "Harmonic", ""}, + {PFIELD_CHARGE, "CHARGE", ICON_FORCE_CHARGE, "Charge", ""}, + {PFIELD_LENNARDJ, "LENNARDJ", ICON_FORCE_LENNARDJONES, "Lennard-Jones", ""}, + {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", ""}, + {PFIELD_GUIDE, "GUIDE", ICON_FORCE_CURVE, "Curve Guide", ""}, + {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""}, + {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""}, + {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""}, + {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""}, + {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem lightprobe_type_items[] = { - {LIGHTPROBE_TYPE_CUBE, "CUBEMAP", ICON_LIGHTPROBE_CUBEMAP, "Reflection Cubemap", + {LIGHTPROBE_TYPE_CUBE, + "CUBEMAP", + ICON_LIGHTPROBE_CUBEMAP, + "Reflection Cubemap", "Reflection probe with spherical or cubic attenuation"}, - {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Reflection Plane", + {LIGHTPROBE_TYPE_PLANAR, + "PLANAR", + ICON_LIGHTPROBE_PLANAR, + "Reflection Plane", "Planar reflection probe"}, - {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Irradiance Volume", + {LIGHTPROBE_TYPE_GRID, + "GRID", + ICON_LIGHTPROBE_GRID, + "Irradiance Volume", "Irradiance probe to capture diffuse indirect lighting"}, - {0, NULL, 0, NULL, NULL}, + {0, NULL, 0, NULL, NULL}, }; /************************** Exported *****************************/ void ED_object_location_from_view(bContext *C, float loc[3]) { - const Scene *scene = CTX_data_scene(C); - copy_v3_v3(loc, scene->cursor.location); + const Scene *scene = CTX_data_scene(C); + copy_v3_v3(loc, scene->cursor.location); } void ED_object_rotation_from_quat(float rot[3], const float viewquat[4], const char align_axis) { - BLI_assert(align_axis >= 'X' && align_axis <= 'Z'); - - switch (align_axis) { - case 'X': - { - /* Same as 'rv3d->viewinv[1]' */ - float axis_y[4] = {0.0f, 1.0f, 0.0f}; - float quat_y[4], quat[4]; - axis_angle_to_quat(quat_y, axis_y, M_PI_2); - mul_qt_qtqt(quat, viewquat, quat_y); - quat_to_eul(rot, quat); - break; - } - case 'Y': - { - quat_to_eul(rot, viewquat); - rot[0] -= (float)M_PI_2; - break; - } - case 'Z': - { - quat_to_eul(rot, viewquat); - break; - } - } + BLI_assert(align_axis >= 'X' && align_axis <= 'Z'); + + switch (align_axis) { + case 'X': { + /* Same as 'rv3d->viewinv[1]' */ + float axis_y[4] = {0.0f, 1.0f, 0.0f}; + float quat_y[4], quat[4]; + axis_angle_to_quat(quat_y, axis_y, M_PI_2); + mul_qt_qtqt(quat, viewquat, quat_y); + quat_to_eul(rot, quat); + break; + } + case 'Y': { + quat_to_eul(rot, viewquat); + rot[0] -= (float)M_PI_2; + break; + } + case 'Z': { + quat_to_eul(rot, viewquat); + break; + } + } } void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_axis) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - BLI_assert(align_axis >= 'X' && align_axis <= 'Z'); - if (rv3d) { - float viewquat[4]; - copy_qt_qt(viewquat, rv3d->viewquat); - viewquat[0] *= -1.0f; - ED_object_rotation_from_quat(rot, viewquat, align_axis); - } - else { - zero_v3(rot); - } + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BLI_assert(align_axis >= 'X' && align_axis <= 'Z'); + if (rv3d) { + float viewquat[4]; + copy_qt_qt(viewquat, rv3d->viewquat); + viewquat[0] *= -1.0f; + ED_object_rotation_from_quat(rot, viewquat, align_axis); + } + else { + zero_v3(rot); + } } void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], const float rot[3]) { - Object *ob = base->object; - Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = base->object; + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); - if (!scene) return; + if (!scene) + return; - if (loc) - copy_v3_v3(ob->loc, loc); + if (loc) + copy_v3_v3(ob->loc, loc); - if (rot) - copy_v3_v3(ob->rot, rot); + if (rot) + copy_v3_v3(ob->rot, rot); - BKE_object_where_is_calc(depsgraph, scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); } /* Uses context to figure out transform for primitive. * Returns standard diameter. */ float ED_object_new_primitive_matrix( - bContext *C, Object *obedit, - const float loc[3], const float rot[3], float primmat[4][4]) + bContext *C, Object *obedit, const float loc[3], const float rot[3], float primmat[4][4]) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; - unit_m4(primmat); + unit_m4(primmat); - eul_to_mat3(rmat, rot); - invert_m3(rmat); + eul_to_mat3(rmat, rot); + invert_m3(rmat); - /* inverse transform for initial rotation and object */ - copy_m3_m4(mat, obedit->obmat); - mul_m3_m3m3(cmat, rmat, mat); - invert_m3_m3(imat, cmat); - copy_m4_m3(primmat, imat); + /* inverse transform for initial rotation and object */ + copy_m3_m4(mat, obedit->obmat); + mul_m3_m3m3(cmat, rmat, mat); + invert_m3_m3(imat, cmat); + copy_m4_m3(primmat, imat); - /* center */ - copy_v3_v3(primmat[3], loc); - sub_v3_v3v3(primmat[3], primmat[3], obedit->obmat[3]); - invert_m3_m3(imat, mat); - mul_m3_v3(imat, primmat[3]); + /* center */ + copy_v3_v3(primmat[3], loc); + sub_v3_v3v3(primmat[3], primmat[3], obedit->obmat[3]); + invert_m3_m3(imat, mat); + mul_m3_v3(imat, primmat[3]); - { - const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); - return dia; - } + { + const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : + ED_scene_grid_scale(scene, NULL); + return dia; + } - // return 1.0f; + // return 1.0f; } /********************* Add Object Operator ********************/ -static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr) +static void view_align_update(struct Main *UNUSED(main), + struct Scene *UNUSED(scene), + struct PointerRNA *ptr) { - RNA_struct_idprops_unset(ptr, "rotation"); + RNA_struct_idprops_unset(ptr, "rotation"); } void ED_object_add_unit_props_size(wmOperatorType *ot) { - RNA_def_float_distance(ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00); + RNA_def_float_distance( + ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00); } void ED_object_add_unit_props_radius(wmOperatorType *ot) { - RNA_def_float_distance(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); + RNA_def_float_distance( + ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); } void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) { - PropertyRNA *prop; - - /* note: this property gets hidden for add-camera operator */ - prop = RNA_def_boolean(ot->srna, "view_align", 0, "Align to View", "Align the new object to the view"); - RNA_def_property_update_runtime(prop, view_align_update); - - if (do_editmode) { - prop = RNA_def_boolean(ot->srna, "enter_editmode", 0, "Enter Editmode", - "Enter editmode when adding this object"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - } - - prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF, - "Location", "Location for the newly added object", -1000.0f, 1000.0f); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF, - "Rotation", "Rotation for the newly added object", - DEG2RADF(-360.0f), DEG2RADF(360.0f)); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* note: this property gets hidden for add-camera operator */ + prop = RNA_def_boolean( + ot->srna, "view_align", 0, "Align to View", "Align the new object to the view"); + RNA_def_property_update_runtime(prop, view_align_update); + + if (do_editmode) { + prop = RNA_def_boolean( + ot->srna, "enter_editmode", 0, "Enter Editmode", "Enter editmode when adding this object"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + } + + prop = RNA_def_float_vector_xyz(ot->srna, + "location", + 3, + NULL, + -OBJECT_ADD_SIZE_MAXF, + OBJECT_ADD_SIZE_MAXF, + "Location", + "Location for the newly added object", + -1000.0f, + 1000.0f); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_rotation(ot->srna, + "rotation", + 3, + NULL, + -OBJECT_ADD_SIZE_MAXF, + OBJECT_ADD_SIZE_MAXF, + "Rotation", + "Rotation for the newly added object", + DEG2RADF(-360.0f), + DEG2RADF(360.0f)); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void ED_object_add_mesh_props(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "calc_uvs", true, "Generate UVs", "Generate a default UV map"); -} - -bool ED_object_add_generic_get_opts( - bContext *C, wmOperator *op, const char view_align_axis, - float loc[3], float rot[3], - bool *enter_editmode, ushort *local_view_bits, bool *is_view_aligned) -{ - PropertyRNA *prop; - - /* Switch to Edit mode? optional prop */ - if ((prop = RNA_struct_find_property(op->ptr, "enter_editmode"))) { - bool _enter_editmode; - if (!enter_editmode) - enter_editmode = &_enter_editmode; - - if (RNA_property_is_set(op->ptr, prop) && enter_editmode) - *enter_editmode = RNA_property_boolean_get(op->ptr, prop); - else { - *enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0; - RNA_property_boolean_set(op->ptr, prop, *enter_editmode); - } - } - - if (local_view_bits) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d && v3d->localvd) { - *local_view_bits = v3d->local_view_uuid; - } - } - - /* Location! */ - { - float _loc[3]; - if (!loc) - loc = _loc; - - if (RNA_struct_property_is_set(op->ptr, "location")) { - RNA_float_get_array(op->ptr, "location", loc); - } - else { - ED_object_location_from_view(C, loc); - RNA_float_set_array(op->ptr, "location", loc); - } - } - - /* Rotation! */ - { - bool _is_view_aligned; - float _rot[3]; - if (!is_view_aligned) - is_view_aligned = &_is_view_aligned; - if (!rot) - rot = _rot; - - if (RNA_struct_property_is_set(op->ptr, "rotation")) - *is_view_aligned = false; - else if (RNA_struct_property_is_set(op->ptr, "view_align")) - *is_view_aligned = RNA_boolean_get(op->ptr, "view_align"); - else { - *is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0; - RNA_boolean_set(op->ptr, "view_align", *is_view_aligned); - } - - if (*is_view_aligned) { - ED_object_rotation_from_view(C, rot, view_align_axis); - RNA_float_set_array(op->ptr, "rotation", rot); - } - else - RNA_float_get_array(op->ptr, "rotation", rot); - } - - return true; + RNA_def_boolean(ot->srna, "calc_uvs", true, "Generate UVs", "Generate a default UV map"); +} + +bool ED_object_add_generic_get_opts(bContext *C, + wmOperator *op, + const char view_align_axis, + float loc[3], + float rot[3], + bool *enter_editmode, + ushort *local_view_bits, + bool *is_view_aligned) +{ + PropertyRNA *prop; + + /* Switch to Edit mode? optional prop */ + if ((prop = RNA_struct_find_property(op->ptr, "enter_editmode"))) { + bool _enter_editmode; + if (!enter_editmode) + enter_editmode = &_enter_editmode; + + if (RNA_property_is_set(op->ptr, prop) && enter_editmode) + *enter_editmode = RNA_property_boolean_get(op->ptr, prop); + else { + *enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0; + RNA_property_boolean_set(op->ptr, prop, *enter_editmode); + } + } + + if (local_view_bits) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d && v3d->localvd) { + *local_view_bits = v3d->local_view_uuid; + } + } + + /* Location! */ + { + float _loc[3]; + if (!loc) + loc = _loc; + + if (RNA_struct_property_is_set(op->ptr, "location")) { + RNA_float_get_array(op->ptr, "location", loc); + } + else { + ED_object_location_from_view(C, loc); + RNA_float_set_array(op->ptr, "location", loc); + } + } + + /* Rotation! */ + { + bool _is_view_aligned; + float _rot[3]; + if (!is_view_aligned) + is_view_aligned = &_is_view_aligned; + if (!rot) + rot = _rot; + + if (RNA_struct_property_is_set(op->ptr, "rotation")) + *is_view_aligned = false; + else if (RNA_struct_property_is_set(op->ptr, "view_align")) + *is_view_aligned = RNA_boolean_get(op->ptr, "view_align"); + else { + *is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0; + RNA_boolean_set(op->ptr, "view_align", *is_view_aligned); + } + + if (*is_view_aligned) { + ED_object_rotation_from_view(C, rot, view_align_axis); + RNA_float_set_array(op->ptr, "rotation", rot); + } + else + RNA_float_get_array(op->ptr, "rotation", rot); + } + + return true; } /* For object add primitive operators. * Do not call undo push in this function (users of this function have to). */ -Object *ED_object_add_type( - bContext *C, - int type, const char *name, - const float loc[3], const float rot[3], - bool enter_editmode, ushort local_view_bits) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob; - - /* for as long scene has editmode... */ - if (CTX_data_edit_object(C)) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - /* deselects all, sets active object */ - ob = BKE_object_add(bmain, scene, view_layer, type, name); - BASACT(view_layer)->local_view_bits = local_view_bits; - /* editor level activate, notifiers */ - ED_object_base_activate(C, view_layer->basact); - - /* more editor stuff */ - ED_object_base_init_transform(C, view_layer->basact, loc, rot); - - /* TODO(sergey): This is weird to manually tag objects for update, better to - * use DEG_id_tag_update here perhaps. - */ - DEG_id_type_tag(bmain, ID_OB); - DEG_relations_tag_update(bmain); - if (ob->data != NULL) { - DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS); - } - - if (enter_editmode) { - ED_object_editmode_enter_ex(bmain, scene, ob, 0); - } - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - - return ob; +Object *ED_object_add_type(bContext *C, + int type, + const char *name, + const float loc[3], + const float rot[3], + bool enter_editmode, + ushort local_view_bits) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob; + + /* for as long scene has editmode... */ + if (CTX_data_edit_object(C)) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + + /* deselects all, sets active object */ + ob = BKE_object_add(bmain, scene, view_layer, type, name); + BASACT(view_layer)->local_view_bits = local_view_bits; + /* editor level activate, notifiers */ + ED_object_base_activate(C, view_layer->basact); + + /* more editor stuff */ + ED_object_base_init_transform(C, view_layer->basact, loc, rot); + + /* TODO(sergey): This is weird to manually tag objects for update, better to + * use DEG_id_tag_update here perhaps. + */ + DEG_id_type_tag(bmain, ID_OB); + DEG_relations_tag_update(bmain); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS); + } + + if (enter_editmode) { + ED_object_editmode_enter_ex(bmain, scene, ob, 0); + } + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + + return ob; } /* for object add operator */ static int object_add_exec(bContext *C, wmOperator *op) { - Object *ob; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3], radius; + Object *ob; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3], radius; - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - radius = RNA_float_get(op->ptr, "radius"); - ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, local_view_bits); + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + radius = RNA_float_get(op->ptr, "radius"); + ob = ED_object_add_type( + C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, local_view_bits); - if (ob->type == OB_LATTICE) { - /* lattice is a special case! - * we never want to scale the obdata since that is the rest-state */ - copy_v3_fl(ob->scale, radius); - } - else { - BKE_object_obdata_size_init(ob, radius); - } + if (ob->type == OB_LATTICE) { + /* lattice is a special case! + * we never want to scale the obdata since that is the rest-state */ + copy_v3_fl(ob->scale, radius); + } + else { + BKE_object_obdata_size_init(ob, radius); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Object"; - ot->description = "Add an object to the scene"; - ot->idname = "OBJECT_OT_add"; + /* identifiers */ + ot->name = "Add Object"; + ot->description = "Add an object to the scene"; + ot->idname = "OBJECT_OT_add"; - /* api callbacks */ - ot->exec = object_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ED_object_add_unit_props_radius(ot); - PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", ""); - RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); + /* properties */ + ED_object_add_unit_props_radius(ot); + PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); - ED_object_add_generic_props(ot, true); + ED_object_add_generic_props(ot, true); } /********************** Add Probe Operator **********************/ @@ -476,82 +510,87 @@ void OBJECT_OT_add(wmOperatorType *ot) /* for object add operator */ static const char *get_lightprobe_defname(int type) { - switch (type) { - case LIGHTPROBE_TYPE_GRID: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "IrradianceVolume"); - case LIGHTPROBE_TYPE_PLANAR: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "ReflectionPlane"); - case LIGHTPROBE_TYPE_CUBE: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "ReflectionCubemap"); - default: - return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "LightProbe"); - } + switch (type) { + case LIGHTPROBE_TYPE_GRID: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "IrradianceVolume"); + case LIGHTPROBE_TYPE_PLANAR: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "ReflectionPlane"); + case LIGHTPROBE_TYPE_CUBE: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "ReflectionCubemap"); + default: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "LightProbe"); + } } static int lightprobe_add_exec(bContext *C, wmOperator *op) { - Object *ob; - LightProbe *probe; - int type; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3]; - float radius; - - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - type = RNA_enum_get(op->ptr, "type"); - radius = RNA_float_get(op->ptr, "radius"); - - ob = ED_object_add_type(C, OB_LIGHTPROBE, get_lightprobe_defname(type), loc, rot, false, local_view_bits); - copy_v3_fl(ob->scale, radius); - - probe = (LightProbe *)ob->data; - probe->type = type; - - switch (type) { - case LIGHTPROBE_TYPE_GRID: - probe->distinf = 0.3f; - probe->falloff = 1.0f; - probe->clipsta = 0.01f; - break; - case LIGHTPROBE_TYPE_PLANAR: - probe->distinf = 0.1f; - probe->falloff = 0.5f; - probe->clipsta = 0.001f; - ob->empty_drawsize = 0.5f; - break; - case LIGHTPROBE_TYPE_CUBE: - probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID; - break; - default: - BLI_assert(!"LightProbe type not configured."); - break; - } - - DEG_relations_tag_update(CTX_data_main(C)); - - return OPERATOR_FINISHED; + Object *ob; + LightProbe *probe; + int type; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3]; + float radius; + + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + type = RNA_enum_get(op->ptr, "type"); + radius = RNA_float_get(op->ptr, "radius"); + + ob = ED_object_add_type( + C, OB_LIGHTPROBE, get_lightprobe_defname(type), loc, rot, false, local_view_bits); + copy_v3_fl(ob->scale, radius); + + probe = (LightProbe *)ob->data; + probe->type = type; + + switch (type) { + case LIGHTPROBE_TYPE_GRID: + probe->distinf = 0.3f; + probe->falloff = 1.0f; + probe->clipsta = 0.01f; + break; + case LIGHTPROBE_TYPE_PLANAR: + probe->distinf = 0.1f; + probe->falloff = 0.5f; + probe->clipsta = 0.001f; + ob->empty_drawsize = 0.5f; + break; + case LIGHTPROBE_TYPE_CUBE: + probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID; + break; + default: + BLI_assert(!"LightProbe type not configured."); + break; + } + + DEG_relations_tag_update(CTX_data_main(C)); + + return OPERATOR_FINISHED; } void OBJECT_OT_lightprobe_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Light Probe"; - ot->description = "Add a light probe object"; - ot->idname = "OBJECT_OT_lightprobe_add"; + /* identifiers */ + ot->name = "Add Light Probe"; + ot->description = "Add a light probe object"; + ot->idname = "OBJECT_OT_lightprobe_add"; - /* api callbacks */ - ot->exec = lightprobe_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = lightprobe_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", lightprobe_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", lightprobe_type_items, 0, "Type", ""); - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, true); } /********************* Add Effector Operator ********************/ @@ -559,759 +598,768 @@ void OBJECT_OT_lightprobe_add(wmOperatorType *ot) /* for object add operator */ static int effector_add_exec(bContext *C, wmOperator *op) { - Object *ob; - int type; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3]; - float mat[4][4]; - float dia; - - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - type = RNA_enum_get(op->ptr, "type"); - dia = RNA_float_get(op->ptr, "radius"); - - if (type == PFIELD_GUIDE) { - Curve *cu; - const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "CurveGuide"); - ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, local_view_bits); - - cu = ob->data; - cu->flag |= CU_PATH | CU_3D; - ED_object_editmode_enter(C, 0); - ED_object_new_primitive_matrix(C, ob, loc, rot, mat); - BLI_addtail(&cu->editnurb->nurbs, ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia)); - if (!enter_editmode) - ED_object_editmode_exit(C, EM_FREEDATA); - } - else { - const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field"); - ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, local_view_bits); - BKE_object_obdata_size_init(ob, dia); - if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) - ob->empty_drawtype = OB_SINGLE_ARROW; - } - - ob->pd = BKE_partdeflect_new(type); - - DEG_relations_tag_update(CTX_data_main(C)); - - return OPERATOR_FINISHED; + Object *ob; + int type; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3]; + float mat[4][4]; + float dia; + + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + type = RNA_enum_get(op->ptr, "type"); + dia = RNA_float_get(op->ptr, "radius"); + + if (type == PFIELD_GUIDE) { + Curve *cu; + const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "CurveGuide"); + ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, local_view_bits); + + cu = ob->data; + cu->flag |= CU_PATH | CU_3D; + ED_object_editmode_enter(C, 0); + ED_object_new_primitive_matrix(C, ob, loc, rot, mat); + BLI_addtail(&cu->editnurb->nurbs, + ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia)); + if (!enter_editmode) + ED_object_editmode_exit(C, EM_FREEDATA); + } + else { + const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field"); + ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, local_view_bits); + BKE_object_obdata_size_init(ob, dia); + if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) + ob->empty_drawtype = OB_SINGLE_ARROW; + } + + ob->pd = BKE_partdeflect_new(type); + + DEG_relations_tag_update(CTX_data_main(C)); + + return OPERATOR_FINISHED; } void OBJECT_OT_effector_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Effector"; - ot->description = "Add an empty object with a physics effector to the scene"; - ot->idname = "OBJECT_OT_effector_add"; + /* identifiers */ + ot->name = "Add Effector"; + ot->description = "Add an empty object with a physics effector to the scene"; + ot->idname = "OBJECT_OT_effector_add"; - /* api callbacks */ - ot->exec = effector_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = effector_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", ""); - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, true); } /********************* Add Camera Operator ********************/ static int object_camera_add_exec(bContext *C, wmOperator *op) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - Object *ob; - Camera *cam; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3]; + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + Object *ob; + Camera *cam; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3]; - /* force view align for cameras */ - RNA_boolean_set(op->ptr, "view_align", true); + /* force view align for cameras */ + RNA_boolean_set(op->ptr, "view_align", true); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits); - if (v3d) { - if (v3d->camera == NULL) - v3d->camera = ob; - if (v3d->scenelock && scene->camera == NULL) { - scene->camera = ob; - } - } + if (v3d) { + if (v3d->camera == NULL) + v3d->camera = ob; + if (v3d->scenelock && scene->camera == NULL) { + scene->camera = ob; + } + } - cam = ob->data; - cam->drawsize = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); + cam = ob->data; + cam->drawsize = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_camera_add(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Add Camera"; - ot->description = "Add a camera object to the scene"; - ot->idname = "OBJECT_OT_camera_add"; + /* identifiers */ + ot->name = "Add Camera"; + ot->description = "Add a camera object to the scene"; + ot->idname = "OBJECT_OT_camera_add"; - /* api callbacks */ - ot->exec = object_camera_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_camera_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ED_object_add_generic_props(ot, true); + ED_object_add_generic_props(ot, true); - /* hide this for cameras, default */ - prop = RNA_struct_type_find_property(ot->srna, "view_align"); - RNA_def_property_flag(prop, PROP_HIDDEN); + /* hide this for cameras, default */ + prop = RNA_struct_type_find_property(ot->srna, "view_align"); + RNA_def_property_flag(prop, PROP_HIDDEN); } - /********************* Add Metaball Operator ********************/ static int object_metaball_add_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - bool newob = false; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3]; - float mat[4][4]; - float dia; + Object *obedit = CTX_data_edit_object(C); + bool newob = false; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3]; + float mat[4][4]; + float dia; - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - if (obedit == NULL || obedit->type != OB_MBALL) { - obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, local_view_bits); - newob = true; - } - else { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + if (obedit == NULL || obedit->type != OB_MBALL) { + obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, local_view_bits); + newob = true; + } + else { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } - ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); - dia = RNA_float_get(op->ptr, "radius"); + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + dia = RNA_float_get(op->ptr, "radius"); - ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); + ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); - /* userdef */ - if (newob && !enter_editmode) { - ED_object_editmode_exit(C, EM_FREEDATA); - } + /* userdef */ + if (newob && !enter_editmode) { + ED_object_editmode_exit(C, EM_FREEDATA); + } - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_metaball_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Metaball"; - ot->description = "Add an metaball object to the scene"; - ot->idname = "OBJECT_OT_metaball_add"; + /* identifiers */ + ot->name = "Add Metaball"; + ot->description = "Add an metaball object to the scene"; + ot->idname = "OBJECT_OT_metaball_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_metaball_add_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_metaball_add_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", ""); + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", ""); - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, true); + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, true); } /********************* Add Text Operator ********************/ static int object_add_text_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3]; + Object *obedit = CTX_data_edit_object(C); + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3]; - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - if (obedit && obedit->type == OB_FONT) - return OPERATOR_CANCELLED; + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + if (obedit && obedit->type == OB_FONT) + return OPERATOR_CANCELLED; - obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, local_view_bits); - BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius")); + obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, local_view_bits); + BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius")); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_text_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Text"; - ot->description = "Add a text object to the scene"; - ot->idname = "OBJECT_OT_text_add"; + /* identifiers */ + ot->name = "Add Text"; + ot->description = "Add a text object to the scene"; + ot->idname = "OBJECT_OT_text_add"; - /* api callbacks */ - ot->exec = object_add_text_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_add_text_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, true); + /* properties */ + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, true); } /********************* Add Armature Operator ********************/ static int object_armature_add_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - bool newob = false; - bool enter_editmode; - ushort local_view_bits; - float loc[3], rot[3], dia; - bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED); - - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) { - obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, local_view_bits); - ED_object_editmode_enter(C, 0); - newob = true; - } - else { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - - if (obedit == NULL) { - BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature"); - return OPERATOR_CANCELLED; - } - - dia = RNA_float_get(op->ptr, "radius"); - ED_armature_ebone_add_primitive(obedit, dia, view_aligned); - - /* userdef */ - if (newob && !enter_editmode) - ED_object_editmode_exit(C, EM_FREEDATA); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - - return OPERATOR_FINISHED; + Object *obedit = CTX_data_edit_object(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + bool newob = false; + bool enter_editmode; + ushort local_view_bits; + float loc[3], rot[3], dia; + bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED); + + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) { + obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, local_view_bits); + ED_object_editmode_enter(C, 0); + newob = true; + } + else { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } + + if (obedit == NULL) { + BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature"); + return OPERATOR_CANCELLED; + } + + dia = RNA_float_get(op->ptr, "radius"); + ED_armature_ebone_add_primitive(obedit, dia, view_aligned); + + /* userdef */ + if (newob && !enter_editmode) + ED_object_editmode_exit(C, EM_FREEDATA); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + + return OPERATOR_FINISHED; } void OBJECT_OT_armature_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Armature"; - ot->description = "Add an armature object to the scene"; - ot->idname = "OBJECT_OT_armature_add"; + /* identifiers */ + ot->name = "Add Armature"; + ot->description = "Add an armature object to the scene"; + ot->idname = "OBJECT_OT_armature_add"; - /* api callbacks */ - ot->exec = object_armature_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_armature_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, true); + /* properties */ + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, true); } /********************* Add Empty Operator ********************/ static int object_empty_add_exec(bContext *C, wmOperator *op) { - Object *ob; - int type = RNA_enum_get(op->ptr, "type"); - ushort local_view_bits; - float loc[3], rot[3]; + Object *ob; + int type = RNA_enum_get(op->ptr, "type"); + ushort local_view_bits; + float loc[3], rot[3]; - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits); + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits); - BKE_object_empty_draw_type_set(ob, type); - BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); + BKE_object_empty_draw_type_set(ob, type); + BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_empty_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Empty"; - ot->description = "Add an empty object to the scene"; - ot->idname = "OBJECT_OT_empty_add"; + /* identifiers */ + ot->name = "Add Empty"; + ot->description = "Add an empty object to the scene"; + ot->idname = "OBJECT_OT_empty_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_empty_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_empty_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", ""); - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, false); + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, false); } static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Scene *scene = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); - Image *ima = NULL; + Image *ima = NULL; - ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); - if (!ima) { - return OPERATOR_CANCELLED; - } - /* handled below */ - id_us_min((ID *)ima); + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + if (!ima) { + return OPERATOR_CANCELLED; + } + /* handled below */ + id_us_min((ID *)ima); - Object *ob = NULL; - Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval); + Object *ob = NULL; + Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval); - /* either change empty under cursor or create a new empty */ - if (ob_cursor && ob_cursor->type == OB_EMPTY) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - DEG_id_tag_update((ID *)ob_cursor, ID_RECALC_TRANSFORM); - ob = ob_cursor; - } - else { - /* add new empty */ - ushort local_view_bits; - float rot[3]; + /* either change empty under cursor or create a new empty */ + if (ob_cursor && ob_cursor->type == OB_EMPTY) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update((ID *)ob_cursor, ID_RECALC_TRANSFORM); + ob = ob_cursor; + } + else { + /* add new empty */ + ushort local_view_bits; + float rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits); + if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits); - ED_object_location_from_view(C, ob->loc); - ED_view3d_cursor3d_position(C, event->mval, false, ob->loc); - ED_object_rotation_from_view(C, ob->rot, 'Z'); - ob->empty_drawsize = 5.0f; - } + ED_object_location_from_view(C, ob->loc); + ED_view3d_cursor3d_position(C, event->mval, false, ob->loc); + ED_object_rotation_from_view(C, ob->rot, 'Z'); + ob->empty_drawsize = 5.0f; + } - BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE); + BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE); - id_us_min(ob->data); - ob->data = ima; - id_us_plus(ob->data); + id_us_min(ob->data); + ob->data = ima; + id_us_plus(ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_drop_named_image(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Add Empty Image/Drop Image To Empty"; - ot->description = "Add an empty image type to scene with data"; - ot->idname = "OBJECT_OT_drop_named_image"; + /* identifiers */ + ot->name = "Add Empty Image/Drop Image To Empty"; + ot->description = "Add an empty image type to scene with data"; + ot->idname = "OBJECT_OT_drop_named_image"; - /* api callbacks */ - ot->invoke = empty_drop_named_image_invoke; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = empty_drop_named_image_invoke; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "Filepath", "Path to image file"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Image name to assign"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - ED_object_add_generic_props(ot, false); + /* properties */ + prop = RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "Filepath", "Path to image file"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, + "relative_path", + true, + "Relative Path", + "Select the file relative to the blend file"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Image name to assign"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + ED_object_add_generic_props(ot, false); } /********************* Add Gpencil Operator ********************/ static bool object_gpencil_add_poll(bContext *C) { - Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); - if ((scene == NULL) || (ID_IS_LINKED(scene))) { - return false; - } + if ((scene == NULL) || (ID_IS_LINKED(scene))) { + return false; + } - if (obact && obact->type == OB_GPENCIL) { - if (obact->mode != OB_MODE_OBJECT) { - return false; - } - } + if (obact && obact->type == OB_GPENCIL) { + if (obact->mode != OB_MODE_OBJECT) { + return false; + } + } - return true; + return true; } static int object_gpencil_add_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL; - - const int type = RNA_enum_get(op->ptr, "type"); - - ushort local_view_bits; - float loc[3], rot[3]; - bool newob = false; - - /* Note: We use 'Y' here (not 'Z'), as */ - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - /* add new object if not currently editing a GP object, - * or if "empty" was chosen (i.e. user wants a blank GP canvas) - */ - if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) { - const char *ob_name = NULL; - switch (type) { - case GP_MONKEY: - { - ob_name = "Suzanne"; - break; - } - case GP_STROKE: - { - ob_name = "Stroke"; - break; - } - default: - { - break; - } - } - - ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, local_view_bits); - gpd = ob->data; - newob = true; - } - else { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL); - } - - /* create relevant geometry */ - switch (type) { - case GP_STROKE: - { - float radius = RNA_float_get(op->ptr, "radius"); - float mat[4][4]; - - ED_object_new_primitive_matrix(C, ob, loc, rot, mat); - mul_v3_fl(mat[0], radius); - mul_v3_fl(mat[1], radius); - mul_v3_fl(mat[2], radius); - - ED_gpencil_create_stroke(C, ob, mat); - break; - } - case GP_MONKEY: - { - float radius = RNA_float_get(op->ptr, "radius"); - float mat[4][4]; - - ED_object_new_primitive_matrix(C, ob, loc, rot, mat); - mul_v3_fl(mat[0], radius); - mul_v3_fl(mat[1], radius); - mul_v3_fl(mat[2], radius); - - ED_gpencil_create_monkey(C, ob, mat); - break; - } - case GP_EMPTY: - /* do nothing */ - break; - - default: - BKE_report(op->reports, RPT_WARNING, "Not implemented"); - break; - } - - /* if this is a new object, initialise default stuff (colors, etc.) */ - if (newob) { - /* set default viewport color to black */ - copy_v3_fl(ob->color, 0.0f); - - ED_gpencil_add_defaults(C, ob); - } - - return OPERATOR_FINISHED; + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL; + + const int type = RNA_enum_get(op->ptr, "type"); + + ushort local_view_bits; + float loc[3], rot[3]; + bool newob = false; + + /* Note: We use 'Y' here (not 'Z'), as */ + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + /* add new object if not currently editing a GP object, + * or if "empty" was chosen (i.e. user wants a blank GP canvas) + */ + if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) { + const char *ob_name = NULL; + switch (type) { + case GP_MONKEY: { + ob_name = "Suzanne"; + break; + } + case GP_STROKE: { + ob_name = "Stroke"; + break; + } + default: { + break; + } + } + + ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, local_view_bits); + gpd = ob->data; + newob = true; + } + else { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL); + } + + /* create relevant geometry */ + switch (type) { + case GP_STROKE: { + float radius = RNA_float_get(op->ptr, "radius"); + float mat[4][4]; + + ED_object_new_primitive_matrix(C, ob, loc, rot, mat); + mul_v3_fl(mat[0], radius); + mul_v3_fl(mat[1], radius); + mul_v3_fl(mat[2], radius); + + ED_gpencil_create_stroke(C, ob, mat); + break; + } + case GP_MONKEY: { + float radius = RNA_float_get(op->ptr, "radius"); + float mat[4][4]; + + ED_object_new_primitive_matrix(C, ob, loc, rot, mat); + mul_v3_fl(mat[0], radius); + mul_v3_fl(mat[1], radius); + mul_v3_fl(mat[2], radius); + + ED_gpencil_create_monkey(C, ob, mat); + break; + } + case GP_EMPTY: + /* do nothing */ + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Not implemented"); + break; + } + + /* if this is a new object, initialise default stuff (colors, etc.) */ + if (newob) { + /* set default viewport color to black */ + copy_v3_fl(ob->color, 0.0f); + + ED_gpencil_add_defaults(C, ob); + } + + return OPERATOR_FINISHED; } void OBJECT_OT_gpencil_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Grease Pencil"; - ot->description = "Add a Grease Pencil object to the scene"; - ot->idname = "OBJECT_OT_gpencil_add"; + /* identifiers */ + ot->name = "Add Grease Pencil"; + ot->description = "Add a Grease Pencil object to the scene"; + ot->idname = "OBJECT_OT_gpencil_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_gpencil_add_exec; - ot->poll = object_gpencil_add_poll; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_gpencil_add_exec; + ot->poll = object_gpencil_add_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, false); + /* properties */ + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, false); - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); } /********************* Add Light Operator ********************/ static const char *get_light_defname(int type) { - switch (type) { - case LA_LOCAL: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Point"); - case LA_SUN: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Sun"); - case LA_SPOT: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Spot"); - case LA_AREA: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Area"); - default: - return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Light"); - } + switch (type) { + case LA_LOCAL: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Point"); + case LA_SUN: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Sun"); + case LA_SPOT: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Spot"); + case LA_AREA: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Area"); + default: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Light"); + } } static int object_light_add_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob; - Light *la; - int type = RNA_enum_get(op->ptr, "type"); - ushort local_view_bits; - float loc[3], rot[3]; - - WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits); - - float size = RNA_float_get(op->ptr, "radius"); - /* Better defaults for light size. */ - switch (type) { - case LA_LOCAL: - case LA_SPOT: - break; - case LA_AREA: - size *= 4.0f; - break; - default: - size *= 0.5f; - break; - } - BKE_object_obdata_size_init(ob, size); - - la = (Light *)ob->data; - la->type = type; - - if (BKE_scene_uses_cycles(scene)) { - ED_node_shader_default(C, &la->id); - la->use_nodes = true; - } - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Object *ob; + Light *la; + int type = RNA_enum_get(op->ptr, "type"); + ushort local_view_bits; + float loc[3], rot[3]; + + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits); + + float size = RNA_float_get(op->ptr, "radius"); + /* Better defaults for light size. */ + switch (type) { + case LA_LOCAL: + case LA_SPOT: + break; + case LA_AREA: + size *= 4.0f; + break; + default: + size *= 0.5f; + break; + } + BKE_object_obdata_size_init(ob, size); + + la = (Light *)ob->data; + la->type = type; + + if (BKE_scene_uses_cycles(scene)) { + ED_node_shader_default(C, &la->id); + la->use_nodes = true; + } + + return OPERATOR_FINISHED; } void OBJECT_OT_light_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Light"; - ot->description = "Add a light object to the scene"; - ot->idname = "OBJECT_OT_light_add"; + /* identifiers */ + ot->name = "Add Light"; + ot->description = "Add a light object to the scene"; + ot->idname = "OBJECT_OT_light_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_light_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_light_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_light_type_items, 0, "Type", ""); - RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LIGHT); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_light_type_items, 0, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LIGHT); - ED_object_add_unit_props_radius(ot); - ED_object_add_generic_props(ot, false); + ED_object_add_unit_props_radius(ot); + ED_object_add_generic_props(ot, false); } /********************* Add Collection Instance Operator ********************/ static int collection_instance_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Collection *collection; - ushort local_view_bits; - float loc[3], rot[3]; - - if (RNA_struct_property_is_set(op->ptr, "name")) { - char name[MAX_ID_NAME - 2]; - - RNA_string_get(op->ptr, "name", name); - collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name); - - if (0 == RNA_struct_property_is_set(op->ptr, "location")) { - const wmEvent *event = CTX_wm_window(C)->eventstate; - ARegion *ar = CTX_wm_region(C); - const int mval[2] = {event->x - ar->winrct.xmin, - event->y - ar->winrct.ymin}; - ED_object_location_from_view(C, loc); - ED_view3d_cursor3d_position(C, mval, false, loc); - RNA_float_set_array(op->ptr, "location", loc); - } - } - else - collection = BLI_findlink(&CTX_data_main(C)->collections, RNA_enum_get(op->ptr, "collection")); - - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - if (collection) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* Avoid dependency cycles. */ - LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); - while (BKE_collection_find_cycle(active_lc->collection, collection)) { - active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); - } - - Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits); - ob->instance_collection = collection; - ob->transflag |= OB_DUPLICOLLECTION; - id_us_plus(&collection->id); - - /* works without this except if you try render right after, see: 22027 */ - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; + Main *bmain = CTX_data_main(C); + Collection *collection; + ushort local_view_bits; + float loc[3], rot[3]; + + if (RNA_struct_property_is_set(op->ptr, "name")) { + char name[MAX_ID_NAME - 2]; + + RNA_string_get(op->ptr, "name", name); + collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name); + + if (0 == RNA_struct_property_is_set(op->ptr, "location")) { + const wmEvent *event = CTX_wm_window(C)->eventstate; + ARegion *ar = CTX_wm_region(C); + const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; + ED_object_location_from_view(C, loc); + ED_view3d_cursor3d_position(C, mval, false, loc); + RNA_float_set_array(op->ptr, "location", loc); + } + } + else + collection = BLI_findlink(&CTX_data_main(C)->collections, RNA_enum_get(op->ptr, "collection")); + + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + if (collection) { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + /* Avoid dependency cycles. */ + LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); + while (BKE_collection_find_cycle(active_lc->collection, collection)) { + active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); + } + + Object *ob = ED_object_add_type( + C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits); + ob->instance_collection = collection; + ob->transflag |= OB_DUPLICOLLECTION; + id_us_plus(&collection->id); + + /* works without this except if you try render right after, see: 22027 */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } /* only used as menu */ void OBJECT_OT_collection_instance_add(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Add Collection Instance"; - ot->description = "Add a collection instance"; - ot->idname = "OBJECT_OT_collection_instance_add"; + /* identifiers */ + ot->name = "Add Collection Instance"; + ot->description = "Add a collection instance"; + ot->idname = "OBJECT_OT_collection_instance_add"; - /* api callbacks */ - ot->invoke = WM_enum_search_invoke; - ot->exec = collection_instance_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = WM_enum_search_invoke; + ot->exec = collection_instance_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add"); - prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); - RNA_def_enum_funcs(prop, RNA_collection_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; - ED_object_add_generic_props(ot, false); + /* properties */ + RNA_def_string( + ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add"); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); + RNA_def_enum_funcs(prop, RNA_collection_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; + ED_object_add_generic_props(ot, false); } /********************* Add Speaker Operator ********************/ static int object_speaker_add_exec(bContext *C, wmOperator *op) { - Object *ob; - ushort local_view_bits; - float loc[3], rot[3]; - Scene *scene = CTX_data_scene(C); + Object *ob; + ushort local_view_bits; + float loc[3], rot[3]; + Scene *scene = CTX_data_scene(C); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { - return OPERATOR_CANCELLED; - } - ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + return OPERATOR_CANCELLED; + } + ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); - /* to make it easier to start using this immediately in NLA, a default sound clip is created - * ready to be moved around to retime the sound and/or make new sound clips - */ - { - /* create new data for NLA hierarchy */ - AnimData *adt = BKE_animdata_add_id(&ob->id); - NlaTrack *nlt = BKE_nlatrack_add(adt, NULL); - NlaStrip *strip = BKE_nla_add_soundstrip(scene, ob->data); - strip->start = CFRA; - strip->end += strip->start; + /* to make it easier to start using this immediately in NLA, a default sound clip is created + * ready to be moved around to retime the sound and/or make new sound clips + */ + { + /* create new data for NLA hierarchy */ + AnimData *adt = BKE_animdata_add_id(&ob->id); + NlaTrack *nlt = BKE_nlatrack_add(adt, NULL); + NlaStrip *strip = BKE_nla_add_soundstrip(scene, ob->data); + strip->start = CFRA; + strip->end += strip->start; - /* hook them up */ - BKE_nlatrack_add_strip(nlt, strip); + /* hook them up */ + BKE_nlatrack_add_strip(nlt, strip); - /* auto-name the strip, and give the track an interesting name */ - BLI_strncpy(nlt->name, DATA_("SoundTrack"), sizeof(nlt->name)); - BKE_nlastrip_validate_name(adt, strip); + /* auto-name the strip, and give the track an interesting name */ + BLI_strncpy(nlt->name, DATA_("SoundTrack"), sizeof(nlt->name)); + BKE_nlastrip_validate_name(adt, strip); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); - } + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_speaker_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Speaker"; - ot->description = "Add a speaker object to the scene"; - ot->idname = "OBJECT_OT_speaker_add"; + /* identifiers */ + ot->name = "Add Speaker"; + ot->description = "Add a speaker object to the scene"; + ot->idname = "OBJECT_OT_speaker_add"; - /* api callbacks */ - ot->exec = object_speaker_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_speaker_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ED_object_add_generic_props(ot, true); + ED_object_add_generic_props(ot, true); } /**************************** Delete Object *************************/ @@ -1320,143 +1368,153 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) /* note: now unlinks constraints as well */ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) { - if (BKE_library_ID_is_indirectly_used(bmain, ob) && - ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) - { - /* We cannot delete indirectly used object... */ - printf("WARNING, undeletable object '%s', should have been catched before reaching this function!", - ob->id.name + 2); - return; - } + if (BKE_library_ID_is_indirectly_used(bmain, ob) && ID_REAL_USERS(ob) <= 1 && + ID_EXTRA_USERS(ob) == 0) { + /* We cannot delete indirectly used object... */ + printf( + "WARNING, undeletable object '%s', should have been catched before reaching this " + "function!", + ob->id.name + 2); + return; + } - DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_BASE_FLAGS); + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_BASE_FLAGS); - BKE_scene_collections_object_remove(bmain, scene, ob, true); + BKE_scene_collections_object_remove(bmain, scene, ob, true); } static int object_delete_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win; - const bool use_global = RNA_boolean_get(op->ptr, "use_global"); - uint changed_count = 0; - - if (CTX_data_edit_object(C)) - return OPERATOR_CANCELLED; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob); - if (ob->id.tag & LIB_TAG_INDIRECT) { - /* Can this case ever happen? */ - BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); - continue; - } - else if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { - BKE_reportf(op->reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - ob->id.name + 2, scene->id.name + 2); - continue; - } - - /* if grease pencil object, set cache as dirty */ - if (ob->type == OB_GPENCIL) { - bGPdata *gpd = (bGPdata *)ob->data; - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - } - - /* This is sort of a quick hack to address T51243 - Proper thing to do here would be to nuke most of all this - * custom scene/object/base handling, and use generic lib remap/query for that. - * But this is for later (aka 2.8, once layers & co are settled and working). - */ - if (use_global && ob->id.lib == NULL) { - /* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */ - BKE_id_delete(bmain, &ob->id); - changed_count += 1; - continue; - } - - /* remove from Grease Pencil parent */ - /* XXX This is likely not correct? Will also remove parent from grease pencil from other scenes, - * even when use_global is false... */ - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent != NULL) { - if (gpl->parent == ob) { - gpl->parent = NULL; - } - } - } - } - - /* remove from current scene only */ - ED_object_base_free_and_unlink(bmain, scene, ob); - changed_count += 1; - - if (use_global) { - Scene *scene_iter; - for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) { - if (scene_iter != scene && !ID_IS_LINKED(scene_iter)) { - if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { - BKE_reportf(op->reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - ob->id.name + 2, scene_iter->id.name + 2); - break; - } - ED_object_base_free_and_unlink(bmain, scene_iter, ob); - } - } - } - /* end global */ - } - CTX_DATA_END; - - BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count); - - if (changed_count == 0) { - return OPERATOR_CANCELLED; - } - - /* delete has to handle all open scenes */ - BKE_main_id_tag_listbase(&bmain->scenes, LIB_TAG_DOIT, true); - for (win = wm->windows.first; win; win = win->next) { - scene = WM_window_get_active_scene(win); - - if (scene->id.tag & LIB_TAG_DOIT) { - scene->id.tag &= ~LIB_TAG_DOIT; - - DEG_relations_tag_update(bmain); - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - } - } - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win; + const bool use_global = RNA_boolean_get(op->ptr, "use_global"); + uint changed_count = 0; + + if (CTX_data_edit_object(C)) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob); + if (ob->id.tag & LIB_TAG_INDIRECT) { + /* Can this case ever happen? */ + BKE_reportf(op->reports, + RPT_WARNING, + "Cannot delete indirectly linked object '%s'", + ob->id.name + 2); + continue; + } + else if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { + BKE_reportf(op->reports, + RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at " + "least one user", + ob->id.name + 2, + scene->id.name + 2); + continue; + } + + /* if grease pencil object, set cache as dirty */ + if (ob->type == OB_GPENCIL) { + bGPdata *gpd = (bGPdata *)ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } + + /* This is sort of a quick hack to address T51243 - Proper thing to do here would be to nuke most of all this + * custom scene/object/base handling, and use generic lib remap/query for that. + * But this is for later (aka 2.8, once layers & co are settled and working). + */ + if (use_global && ob->id.lib == NULL) { + /* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */ + BKE_id_delete(bmain, &ob->id); + changed_count += 1; + continue; + } + + /* remove from Grease Pencil parent */ + /* XXX This is likely not correct? Will also remove parent from grease pencil from other scenes, + * even when use_global is false... */ + for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent != NULL) { + if (gpl->parent == ob) { + gpl->parent = NULL; + } + } + } + } + + /* remove from current scene only */ + ED_object_base_free_and_unlink(bmain, scene, ob); + changed_count += 1; + + if (use_global) { + Scene *scene_iter; + for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) { + if (scene_iter != scene && !ID_IS_LINKED(scene_iter)) { + if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { + BKE_reportf(op->reports, + RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need " + "at least one user", + ob->id.name + 2, + scene_iter->id.name + 2); + break; + } + ED_object_base_free_and_unlink(bmain, scene_iter, ob); + } + } + } + /* end global */ + } + CTX_DATA_END; + + BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count); + + if (changed_count == 0) { + return OPERATOR_CANCELLED; + } + + /* delete has to handle all open scenes */ + BKE_main_id_tag_listbase(&bmain->scenes, LIB_TAG_DOIT, true); + for (win = wm->windows.first; win; win = win->next) { + scene = WM_window_get_active_scene(win); + + if (scene->id.tag & LIB_TAG_DOIT) { + scene->id.tag &= ~LIB_TAG_DOIT; + + DEG_relations_tag_update(bmain); + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + } + } + + return OPERATOR_FINISHED; } void OBJECT_OT_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete"; - ot->description = "Delete selected objects"; - ot->idname = "OBJECT_OT_delete"; + /* identifiers */ + ot->name = "Delete"; + ot->description = "Delete selected objects"; + ot->idname = "OBJECT_OT_delete"; - /* api callbacks */ - ot->invoke = WM_operator_confirm_or_exec; - ot->exec = object_delete_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = WM_operator_confirm_or_exec; + ot->exec = object_delete_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - PropertyRNA *prop; - prop = RNA_def_boolean(ot->srna, "use_global", 0, "Delete Globally", "Remove object from all scenes"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - WM_operator_properties_confirm_or_exec(ot); + PropertyRNA *prop; + prop = RNA_def_boolean( + ot->srna, "use_global", 0, "Delete Globally", "Remove object from all scenes"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + WM_operator_properties_confirm_or_exec(ot); } /**************************** Copy Utilities ******************************/ @@ -1464,15 +1522,14 @@ void OBJECT_OT_delete(wmOperatorType *ot) /* after copying objects, copied data should get new pointers */ static void copy_object_set_idnew(bContext *C) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main(C); - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - BKE_libblock_relink_to_newid(&ob->id); - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + BKE_libblock_relink_to_newid(&ob->id); + } + CTX_DATA_END; - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_clear_newpoins(bmain); } /********************* Make Duplicates Real ************************/ @@ -1483,13 +1540,13 @@ static void copy_object_set_idnew(bContext *C) */ static unsigned int dupliobject_group_hash(const void *ptr) { - const DupliObject *dob = ptr; - unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - unsigned int i; - for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { - hash ^= (dob->persistent_id[i] ^ i); - } - return hash; + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + unsigned int i; + for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } + return hash; } /** @@ -1498,704 +1555,714 @@ static unsigned int dupliobject_group_hash(const void *ptr) */ static unsigned int dupliobject_hash(const void *ptr) { - const DupliObject *dob = ptr; - unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - hash ^= (dob->persistent_id[0] ^ 0); - return hash; + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + hash ^= (dob->persistent_id[0] ^ 0); + return hash; } /* Compare function that matches dupliobject_group_hash */ static bool dupliobject_group_cmp(const void *a_, const void *b_) { - const DupliObject *a = a_; - const DupliObject *b = b_; - unsigned int i; + const DupliObject *a = a_; + const DupliObject *b = b_; + unsigned int i; - if (a->ob != b->ob) { - return true; - } + if (a->ob != b->ob) { + return true; + } - for (i = 1; (i < MAX_DUPLI_RECUR); i++) { - if (a->persistent_id[i] != b->persistent_id[i]) { - return true; - } - else if (a->persistent_id[i] == INT_MAX) { - break; - } - } + for (i = 1; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } + } - /* matching */ - return false; + /* matching */ + return false; } /* Compare function that matches dupliobject_hash */ static bool dupliobject_cmp(const void *a_, const void *b_) { - const DupliObject *a = a_; - const DupliObject *b = b_; - - if (a->ob != b->ob) { - return true; - } - - if (a->persistent_id[0] != b->persistent_id[0]) { - return true; - } - - /* matching */ - return false; -} - -static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, - const bool use_base_parent, - const bool use_hierarchy) -{ - Main *bmain = CTX_data_main(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ListBase *lb_duplis; - DupliObject *dob; - GHash *dupli_gh, *parent_gh = NULL; - - if (!(base->object->transflag & OB_DUPLI)) { - return; - } - - Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object); - lb_duplis = object_duplilist(depsgraph, scene, object_eval); - - dupli_gh = BLI_ghash_ptr_new(__func__); - if (use_hierarchy) { - if (base->object->transflag & OB_DUPLICOLLECTION) { - parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); - } - else { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); - } - } - - for (dob = lb_duplis->first; dob; dob = dob->next) { - Object *ob_src = DEG_get_original_object(dob->ob); - Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); - Base *base_dst; - - /* font duplis can have a totcol without material, we get them from parent - * should be implemented better... - */ - if (ob_dst->mat == NULL) { - ob_dst->totcol = 0; - } - - BKE_collection_object_add_from(bmain, scene, base->object, ob_dst); - base_dst = BKE_view_layer_base_find(view_layer, ob_dst); - BLI_assert(base_dst != NULL); - - BKE_scene_object_base_flag_sync_from_base(base_dst); - - /* make sure apply works */ - BKE_animdata_free(&ob_dst->id, true); - ob_dst->adt = NULL; - - /* Proxies are not to be copied. */ - ob_dst->proxy_from = NULL; - ob_dst->proxy_group = NULL; - ob_dst->proxy = NULL; - - ob_dst->parent = NULL; - BKE_constraints_free(&ob_dst->constraints); - ob_dst->runtime.curve_cache = NULL; - ob_dst->transflag &= ~OB_DUPLI; - - copy_m4_m4(ob_dst->obmat, dob->mat); - BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); - - BLI_ghash_insert(dupli_gh, dob, ob_dst); - if (parent_gh) { - void **val; - /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as - * 'the same', this avoids trying to insert same key several time and - * raise asserts in debug builds... */ - if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { - *val = ob_dst; - } - } - } - - for (dob = lb_duplis->first; dob; dob = dob->next) { - Object *ob_src = dob->ob; - Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); - - /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob_dst->id); - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - - if (use_hierarchy) { - /* original parents */ - Object *ob_src_par = ob_src->parent; - Object *ob_dst_par = NULL; - - /* find parent that was also made real */ - if (ob_src_par) { - /* OK to keep most of the members uninitialized, - * they won't be read, this is simply for a hash lookup. */ - DupliObject dob_key; - dob_key.ob = ob_src_par; - if (base->object->transflag & OB_DUPLICOLLECTION) { - memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); - } - else { - dob_key.persistent_id[0] = dob->persistent_id[0]; - } - ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); - } - - if (ob_dst_par) { - /* allow for all possible parent types */ - ob_dst->partype = ob_src->partype; - BLI_strncpy(ob_dst->parsubstr, ob_src->parsubstr, sizeof(ob_dst->parsubstr)); - ob_dst->par1 = ob_src->par1; - ob_dst->par2 = ob_src->par2; - ob_dst->par3 = ob_src->par3; - - copy_m4_m4(ob_dst->parentinv, ob_src->parentinv); - - ob_dst->parent = ob_dst_par; - } - else if (use_base_parent) { - ob_dst->parent = base->object; - ob_dst->partype = PAROBJECT; - } - } - else if (use_base_parent) { - /* since we are ignoring the internal hierarchy - parent all to the - * base object */ - ob_dst->parent = base->object; - ob_dst->partype = PAROBJECT; - } - - if (ob_dst->parent) { - /* note, this may be the parent of other objects, but it should - * still work out ok */ - BKE_object_apply_mat4(ob_dst, dob->mat, false, true); - - /* to set ob_dst->orig and in case there's any other discrepancies */ - DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM); - } - } - - if (base->object->transflag & OB_DUPLICOLLECTION && base->object->instance_collection) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->proxy_group == base->object) { - ob->proxy = NULL; - ob->proxy_from = NULL; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - } - } - - BLI_ghash_free(dupli_gh, NULL, NULL); - if (parent_gh) { - BLI_ghash_free(parent_gh, NULL, NULL); - } - - free_object_duplilist(lb_duplis); - - BKE_main_id_clear_newpoins(bmain); - - base->object->transflag &= ~OB_DUPLI; - DEG_id_tag_update(&base->object->id, ID_RECALC_COPY_ON_WRITE); + const DupliObject *a = a_; + const DupliObject *b = b_; + + if (a->ob != b->ob) { + return true; + } + + if (a->persistent_id[0] != b->persistent_id[0]) { + return true; + } + + /* matching */ + return false; +} + +static void make_object_duplilist_real( + bContext *C, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy) +{ + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ListBase *lb_duplis; + DupliObject *dob; + GHash *dupli_gh, *parent_gh = NULL; + + if (!(base->object->transflag & OB_DUPLI)) { + return; + } + + Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object); + lb_duplis = object_duplilist(depsgraph, scene, object_eval); + + dupli_gh = BLI_ghash_ptr_new(__func__); + if (use_hierarchy) { + if (base->object->transflag & OB_DUPLICOLLECTION) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } + } + + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = DEG_get_original_object(dob->ob); + Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); + Base *base_dst; + + /* font duplis can have a totcol without material, we get them from parent + * should be implemented better... + */ + if (ob_dst->mat == NULL) { + ob_dst->totcol = 0; + } + + BKE_collection_object_add_from(bmain, scene, base->object, ob_dst); + base_dst = BKE_view_layer_base_find(view_layer, ob_dst); + BLI_assert(base_dst != NULL); + + BKE_scene_object_base_flag_sync_from_base(base_dst); + + /* make sure apply works */ + BKE_animdata_free(&ob_dst->id, true); + ob_dst->adt = NULL; + + /* Proxies are not to be copied. */ + ob_dst->proxy_from = NULL; + ob_dst->proxy_group = NULL; + ob_dst->proxy = NULL; + + ob_dst->parent = NULL; + BKE_constraints_free(&ob_dst->constraints); + ob_dst->runtime.curve_cache = NULL; + ob_dst->transflag &= ~OB_DUPLI; + + copy_m4_m4(ob_dst->obmat, dob->mat); + BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); + + BLI_ghash_insert(dupli_gh, dob, ob_dst); + if (parent_gh) { + void **val; + /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as + * 'the same', this avoids trying to insert same key several time and + * raise asserts in debug builds... */ + if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { + *val = ob_dst; + } + } + } + + for (dob = lb_duplis->first; dob; dob = dob->next) { + Object *ob_src = dob->ob; + Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); + + /* Remap new object to itself, and clear again newid pointer of orig object. */ + BKE_libblock_relink_to_newid(&ob_dst->id); + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + + if (use_hierarchy) { + /* original parents */ + Object *ob_src_par = ob_src->parent; + Object *ob_dst_par = NULL; + + /* find parent that was also made real */ + if (ob_src_par) { + /* OK to keep most of the members uninitialized, + * they won't be read, this is simply for a hash lookup. */ + DupliObject dob_key; + dob_key.ob = ob_src_par; + if (base->object->transflag & OB_DUPLICOLLECTION) { + memcpy(&dob_key.persistent_id[1], + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + } + else { + dob_key.persistent_id[0] = dob->persistent_id[0]; + } + ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); + } + + if (ob_dst_par) { + /* allow for all possible parent types */ + ob_dst->partype = ob_src->partype; + BLI_strncpy(ob_dst->parsubstr, ob_src->parsubstr, sizeof(ob_dst->parsubstr)); + ob_dst->par1 = ob_src->par1; + ob_dst->par2 = ob_src->par2; + ob_dst->par3 = ob_src->par3; + + copy_m4_m4(ob_dst->parentinv, ob_src->parentinv); + + ob_dst->parent = ob_dst_par; + } + else if (use_base_parent) { + ob_dst->parent = base->object; + ob_dst->partype = PAROBJECT; + } + } + else if (use_base_parent) { + /* since we are ignoring the internal hierarchy - parent all to the + * base object */ + ob_dst->parent = base->object; + ob_dst->partype = PAROBJECT; + } + + if (ob_dst->parent) { + /* note, this may be the parent of other objects, but it should + * still work out ok */ + BKE_object_apply_mat4(ob_dst, dob->mat, false, true); + + /* to set ob_dst->orig and in case there's any other discrepancies */ + DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM); + } + } + + if (base->object->transflag & OB_DUPLICOLLECTION && base->object->instance_collection) { + for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { + if (ob->proxy_group == base->object) { + ob->proxy = NULL; + ob->proxy_from = NULL; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + } + } + + BLI_ghash_free(dupli_gh, NULL, NULL); + if (parent_gh) { + BLI_ghash_free(parent_gh, NULL, NULL); + } + + free_object_duplilist(lb_duplis); + + BKE_main_id_clear_newpoins(bmain); + + base->object->transflag &= ~OB_DUPLI; + DEG_id_tag_update(&base->object->id, ID_RECALC_COPY_ON_WRITE); } static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); - const bool use_base_parent = RNA_boolean_get(op->ptr, "use_base_parent"); - const bool use_hierarchy = RNA_boolean_get(op->ptr, "use_hierarchy"); + const bool use_base_parent = RNA_boolean_get(op->ptr, "use_base_parent"); + const bool use_hierarchy = RNA_boolean_get(op->ptr, "use_hierarchy"); - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_clear_newpoins(bmain); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - make_object_duplilist_real(C, scene, base, use_base_parent, use_hierarchy); + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + make_object_duplilist_real(C, scene, base, use_base_parent, use_hierarchy); - /* dependencies were changed */ - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, base->object); - } - CTX_DATA_END; + /* dependencies were changed */ + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, base->object); + } + CTX_DATA_END; - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE, scene); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_SCENE, scene); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Duplicates Real"; - ot->description = "Make dupli objects attached to this object real"; - ot->idname = "OBJECT_OT_duplicates_make_real"; + /* identifiers */ + ot->name = "Make Duplicates Real"; + ot->description = "Make dupli objects attached to this object real"; + ot->idname = "OBJECT_OT_duplicates_make_real"; - /* api callbacks */ - ot->exec = object_duplicates_make_real_exec; + /* api callbacks */ + ot->exec = object_duplicates_make_real_exec; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; - RNA_def_boolean(ot->srna, "use_base_parent", 0, "Parent", "Parent newly created objects to the original duplicator"); - RNA_def_boolean(ot->srna, "use_hierarchy", 0, "Keep Hierarchy", "Maintain parent child relationships"); + RNA_def_boolean(ot->srna, + "use_base_parent", + 0, + "Parent", + "Parent newly created objects to the original duplicator"); + RNA_def_boolean( + ot->srna, "use_hierarchy", 0, "Keep Hierarchy", "Maintain parent child relationships"); } /**************************** Convert **************************/ static const EnumPropertyItem convert_target_items[] = { - {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, - {OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""}, - {0, NULL, 0, NULL, NULL}, + {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, + {OB_MESH, "MESH", ICON_OUTLINER_OB_MESH, "Mesh from Curve/Meta/Surf/Text", ""}, + {0, NULL, 0, NULL, NULL}, }; static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) { - if (ob->runtime.curve_cache == NULL) { - /* Force creation. This is normally not needed but on operator - * redo we might end up with an object which isn't evaluated yet. - * Also happens in case we are working on a copy of the object (all its caches have been nuked then). - */ - if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { - /* We need 'for render' ON here, to enable computing bevel dipslist if needed. - * Also makes sense anyway, we would not want e.g. to loose hidden parts etc. */ - BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false, NULL); - } - else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(depsgraph, scene, ob); - } - } + if (ob->runtime.curve_cache == NULL) { + /* Force creation. This is normally not needed but on operator + * redo we might end up with an object which isn't evaluated yet. + * Also happens in case we are working on a copy of the object (all its caches have been nuked then). + */ + if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + /* We need 'for render' ON here, to enable computing bevel dipslist if needed. + * Also makes sense anyway, we would not want e.g. to loose hidden parts etc. */ + BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false, NULL); + } + else if (ob->type == OB_MBALL) { + BKE_displist_make_mball(depsgraph, scene, ob); + } + } } static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { - convert_ensure_curve_cache(depsgraph, scene, ob); - BKE_mesh_from_nurbs(bmain, ob); /* also does users */ + convert_ensure_curve_cache(depsgraph, scene, ob); + BKE_mesh_from_nurbs(bmain, ob); /* also does users */ - if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob, 0); - } + if (ob->type == OB_MESH) { + BKE_object_free_modifiers(ob, 0); + } } static bool convert_poll(bContext *C) { - Scene *scene = CTX_data_scene(C); - Base *base_act = CTX_data_active_base(C); - Object *obact = base_act ? base_act->object : NULL; + Scene *scene = CTX_data_scene(C); + Base *base_act = CTX_data_active_base(C); + Object *obact = base_act ? base_act->object : NULL; - return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) && - (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact)); + return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) && + (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact)); } /* Helper for convert_exec */ -static Base *duplibase_for_convert(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob) +static Base *duplibase_for_convert( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob) { - Object *obn; - Base *basen; + Object *obn; + Base *basen; - if (ob == NULL) { - ob = base->object; - } + if (ob == NULL) { + ob = base->object; + } - obn = BKE_object_copy(bmain, ob); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - BKE_collection_object_add_from(bmain, scene, ob, obn); + obn = BKE_object_copy(bmain, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + BKE_collection_object_add_from(bmain, scene, ob, obn); - basen = BKE_view_layer_base_find(view_layer, obn); - ED_object_base_select(basen, BA_SELECT); - ED_object_base_select(basen, BA_DESELECT); - return basen; + basen = BKE_view_layer_base_find(view_layer, obn); + ED_object_base_select(basen, BA_SELECT); + ED_object_base_select(basen, BA_DESELECT); + return basen; } static int convert_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *basen = NULL, *basact = NULL; - Object *ob1, *obact = CTX_data_active_object(C); - Curve *cu; - Nurb *nu; - MetaBall *mb; - Mesh *me; - const short target = RNA_enum_get(op->ptr, "target"); - bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); - int a, mballConverted = 0; - - /* don't forget multiple users! */ - - { - FOREACH_SCENE_OBJECT_BEGIN(scene, ob) - { - ob->flag &= ~OB_DONE; - - /* flag data that's not been edited (only needed for !keep_original) */ - if (ob->data) { - ((ID *)ob->data)->tag |= LIB_TAG_DOIT; - } - - /* possible metaball basis is not in this scene */ - if (ob->type == OB_MBALL && target == OB_MESH) { - if (BKE_mball_is_basis(ob) == false) { - Object *ob_basis; - ob_basis = BKE_mball_basis_find(scene, ob); - if (ob_basis) { - ob_basis->flag &= ~OB_DONE; - } - } - } - } - FOREACH_SCENE_OBJECT_END; - } - - ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases"); - - /* Ensure we get all meshes calculated with a sufficient data-mask, - * needed since re-evaluating single modifiers causes bugs if they depend - * on other objects data masks too, see: T50950. */ - { - for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) { - Base *base = link->ptr.data; - Object *ob = base->object; - - /* The way object type conversion works currently (enforcing conversion of *all* objects using converted - * object-data, even some un-selected/hidden/another scene ones, sounds totally bad to me. - * However, changing this is more design than bug-fix, not to mention convoluted code below, - * so that will be for later. - * But at the very least, do not do that with linked IDs! */ - if ((ID_IS_LINKED(ob) || (ob->data && ID_IS_LINKED(ob->data))) && !keep_original) { - keep_original = true; - BKE_report(op->reports, RPT_INFO, - "Converting some linked object/object data, enforcing 'Keep Original' option to True"); - } - - DEG_id_tag_update(&base->object->id, ID_RECALC_GEOMETRY); - } - - CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask; - CustomData_MeshMasks_update(&scene->customdata_mask, &CD_MASK_MESH); - BKE_scene_graph_update_tagged(depsgraph, bmain); - scene->customdata_mask = customdata_mask_prev; - } - - for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) { - Object *newob = NULL; - Base *base = link->ptr.data; - Object *ob = base->object; - - if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) { - if (ob->type != target) { - base->flag &= ~SELECT; - ob->flag &= ~SELECT; - } - - /* obdata already modified */ - if (!IS_TAGGED(ob->data)) { - /* When 2 objects with linked data are selected, converting both - * would keep modifiers on all but the converted object [#26003] */ - if (ob->type == OB_MESH) { - BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ - } - if (ob->type == OB_GPENCIL) { - BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ - BKE_object_free_shaderfx(ob, 0); - } - } - } - else if (ob->type == OB_MESH && target == OB_CURVE) { - ob->flag |= OB_DONE; - - if (keep_original) { - basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); - newob = basen->object; - - /* decrement original mesh's usage count */ - me = newob->data; - id_us_min(&me->id); - - /* make a new copy of the mesh */ - newob->data = BKE_mesh_copy(bmain, me); - } - else { - newob = ob; - } - - BKE_mesh_to_curve(bmain, depsgraph, scene, newob); - - if (newob->type == OB_CURVE) { - BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ - ED_rigidbody_object_remove(bmain, scene, newob); - } - } - else if (ob->type == OB_MESH) { - ob->flag |= OB_DONE; - - if (keep_original) { - basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); - newob = basen->object; - - /* decrement original mesh's usage count */ - me = newob->data; - id_us_min(&me->id); - - /* make a new copy of the mesh */ - newob->data = BKE_mesh_copy(bmain, me); - } - else { - newob = ob; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - } - - /* make new mesh data from the original copy */ - /* note: get the mesh from the original, not from the copy in some - * cases this doesn't give correct results (when MDEF is used for eg) - */ - Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); - me_eval = BKE_mesh_copy_for_eval(me_eval, false); - BKE_mesh_nomain_to_mesh(me_eval, newob->data, newob, &CD_MASK_MESH, true); - BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ - } - else if (ob->type == OB_FONT) { - ob->flag |= OB_DONE; - - if (keep_original) { - basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); - newob = basen->object; - - /* decrement original curve's usage count */ - id_us_min(&((Curve *)newob->data)->id); - - /* make a new copy of the curve */ - newob->data = BKE_curve_copy(bmain, ob->data); - } - else { - newob = ob; - } - - cu = newob->data; - - /* TODO(sergey): Ideally DAG will create nurbs list for a curve data - * datablock, but for until we've got granular update - * lets take care by selves. - */ - /* XXX This may fail/crash, since BKE_vfont_to_curve() - * accesses evaluated data in some cases (bastien). */ - BKE_vfont_to_curve(newob, FO_EDIT); - - newob->type = OB_CURVE; - cu->type = OB_CURVE; - - if (cu->vfont) { - id_us_min(&cu->vfont->id); - cu->vfont = NULL; - } - if (cu->vfontb) { - id_us_min(&cu->vfontb->id); - cu->vfontb = NULL; - } - if (cu->vfonti) { - id_us_min(&cu->vfonti->id); - cu->vfonti = NULL; - } - if (cu->vfontbi) { - id_us_min(&cu->vfontbi->id); - cu->vfontbi = NULL; - } - - if (!keep_original) { - /* other users */ - if (cu->id.us > 1) { - for (ob1 = bmain->objects.first; ob1; ob1 = ob1->id.next) { - if (ob1->data == ob->data) { - ob1->type = OB_CURVE; - DEG_id_tag_update(&ob1->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - } - } - } - } - - for (nu = cu->nurb.first; nu; nu = nu->next) - nu->charidx = 0; - - cu->flag &= ~CU_3D; - BKE_curve_curve_dimension_update(cu); - - if (target == OB_MESH) { - curvetomesh(bmain, depsgraph, scene, newob); - - /* meshes doesn't use displist */ - BKE_object_free_curve_cache(newob); - } - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - ob->flag |= OB_DONE; - - if (target == OB_MESH) { - if (keep_original) { - basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); - newob = basen->object; - - /* decrement original curve's usage count */ - id_us_min(&((Curve *)newob->data)->id); - - /* make a new copy of the curve */ - newob->data = BKE_curve_copy(bmain, ob->data); - } - else { - newob = ob; - } - - curvetomesh(bmain, depsgraph, scene, newob); - - /* meshes doesn't use displist */ - BKE_object_free_curve_cache(newob); - } - } - else if (ob->type == OB_MBALL && target == OB_MESH) { - Object *baseob; - - base->flag &= ~BASE_SELECTED; - ob->base_flag &= ~BASE_SELECTED; - - baseob = BKE_mball_basis_find(scene, ob); - - if (ob != baseob) { - /* if motherball is converting it would be marked as done later */ - ob->flag |= OB_DONE; - } - - if (!(baseob->flag & OB_DONE)) { - baseob->flag |= OB_DONE; - - basen = duplibase_for_convert(bmain, scene, view_layer, base, baseob); - newob = basen->object; - - mb = newob->data; - id_us_min(&mb->id); - - newob->data = BKE_mesh_add(bmain, "Mesh"); - newob->type = OB_MESH; - - me = newob->data; - me->totcol = mb->totcol; - if (newob->totcol) { - me->mat = MEM_dupallocN(mb->mat); - for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]); - } - - convert_ensure_curve_cache(depsgraph, scene, baseob); - BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data); - - if (obact->type == OB_MBALL) { - basact = basen; - } - - mballConverted = 1; - } - } - else { - continue; - } - - /* Ensure new object has consistent material data with its new obdata. */ - if (newob) { - test_object_materials(bmain, newob, newob->data); - } - - /* tag obdata if it was been changed */ - - /* If the original object is active then make this object active */ - if (basen) { - if (ob == obact) { - /* store new active base to update BASACT */ - basact = basen; - } - - basen = NULL; - } - - if (!keep_original && (ob->flag & OB_DONE)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */ - } - } - BLI_freelistN(&selected_editable_bases); - - if (!keep_original) { - if (mballConverted) { - FOREACH_SCENE_OBJECT_BEGIN(scene, ob_mball) - { - if (ob_mball->type == OB_MBALL) { - if (ob_mball->flag & OB_DONE) { - Object *ob_basis = NULL; - if (BKE_mball_is_basis(ob_mball) || - ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE))) - { - ED_object_base_free_and_unlink(bmain, scene, ob_mball); - } - } - } - } - FOREACH_SCENE_OBJECT_END; - } - } - -// XXX ED_object_editmode_enter(C, 0); -// XXX exit_editmode(C, EM_FREEDATA|); /* freedata, but no undo */ - - if (basact) { - /* active base was changed */ - ED_object_base_activate(C, basact); - BASACT(view_layer) = basact; - } - else if (BASACT(view_layer)->object->flag & OB_DONE) { - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT(view_layer)->object); - WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT(view_layer)->object); - } - - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *basen = NULL, *basact = NULL; + Object *ob1, *obact = CTX_data_active_object(C); + Curve *cu; + Nurb *nu; + MetaBall *mb; + Mesh *me; + const short target = RNA_enum_get(op->ptr, "target"); + bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); + int a, mballConverted = 0; + + /* don't forget multiple users! */ + + { + FOREACH_SCENE_OBJECT_BEGIN (scene, ob) { + ob->flag &= ~OB_DONE; + + /* flag data that's not been edited (only needed for !keep_original) */ + if (ob->data) { + ((ID *)ob->data)->tag |= LIB_TAG_DOIT; + } + + /* possible metaball basis is not in this scene */ + if (ob->type == OB_MBALL && target == OB_MESH) { + if (BKE_mball_is_basis(ob) == false) { + Object *ob_basis; + ob_basis = BKE_mball_basis_find(scene, ob); + if (ob_basis) { + ob_basis->flag &= ~OB_DONE; + } + } + } + } + FOREACH_SCENE_OBJECT_END; + } + + ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases"); + + /* Ensure we get all meshes calculated with a sufficient data-mask, + * needed since re-evaluating single modifiers causes bugs if they depend + * on other objects data masks too, see: T50950. */ + { + for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) { + Base *base = link->ptr.data; + Object *ob = base->object; + + /* The way object type conversion works currently (enforcing conversion of *all* objects using converted + * object-data, even some un-selected/hidden/another scene ones, sounds totally bad to me. + * However, changing this is more design than bug-fix, not to mention convoluted code below, + * so that will be for later. + * But at the very least, do not do that with linked IDs! */ + if ((ID_IS_LINKED(ob) || (ob->data && ID_IS_LINKED(ob->data))) && !keep_original) { + keep_original = true; + BKE_report( + op->reports, + RPT_INFO, + "Converting some linked object/object data, enforcing 'Keep Original' option to True"); + } + + DEG_id_tag_update(&base->object->id, ID_RECALC_GEOMETRY); + } + + CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask; + CustomData_MeshMasks_update(&scene->customdata_mask, &CD_MASK_MESH); + BKE_scene_graph_update_tagged(depsgraph, bmain); + scene->customdata_mask = customdata_mask_prev; + } + + for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) { + Object *newob = NULL; + Base *base = link->ptr.data; + Object *ob = base->object; + + if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) { + if (ob->type != target) { + base->flag &= ~SELECT; + ob->flag &= ~SELECT; + } + + /* obdata already modified */ + if (!IS_TAGGED(ob->data)) { + /* When 2 objects with linked data are selected, converting both + * would keep modifiers on all but the converted object [#26003] */ + if (ob->type == OB_MESH) { + BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ + } + if (ob->type == OB_GPENCIL) { + BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ + BKE_object_free_shaderfx(ob, 0); + } + } + } + else if (ob->type == OB_MESH && target == OB_CURVE) { + ob->flag |= OB_DONE; + + if (keep_original) { + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); + newob = basen->object; + + /* decrement original mesh's usage count */ + me = newob->data; + id_us_min(&me->id); + + /* make a new copy of the mesh */ + newob->data = BKE_mesh_copy(bmain, me); + } + else { + newob = ob; + } + + BKE_mesh_to_curve(bmain, depsgraph, scene, newob); + + if (newob->type == OB_CURVE) { + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ + ED_rigidbody_object_remove(bmain, scene, newob); + } + } + else if (ob->type == OB_MESH) { + ob->flag |= OB_DONE; + + if (keep_original) { + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); + newob = basen->object; + + /* decrement original mesh's usage count */ + me = newob->data; + id_us_min(&me->id); + + /* make a new copy of the mesh */ + newob->data = BKE_mesh_copy(bmain, me); + } + else { + newob = ob; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + } + + /* make new mesh data from the original copy */ + /* note: get the mesh from the original, not from the copy in some + * cases this doesn't give correct results (when MDEF is used for eg) + */ + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); + me_eval = BKE_mesh_copy_for_eval(me_eval, false); + BKE_mesh_nomain_to_mesh(me_eval, newob->data, newob, &CD_MASK_MESH, true); + BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ + } + else if (ob->type == OB_FONT) { + ob->flag |= OB_DONE; + + if (keep_original) { + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); + newob = basen->object; + + /* decrement original curve's usage count */ + id_us_min(&((Curve *)newob->data)->id); + + /* make a new copy of the curve */ + newob->data = BKE_curve_copy(bmain, ob->data); + } + else { + newob = ob; + } + + cu = newob->data; + + /* TODO(sergey): Ideally DAG will create nurbs list for a curve data + * datablock, but for until we've got granular update + * lets take care by selves. + */ + /* XXX This may fail/crash, since BKE_vfont_to_curve() + * accesses evaluated data in some cases (bastien). */ + BKE_vfont_to_curve(newob, FO_EDIT); + + newob->type = OB_CURVE; + cu->type = OB_CURVE; + + if (cu->vfont) { + id_us_min(&cu->vfont->id); + cu->vfont = NULL; + } + if (cu->vfontb) { + id_us_min(&cu->vfontb->id); + cu->vfontb = NULL; + } + if (cu->vfonti) { + id_us_min(&cu->vfonti->id); + cu->vfonti = NULL; + } + if (cu->vfontbi) { + id_us_min(&cu->vfontbi->id); + cu->vfontbi = NULL; + } + + if (!keep_original) { + /* other users */ + if (cu->id.us > 1) { + for (ob1 = bmain->objects.first; ob1; ob1 = ob1->id.next) { + if (ob1->data == ob->data) { + ob1->type = OB_CURVE; + DEG_id_tag_update(&ob1->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + } + } + } + } + + for (nu = cu->nurb.first; nu; nu = nu->next) + nu->charidx = 0; + + cu->flag &= ~CU_3D; + BKE_curve_curve_dimension_update(cu); + + if (target == OB_MESH) { + curvetomesh(bmain, depsgraph, scene, newob); + + /* meshes doesn't use displist */ + BKE_object_free_curve_cache(newob); + } + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + ob->flag |= OB_DONE; + + if (target == OB_MESH) { + if (keep_original) { + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); + newob = basen->object; + + /* decrement original curve's usage count */ + id_us_min(&((Curve *)newob->data)->id); + + /* make a new copy of the curve */ + newob->data = BKE_curve_copy(bmain, ob->data); + } + else { + newob = ob; + } + + curvetomesh(bmain, depsgraph, scene, newob); + + /* meshes doesn't use displist */ + BKE_object_free_curve_cache(newob); + } + } + else if (ob->type == OB_MBALL && target == OB_MESH) { + Object *baseob; + + base->flag &= ~BASE_SELECTED; + ob->base_flag &= ~BASE_SELECTED; + + baseob = BKE_mball_basis_find(scene, ob); + + if (ob != baseob) { + /* if motherball is converting it would be marked as done later */ + ob->flag |= OB_DONE; + } + + if (!(baseob->flag & OB_DONE)) { + baseob->flag |= OB_DONE; + + basen = duplibase_for_convert(bmain, scene, view_layer, base, baseob); + newob = basen->object; + + mb = newob->data; + id_us_min(&mb->id); + + newob->data = BKE_mesh_add(bmain, "Mesh"); + newob->type = OB_MESH; + + me = newob->data; + me->totcol = mb->totcol; + if (newob->totcol) { + me->mat = MEM_dupallocN(mb->mat); + for (a = 0; a < newob->totcol; a++) + id_us_plus((ID *)me->mat[a]); + } + + convert_ensure_curve_cache(depsgraph, scene, baseob); + BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data); + + if (obact->type == OB_MBALL) { + basact = basen; + } + + mballConverted = 1; + } + } + else { + continue; + } + + /* Ensure new object has consistent material data with its new obdata. */ + if (newob) { + test_object_materials(bmain, newob, newob->data); + } + + /* tag obdata if it was been changed */ + + /* If the original object is active then make this object active */ + if (basen) { + if (ob == obact) { + /* store new active base to update BASACT */ + basact = basen; + } + + basen = NULL; + } + + if (!keep_original && (ob->flag & OB_DONE)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */ + } + } + BLI_freelistN(&selected_editable_bases); + + if (!keep_original) { + if (mballConverted) { + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_mball) { + if (ob_mball->type == OB_MBALL) { + if (ob_mball->flag & OB_DONE) { + Object *ob_basis = NULL; + if (BKE_mball_is_basis(ob_mball) || + ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && + (ob_basis->flag & OB_DONE))) { + ED_object_base_free_and_unlink(bmain, scene, ob_mball); + } + } + } + } + FOREACH_SCENE_OBJECT_END; + } + } + + // XXX ED_object_editmode_enter(C, 0); + // XXX exit_editmode(C, EM_FREEDATA|); /* freedata, but no undo */ + + if (basact) { + /* active base was changed */ + ED_object_base_activate(C, basact); + BASACT(view_layer) = basact; + } + else if (BASACT(view_layer)->object->flag & OB_DONE) { + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT(view_layer)->object); + WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT(view_layer)->object); + } + + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } - void OBJECT_OT_convert(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Convert to"; - ot->description = "Convert selected objects to another type"; - ot->idname = "OBJECT_OT_convert"; + /* identifiers */ + ot->name = "Convert to"; + ot->description = "Convert selected objects to another type"; + ot->idname = "OBJECT_OT_convert"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = convert_exec; - ot->poll = convert_poll; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = convert_exec; + ot->poll = convert_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to"); - RNA_def_boolean(ot->srna, "keep_original", 0, "Keep Original", "Keep original objects instead of replacing them"); + /* properties */ + ot->prop = RNA_def_enum( + ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to"); + RNA_def_boolean(ot->srna, + "keep_original", + 0, + "Keep Original", + "Keep original objects instead of replacing them"); } /**************************** Duplicate ************************/ @@ -2209,45 +2276,46 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ /* Does set ID->newid pointers. */ -static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, int dupflag) -{ - Base *base, *basen = NULL; - Object *obn; - - if (ob->mode & OB_MODE_POSE) { - /* nothing? */ - } - else { - obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag)); - DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { - BKE_collection_object_add_from(bmain, scene, ob, obn); - } - else { - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, obn); - } - - basen = BKE_view_layer_base_find(view_layer, obn); - if (base != NULL) { - basen->local_view_bits = base->local_view_bits; - } - - /* 1) duplis should end up in same collection as the original - * 2) Rigid Body sim participants MUST always be part of a collection... - */ - // XXX: is 2) really a good measure here? - if (ob->rigidbody_object || ob->rigidbody_constraint) { - Collection *collection; - for (collection = bmain->collections.first; collection; collection = collection->id.next) { - if (BKE_collection_has_object(collection, ob)) - BKE_collection_object_add(bmain, collection, obn); - } - } - } - return basen; +static Base *object_add_duplicate_internal( + Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, int dupflag) +{ + Base *base, *basen = NULL; + Object *obn; + + if (ob->mode & OB_MODE_POSE) { + /* nothing? */ + } + else { + obn = ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag)); + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + base = BKE_view_layer_base_find(view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + BKE_collection_object_add_from(bmain, scene, ob, obn); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, obn); + } + + basen = BKE_view_layer_base_find(view_layer, obn); + if (base != NULL) { + basen->local_view_bits = base->local_view_bits; + } + + /* 1) duplis should end up in same collection as the original + * 2) Rigid Body sim participants MUST always be part of a collection... + */ + // XXX: is 2) really a good measure here? + if (ob->rigidbody_object || ob->rigidbody_constraint) { + Collection *collection; + for (collection = bmain->collections.first; collection; collection = collection->id.next) { + if (BKE_collection_has_object(collection, ob)) + BKE_collection_object_add(bmain, collection, obn); + } + } + } + return basen; } /* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */ @@ -2255,278 +2323,288 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer * note: don't call this within a loop since clear_* funcs loop over the entire database. * note: caller must do DAG_relations_tag_update(bmain); * this is not done automatic since we may duplicate many objects in a batch */ -Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, int dupflag) +Base *ED_object_add_duplicate( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, int dupflag) { - Base *basen; - Object *ob; + Base *basen; + Object *ob; - basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); - if (basen == NULL) { - return NULL; - } + basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + if (basen == NULL) { + return NULL; + } - ob = basen->object; + ob = basen->object; - /* link own references to the newly duplicated data [#26816] */ - BKE_libblock_relink_to_newid(&ob->id); + /* link own references to the newly duplicated data [#26816] */ + BKE_libblock_relink_to_newid(&ob->id); - /* DAG_relations_tag_update(bmain); */ /* caller must do */ + /* DAG_relations_tag_update(bmain); */ /* caller must do */ - if (ob->data != NULL) { - DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS); - } + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS); + } - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_clear_newpoins(bmain); - return basen; + return basen; } /* contextual operator dupli */ static int duplicate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool linked = RNA_boolean_get(op->ptr, "linked"); - int dupflag = (linked) ? 0 : U.dupflag; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool linked = RNA_boolean_get(op->ptr, "linked"); + int dupflag = (linked) ? 0 : U.dupflag; - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - Base *basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { + Base *basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); - /* note that this is safe to do with this context iterator, - * the list is made in advance */ - ED_object_base_select(base, BA_DESELECT); - ED_object_base_select(basen, BA_SELECT); + /* note that this is safe to do with this context iterator, + * the list is made in advance */ + ED_object_base_select(base, BA_DESELECT); + ED_object_base_select(basen, BA_SELECT); - if (basen == NULL) { - continue; - } + if (basen == NULL) { + continue; + } - /* new object becomes active */ - if (BASACT(view_layer) == base) - ED_object_base_activate(C, basen); + /* new object becomes active */ + if (BASACT(view_layer) == base) + ED_object_base_activate(C, basen); - if (basen->object->data) { - DEG_id_tag_update(basen->object->data, 0); - } - } - CTX_DATA_END; + if (basen->object->data) { + DEG_id_tag_update(basen->object->data, 0); + } + } + CTX_DATA_END; - copy_object_set_idnew(C); + copy_object_set_idnew(C); - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_duplicate(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Duplicate Objects"; - ot->description = "Duplicate selected objects"; - ot->idname = "OBJECT_OT_duplicate"; + /* identifiers */ + ot->name = "Duplicate Objects"; + ot->description = "Duplicate selected objects"; + ot->idname = "OBJECT_OT_duplicate"; - /* api callbacks */ - ot->exec = duplicate_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = duplicate_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* to give to transform */ - RNA_def_boolean(ot->srna, "linked", 0, "Linked", "Duplicate object but not object data, linking to the original data"); - prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); + /* to give to transform */ + RNA_def_boolean(ot->srna, + "linked", + 0, + "Linked", + "Duplicate object but not object data, linking to the original data"); + prop = RNA_def_enum( + ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* **************** add named object, for dragdrop ************* */ static int add_named_exec(bContext *C, wmOperator *op) { - wmWindow *win = CTX_wm_window(C); - const wmEvent *event = win ? win->eventstate : NULL; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *basen; - Object *ob; - const bool linked = RNA_boolean_get(op->ptr, "linked"); - int dupflag = (linked) ? 0 : U.dupflag; - char name[MAX_ID_NAME - 2]; + wmWindow *win = CTX_wm_window(C); + const wmEvent *event = win ? win->eventstate : NULL; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *basen; + Object *ob; + const bool linked = RNA_boolean_get(op->ptr, "linked"); + int dupflag = (linked) ? 0 : U.dupflag; + char name[MAX_ID_NAME - 2]; - /* find object, create fake base */ - RNA_string_get(op->ptr, "name", name); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name); + /* find object, create fake base */ + RNA_string_get(op->ptr, "name", name); + ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name); - if (ob == NULL) { - BKE_report(op->reports, RPT_ERROR, "Object not found"); - return OPERATOR_CANCELLED; - } + if (ob == NULL) { + BKE_report(op->reports, RPT_ERROR, "Object not found"); + return OPERATOR_CANCELLED; + } - /* prepare dupli */ - basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); + /* prepare dupli */ + basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); - if (basen == NULL) { - BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); - return OPERATOR_CANCELLED; - } + if (basen == NULL) { + BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); + return OPERATOR_CANCELLED; + } - BKE_scene_object_base_flag_sync_from_object(basen); - basen->object->restrictflag &= ~OB_RESTRICT_VIEW; + BKE_scene_object_base_flag_sync_from_object(basen); + basen->object->restrictflag &= ~OB_RESTRICT_VIEW; - if (event) { - ARegion *ar = CTX_wm_region(C); - const int mval[2] = {event->x - ar->winrct.xmin, - event->y - ar->winrct.ymin}; - ED_object_location_from_view(C, basen->object->loc); - ED_view3d_cursor3d_position(C, mval, false, basen->object->loc); - } + if (event) { + ARegion *ar = CTX_wm_region(C); + const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; + ED_object_location_from_view(C, basen->object->loc); + ED_view3d_cursor3d_position(C, mval, false, basen->object->loc); + } - ED_object_base_select(basen, BA_SELECT); - ED_object_base_activate(C, basen); + ED_object_base_select(basen, BA_SELECT); + ED_object_base_activate(C, basen); - copy_object_set_idnew(C); + copy_object_set_idnew(C); - /* TODO(sergey): Only update relations for the current scene. */ - DEG_relations_tag_update(bmain); + /* TODO(sergey): Only update relations for the current scene. */ + DEG_relations_tag_update(bmain); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_add_named(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Named Object"; - ot->description = "Add named object"; - ot->idname = "OBJECT_OT_add_named"; + /* identifiers */ + ot->name = "Add Named Object"; + ot->description = "Add named object"; + ot->idname = "OBJECT_OT_add_named"; - /* api callbacks */ - ot->exec = add_named_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = add_named_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "linked", 0, "Linked", "Duplicate object but not object data, linking to the original data"); - RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add"); + RNA_def_boolean(ot->srna, + "linked", + 0, + "Linked", + "Duplicate object but not object data, linking to the original data"); + RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add"); } /**************************** Join *************************/ static bool join_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (!ob || ID_IS_LINKED(ob)) return 0; + if (!ob || ID_IS_LINKED(ob)) + return 0; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL)) - return ED_operator_screenactive(C); - else - return 0; + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL)) + return ED_operator_screenactive(C); + else + return 0; } static int join_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - - if (ob->mode & OB_MODE_EDIT) { - BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); - return OPERATOR_CANCELLED; - } - else if (BKE_object_obdata_is_libdata(ob)) { - BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data"); - return OPERATOR_CANCELLED; - } - else if (ob->type == OB_GPENCIL) { - bGPdata *gpd = (bGPdata *)ob->data; - if ((!gpd) || GPENCIL_ANY_MODE(gpd)) { - BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode"); - return OPERATOR_CANCELLED; - } - } - - if (ob->type == OB_MESH) - return join_mesh_exec(C, op); - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) - return join_curve_exec(C, op); - else if (ob->type == OB_ARMATURE) - return join_armature_exec(C, op); - else if (ob->type == OB_GPENCIL) - return ED_gpencil_join_objects_exec(C, op); - - return OPERATOR_CANCELLED; + Object *ob = CTX_data_active_object(C); + + if (ob->mode & OB_MODE_EDIT) { + BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); + return OPERATOR_CANCELLED; + } + else if (BKE_object_obdata_is_libdata(ob)) { + BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data"); + return OPERATOR_CANCELLED; + } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = (bGPdata *)ob->data; + if ((!gpd) || GPENCIL_ANY_MODE(gpd)) { + BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode"); + return OPERATOR_CANCELLED; + } + } + + if (ob->type == OB_MESH) + return join_mesh_exec(C, op); + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) + return join_curve_exec(C, op); + else if (ob->type == OB_ARMATURE) + return join_armature_exec(C, op); + else if (ob->type == OB_GPENCIL) + return ED_gpencil_join_objects_exec(C, op); + + return OPERATOR_CANCELLED; } void OBJECT_OT_join(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Join"; - ot->description = "Join selected objects into active object"; - ot->idname = "OBJECT_OT_join"; + /* identifiers */ + ot->name = "Join"; + ot->description = "Join selected objects into active object"; + ot->idname = "OBJECT_OT_join"; - /* api callbacks */ - ot->exec = join_exec; - ot->poll = join_poll; + /* api callbacks */ + ot->exec = join_exec; + ot->poll = join_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /**************************** Join as Shape Key*************************/ static bool join_shapes_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (!ob || ID_IS_LINKED(ob)) return 0; + if (!ob || ID_IS_LINKED(ob)) + return 0; - /* only meshes supported at the moment */ - if (ob->type == OB_MESH) - return ED_operator_screenactive(C); - else - return 0; + /* only meshes supported at the moment */ + if (ob->type == OB_MESH) + return ED_operator_screenactive(C); + else + return 0; } static int join_shapes_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (ob->mode & OB_MODE_EDIT) { - BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); - return OPERATOR_CANCELLED; - } - else if (BKE_object_obdata_is_libdata(ob)) { - BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data"); - return OPERATOR_CANCELLED; - } + if (ob->mode & OB_MODE_EDIT) { + BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); + return OPERATOR_CANCELLED; + } + else if (BKE_object_obdata_is_libdata(ob)) { + BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data"); + return OPERATOR_CANCELLED; + } - if (ob->type == OB_MESH) - return join_mesh_shapes_exec(C, op); + if (ob->type == OB_MESH) + return join_mesh_shapes_exec(C, op); - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void OBJECT_OT_join_shapes(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Join as Shapes"; - ot->description = "Merge selected objects to shapes of active object"; - ot->idname = "OBJECT_OT_join_shapes"; + /* identifiers */ + ot->name = "Join as Shapes"; + ot->description = "Merge selected objects to shapes of active object"; + ot->idname = "OBJECT_OT_join_shapes"; - /* api callbacks */ - ot->exec = join_shapes_exec; - ot->poll = join_shapes_poll; + /* api callbacks */ + ot->exec = join_shapes_exec; + ot->poll = join_shapes_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index ac1f31d0b48..f3138c5afec 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -73,18 +73,18 @@ static Image *bake_object_image_get(Object *ob, int mat_nr) { - Image *image = NULL; - ED_object_get_active_image(ob, mat_nr + 1, &image, NULL, NULL, NULL); - return image; + Image *image = NULL; + ED_object_get_active_image(ob, mat_nr + 1, &image, NULL, NULL, NULL); + return image; } static Image **bake_object_image_get_array(Object *ob) { - Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__); - for (int i = 0; i < ob->totcol; i++) { - image_array[i] = bake_object_image_get(ob, i); - } - return image_array; + Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__); + for (int i = 0; i < ob->totcol; i++) { + image_array[i] = bake_object_image_get(ob, i); + } + return image_array; } /* ****************** multires BAKING ********************** */ @@ -92,485 +92,486 @@ static Image **bake_object_image_get_array(Object *ob) /* holder of per-object data needed for bake job * needed to make job totally thread-safe */ typedef struct MultiresBakerJobData { - struct MultiresBakerJobData *next, *prev; - /* material aligned image array (for per-face bake image) */ - struct { - Image **array; - int len; - } ob_image; - DerivedMesh *lores_dm, *hires_dm; - bool simple; - int lvl, tot_lvl; - ListBase images; + struct MultiresBakerJobData *next, *prev; + /* material aligned image array (for per-face bake image) */ + struct { + Image **array; + int len; + } ob_image; + DerivedMesh *lores_dm, *hires_dm; + bool simple; + int lvl, tot_lvl; + ListBase images; } MultiresBakerJobData; /* data passing to multires-baker job */ typedef struct { - Scene *scene; - ListBase data; - /** Clear the images before baking */ - bool bake_clear; - /** Bake-filter, aka margin */ - int bake_filter; - /** mode of baking (displacement, normals, AO) */ - short mode; - /** Use low-resolution mesh when baking displacement maps */ - bool use_lores_mesh; - /** Number of rays to be cast when doing AO baking */ - int number_of_rays; - /** Bias between object and start ray point when doing AO baking */ - float bias; - /** Number of threads to be used for baking */ - int threads; - /** User scale used to scale displacement when baking derivative map. */ - float user_scale; + Scene *scene; + ListBase data; + /** Clear the images before baking */ + bool bake_clear; + /** Bake-filter, aka margin */ + int bake_filter; + /** mode of baking (displacement, normals, AO) */ + short mode; + /** Use low-resolution mesh when baking displacement maps */ + bool use_lores_mesh; + /** Number of rays to be cast when doing AO baking */ + int number_of_rays; + /** Bias between object and start ray point when doing AO baking */ + float bias; + /** Number of threads to be used for baking */ + int threads; + /** User scale used to scale displacement when baking derivative map. */ + float user_scale; } MultiresBakeJob; static bool multiresbake_check(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob; - Mesh *me; - MultiresModifierData *mmd; - bool ok = true; - int a; - - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - ob = base->object; - - if (ob->type != OB_MESH) { - BKE_report(op->reports, RPT_ERROR, "Baking of multires data only works with an active mesh object"); - - ok = false; - break; - } - - me = (Mesh *)ob->data; - mmd = get_multires_modifier(scene, ob, 0); - - /* Multi-resolution should be and be last in the stack */ - if (ok && mmd) { - ModifierData *md; - - ok = mmd->totlvl > 0; - - for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) { - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { - ok = false; - } - } - } - else { - ok = false; - } - - if (!ok) { - BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object"); - - break; - } - - if (!me->mloopuv) { - BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking"); - - ok = false; - } - else { - a = me->totpoly; - while (ok && a--) { - Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr); - - if (!ima) { - BKE_report(op->reports, RPT_ERROR, "You should have active texture to use multires baker"); - - ok = false; - } - else { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (!ibuf) { - BKE_report(op->reports, RPT_ERROR, "Baking should happen to image with image buffer"); - - ok = false; - } - else { - if (ibuf->rect == NULL && ibuf->rect_float == NULL) - ok = false; - - if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) - ok = false; - - if (!ok) - BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type"); - } - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - } - } - - if (!ok) - break; - } - CTX_DATA_END; - - return ok; + Scene *scene = CTX_data_scene(C); + Object *ob; + Mesh *me; + MultiresModifierData *mmd; + bool ok = true; + int a; + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + ob = base->object; + + if (ob->type != OB_MESH) { + BKE_report( + op->reports, RPT_ERROR, "Baking of multires data only works with an active mesh object"); + + ok = false; + break; + } + + me = (Mesh *)ob->data; + mmd = get_multires_modifier(scene, ob, 0); + + /* Multi-resolution should be and be last in the stack */ + if (ok && mmd) { + ModifierData *md; + + ok = mmd->totlvl > 0; + + for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) { + if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + ok = false; + } + } + } + else { + ok = false; + } + + if (!ok) { + BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object"); + + break; + } + + if (!me->mloopuv) { + BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking"); + + ok = false; + } + else { + a = me->totpoly; + while (ok && a--) { + Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr); + + if (!ima) { + BKE_report( + op->reports, RPT_ERROR, "You should have active texture to use multires baker"); + + ok = false; + } + else { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + if (!ibuf) { + BKE_report(op->reports, RPT_ERROR, "Baking should happen to image with image buffer"); + + ok = false; + } + else { + if (ibuf->rect == NULL && ibuf->rect_float == NULL) + ok = false; + + if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) + ok = false; + + if (!ok) + BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type"); + } + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + } + + if (!ok) + break; + } + CTX_DATA_END; + + return ok; } static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *lvl) { - DerivedMesh *dm; - MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); - Mesh *me = (Mesh *)ob->data; - MultiresModifierData tmp_mmd = *mmd; - DerivedMesh *cddm = CDDM_from_mesh(me); + DerivedMesh *dm; + MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); + Mesh *me = (Mesh *)ob->data; + MultiresModifierData tmp_mmd = *mmd; + DerivedMesh *cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - if (mmd->lvl == 0) { - dm = CDDM_copy(cddm); - } - else { - tmp_mmd.lvl = mmd->lvl; - tmp_mmd.sculptlvl = mmd->lvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); - } + if (mmd->lvl == 0) { + dm = CDDM_copy(cddm); + } + else { + tmp_mmd.lvl = mmd->lvl; + tmp_mmd.sculptlvl = mmd->lvl; + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); + } - cddm->release(cddm); + cddm->release(cddm); - *lvl = mmd->lvl; + *lvl = mmd->lvl; - return dm; + return dm; } static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *lvl, bool *simple) { - Mesh *me = (Mesh *)ob->data; - MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); - MultiresModifierData tmp_mmd = *mmd; - DerivedMesh *cddm = CDDM_from_mesh(me); - DerivedMesh *dm; + Mesh *me = (Mesh *)ob->data; + MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); + MultiresModifierData tmp_mmd = *mmd; + DerivedMesh *cddm = CDDM_from_mesh(me); + DerivedMesh *dm; - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - /* TODO: DM_set_only_copy wouldn't set mask for loop and poly data, - * but we really need BAREMESH only to save lots of memory - */ - CustomData_set_only_copy(&cddm->loopData, CD_MASK_BAREMESH.lmask); - CustomData_set_only_copy(&cddm->polyData, CD_MASK_BAREMESH.pmask); + /* TODO: DM_set_only_copy wouldn't set mask for loop and poly data, + * but we really need BAREMESH only to save lots of memory + */ + CustomData_set_only_copy(&cddm->loopData, CD_MASK_BAREMESH.lmask); + CustomData_set_only_copy(&cddm->polyData, CD_MASK_BAREMESH.pmask); - *lvl = mmd->totlvl; - *simple = mmd->simple != 0; + *lvl = mmd->totlvl; + *simple = mmd->simple != 0; - tmp_mmd.lvl = mmd->totlvl; - tmp_mmd.sculptlvl = mmd->totlvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); - cddm->release(cddm); + tmp_mmd.lvl = mmd->totlvl; + tmp_mmd.sculptlvl = mmd->totlvl; + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); + cddm->release(cddm); - return dm; + return dm; } typedef enum ClearFlag { - CLEAR_TANGENT_NORMAL = 1, - CLEAR_DISPLACEMENT = 2, + CLEAR_TANGENT_NORMAL = 1, + CLEAR_DISPLACEMENT = 2, } ClearFlag; - static void clear_single_image(Image *image, ClearFlag flag) { - const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; - const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; - const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; - const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - - if ((image->id.tag & LIB_TAG_DOIT) == 0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); - - if (flag == CLEAR_TANGENT_NORMAL) - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); - else if (flag == CLEAR_DISPLACEMENT) - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); - else - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); - - image->id.tag |= LIB_TAG_DOIT; - - BKE_image_release_ibuf(image, ibuf, NULL); - } + const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; + const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; + const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; + const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + + if ((image->id.tag & LIB_TAG_DOIT) == 0) { + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + + if (flag == CLEAR_TANGENT_NORMAL) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); + else if (flag == CLEAR_DISPLACEMENT) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); + else + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); + + image->id.tag |= LIB_TAG_DOIT; + + BKE_image_release_ibuf(image, ibuf, NULL); + } } static void clear_images_poly(Image **ob_image_array, int ob_image_array_len, ClearFlag flag) { - for (int i = 0; i < ob_image_array_len; i++) { - Image *image = ob_image_array[i]; - if (image) { - image->id.tag &= ~LIB_TAG_DOIT; - } - } - - for (int i = 0; i < ob_image_array_len; i++) { - Image *image = ob_image_array[i]; - if (image) { - clear_single_image(image, flag); - } - } - - for (int i = 0; i < ob_image_array_len; i++) { - Image *image = ob_image_array[i]; - if (image) { - image->id.tag &= ~LIB_TAG_DOIT; - } - } + for (int i = 0; i < ob_image_array_len; i++) { + Image *image = ob_image_array[i]; + if (image) { + image->id.tag &= ~LIB_TAG_DOIT; + } + } + + for (int i = 0; i < ob_image_array_len; i++) { + Image *image = ob_image_array[i]; + if (image) { + clear_single_image(image, flag); + } + } + + for (int i = 0; i < ob_image_array_len; i++) { + Image *image = ob_image_array[i]; + if (image) { + image->id.tag &= ~LIB_TAG_DOIT; + } + } } static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) { - Object *ob; - Scene *scene = CTX_data_scene(C); - int objects_baked = 0; + Object *ob; + Scene *scene = CTX_data_scene(C); + int objects_baked = 0; - if (!multiresbake_check(C, op)) - return OPERATOR_CANCELLED; + if (!multiresbake_check(C, op)) + return OPERATOR_CANCELLED; - if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */ - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - ClearFlag clear_flag = 0; + if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + ClearFlag clear_flag = 0; - ob = base->object; - // me = (Mesh *)ob->data; + ob = base->object; + // me = (Mesh *)ob->data; - if (scene->r.bake_mode == RE_BAKE_NORMALS) { - clear_flag = CLEAR_TANGENT_NORMAL; - } - else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) { - clear_flag = CLEAR_DISPLACEMENT; - } + if (scene->r.bake_mode == RE_BAKE_NORMALS) { + clear_flag = CLEAR_TANGENT_NORMAL; + } + else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) { + clear_flag = CLEAR_DISPLACEMENT; + } - { - Image **ob_image_array = bake_object_image_get_array(ob); - clear_images_poly(ob_image_array, ob->totcol, clear_flag); - MEM_freeN(ob_image_array); - } - } - CTX_DATA_END; - } + { + Image **ob_image_array = bake_object_image_get_array(ob); + clear_images_poly(ob_image_array, ob->totcol, clear_flag); + MEM_freeN(ob_image_array); + } + } + CTX_DATA_END; + } - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - MultiresBakeRender bkr = {NULL}; + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + MultiresBakeRender bkr = {NULL}; - ob = base->object; + ob = base->object; - multires_force_update(ob); + multires_force_update(ob); - /* copy data stored in job descriptor */ - bkr.scene = scene; - bkr.bake_filter = scene->r.bake_filter; - bkr.mode = scene->r.bake_mode; - bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; - bkr.bias = scene->r.bake_biasdist; - bkr.number_of_rays = scene->r.bake_samples; - bkr.threads = BKE_scene_num_threads(scene); - bkr.user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f; - //bkr.reports= op->reports; + /* copy data stored in job descriptor */ + bkr.scene = scene; + bkr.bake_filter = scene->r.bake_filter; + bkr.mode = scene->r.bake_mode; + bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; + bkr.bias = scene->r.bake_biasdist; + bkr.number_of_rays = scene->r.bake_samples; + bkr.threads = BKE_scene_num_threads(scene); + bkr.user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f; + //bkr.reports= op->reports; - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - bkr.ob_image.array = bake_object_image_get_array(ob); - bkr.ob_image.len = ob->totcol; + /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ + bkr.ob_image.array = bake_object_image_get_array(ob); + bkr.ob_image.len = ob->totcol; - bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple); - bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl); + bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple); + bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl); - RE_multires_bake_images(&bkr); + RE_multires_bake_images(&bkr); - MEM_freeN(bkr.ob_image.array); + MEM_freeN(bkr.ob_image.array); - BLI_freelistN(&bkr.image); + BLI_freelistN(&bkr.image); - bkr.lores_dm->release(bkr.lores_dm); - bkr.hires_dm->release(bkr.hires_dm); + bkr.lores_dm->release(bkr.lores_dm); + bkr.hires_dm->release(bkr.hires_dm); - objects_baked++; - } - CTX_DATA_END; + objects_baked++; + } + CTX_DATA_END; - if (!objects_baked) - BKE_report(op->reports, RPT_ERROR, "No objects found to bake from"); + if (!objects_baked) + BKE_report(op->reports, RPT_ERROR, "No objects found to bake from"); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* Multiresbake adopted for job-system executing */ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) { - Scene *scene = CTX_data_scene(C); - Object *ob; - - /* backup scene settings, so their changing in UI would take no effect on baker */ - bkj->scene = scene; - bkj->bake_filter = scene->r.bake_filter; - bkj->mode = scene->r.bake_mode; - bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; - bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; - bkj->bias = scene->r.bake_biasdist; - bkj->number_of_rays = scene->r.bake_samples; - bkj->threads = BKE_scene_num_threads(scene); - bkj->user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f; - //bkj->reports = op->reports; - - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - MultiresBakerJobData *data; - int lvl; - - ob = base->object; - - multires_force_update(ob); - - data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data"); - - data->ob_image.array = bake_object_image_get_array(ob); - data->ob_image.len = ob->totcol; - - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple); - data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl); - data->lvl = lvl; - - BLI_addtail(&bkj->data, data); - } - CTX_DATA_END; + Scene *scene = CTX_data_scene(C); + Object *ob; + + /* backup scene settings, so their changing in UI would take no effect on baker */ + bkj->scene = scene; + bkj->bake_filter = scene->r.bake_filter; + bkj->mode = scene->r.bake_mode; + bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; + bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; + bkj->bias = scene->r.bake_biasdist; + bkj->number_of_rays = scene->r.bake_samples; + bkj->threads = BKE_scene_num_threads(scene); + bkj->user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f; + //bkj->reports = op->reports; + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + MultiresBakerJobData *data; + int lvl; + + ob = base->object; + + multires_force_update(ob); + + data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data"); + + data->ob_image.array = bake_object_image_get_array(ob); + data->ob_image.len = ob->totcol; + + /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ + data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple); + data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl); + data->lvl = lvl; + + BLI_addtail(&bkj->data, data); + } + CTX_DATA_END; } static void multiresbake_startjob(void *bkv, short *stop, short *do_update, float *progress) { - MultiresBakerJobData *data; - MultiresBakeJob *bkj = bkv; - int baked_objects = 0, tot_obj; - - tot_obj = BLI_listbase_count(&bkj->data); - - if (bkj->bake_clear) { /* clear images */ - for (data = bkj->data.first; data; data = data->next) { - ClearFlag clear_flag = 0; - - if (bkj->mode == RE_BAKE_NORMALS) { - clear_flag = CLEAR_TANGENT_NORMAL; - } - else if (bkj->mode == RE_BAKE_DISPLACEMENT) { - clear_flag = CLEAR_DISPLACEMENT; - } - - clear_images_poly(data->ob_image.array, data->ob_image.len, clear_flag); - } - } - - for (data = bkj->data.first; data; data = data->next) { - MultiresBakeRender bkr = {NULL}; - - /* copy data stored in job descriptor */ - bkr.scene = bkj->scene; - bkr.bake_filter = bkj->bake_filter; - bkr.mode = bkj->mode; - bkr.use_lores_mesh = bkj->use_lores_mesh; - bkr.user_scale = bkj->user_scale; - //bkr.reports = bkj->reports; - bkr.ob_image.array = data->ob_image.array; - bkr.ob_image.len = data->ob_image.len; - - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - bkr.lores_dm = data->lores_dm; - bkr.hires_dm = data->hires_dm; - bkr.tot_lvl = data->tot_lvl; - bkr.lvl = data->lvl; - bkr.simple = data->simple; - - /* needed for proper progress bar */ - bkr.tot_obj = tot_obj; - bkr.baked_objects = baked_objects; - - bkr.stop = stop; - bkr.do_update = do_update; - bkr.progress = progress; - - bkr.bias = bkj->bias; - bkr.number_of_rays = bkj->number_of_rays; - bkr.threads = bkj->threads; - - RE_multires_bake_images(&bkr); - - data->images = bkr.image; - - baked_objects++; - } + MultiresBakerJobData *data; + MultiresBakeJob *bkj = bkv; + int baked_objects = 0, tot_obj; + + tot_obj = BLI_listbase_count(&bkj->data); + + if (bkj->bake_clear) { /* clear images */ + for (data = bkj->data.first; data; data = data->next) { + ClearFlag clear_flag = 0; + + if (bkj->mode == RE_BAKE_NORMALS) { + clear_flag = CLEAR_TANGENT_NORMAL; + } + else if (bkj->mode == RE_BAKE_DISPLACEMENT) { + clear_flag = CLEAR_DISPLACEMENT; + } + + clear_images_poly(data->ob_image.array, data->ob_image.len, clear_flag); + } + } + + for (data = bkj->data.first; data; data = data->next) { + MultiresBakeRender bkr = {NULL}; + + /* copy data stored in job descriptor */ + bkr.scene = bkj->scene; + bkr.bake_filter = bkj->bake_filter; + bkr.mode = bkj->mode; + bkr.use_lores_mesh = bkj->use_lores_mesh; + bkr.user_scale = bkj->user_scale; + //bkr.reports = bkj->reports; + bkr.ob_image.array = data->ob_image.array; + bkr.ob_image.len = data->ob_image.len; + + /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ + bkr.lores_dm = data->lores_dm; + bkr.hires_dm = data->hires_dm; + bkr.tot_lvl = data->tot_lvl; + bkr.lvl = data->lvl; + bkr.simple = data->simple; + + /* needed for proper progress bar */ + bkr.tot_obj = tot_obj; + bkr.baked_objects = baked_objects; + + bkr.stop = stop; + bkr.do_update = do_update; + bkr.progress = progress; + + bkr.bias = bkj->bias; + bkr.number_of_rays = bkj->number_of_rays; + bkr.threads = bkj->threads; + + RE_multires_bake_images(&bkr); + + data->images = bkr.image; + + baked_objects++; + } } static void multiresbake_freejob(void *bkv) { - MultiresBakeJob *bkj = bkv; - MultiresBakerJobData *data, *next; - LinkData *link; + MultiresBakeJob *bkj = bkv; + MultiresBakerJobData *data, *next; + LinkData *link; - data = bkj->data.first; - while (data) { - next = data->next; - data->lores_dm->release(data->lores_dm); - data->hires_dm->release(data->hires_dm); + data = bkj->data.first; + while (data) { + next = data->next; + data->lores_dm->release(data->lores_dm); + data->hires_dm->release(data->hires_dm); - /* delete here, since this delete will be called from main thread */ - for (link = data->images.first; link; link = link->next) { - Image *ima = (Image *)link->data; - GPU_free_image(ima); - } + /* delete here, since this delete will be called from main thread */ + for (link = data->images.first; link; link = link->next) { + Image *ima = (Image *)link->data; + GPU_free_image(ima); + } - MEM_freeN(data->ob_image.array); + MEM_freeN(data->ob_image.array); - BLI_freelistN(&data->images); + BLI_freelistN(&data->images); - MEM_freeN(data); - data = next; - } + MEM_freeN(data); + data = next; + } - MEM_freeN(bkj); + MEM_freeN(bkj); } static int multiresbake_image_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - MultiresBakeJob *bkr; - wmJob *wm_job; + Scene *scene = CTX_data_scene(C); + MultiresBakeJob *bkr; + wmJob *wm_job; - if (!multiresbake_check(C, op)) - return OPERATOR_CANCELLED; + if (!multiresbake_check(C, op)) + return OPERATOR_CANCELLED; - bkr = MEM_callocN(sizeof(MultiresBakeJob), "MultiresBakeJob data"); - init_multiresbake_job(C, bkr); + bkr = MEM_callocN(sizeof(MultiresBakeJob), "MultiresBakeJob data"); + init_multiresbake_job(C, bkr); - if (!bkr->data.first) { - BKE_report(op->reports, RPT_ERROR, "No objects found to bake from"); - return OPERATOR_CANCELLED; - } + if (!bkr->data.first) { + BKE_report(op->reports, RPT_ERROR, "No objects found to bake from"); + return OPERATOR_CANCELLED; + } - /* setup job */ - wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Multires Bake", - WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_BAKE_TEXTURE); - WM_jobs_customdata_set(wm_job, bkr, multiresbake_freejob); - WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ - WM_jobs_callbacks(wm_job, multiresbake_startjob, NULL, NULL, NULL); + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Multires Bake", + WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_BAKE_TEXTURE); + WM_jobs_customdata_set(wm_job, bkr, multiresbake_freejob); + WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ + WM_jobs_callbacks(wm_job, multiresbake_startjob, NULL, NULL, NULL); - G.is_break = false; + G.is_break = false; - WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_jobs_start(CTX_wm_manager(C), wm_job); + WM_cursor_wait(0); - /* add modal handler for ESC */ - WM_event_add_modal_handler(C, op); + /* add modal handler for ESC */ + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } /* ****************** render BAKING ********************** */ @@ -578,66 +579,65 @@ static int multiresbake_image_exec(bContext *C, wmOperator *op) /* catch esc */ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - /* no running blender, remove handler and pass through */ - if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE_TEXTURE)) - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; - - /* running render */ - switch (event->type) { - case ESCKEY: - return OPERATOR_RUNNING_MODAL; - } - return OPERATOR_PASS_THROUGH; + /* no running blender, remove handler and pass through */ + if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE_TEXTURE)) + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + + /* running render */ + switch (event->type) { + case ESCKEY: + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_PASS_THROUGH; } static bool is_multires_bake(Scene *scene) { - if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO)) - return scene->r.bake_flag & R_BAKE_MULTIRES; + if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO)) + return scene->r.bake_flag & R_BAKE_MULTIRES; - return 0; + return 0; } static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(_event)) { - Scene *scene = CTX_data_scene(C); - int result = OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + int result = OPERATOR_CANCELLED; - result = multiresbake_image_exec(C, op); + result = multiresbake_image_exec(C, op); - WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); - return result; + return result; } - static int bake_image_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - int result = OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + int result = OPERATOR_CANCELLED; - if (!is_multires_bake(scene)) { - BLI_assert(0); - return result; - } + if (!is_multires_bake(scene)) { + BLI_assert(0); + return result; + } - result = multiresbake_image_exec_locked(C, op); + result = multiresbake_image_exec_locked(C, op); - WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); - return result; + return result; } void OBJECT_OT_bake_image(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Bake"; - ot->description = "Bake image textures of selected objects"; - ot->idname = "OBJECT_OT_bake_image"; - - /* api callbacks */ - ot->exec = bake_image_exec; - ot->invoke = objects_bake_render_invoke; - ot->modal = objects_bake_render_modal; - ot->poll = ED_operator_object_active; + /* identifiers */ + ot->name = "Bake"; + ot->description = "Bake image textures of selected objects"; + ot->idname = "OBJECT_OT_bake_image"; + + /* api callbacks */ + ot->exec = bake_image_exec; + ot->invoke = objects_bake_render_invoke; + ot->modal = objects_bake_render_modal; + ot->poll = ED_operator_object_active; } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index e3e3f3d10ef..fba5a4e281e 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include "MEM_guardedalloc.h" #include "DNA_object_types.h" @@ -77,517 +76,584 @@ static void bake_set_props(wmOperator *op, Scene *scene); typedef struct BakeAPIRender { - Object *ob; - Main *main; - Scene *scene; - ViewLayer *view_layer; - ReportList *reports; - ListBase selected_objects; - - eScenePassType pass_type; - int pass_filter; - int margin; - - int save_mode; - - bool is_clear; - bool is_split_materials; - bool is_automatic_name; - bool is_selected_to_active; - bool is_cage; - - float cage_extrusion; - int normal_space; - eBakeNormalSwizzle normal_swizzle[3]; - - char uv_layer[MAX_CUSTOMDATA_LAYER_NAME]; - char custom_cage[MAX_NAME]; - char filepath[FILE_MAX]; - - int width; - int height; - const char *identifier; - - int result; - bool ready; - - /* callbacks */ - Render *render; - float *progress; - short *do_update; - - /* for redrawing */ - ScrArea *sa; + Object *ob; + Main *main; + Scene *scene; + ViewLayer *view_layer; + ReportList *reports; + ListBase selected_objects; + + eScenePassType pass_type; + int pass_filter; + int margin; + + int save_mode; + + bool is_clear; + bool is_split_materials; + bool is_automatic_name; + bool is_selected_to_active; + bool is_cage; + + float cage_extrusion; + int normal_space; + eBakeNormalSwizzle normal_swizzle[3]; + + char uv_layer[MAX_CUSTOMDATA_LAYER_NAME]; + char custom_cage[MAX_NAME]; + char filepath[FILE_MAX]; + + int width; + int height; + const char *identifier; + + int result; + bool ready; + + /* callbacks */ + Render *render; + float *progress; + short *do_update; + + /* for redrawing */ + ScrArea *sa; } BakeAPIRender; /* callbacks */ static void bake_progress_update(void *bjv, float progress) { - BakeAPIRender *bj = bjv; + BakeAPIRender *bj = bjv; - if (bj->progress && *bj->progress != progress) { - *bj->progress = progress; + if (bj->progress && *bj->progress != progress) { + *bj->progress = progress; - /* make jobs timer to send notifier */ - *(bj->do_update) = true; - } + /* make jobs timer to send notifier */ + *(bj->do_update) = true; + } } /* catch esc */ static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - /* no running blender, remove handler and pass through */ - if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE)) - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; - - /* running render */ - switch (event->type) { - case ESCKEY: - { - G.is_break = true; - return OPERATOR_RUNNING_MODAL; - } - } - return OPERATOR_PASS_THROUGH; + /* no running blender, remove handler and pass through */ + if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE)) + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + + /* running render */ + switch (event->type) { + case ESCKEY: { + G.is_break = true; + return OPERATOR_RUNNING_MODAL; + } + } + return OPERATOR_PASS_THROUGH; } /* for exec() when there is no render job * note: this wont check for the escape key being pressed, but doing so isnt threadsafe */ static int bake_break(void *UNUSED(rjv)) { - if (G.is_break) - return 1; - return 0; + if (G.is_break) + return 1; + return 0; } - static void bake_update_image(ScrArea *sa, Image *image) { - if (sa && sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */ - SpaceImage *sima = sa->spacedata.first; - if (sima) - sima->image = image; - } + if (sa && sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */ + SpaceImage *sima = sa->spacedata.first; + if (sima) + sima->image = image; + } } -static bool write_internal_bake_pixels( - Image *image, BakePixel pixel_array[], float *buffer, - const int width, const int height, const int margin, - const bool is_clear, const bool is_noncolor) +static bool write_internal_bake_pixels(Image *image, + BakePixel pixel_array[], + float *buffer, + const int width, + const int height, + const int margin, + const bool is_clear, + const bool is_noncolor) { - ImBuf *ibuf; - void *lock; - bool is_float; - char *mask_buffer = NULL; - const size_t num_pixels = (size_t)width * (size_t)height; - - ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); - - if (!ibuf) - return false; - - if (margin > 0 || !is_clear) { - mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); - RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); - } - - is_float = (ibuf->rect_float != NULL); - - /* colormanagement conversions */ - if (!is_noncolor) { - const char *from_colorspace; - const char *to_colorspace; - - from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); - - if (is_float) - to_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); - else - to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); - - if (from_colorspace != to_colorspace) - IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); - } - - /* populates the ImBuf */ - if (is_clear) { - if (is_float) { - IMB_buffer_float_from_float( - ibuf->rect_float, buffer, ibuf->channels, - IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, - ibuf->x, ibuf->y, ibuf->x, ibuf->x); - } - else { - IMB_buffer_byte_from_float( - (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, - IB_PROFILE_SRGB, IB_PROFILE_SRGB, - false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); - } - } - else { - if (is_float) { - IMB_buffer_float_from_float_mask( - ibuf->rect_float, buffer, ibuf->channels, - ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer); - } - else { - IMB_buffer_byte_from_float_mask( - (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, - false, ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer); - } - } - - /* margins */ - if (margin > 0) - RE_bake_margin(ibuf, mask_buffer, margin); - - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY; - - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; - - /* force mipmap recalc */ - if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; - imb_freemipmapImBuf(ibuf); - } - - BKE_image_release_ibuf(image, ibuf, NULL); - - if (mask_buffer) - MEM_freeN(mask_buffer); - - return true; + ImBuf *ibuf; + void *lock; + bool is_float; + char *mask_buffer = NULL; + const size_t num_pixels = (size_t)width * (size_t)height; + + ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + + if (!ibuf) + return false; + + if (margin > 0 || !is_clear) { + mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); + RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); + } + + is_float = (ibuf->rect_float != NULL); + + /* colormanagement conversions */ + if (!is_noncolor) { + const char *from_colorspace; + const char *to_colorspace; + + from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); + + if (is_float) + to_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); + else + to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); + + if (from_colorspace != to_colorspace) + IMB_colormanagement_transform( + buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); + } + + /* populates the ImBuf */ + if (is_clear) { + if (is_float) { + IMB_buffer_float_from_float(ibuf->rect_float, + buffer, + ibuf->channels, + IB_PROFILE_LINEAR_RGB, + IB_PROFILE_LINEAR_RGB, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x); + } + else { + IMB_buffer_byte_from_float((unsigned char *)ibuf->rect, + buffer, + ibuf->channels, + ibuf->dither, + IB_PROFILE_SRGB, + IB_PROFILE_SRGB, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x); + } + } + else { + if (is_float) { + IMB_buffer_float_from_float_mask(ibuf->rect_float, + buffer, + ibuf->channels, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x, + mask_buffer); + } + else { + IMB_buffer_byte_from_float_mask((unsigned char *)ibuf->rect, + buffer, + ibuf->channels, + ibuf->dither, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x, + mask_buffer); + } + } + + /* margins */ + if (margin > 0) + RE_bake_margin(ibuf, mask_buffer, margin); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY; + + if (ibuf->rect_float) + ibuf->userflags |= IB_RECT_INVALID; + + /* force mipmap recalc */ + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; + imb_freemipmapImBuf(ibuf); + } + + BKE_image_release_ibuf(image, ibuf, NULL); + + if (mask_buffer) + MEM_freeN(mask_buffer); + + return true; } /* force OpenGL reload */ static void refresh_images(BakeImages *bake_images) { - int i; - for (i = 0; i < bake_images->size; i++) { - Image *ima = bake_images->data[i].image; - if (ima->ok == IMA_OK_LOADED) { - GPU_free_image(ima); - DEG_id_tag_update(&ima->id, 0); - } - } + int i; + for (i = 0; i < bake_images->size; i++) { + Image *ima = bake_images->data[i].image; + if (ima->ok == IMA_OK_LOADED) { + GPU_free_image(ima); + DEG_id_tag_update(&ima->id, 0); + } + } } -static bool write_external_bake_pixels( - const char *filepath, BakePixel pixel_array[], float *buffer, - const int width, const int height, const int margin, - ImageFormatData *im_format, const bool is_noncolor) +static bool write_external_bake_pixels(const char *filepath, + BakePixel pixel_array[], + float *buffer, + const int width, + const int height, + const int margin, + ImageFormatData *im_format, + const bool is_noncolor) { - ImBuf *ibuf = NULL; - bool ok = false; - bool is_float; - - is_float = im_format->depth > 8; - - /* create a new ImBuf */ - ibuf = IMB_allocImBuf(width, height, im_format->planes, (is_float ? IB_rectfloat : IB_rect)); - - if (!ibuf) - return false; - - /* populates the ImBuf */ - if (is_float) { - IMB_buffer_float_from_float( - ibuf->rect_float, buffer, ibuf->channels, - IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, - ibuf->x, ibuf->y, ibuf->x, ibuf->x); - } - else { - if (!is_noncolor) { - const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); - const char *to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); - IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); - } - - IMB_buffer_byte_from_float( - (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, - IB_PROFILE_SRGB, IB_PROFILE_SRGB, - false, ibuf->x, ibuf->y, ibuf->x, ibuf->x); - } - - /* margins */ - if (margin > 0) { - char *mask_buffer = NULL; - const size_t num_pixels = (size_t)width * (size_t)height; - - mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); - RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); - RE_bake_margin(ibuf, mask_buffer, margin); - - if (mask_buffer) - MEM_freeN(mask_buffer); - } - - if ((ok = BKE_imbuf_write(ibuf, filepath, im_format))) { + ImBuf *ibuf = NULL; + bool ok = false; + bool is_float; + + is_float = im_format->depth > 8; + + /* create a new ImBuf */ + ibuf = IMB_allocImBuf(width, height, im_format->planes, (is_float ? IB_rectfloat : IB_rect)); + + if (!ibuf) + return false; + + /* populates the ImBuf */ + if (is_float) { + IMB_buffer_float_from_float(ibuf->rect_float, + buffer, + ibuf->channels, + IB_PROFILE_LINEAR_RGB, + IB_PROFILE_LINEAR_RGB, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x); + } + else { + if (!is_noncolor) { + const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get( + COLOR_ROLE_SCENE_LINEAR); + const char *to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); + IMB_colormanagement_transform( + buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false); + } + + IMB_buffer_byte_from_float((unsigned char *)ibuf->rect, + buffer, + ibuf->channels, + ibuf->dither, + IB_PROFILE_SRGB, + IB_PROFILE_SRGB, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x); + } + + /* margins */ + if (margin > 0) { + char *mask_buffer = NULL; + const size_t num_pixels = (size_t)width * (size_t)height; + + mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); + RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); + RE_bake_margin(ibuf, mask_buffer, margin); + + if (mask_buffer) + MEM_freeN(mask_buffer); + } + + if ((ok = BKE_imbuf_write(ibuf, filepath, im_format))) { #ifndef WIN32 - chmod(filepath, S_IRUSR | S_IWUSR); + chmod(filepath, S_IRUSR | S_IWUSR); #endif - //printf("%s saving bake map: '%s'\n", __func__, filepath); - } + //printf("%s saving bake map: '%s'\n", __func__, filepath); + } - /* garbage collection */ - IMB_freeImBuf(ibuf); + /* garbage collection */ + IMB_freeImBuf(ibuf); - return ok; + return ok; } static bool is_noncolor_pass(eScenePassType pass_type) { - return ELEM(pass_type, - SCE_PASS_Z, - SCE_PASS_NORMAL, - SCE_PASS_VECTOR, - SCE_PASS_INDEXOB, - SCE_PASS_UV, - SCE_PASS_RAYHITS, - SCE_PASS_INDEXMA); + return ELEM(pass_type, + SCE_PASS_Z, + SCE_PASS_NORMAL, + SCE_PASS_VECTOR, + SCE_PASS_INDEXOB, + SCE_PASS_UV, + SCE_PASS_RAYHITS, + SCE_PASS_INDEXMA); } /* if all is good tag image and return true */ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *reports) { - Image *image; - Base *base = BKE_view_layer_base_find(view_layer, ob); - void *lock; - int i; - - if (base == NULL) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not in view layer", ob->id.name + 2); - return false; - } - - if (!(base->flag & BASE_ENABLED_RENDER)) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not enabled for rendering", ob->id.name + 2); - return false; - } - - - if (ob->type != OB_MESH) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2); - return false; - } - else { - Mesh *me = (Mesh *)ob->data; - - if (CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV) == -1) { - BKE_reportf(reports, RPT_ERROR, - "No active UV layer found in the object \"%s\"", ob->id.name + 2); - return false; - } - } - - for (i = 0; i < ob->totcol; i++) { - bNodeTree *ntree = NULL; - bNode *node = NULL; - ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree); - - if (image) { - ImBuf *ibuf; - - if (node) { - if (BKE_node_is_connected_to_output(ntree, node)) { - /* we don't return false since this may be a false positive - * this can't be RPT_ERROR though, otherwise it prevents - * multiple highpoly objects to be baked at once */ - BKE_reportf(reports, RPT_INFO, - "Circular dependency for image \"%s\" from object \"%s\"", - image->id.name + 2, ob->id.name + 2); - } - } - - ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); - - if (ibuf) { - BKE_image_release_ibuf(image, ibuf, lock); - } - else { - BKE_reportf(reports, RPT_ERROR, - "Uninitialized image \"%s\" from object \"%s\"", - image->id.name + 2, ob->id.name + 2); - - BKE_image_release_ibuf(image, ibuf, lock); - return false; - } - } - else { - Material *mat = give_current_material(ob, i); - if (mat != NULL) { - BKE_reportf(reports, RPT_INFO, - "No active image found in material \"%s\" (%d) for object \"%s\"", - mat->id.name + 2, i, ob->id.name + 2); - } - else { - BKE_reportf(reports, RPT_INFO, - "No active image found in material slot (%d) for object \"%s\"", - i, ob->id.name + 2); - } - continue; - } - - image->id.tag |= LIB_TAG_DOIT; - } - return true; + Image *image; + Base *base = BKE_view_layer_base_find(view_layer, ob); + void *lock; + int i; + + if (base == NULL) { + BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not in view layer", ob->id.name + 2); + return false; + } + + if (!(base->flag & BASE_ENABLED_RENDER)) { + BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not enabled for rendering", ob->id.name + 2); + return false; + } + + if (ob->type != OB_MESH) { + BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2); + return false; + } + else { + Mesh *me = (Mesh *)ob->data; + + if (CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV) == -1) { + BKE_reportf( + reports, RPT_ERROR, "No active UV layer found in the object \"%s\"", ob->id.name + 2); + return false; + } + } + + for (i = 0; i < ob->totcol; i++) { + bNodeTree *ntree = NULL; + bNode *node = NULL; + ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree); + + if (image) { + ImBuf *ibuf; + + if (node) { + if (BKE_node_is_connected_to_output(ntree, node)) { + /* we don't return false since this may be a false positive + * this can't be RPT_ERROR though, otherwise it prevents + * multiple highpoly objects to be baked at once */ + BKE_reportf(reports, + RPT_INFO, + "Circular dependency for image \"%s\" from object \"%s\"", + image->id.name + 2, + ob->id.name + 2); + } + } + + ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + + if (ibuf) { + BKE_image_release_ibuf(image, ibuf, lock); + } + else { + BKE_reportf(reports, + RPT_ERROR, + "Uninitialized image \"%s\" from object \"%s\"", + image->id.name + 2, + ob->id.name + 2); + + BKE_image_release_ibuf(image, ibuf, lock); + return false; + } + } + else { + Material *mat = give_current_material(ob, i); + if (mat != NULL) { + BKE_reportf(reports, + RPT_INFO, + "No active image found in material \"%s\" (%d) for object \"%s\"", + mat->id.name + 2, + i, + ob->id.name + 2); + } + else { + BKE_reportf(reports, + RPT_INFO, + "No active image found in material slot (%d) for object \"%s\"", + i, + ob->id.name + 2); + } + continue; + } + + image->id.tag |= LIB_TAG_DOIT; + } + return true; } -static bool bake_pass_filter_check(eScenePassType pass_type, const int pass_filter, ReportList *reports) +static bool bake_pass_filter_check(eScenePassType pass_type, + const int pass_filter, + ReportList *reports) { - switch (pass_type) { - case SCE_PASS_COMBINED: - if ((pass_filter & R_BAKE_PASS_FILTER_EMIT) != 0) { - return true; - } - - if (((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0)) - { - if (((pass_filter & R_BAKE_PASS_FILTER_DIFFUSE) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_GLOSSY) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_TRANSM) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_SUBSURFACE) != 0)) - { - return true; - } - - if ((pass_filter & R_BAKE_PASS_FILTER_AO) != 0) { - BKE_report(reports, RPT_ERROR, - "Combined bake pass Ambient Occlusion contribution requires an enabled light pass " - "(bake the Ambient Occlusion pass type instead)"); - } - else { - BKE_report(reports, RPT_ERROR, - "Combined bake pass requires Emit, or a light pass with " - "Direct or Indirect contributions enabled"); - } - - return false; - } - else { - BKE_report(reports, RPT_ERROR, - "Combined bake pass requires Emit, or a light pass with " - "Direct or Indirect contributions enabled"); - return false; - } - break; - case SCE_PASS_DIFFUSE_COLOR: - case SCE_PASS_GLOSSY_COLOR: - case SCE_PASS_TRANSM_COLOR: - case SCE_PASS_SUBSURFACE_COLOR: - if (((pass_filter & R_BAKE_PASS_FILTER_COLOR) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) || - ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0)) - { - return true; - } - else { - BKE_report(reports, RPT_ERROR, - "Bake pass requires Direct, Indirect, or Color contributions to be enabled"); - return false; - } - break; - default: - return true; - break; - } + switch (pass_type) { + case SCE_PASS_COMBINED: + if ((pass_filter & R_BAKE_PASS_FILTER_EMIT) != 0) { + return true; + } + + if (((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0)) { + if (((pass_filter & R_BAKE_PASS_FILTER_DIFFUSE) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_GLOSSY) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_TRANSM) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_SUBSURFACE) != 0)) { + return true; + } + + if ((pass_filter & R_BAKE_PASS_FILTER_AO) != 0) { + BKE_report( + reports, + RPT_ERROR, + "Combined bake pass Ambient Occlusion contribution requires an enabled light pass " + "(bake the Ambient Occlusion pass type instead)"); + } + else { + BKE_report(reports, + RPT_ERROR, + "Combined bake pass requires Emit, or a light pass with " + "Direct or Indirect contributions enabled"); + } + + return false; + } + else { + BKE_report(reports, + RPT_ERROR, + "Combined bake pass requires Emit, or a light pass with " + "Direct or Indirect contributions enabled"); + return false; + } + break; + case SCE_PASS_DIFFUSE_COLOR: + case SCE_PASS_GLOSSY_COLOR: + case SCE_PASS_TRANSM_COLOR: + case SCE_PASS_SUBSURFACE_COLOR: + if (((pass_filter & R_BAKE_PASS_FILTER_COLOR) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) || + ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0)) { + return true; + } + else { + BKE_report(reports, + RPT_ERROR, + "Bake pass requires Direct, Indirect, or Color contributions to be enabled"); + return false; + } + break; + default: + return true; + break; + } } /* before even getting in the bake function we check for some basic errors */ -static bool bake_objects_check(Main *bmain, ViewLayer *view_layer, Object *ob, ListBase *selected_objects, - ReportList *reports, const bool is_selected_to_active) +static bool bake_objects_check(Main *bmain, + ViewLayer *view_layer, + Object *ob, + ListBase *selected_objects, + ReportList *reports, + const bool is_selected_to_active) { - CollectionPointerLink *link; - - /* error handling and tag (in case multiple materials share the same image) */ - BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false); - - if (is_selected_to_active) { - int tot_objects = 0; - - if (!bake_object_check(view_layer, ob, reports)) - return false; - - for (link = selected_objects->first; link; link = link->next) { - Object *ob_iter = (Object *)link->ptr.data; - - if (ob_iter == ob) - continue; - - if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, Surface or Metaball)", ob_iter->id.name + 2); - return false; - } - tot_objects += 1; - } - - if (tot_objects == 0) { - BKE_report(reports, RPT_ERROR, "No valid selected objects"); - return false; - } - } - else { - if (BLI_listbase_is_empty(selected_objects)) { - BKE_report(reports, RPT_ERROR, "No valid selected objects"); - return false; - } - - for (link = selected_objects->first; link; link = link->next) { - if (!bake_object_check(view_layer, link->ptr.data, reports)) - return false; - } - } - return true; + CollectionPointerLink *link; + + /* error handling and tag (in case multiple materials share the same image) */ + BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false); + + if (is_selected_to_active) { + int tot_objects = 0; + + if (!bake_object_check(view_layer, ob, reports)) + return false; + + for (link = selected_objects->first; link; link = link->next) { + Object *ob_iter = (Object *)link->ptr.data; + + if (ob_iter == ob) + continue; + + if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { + BKE_reportf(reports, + RPT_ERROR, + "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, " + "Surface or Metaball)", + ob_iter->id.name + 2); + return false; + } + tot_objects += 1; + } + + if (tot_objects == 0) { + BKE_report(reports, RPT_ERROR, "No valid selected objects"); + return false; + } + } + else { + if (BLI_listbase_is_empty(selected_objects)) { + BKE_report(reports, RPT_ERROR, "No valid selected objects"); + return false; + } + + for (link = selected_objects->first; link; link = link->next) { + if (!bake_object_check(view_layer, link->ptr.data, reports)) + return false; + } + } + return true; } /* it needs to be called after bake_objects_check since the image tagging happens there */ static void bake_images_clear(Main *bmain, const bool is_tangent) { - Image *image; - for (image = bmain->images.first; image; image = image->id.next) { - if ((image->id.tag & LIB_TAG_DOIT) != 0) { - RE_bake_ibuf_clear(image, is_tangent); - } - } + Image *image; + for (image = bmain->images.first; image; image = image->id.next) { + if ((image->id.tag & LIB_TAG_DOIT) != 0) { + RE_bake_ibuf_clear(image, is_tangent); + } + } } static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) { - const int tot_mat = ob->totcol; - int i, j; - int tot_images = 0; - - /* error handling and tag (in case multiple materials share the same image) */ - BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false); - - for (i = 0; i < tot_mat; i++) { - Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); - - /* Some materials have no image, we just ignore those cases. */ - if (image == NULL) { - bake_images->lookup[i] = -1; - } - else if (image->id.tag & LIB_TAG_DOIT) { - for (j = 0; j < i; j++) { - if (bake_images->data[j].image == image) { - bake_images->lookup[i] = j; - break; - } - } - } - else { - bake_images->lookup[i] = tot_images; - bake_images->data[tot_images].image = image; - image->id.tag |= LIB_TAG_DOIT; - tot_images++; - } - } - - bake_images->size = tot_images; + const int tot_mat = ob->totcol; + int i, j; + int tot_images = 0; + + /* error handling and tag (in case multiple materials share the same image) */ + BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false); + + for (i = 0; i < tot_mat; i++) { + Image *image; + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); + + /* Some materials have no image, we just ignore those cases. */ + if (image == NULL) { + bake_images->lookup[i] = -1; + } + else if (image->id.tag & LIB_TAG_DOIT) { + for (j = 0; j < i; j++) { + if (bake_images->data[j].image == image) { + bake_images->lookup[i] = j; + break; + } + } + } + else { + bake_images->lookup[i] = tot_images; + bake_images->data[tot_images].image = image; + image->id.tag |= LIB_TAG_DOIT; + tot_images++; + } + } + + bake_images->size = tot_images; } /* @@ -595,881 +661,1130 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) */ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *reports) { - int i; - size_t tot_size = 0; - - for (i = 0; i < bake_images->size; i++) { - ImBuf *ibuf; - void *lock; - - BakeImage *bk_image = &bake_images->data[i]; - ibuf = BKE_image_acquire_ibuf(bk_image->image, NULL, &lock); - - if (ibuf) { - bk_image->width = ibuf->x; - bk_image->height = ibuf->y; - bk_image->offset = tot_size; - - tot_size += (size_t)ibuf->x * (size_t)ibuf->y; - } - else { - BKE_image_release_ibuf(bk_image->image, ibuf, lock); - BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2); - return 0; - } - BKE_image_release_ibuf(bk_image->image, ibuf, lock); - } - return tot_size; + int i; + size_t tot_size = 0; + + for (i = 0; i < bake_images->size; i++) { + ImBuf *ibuf; + void *lock; + + BakeImage *bk_image = &bake_images->data[i]; + ibuf = BKE_image_acquire_ibuf(bk_image->image, NULL, &lock); + + if (ibuf) { + bk_image->width = ibuf->x; + bk_image->height = ibuf->y; + bk_image->offset = tot_size; + + tot_size += (size_t)ibuf->x * (size_t)ibuf->y; + } + else { + BKE_image_release_ibuf(bk_image->image, ibuf, lock); + BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2); + return 0; + } + BKE_image_release_ibuf(bk_image->image, ibuf, lock); + } + return tot_size; } /* create new mesh with edit mode changes and modifiers applied */ static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob) { - bool apply_modifiers = (ob->type != OB_MESH); - Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, apply_modifiers, false); + bool apply_modifiers = (ob->type != OB_MESH); + Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, apply_modifiers, false); - if (me->flag & ME_AUTOSMOOTH) { - BKE_mesh_split_faces(me, true); - } + if (me->flag & ME_AUTOSMOOTH) { + BKE_mesh_split_faces(me, true); + } - return me; + return me; } -static int bake( - Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob_low, ListBase *selected_objects, - ReportList *reports, - const eScenePassType pass_type, const int pass_filter, const int margin, - const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, - const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, - const float cage_extrusion, const int normal_space, const eBakeNormalSwizzle normal_swizzle[], - const char *custom_cage, const char *filepath, const int width, const int height, - const char *identifier, ScrArea *sa, const char *uv_layer) +static int bake(Render *re, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + Object *ob_low, + ListBase *selected_objects, + ReportList *reports, + const eScenePassType pass_type, + const int pass_filter, + const int margin, + const eBakeSaveMode save_mode, + const bool is_clear, + const bool is_split_materials, + const bool is_automatic_name, + const bool is_selected_to_active, + const bool is_cage, + const float cage_extrusion, + const int normal_space, + const eBakeNormalSwizzle normal_swizzle[], + const char *custom_cage, + const char *filepath, + const int width, + const int height, + const char *identifier, + ScrArea *sa, + const char *uv_layer) { - /* We build a depsgraph for the baking, - * so we don't need to change the original data to adjust visibility and modifiers. */ - Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); - DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); - - int op_result = OPERATOR_CANCELLED; - bool ok = false; - - Object *ob_cage = NULL; - Object *ob_cage_eval = NULL; - Object *ob_low_eval = NULL; - - BakeHighPolyData *highpoly = NULL; - int tot_highpoly = 0; - - Mesh *me_low = NULL; - Mesh *me_cage = NULL; - - MultiresModifierData *mmd_low = NULL; - int mmd_flags_low = 0; - - float *result = NULL; - - BakePixel *pixel_array_low = NULL; - BakePixel *pixel_array_high = NULL; - - const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); - const bool is_noncolor = is_noncolor_pass(pass_type); - const int depth = RE_pass_depth(pass_type); - - BakeImages bake_images = {NULL}; - - size_t num_pixels; - int tot_materials; - - RE_bake_engine_set_engine_parameters(re, bmain, scene); - - if (!RE_bake_has_engine(re)) { - BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); - goto cleanup; - } - - tot_materials = ob_low->totcol; - - if (uv_layer && uv_layer[0] != '\0') { - Mesh *me = (Mesh *)ob_low->data; - if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { - BKE_reportf(reports, RPT_ERROR, - "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); - goto cleanup; - } - } - - if (tot_materials == 0) { - if (is_save_internal) { - BKE_report(reports, RPT_ERROR, - "No active image found, add a material or bake to an external file"); - - goto cleanup; - } - else if (is_split_materials) { - BKE_report(reports, RPT_ERROR, - "No active image found, add a material or bake without the Split Materials option"); - - goto cleanup; - } - else { - /* baking externally without splitting materials */ - tot_materials = 1; - } - } - - /* we overallocate in case there is more materials than images */ - bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); - bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); - - build_image_lookup(bmain, ob_low, &bake_images); - - if (is_save_internal) { - num_pixels = initialize_internal_images(&bake_images, reports); - - if (num_pixels == 0) { - goto cleanup; - } - } - else { - /* when saving externally always use the size specified in the UI */ - - num_pixels = (size_t)width * (size_t)height * bake_images.size; - - for (int i = 0; i < bake_images.size; i++) { - bake_images.data[i].width = width; - bake_images.data[i].height = height; - bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); - bake_images.data[i].image = NULL; - } - - if (!is_split_materials) { - /* saving a single image */ - for (int i = 0; i < tot_materials; i++) { - bake_images.lookup[i] = 0; - } - } - } - - if (is_selected_to_active) { - CollectionPointerLink *link; - tot_highpoly = 0; - - for (link = selected_objects->first; link; link = link->next) { - Object *ob_iter = link->ptr.data; - - if (ob_iter == ob_low) - continue; - - tot_highpoly ++; - } - - if (is_cage && custom_cage[0] != '\0') { - ob_cage = BLI_findstring(&bmain->objects, custom_cage, offsetof(ID, name) + 2); - - if (ob_cage == NULL || ob_cage->type != OB_MESH) { - BKE_report(reports, RPT_ERROR, "No valid cage object"); - goto cleanup; - } - else { - ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage); - ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); - } - } - } - - pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); - pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); - result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); - - /* for multires bake, use linear UV subdivision to match low res UVs */ - if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && !is_selected_to_active) { - mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires); - if (mmd_low) { - mmd_flags_low = mmd_low->flags; - mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE; - } - } - - /* Make sure depsgraph is up to date. */ - BKE_scene_graph_update_tagged(depsgraph, bmain); - ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); - - /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); - - /* populate the pixel array with the face data */ - if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) - RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); - /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ - - if (is_selected_to_active) { - CollectionPointerLink *link; - int i = 0; - - /* prepare cage mesh */ - if (ob_cage) { - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage_eval); - if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { - BKE_report(reports, RPT_ERROR, - "Invalid cage object, the cage mesh must have the same number " - "of faces as the active object"); - goto cleanup; - } - } - else if (is_cage) { - BKE_object_eval_reset(ob_low_eval); - - ModifierData *md = ob_low_eval->modifiers.first; - while (md) { - ModifierData *md_next = md->next; - - /* Edge Split cannot be applied in the cage, - * the cage is supposed to have interpolated normals - * between the faces unless the geometry is physically - * split. So we create a copy of the low poly mesh without - * the eventual edge split.*/ - - if (md->type == eModifierType_EdgeSplit) { - BLI_remlink(&ob_low_eval->modifiers, md); - modifier_free(md); - } - md = md_next; - } - - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); - RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); - } - - highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); - - /* populate highpoly array */ - for (link = selected_objects->first; link; link = link->next) { - Object *ob_iter = link->ptr.data; - - if (ob_iter == ob_low) - continue; - - /* initialize highpoly_data */ - highpoly[i].ob = ob_iter; - highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); - highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; - highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob_eval); - - /* lowpoly to highpoly transformation matrix */ - copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); - invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); - - highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); - - i++; - } - - BLI_assert(i == tot_highpoly); - - - if (ob_cage != NULL) { - ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); - } - ob_low_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); - - /* populate the pixel arrays with the corresponding face data for each high poly object */ - if (!RE_bake_pixels_populate_from_objects( - me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, - cage_extrusion, ob_low_eval->obmat, (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), me_cage)) - { - BKE_report(reports, RPT_ERROR, "Error handling selected objects"); - goto cleanup; - } - - /* the baking itself */ - for (i = 0; i < tot_highpoly; i++) { - ok = RE_bake_engine(re, depsgraph, highpoly[i].ob, i, pixel_array_high, - num_pixels, depth, pass_type, pass_filter, result); - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); - goto cleanup; - } - } - } - else { - /* If low poly is not renderable it should have failed long ago. */ - BLI_assert((ob_low_eval->restrictflag & OB_RESTRICT_RENDER) == 0); - - if (RE_bake_has_engine(re)) { - ok = RE_bake_engine(re, depsgraph, ob_low_eval, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result); - } - else { - BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); - goto cleanup; - } - } - - /* normal space conversion - * the normals are expected to be in world space, +X +Y +Z */ - if (ok && pass_type == SCE_PASS_NORMAL) { - switch (normal_space) { - case R_BAKE_SPACE_WORLD: - { - /* Cycles internal format */ - if ((normal_swizzle[0] == R_BAKE_POSX) && - (normal_swizzle[1] == R_BAKE_POSY) && - (normal_swizzle[2] == R_BAKE_POSZ)) - { - break; - } - else { - RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); - } - break; - } - case R_BAKE_SPACE_OBJECT: - { - RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low_eval, normal_swizzle); - break; - } - case R_BAKE_SPACE_TANGENT: - { - if (is_selected_to_active) { - RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low_eval->obmat); - } - else { - /* from multiresolution */ - Mesh *me_nores = NULL; - ModifierData *md = NULL; - int mode; - - BKE_object_eval_reset(ob_low_eval); - md = modifiers_findByType(ob_low_eval, eModifierType_Multires); - - if (md) { - mode = md->mode; - md->mode &= ~eModifierMode_Render; - } - - /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval, true, false); - RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); - - RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_id_free(bmain, me_nores); - - if (md) - md->mode = mode; - } - break; - } - default: - break; - } - } - - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); - op_result = OPERATOR_CANCELLED; - } - else { - /* save the results */ - for (int i = 0; i < bake_images.size; i++) { - BakeImage *bk_image = &bake_images.data[i]; - - if (is_save_internal) { - ok = write_internal_bake_pixels( - bk_image->image, - pixel_array_low + bk_image->offset, - result + bk_image->offset * depth, - bk_image->width, bk_image->height, - margin, is_clear, is_noncolor); - - /* might be read by UI to set active image for display */ - bake_update_image(sa, bk_image->image); - - if (!ok) { - BKE_reportf(reports, RPT_ERROR, - "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); - op_result = OPERATOR_CANCELLED; - } - else { - BKE_report(reports, RPT_INFO, - "Baking map saved to internal image, save it externally or pack it"); - op_result = OPERATOR_FINISHED; - } - } - /* save externally */ - else { - BakeData *bake = &scene->r.bake; - char name[FILE_MAX]; - - BKE_image_path_from_imtype(name, filepath, BKE_main_blendfile_path(bmain), - 0, bake->im_format.imtype, true, false, NULL); - - if (is_automatic_name) { - BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); - BLI_path_suffix(name, FILE_MAX, identifier, "_"); - } - - if (is_split_materials) { - if (bk_image->image) { - BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); - } - else { - if (ob_low_eval->mat[i]) { - BLI_path_suffix(name, FILE_MAX, ob_low_eval->mat[i]->id.name + 2, "_"); - } - else if (me_low->mat[i]) { - BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); - } - else { - /* if everything else fails, use the material index */ - char tmp[5]; - sprintf(tmp, "%d", i % 1000); - BLI_path_suffix(name, FILE_MAX, tmp, "_"); - } - } - } - - /* save it externally */ - ok = write_external_bake_pixels( - name, - pixel_array_low + bk_image->offset, - result + bk_image->offset * depth, - bk_image->width, bk_image->height, - margin, &bake->im_format, is_noncolor); - - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); - op_result = OPERATOR_CANCELLED; - } - else { - BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); - op_result = OPERATOR_FINISHED; - } - - if (!is_split_materials) { - break; - } - } - } - } - - if (is_save_internal) - refresh_images(&bake_images); + /* We build a depsgraph for the baking, + * so we don't need to change the original data to adjust visibility and modifiers. */ + Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); + DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); + + int op_result = OPERATOR_CANCELLED; + bool ok = false; + + Object *ob_cage = NULL; + Object *ob_cage_eval = NULL; + Object *ob_low_eval = NULL; + + BakeHighPolyData *highpoly = NULL; + int tot_highpoly = 0; + + Mesh *me_low = NULL; + Mesh *me_cage = NULL; + + MultiresModifierData *mmd_low = NULL; + int mmd_flags_low = 0; + + float *result = NULL; + + BakePixel *pixel_array_low = NULL; + BakePixel *pixel_array_high = NULL; + + const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); + const bool is_noncolor = is_noncolor_pass(pass_type); + const int depth = RE_pass_depth(pass_type); + + BakeImages bake_images = {NULL}; + + size_t num_pixels; + int tot_materials; + + RE_bake_engine_set_engine_parameters(re, bmain, scene); + + if (!RE_bake_has_engine(re)) { + BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); + goto cleanup; + } + + tot_materials = ob_low->totcol; + + if (uv_layer && uv_layer[0] != '\0') { + Mesh *me = (Mesh *)ob_low->data; + if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { + BKE_reportf(reports, + RPT_ERROR, + "No UV layer named \"%s\" found in the object \"%s\"", + uv_layer, + ob_low->id.name + 2); + goto cleanup; + } + } + + if (tot_materials == 0) { + if (is_save_internal) { + BKE_report( + reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); + + goto cleanup; + } + else if (is_split_materials) { + BKE_report( + reports, + RPT_ERROR, + "No active image found, add a material or bake without the Split Materials option"); + + goto cleanup; + } + else { + /* baking externally without splitting materials */ + tot_materials = 1; + } + } + + /* we overallocate in case there is more materials than images */ + bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, + "bake images dimensions (width, height, offset)"); + bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, + "bake images lookup (from material to BakeImage)"); + + build_image_lookup(bmain, ob_low, &bake_images); + + if (is_save_internal) { + num_pixels = initialize_internal_images(&bake_images, reports); + + if (num_pixels == 0) { + goto cleanup; + } + } + else { + /* when saving externally always use the size specified in the UI */ + + num_pixels = (size_t)width * (size_t)height * bake_images.size; + + for (int i = 0; i < bake_images.size; i++) { + bake_images.data[i].width = width; + bake_images.data[i].height = height; + bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); + bake_images.data[i].image = NULL; + } + + if (!is_split_materials) { + /* saving a single image */ + for (int i = 0; i < tot_materials; i++) { + bake_images.lookup[i] = 0; + } + } + } + + if (is_selected_to_active) { + CollectionPointerLink *link; + tot_highpoly = 0; + + for (link = selected_objects->first; link; link = link->next) { + Object *ob_iter = link->ptr.data; + + if (ob_iter == ob_low) + continue; + + tot_highpoly++; + } + + if (is_cage && custom_cage[0] != '\0') { + ob_cage = BLI_findstring(&bmain->objects, custom_cage, offsetof(ID, name) + 2); + + if (ob_cage == NULL || ob_cage->type != OB_MESH) { + BKE_report(reports, RPT_ERROR, "No valid cage object"); + goto cleanup; + } + else { + ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage); + ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; + ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + } + } + } + + pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); + pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); + result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); + + /* for multires bake, use linear UV subdivision to match low res UVs */ + if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && + !is_selected_to_active) { + mmd_low = (MultiresModifierData *)modifiers_findByType(ob_low, eModifierType_Multires); + if (mmd_low) { + mmd_flags_low = mmd_low->flags; + mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE; + } + } + + /* Make sure depsgraph is up to date. */ + BKE_scene_graph_update_tagged(depsgraph, bmain); + ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); + + /* get the mesh as it arrives in the renderer */ + me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + + /* populate the pixel array with the face data */ + if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) + RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); + /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ + + if (is_selected_to_active) { + CollectionPointerLink *link; + int i = 0; + + /* prepare cage mesh */ + if (ob_cage) { + me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage_eval); + if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { + BKE_report(reports, + RPT_ERROR, + "Invalid cage object, the cage mesh must have the same number " + "of faces as the active object"); + goto cleanup; + } + } + else if (is_cage) { + BKE_object_eval_reset(ob_low_eval); + + ModifierData *md = ob_low_eval->modifiers.first; + while (md) { + ModifierData *md_next = md->next; + + /* Edge Split cannot be applied in the cage, + * the cage is supposed to have interpolated normals + * between the faces unless the geometry is physically + * split. So we create a copy of the low poly mesh without + * the eventual edge split.*/ + + if (md->type == eModifierType_EdgeSplit) { + BLI_remlink(&ob_low_eval->modifiers, md); + modifier_free(md); + } + md = md_next; + } + + me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); + } + + highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); + + /* populate highpoly array */ + for (link = selected_objects->first; link; link = link->next) { + Object *ob_iter = link->ptr.data; + + if (ob_iter == ob_low) + continue; + + /* initialize highpoly_data */ + highpoly[i].ob = ob_iter; + highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); + highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; + highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); + highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob_eval); + + /* lowpoly to highpoly transformation matrix */ + copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); + invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); + + highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); + + i++; + } + + BLI_assert(i == tot_highpoly); + + if (ob_cage != NULL) { + ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; + ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + } + ob_low_eval->restrictflag |= OB_RESTRICT_RENDER; + ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + + /* populate the pixel arrays with the corresponding face data for each high poly object */ + if (!RE_bake_pixels_populate_from_objects(me_low, + pixel_array_low, + pixel_array_high, + highpoly, + tot_highpoly, + num_pixels, + ob_cage != NULL, + cage_extrusion, + ob_low_eval->obmat, + (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), + me_cage)) { + BKE_report(reports, RPT_ERROR, "Error handling selected objects"); + goto cleanup; + } + + /* the baking itself */ + for (i = 0; i < tot_highpoly; i++) { + ok = RE_bake_engine(re, + depsgraph, + highpoly[i].ob, + i, + pixel_array_high, + num_pixels, + depth, + pass_type, + pass_filter, + result); + if (!ok) { + BKE_reportf( + reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); + goto cleanup; + } + } + } + else { + /* If low poly is not renderable it should have failed long ago. */ + BLI_assert((ob_low_eval->restrictflag & OB_RESTRICT_RENDER) == 0); + + if (RE_bake_has_engine(re)) { + ok = RE_bake_engine(re, + depsgraph, + ob_low_eval, + 0, + pixel_array_low, + num_pixels, + depth, + pass_type, + pass_filter, + result); + } + else { + BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); + goto cleanup; + } + } + + /* normal space conversion + * the normals are expected to be in world space, +X +Y +Z */ + if (ok && pass_type == SCE_PASS_NORMAL) { + switch (normal_space) { + case R_BAKE_SPACE_WORLD: { + /* Cycles internal format */ + if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && + (normal_swizzle[2] == R_BAKE_POSZ)) { + break; + } + else { + RE_bake_normal_world_to_world( + pixel_array_low, num_pixels, depth, result, normal_swizzle); + } + break; + } + case R_BAKE_SPACE_OBJECT: { + RE_bake_normal_world_to_object( + pixel_array_low, num_pixels, depth, result, ob_low_eval, normal_swizzle); + break; + } + case R_BAKE_SPACE_TANGENT: { + if (is_selected_to_active) { + RE_bake_normal_world_to_tangent(pixel_array_low, + num_pixels, + depth, + result, + me_low, + normal_swizzle, + ob_low_eval->obmat); + } + else { + /* from multiresolution */ + Mesh *me_nores = NULL; + ModifierData *md = NULL; + int mode; + + BKE_object_eval_reset(ob_low_eval); + md = modifiers_findByType(ob_low_eval, eModifierType_Multires); + + if (md) { + mode = md->mode; + md->mode &= ~eModifierMode_Render; + } + + /* Evaluate modifiers again. */ + me_nores = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval, true, false); + RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); + + RE_bake_normal_world_to_tangent(pixel_array_low, + num_pixels, + depth, + result, + me_nores, + normal_swizzle, + ob_low_eval->obmat); + BKE_id_free(bmain, me_nores); + + if (md) + md->mode = mode; + } + break; + } + default: + break; + } + } + + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); + op_result = OPERATOR_CANCELLED; + } + else { + /* save the results */ + for (int i = 0; i < bake_images.size; i++) { + BakeImage *bk_image = &bake_images.data[i]; + + if (is_save_internal) { + ok = write_internal_bake_pixels(bk_image->image, + pixel_array_low + bk_image->offset, + result + bk_image->offset * depth, + bk_image->width, + bk_image->height, + margin, + is_clear, + is_noncolor); + + /* might be read by UI to set active image for display */ + bake_update_image(sa, bk_image->image); + + if (!ok) { + BKE_reportf(reports, + RPT_ERROR, + "Problem saving the bake map internally for object \"%s\"", + ob_low->id.name + 2); + op_result = OPERATOR_CANCELLED; + } + else { + BKE_report(reports, + RPT_INFO, + "Baking map saved to internal image, save it externally or pack it"); + op_result = OPERATOR_FINISHED; + } + } + /* save externally */ + else { + BakeData *bake = &scene->r.bake; + char name[FILE_MAX]; + + BKE_image_path_from_imtype(name, + filepath, + BKE_main_blendfile_path(bmain), + 0, + bake->im_format.imtype, + true, + false, + NULL); + + if (is_automatic_name) { + BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); + BLI_path_suffix(name, FILE_MAX, identifier, "_"); + } + + if (is_split_materials) { + if (bk_image->image) { + BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); + } + else { + if (ob_low_eval->mat[i]) { + BLI_path_suffix(name, FILE_MAX, ob_low_eval->mat[i]->id.name + 2, "_"); + } + else if (me_low->mat[i]) { + BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); + } + else { + /* if everything else fails, use the material index */ + char tmp[5]; + sprintf(tmp, "%d", i % 1000); + BLI_path_suffix(name, FILE_MAX, tmp, "_"); + } + } + } + + /* save it externally */ + ok = write_external_bake_pixels(name, + pixel_array_low + bk_image->offset, + result + bk_image->offset * depth, + bk_image->width, + bk_image->height, + margin, + &bake->im_format, + is_noncolor); + + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); + op_result = OPERATOR_CANCELLED; + } + else { + BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); + op_result = OPERATOR_FINISHED; + } + + if (!is_split_materials) { + break; + } + } + } + } + + if (is_save_internal) + refresh_images(&bake_images); cleanup: - if (highpoly) { - int i; - for (i = 0; i < tot_highpoly; i++) { - if (highpoly[i].me) - BKE_id_free(bmain, highpoly[i].me); - } - MEM_freeN(highpoly); - } + if (highpoly) { + int i; + for (i = 0; i < tot_highpoly; i++) { + if (highpoly[i].me) + BKE_id_free(bmain, highpoly[i].me); + } + MEM_freeN(highpoly); + } - if (mmd_low) - mmd_low->flags = mmd_flags_low; + if (mmd_low) + mmd_low->flags = mmd_flags_low; - if (pixel_array_low) - MEM_freeN(pixel_array_low); + if (pixel_array_low) + MEM_freeN(pixel_array_low); - if (pixel_array_high) - MEM_freeN(pixel_array_high); + if (pixel_array_high) + MEM_freeN(pixel_array_high); - if (bake_images.data) - MEM_freeN(bake_images.data); + if (bake_images.data) + MEM_freeN(bake_images.data); - if (bake_images.lookup) - MEM_freeN(bake_images.lookup); + if (bake_images.lookup) + MEM_freeN(bake_images.lookup); - if (result) - MEM_freeN(result); + if (result) + MEM_freeN(result); - if (me_low) - BKE_id_free(bmain, me_low); + if (me_low) + BKE_id_free(bmain, me_low); - if (me_cage) - BKE_id_free(bmain, me_cage); + if (me_cage) + BKE_id_free(bmain, me_cage); - DEG_graph_free(depsgraph); + DEG_graph_free(depsgraph); - return op_result; + return op_result; } static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) { - bool is_save_internal; - bScreen *sc = CTX_wm_screen(C); + bool is_save_internal; + bScreen *sc = CTX_wm_screen(C); - bkr->ob = CTX_data_active_object(C); - bkr->main = CTX_data_main(C); - bkr->view_layer = CTX_data_view_layer(C); - bkr->scene = CTX_data_scene(C); - bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; + bkr->ob = CTX_data_active_object(C); + bkr->main = CTX_data_main(C); + bkr->view_layer = CTX_data_view_layer(C); + bkr->scene = CTX_data_scene(C); + bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; - bkr->pass_type = RNA_enum_get(op->ptr, "type"); - bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter"); - bkr->margin = RNA_int_get(op->ptr, "margin"); + bkr->pass_type = RNA_enum_get(op->ptr, "type"); + bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter"); + bkr->margin = RNA_int_get(op->ptr, "margin"); - bkr->save_mode = RNA_enum_get(op->ptr, "save_mode"); - is_save_internal = (bkr->save_mode == R_BAKE_SAVE_INTERNAL); + bkr->save_mode = RNA_enum_get(op->ptr, "save_mode"); + is_save_internal = (bkr->save_mode == R_BAKE_SAVE_INTERNAL); - bkr->is_clear = RNA_boolean_get(op->ptr, "use_clear"); - bkr->is_split_materials = (!is_save_internal) && RNA_boolean_get(op->ptr, "use_split_materials"); - bkr->is_automatic_name = RNA_boolean_get(op->ptr, "use_automatic_name"); - bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active"); - bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage"); - bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion"); + bkr->is_clear = RNA_boolean_get(op->ptr, "use_clear"); + bkr->is_split_materials = (!is_save_internal) && RNA_boolean_get(op->ptr, "use_split_materials"); + bkr->is_automatic_name = RNA_boolean_get(op->ptr, "use_automatic_name"); + bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active"); + bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage"); + bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion"); - bkr->normal_space = RNA_enum_get(op->ptr, "normal_space"); - bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r"); - bkr->normal_swizzle[1] = RNA_enum_get(op->ptr, "normal_g"); - bkr->normal_swizzle[2] = RNA_enum_get(op->ptr, "normal_b"); + bkr->normal_space = RNA_enum_get(op->ptr, "normal_space"); + bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r"); + bkr->normal_swizzle[1] = RNA_enum_get(op->ptr, "normal_g"); + bkr->normal_swizzle[2] = RNA_enum_get(op->ptr, "normal_b"); - bkr->width = RNA_int_get(op->ptr, "width"); - bkr->height = RNA_int_get(op->ptr, "height"); - bkr->identifier = ""; + bkr->width = RNA_int_get(op->ptr, "width"); + bkr->height = RNA_int_get(op->ptr, "height"); + bkr->identifier = ""; - RNA_string_get(op->ptr, "uv_layer", bkr->uv_layer); + RNA_string_get(op->ptr, "uv_layer", bkr->uv_layer); - RNA_string_get(op->ptr, "cage_object", bkr->custom_cage); + RNA_string_get(op->ptr, "cage_object", bkr->custom_cage); - if ((!is_save_internal) && bkr->is_automatic_name) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); - RNA_property_enum_identifier(C, op->ptr, prop, bkr->pass_type, &bkr->identifier); - } + if ((!is_save_internal) && bkr->is_automatic_name) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); + RNA_property_enum_identifier(C, op->ptr, prop, bkr->pass_type, &bkr->identifier); + } - CTX_data_selected_objects(C, &bkr->selected_objects); + CTX_data_selected_objects(C, &bkr->selected_objects); - bkr->reports = op->reports; + bkr->reports = op->reports; - bkr->result = OPERATOR_CANCELLED; + bkr->result = OPERATOR_CANCELLED; - bkr->render = RE_NewSceneRender(bkr->scene); + bkr->render = RE_NewSceneRender(bkr->scene); - /* XXX hack to force saving to always be internal. Whether (and how) to support - * external saving will be addressed later */ - bkr->save_mode = R_BAKE_SAVE_INTERNAL; + /* XXX hack to force saving to always be internal. Whether (and how) to support + * external saving will be addressed later */ + bkr->save_mode = R_BAKE_SAVE_INTERNAL; } static int bake_exec(bContext *C, wmOperator *op) { - Render *re; - int result = OPERATOR_CANCELLED; - BakeAPIRender bkr = {NULL}; - Scene *scene = CTX_data_scene(C); - - G.is_break = false; - G.is_rendering = true; - - bake_set_props(op, scene); - - bake_init_api_data(op, C, &bkr); - re = bkr.render; - - /* setup new render */ - RE_test_break_cb(re, NULL, bake_break); - - if (!bake_pass_filter_check(bkr.pass_type, bkr.pass_filter, bkr.reports)) { - goto finally; - } - - if (!bake_objects_check(bkr.main, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { - goto finally; - } - - if (bkr.is_clear) { - const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT)); - bake_images_clear(bkr.main, is_tangent); - } - - RE_SetReports(re, bkr.reports); - - if (bkr.is_selected_to_active) { - result = bake( - bkr.render, bkr.main, bkr.scene, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, - bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode, - bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage, - bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, - bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa, - bkr.uv_layer); - } - else { - CollectionPointerLink *link; - const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects); - for (link = bkr.selected_objects.first; link; link = link->next) { - Object *ob_iter = link->ptr.data; - result = bake( - bkr.render, bkr.main, bkr.scene, bkr.view_layer, ob_iter, NULL, bkr.reports, - bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode, - is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage, - bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, - bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa, - bkr.uv_layer); - } - } - - RE_SetReports(re, NULL); - + Render *re; + int result = OPERATOR_CANCELLED; + BakeAPIRender bkr = {NULL}; + Scene *scene = CTX_data_scene(C); + + G.is_break = false; + G.is_rendering = true; + + bake_set_props(op, scene); + + bake_init_api_data(op, C, &bkr); + re = bkr.render; + + /* setup new render */ + RE_test_break_cb(re, NULL, bake_break); + + if (!bake_pass_filter_check(bkr.pass_type, bkr.pass_filter, bkr.reports)) { + goto finally; + } + + if (!bake_objects_check(bkr.main, + bkr.view_layer, + bkr.ob, + &bkr.selected_objects, + bkr.reports, + bkr.is_selected_to_active)) { + goto finally; + } + + if (bkr.is_clear) { + const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && + (bkr.normal_space == R_BAKE_SPACE_TANGENT)); + bake_images_clear(bkr.main, is_tangent); + } + + RE_SetReports(re, bkr.reports); + + if (bkr.is_selected_to_active) { + result = bake(bkr.render, + bkr.main, + bkr.scene, + bkr.view_layer, + bkr.ob, + &bkr.selected_objects, + bkr.reports, + bkr.pass_type, + bkr.pass_filter, + bkr.margin, + bkr.save_mode, + bkr.is_clear, + bkr.is_split_materials, + bkr.is_automatic_name, + true, + bkr.is_cage, + bkr.cage_extrusion, + bkr.normal_space, + bkr.normal_swizzle, + bkr.custom_cage, + bkr.filepath, + bkr.width, + bkr.height, + bkr.identifier, + bkr.sa, + bkr.uv_layer); + } + else { + CollectionPointerLink *link; + const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects); + for (link = bkr.selected_objects.first; link; link = link->next) { + Object *ob_iter = link->ptr.data; + result = bake(bkr.render, + bkr.main, + bkr.scene, + bkr.view_layer, + ob_iter, + NULL, + bkr.reports, + bkr.pass_type, + bkr.pass_filter, + bkr.margin, + bkr.save_mode, + is_clear, + bkr.is_split_materials, + bkr.is_automatic_name, + false, + bkr.is_cage, + bkr.cage_extrusion, + bkr.normal_space, + bkr.normal_swizzle, + bkr.custom_cage, + bkr.filepath, + bkr.width, + bkr.height, + bkr.identifier, + bkr.sa, + bkr.uv_layer); + } + } + + RE_SetReports(re, NULL); finally: - G.is_rendering = false; - BLI_freelistN(&bkr.selected_objects); - return result; + G.is_rendering = false; + BLI_freelistN(&bkr.selected_objects); + return result; } static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress) { - BakeAPIRender *bkr = (BakeAPIRender *)bkv; - - /* setup new render */ - bkr->do_update = do_update; - bkr->progress = progress; - - RE_SetReports(bkr->render, bkr->reports); - - if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) { - bkr->result = OPERATOR_CANCELLED; - return; - } - - if (!bake_objects_check(bkr->main, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { - bkr->result = OPERATOR_CANCELLED; - return; - } - - if (bkr->is_clear) { - const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT)); - bake_images_clear(bkr->main, is_tangent); - } - - if (bkr->is_selected_to_active) { - bkr->result = bake( - bkr->render, bkr->main, bkr->scene, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports, - bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, - bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage, - bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, - bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa, - bkr->uv_layer); - } - else { - CollectionPointerLink *link; - const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects); - for (link = bkr->selected_objects.first; link; link = link->next) { - Object *ob_iter = link->ptr.data; - bkr->result = bake( - bkr->render, bkr->main, bkr->scene, bkr->view_layer, ob_iter, NULL, bkr->reports, - bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode, - is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage, - bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, - bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa, - bkr->uv_layer); - - if (bkr->result == OPERATOR_CANCELLED) - return; - } - } - - RE_SetReports(bkr->render, NULL); + BakeAPIRender *bkr = (BakeAPIRender *)bkv; + + /* setup new render */ + bkr->do_update = do_update; + bkr->progress = progress; + + RE_SetReports(bkr->render, bkr->reports); + + if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) { + bkr->result = OPERATOR_CANCELLED; + return; + } + + if (!bake_objects_check(bkr->main, + bkr->view_layer, + bkr->ob, + &bkr->selected_objects, + bkr->reports, + bkr->is_selected_to_active)) { + bkr->result = OPERATOR_CANCELLED; + return; + } + + if (bkr->is_clear) { + const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && + (bkr->normal_space == R_BAKE_SPACE_TANGENT)); + bake_images_clear(bkr->main, is_tangent); + } + + if (bkr->is_selected_to_active) { + bkr->result = bake(bkr->render, + bkr->main, + bkr->scene, + bkr->view_layer, + bkr->ob, + &bkr->selected_objects, + bkr->reports, + bkr->pass_type, + bkr->pass_filter, + bkr->margin, + bkr->save_mode, + bkr->is_clear, + bkr->is_split_materials, + bkr->is_automatic_name, + true, + bkr->is_cage, + bkr->cage_extrusion, + bkr->normal_space, + bkr->normal_swizzle, + bkr->custom_cage, + bkr->filepath, + bkr->width, + bkr->height, + bkr->identifier, + bkr->sa, + bkr->uv_layer); + } + else { + CollectionPointerLink *link; + const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects); + for (link = bkr->selected_objects.first; link; link = link->next) { + Object *ob_iter = link->ptr.data; + bkr->result = bake(bkr->render, + bkr->main, + bkr->scene, + bkr->view_layer, + ob_iter, + NULL, + bkr->reports, + bkr->pass_type, + bkr->pass_filter, + bkr->margin, + bkr->save_mode, + is_clear, + bkr->is_split_materials, + bkr->is_automatic_name, + false, + bkr->is_cage, + bkr->cage_extrusion, + bkr->normal_space, + bkr->normal_swizzle, + bkr->custom_cage, + bkr->filepath, + bkr->width, + bkr->height, + bkr->identifier, + bkr->sa, + bkr->uv_layer); + + if (bkr->result == OPERATOR_CANCELLED) + return; + } + } + + RE_SetReports(bkr->render, NULL); } static void bake_freejob(void *bkv) { - BakeAPIRender *bkr = (BakeAPIRender *)bkv; + BakeAPIRender *bkr = (BakeAPIRender *)bkv; - BLI_freelistN(&bkr->selected_objects); - MEM_freeN(bkr); + BLI_freelistN(&bkr->selected_objects); + MEM_freeN(bkr); - G.is_rendering = false; + G.is_rendering = false; } static void bake_set_props(wmOperator *op, Scene *scene) { - PropertyRNA *prop; - BakeData *bake = &scene->r.bake; - - prop = RNA_struct_find_property(op->ptr, "filepath"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_string_set(op->ptr, prop, bake->filepath); - } - - prop = RNA_struct_find_property(op->ptr, "width"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_int_set(op->ptr, prop, bake->width); - } - - prop = RNA_struct_find_property(op->ptr, "height"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_int_set(op->ptr, prop, bake->width); - } - - prop = RNA_struct_find_property(op->ptr, "margin"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_int_set(op->ptr, prop, bake->margin); - } - - prop = RNA_struct_find_property(op->ptr, "use_selected_to_active"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); - } - - prop = RNA_struct_find_property(op->ptr, "cage_extrusion"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_float_set(op->ptr, prop, bake->cage_extrusion); - } - - prop = RNA_struct_find_property(op->ptr, "cage_object"); - if (!RNA_property_is_set(op->ptr, prop)) { - if (bake->cage_object) { - RNA_property_string_set(op->ptr, prop, bake->cage_object->id.name + 2); - } - } - - prop = RNA_struct_find_property(op->ptr, "normal_space"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->normal_space); - } - - prop = RNA_struct_find_property(op->ptr, "normal_r"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[0]); - } - - prop = RNA_struct_find_property(op->ptr, "normal_g"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[1]); - } - - prop = RNA_struct_find_property(op->ptr, "normal_b"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[2]); - } - - prop = RNA_struct_find_property(op->ptr, "save_mode"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->save_mode); - } - - prop = RNA_struct_find_property(op->ptr, "use_clear"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR) != 0); - } - - prop = RNA_struct_find_property(op->ptr, "use_cage"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE) != 0); - } - - prop = RNA_struct_find_property(op->ptr, "use_split_materials"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT) != 0); - } - - prop = RNA_struct_find_property(op->ptr, "use_automatic_name"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME) != 0); - } - - prop = RNA_struct_find_property(op->ptr, "pass_filter"); - if (!RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(op->ptr, prop, bake->pass_filter); - } + PropertyRNA *prop; + BakeData *bake = &scene->r.bake; + + prop = RNA_struct_find_property(op->ptr, "filepath"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_string_set(op->ptr, prop, bake->filepath); + } + + prop = RNA_struct_find_property(op->ptr, "width"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_int_set(op->ptr, prop, bake->width); + } + + prop = RNA_struct_find_property(op->ptr, "height"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_int_set(op->ptr, prop, bake->width); + } + + prop = RNA_struct_find_property(op->ptr, "margin"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_int_set(op->ptr, prop, bake->margin); + } + + prop = RNA_struct_find_property(op->ptr, "use_selected_to_active"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); + } + + prop = RNA_struct_find_property(op->ptr, "cage_extrusion"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, bake->cage_extrusion); + } + + prop = RNA_struct_find_property(op->ptr, "cage_object"); + if (!RNA_property_is_set(op->ptr, prop)) { + if (bake->cage_object) { + RNA_property_string_set(op->ptr, prop, bake->cage_object->id.name + 2); + } + } + + prop = RNA_struct_find_property(op->ptr, "normal_space"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->normal_space); + } + + prop = RNA_struct_find_property(op->ptr, "normal_r"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[0]); + } + + prop = RNA_struct_find_property(op->ptr, "normal_g"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[1]); + } + + prop = RNA_struct_find_property(op->ptr, "normal_b"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[2]); + } + + prop = RNA_struct_find_property(op->ptr, "save_mode"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->save_mode); + } + + prop = RNA_struct_find_property(op->ptr, "use_clear"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR) != 0); + } + + prop = RNA_struct_find_property(op->ptr, "use_cage"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE) != 0); + } + + prop = RNA_struct_find_property(op->ptr, "use_split_materials"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT) != 0); + } + + prop = RNA_struct_find_property(op->ptr, "use_automatic_name"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME) != 0); + } + + prop = RNA_struct_find_property(op->ptr, "pass_filter"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->pass_filter); + } } static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - wmJob *wm_job; - BakeAPIRender *bkr; - Render *re; - Scene *scene = CTX_data_scene(C); + wmJob *wm_job; + BakeAPIRender *bkr; + Render *re; + Scene *scene = CTX_data_scene(C); - bake_set_props(op, scene); + bake_set_props(op, scene); - /* only one render job at a time */ - if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE)) - return OPERATOR_CANCELLED; + /* only one render job at a time */ + if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE)) + return OPERATOR_CANCELLED; - bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake"); + bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake"); - /* init bake render */ - bake_init_api_data(op, C, bkr); - re = bkr->render; + /* init bake render */ + bake_init_api_data(op, C, bkr); + re = bkr->render; - /* setup new render */ - RE_test_break_cb(re, NULL, bake_break); - RE_progress_cb(re, bkr, bake_progress_update); + /* setup new render */ + RE_test_break_cb(re, NULL, bake_break); + RE_progress_cb(re, bkr, bake_progress_update); - /* setup job */ - wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake", - WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_BAKE); - WM_jobs_customdata_set(wm_job, bkr, bake_freejob); - WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ - WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL); + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Texture Bake", + WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_BAKE); + WM_jobs_customdata_set(wm_job, bkr, bake_freejob); + WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ + WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL); - G.is_break = false; - G.is_rendering = true; + G.is_break = false; + G.is_rendering = true; - WM_jobs_start(CTX_wm_manager(C), wm_job); + WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(0); - /* add modal handler for ESC */ - WM_event_add_modal_handler(C, op); + /* add modal handler for ESC */ + WM_event_add_modal_handler(C, op); - WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); - return OPERATOR_RUNNING_MODAL; + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); + return OPERATOR_RUNNING_MODAL; } void OBJECT_OT_bake(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Bake"; - ot->description = "Bake image textures of selected objects"; - ot->idname = "OBJECT_OT_bake"; - - /* api callbacks */ - ot->exec = bake_exec; - ot->modal = bake_modal; - ot->invoke = bake_invoke; - ot->poll = ED_operator_object_active_editable_mesh; - - RNA_def_enum(ot->srna, "type", rna_enum_bake_pass_type_items, SCE_PASS_COMBINED, "Type", - "Type of pass to bake, some of them may not be supported by the current render engine"); - prop = RNA_def_enum(ot->srna, "pass_filter", rna_enum_bake_pass_filter_type_items, R_BAKE_PASS_FILTER_NONE, "Pass Filter", - "Filter to combined, diffuse, glossy, transmission and subsurface passes"); - RNA_def_property_flag(prop, PROP_ENUM_FLAG); - RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", - "Image filepath to use when saving externally"); - RNA_def_int(ot->srna, "width", 512, 1, INT_MAX, "Width", - "Horizontal dimension of the baking map (external only)", 64, 4096); - RNA_def_int(ot->srna, "height", 512, 1, INT_MAX, "Height", - "Vertical dimension of the baking map (external only)", 64, 4096); - RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", - "Extends the baked result as a post process filter", 0, 64); - RNA_def_boolean(ot->srna, "use_selected_to_active", false, "Selected to Active", - "Bake shading on the surface of selected objects to the active object"); - RNA_def_float(ot->srna, "cage_extrusion", 0.0f, 0.0f, FLT_MAX, "Cage Extrusion", - "Distance to use for the inward ray cast when using selected to active", 0.0f, 1.0f); - RNA_def_string(ot->srna, "cage_object", NULL, MAX_NAME, "Cage Object", - "Object to use as cage, instead of calculating the cage from the active object with cage extrusion"); - RNA_def_enum(ot->srna, "normal_space", rna_enum_normal_space_items, R_BAKE_SPACE_TANGENT, "Normal Space", - "Choose normal space for baking"); - RNA_def_enum(ot->srna, "normal_r", rna_enum_normal_swizzle_items, R_BAKE_POSX, "R", "Axis to bake in red channel"); - RNA_def_enum(ot->srna, "normal_g", rna_enum_normal_swizzle_items, R_BAKE_POSY, "G", "Axis to bake in green channel"); - RNA_def_enum(ot->srna, "normal_b", rna_enum_normal_swizzle_items, R_BAKE_POSZ, "B", "Axis to bake in blue channel"); - RNA_def_enum(ot->srna, "save_mode", rna_enum_bake_save_mode_items, R_BAKE_SAVE_INTERNAL, "Save Mode", - "Choose how to save the baking map"); - RNA_def_boolean(ot->srna, "use_clear", false, "Clear", - "Clear Images before baking (only for internal saving)"); - RNA_def_boolean(ot->srna, "use_cage", false, "Cage", - "Cast rays to active object from a cage"); - RNA_def_boolean(ot->srna, "use_split_materials", false, "Split Materials", - "Split baked maps per material, using material name in output file (external only)"); - RNA_def_boolean(ot->srna, "use_automatic_name", false, "Automatic Name", - "Automatically name the output file with the pass type"); - RNA_def_string(ot->srna, "uv_layer", NULL, MAX_CUSTOMDATA_LAYER_NAME, "UV Layer", "UV layer to override active"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bake"; + ot->description = "Bake image textures of selected objects"; + ot->idname = "OBJECT_OT_bake"; + + /* api callbacks */ + ot->exec = bake_exec; + ot->modal = bake_modal; + ot->invoke = bake_invoke; + ot->poll = ED_operator_object_active_editable_mesh; + + RNA_def_enum( + ot->srna, + "type", + rna_enum_bake_pass_type_items, + SCE_PASS_COMBINED, + "Type", + "Type of pass to bake, some of them may not be supported by the current render engine"); + prop = RNA_def_enum(ot->srna, + "pass_filter", + rna_enum_bake_pass_filter_type_items, + R_BAKE_PASS_FILTER_NONE, + "Pass Filter", + "Filter to combined, diffuse, glossy, transmission and subsurface passes"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_string_file_path(ot->srna, + "filepath", + NULL, + FILE_MAX, + "File Path", + "Image filepath to use when saving externally"); + RNA_def_int(ot->srna, + "width", + 512, + 1, + INT_MAX, + "Width", + "Horizontal dimension of the baking map (external only)", + 64, + 4096); + RNA_def_int(ot->srna, + "height", + 512, + 1, + INT_MAX, + "Height", + "Vertical dimension of the baking map (external only)", + 64, + 4096); + RNA_def_int(ot->srna, + "margin", + 16, + 0, + INT_MAX, + "Margin", + "Extends the baked result as a post process filter", + 0, + 64); + RNA_def_boolean(ot->srna, + "use_selected_to_active", + false, + "Selected to Active", + "Bake shading on the surface of selected objects to the active object"); + RNA_def_float(ot->srna, + "cage_extrusion", + 0.0f, + 0.0f, + FLT_MAX, + "Cage Extrusion", + "Distance to use for the inward ray cast when using selected to active", + 0.0f, + 1.0f); + RNA_def_string(ot->srna, + "cage_object", + NULL, + MAX_NAME, + "Cage Object", + "Object to use as cage, instead of calculating the cage from the active object " + "with cage extrusion"); + RNA_def_enum(ot->srna, + "normal_space", + rna_enum_normal_space_items, + R_BAKE_SPACE_TANGENT, + "Normal Space", + "Choose normal space for baking"); + RNA_def_enum(ot->srna, + "normal_r", + rna_enum_normal_swizzle_items, + R_BAKE_POSX, + "R", + "Axis to bake in red channel"); + RNA_def_enum(ot->srna, + "normal_g", + rna_enum_normal_swizzle_items, + R_BAKE_POSY, + "G", + "Axis to bake in green channel"); + RNA_def_enum(ot->srna, + "normal_b", + rna_enum_normal_swizzle_items, + R_BAKE_POSZ, + "B", + "Axis to bake in blue channel"); + RNA_def_enum(ot->srna, + "save_mode", + rna_enum_bake_save_mode_items, + R_BAKE_SAVE_INTERNAL, + "Save Mode", + "Choose how to save the baking map"); + RNA_def_boolean(ot->srna, + "use_clear", + false, + "Clear", + "Clear Images before baking (only for internal saving)"); + RNA_def_boolean(ot->srna, "use_cage", false, "Cage", "Cast rays to active object from a cage"); + RNA_def_boolean( + ot->srna, + "use_split_materials", + false, + "Split Materials", + "Split baked maps per material, using material name in output file (external only)"); + RNA_def_boolean(ot->srna, + "use_automatic_name", + false, + "Automatic Name", + "Automatically name the output file with the pass type"); + RNA_def_string(ot->srna, + "uv_layer", + NULL, + MAX_CUSTOMDATA_LAYER_NAME, + "UV Layer", + "UV layer to override active"); } diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c index e8552c823bf..0b22dec99c7 100644 --- a/source/blender/editors/object/object_collection.c +++ b/source/blender/editors/object/object_collection.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <string.h> #include "BLI_blenlib.h" @@ -56,546 +55,566 @@ /********************* 3d view operators ***********************/ /* can be called with C == NULL */ -static const EnumPropertyItem *collection_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *collection_object_active_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob; - EnumPropertyItem *item = NULL, item_tmp = {0}; - int totitem = 0; - - if (C == NULL) { - return DummyRNA_NULL_items; - } - - ob = ED_object_context(C); - - /* check that the object exists */ - if (ob) { - Collection *collection; - int i = 0, count = 0; - - /* if 2 or more collections, add option to add to all collections */ - collection = NULL; - while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) - count++; - - if (count >= 2) { - item_tmp.identifier = item_tmp.name = "All Collections"; - item_tmp.value = INT_MAX; /* this will give NULL on lookup */ - RNA_enum_item_add(&item, &totitem, &item_tmp); - RNA_enum_item_add_separator(&item, &totitem); - } - - /* add collections */ - collection = NULL; - while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) { - item_tmp.identifier = item_tmp.name = collection->id.name + 2; - /* item_tmp.icon = ICON_ARMATURE_DATA; */ - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - i++; - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob; + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + + if (C == NULL) { + return DummyRNA_NULL_items; + } + + ob = ED_object_context(C); + + /* check that the object exists */ + if (ob) { + Collection *collection; + int i = 0, count = 0; + + /* if 2 or more collections, add option to add to all collections */ + collection = NULL; + while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) + count++; + + if (count >= 2) { + item_tmp.identifier = item_tmp.name = "All Collections"; + item_tmp.value = INT_MAX; /* this will give NULL on lookup */ + RNA_enum_item_add(&item, &totitem, &item_tmp); + RNA_enum_item_add_separator(&item, &totitem); + } + + /* add collections */ + collection = NULL; + while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) { + item_tmp.identifier = item_tmp.name = collection->id.name + 2; + /* item_tmp.icon = ICON_ARMATURE_DATA; */ + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + i++; + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } /* get the collection back from the enum index, quite awkward and UI specific */ -static Collection *collection_object_active_find_index(Main *bmain, Scene *scene, Object *ob, const int collection_object_index) +static Collection *collection_object_active_find_index(Main *bmain, + Scene *scene, + Object *ob, + const int collection_object_index) { - Collection *collection = NULL; - int i = 0; - while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) { - if (i == collection_object_index) { - break; - } - i++; - } - - return collection; + Collection *collection = NULL; + int i = 0; + while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) { + if (i == collection_object_index) { + break; + } + i++; + } + + return collection; } static int objects_add_active_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int single_collection_index = RNA_enum_get(op->ptr, "collection"); - Collection *single_collection = collection_object_active_find_index(bmain, scene, ob, single_collection_index); - bool is_cycle = false; - bool updated = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - /* now add all selected objects to the collection(s) */ - FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) - { - if (single_collection && collection != single_collection) - continue; - if (!BKE_collection_has_object(collection, ob)) - continue; - - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - if (BKE_collection_has_object(collection, base->object)) - continue; - - if (!BKE_collection_object_cyclic_check(bmain, base->object, collection)) { - BKE_collection_object_add(bmain, collection, base->object); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - updated = true; - } - else { - is_cycle = true; - } - } - CTX_DATA_END; - } - FOREACH_COLLECTION_END; - - if (is_cycle) - BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); - - if (!updated) - return OPERATOR_CANCELLED; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index( + bmain, scene, ob, single_collection_index); + bool is_cycle = false; + bool updated = false; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + /* now add all selected objects to the collection(s) */ + FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) + { + if (single_collection && collection != single_collection) + continue; + if (!BKE_collection_has_object(collection, ob)) + continue; + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + if (BKE_collection_has_object(collection, base->object)) + continue; + + if (!BKE_collection_object_cyclic_check(bmain, base->object, collection)) { + BKE_collection_object_add(bmain, collection, base->object); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + updated = true; + } + else { + is_cycle = true; + } + } + CTX_DATA_END; + } + FOREACH_COLLECTION_END; + + if (is_cycle) + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); + + if (!updated) + return OPERATOR_CANCELLED; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } void COLLECTION_OT_objects_add_active(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Add Selected To Active Collection"; - ot->description = "Add the object to an object collection that contains the active object"; - ot->idname = "COLLECTION_OT_objects_add_active"; - - /* api callbacks */ - ot->exec = objects_add_active_exec; - ot->invoke = WM_menu_invoke; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to add other selected objects to"); - RNA_def_enum_funcs(prop, collection_object_active_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Add Selected To Active Collection"; + ot->description = "Add the object to an object collection that contains the active object"; + ot->idname = "COLLECTION_OT_objects_add_active"; + + /* api callbacks */ + ot->exec = objects_add_active_exec; + ot->invoke = WM_menu_invoke; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, + "collection", + DummyRNA_NULL_items, + 0, + "Collection", + "The collection to add other selected objects to"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static int objects_remove_active_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - int single_collection_index = RNA_enum_get(op->ptr, "collection"); - Collection *single_collection = collection_object_active_find_index(bmain, scene, ob, single_collection_index); - bool ok = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - /* Linking to same collection requires its own loop so we can avoid - * looking up the active objects collections each time. */ - FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) - { - if (single_collection && collection != single_collection) - continue; - - if (BKE_collection_has_object(collection, ob)) { - /* Remove collections from selected objects */ - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - BKE_collection_object_remove(bmain, collection, base->object, false); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - ok = 1; - } - CTX_DATA_END; - } - } - FOREACH_COLLECTION_END; - - if (!ok) - BKE_report(op->reports, RPT_ERROR, "Active object contains no collections"); - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index( + bmain, scene, ob, single_collection_index); + bool ok = false; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + /* Linking to same collection requires its own loop so we can avoid + * looking up the active objects collections each time. */ + FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) + { + if (single_collection && collection != single_collection) + continue; + + if (BKE_collection_has_object(collection, ob)) { + /* Remove collections from selected objects */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + BKE_collection_object_remove(bmain, collection, base->object, false); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + ok = 1; + } + CTX_DATA_END; + } + } + FOREACH_COLLECTION_END; + + if (!ok) + BKE_report(op->reports, RPT_ERROR, "Active object contains no collections"); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } void COLLECTION_OT_objects_remove_active(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Remove Selected From Active Collection"; - ot->description = "Remove the object from an object collection that contains the active object"; - ot->idname = "COLLECTION_OT_objects_remove_active"; - - /* api callbacks */ - ot->exec = objects_remove_active_exec; - ot->invoke = WM_menu_invoke; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove other selected objects from"); - RNA_def_enum_funcs(prop, collection_object_active_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Remove Selected From Active Collection"; + ot->description = "Remove the object from an object collection that contains the active object"; + ot->idname = "COLLECTION_OT_objects_remove_active"; + + /* api callbacks */ + ot->exec = objects_remove_active_exec; + ot->invoke = WM_menu_invoke; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, + "collection", + DummyRNA_NULL_items, + 0, + "Collection", + "The collection to remove other selected objects from"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - BKE_object_groups_clear(bmain, scene, base->object); - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + BKE_object_groups_clear(bmain, scene, base->object); + } + CTX_DATA_END; - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void COLLECTION_OT_objects_remove_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove From All Unlinked Collections"; - ot->description = "Remove selected objects from all collections not used in a scene"; - ot->idname = "COLLECTION_OT_objects_remove_all"; + /* identifiers */ + ot->name = "Remove From All Unlinked Collections"; + ot->description = "Remove selected objects from all collections not used in a scene"; + ot->idname = "COLLECTION_OT_objects_remove_all"; - /* api callbacks */ - ot->exec = collection_objects_remove_all_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = collection_objects_remove_all_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int collection_objects_remove_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int single_collection_index = RNA_enum_get(op->ptr, "collection"); - Collection *single_collection = collection_object_active_find_index(bmain, scene, ob, single_collection_index); - bool updated = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) - { - if (single_collection && collection != single_collection) - continue; - if (!BKE_collection_has_object(collection, ob)) - continue; - - /* now remove all selected objects from the collection */ - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - BKE_collection_object_remove(bmain, collection, base->object, false); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - updated = true; - } - CTX_DATA_END; - } - FOREACH_COLLECTION_END; - - if (!updated) - return OPERATOR_CANCELLED; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index( + bmain, scene, ob, single_collection_index); + bool updated = false; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + FOREACH_COLLECTION_BEGIN(bmain, scene, Collection *, collection) + { + if (single_collection && collection != single_collection) + continue; + if (!BKE_collection_has_object(collection, ob)) + continue; + + /* now remove all selected objects from the collection */ + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { + BKE_collection_object_remove(bmain, collection, base->object, false); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + updated = true; + } + CTX_DATA_END; + } + FOREACH_COLLECTION_END; + + if (!updated) + return OPERATOR_CANCELLED; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } void COLLECTION_OT_objects_remove(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Remove From Collection"; - ot->description = "Remove selected objects from a collection"; - ot->idname = "COLLECTION_OT_objects_remove"; - - /* api callbacks */ - ot->exec = collection_objects_remove_exec; - ot->invoke = WM_menu_invoke; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove this object from"); - RNA_def_enum_funcs(prop, collection_object_active_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Remove From Collection"; + ot->description = "Remove selected objects from a collection"; + ot->idname = "COLLECTION_OT_objects_remove"; + + /* api callbacks */ + ot->exec = collection_objects_remove_exec; + ot->invoke = WM_menu_invoke; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, + "collection", + DummyRNA_NULL_items, + 0, + "Collection", + "The collection to remove this object from"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static int collection_create_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - char name[MAX_ID_NAME - 2]; /* id name */ + Main *bmain = CTX_data_main(C); + char name[MAX_ID_NAME - 2]; /* id name */ - RNA_string_get(op->ptr, "name", name); + RNA_string_get(op->ptr, "name", name); - Collection *collection = BKE_collection_add(bmain, NULL, name); - id_fake_user_set(&collection->id); + Collection *collection = BKE_collection_add(bmain, NULL, name); + id_fake_user_set(&collection->id); - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - BKE_collection_object_add(bmain, collection, base->object); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { + BKE_collection_object_add(bmain, collection, base->object); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + } + CTX_DATA_END; - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void COLLECTION_OT_create(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Create New Collection"; - ot->description = "Create an object collection from selected objects"; - ot->idname = "COLLECTION_OT_create"; + /* identifiers */ + ot->name = "Create New Collection"; + ot->description = "Create an object collection from selected objects"; + ot->idname = "COLLECTION_OT_create"; - /* api callbacks */ - ot->exec = collection_create_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = collection_create_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Name of the new collection"); + RNA_def_string( + ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Name of the new collection"); } /****************** properties window operators *********************/ static int collection_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); + Object *ob = ED_object_context(C); + Main *bmain = CTX_data_main(C); - if (ob == NULL) - return OPERATOR_CANCELLED; + if (ob == NULL) + return OPERATOR_CANCELLED; - Collection *collection = BKE_collection_add(bmain, NULL, "Collection"); - id_fake_user_set(&collection->id); - BKE_collection_object_add(bmain, collection, ob); + Collection *collection = BKE_collection_add(bmain, NULL, "Collection"); + id_fake_user_set(&collection->id); + BKE_collection_object_add(bmain, collection, ob); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_collection_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add to Collection"; - ot->idname = "OBJECT_OT_collection_add"; - ot->description = "Add an object to a new collection"; + /* identifiers */ + ot->name = "Add to Collection"; + ot->idname = "OBJECT_OT_collection_add"; + ot->description = "Add an object to a new collection"; - /* api callbacks */ - ot->exec = collection_add_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = collection_add_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int collection_link_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_context(C); - Collection *collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); - - if (ELEM(NULL, ob, collection)) - return OPERATOR_CANCELLED; - - /* Early return check, if the object is already in collection - * we could skip all the dependency check and just consider - * operator is finished. - */ - if (BKE_collection_has_object(collection, ob)) { - return OPERATOR_FINISHED; - } - - /* Adding object to collection which is used as duplicollection for self is bad idea. - * - * It is also bad idea to add object to collection which is in collection which - * contains our current object. - */ - if (BKE_collection_object_cyclic_check(bmain, ob, collection)) { - BKE_report(op->reports, RPT_ERROR, "Could not add the collection because of dependency cycle detected"); - return OPERATOR_CANCELLED; - } - - BKE_collection_object_add(bmain, collection, ob); - - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_context(C); + Collection *collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); + + if (ELEM(NULL, ob, collection)) + return OPERATOR_CANCELLED; + + /* Early return check, if the object is already in collection + * we could skip all the dependency check and just consider + * operator is finished. + */ + if (BKE_collection_has_object(collection, ob)) { + return OPERATOR_FINISHED; + } + + /* Adding object to collection which is used as duplicollection for self is bad idea. + * + * It is also bad idea to add object to collection which is in collection which + * contains our current object. + */ + if (BKE_collection_object_cyclic_check(bmain, ob, collection)) { + BKE_report(op->reports, + RPT_ERROR, + "Could not add the collection because of dependency cycle detected"); + return OPERATOR_CANCELLED; + } + + BKE_collection_object_add(bmain, collection, ob); + + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; } void OBJECT_OT_collection_link(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Link to Collection"; - ot->idname = "OBJECT_OT_collection_link"; - ot->description = "Add an object to an existing collection"; - - /* api callbacks */ - ot->exec = collection_link_exec; - ot->invoke = WM_enum_search_invoke; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); - RNA_def_enum_funcs(prop, RNA_collection_local_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Link to Collection"; + ot->idname = "OBJECT_OT_collection_link"; + ot->description = "Add an object to an existing collection"; + + /* api callbacks */ + ot->exec = collection_link_exec; + ot->invoke = WM_enum_search_invoke; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); + RNA_def_enum_funcs(prop, RNA_collection_local_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_context(C); - Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_context(C); + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - if (!ob || !collection) - return OPERATOR_CANCELLED; + if (!ob || !collection) + return OPERATOR_CANCELLED; - BKE_collection_object_remove(bmain, collection, ob, false); + BKE_collection_object_remove(bmain, collection, ob, false); - DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_collection_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Collection"; - ot->idname = "OBJECT_OT_collection_remove"; - ot->description = "Remove the active object from this collection"; + /* identifiers */ + ot->name = "Remove Collection"; + ot->idname = "OBJECT_OT_collection_remove"; + ot->description = "Remove the active object from this collection"; - /* api callbacks */ - ot->exec = collection_remove_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = collection_remove_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; + Main *bmain = CTX_data_main(C); + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - if (!collection) - return OPERATOR_CANCELLED; + if (!collection) + return OPERATOR_CANCELLED; - BKE_id_delete(bmain, collection); + BKE_id_delete(bmain, collection); - DEG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_collection_unlink(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Unlink Collection"; - ot->idname = "OBJECT_OT_collection_unlink"; - ot->description = "Unlink the collection from all objects"; + /* identifiers */ + ot->name = "Unlink Collection"; + ot->idname = "OBJECT_OT_collection_unlink"; + ot->description = "Unlink the collection from all objects"; - /* api callbacks */ - ot->exec = collection_unlink_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = collection_unlink_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* Select objects in the same collection as the active */ static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - - if (!collection) - return OPERATOR_CANCELLED; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (BKE_collection_has_object_recursive(collection, base->object)) { - ED_object_base_select(base, BA_SELECT); - } - } - } - CTX_DATA_END; - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; + + if (!collection) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (BKE_collection_has_object_recursive(collection, base->object)) { + ED_object_base_select(base, BA_SELECT); + } + } + } + CTX_DATA_END; + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } void OBJECT_OT_collection_objects_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Objects in Collection"; - ot->idname = "OBJECT_OT_collection_objects_select"; - ot->description = "Select all objects in collection"; + /* identifiers */ + ot->name = "Select Objects in Collection"; + ot->idname = "OBJECT_OT_collection_objects_select"; + ot->description = "Select all objects in collection"; - /* api callbacks */ - ot->exec = select_grouped_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = select_grouped_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 988d9373766..c571fc6821e 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdio.h> #include <string.h> @@ -56,7 +55,7 @@ #include "DEG_depsgraph_build.h" #ifdef WITH_PYTHON -#include "BPY_extern.h" +# include "BPY_extern.h" #endif #include "WM_api.h" @@ -80,63 +79,63 @@ /* if object in posemode, active bone constraints, else object constraints */ ListBase *get_active_constraints(Object *ob) { - if (ob == NULL) - return NULL; + if (ob == NULL) + return NULL; - if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan; + if (ob->mode & OB_MODE_POSE) { + bPoseChannel *pchan; - pchan = BKE_pose_channel_active(ob); - if (pchan) - return &pchan->constraints; - } - else - return &ob->constraints; + pchan = BKE_pose_channel_active(ob); + if (pchan) + return &pchan->constraints; + } + else + return &ob->constraints; - return NULL; + return NULL; } /* Find the list that a given constraint belongs to, * and/or also get the posechannel this is from (if applicable) */ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan) { - if (r_pchan) - *r_pchan = NULL; + if (r_pchan) + *r_pchan = NULL; - if (ELEM(NULL, ob, con)) - return NULL; + if (ELEM(NULL, ob, con)) + return NULL; - /* try object constraints first */ - if ((BLI_findindex(&ob->constraints, con) != -1)) { - return &ob->constraints; - } + /* try object constraints first */ + if ((BLI_findindex(&ob->constraints, con) != -1)) { + return &ob->constraints; + } - /* if armature, try pose bones too */ - if (ob->pose) { - bPoseChannel *pchan; + /* if armature, try pose bones too */ + if (ob->pose) { + bPoseChannel *pchan; - /* try each bone in order - * NOTE: it's not possible to directly look up the active bone yet, so this will have to do - */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((BLI_findindex(&pchan->constraints, con) != -1)) { + /* try each bone in order + * NOTE: it's not possible to directly look up the active bone yet, so this will have to do + */ + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((BLI_findindex(&pchan->constraints, con) != -1)) { - if (r_pchan) - *r_pchan = pchan; + if (r_pchan) + *r_pchan = pchan; - return &pchan->constraints; - } - } - } + return &pchan->constraints; + } + } + } - /* done */ - return NULL; + /* done */ + return NULL; } /* single constraint */ bConstraint *get_active_constraint(Object *ob) { - return BKE_constraints_active_get(get_active_constraints(ob)); + return BKE_constraints_active_get(get_active_constraints(ob)); } /* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */ @@ -146,367 +145,377 @@ bConstraint *get_active_constraint(Object *ob) /* this callback sets the text-file to be used for selected menu item */ static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2) { - bPythonConstraint *data = arg1; - Text *text = NULL; - int index = *((int *)arg2); - int i; + bPythonConstraint *data = arg1; + Text *text = NULL; + int index = *((int *)arg2); + int i; - /* exception for no script */ - if (index) { - /* innovative use of a for...loop to search */ - for (text = bmain->texts.first, i = 1; text && index != i; i++, text = text->id.next) ; - } - data->text = text; + /* exception for no script */ + if (index) { + /* innovative use of a for...loop to search */ + for (text = bmain->texts.first, i = 1; text && index != i; i++, text = text->id.next) + ; + } + data->text = text; } /* this returns a string for the list of usable pyconstraint script names */ static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconindex) { - DynStr *pupds = BLI_dynstr_new(); - Text *text; - char *str; - char buf[64]; - int i; + DynStr *pupds = BLI_dynstr_new(); + Text *text; + char *str; + char buf[64]; + int i; - /* add title first */ - sprintf(buf, "Scripts: %%t|[None]%%x0|"); - BLI_dynstr_append(pupds, buf); + /* add title first */ + sprintf(buf, "Scripts: %%t|[None]%%x0|"); + BLI_dynstr_append(pupds, buf); - /* init active-index first */ - if (con_text == NULL) - *pyconindex = 0; + /* init active-index first */ + if (con_text == NULL) + *pyconindex = 0; - /* loop through markers, adding them */ - for (text = bmain->texts.first, i = 1; text; i++, text = text->id.next) { - /* this is important to ensure that right script is shown as active */ - if (text == con_text) *pyconindex = i; + /* loop through markers, adding them */ + for (text = bmain->texts.first, i = 1; text; i++, text = text->id.next) { + /* this is important to ensure that right script is shown as active */ + if (text == con_text) + *pyconindex = i; - /* only include valid pyconstraint scripts */ - if (BPY_is_pyconstraint(text)) { - BLI_dynstr_append(pupds, text->id.name + 2); + /* only include valid pyconstraint scripts */ + if (BPY_is_pyconstraint(text)) { + BLI_dynstr_append(pupds, text->id.name + 2); - sprintf(buf, "%%x%d", i); - BLI_dynstr_append(pupds, buf); + sprintf(buf, "%%x%d", i); + BLI_dynstr_append(pupds, buf); - if (text->id.next) - BLI_dynstr_append(pupds, "|"); - } - } + if (text->id.next) + BLI_dynstr_append(pupds, "|"); + } + } - /* convert to normal MEM_malloc'd string */ - str = BLI_dynstr_get_cstring(pupds); - BLI_dynstr_free(pupds); + /* convert to normal MEM_malloc'd string */ + str = BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); - return str; + return str; } #endif /* WITH_PYTHON */ -#if 0 // UNUSED, until pyconstraints are added back. +#if 0 // UNUSED, until pyconstraints are added back. /* this callback gets called when the 'refresh' button of a pyconstraint gets pressed */ static void update_pyconstraint_cb(void *arg1, void *arg2) { -#ifndef WITH_PYTHON - (void)arg1; /* unused */ - (void)arg2; /* unused */ -#else - Object *owner = (Object *)arg1; - bConstraint *con = (bConstraint *)arg2; - if (owner && con) - BPY_pyconstraint_update(owner, con); -#endif +# ifndef WITH_PYTHON + (void)arg1; /* unused */ + (void)arg2; /* unused */ +# else + Object *owner = (Object *)arg1; + bConstraint *con = (bConstraint *)arg2; + if (owner && con) + BPY_pyconstraint_update(owner, con); +# endif } -#endif // UNUSED +#endif // UNUSED /* helper function for add_constriant - sets the last target for the active constraint */ -static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index) -{ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - int num_targets, i; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - num_targets = BLI_listbase_count(&targets); - - if (index < 0) { - if (abs(index) < num_targets) - index = num_targets - abs(index); - else - index = num_targets - 1; - } - else if (index >= num_targets) { - index = num_targets - 1; - } - - for (ct = targets.first, i = 0; ct; ct = ct->next, i++) { - if (i == index) { - ct->tar = target; - BLI_strncpy(ct->subtarget, subtarget, sizeof(ct->subtarget)); - break; - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } +static void set_constraint_nth_target(bConstraint *con, + Object *target, + const char subtarget[], + int index) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + int num_targets, i; + + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + num_targets = BLI_listbase_count(&targets); + + if (index < 0) { + if (abs(index) < num_targets) + index = num_targets - abs(index); + else + index = num_targets - 1; + } + else if (index >= num_targets) { + index = num_targets - 1; + } + + for (ct = targets.first, i = 0; ct; ct = ct->next, i++) { + if (i == index) { + ct->tar = target; + BLI_strncpy(ct->subtarget, subtarget, sizeof(ct->subtarget)); + break; + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } } /* ------------- Constraint Sanity Testing ------------------- */ -static void test_constraint(Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type) -{ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - bool check_targets = true; - - /* clear disabled-flag first */ - con->flag &= ~CONSTRAINT_DISABLE; - - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data = con->data; - - /* bad: we need a separate set of checks here as poletarget is - * optional... otherwise poletarget must exist too or else - * the constraint is deemed invalid - */ - /* default IK check ... */ - if (BKE_object_exists_check(bmain, data->tar) == 0) { - data->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else if (data->tar == owner) { - if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) { - con->flag |= CONSTRAINT_DISABLE; - } - } - - if (data->poletar) { - if (BKE_object_exists_check(bmain, data->poletar) == 0) { - data->poletar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else if (data->poletar == owner) { - if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) { - con->flag |= CONSTRAINT_DISABLE; - } - } - } - /* ... can be overwritten here */ - BIK_test_constraint(owner, con); - /* targets have already been checked for this */ - check_targets = false; - } - else if (con->type == CONSTRAINT_TYPE_PIVOT) { - bPivotConstraint *data = con->data; - - /* target doesn't have to exist, but if it is non-null, it must exist! */ - if (data->tar && BKE_object_exists_check(bmain, data->tar) == 0) { - data->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else if (data->tar == owner) { - if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) { - con->flag |= CONSTRAINT_DISABLE; - } - } - - /* targets have already been checked for this */ - check_targets = false; - } - else if (con->type == CONSTRAINT_TYPE_ACTION) { - bActionConstraint *data = con->data; - - /* validate action */ - if (data->act == NULL) { - /* must have action */ - con->flag |= CONSTRAINT_DISABLE; - } - else if (data->act->idroot != ID_OB) { - /* only object-rooted actions can be used */ - data->act = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - } - else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) { - bFollowPathConstraint *data = con->data; - - /* don't allow track/up axes to be the same */ - if (data->upflag == data->trackflag) - con->flag |= CONSTRAINT_DISABLE; - if (data->upflag + 3 == data->trackflag) - con->flag |= CONSTRAINT_DISABLE; - } - else if (con->type == CONSTRAINT_TYPE_TRACKTO) { - bTrackToConstraint *data = con->data; - - /* don't allow track/up axes to be the same */ - if (data->reserved2 == data->reserved1) - con->flag |= CONSTRAINT_DISABLE; - if (data->reserved2 + 3 == data->reserved1) - con->flag |= CONSTRAINT_DISABLE; - } - else if (con->type == CONSTRAINT_TYPE_LOCKTRACK) { - bLockTrackConstraint *data = con->data; - - if (data->lockflag == data->trackflag) - con->flag |= CONSTRAINT_DISABLE; - if (data->lockflag + 3 == data->trackflag) - con->flag |= CONSTRAINT_DISABLE; - } - else if (con->type == CONSTRAINT_TYPE_SPLINEIK) { - bSplineIKConstraint *data = con->data; - - /* if the number of points does not match the amount required by the chain length, - * free the points array and request a rebind... - */ - if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) { - /* free the points array */ - if (data->points) { - MEM_freeN(data->points); - data->points = NULL; - } - - /* clear the bound flag, forcing a rebind next time this is evaluated */ - data->flag &= ~CONSTRAINT_SPLINEIK_BOUND; - } - } - else if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = con->data; - - if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) { - if (data->clip != NULL && data->track[0]) { - MovieTracking *tracking = &data->clip->tracking; - MovieTrackingObject *tracking_object; - - if (data->object[0]) - tracking_object = BKE_tracking_object_get_named(tracking, data->object); - else - tracking_object = BKE_tracking_object_get_camera(tracking); - - if (!tracking_object) { - con->flag |= CONSTRAINT_DISABLE; - } - else { - if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track)) - con->flag |= CONSTRAINT_DISABLE; - } - } - else { - con->flag |= CONSTRAINT_DISABLE; - } - } - } - else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { - bCameraSolverConstraint *data = con->data; - - if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL)) - con->flag |= CONSTRAINT_DISABLE; - } - else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = con->data; - - if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL)) - con->flag |= CONSTRAINT_DISABLE; - } - else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { - bTransformCacheConstraint *data = con->data; - - if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) { - con->flag |= CONSTRAINT_DISABLE; - } - } - - /* Check targets for constraints */ - if (check_targets && cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - /* constraints with empty target list that actually require targets */ - if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { - con->flag |= CONSTRAINT_DISABLE; - } - - /* disable and clear constraints targets that are incorrect */ - for (ct = targets.first; ct; ct = ct->next) { - /* general validity checks (for those constraints that need this) */ - if (BKE_object_exists_check(bmain, ct->tar) == 0) { - /* object doesn't exist, but constraint requires target */ - ct->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else if (ct->tar == owner) { - if (type == CONSTRAINT_OBTYPE_BONE) { - if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) { - /* bone must exist in armature... */ - /* TODO: clear subtarget? */ - con->flag |= CONSTRAINT_DISABLE; - } - else if (STREQ(pchan->name, ct->subtarget)) { - /* cannot target self */ - ct->subtarget[0] = '\0'; - con->flag |= CONSTRAINT_DISABLE; - } - } - else { - /* cannot use self as target */ - ct->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - } - - /* target checks for specific constraints */ - if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) { - if (ct->tar) { - if (ct->tar->type != OB_CURVE) { - ct->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else { - Curve *cu = ct->tar->data; - - /* auto-set 'Path' setting on curve so this works */ - cu->flag |= CU_PATH; - } - } - } - else if (con->type == CONSTRAINT_TYPE_ARMATURE) { - if (ct->tar) { - if (ct->tar->type != OB_ARMATURE) { - ct->tar = NULL; - con->flag |= CONSTRAINT_DISABLE; - } - else if (!BKE_armature_find_bone_name(BKE_armature_from_object(ct->tar), ct->subtarget)) { - /* bone must exist in armature... */ - con->flag |= CONSTRAINT_DISABLE; - } - } - } - } - - /* free any temporary targets */ - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } +static void test_constraint( + Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + bool check_targets = true; + + /* clear disabled-flag first */ + con->flag &= ~CONSTRAINT_DISABLE; + + if (con->type == CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = con->data; + + /* bad: we need a separate set of checks here as poletarget is + * optional... otherwise poletarget must exist too or else + * the constraint is deemed invalid + */ + /* default IK check ... */ + if (BKE_object_exists_check(bmain, data->tar) == 0) { + data->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else if (data->tar == owner) { + if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) { + con->flag |= CONSTRAINT_DISABLE; + } + } + + if (data->poletar) { + if (BKE_object_exists_check(bmain, data->poletar) == 0) { + data->poletar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else if (data->poletar == owner) { + if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) { + con->flag |= CONSTRAINT_DISABLE; + } + } + } + /* ... can be overwritten here */ + BIK_test_constraint(owner, con); + /* targets have already been checked for this */ + check_targets = false; + } + else if (con->type == CONSTRAINT_TYPE_PIVOT) { + bPivotConstraint *data = con->data; + + /* target doesn't have to exist, but if it is non-null, it must exist! */ + if (data->tar && BKE_object_exists_check(bmain, data->tar) == 0) { + data->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else if (data->tar == owner) { + if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) { + con->flag |= CONSTRAINT_DISABLE; + } + } + + /* targets have already been checked for this */ + check_targets = false; + } + else if (con->type == CONSTRAINT_TYPE_ACTION) { + bActionConstraint *data = con->data; + + /* validate action */ + if (data->act == NULL) { + /* must have action */ + con->flag |= CONSTRAINT_DISABLE; + } + else if (data->act->idroot != ID_OB) { + /* only object-rooted actions can be used */ + data->act = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + } + else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) { + bFollowPathConstraint *data = con->data; + + /* don't allow track/up axes to be the same */ + if (data->upflag == data->trackflag) + con->flag |= CONSTRAINT_DISABLE; + if (data->upflag + 3 == data->trackflag) + con->flag |= CONSTRAINT_DISABLE; + } + else if (con->type == CONSTRAINT_TYPE_TRACKTO) { + bTrackToConstraint *data = con->data; + + /* don't allow track/up axes to be the same */ + if (data->reserved2 == data->reserved1) + con->flag |= CONSTRAINT_DISABLE; + if (data->reserved2 + 3 == data->reserved1) + con->flag |= CONSTRAINT_DISABLE; + } + else if (con->type == CONSTRAINT_TYPE_LOCKTRACK) { + bLockTrackConstraint *data = con->data; + + if (data->lockflag == data->trackflag) + con->flag |= CONSTRAINT_DISABLE; + if (data->lockflag + 3 == data->trackflag) + con->flag |= CONSTRAINT_DISABLE; + } + else if (con->type == CONSTRAINT_TYPE_SPLINEIK) { + bSplineIKConstraint *data = con->data; + + /* if the number of points does not match the amount required by the chain length, + * free the points array and request a rebind... + */ + if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) { + /* free the points array */ + if (data->points) { + MEM_freeN(data->points); + data->points = NULL; + } + + /* clear the bound flag, forcing a rebind next time this is evaluated */ + data->flag &= ~CONSTRAINT_SPLINEIK_BOUND; + } + } + else if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { + bFollowTrackConstraint *data = con->data; + + if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) { + if (data->clip != NULL && data->track[0]) { + MovieTracking *tracking = &data->clip->tracking; + MovieTrackingObject *tracking_object; + + if (data->object[0]) + tracking_object = BKE_tracking_object_get_named(tracking, data->object); + else + tracking_object = BKE_tracking_object_get_camera(tracking); + + if (!tracking_object) { + con->flag |= CONSTRAINT_DISABLE; + } + else { + if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track)) + con->flag |= CONSTRAINT_DISABLE; + } + } + else { + con->flag |= CONSTRAINT_DISABLE; + } + } + } + else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { + bCameraSolverConstraint *data = con->data; + + if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL)) + con->flag |= CONSTRAINT_DISABLE; + } + else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { + bObjectSolverConstraint *data = con->data; + + if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL)) + con->flag |= CONSTRAINT_DISABLE; + } + else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { + bTransformCacheConstraint *data = con->data; + + if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) { + con->flag |= CONSTRAINT_DISABLE; + } + } + + /* Check targets for constraints */ + if (check_targets && cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + /* constraints with empty target list that actually require targets */ + if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + con->flag |= CONSTRAINT_DISABLE; + } + + /* disable and clear constraints targets that are incorrect */ + for (ct = targets.first; ct; ct = ct->next) { + /* general validity checks (for those constraints that need this) */ + if (BKE_object_exists_check(bmain, ct->tar) == 0) { + /* object doesn't exist, but constraint requires target */ + ct->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else if (ct->tar == owner) { + if (type == CONSTRAINT_OBTYPE_BONE) { + if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) { + /* bone must exist in armature... */ + /* TODO: clear subtarget? */ + con->flag |= CONSTRAINT_DISABLE; + } + else if (STREQ(pchan->name, ct->subtarget)) { + /* cannot target self */ + ct->subtarget[0] = '\0'; + con->flag |= CONSTRAINT_DISABLE; + } + } + else { + /* cannot use self as target */ + ct->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + } + + /* target checks for specific constraints */ + if (ELEM(con->type, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_CLAMPTO, + CONSTRAINT_TYPE_SPLINEIK)) { + if (ct->tar) { + if (ct->tar->type != OB_CURVE) { + ct->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else { + Curve *cu = ct->tar->data; + + /* auto-set 'Path' setting on curve so this works */ + cu->flag |= CU_PATH; + } + } + } + else if (con->type == CONSTRAINT_TYPE_ARMATURE) { + if (ct->tar) { + if (ct->tar->type != OB_ARMATURE) { + ct->tar = NULL; + con->flag |= CONSTRAINT_DISABLE; + } + else if (!BKE_armature_find_bone_name(BKE_armature_from_object(ct->tar), + ct->subtarget)) { + /* bone must exist in armature... */ + con->flag |= CONSTRAINT_DISABLE; + } + } + } + } + + /* free any temporary targets */ + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } } static int constraint_type_get(Object *owner, bPoseChannel *pchan) { - int type; - /* Check parents */ - if (pchan) { - switch (owner->type) { - case OB_ARMATURE: - type = CONSTRAINT_OBTYPE_BONE; - break; - default: - type = CONSTRAINT_OBTYPE_OBJECT; - break; - } - } - else - type = CONSTRAINT_OBTYPE_OBJECT; - return type; + int type; + /* Check parents */ + if (pchan) { + switch (owner->type) { + case OB_ARMATURE: + type = CONSTRAINT_OBTYPE_BONE; + break; + default: + type = CONSTRAINT_OBTYPE_OBJECT; + break; + } + } + else + type = CONSTRAINT_OBTYPE_OBJECT; + return type; } /* checks validity of object pointers, and NULLs, @@ -514,185 +523,192 @@ static int constraint_type_get(Object *owner, bPoseChannel *pchan) */ static void test_constraints(Main *bmain, Object *owner, bPoseChannel *pchan) { - bConstraint *curcon; - ListBase *conlist = NULL; - int type; + bConstraint *curcon; + ListBase *conlist = NULL; + int type; - if (owner == NULL) return; + if (owner == NULL) + return; - type = constraint_type_get(owner, pchan); + type = constraint_type_get(owner, pchan); - /* Get the constraint list for this object */ - switch (type) { - case CONSTRAINT_OBTYPE_OBJECT: - conlist = &owner->constraints; - break; - case CONSTRAINT_OBTYPE_BONE: - conlist = &pchan->constraints; - break; - } + /* Get the constraint list for this object */ + switch (type) { + case CONSTRAINT_OBTYPE_OBJECT: + conlist = &owner->constraints; + break; + case CONSTRAINT_OBTYPE_BONE: + conlist = &pchan->constraints; + break; + } - /* Check all constraints - is constraint valid? */ - if (conlist) { - for (curcon = conlist->first; curcon; curcon = curcon->next) { - test_constraint(bmain, owner, pchan, curcon, type); - } - } + /* Check all constraints - is constraint valid? */ + if (conlist) { + for (curcon = conlist->first; curcon; curcon = curcon->next) { + test_constraint(bmain, owner, pchan, curcon, type); + } + } } void object_test_constraints(Main *bmain, Object *owner) { - if (owner->constraints.first) - test_constraints(bmain, owner, NULL); + if (owner->constraints.first) + test_constraints(bmain, owner, NULL); - if (owner->type == OB_ARMATURE && owner->pose) { - bPoseChannel *pchan; + if (owner->type == OB_ARMATURE && owner->pose) { + bPoseChannel *pchan; - for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->constraints.first) - test_constraints(bmain, owner, pchan); - } - } + for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->constraints.first) + test_constraints(bmain, owner, pchan); + } + } } static void object_test_constraint(Main *bmain, Object *owner, bConstraint *con) { - if (owner->type == OB_ARMATURE && owner->pose) { - if (BLI_findindex(&owner->constraints, con) != -1) { - test_constraint(bmain, owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT); - } - else { - bPoseChannel *pchan; - for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) { - if (BLI_findindex(&pchan->constraints, con) != -1) { - test_constraint(bmain, owner, pchan, con, CONSTRAINT_OBTYPE_BONE); - break; - } - } - } - } - else { - test_constraint(bmain, owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT); - } + if (owner->type == OB_ARMATURE && owner->pose) { + if (BLI_findindex(&owner->constraints, con) != -1) { + test_constraint(bmain, owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT); + } + else { + bPoseChannel *pchan; + for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) { + if (BLI_findindex(&pchan->constraints, con) != -1) { + test_constraint(bmain, owner, pchan, con, CONSTRAINT_OBTYPE_BONE); + break; + } + } + } + } + else { + test_constraint(bmain, owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT); + } } /************************ generic functions for operators using constraint names and data context *********************/ -#define EDIT_CONSTRAINT_OWNER_OBJECT 0 -#define EDIT_CONSTRAINT_OWNER_BONE 1 +#define EDIT_CONSTRAINT_OWNER_OBJECT 0 +#define EDIT_CONSTRAINT_OWNER_BONE 1 static const EnumPropertyItem constraint_owner_items[] = { - {EDIT_CONSTRAINT_OWNER_OBJECT, "OBJECT", 0, "Object", "Edit a constraint on the active object"}, - {EDIT_CONSTRAINT_OWNER_BONE, "BONE", 0, "Bone", "Edit a constraint on the active bone"}, - {0, NULL, 0, NULL, NULL}, + {EDIT_CONSTRAINT_OWNER_OBJECT, + "OBJECT", + 0, + "Object", + "Edit a constraint on the active object"}, + {EDIT_CONSTRAINT_OWNER_BONE, "BONE", 0, "Bone", "Edit a constraint on the active bone"}, + {0, NULL, 0, NULL, NULL}, }; - static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", rna_type); - Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - if (!ptr.data) { - CTX_wm_operator_poll_msg_set(C, "Context missing 'constraint'"); - return 0; - } + if (!ptr.data) { + CTX_wm_operator_poll_msg_set(C, "Context missing 'constraint'"); + return 0; + } - if (!ob) { - CTX_wm_operator_poll_msg_set(C, "Context missing active object"); - return 0; - } + if (!ob) { + CTX_wm_operator_poll_msg_set(C, "Context missing active object"); + return 0; + } - if (ID_IS_LINKED(ob) || (ptr.id.data && ID_IS_LINKED(ptr.id.data))) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit library data"); - return 0; - } + if (ID_IS_LINKED(ob) || (ptr.id.data && ID_IS_LINKED(ptr.id.data))) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit library data"); + return 0; + } - if (ID_IS_STATIC_OVERRIDE(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from static override"); - return (((bConstraint *)ptr.data)->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) != 0; - } + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from static override"); + return (((bConstraint *)ptr.data)->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) != 0; + } - return 1; + return 1; } static bool edit_constraint_poll(bContext *C) { - return edit_constraint_poll_generic(C, &RNA_Constraint); + return edit_constraint_poll_generic(C, &RNA_Constraint); } static void edit_constraint_properties(wmOperatorType *ot) { - PropertyRNA *prop; - prop = RNA_def_string(ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit"); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_enum(ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + prop = RNA_def_string( + ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit"); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_enum( + ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint"); + RNA_def_property_flag(prop, PROP_HIDDEN); } static int edit_constraint_invoke_properties(bContext *C, wmOperator *op) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); - Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - bConstraint *con; - ListBase *list; + PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + bConstraint *con; + ListBase *list; - if (RNA_struct_property_is_set(op->ptr, "constraint") && RNA_struct_property_is_set(op->ptr, "owner")) - return 1; + if (RNA_struct_property_is_set(op->ptr, "constraint") && + RNA_struct_property_is_set(op->ptr, "owner")) + return 1; - if (ptr.data) { - con = ptr.data; - RNA_string_set(op->ptr, "constraint", con->name); + if (ptr.data) { + con = ptr.data; + RNA_string_set(op->ptr, "constraint", con->name); - list = get_constraint_lb(ob, con, NULL); + list = get_constraint_lb(ob, con, NULL); - if (&ob->constraints == list) - RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_OBJECT); - else - RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_BONE); + if (&ob->constraints == list) + RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_OBJECT); + else + RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_BONE); - return 1; - } + return 1; + } - return 0; + return 0; } static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int type) { - char constraint_name[MAX_NAME]; - int owner = RNA_enum_get(op->ptr, "owner"); - bConstraint *con; - ListBase *list = NULL; - - RNA_string_get(op->ptr, "constraint", constraint_name); - - if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { - list = &ob->constraints; - } - else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); - if (pchan) - list = &pchan->constraints; - else { - //if (G.debug & G_DEBUG) - //printf("edit_constraint_property_get: No active bone for object '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); - return NULL; - } - } - else { - //if (G.debug & G_DEBUG) - //printf("edit_constraint_property_get: defaulting to getting list in the standard way\n"); - list = get_active_constraints(ob); - } - - con = BKE_constraints_find_name(list, constraint_name); - //if (G.debug & G_DEBUG) - //printf("constraint found = %p, %s\n", (void *)con, (con) ? con->name : "<Not found>"); - - if (con && (type != 0) && (con->type != type)) - con = NULL; - - return con; + char constraint_name[MAX_NAME]; + int owner = RNA_enum_get(op->ptr, "owner"); + bConstraint *con; + ListBase *list = NULL; + + RNA_string_get(op->ptr, "constraint", constraint_name); + + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + list = &ob->constraints; + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + bPoseChannel *pchan = BKE_pose_channel_active(ob); + if (pchan) + list = &pchan->constraints; + else { + //if (G.debug & G_DEBUG) + //printf("edit_constraint_property_get: No active bone for object '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); + return NULL; + } + } + else { + //if (G.debug & G_DEBUG) + //printf("edit_constraint_property_get: defaulting to getting list in the standard way\n"); + list = get_active_constraints(ob); + } + + con = BKE_constraints_find_name(list, constraint_name); + //if (G.debug & G_DEBUG) + //printf("constraint found = %p, %s\n", (void *)con, (con) ? con->name : "<Not found>"); + + if (con && (type != 0) && (con->type != type)) + con = NULL; + + return con; } /* ********************** CONSTRAINT-SPECIFIC STUFF ********************* */ @@ -702,733 +718,755 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int static int stretchto_reset_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_STRETCHTO); - bStretchToConstraint *data = (con) ? (bStretchToConstraint *)con->data : NULL; + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_STRETCHTO); + bStretchToConstraint *data = (con) ? (bStretchToConstraint *)con->data : NULL; - /* despite 3 layers of checks, we may still not be able to find a constraint */ - if (data == NULL) - return OPERATOR_CANCELLED; + /* despite 3 layers of checks, we may still not be able to find a constraint */ + if (data == NULL) + return OPERATOR_CANCELLED; - /* just set original length to 0.0, which will cause a reset on next recalc */ - data->orglength = 0.0f; - ED_object_constraint_update(bmain, ob); + /* just set original length to 0.0, which will cause a reset on next recalc */ + data->orglength = 0.0f; + ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); - return OPERATOR_FINISHED; + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); + return OPERATOR_FINISHED; } static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return stretchto_reset_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return stretchto_reset_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_stretchto_reset(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reset Original Length"; - ot->idname = "CONSTRAINT_OT_stretchto_reset"; - ot->description = "Reset original length of bone for Stretch To Constraint"; + /* identifiers */ + ot->name = "Reset Original Length"; + ot->idname = "CONSTRAINT_OT_stretchto_reset"; + ot->description = "Reset original length of bone for Stretch To Constraint"; - /* callbacks */ - ot->invoke = stretchto_reset_invoke; - ot->exec = stretchto_reset_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = stretchto_reset_invoke; + ot->exec = stretchto_reset_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } - static int limitdistance_reset_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_DISTLIMIT); - bDistLimitConstraint *data = (con) ? (bDistLimitConstraint *)con->data : NULL; + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_DISTLIMIT); + bDistLimitConstraint *data = (con) ? (bDistLimitConstraint *)con->data : NULL; - /* despite 3 layers of checks, we may still not be able to find a constraint */ - if (data == NULL) - return OPERATOR_CANCELLED; + /* despite 3 layers of checks, we may still not be able to find a constraint */ + if (data == NULL) + return OPERATOR_CANCELLED; - /* just set original length to 0.0, which will cause a reset on next recalc */ - data->dist = 0.0f; - ED_object_constraint_update(bmain, ob); + /* just set original length to 0.0, which will cause a reset on next recalc */ + data->dist = 0.0f; + ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); - return OPERATOR_FINISHED; + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); + return OPERATOR_FINISHED; } static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return limitdistance_reset_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return limitdistance_reset_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reset Distance"; - ot->idname = "CONSTRAINT_OT_limitdistance_reset"; - ot->description = "Reset limiting distance for Limit Distance Constraint"; + /* identifiers */ + ot->name = "Reset Distance"; + ot->idname = "CONSTRAINT_OT_limitdistance_reset"; + ot->description = "Reset limiting distance for Limit Distance Constraint"; - /* callbacks */ - ot->invoke = limitdistance_reset_invoke; - ot->exec = limitdistance_reset_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = limitdistance_reset_invoke; + ot->exec = limitdistance_reset_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } /* ------------- Child-Of Constraint ------------------ */ -static void child_get_inverse_matrix(const bContext *C, Scene *scene, Object *ob, bConstraint *con, float invmat[4][4], const int owner) -{ - Depsgraph *depsgraph = CTX_data_depsgraph(C); - - /* nullify inverse matrix first */ - unit_m4(invmat); - - if (owner == EDIT_CONSTRAINT_OWNER_BONE) { - bPoseChannel *pchan; - /* try to find a pose channel - assume that this is the constraint owner */ - /* TODO: get from context instead? */ - if (ob && ob->pose && (pchan = BKE_pose_channel_active(ob))) { - bConstraint *con_last; - /* calculate/set inverse matrix: - * We just calculate all transform-stack eval up to but not including this constraint. - * This is because inverse should just inverse correct for just the constraint's influence - * when it gets applied; that is, at the time of application, we don't know anything about - * what follows. - */ - float imat[4][4], tmat[4][4]; - float pmat[4][4]; - - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&pchan->constraints, con) != -1); - - /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), - * to use as baseline ("pmat") to derive delta from. This extra calc saves users - * from having pressing "Clear Inverse" first - */ - BKE_pose_where_is(depsgraph, scene, ob); - copy_m4_m4(pmat, pchan->pose_mat); - - /* 2. knock out constraints starting from this one */ - con_last = pchan->constraints.last; - pchan->constraints.last = con->prev; - - if (con->prev) { - /* new end must not point to this one, else this chain cutting is useless */ - con->prev->next = NULL; - } - else { - /* constraint was first */ - pchan->constraints.first = NULL; - } - - /* 3. solve pose without disabled constraints */ - BKE_pose_where_is(depsgraph, scene, ob); - - /* 4. determine effect of constraint by removing the newly calculated - * pchan->pose_mat from the original pchan->pose_mat, thus determining - * the effect of the constraint - */ - invert_m4_m4(imat, pchan->pose_mat); - mul_m4_m4m4(tmat, pmat, imat); - invert_m4_m4(invmat, tmat); - - /* 5. restore constraints */ - pchan->constraints.last = con_last; - - if (con->prev) { - /* hook up prev to this one again */ - con->prev->next = con; - } - else { - /* set as first again */ - pchan->constraints.first = con; - } - - /* 6. recalculate pose with new inv-mat applied */ - BKE_pose_where_is(depsgraph, scene, ob); - } - } - if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { - if (ob) { - Object workob; - - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&ob->constraints, con) != -1); - - /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(invmat, workob.obmat); - } - } +static void child_get_inverse_matrix(const bContext *C, + Scene *scene, + Object *ob, + bConstraint *con, + float invmat[4][4], + const int owner) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + /* nullify inverse matrix first */ + unit_m4(invmat); + + if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + bPoseChannel *pchan; + /* try to find a pose channel - assume that this is the constraint owner */ + /* TODO: get from context instead? */ + if (ob && ob->pose && (pchan = BKE_pose_channel_active(ob))) { + bConstraint *con_last; + /* calculate/set inverse matrix: + * We just calculate all transform-stack eval up to but not including this constraint. + * This is because inverse should just inverse correct for just the constraint's influence + * when it gets applied; that is, at the time of application, we don't know anything about + * what follows. + */ + float imat[4][4], tmat[4][4]; + float pmat[4][4]; + + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&pchan->constraints, con) != -1); + + /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), + * to use as baseline ("pmat") to derive delta from. This extra calc saves users + * from having pressing "Clear Inverse" first + */ + BKE_pose_where_is(depsgraph, scene, ob); + copy_m4_m4(pmat, pchan->pose_mat); + + /* 2. knock out constraints starting from this one */ + con_last = pchan->constraints.last; + pchan->constraints.last = con->prev; + + if (con->prev) { + /* new end must not point to this one, else this chain cutting is useless */ + con->prev->next = NULL; + } + else { + /* constraint was first */ + pchan->constraints.first = NULL; + } + + /* 3. solve pose without disabled constraints */ + BKE_pose_where_is(depsgraph, scene, ob); + + /* 4. determine effect of constraint by removing the newly calculated + * pchan->pose_mat from the original pchan->pose_mat, thus determining + * the effect of the constraint + */ + invert_m4_m4(imat, pchan->pose_mat); + mul_m4_m4m4(tmat, pmat, imat); + invert_m4_m4(invmat, tmat); + + /* 5. restore constraints */ + pchan->constraints.last = con_last; + + if (con->prev) { + /* hook up prev to this one again */ + con->prev->next = con; + } + else { + /* set as first again */ + pchan->constraints.first = con; + } + + /* 6. recalculate pose with new inv-mat applied */ + BKE_pose_where_is(depsgraph, scene, ob); + } + } + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + if (ob) { + Object workob; + + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&ob->constraints, con) != -1); + + /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(invmat, workob.obmat); + } + } } /* ChildOf Constraint - set inverse callback */ static int childof_set_inverse_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); - bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL; - const int owner = RNA_enum_get(op->ptr, "owner"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); + bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL; + const int owner = RNA_enum_get(op->ptr, "owner"); - /* despite 3 layers of checks, we may still not be able to find a constraint */ - if (data == NULL) { - printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); - BKE_report(op->reports, RPT_ERROR, "Could not find constraint data for Child-Of Set Inverse"); - return OPERATOR_CANCELLED; - } + /* despite 3 layers of checks, we may still not be able to find a constraint */ + if (data == NULL) { + printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); + BKE_report(op->reports, RPT_ERROR, "Could not find constraint data for Child-Of Set Inverse"); + return OPERATOR_CANCELLED; + } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); - ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + ED_object_constraint_update(bmain, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return childof_set_inverse_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return childof_set_inverse_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_childof_set_inverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Inverse"; - ot->idname = "CONSTRAINT_OT_childof_set_inverse"; - ot->description = "Set inverse correction for ChildOf constraint"; + /* identifiers */ + ot->name = "Set Inverse"; + ot->idname = "CONSTRAINT_OT_childof_set_inverse"; + ot->description = "Set inverse correction for ChildOf constraint"; - /* callbacks */ - ot->invoke = childof_set_inverse_invoke; - ot->exec = childof_set_inverse_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = childof_set_inverse_invoke; + ot->exec = childof_set_inverse_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } /* ChildOf Constraint - clear inverse callback */ static int childof_clear_inverse_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); - bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL; + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF); + bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL; - if (data == NULL) { - BKE_report(op->reports, RPT_ERROR, "Child Of constraint not found"); - return OPERATOR_CANCELLED; - } + if (data == NULL) { + BKE_report(op->reports, RPT_ERROR, "Child Of constraint not found"); + return OPERATOR_CANCELLED; + } - /* simply clear the matrix */ - unit_m4(data->invmat); + /* simply clear the matrix */ + unit_m4(data->invmat); - ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + ED_object_constraint_update(bmain, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return childof_clear_inverse_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return childof_clear_inverse_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Inverse"; - ot->idname = "CONSTRAINT_OT_childof_clear_inverse"; - ot->description = "Clear inverse correction for ChildOf constraint"; + /* identifiers */ + ot->name = "Clear Inverse"; + ot->idname = "CONSTRAINT_OT_childof_clear_inverse"; + ot->description = "Clear inverse correction for ChildOf constraint"; - /* callbacks */ - ot->invoke = childof_clear_inverse_invoke; - ot->exec = childof_clear_inverse_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = childof_clear_inverse_invoke; + ot->exec = childof_clear_inverse_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } /* --------------- Follow Path Constraint ------------------ */ static int followpath_path_animate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH); - bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL; - - bAction *act = NULL; - FCurve *fcu = NULL; - int sfra = RNA_int_get(op->ptr, "frame_start"); - int len = RNA_int_get(op->ptr, "length"); - float standardRange = 1.0; - - /* nearly impossible sanity check */ - if (data == NULL) { - BKE_report(op->reports, RPT_ERROR, "Follow Path constraint not found"); - return OPERATOR_CANCELLED; - } - - /* add F-Curve as appropriate */ - if (data->tar) { - Curve *cu = (Curve *)data->tar->data; - - if (ELEM(NULL, cu->adt, cu->adt->action) || - (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) - { - /* create F-Curve for path animation */ - act = verify_adt_action(bmain, &cu->id, 1); - fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1); - - /* standard vertical range - 1:1 = 100 frames */ - standardRange = 100.0f; - } - else { - /* path anim exists already - abort for now as this may well be what was intended */ - BKE_report(op->reports, RPT_WARNING, "Path is already animated"); - return OPERATOR_CANCELLED; - } - } - else { - /* animate constraint's "fixed offset" */ - PointerRNA ptr; - PropertyRNA *prop; - char *path; - - /* get RNA pointer to constraint's "offset_factor" property - to build RNA path */ - RNA_pointer_create(&ob->id, &RNA_FollowPathConstraint, con, &ptr); - prop = RNA_struct_find_property(&ptr, "offset_factor"); - - path = RNA_path_from_ID_to_property(&ptr, prop); - - /* create F-Curve for constraint */ - act = verify_adt_action(bmain, &ob->id, 1); - fcu = verify_fcurve(bmain, act, NULL, NULL, path, 0, 1); - - /* standard vertical range - 0.0 to 1.0 */ - standardRange = 1.0f; - - /* enable "Use Fixed Position" so that animating this has effect */ - data->followflag |= FOLLOWPATH_STATIC; - - /* path needs to be freed */ - if (path) - MEM_freeN(path); - } - - /* setup dummy 'generator' modifier here to get 1-1 correspondence still working - * and define basic slope of this curve based on the properties - */ - if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) { - FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); - FMod_Generator *gen = fcm->data; - - /* Assume that we have the following equation: - * y = Ax + B - * 1 0 <-- coefficients array indices - */ - float A = standardRange / (float)(len); - float B = (float)(-sfra) * A; - - gen->coefficients[1] = A; - gen->coefficients[0] = B; - } - - /* updates... */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; -} - -static int followpath_path_animate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* hook up invoke properties for figuring out which constraint we're dealing with */ - if (edit_constraint_invoke_properties(C, op)) { - return followpath_path_animate_exec(C, op); - } - else { - return OPERATOR_CANCELLED; - } + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH); + bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL; + + bAction *act = NULL; + FCurve *fcu = NULL; + int sfra = RNA_int_get(op->ptr, "frame_start"); + int len = RNA_int_get(op->ptr, "length"); + float standardRange = 1.0; + + /* nearly impossible sanity check */ + if (data == NULL) { + BKE_report(op->reports, RPT_ERROR, "Follow Path constraint not found"); + return OPERATOR_CANCELLED; + } + + /* add F-Curve as appropriate */ + if (data->tar) { + Curve *cu = (Curve *)data->tar->data; + + if (ELEM(NULL, cu->adt, cu->adt->action) || + (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) { + /* create F-Curve for path animation */ + act = verify_adt_action(bmain, &cu->id, 1); + fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1); + + /* standard vertical range - 1:1 = 100 frames */ + standardRange = 100.0f; + } + else { + /* path anim exists already - abort for now as this may well be what was intended */ + BKE_report(op->reports, RPT_WARNING, "Path is already animated"); + return OPERATOR_CANCELLED; + } + } + else { + /* animate constraint's "fixed offset" */ + PointerRNA ptr; + PropertyRNA *prop; + char *path; + + /* get RNA pointer to constraint's "offset_factor" property - to build RNA path */ + RNA_pointer_create(&ob->id, &RNA_FollowPathConstraint, con, &ptr); + prop = RNA_struct_find_property(&ptr, "offset_factor"); + + path = RNA_path_from_ID_to_property(&ptr, prop); + + /* create F-Curve for constraint */ + act = verify_adt_action(bmain, &ob->id, 1); + fcu = verify_fcurve(bmain, act, NULL, NULL, path, 0, 1); + + /* standard vertical range - 0.0 to 1.0 */ + standardRange = 1.0f; + + /* enable "Use Fixed Position" so that animating this has effect */ + data->followflag |= FOLLOWPATH_STATIC; + + /* path needs to be freed */ + if (path) + MEM_freeN(path); + } + + /* setup dummy 'generator' modifier here to get 1-1 correspondence still working + * and define basic slope of this curve based on the properties + */ + if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) { + FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); + FMod_Generator *gen = fcm->data; + + /* Assume that we have the following equation: + * y = Ax + B + * 1 0 <-- coefficients array indices + */ + float A = standardRange / (float)(len); + float B = (float)(-sfra) * A; + + gen->coefficients[1] = A; + gen->coefficients[0] = B; + } + + /* updates... */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + return OPERATOR_FINISHED; +} + +static int followpath_path_animate_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + /* hook up invoke properties for figuring out which constraint we're dealing with */ + if (edit_constraint_invoke_properties(C, op)) { + return followpath_path_animate_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } } void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Auto Animate Path"; - ot->idname = "CONSTRAINT_OT_followpath_path_animate"; - ot->description = "Add default animation for path used by constraint if it isn't animated already"; - - /* callbacks */ - ot->invoke = followpath_path_animate_invoke; - ot->exec = followpath_path_animate_exec; - ot->poll = edit_constraint_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - edit_constraint_properties(ot); - RNA_def_int(ot->srna, "frame_start", 1, MINAFRAME, MAXFRAME, "Start Frame", - "First frame of path animation", MINAFRAME, MAXFRAME); - RNA_def_int(ot->srna, "length", 100, 0, MAXFRAME, "Length", - "Number of frames that path animation should take", 0, MAXFRAME); + /* identifiers */ + ot->name = "Auto Animate Path"; + ot->idname = "CONSTRAINT_OT_followpath_path_animate"; + ot->description = + "Add default animation for path used by constraint if it isn't animated already"; + + /* callbacks */ + ot->invoke = followpath_path_animate_invoke; + ot->exec = followpath_path_animate_exec; + ot->poll = edit_constraint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + edit_constraint_properties(ot); + RNA_def_int(ot->srna, + "frame_start", + 1, + MINAFRAME, + MAXFRAME, + "Start Frame", + "First frame of path animation", + MINAFRAME, + MAXFRAME); + RNA_def_int(ot->srna, + "length", + 100, + 0, + MAXFRAME, + "Length", + "Number of frames that path animation should take", + 0, + MAXFRAME); } /* ------------- Object Solver Constraint ------------------ */ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); - bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL; - const int owner = RNA_enum_get(op->ptr, "owner"); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); + bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL; + const int owner = RNA_enum_get(op->ptr, "owner"); - /* despite 3 layers of checks, we may still not be able to find a constraint */ - if (data == NULL) { - printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); - BKE_report(op->reports, RPT_ERROR, "Could not find constraint data for Child-Of Set Inverse"); - return OPERATOR_CANCELLED; - } + /* despite 3 layers of checks, we may still not be able to find a constraint */ + if (data == NULL) { + printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob) ? ob->id.name + 2 : "<None>"); + BKE_report(op->reports, RPT_ERROR, "Could not find constraint data for Child-Of Set Inverse"); + return OPERATOR_CANCELLED; + } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int objectsolver_set_inverse_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return objectsolver_set_inverse_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return objectsolver_set_inverse_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_objectsolver_set_inverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Inverse"; - ot->idname = "CONSTRAINT_OT_objectsolver_set_inverse"; - ot->description = "Set inverse correction for ObjectSolver constraint"; + /* identifiers */ + ot->name = "Set Inverse"; + ot->idname = "CONSTRAINT_OT_objectsolver_set_inverse"; + ot->description = "Set inverse correction for ObjectSolver constraint"; - /* callbacks */ - ot->invoke = objectsolver_set_inverse_invoke; - ot->exec = objectsolver_set_inverse_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = objectsolver_set_inverse_invoke; + ot->exec = objectsolver_set_inverse_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); - bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL; + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); + bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL; - if (data == NULL) { - BKE_report(op->reports, RPT_ERROR, "Child Of constraint not found"); - return OPERATOR_CANCELLED; - } + if (data == NULL) { + BKE_report(op->reports, RPT_ERROR, "Child Of constraint not found"); + return OPERATOR_CANCELLED; + } - /* simply clear the matrix */ - unit_m4(data->invmat); + /* simply clear the matrix */ + unit_m4(data->invmat); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int objectsolver_clear_inverse_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return objectsolver_clear_inverse_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return objectsolver_clear_inverse_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Inverse"; - ot->idname = "CONSTRAINT_OT_objectsolver_clear_inverse"; - ot->description = "Clear inverse correction for ObjectSolver constraint"; + /* identifiers */ + ot->name = "Clear Inverse"; + ot->idname = "CONSTRAINT_OT_objectsolver_clear_inverse"; + ot->description = "Clear inverse correction for ObjectSolver constraint"; - /* callbacks */ - ot->invoke = objectsolver_clear_inverse_invoke; - ot->exec = objectsolver_clear_inverse_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = objectsolver_clear_inverse_invoke; + ot->exec = objectsolver_clear_inverse_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } /***************************** BUTTONS ****************************/ void ED_object_constraint_set_active(Object *ob, bConstraint *con) { - ListBase *lb = get_constraint_lb(ob, con, NULL); + ListBase *lb = get_constraint_lb(ob, con, NULL); - /* lets be nice and escape if its active already */ - /* NOTE: this assumes that the stack doesn't have other active ones set... */ - if ((lb && con) && (con->flag & CONSTRAINT_ACTIVE)) - return; + /* lets be nice and escape if its active already */ + /* NOTE: this assumes that the stack doesn't have other active ones set... */ + if ((lb && con) && (con->flag & CONSTRAINT_ACTIVE)) + return; - BKE_constraints_active_set(lb, con); + BKE_constraints_active_set(lb, con); } void ED_object_constraint_update(Main *bmain, Object *ob) { - if (ob->pose) BKE_pose_update_constraint_flags(ob->pose); + if (ob->pose) + BKE_pose_update_constraint_flags(ob->pose); - object_test_constraints(bmain, ob); + object_test_constraints(bmain, ob); - if (ob->type == OB_ARMATURE) - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); - else - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + if (ob->type == OB_ARMATURE) + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); + else + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } static void object_pose_tag_update(Main *bmain, Object *ob) { - BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */ - if (ob->proxy && ob->adt) { - /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded - * after calling `BKE_pose_rebuild()`, which causes T43872. - * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones - * or not... - * XXX Temp hack until new depsgraph hopefully solves this. */ - DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); - } + BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */ + if (ob->proxy && ob->adt) { + /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded + * after calling `BKE_pose_rebuild()`, which causes T43872. + * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones + * or not... + * XXX Temp hack until new depsgraph hopefully solves this. */ + DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); + } } void ED_object_constraint_dependency_update(Main *bmain, Object *ob) { - ED_object_constraint_update(bmain, ob); + ED_object_constraint_update(bmain, ob); - if (ob->pose) { - object_pose_tag_update(bmain, ob); - } - DEG_relations_tag_update(bmain); + if (ob->pose) { + object_pose_tag_update(bmain, ob); + } + DEG_relations_tag_update(bmain); } void ED_object_constraint_tag_update(Main *bmain, Object *ob, bConstraint *con) { - if (ob->pose) { - BKE_pose_tag_update_constraint_flags(ob->pose); - } + if (ob->pose) { + BKE_pose_tag_update_constraint_flags(ob->pose); + } - if (con) { - object_test_constraint(bmain, ob, con); - } + if (con) { + object_test_constraint(bmain, ob, con); + } - if (ob->type == OB_ARMATURE) - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); - else - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + if (ob->type == OB_ARMATURE) + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); + else + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - /* Do Copy-on-Write tag here too, otherwise constraint - * influence/mute buttons in UI have no effect - */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + /* Do Copy-on-Write tag here too, otherwise constraint + * influence/mute buttons in UI have no effect + */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); } void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con) { - ED_object_constraint_tag_update(bmain, ob, con); + ED_object_constraint_tag_update(bmain, ob, con); - if (ob->pose) { - object_pose_tag_update(bmain, ob); - } - DEG_relations_tag_update(bmain); + if (ob->pose) { + object_pose_tag_update(bmain, ob); + } + DEG_relations_tag_update(bmain); } static bool constraint_poll(bContext *C) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); - return (ptr.id.data && ptr.data); + PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); + return (ptr.id.data && ptr.data); } - static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); - Object *ob = ptr.id.data; - bConstraint *con = ptr.data; - ListBase *lb = get_constraint_lb(ob, con, NULL); + Main *bmain = CTX_data_main(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); + Object *ob = ptr.id.data; + bConstraint *con = ptr.data; + ListBase *lb = get_constraint_lb(ob, con, NULL); - /* free the constraint */ - if (BKE_constraint_remove_ex(lb, ob, con, true)) { - /* there's no active constraint now, so make sure this is the case */ - BKE_constraints_active_set(&ob->constraints, NULL); - /* needed to set the flags on posebones correctly */ - ED_object_constraint_update(bmain, ob); + /* free the constraint */ + if (BKE_constraint_remove_ex(lb, ob, con, true)) { + /* there's no active constraint now, so make sure this is the case */ + BKE_constraints_active_set(&ob->constraints, NULL); + /* needed to set the flags on posebones correctly */ + ED_object_constraint_update(bmain, ob); - /* relations */ - DEG_relations_tag_update(CTX_data_main(C)); + /* relations */ + DEG_relations_tag_update(CTX_data_main(C)); - /* notifiers */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + /* notifiers */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); - return OPERATOR_FINISHED; - } - else { - /* couldn't remove due to some invalid data */ - return OPERATOR_CANCELLED; - } + return OPERATOR_FINISHED; + } + else { + /* couldn't remove due to some invalid data */ + return OPERATOR_CANCELLED; + } } void CONSTRAINT_OT_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Constraint"; - ot->idname = "CONSTRAINT_OT_delete"; - ot->description = "Remove constraint from constraint stack"; + /* identifiers */ + ot->name = "Delete Constraint"; + ot->idname = "CONSTRAINT_OT_delete"; + ot->description = "Remove constraint from constraint stack"; - /* callbacks */ - ot->exec = constraint_delete_exec; - ot->poll = constraint_poll; + /* callbacks */ + ot->exec = constraint_delete_exec; + ot->poll = constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int constraint_move_down_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, 0); - if (con && con->next) { - ListBase *conlist = get_constraint_lb(ob, con, NULL); - bConstraint *nextCon = con->next; + if (con && con->next) { + ListBase *conlist = get_constraint_lb(ob, con, NULL); + bConstraint *nextCon = con->next; - /* insert the nominated constraint after the one that used to be after it */ - BLI_remlink(conlist, con); - BLI_insertlinkafter(conlist, nextCon, con); + /* insert the nominated constraint after the one that used to be after it */ + BLI_remlink(conlist, con); + BLI_insertlinkafter(conlist, nextCon, con); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return constraint_move_down_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return constraint_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_move_down(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Move Constraint Down"; - ot->idname = "CONSTRAINT_OT_move_down"; - ot->description = "Move constraint down in constraint stack"; + /* identifiers */ + ot->name = "Move Constraint Down"; + ot->idname = "CONSTRAINT_OT_move_down"; + ot->description = "Move constraint down in constraint stack"; - /* callbacks */ - ot->invoke = constraint_move_down_invoke; - ot->exec = constraint_move_down_exec; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->invoke = constraint_move_down_invoke; + ot->exec = constraint_move_down_exec; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - edit_constraint_properties(ot); + /* properties */ + edit_constraint_properties(ot); } - static int constraint_move_up_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - bConstraint *con = edit_constraint_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, 0); - if (con && con->prev) { - ListBase *conlist = get_constraint_lb(ob, con, NULL); - bConstraint *prevCon = con->prev; + if (con && con->prev) { + ListBase *conlist = get_constraint_lb(ob, con, NULL); + bConstraint *prevCon = con->prev; - /* insert the nominated constraint before the one that used to be before it */ - BLI_remlink(conlist, con); - BLI_insertlinkbefore(conlist, prevCon, con); + /* insert the nominated constraint before the one that used to be before it */ + BLI_remlink(conlist, con); + BLI_insertlinkbefore(conlist, prevCon, con); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) - return constraint_move_up_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_constraint_invoke_properties(C, op)) + return constraint_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; } void CONSTRAINT_OT_move_up(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Move Constraint Up"; - ot->idname = "CONSTRAINT_OT_move_up"; - ot->description = "Move constraint up in constraint stack"; + /* identifiers */ + ot->name = "Move Constraint Up"; + ot->idname = "CONSTRAINT_OT_move_up"; + ot->description = "Move constraint up in constraint stack"; - /* callbacks */ - ot->exec = constraint_move_up_exec; - ot->invoke = constraint_move_up_invoke; - ot->poll = edit_constraint_poll; + /* callbacks */ + ot->exec = constraint_move_up_exec; + ot->invoke = constraint_move_up_invoke; + ot->poll = edit_constraint_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edit_constraint_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); } /***************************** OPERATORS ****************************/ @@ -1437,433 +1475,428 @@ void CONSTRAINT_OT_move_up(wmOperatorType *ot) static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Object *prev_ob = NULL; + Main *bmain = CTX_data_main(C); + Object *prev_ob = NULL; - /* free constraints for all selected bones */ - CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) - { - BKE_constraints_free(&pchan->constraints); - pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST); + /* free constraints for all selected bones */ + CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) + { + BKE_constraints_free(&pchan->constraints); + pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST); - if (prev_ob != ob) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); - prev_ob = ob; - } - } - CTX_DATA_END; + if (prev_ob != ob) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + prev_ob = ob; + } + } + CTX_DATA_END; - /* force depsgraph to get recalculated since relationships removed */ - DEG_relations_tag_update(bmain); + /* force depsgraph to get recalculated since relationships removed */ + DEG_relations_tag_update(bmain); - /* note, calling BIK_clear_data() isn't needed here */ + /* note, calling BIK_clear_data() isn't needed here */ - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void POSE_OT_constraints_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Pose Constraints"; - ot->idname = "POSE_OT_constraints_clear"; - ot->description = "Clear all the constraints for the selected bones"; + /* identifiers */ + ot->name = "Clear Pose Constraints"; + ot->idname = "POSE_OT_constraints_clear"; + ot->description = "Clear all the constraints for the selected bones"; - /* callbacks */ - ot->exec = pose_constraints_clear_exec; - ot->poll = ED_operator_posemode_exclusive; // XXX - do we want to ensure there are selected bones too? + /* callbacks */ + ot->exec = pose_constraints_clear_exec; + ot->poll = + ED_operator_posemode_exclusive; // XXX - do we want to ensure there are selected bones too? } - static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main(C); - /* do freeing */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - BKE_constraints_free(&ob->constraints); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - CTX_DATA_END; + /* do freeing */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + BKE_constraints_free(&ob->constraints); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + CTX_DATA_END; - /* force depsgraph to get recalculated since relationships removed */ - DEG_relations_tag_update(bmain); + /* force depsgraph to get recalculated since relationships removed */ + DEG_relations_tag_update(bmain); - /* do updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, NULL); + /* do updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_constraints_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Object Constraints"; - ot->idname = "OBJECT_OT_constraints_clear"; - ot->description = "Clear all the constraints for the active Object only"; + /* identifiers */ + ot->name = "Clear Object Constraints"; + ot->idname = "OBJECT_OT_constraints_clear"; + ot->description = "Clear all the constraints for the active Object only"; - /* callbacks */ - ot->exec = object_constraints_clear_exec; - ot->poll = ED_operator_object_active_editable; + /* callbacks */ + ot->exec = object_constraints_clear_exec; + ot->poll = ED_operator_object_active_editable; } /************************ copy all constraints operators *********************/ static int pose_constraint_copy_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - bPoseChannel *pchan = CTX_data_active_pose_bone(C); + Main *bmain = CTX_data_main(C); + bPoseChannel *pchan = CTX_data_active_pose_bone(C); - /* don't do anything if bone doesn't exist or doesn't have any constraints */ - if (ELEM(NULL, pchan, pchan->constraints.first)) { - BKE_report(op->reports, RPT_ERROR, "No active bone with constraints for copying"); - return OPERATOR_CANCELLED; - } + /* don't do anything if bone doesn't exist or doesn't have any constraints */ + if (ELEM(NULL, pchan, pchan->constraints.first)) { + BKE_report(op->reports, RPT_ERROR, "No active bone with constraints for copying"); + return OPERATOR_CANCELLED; + } - Object *prev_ob = NULL; + Object *prev_ob = NULL; - /* copy all constraints from active posebone to all selected posebones */ - CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) - { - /* if we're not handling the object we're copying from, copy all constraints over */ - if (pchan != chan) { - BKE_constraints_copy(&chan->constraints, &pchan->constraints, true); - /* update flags (need to add here, not just copy) */ - chan->constflag |= pchan->constflag; + /* copy all constraints from active posebone to all selected posebones */ + CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) + { + /* if we're not handling the object we're copying from, copy all constraints over */ + if (pchan != chan) { + BKE_constraints_copy(&chan->constraints, &pchan->constraints, true); + /* update flags (need to add here, not just copy) */ + chan->constflag |= pchan->constflag; - if (prev_ob != ob) { - BKE_pose_tag_recalc(bmain, ob->pose); - DEG_id_tag_update((ID *)ob, ID_RECALC_GEOMETRY); - prev_ob = ob; - } - } - } - CTX_DATA_END; + if (prev_ob != ob) { + BKE_pose_tag_recalc(bmain, ob->pose); + DEG_id_tag_update((ID *)ob, ID_RECALC_GEOMETRY); + prev_ob = ob; + } + } + } + CTX_DATA_END; - /* force depsgraph to get recalculated since new relationships added */ - DEG_relations_tag_update(bmain); + /* force depsgraph to get recalculated since new relationships added */ + DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void POSE_OT_constraints_copy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Constraints to Selected Bones"; - ot->idname = "POSE_OT_constraints_copy"; - ot->description = "Copy constraints to other selected bones"; + /* identifiers */ + ot->name = "Copy Constraints to Selected Bones"; + ot->idname = "POSE_OT_constraints_copy"; + ot->description = "Copy constraints to other selected bones"; - /* api callbacks */ - ot->exec = pose_constraint_copy_exec; - ot->poll = ED_operator_posemode_exclusive; + /* api callbacks */ + ot->exec = pose_constraint_copy_exec; + ot->poll = ED_operator_posemode_exclusive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Object *obact = ED_object_active_context(C); + Main *bmain = CTX_data_main(C); + Object *obact = ED_object_active_context(C); - /* copy all constraints from active object to all selected objects */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - /* if we're not handling the object we're copying from, copy all constraints over */ - if (obact != ob) { - BKE_constraints_copy(&ob->constraints, &obact->constraints, true); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); - } - } - CTX_DATA_END; + /* copy all constraints from active object to all selected objects */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + /* if we're not handling the object we're copying from, copy all constraints over */ + if (obact != ob) { + BKE_constraints_copy(&ob->constraints, &obact->constraints, true); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); + } + } + CTX_DATA_END; - /* force depsgraph to get recalculated since new relationships added */ - DEG_relations_tag_update(bmain); + /* force depsgraph to get recalculated since new relationships added */ + DEG_relations_tag_update(bmain); - /* notifiers for updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL); + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_constraints_copy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Constraints to Selected Objects"; - ot->idname = "OBJECT_OT_constraints_copy"; - ot->description = "Copy constraints to other selected objects"; + /* identifiers */ + ot->name = "Copy Constraints to Selected Objects"; + ot->idname = "OBJECT_OT_constraints_copy"; + ot->description = "Copy constraints to other selected objects"; - /* api callbacks */ - ot->exec = object_constraint_copy_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->exec = object_constraint_copy_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ -static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) -{ - Object *obact = ED_object_active_context(C); - bPoseChannel *pchanact = BKE_pose_channel_active(obact); - bool only_curve = false, only_mesh = false, only_ob = false; - bool found = false; - - /* clear tar_ob and tar_pchan fields before use - * - assume for now that both always exist... - */ - *tar_ob = NULL; - *tar_pchan = NULL; - - /* check if constraint type doesn't requires a target - * - if so, no need to get any targets - */ - switch (con_type) { - /* no-target constraints --------------------------- */ - /* null constraint - shouldn't even be added! */ - case CONSTRAINT_TYPE_NULL: - /* limit constraints - no targets needed */ - case CONSTRAINT_TYPE_LOCLIMIT: - case CONSTRAINT_TYPE_ROTLIMIT: - case CONSTRAINT_TYPE_SIZELIMIT: - case CONSTRAINT_TYPE_SAMEVOL: - return false; - - /* restricted target-type constraints -------------- */ - /* NOTE: for these, we cannot try to add a target object if no valid ones are found, - * since that doesn't work */ - /* curve-based constraints - set the only_curve and only_ob flags */ - case CONSTRAINT_TYPE_CLAMPTO: - case CONSTRAINT_TYPE_FOLLOWPATH: - case CONSTRAINT_TYPE_SPLINEIK: - only_curve = true; - only_ob = true; - add = false; - break; - - /* mesh only? */ - case CONSTRAINT_TYPE_SHRINKWRAP: - only_mesh = true; - only_ob = true; - add = false; - break; - } - - /* if the active Object is Armature, and we can search for bones, do so... */ - if ((obact->type == OB_ARMATURE) && (only_ob == false)) { - /* search in list of selected Pose-Channels for target */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object) - { - /* just use the first one that we encounter, as long as it is not the active one */ - if (pchan != pchanact) { - *tar_ob = obact; - *tar_pchan = pchan; - found = true; - - break; - } - } - CTX_DATA_END; - } - - /* if not yet found, try selected Objects... */ - if (found == false) { - /* search in selected objects context */ - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - /* just use the first object we encounter (that isn't the active object) - * and which fulfills the criteria for the object-target that we've got - */ - if (ob != obact) { - /* for armatures in pose mode, look inside the armature for the active bone - * so that we set up cross-armature constraints with less effort - */ - if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && - (!only_curve && !only_mesh)) - { - /* just use the active bone, and assume that it is visible + usable */ - *tar_ob = ob; - *tar_pchan = BKE_pose_channel_active(ob); - found = true; - - break; - } - else if (((!only_curve) || (ob->type == OB_CURVE)) && - ((!only_mesh) || (ob->type == OB_MESH))) - { - /* set target */ - *tar_ob = ob; - found = true; - - /* perform some special operations on the target */ - if (only_curve) { - /* Curve-Path option must be enabled for follow-path constraints to be able to work */ - Curve *cu = (Curve *)ob->data; - cu->flag |= CU_PATH; - } - - break; - } - } - } - CTX_DATA_END; - } - - /* if still not found, add a new empty to act as a target (if allowed) */ - if ((found == false) && (add)) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = BASACT(view_layer); - Object *obt; - - /* add new target object */ - obt = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); - - /* transform cent to global coords for loc */ - if (pchanact) { - /* since by default, IK targets the tip of the last bone, use the tip of the active PoseChannel - * if adding a target for an IK Constraint - */ - if (con_type == CONSTRAINT_TYPE_KINEMATIC) - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_tail); - else - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_head); - } - else { - copy_v3_v3(obt->loc, obact->obmat[3]); - } - - /* restore, BKE_object_add sets active */ - BASACT(view_layer) = base; - base->flag |= BASE_SELECTED; - - /* make our new target the new object */ - *tar_ob = obt; - found = true; - } - - /* return whether there's any target */ - return found; +static bool get_new_constraint_target( + bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) +{ + Object *obact = ED_object_active_context(C); + bPoseChannel *pchanact = BKE_pose_channel_active(obact); + bool only_curve = false, only_mesh = false, only_ob = false; + bool found = false; + + /* clear tar_ob and tar_pchan fields before use + * - assume for now that both always exist... + */ + *tar_ob = NULL; + *tar_pchan = NULL; + + /* check if constraint type doesn't requires a target + * - if so, no need to get any targets + */ + switch (con_type) { + /* no-target constraints --------------------------- */ + /* null constraint - shouldn't even be added! */ + case CONSTRAINT_TYPE_NULL: + /* limit constraints - no targets needed */ + case CONSTRAINT_TYPE_LOCLIMIT: + case CONSTRAINT_TYPE_ROTLIMIT: + case CONSTRAINT_TYPE_SIZELIMIT: + case CONSTRAINT_TYPE_SAMEVOL: + return false; + + /* restricted target-type constraints -------------- */ + /* NOTE: for these, we cannot try to add a target object if no valid ones are found, + * since that doesn't work */ + /* curve-based constraints - set the only_curve and only_ob flags */ + case CONSTRAINT_TYPE_CLAMPTO: + case CONSTRAINT_TYPE_FOLLOWPATH: + case CONSTRAINT_TYPE_SPLINEIK: + only_curve = true; + only_ob = true; + add = false; + break; + + /* mesh only? */ + case CONSTRAINT_TYPE_SHRINKWRAP: + only_mesh = true; + only_ob = true; + add = false; + break; + } + + /* if the active Object is Armature, and we can search for bones, do so... */ + if ((obact->type == OB_ARMATURE) && (only_ob == false)) { + /* search in list of selected Pose-Channels for target */ + CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object) { + /* just use the first one that we encounter, as long as it is not the active one */ + if (pchan != pchanact) { + *tar_ob = obact; + *tar_pchan = pchan; + found = true; + + break; + } + } + CTX_DATA_END; + } + + /* if not yet found, try selected Objects... */ + if (found == false) { + /* search in selected objects context */ + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + /* just use the first object we encounter (that isn't the active object) + * and which fulfills the criteria for the object-target that we've got + */ + if (ob != obact) { + /* for armatures in pose mode, look inside the armature for the active bone + * so that we set up cross-armature constraints with less effort + */ + if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + (!only_curve && !only_mesh)) { + /* just use the active bone, and assume that it is visible + usable */ + *tar_ob = ob; + *tar_pchan = BKE_pose_channel_active(ob); + found = true; + + break; + } + else if (((!only_curve) || (ob->type == OB_CURVE)) && + ((!only_mesh) || (ob->type == OB_MESH))) { + /* set target */ + *tar_ob = ob; + found = true; + + /* perform some special operations on the target */ + if (only_curve) { + /* Curve-Path option must be enabled for follow-path constraints to be able to work */ + Curve *cu = (Curve *)ob->data; + cu->flag |= CU_PATH; + } + + break; + } + } + } + CTX_DATA_END; + } + + /* if still not found, add a new empty to act as a target (if allowed) */ + if ((found == false) && (add)) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base = BASACT(view_layer); + Object *obt; + + /* add new target object */ + obt = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); + + /* transform cent to global coords for loc */ + if (pchanact) { + /* since by default, IK targets the tip of the last bone, use the tip of the active PoseChannel + * if adding a target for an IK Constraint + */ + if (con_type == CONSTRAINT_TYPE_KINEMATIC) + mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_tail); + else + mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_head); + } + else { + copy_v3_v3(obt->loc, obact->obmat[3]); + } + + /* restore, BKE_object_add sets active */ + BASACT(view_layer) = base; + base->flag |= BASE_SELECTED; + + /* make our new target the new object */ + *tar_ob = obt; + found = true; + } + + /* return whether there's any target */ + return found; } /* used by add constraint operators to add the constraint required */ -static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase *list, int type, const bool setTarget) -{ - Main *bmain = CTX_data_main(C); - bPoseChannel *pchan; - bConstraint *con; - - if (list == &ob->constraints) { - pchan = NULL; - } - else { - pchan = BKE_pose_channel_active(ob); - - /* ensure not to confuse object/pose adding */ - if (pchan == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active pose bone to add a constraint to"); - return OPERATOR_CANCELLED; - } - } - /* check if constraint to be added is valid for the given constraints stack */ - if (type == CONSTRAINT_TYPE_NULL) { - return OPERATOR_CANCELLED; - } - if ((type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } - if ((type == CONSTRAINT_TYPE_SPLINEIK) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "Spline IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } - - /* create a new constraint of the type required, and add it to the active/given constraints list */ - if (pchan) - con = BKE_constraint_add_for_pose(ob, pchan, NULL, type); - else - con = BKE_constraint_add_for_object(ob, NULL, type); - - /* get the first selected object/bone, and make that the target - * - apart from the buttons-window add buttons, we shouldn't add in this way - */ - if (setTarget) { - Object *tar_ob = NULL; - bPoseChannel *tar_pchan = NULL; - - /* get the target objects, adding them as need be */ - if (get_new_constraint_target(C, type, &tar_ob, &tar_pchan, 1)) { - /* method of setting target depends on the type of target we've got - * - by default, just set the first target (distinction here is only for multiple-targeted constraints) - */ - if (tar_pchan) - set_constraint_nth_target(con, tar_ob, tar_pchan->name, 0); - else - set_constraint_nth_target(con, tar_ob, "", 0); - } - } - - /* do type-specific tweaking to the constraint settings */ - switch (type) { - case CONSTRAINT_TYPE_PYTHON: /* FIXME: this code is not really valid anymore */ - { +static int constraint_add_exec( + bContext *C, wmOperator *op, Object *ob, ListBase *list, int type, const bool setTarget) +{ + Main *bmain = CTX_data_main(C); + bPoseChannel *pchan; + bConstraint *con; + + if (list == &ob->constraints) { + pchan = NULL; + } + else { + pchan = BKE_pose_channel_active(ob); + + /* ensure not to confuse object/pose adding */ + if (pchan == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active pose bone to add a constraint to"); + return OPERATOR_CANCELLED; + } + } + /* check if constraint to be added is valid for the given constraints stack */ + if (type == CONSTRAINT_TYPE_NULL) { + return OPERATOR_CANCELLED; + } + if ((type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints))) { + BKE_report(op->reports, RPT_ERROR, "IK constraint can only be added to bones"); + return OPERATOR_CANCELLED; + } + if ((type == CONSTRAINT_TYPE_SPLINEIK) && ((!pchan) || (list != &pchan->constraints))) { + BKE_report(op->reports, RPT_ERROR, "Spline IK constraint can only be added to bones"); + return OPERATOR_CANCELLED; + } + + /* create a new constraint of the type required, and add it to the active/given constraints list */ + if (pchan) + con = BKE_constraint_add_for_pose(ob, pchan, NULL, type); + else + con = BKE_constraint_add_for_object(ob, NULL, type); + + /* get the first selected object/bone, and make that the target + * - apart from the buttons-window add buttons, we shouldn't add in this way + */ + if (setTarget) { + Object *tar_ob = NULL; + bPoseChannel *tar_pchan = NULL; + + /* get the target objects, adding them as need be */ + if (get_new_constraint_target(C, type, &tar_ob, &tar_pchan, 1)) { + /* method of setting target depends on the type of target we've got + * - by default, just set the first target (distinction here is only for multiple-targeted constraints) + */ + if (tar_pchan) + set_constraint_nth_target(con, tar_ob, tar_pchan->name, 0); + else + set_constraint_nth_target(con, tar_ob, "", 0); + } + } + + /* do type-specific tweaking to the constraint settings */ + switch (type) { + case CONSTRAINT_TYPE_PYTHON: /* FIXME: this code is not really valid anymore */ + { #ifdef WITH_PYTHON - char *menustr; - int scriptint = 0; - /* popup a list of usable scripts */ - menustr = buildmenu_pyconstraints(bmain, NULL, &scriptint); - /* XXX scriptint = pupmenu(menustr); */ - MEM_freeN(menustr); - - /* only add constraint if a script was chosen */ - if (scriptint) { - /* add constraint */ - validate_pyconstraint_cb(bmain, con->data, &scriptint); - - /* make sure target allowance is set correctly */ - BPY_pyconstraint_update(ob, con); - } + char *menustr; + int scriptint = 0; + /* popup a list of usable scripts */ + menustr = buildmenu_pyconstraints(bmain, NULL, &scriptint); + /* XXX scriptint = pupmenu(menustr); */ + MEM_freeN(menustr); + + /* only add constraint if a script was chosen */ + if (scriptint) { + /* add constraint */ + validate_pyconstraint_cb(bmain, con->data, &scriptint); + + /* make sure target allowance is set correctly */ + BPY_pyconstraint_update(ob, con); + } #endif - break; - } - - default: - break; - } + break; + } - /* make sure all settings are valid - similar to above checks, but sometimes can be wrong */ - object_test_constraints(bmain, ob); + default: + break; + } - if (pchan) - BKE_pose_update_constraint_flags(ob->pose); + /* make sure all settings are valid - similar to above checks, but sometimes can be wrong */ + object_test_constraints(bmain, ob); + if (pchan) + BKE_pose_update_constraint_flags(ob->pose); - /* force depsgraph to get recalculated since new relationships added */ - DEG_relations_tag_update(bmain); + /* force depsgraph to get recalculated since new relationships added */ + DEG_relations_tag_update(bmain); - if ((ob->type == OB_ARMATURE) && (pchan)) { - BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */ - if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) { - /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded - * after calling `BKE_pose_rebuild()`, which causes T43872. - * XXX Temp hack until new depsgraph hopefully solves this. */ - DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); - } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); - } - else - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + if ((ob->type == OB_ARMATURE) && (pchan)) { + BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */ + if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) { + /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded + * after calling `BKE_pose_rebuild()`, which causes T43872. + * XXX Temp hack until new depsgraph hopefully solves this. */ + DEG_id_tag_update(&ob->id, ID_RECALC_ANIMATION); + } + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); + } + else + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - /* notifiers for updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob); + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* ------------------ */ @@ -1871,121 +1904,125 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase /* dummy operator callback */ static int object_constraint_add_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - int type = RNA_enum_get(op->ptr, "type"); - short with_targets = 0; + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); + short with_targets = 0; - if (!ob) { - BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to"); - return OPERATOR_CANCELLED; - } + if (!ob) { + BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to"); + return OPERATOR_CANCELLED; + } - /* hack: set constraint targets from selected objects in context is allowed when - * operator name included 'with_targets', since the menu doesn't allow multiple properties - */ - if (strstr(op->idname, "with_targets")) - with_targets = 1; + /* hack: set constraint targets from selected objects in context is allowed when + * operator name included 'with_targets', since the menu doesn't allow multiple properties + */ + if (strstr(op->idname, "with_targets")) + with_targets = 1; - return constraint_add_exec(C, op, ob, &ob->constraints, type, with_targets); + return constraint_add_exec(C, op, ob, &ob->constraints, type, with_targets); } /* dummy operator callback */ static int pose_constraint_add_exec(bContext *C, wmOperator *op) { - Object *ob = BKE_object_pose_armature_get(ED_object_active_context(C)); - int type = RNA_enum_get(op->ptr, "type"); - short with_targets = 0; + Object *ob = BKE_object_pose_armature_get(ED_object_active_context(C)); + int type = RNA_enum_get(op->ptr, "type"); + short with_targets = 0; - if (!ob) { - BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to"); - return OPERATOR_CANCELLED; - } + if (!ob) { + BKE_report(op->reports, RPT_ERROR, "No active object to add constraint to"); + return OPERATOR_CANCELLED; + } - /* hack: set constraint targets from selected objects in context is allowed when - * operator name included 'with_targets', since the menu doesn't allow multiple properties - */ - if (strstr(op->idname, "with_targets")) - with_targets = 1; + /* hack: set constraint targets from selected objects in context is allowed when + * operator name included 'with_targets', since the menu doesn't allow multiple properties + */ + if (strstr(op->idname, "with_targets")) + with_targets = 1; - return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets); + return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets); } /* ------------------ */ void OBJECT_OT_constraint_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Constraint"; - ot->description = "Add a constraint to the active object"; - ot->idname = "OBJECT_OT_constraint_add"; + /* identifiers */ + ot->name = "Add Constraint"; + ot->description = "Add a constraint to the active object"; + ot->idname = "OBJECT_OT_constraint_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_constraint_add_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_constraint_add_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); } void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Constraint (with Targets)"; - ot->description = "Add a constraint to the active object, with target (where applicable) set to the selected Objects/Bones"; - ot->idname = "OBJECT_OT_constraint_add_with_targets"; + /* identifiers */ + ot->name = "Add Constraint (with Targets)"; + ot->description = + "Add a constraint to the active object, with target (where applicable) set to the selected " + "Objects/Bones"; + ot->idname = "OBJECT_OT_constraint_add_with_targets"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_constraint_add_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_constraint_add_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); } void POSE_OT_constraint_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Constraint"; - ot->description = "Add a constraint to the active bone"; - ot->idname = "POSE_OT_constraint_add"; + /* identifiers */ + ot->name = "Add Constraint"; + ot->description = "Add a constraint to the active bone"; + ot->idname = "POSE_OT_constraint_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = pose_constraint_add_exec; - ot->poll = ED_operator_posemode_exclusive; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = pose_constraint_add_exec; + ot->poll = ED_operator_posemode_exclusive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); } void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Constraint (with Targets)"; - ot->description = "Add a constraint to the active bone, with target (where applicable) set to the selected Objects/Bones"; - ot->idname = "POSE_OT_constraint_add_with_targets"; + /* identifiers */ + ot->name = "Add Constraint (with Targets)"; + ot->description = + "Add a constraint to the active bone, with target (where applicable) set to the selected " + "Objects/Bones"; + ot->idname = "POSE_OT_constraint_add_with_targets"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = pose_constraint_add_exec; - ot->poll = ED_operator_posemode_exclusive; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = pose_constraint_add_exec; + ot->poll = ED_operator_posemode_exclusive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); } /************************ IK Constraint operators *********************/ @@ -1995,83 +2032,93 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) /* present menu with options + validation for targets to use */ static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); - bConstraint *con = NULL; - - uiPopupMenu *pup; - uiLayout *layout; - Object *tar_ob = NULL; - bPoseChannel *tar_pchan = NULL; - - /* must have active bone */ - if (ELEM(NULL, ob, pchan)) { - BKE_report(op->reports, RPT_ERROR, "Must have an active bone to add IK constraint to"); - return OPERATOR_CANCELLED; - } - - /* bone must not have any constraints already */ - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC) break; - } - if (con) { - BKE_report(op->reports, RPT_ERROR, "Bone already has an IK constraint"); - return OPERATOR_CANCELLED; - } - - /* prepare popup menu to choose targeting options */ - pup = UI_popup_menu_begin(C, IFACE_("Add IK"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - /* the type of targets we'll set determines the menu entries to show... */ - if (get_new_constraint_target(C, CONSTRAINT_TYPE_KINEMATIC, &tar_ob, &tar_pchan, 0)) { - /* bone target, or object target? - * - the only thing that matters is that we want a target... - */ - if (tar_pchan) - uiItemBooleanO(layout, IFACE_("To Active Bone"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); - else - uiItemBooleanO(layout, IFACE_("To Active Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); - } - else { - /* we have a choice of adding to a new empty, or not setting any target (targetless IK) */ - uiItemBooleanO(layout, IFACE_("To New Empty Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); - uiItemBooleanO(layout, IFACE_("Without Targets"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 0); - } - - /* finish building the menu, and process it (should result in calling self again) */ - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + bPoseChannel *pchan = BKE_pose_channel_active(ob); + bConstraint *con = NULL; + + uiPopupMenu *pup; + uiLayout *layout; + Object *tar_ob = NULL; + bPoseChannel *tar_pchan = NULL; + + /* must have active bone */ + if (ELEM(NULL, ob, pchan)) { + BKE_report(op->reports, RPT_ERROR, "Must have an active bone to add IK constraint to"); + return OPERATOR_CANCELLED; + } + + /* bone must not have any constraints already */ + for (con = pchan->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_KINEMATIC) + break; + } + if (con) { + BKE_report(op->reports, RPT_ERROR, "Bone already has an IK constraint"); + return OPERATOR_CANCELLED; + } + + /* prepare popup menu to choose targeting options */ + pup = UI_popup_menu_begin(C, IFACE_("Add IK"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + + /* the type of targets we'll set determines the menu entries to show... */ + if (get_new_constraint_target(C, CONSTRAINT_TYPE_KINEMATIC, &tar_ob, &tar_pchan, 0)) { + /* bone target, or object target? + * - the only thing that matters is that we want a target... + */ + if (tar_pchan) + uiItemBooleanO( + layout, IFACE_("To Active Bone"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); + else + uiItemBooleanO( + layout, IFACE_("To Active Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); + } + else { + /* we have a choice of adding to a new empty, or not setting any target (targetless IK) */ + uiItemBooleanO( + layout, IFACE_("To New Empty Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1); + uiItemBooleanO( + layout, IFACE_("Without Targets"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 0); + } + + /* finish building the menu, and process it (should result in calling self again) */ + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; } /* call constraint_add_exec() to add the IK constraint */ static int pose_ik_add_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - const bool with_targets = RNA_boolean_get(op->ptr, "with_targets"); + Object *ob = CTX_data_active_object(C); + const bool with_targets = RNA_boolean_get(op->ptr, "with_targets"); - /* add the constraint - all necessary checks should have been done by the invoke() callback already... */ - return constraint_add_exec(C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets); + /* add the constraint - all necessary checks should have been done by the invoke() callback already... */ + return constraint_add_exec( + C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets); } void POSE_OT_ik_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add IK to Bone"; - ot->description = "Add IK Constraint to the active Bone"; - ot->idname = "POSE_OT_ik_add"; + /* identifiers */ + ot->name = "Add IK to Bone"; + ot->description = "Add IK Constraint to the active Bone"; + ot->idname = "POSE_OT_ik_add"; - /* api callbacks */ - ot->invoke = pose_ik_add_invoke; - ot->exec = pose_ik_add_exec; - ot->poll = ED_operator_posemode_exclusive; + /* api callbacks */ + ot->invoke = pose_ik_add_invoke; + ot->exec = pose_ik_add_exec; + ot->poll = ED_operator_posemode_exclusive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - RNA_def_boolean(ot->srna, "with_targets", 1, "With Targets", "Assign IK Constraint with targets derived from the select bones/objects"); + /* properties */ + RNA_def_boolean(ot->srna, + "with_targets", + 1, + "With Targets", + "Assign IK Constraint with targets derived from the select bones/objects"); } /* ------------------ */ @@ -2079,48 +2126,48 @@ void POSE_OT_ik_add(wmOperatorType *ot) /* remove IK constraints from selected bones */ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *prev_ob = NULL; + Object *prev_ob = NULL; - /* only remove IK Constraints */ - CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) - { - bConstraint *con, *next; + /* only remove IK Constraints */ + CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) + { + bConstraint *con, *next; - /* TODO: should we be checking if these constraints were local before we try and remove them? */ - for (con = pchan->constraints.first; con; con = next) { - next = con->next; - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - BKE_constraint_remove(&pchan->constraints, con); - } - } - pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET); + /* TODO: should we be checking if these constraints were local before we try and remove them? */ + for (con = pchan->constraints.first; con; con = next) { + next = con->next; + if (con->type == CONSTRAINT_TYPE_KINEMATIC) { + BKE_constraint_remove(&pchan->constraints, con); + } + } + pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET); - if (prev_ob != ob) { - prev_ob = ob; + if (prev_ob != ob) { + prev_ob = ob; - /* Refresh depsgraph. */ - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + /* Refresh depsgraph. */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - /* Note, notifier might evolve. */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); - } - } - CTX_DATA_END; + /* Note, notifier might evolve. */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + } + } + CTX_DATA_END; - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void POSE_OT_ik_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove IK"; - ot->description = "Remove all IK Constraints from selected bones"; - ot->idname = "POSE_OT_ik_clear"; + /* identifiers */ + ot->name = "Remove IK"; + ot->description = "Remove all IK Constraints from selected bones"; + ot->idname = "POSE_OT_ik_clear"; - /* api callbacks */ - ot->exec = pose_ik_clear_exec; - ot->poll = ED_operator_posemode_exclusive; + /* api callbacks */ + ot->exec = pose_ik_clear_exec; + ot->poll = ED_operator_posemode_exclusive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 52b60793585..57c7ff1535d 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -58,402 +58,463 @@ * Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */ /* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */ static const EnumPropertyItem DT_layer_items[] = { - {0, "", 0, "Vertex Data", ""}, - {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"}, -#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */ - {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"}, + {0, "", 0, "Vertex Data", ""}, + {DT_TYPE_MDEFORMVERT, + "VGROUP_WEIGHTS", + 0, + "Vertex Group(s)", + "Transfer active or all vertex groups"}, +#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */ + {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"}, #endif -#if 0 /* XXX When SkinModifier is enabled, +#if 0 /* XXX When SkinModifier is enabled, * it seems to erase its own CD_MVERT_SKIN layer from final DM :( */ - {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, + {DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"}, #endif - {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, - {0, "", 0, "Edge Data", ""}, - {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, - {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, - {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"}, - {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, - {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, - {0, "", 0, "Face Corner Data", ""}, - {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, - {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, - {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, - {0, "", 0, "Face Data", ""}, - {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, - {DT_TYPE_FREESTYLE_FACE, "FREESTYLE_FACE", 0, "Freestyle Mark", "Transfer Freestyle face mark"}, - {0, NULL, 0, NULL, NULL}, + {DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"}, + {0, "", 0, "Edge Data", ""}, + {DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"}, + {DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"}, + {DT_TYPE_CREASE, "CREASE", 0, "Subsurf Crease", "Transfer crease values"}, + {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, + {DT_TYPE_FREESTYLE_EDGE, + "FREESTYLE_EDGE", + 0, + "Freestyle Mark", + "Transfer Freestyle edge mark"}, + {0, "", 0, "Face Corner Data", ""}, + {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, + {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, + {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, + {0, "", 0, "Face Data", ""}, + {DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"}, + {DT_TYPE_FREESTYLE_FACE, + "FREESTYLE_FACE", + 0, + "Freestyle Mark", + "Transfer Freestyle face mark"}, + {0, NULL, 0, NULL, NULL}, }; /* Note: rna_enum_dt_layers_select_src_items enum is from rna_modifier.c */ -static const EnumPropertyItem *dt_layers_select_src_itemf( - bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *dt_layers_select_src_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) { - if (!C) { /* needed for docs and i18n tools */ - return rna_enum_dt_layers_select_src_items; - } - - EnumPropertyItem *item = NULL, tmp_item = {0}; - int totitem = 0; - const int data_type = RNA_enum_get(ptr, "data_type"); - - Depsgraph *depsgraph = CTX_data_depsgraph(C); - - PropertyRNA *prop = RNA_struct_find_property(ptr, "use_reverse_transfer"); - const bool reverse_transfer = prop != NULL && RNA_property_boolean_get(ptr, prop); - const int layers_select_dst = reverse_transfer ? RNA_enum_get(ptr, "layers_select_src") : - RNA_enum_get(ptr, "layers_select_dst"); - - if (!reverse_transfer || layers_select_dst == DT_LAYERS_ACTIVE_DST || layers_select_dst >= 0) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC); - } - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC); - - - - if (data_type == DT_TYPE_MDEFORMVERT) { - Object *ob_src = CTX_data_active_object(C); - - if (BKE_object_pose_armature_get(ob_src)) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); - } - - if (ob_src) { - bDeformGroup *dg; - int i; - - RNA_enum_item_add_separator(&item, &totitem); - - for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = dg->name; - RNA_enum_item_add(&item, &totitem, &tmp_item); - } - } - } - else if (data_type == DT_TYPE_SHAPEKEY) { - /* TODO */ - } - else if (data_type == DT_TYPE_UV) { - Object *ob_src = CTX_data_active_object(C); - - if (ob_src) { - Mesh *me_eval; - int num_data, i; - - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - - CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; - cddata_masks.lmask |= CD_MASK_MLOOPUV; - me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); - num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV); - - RNA_enum_item_add_separator(&item, &totitem); - - for (i = 0; i < num_data; i++) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPUV, i); - RNA_enum_item_add(&item, &totitem, &tmp_item); - } - } - } - else if (data_type == DT_TYPE_VCOL) { - Object *ob_src = CTX_data_active_object(C); - - if (ob_src) { - Mesh *me_eval; - int num_data, i; - - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - - CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; - cddata_masks.lmask |= CD_MASK_MLOOPCOL; - me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); - num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL); - - RNA_enum_item_add_separator(&item, &totitem); - - for (i = 0; i < num_data; i++) { - tmp_item.value = i; - tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPCOL, i); - RNA_enum_item_add(&item, &totitem, &tmp_item); - } - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + if (!C) { /* needed for docs and i18n tools */ + return rna_enum_dt_layers_select_src_items; + } + + EnumPropertyItem *item = NULL, tmp_item = {0}; + int totitem = 0; + const int data_type = RNA_enum_get(ptr, "data_type"); + + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + PropertyRNA *prop = RNA_struct_find_property(ptr, "use_reverse_transfer"); + const bool reverse_transfer = prop != NULL && RNA_property_boolean_get(ptr, prop); + const int layers_select_dst = reverse_transfer ? RNA_enum_get(ptr, "layers_select_src") : + RNA_enum_get(ptr, "layers_select_dst"); + + if (!reverse_transfer || layers_select_dst == DT_LAYERS_ACTIVE_DST || layers_select_dst >= 0) { + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC); + } + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC); + + if (data_type == DT_TYPE_MDEFORMVERT) { + Object *ob_src = CTX_data_active_object(C); + + if (BKE_object_pose_armature_get(ob_src)) { + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); + } + + if (ob_src) { + bDeformGroup *dg; + int i; + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = dg->name; + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_SHAPEKEY) { + /* TODO */ + } + else if (data_type == DT_TYPE_UV) { + Object *ob_src = CTX_data_active_object(C); + + if (ob_src) { + Mesh *me_eval; + int num_data, i; + + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + + CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; + cddata_masks.lmask |= CD_MASK_MLOOPUV; + me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); + num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( + &me_eval->ldata, CD_MLOOPUV, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + else if (data_type == DT_TYPE_VCOL) { + Object *ob_src = CTX_data_active_object(C); + + if (ob_src) { + Mesh *me_eval; + int num_data, i; + + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + + CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH; + cddata_masks.lmask |= CD_MASK_MLOOPCOL; + me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_src_eval, &cddata_masks); + num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL); + + RNA_enum_item_add_separator(&item, &totitem); + + for (i = 0; i < num_data; i++) { + tmp_item.value = i; + tmp_item.identifier = tmp_item.name = CustomData_get_layer_name( + &me_eval->ldata, CD_MLOOPCOL, i); + RNA_enum_item_add(&item, &totitem, &tmp_item); + } + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } /* Note: rna_enum_dt_layers_select_dst_items enum is from rna_modifier.c */ -static const EnumPropertyItem *dt_layers_select_dst_itemf( - bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *dt_layers_select_dst_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) { - if (!C) { /* needed for docs and i18n tools */ - return rna_enum_dt_layers_select_dst_items; - } + if (!C) { /* needed for docs and i18n tools */ + return rna_enum_dt_layers_select_dst_items; + } - EnumPropertyItem *item = NULL; - int totitem = 0; + EnumPropertyItem *item = NULL; + int totitem = 0; - PropertyRNA *prop = RNA_struct_find_property(ptr, "use_reverse_transfer"); - const bool reverse_transfer = prop != NULL && RNA_property_boolean_get(ptr, prop); - const int layers_select_src = reverse_transfer ? RNA_enum_get(ptr, "layers_select_dst") : - RNA_enum_get(ptr, "layers_select_src"); + PropertyRNA *prop = RNA_struct_find_property(ptr, "use_reverse_transfer"); + const bool reverse_transfer = prop != NULL && RNA_property_boolean_get(ptr, prop); + const int layers_select_src = reverse_transfer ? RNA_enum_get(ptr, "layers_select_dst") : + RNA_enum_get(ptr, "layers_select_src"); - if (reverse_transfer || layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST); - } - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_INDEX_DST); + if (reverse_transfer || layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) { + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST); + } + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST); + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_INDEX_DST); - /* No 'specific' to-layers here, since we may transfer to several objects at once! */ + /* No 'specific' to-layers here, since we may transfer to several objects at once! */ - RNA_enum_item_end(&item, &totitem); - *r_free = true; + RNA_enum_item_end(&item, &totitem); + *r_free = true; - return item; + return item; } -static const EnumPropertyItem *dt_layers_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free) +static const EnumPropertyItem *dt_layers_select_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *prop, + bool *r_free) { - const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer"); - - if (STREQ(RNA_property_identifier(prop), "layers_select_dst")) { - if (reverse_transfer) { - return dt_layers_select_src_itemf(C, ptr, prop, r_free); - } - else { - return dt_layers_select_dst_itemf(C, ptr, prop, r_free); - } - } - else if (reverse_transfer) { - return dt_layers_select_dst_itemf(C, ptr, prop, r_free); - } - else { - return dt_layers_select_src_itemf(C, ptr, prop, r_free); - } + const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer"); + + if (STREQ(RNA_property_identifier(prop), "layers_select_dst")) { + if (reverse_transfer) { + return dt_layers_select_src_itemf(C, ptr, prop, r_free); + } + else { + return dt_layers_select_dst_itemf(C, ptr, prop, r_free); + } + } + else if (reverse_transfer) { + return dt_layers_select_dst_itemf(C, ptr, prop, r_free); + } + else { + return dt_layers_select_src_itemf(C, ptr, prop, r_free); + } } /* Note: rna_enum_dt_mix_mode_items enum is from rna_modifier.c */ -static const EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *dt_mix_mode_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) { - EnumPropertyItem *item = NULL; - int totitem = 0; + EnumPropertyItem *item = NULL; + int totitem = 0; - const int dtdata_type = RNA_enum_get(ptr, "data_type"); - bool support_advanced_mixing, support_threshold; + const int dtdata_type = RNA_enum_get(ptr, "data_type"); + bool support_advanced_mixing, support_threshold; - if (!C) { /* needed for docs and i18n tools */ - return rna_enum_dt_mix_mode_items; - } + if (!C) { /* needed for docs and i18n tools */ + return rna_enum_dt_mix_mode_items; + } - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER); + RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER); - BKE_object_data_transfer_get_dttypes_capacity(dtdata_type, &support_advanced_mixing, &support_threshold); + BKE_object_data_transfer_get_dttypes_capacity( + dtdata_type, &support_advanced_mixing, &support_threshold); - if (support_threshold) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD); - } + if (support_threshold) { + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD); + RNA_enum_items_add_value( + &item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD); + } - if (support_advanced_mixing) { - RNA_enum_item_add_separator(&item, &totitem); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MIX); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_ADD); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_SUB); - RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MUL); - } + if (support_advanced_mixing) { + RNA_enum_item_add_separator(&item, &totitem); + RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MIX); + RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_ADD); + RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_SUB); + RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MUL); + } - RNA_enum_item_end(&item, &totitem); - *r_free = true; + RNA_enum_item_end(&item, &totitem); + *r_free = true; - return item; + return item; } static bool data_transfer_check(bContext *UNUSED(C), wmOperator *op) { - const int layers_select_src = RNA_enum_get(op->ptr, "layers_select_src"); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "layers_select_dst"); - const int layers_select_dst = RNA_property_enum_get(op->ptr, prop); + const int layers_select_src = RNA_enum_get(op->ptr, "layers_select_src"); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "layers_select_dst"); + const int layers_select_dst = RNA_property_enum_get(op->ptr, prop); - /* TODO: check for invalid layers_src select modes too! */ + /* TODO: check for invalid layers_src select modes too! */ - if ((layers_select_src != DT_LAYERS_ACTIVE_SRC) && (layers_select_dst == DT_LAYERS_ACTIVE_DST)) { - RNA_property_enum_set(op->ptr, prop, DT_LAYERS_NAME_DST); - return true; - } + if ((layers_select_src != DT_LAYERS_ACTIVE_SRC) && (layers_select_dst == DT_LAYERS_ACTIVE_DST)) { + RNA_property_enum_set(op->ptr, prop, DT_LAYERS_NAME_DST); + return true; + } - return false; + return false; } /* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ -static void data_transfer_exec_preprocess_objects( - bContext *C, wmOperator *op, Object *ob_src, ListBase *ctx_objects, const bool reverse_transfer) +static void data_transfer_exec_preprocess_objects(bContext *C, + wmOperator *op, + Object *ob_src, + ListBase *ctx_objects, + const bool reverse_transfer) { - CollectionPointerLink *ctx_ob; - CTX_data_selected_editable_objects(C, ctx_objects); - - if (reverse_transfer) { - return; /* Nothing else to do in this case... */ - } - - for (ctx_ob = ctx_objects->first; ctx_ob; ctx_ob = ctx_ob->next) { - Object *ob = ctx_ob->ptr.data; - Mesh *me; - if ((ob == ob_src) || (ob->type != OB_MESH)) { - continue; - } - - me = ob->data; - if (ID_IS_LINKED(me)) { - /* Do not transfer to linked data, not supported. */ - BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified", - ob->id.name + 2, me->id.name + 2); - me->id.tag &= ~LIB_TAG_DOIT; - continue; - } - - me->id.tag |= LIB_TAG_DOIT; - } + CollectionPointerLink *ctx_ob; + CTX_data_selected_editable_objects(C, ctx_objects); + + if (reverse_transfer) { + return; /* Nothing else to do in this case... */ + } + + for (ctx_ob = ctx_objects->first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + Mesh *me; + if ((ob == ob_src) || (ob->type != OB_MESH)) { + continue; + } + + me = ob->data; + if (ID_IS_LINKED(me)) { + /* Do not transfer to linked data, not supported. */ + BKE_reportf(op->reports, + RPT_WARNING, + "Skipping object '%s', linked data '%s' cannot be modified", + ob->id.name + 2, + me->id.name + 2); + me->id.tag &= ~LIB_TAG_DOIT; + continue; + } + + me->id.tag |= LIB_TAG_DOIT; + } } /* Helper, used by both data_transfer_exec and datalayout_transfer_exec. */ -static bool data_transfer_exec_is_object_valid( - wmOperator *op, Object *ob_src, Object *ob_dst, const bool reverse_transfer) +static bool data_transfer_exec_is_object_valid(wmOperator *op, + Object *ob_src, + Object *ob_dst, + const bool reverse_transfer) { - Mesh *me; - if ((ob_dst == ob_src) || (ob_src->type != OB_MESH) || (ob_dst->type != OB_MESH)) { - return false; - } - - if (reverse_transfer) { - return true; - } - - me = ob_dst->data; - if (me->id.tag & LIB_TAG_DOIT) { - me->id.tag &= ~LIB_TAG_DOIT; - return true; - } - else if (!ID_IS_LINKED(me)) { - /* Do not apply transfer operation more than once. */ - /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ - BKE_reportf(op->reports, RPT_WARNING, - "Skipping object '%s', data '%s' has already been processed with a previous object", - ob_dst->id.name + 2, me->id.name + 2); - } - return false; + Mesh *me; + if ((ob_dst == ob_src) || (ob_src->type != OB_MESH) || (ob_dst->type != OB_MESH)) { + return false; + } + + if (reverse_transfer) { + return true; + } + + me = ob_dst->data; + if (me->id.tag & LIB_TAG_DOIT) { + me->id.tag &= ~LIB_TAG_DOIT; + return true; + } + else if (!ID_IS_LINKED(me)) { + /* Do not apply transfer operation more than once. */ + /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ + BKE_reportf( + op->reports, + RPT_WARNING, + "Skipping object '%s', data '%s' has already been processed with a previous object", + ob_dst->id.name + 2, + me->id.name + 2); + } + return false; } static int data_transfer_exec(bContext *C, wmOperator *op) { - Object *ob_src = ED_object_active_context(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - - ListBase ctx_objects; - CollectionPointerLink *ctx_ob_dst; - - bool changed = false; - - const bool is_frozen = RNA_boolean_get(op->ptr, "use_freeze"); - - const bool reverse_transfer = RNA_boolean_get(op->ptr, "use_reverse_transfer"); - - const int data_type = RNA_enum_get(op->ptr, "data_type"); - const bool use_create = RNA_boolean_get(op->ptr, "use_create"); - - const int map_vert_mode = RNA_enum_get(op->ptr, "vert_mapping"); - const int map_edge_mode = RNA_enum_get(op->ptr, "edge_mapping"); - const int map_loop_mode = RNA_enum_get(op->ptr, "loop_mapping"); - const int map_poly_mode = RNA_enum_get(op->ptr, "poly_mapping"); - - const bool use_auto_transform = RNA_boolean_get(op->ptr, "use_auto_transform"); - const bool use_object_transform = RNA_boolean_get(op->ptr, "use_object_transform"); - const bool use_max_distance = RNA_boolean_get(op->ptr, "use_max_distance"); - const float max_distance = use_max_distance ? RNA_float_get(op->ptr, "max_distance") : FLT_MAX; - const float ray_radius = RNA_float_get(op->ptr, "ray_radius"); - const float islands_precision = RNA_float_get(op->ptr, "islands_precision"); - - const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); - const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); - int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; - int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; - const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); - - const int mix_mode = RNA_enum_get(op->ptr, "mix_mode"); - const float mix_factor = RNA_float_get(op->ptr, "mix_factor"); - - SpaceTransform space_transform_data; - SpaceTransform *space_transform = (use_object_transform && !use_auto_transform) ? &space_transform_data : NULL; - - if (is_frozen) { - BKE_report(op->reports, RPT_INFO, - "Operator is frozen, changes to its settings won't take effect until you unfreeze it"); - return OPERATOR_FINISHED; - } - - if (reverse_transfer && ID_IS_LINKED(ob_src->data)) { - /* Do not transfer to linked data, not supported. */ - return OPERATOR_CANCELLED; - } - - if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { - layers_select_src[fromto_idx] = layers_src; - layers_select_dst[fromto_idx] = layers_dst; - } - - data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, reverse_transfer); - - for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { - Object *ob_dst = ctx_ob_dst->ptr.data; - - if (reverse_transfer) { - SWAP(Object *, ob_src, ob_dst); - } - - if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, reverse_transfer)) { - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - - if (space_transform) { - Object *ob_dst_eval = DEG_get_evaluated_object(depsgraph, ob_dst); - BLI_SPACE_TRANSFORM_SETUP(space_transform, ob_dst_eval, ob_src_eval); - } - - if (BKE_object_data_transfer_mesh( - depsgraph, scene_eval, ob_src_eval, ob_dst, data_type, use_create, - map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, - space_transform, use_auto_transform, - max_distance, ray_radius, islands_precision, - layers_select_src, layers_select_dst, - mix_mode, mix_factor, NULL, false, op->reports)) - { - changed = true; - } - } - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - - if (reverse_transfer) { - SWAP(Object *, ob_src, ob_dst); - } - } - - BLI_freelistN(&ctx_objects); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - -#if 0 /* TODO */ - /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */ - return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Object *ob_src = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + + ListBase ctx_objects; + CollectionPointerLink *ctx_ob_dst; + + bool changed = false; + + const bool is_frozen = RNA_boolean_get(op->ptr, "use_freeze"); + + const bool reverse_transfer = RNA_boolean_get(op->ptr, "use_reverse_transfer"); + + const int data_type = RNA_enum_get(op->ptr, "data_type"); + const bool use_create = RNA_boolean_get(op->ptr, "use_create"); + + const int map_vert_mode = RNA_enum_get(op->ptr, "vert_mapping"); + const int map_edge_mode = RNA_enum_get(op->ptr, "edge_mapping"); + const int map_loop_mode = RNA_enum_get(op->ptr, "loop_mapping"); + const int map_poly_mode = RNA_enum_get(op->ptr, "poly_mapping"); + + const bool use_auto_transform = RNA_boolean_get(op->ptr, "use_auto_transform"); + const bool use_object_transform = RNA_boolean_get(op->ptr, "use_object_transform"); + const bool use_max_distance = RNA_boolean_get(op->ptr, "use_max_distance"); + const float max_distance = use_max_distance ? RNA_float_get(op->ptr, "max_distance") : FLT_MAX; + const float ray_radius = RNA_float_get(op->ptr, "ray_radius"); + const float islands_precision = RNA_float_get(op->ptr, "islands_precision"); + + const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); + const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); + int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; + int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; + const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); + + const int mix_mode = RNA_enum_get(op->ptr, "mix_mode"); + const float mix_factor = RNA_float_get(op->ptr, "mix_factor"); + + SpaceTransform space_transform_data; + SpaceTransform *space_transform = (use_object_transform && !use_auto_transform) ? + &space_transform_data : + NULL; + + if (is_frozen) { + BKE_report( + op->reports, + RPT_INFO, + "Operator is frozen, changes to its settings won't take effect until you unfreeze it"); + return OPERATOR_FINISHED; + } + + if (reverse_transfer && ID_IS_LINKED(ob_src->data)) { + /* Do not transfer to linked data, not supported. */ + return OPERATOR_CANCELLED; + } + + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + layers_select_src[fromto_idx] = layers_src; + layers_select_dst[fromto_idx] = layers_dst; + } + + data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, reverse_transfer); + + for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { + Object *ob_dst = ctx_ob_dst->ptr.data; + + if (reverse_transfer) { + SWAP(Object *, ob_src, ob_dst); + } + + if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, reverse_transfer)) { + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + + if (space_transform) { + Object *ob_dst_eval = DEG_get_evaluated_object(depsgraph, ob_dst); + BLI_SPACE_TRANSFORM_SETUP(space_transform, ob_dst_eval, ob_src_eval); + } + + if (BKE_object_data_transfer_mesh(depsgraph, + scene_eval, + ob_src_eval, + ob_dst, + data_type, + use_create, + map_vert_mode, + map_edge_mode, + map_loop_mode, + map_poly_mode, + space_transform, + use_auto_transform, + max_distance, + ray_radius, + islands_precision, + layers_select_src, + layers_select_dst, + mix_mode, + mix_factor, + NULL, + false, + op->reports)) { + changed = true; + } + } + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + + if (reverse_transfer) { + SWAP(Object *, ob_src, ob_dst); + } + } + + BLI_freelistN(&ctx_objects); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + +#if 0 /* TODO */ + /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */ + return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; #else - (void)changed; - return OPERATOR_FINISHED; + (void)changed; + return OPERATOR_FINISHED; #endif } @@ -461,153 +522,233 @@ static int data_transfer_exec(bContext *C, wmOperator *op) /* Note this context poll is only really partial, it cannot check for all possible invalid cases. */ static bool data_transfer_poll(bContext *C) { - Object *ob = ED_object_active_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && ob->type == OB_MESH && data); + Object *ob = ED_object_active_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && ob->type == OB_MESH && data); } /* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ -static bool data_transfer_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +static bool data_transfer_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { - PointerRNA *ptr = op->ptr; - PropertyRNA *prop_other; - - const char *prop_id = RNA_property_identifier(prop); - const int data_type = RNA_enum_get(ptr, "data_type"); - bool use_auto_transform = false; - bool use_max_distance = false; - bool use_modifier = false; - - if ((prop_other = RNA_struct_find_property(ptr, "use_auto_transform"))) { - use_auto_transform = RNA_property_boolean_get(ptr, prop_other); - } - if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) { - use_max_distance = RNA_property_boolean_get(ptr, prop_other); - } - if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) { - use_modifier = RNA_property_is_set(ptr, prop_other); - } - - if (STREQ(prop_id, "modifier")) { - return use_modifier; - } - - if (use_modifier) { - /* Hide everything but 'modifier' property, if set. */ - return false; - } - - if (STREQ(prop_id, "use_object_transform") && use_auto_transform) { - return false; - } - if (STREQ(prop_id, "max_distance") && !use_max_distance) { - return false; - } - if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) { - return false; - } - - if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) { - return false; - } - if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) { - return false; - } - if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) { - return false; - } - if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) { - return false; - } - - if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) && - !DT_DATATYPE_IS_MULTILAYERS(data_type)) - { - return false; - } - - /* Else, show it! */ - return true; + PointerRNA *ptr = op->ptr; + PropertyRNA *prop_other; + + const char *prop_id = RNA_property_identifier(prop); + const int data_type = RNA_enum_get(ptr, "data_type"); + bool use_auto_transform = false; + bool use_max_distance = false; + bool use_modifier = false; + + if ((prop_other = RNA_struct_find_property(ptr, "use_auto_transform"))) { + use_auto_transform = RNA_property_boolean_get(ptr, prop_other); + } + if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) { + use_max_distance = RNA_property_boolean_get(ptr, prop_other); + } + if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) { + use_modifier = RNA_property_is_set(ptr, prop_other); + } + + if (STREQ(prop_id, "modifier")) { + return use_modifier; + } + + if (use_modifier) { + /* Hide everything but 'modifier' property, if set. */ + return false; + } + + if (STREQ(prop_id, "use_object_transform") && use_auto_transform) { + return false; + } + if (STREQ(prop_id, "max_distance") && !use_max_distance) { + return false; + } + if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) { + return false; + } + + if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) { + return false; + } + if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) { + return false; + } + if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) { + return false; + } + if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) { + return false; + } + + if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) && + !DT_DATATYPE_IS_MULTILAYERS(data_type)) { + return false; + } + + /* Else, show it! */ + return true; } /* Transfer mesh data from active to selected objects. */ void OBJECT_OT_data_transfer(wmOperatorType *ot) { - PropertyRNA *prop; - - /* Identifiers.*/ - ot->name = "Transfer Mesh Data"; - ot->idname = "OBJECT_OT_data_transfer"; - ot->description = "Transfer data layer(s) (weights, edge sharp, ...) from active to selected meshes"; - - /* API callbacks.*/ - ot->poll = data_transfer_poll; - ot->poll_property = data_transfer_poll_property; - ot->invoke = WM_menu_invoke; - ot->exec = data_transfer_exec; - ot->check = data_transfer_check; - - /* Flags.*/ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; - - /* Properties.*/ - prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer", - "Transfer from selected objects to active one"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - RNA_def_boolean(ot->srna, "use_freeze", false, "Freeze Operator", - "Prevent changes to settings to re-run the operator, " - "handy to change several things at once with heavy geometry"); - - /* Data type to transfer. */ - ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); - RNA_def_boolean(ot->srna, "use_create", true, "Create Data", "Add data layers on destination meshes if needed"); - - /* Mapping methods. */ - RNA_def_enum(ot->srna, "vert_mapping", rna_enum_dt_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping", - "Method used to map source vertices to destination ones"); - RNA_def_enum(ot->srna, "edge_mapping", rna_enum_dt_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping", - "Method used to map source edges to destination ones"); - RNA_def_enum(ot->srna, "loop_mapping", rna_enum_dt_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR, - "Face Corner Mapping", "Method used to map source faces' corners to destination ones"); - RNA_def_enum(ot->srna, "poly_mapping", rna_enum_dt_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping", - "Method used to map source faces to destination ones"); - - /* Mapping options and filtering. */ - RNA_def_boolean(ot->srna, "use_auto_transform", false, "Auto Transform", - "Automatically compute transformation to get the best possible match between source and " - "destination meshes (WARNING: results will never be as good as manual matching of objects)"); - RNA_def_boolean(ot->srna, "use_object_transform", true, "Object Transform", - "Evaluate source and destination meshes in global space"); - RNA_def_boolean(ot->srna, "use_max_distance", false, "Only Neighbor Geometry", - "Source elements must be closer than given distance from destination one"); - prop = RNA_def_float(ot->srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance", - "Maximum allowed distance between source and destination element, for non-topology mappings", - 0.0f, 100.0f); - RNA_def_property_subtype(prop, PROP_DISTANCE); - prop = RNA_def_float(ot->srna, "ray_radius", 0.0f, 0.0f, FLT_MAX, "Ray Radius", - "'Width' of rays (especially useful when raycasting against vertices or edges)", - 0.0f, 10.0f); - RNA_def_property_subtype(prop, PROP_DISTANCE); - prop = RNA_def_float(ot->srna, "islands_precision", 0.1f, 0.0f, 10.0f, "Islands Precision", - "Factor controlling precision of islands handling (the higher, the better the results)", - 0.0f, 1.0f); - RNA_def_property_subtype(prop, PROP_FACTOR); - - /* How to handle multi-layers types of data. */ - prop = RNA_def_enum(ot->srna, "layers_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, - "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); - - prop = RNA_def_enum(ot->srna, "layers_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, - "Destination Layers Matching", "How to match source and destination layers"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); - - prop = RNA_def_enum(ot->srna, "mix_mode", rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode", - "How to affect destination elements with source values"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf); - RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor", - "Factor to use when applying data to destination (exact behavior depends on mix mode)", 0.0f, 1.0f); + PropertyRNA *prop; + + /* Identifiers.*/ + ot->name = "Transfer Mesh Data"; + ot->idname = "OBJECT_OT_data_transfer"; + ot->description = + "Transfer data layer(s) (weights, edge sharp, ...) from active to selected meshes"; + + /* API callbacks.*/ + ot->poll = data_transfer_poll; + ot->poll_property = data_transfer_poll_property; + ot->invoke = WM_menu_invoke; + ot->exec = data_transfer_exec; + ot->check = data_transfer_check; + + /* Flags.*/ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; + + /* Properties.*/ + prop = RNA_def_boolean(ot->srna, + "use_reverse_transfer", + false, + "Reverse Transfer", + "Transfer from selected objects to active one"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + RNA_def_boolean(ot->srna, + "use_freeze", + false, + "Freeze Operator", + "Prevent changes to settings to re-run the operator, " + "handy to change several things at once with heavy geometry"); + + /* Data type to transfer. */ + ot->prop = RNA_def_enum( + ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, + "use_create", + true, + "Create Data", + "Add data layers on destination meshes if needed"); + + /* Mapping methods. */ + RNA_def_enum(ot->srna, + "vert_mapping", + rna_enum_dt_method_vertex_items, + MREMAP_MODE_VERT_NEAREST, + "Vertex Mapping", + "Method used to map source vertices to destination ones"); + RNA_def_enum(ot->srna, + "edge_mapping", + rna_enum_dt_method_edge_items, + MREMAP_MODE_EDGE_NEAREST, + "Edge Mapping", + "Method used to map source edges to destination ones"); + RNA_def_enum(ot->srna, + "loop_mapping", + rna_enum_dt_method_loop_items, + MREMAP_MODE_LOOP_NEAREST_POLYNOR, + "Face Corner Mapping", + "Method used to map source faces' corners to destination ones"); + RNA_def_enum(ot->srna, + "poly_mapping", + rna_enum_dt_method_poly_items, + MREMAP_MODE_POLY_NEAREST, + "Face Mapping", + "Method used to map source faces to destination ones"); + + /* Mapping options and filtering. */ + RNA_def_boolean( + ot->srna, + "use_auto_transform", + false, + "Auto Transform", + "Automatically compute transformation to get the best possible match between source and " + "destination meshes (WARNING: results will never be as good as manual matching of objects)"); + RNA_def_boolean(ot->srna, + "use_object_transform", + true, + "Object Transform", + "Evaluate source and destination meshes in global space"); + RNA_def_boolean(ot->srna, + "use_max_distance", + false, + "Only Neighbor Geometry", + "Source elements must be closer than given distance from destination one"); + prop = RNA_def_float( + ot->srna, + "max_distance", + 1.0f, + 0.0f, + FLT_MAX, + "Max Distance", + "Maximum allowed distance between source and destination element, for non-topology mappings", + 0.0f, + 100.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float( + ot->srna, + "ray_radius", + 0.0f, + 0.0f, + FLT_MAX, + "Ray Radius", + "'Width' of rays (especially useful when raycasting against vertices or edges)", + 0.0f, + 10.0f); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float( + ot->srna, + "islands_precision", + 0.1f, + 0.0f, + 10.0f, + "Islands Precision", + "Factor controlling precision of islands handling (the higher, the better the results)", + 0.0f, + 1.0f); + RNA_def_property_subtype(prop, PROP_FACTOR); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, + "layers_select_src", + rna_enum_dt_layers_select_src_items, + DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", + "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); + + prop = RNA_def_enum(ot->srna, + "layers_select_dst", + rna_enum_dt_layers_select_dst_items, + DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", + "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf); + + prop = RNA_def_enum(ot->srna, + "mix_mode", + rna_enum_dt_mix_mode_items, + CDT_MIX_TRANSFER, + "Mix Mode", + "How to affect destination elements with source values"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf); + RNA_def_float( + ot->srna, + "mix_factor", + 1.0f, + 0.0f, + 1.0f, + "Mix Factor", + "Factor to use when applying data to destination (exact behavior depends on mix mode)", + 0.0f, + 1.0f); } /******************************************************************************/ @@ -617,120 +758,147 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) static bool datalayout_transfer_poll(bContext *C) { - return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH)) || data_transfer_poll(C)); + return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH)) || + data_transfer_poll(C)); } static int datalayout_transfer_exec(bContext *C, wmOperator *op) { - Object *ob_act = ED_object_active_context(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - DataTransferModifierData *dtmd; - - dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer); - - /* If we have a modifier, we transfer data layout from this modifier's source object to active one. - * Else, we transfer data layout from active object to all selected ones. */ - if (dtmd) { - Object *ob_src = dtmd->ob_source; - Object *ob_dst = ob_act; - - const bool use_delete = false; /* Never when used from modifier, for now. */ - - if (!ob_src) { - return OPERATOR_CANCELLED; - } - - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - - BKE_object_data_transfer_layout(depsgraph, scene_eval, ob_src_eval, ob_dst, dtmd->data_types, use_delete, - dtmd->layers_select_src, dtmd->layers_select_dst); - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - } - else { - Object *ob_src = ob_act; - - ListBase ctx_objects; - CollectionPointerLink *ctx_ob_dst; - - const int data_type = RNA_enum_get(op->ptr, "data_type"); - const bool use_delete = RNA_boolean_get(op->ptr, "use_delete"); - - const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); - const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); - int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; - int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; - const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); - - if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { - layers_select_src[fromto_idx] = layers_src; - layers_select_dst[fromto_idx] = layers_dst; - } - - Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); - - data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, false); - - for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { - Object *ob_dst = ctx_ob_dst->ptr.data; - if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) { - BKE_object_data_transfer_layout(depsgraph, scene_eval, ob_src_eval, ob_dst, data_type, use_delete, - layers_select_src, layers_select_dst); - } - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - } - - BLI_freelistN(&ctx_objects); - } - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - - return OPERATOR_FINISHED; + Object *ob_act = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + DataTransferModifierData *dtmd; + + dtmd = (DataTransferModifierData *)edit_modifier_property_get( + op, ob_act, eModifierType_DataTransfer); + + /* If we have a modifier, we transfer data layout from this modifier's source object to active one. + * Else, we transfer data layout from active object to all selected ones. */ + if (dtmd) { + Object *ob_src = dtmd->ob_source; + Object *ob_dst = ob_act; + + const bool use_delete = false; /* Never when used from modifier, for now. */ + + if (!ob_src) { + return OPERATOR_CANCELLED; + } + + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + + BKE_object_data_transfer_layout(depsgraph, + scene_eval, + ob_src_eval, + ob_dst, + dtmd->data_types, + use_delete, + dtmd->layers_select_src, + dtmd->layers_select_dst); + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + } + else { + Object *ob_src = ob_act; + + ListBase ctx_objects; + CollectionPointerLink *ctx_ob_dst; + + const int data_type = RNA_enum_get(op->ptr, "data_type"); + const bool use_delete = RNA_boolean_get(op->ptr, "use_delete"); + + const int layers_src = RNA_enum_get(op->ptr, "layers_select_src"); + const int layers_dst = RNA_enum_get(op->ptr, "layers_select_dst"); + int layers_select_src[DT_MULTILAYER_INDEX_MAX] = {0}; + int layers_select_dst[DT_MULTILAYER_INDEX_MAX] = {0}; + const int fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(data_type); + + if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { + layers_select_src[fromto_idx] = layers_src; + layers_select_dst[fromto_idx] = layers_dst; + } + + Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src); + + data_transfer_exec_preprocess_objects(C, op, ob_src, &ctx_objects, false); + + for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) { + Object *ob_dst = ctx_ob_dst->ptr.data; + if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) { + BKE_object_data_transfer_layout(depsgraph, + scene_eval, + ob_src_eval, + ob_dst, + data_type, + use_delete, + layers_select_src, + layers_select_dst); + } + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + } + + BLI_freelistN(&ctx_objects); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; } static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { - return datalayout_transfer_exec(C, op); - } - else { - return WM_menu_invoke(C, op, event); - } + if (edit_modifier_invoke_properties(C, op)) { + return datalayout_transfer_exec(C, op); + } + else { + return WM_menu_invoke(C, op, event); + } } void OBJECT_OT_datalayout_transfer(wmOperatorType *ot) { - PropertyRNA *prop; - - ot->name = "Transfer Mesh Data Layout"; - ot->description = "Transfer layout of data layer(s) from active to selected meshes"; - ot->idname = "OBJECT_OT_datalayout_transfer"; - - ot->poll = datalayout_transfer_poll; - ot->poll_property = data_transfer_poll_property; - ot->invoke = datalayout_transfer_invoke; - ot->exec = datalayout_transfer_exec; - ot->check = data_transfer_check; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; - - /* Properties.*/ - edit_modifier_properties(ot); - - /* Data type to transfer. */ - ot->prop = RNA_def_enum(ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); - RNA_def_boolean(ot->srna, "use_delete", false, "Exact Match", - "Also delete some data layers from destination if necessary, so that it matches exactly source"); - - /* How to handle multi-layers types of data. */ - prop = RNA_def_enum(ot->srna, "layers_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC, - "Source Layers Selection", "Which layers to transfer, in case of multi-layers types"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); - - prop = RNA_def_enum(ot->srna, "layers_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST, - "Destination Layers Matching", "How to match source and destination layers"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); + PropertyRNA *prop; + + ot->name = "Transfer Mesh Data Layout"; + ot->description = "Transfer layout of data layer(s) from active to selected meshes"; + ot->idname = "OBJECT_OT_datalayout_transfer"; + + ot->poll = datalayout_transfer_poll; + ot->poll_property = data_transfer_poll_property; + ot->invoke = datalayout_transfer_invoke; + ot->exec = datalayout_transfer_exec; + ot->check = data_transfer_check; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; + + /* Properties.*/ + edit_modifier_properties(ot); + + /* Data type to transfer. */ + ot->prop = RNA_def_enum( + ot->srna, "data_type", DT_layer_items, 0, "Data Type", "Which data to transfer"); + RNA_def_boolean(ot->srna, + "use_delete", + false, + "Exact Match", + "Also delete some data layers from destination if necessary, so that it matches " + "exactly source"); + + /* How to handle multi-layers types of data. */ + prop = RNA_def_enum(ot->srna, + "layers_select_src", + rna_enum_dt_layers_select_src_items, + DT_LAYERS_ACTIVE_SRC, + "Source Layers Selection", + "Which layers to transfer, in case of multi-layers types"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf); + + prop = RNA_def_enum(ot->srna, + "layers_select_dst", + rna_enum_dt_layers_select_dst_items, + DT_LAYERS_ACTIVE_DST, + "Destination Layers Matching", + "How to match source and destination layers"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf); } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index ce1a7306773..4e532b0ab41 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -27,7 +27,7 @@ #include <time.h> #include <float.h> #include <ctype.h> -#include <stddef.h> //for offsetof +#include <stddef.h> //for offsetof #include "MEM_guardedalloc.h" @@ -114,285 +114,298 @@ /* prototypes */ typedef struct MoveToCollectionData MoveToCollectionData; -static void move_to_collection_menus_items(struct uiLayout *layout, struct MoveToCollectionData *menu); +static void move_to_collection_menus_items(struct uiLayout *layout, + struct MoveToCollectionData *menu); /* ************* XXX **************** */ -static void error(const char *UNUSED(arg)) {} +static void error(const char *UNUSED(arg)) +{ +} /* port over here */ -static void error_libdata(void) {} +static void error_libdata(void) +{ +} Object *ED_object_context(bContext *C) { - return CTX_data_pointer_get_type(C, "object", &RNA_Object).data; + return CTX_data_pointer_get_type(C, "object", &RNA_Object).data; } /* find the correct active object per context * note: context can be NULL when called from a enum with PROP_ENUM_NO_CONTEXT */ Object *ED_object_active_context(bContext *C) { - Object *ob = NULL; - if (C) { - ob = ED_object_context(C); - if (!ob) ob = CTX_data_active_object(C); - } - return ob; + Object *ob = NULL; + if (C) { + ob = ED_object_context(C); + if (!ob) + ob = CTX_data_active_object(C); + } + return ob; } /* ********************** object hiding *************************** */ static bool object_hide_poll(bContext *C) { - if (CTX_wm_space_outliner(C) != NULL) { - return ED_outliner_collections_editor_poll(C); - } - else { - return ED_operator_view3d_active(C); - } + if (CTX_wm_space_outliner(C) != NULL) { + return ED_outliner_collections_editor_poll(C); + } + else { + return ED_operator_view3d_active(C); + } } static int object_hide_view_clear_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool select = RNA_boolean_get(op->ptr, "select"); - bool changed = false; - - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (base->flag & BASE_HIDDEN) { - base->flag &= ~BASE_HIDDEN; - changed = true; - - if (select) { - /* We cannot call `ED_object_base_select` because - * base is not selectable while it is hidden. */ - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - } - } - } - - if (!changed) { - return OPERATOR_CANCELLED; - } - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool select = RNA_boolean_get(op->ptr, "select"); + bool changed = false; + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->flag & BASE_HIDDEN) { + base->flag &= ~BASE_HIDDEN; + changed = true; + + if (select) { + /* We cannot call `ED_object_base_select` because + * base is not selectable while it is hidden. */ + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + } + } + } + + if (!changed) { + return OPERATOR_CANCELLED; + } + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } void OBJECT_OT_hide_view_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Show Hidden Objects"; - ot->description = "Reveal temporarily hidden objects"; - ot->idname = "OBJECT_OT_hide_view_clear"; + /* identifiers */ + ot->name = "Show Hidden Objects"; + ot->description = "Reveal temporarily hidden objects"; + ot->idname = "OBJECT_OT_hide_view_clear"; - /* api callbacks */ - ot->exec = object_hide_view_clear_exec; - ot->poll = object_hide_poll; + /* api callbacks */ + ot->exec = object_hide_view_clear_exec; + ot->poll = object_hide_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - PropertyRNA *prop = RNA_def_boolean(ot->srna, "select", true, "Select", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + PropertyRNA *prop = RNA_def_boolean(ot->srna, "select", true, "Select", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int object_hide_view_set_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool unselected = RNA_boolean_get(op->ptr, "unselected"); - bool changed = false; - - /* Hide selected or unselected objects. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (!(base->flag & BASE_VISIBLE)) { - continue; - } - - if (!unselected) { - if (base->flag & BASE_SELECTED) { - ED_object_base_select(base, BA_DESELECT); - base->flag |= BASE_HIDDEN; - changed = true; - } - } - else { - if (!(base->flag & BASE_SELECTED)) { - ED_object_base_select(base, BA_DESELECT); - base->flag |= BASE_HIDDEN; - changed = true; - } - } - } - if (!changed) { - return OPERATOR_CANCELLED; - } - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool unselected = RNA_boolean_get(op->ptr, "unselected"); + bool changed = false; + + /* Hide selected or unselected objects. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (!(base->flag & BASE_VISIBLE)) { + continue; + } + + if (!unselected) { + if (base->flag & BASE_SELECTED) { + ED_object_base_select(base, BA_DESELECT); + base->flag |= BASE_HIDDEN; + changed = true; + } + } + else { + if (!(base->flag & BASE_SELECTED)) { + ED_object_base_select(base, BA_DESELECT); + base->flag |= BASE_HIDDEN; + changed = true; + } + } + } + if (!changed) { + return OPERATOR_CANCELLED; + } + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } void OBJECT_OT_hide_view_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Objects"; - ot->description = "Temporarily hide objects from the viewport"; - ot->idname = "OBJECT_OT_hide_view_set"; - - /* api callbacks */ - ot->exec = object_hide_view_set_exec; - ot->poll = object_hide_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - PropertyRNA *prop; - prop = RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + /* identifiers */ + ot->name = "Hide Objects"; + ot->description = "Temporarily hide objects from the viewport"; + ot->idname = "OBJECT_OT_hide_view_set"; + + /* api callbacks */ + ot->exec = object_hide_view_set_exec; + ot->poll = object_hide_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + prop = RNA_def_boolean( + ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int object_hide_collection_exec(bContext *C, wmOperator *op) { - wmWindow *win = CTX_wm_window(C); + wmWindow *win = CTX_wm_window(C); - int index = RNA_int_get(op->ptr, "collection_index"); - const bool extend = (win->eventstate->shift != 0) || - RNA_boolean_get(op->ptr, "toggle"); + int index = RNA_int_get(op->ptr, "collection_index"); + const bool extend = (win->eventstate->shift != 0) || RNA_boolean_get(op->ptr, "toggle"); - if (win->eventstate->alt != 0) { - index += 10; - } + if (win->eventstate->alt != 0) { + index += 10; + } - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index); - if (!lc) { - return OPERATOR_CANCELLED; - } + if (!lc) { + return OPERATOR_CANCELLED; + } - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - if (BKE_layer_collection_isolate(scene, view_layer, lc, extend)) { - DEG_relations_tag_update(CTX_data_main(C)); - } + if (BKE_layer_collection_isolate(scene, view_layer, lc, extend)) { + DEG_relations_tag_update(CTX_data_main(C)); + } - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } #define COLLECTION_INVALID_INDEX -1 void ED_collection_hide_menu_draw(const bContext *C, uiLayout *layout) { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc_scene = view_layer->layer_collections.first; - - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); - - for (LayerCollection *lc = lc_scene->layer_collections.first; lc; lc = lc->next) { - int index = BKE_layer_collection_findindex(view_layer, lc); - uiLayout *row = uiLayoutRow(layout, false); - - if (lc->flag & LAYER_COLLECTION_EXCLUDE) { - continue; - } - - if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { - continue; - } - - int icon = ICON_NONE; - if (BKE_layer_collection_has_selected_objects(view_layer, lc)) { - icon = ICON_LAYER_ACTIVE; - } - else if (lc->runtime_flag & LAYER_COLLECTION_HAS_OBJECTS) { - icon = ICON_LAYER_USED; - } - - uiItemIntO(row, - lc->collection->id.name + 2, - icon, - "OBJECT_OT_hide_collection", - "collection_index", - index); - } + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *lc_scene = view_layer->layer_collections.first; + + uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); + + for (LayerCollection *lc = lc_scene->layer_collections.first; lc; lc = lc->next) { + int index = BKE_layer_collection_findindex(view_layer, lc); + uiLayout *row = uiLayoutRow(layout, false); + + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } + + if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { + continue; + } + + int icon = ICON_NONE; + if (BKE_layer_collection_has_selected_objects(view_layer, lc)) { + icon = ICON_LAYER_ACTIVE; + } + else if (lc->runtime_flag & LAYER_COLLECTION_HAS_OBJECTS) { + icon = ICON_LAYER_USED; + } + + uiItemIntO(row, + lc->collection->id.name + 2, + icon, + "OBJECT_OT_hide_collection", + "collection_index", + index); + } } static int object_hide_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - /* Immediately execute if collection index was specified. */ - int index = RNA_int_get(op->ptr, "collection_index"); - if (index != COLLECTION_INVALID_INDEX) { - return object_hide_collection_exec(C, op); - } + /* Immediately execute if collection index was specified. */ + int index = RNA_int_get(op->ptr, "collection_index"); + if (index != COLLECTION_INVALID_INDEX) { + return object_hide_collection_exec(C, op); + } - /* Open popup menu. */ - const char *title = CTX_IFACE_(op->type->translation_context, op->type->name); - uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_GROUP); - uiLayout *layout = UI_popup_menu_layout(pup); + /* Open popup menu. */ + const char *title = CTX_IFACE_(op->type->translation_context, op->type->name); + uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_GROUP); + uiLayout *layout = UI_popup_menu_layout(pup); - ED_collection_hide_menu_draw(C, layout); + ED_collection_hide_menu_draw(C, layout); - UI_popup_menu_end(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } void OBJECT_OT_hide_collection(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Collection"; - ot->description = "Show only objects in collection (Shift to extend)"; - ot->idname = "OBJECT_OT_hide_collection"; - - /* api callbacks */ - ot->exec = object_hide_collection_exec; - ot->invoke = object_hide_collection_invoke; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* Properties. */ - PropertyRNA *prop; - prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, - "Collection Index", "Index of the collection to change visibility", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle visibility"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + /* identifiers */ + ot->name = "Hide Collection"; + ot->description = "Show only objects in collection (Shift to extend)"; + ot->idname = "OBJECT_OT_hide_collection"; + + /* api callbacks */ + ot->exec = object_hide_collection_exec; + ot->invoke = object_hide_collection_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties. */ + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, + "collection_index", + COLLECTION_INVALID_INDEX, + COLLECTION_INVALID_INDEX, + INT_MAX, + "Collection Index", + "Index of the collection to change visibility", + 0, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle visibility"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } /* ******************* toggle editmode operator ***************** */ static bool mesh_needs_keyindex(Main *bmain, const Mesh *me) { - if (me->key) { - return false; /* will be added */ - } - - for (const Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { - return true; - } - if (ob->data == me) { - for (const ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - return true; - } - } - } - } - return false; + if (me->key) { + return false; /* will be added */ + } + + for (const Object *ob = bmain->objects.first; ob; ob = ob->id.next) { + if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { + return true; + } + if (ob->data == me) { + for (const ModifierData *md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Hook) { + return true; + } + } + } + } + return false; } /** @@ -401,96 +414,96 @@ static bool mesh_needs_keyindex(Main *bmain, const Mesh *me) */ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool freedata) { - if (obedit == NULL) { - return false; - } - - if (obedit->type == OB_MESH) { - Mesh *me = obedit->data; - if (me->edit_mesh == NULL) { - return false; - } - - if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) { - error("Too many vertices"); - return false; - } - - EDBM_mesh_load(bmain, obedit); - - if (freedata) { - EDBM_mesh_free(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh = NULL; - } - /* will be recalculated as needed. */ - { - ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); - ED_mesh_mirror_topo_table(NULL, NULL, 'e'); - } - } - else if (obedit->type == OB_ARMATURE) { - const bArmature *arm = obedit->data; - if (arm->edbo == NULL) { - return false; - } - ED_armature_from_edit(bmain, obedit->data); - if (freedata) { - ED_armature_edit_free(obedit->data); - } - /* TODO(sergey): Pose channels might have been changed, so need - * to inform dependency graph about this. But is it really the - * best place to do this? - */ - DEG_relations_tag_update(bmain); - } - else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { - const Curve *cu = obedit->data; - if (cu->editnurb == NULL) { - return false; - } - ED_curve_editnurb_load(bmain, obedit); - if (freedata) { - ED_curve_editnurb_free(obedit); - } - } - else if (obedit->type == OB_FONT) { - const Curve *cu = obedit->data; - if (cu->editfont == NULL) { - return false; - } - ED_curve_editfont_load(obedit); - if (freedata) { - ED_curve_editfont_free(obedit); - } - } - else if (obedit->type == OB_LATTICE) { - const Lattice *lt = obedit->data; - if (lt->editlatt == NULL) { - return false; - } - BKE_editlattice_load(obedit); - if (freedata) { - BKE_editlattice_free(obedit); - } - } - else if (obedit->type == OB_MBALL) { - const MetaBall *mb = obedit->data; - if (mb->editelems == NULL) { - return false; - } - ED_mball_editmball_load(obedit); - if (freedata) { - ED_mball_editmball_free(obedit); - } - } - - return true; + if (obedit == NULL) { + return false; + } + + if (obedit->type == OB_MESH) { + Mesh *me = obedit->data; + if (me->edit_mesh == NULL) { + return false; + } + + if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) { + error("Too many vertices"); + return false; + } + + EDBM_mesh_load(bmain, obedit); + + if (freedata) { + EDBM_mesh_free(me->edit_mesh); + MEM_freeN(me->edit_mesh); + me->edit_mesh = NULL; + } + /* will be recalculated as needed. */ + { + ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); + ED_mesh_mirror_topo_table(NULL, NULL, 'e'); + } + } + else if (obedit->type == OB_ARMATURE) { + const bArmature *arm = obedit->data; + if (arm->edbo == NULL) { + return false; + } + ED_armature_from_edit(bmain, obedit->data); + if (freedata) { + ED_armature_edit_free(obedit->data); + } + /* TODO(sergey): Pose channels might have been changed, so need + * to inform dependency graph about this. But is it really the + * best place to do this? + */ + DEG_relations_tag_update(bmain); + } + else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { + const Curve *cu = obedit->data; + if (cu->editnurb == NULL) { + return false; + } + ED_curve_editnurb_load(bmain, obedit); + if (freedata) { + ED_curve_editnurb_free(obedit); + } + } + else if (obedit->type == OB_FONT) { + const Curve *cu = obedit->data; + if (cu->editfont == NULL) { + return false; + } + ED_curve_editfont_load(obedit); + if (freedata) { + ED_curve_editfont_free(obedit); + } + } + else if (obedit->type == OB_LATTICE) { + const Lattice *lt = obedit->data; + if (lt->editlatt == NULL) { + return false; + } + BKE_editlattice_load(obedit); + if (freedata) { + BKE_editlattice_free(obedit); + } + } + else if (obedit->type == OB_MBALL) { + const MetaBall *mb = obedit->data; + if (mb->editelems == NULL) { + return false; + } + ED_mball_editmball_load(obedit); + if (freedata) { + ED_mball_editmball_free(obedit); + } + } + + return true; } bool ED_object_editmode_load(Main *bmain, Object *obedit) { - return ED_object_editmode_load_ex(bmain, obedit, false); + return ED_object_editmode_load_ex(bmain, obedit, false); } /** @@ -499,387 +512,379 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit) */ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag) { - const bool freedata = (flag & EM_FREEDATA) != 0; - - if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) { - /* in rare cases (background mode) its possible active object - * is flagged for editmode, without 'obedit' being set [#35489] */ - if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { - obedit->mode &= ~OB_MODE_EDIT; - } - return true; - } - - /* freedata only 0 now on file saves and render */ - if (freedata) { - ListBase pidlist; - PTCacheID *pid; - - /* flag object caches as outdated */ - BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); - for (pid = pidlist.first; pid; pid = pid->next) { - /* particles don't need reset on geometry change */ - if (pid->type != PTCACHE_TYPE_PARTICLES) { - pid->cache->flag |= PTCACHE_OUTDATED; - } - } - BLI_freelistN(&pidlist); - - BKE_particlesystem_reset_all(obedit); - BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED); - - /* also flush ob recalc, doesn't take much overhead, but used for particles */ - DEG_id_tag_update(&obedit->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); - - obedit->mode &= ~OB_MODE_EDIT; - } - - return (obedit->mode & OB_MODE_EDIT) == 0; + const bool freedata = (flag & EM_FREEDATA) != 0; + + if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) { + /* in rare cases (background mode) its possible active object + * is flagged for editmode, without 'obedit' being set [#35489] */ + if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { + obedit->mode &= ~OB_MODE_EDIT; + } + return true; + } + + /* freedata only 0 now on file saves and render */ + if (freedata) { + ListBase pidlist; + PTCacheID *pid; + + /* flag object caches as outdated */ + BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); + for (pid = pidlist.first; pid; pid = pid->next) { + /* particles don't need reset on geometry change */ + if (pid->type != PTCACHE_TYPE_PARTICLES) { + pid->cache->flag |= PTCACHE_OUTDATED; + } + } + BLI_freelistN(&pidlist); + + BKE_particlesystem_reset_all(obedit); + BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED); + + /* also flush ob recalc, doesn't take much overhead, but used for particles */ + DEG_id_tag_update(&obedit->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); + + obedit->mode &= ~OB_MODE_EDIT; + } + + return (obedit->mode & OB_MODE_EDIT) == 0; } bool ED_object_editmode_exit(bContext *C, int flag) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); } bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag) { - bool ok = false; - - if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob)) { - return false; - } - - /* this checks actual object->data, for cases when other scenes have it in editmode context */ - if (BKE_object_is_in_editmode(ob)) { - return true; - } - - if (BKE_object_obdata_is_libdata(ob)) { - error_libdata(); - return false; - } - - ob->restore_mode = ob->mode; - - ob->mode = OB_MODE_EDIT; - - if (ob->type == OB_MESH) { - BMEditMesh *em; - ok = 1; - - const bool use_key_index = mesh_needs_keyindex(bmain, ob->data); - - EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index); - - em = BKE_editmesh_from_object(ob); - if (LIKELY(em)) { - /* order doesn't matter */ - EDBM_mesh_normals_update(em); - BKE_editmesh_tessface_calc(em); - } - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL); - } - else if (ob->type == OB_ARMATURE) { - ok = 1; - ED_armature_to_edit(ob->data); - /* to ensure all goes in restposition and without striding */ - - /* XXX: should this be ID_RECALC_GEOMETRY? */ - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene); - } - else if (ob->type == OB_FONT) { - ok = 1; - ED_curve_editfont_make(ob); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); - } - else if (ob->type == OB_MBALL) { - ok = 1; - ED_mball_editmball_make(ob); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); - } - else if (ob->type == OB_LATTICE) { - ok = 1; - BKE_editlattice_make(ob); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene); - } - else if (ob->type == OB_SURF || ob->type == OB_CURVE) { - ok = 1; - ED_curve_editnurb_make(ob); - - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene); - } - - if (ok) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - else { - if ((flag & EM_NO_CONTEXT) == 0) { - ob->mode &= ~OB_MODE_EDIT; - } - WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); - } - - return (ob->mode & OB_MODE_EDIT) != 0; + bool ok = false; + + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob)) { + return false; + } + + /* this checks actual object->data, for cases when other scenes have it in editmode context */ + if (BKE_object_is_in_editmode(ob)) { + return true; + } + + if (BKE_object_obdata_is_libdata(ob)) { + error_libdata(); + return false; + } + + ob->restore_mode = ob->mode; + + ob->mode = OB_MODE_EDIT; + + if (ob->type == OB_MESH) { + BMEditMesh *em; + ok = 1; + + const bool use_key_index = mesh_needs_keyindex(bmain, ob->data); + + EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index); + + em = BKE_editmesh_from_object(ob); + if (LIKELY(em)) { + /* order doesn't matter */ + EDBM_mesh_normals_update(em); + BKE_editmesh_tessface_calc(em); + } + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL); + } + else if (ob->type == OB_ARMATURE) { + ok = 1; + ED_armature_to_edit(ob->data); + /* to ensure all goes in restposition and without striding */ + + /* XXX: should this be ID_RECALC_GEOMETRY? */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene); + } + else if (ob->type == OB_FONT) { + ok = 1; + ED_curve_editfont_make(ob); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); + } + else if (ob->type == OB_MBALL) { + ok = 1; + ED_mball_editmball_make(ob); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); + } + else if (ob->type == OB_LATTICE) { + ok = 1; + BKE_editlattice_make(ob); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene); + } + else if (ob->type == OB_SURF || ob->type == OB_CURVE) { + ok = 1; + ED_curve_editnurb_make(ob); + + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene); + } + + if (ok) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + else { + if ((flag & EM_NO_CONTEXT) == 0) { + ob->mode &= ~OB_MODE_EDIT; + } + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); + } + + return (ob->mode & OB_MODE_EDIT) != 0; } bool ED_object_editmode_enter(bContext *C, int flag) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob; - - /* Active layer checked here for view3d, - * callers that don't want view context can call the extended version. */ - ob = CTX_data_active_object(C); - if ((ob == NULL) || ID_IS_LINKED(ob)) { - return false; - } - return ED_object_editmode_enter_ex(bmain, scene, ob, flag); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob; + + /* Active layer checked here for view3d, + * callers that don't want view context can call the extended version. */ + ob = CTX_data_active_object(C); + if ((ob == NULL) || ID_IS_LINKED(ob)) { + return false; + } + return ED_object_editmode_enter_ex(bmain, scene, ob, flag); } static int editmode_toggle_exec(bContext *C, wmOperator *op) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - const int mode_flag = OB_MODE_EDIT; - const bool is_mode_set = (CTX_data_edit_object(C) != NULL); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Object *obact = OBACT(view_layer); - - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } - - if (!is_mode_set) { - ED_object_editmode_enter(C, 0); - if (obact->mode & mode_flag) { - FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob) - { - if ((ob != obact) && (ob->type == obact->type)) { - ED_object_editmode_enter_ex(bmain, scene, ob, EM_NO_CONTEXT); - } - } - FOREACH_SELECTED_OBJECT_END; - } - } - else { - ED_object_editmode_exit(C, EM_FREEDATA); - if ((obact->mode & mode_flag) == 0) { - FOREACH_OBJECT_BEGIN(view_layer, ob) - { - if ((ob != obact) && (ob->type == obact->type)) { - ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); - } - } - FOREACH_OBJECT_END; - } - } - - ED_space_image_uv_sculpt_update(bmain, CTX_wm_manager(C), scene); - - WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); - - if (G.background == false) { - WM_toolsystem_update_from_context_view3d(C); - } - - return OPERATOR_FINISHED; + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + const int mode_flag = OB_MODE_EDIT; + const bool is_mode_set = (CTX_data_edit_object(C) != NULL); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Object *obact = OBACT(view_layer); + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (!is_mode_set) { + ED_object_editmode_enter(C, 0); + if (obact->mode & mode_flag) { + FOREACH_SELECTED_OBJECT_BEGIN (view_layer, v3d, ob) { + if ((ob != obact) && (ob->type == obact->type)) { + ED_object_editmode_enter_ex(bmain, scene, ob, EM_NO_CONTEXT); + } + } + FOREACH_SELECTED_OBJECT_END; + } + } + else { + ED_object_editmode_exit(C, EM_FREEDATA); + if ((obact->mode & mode_flag) == 0) { + FOREACH_OBJECT_BEGIN (view_layer, ob) { + if ((ob != obact) && (ob->type == obact->type)) { + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); + } + } + FOREACH_OBJECT_END; + } + } + + ED_space_image_uv_sculpt_update(bmain, CTX_wm_manager(C), scene); + + WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); + + if (G.background == false) { + WM_toolsystem_update_from_context_view3d(C); + } + + return OPERATOR_FINISHED; } static bool editmode_toggle_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - /* covers proxies too */ - if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob->data)) - return 0; + /* covers proxies too */ + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob->data)) + return 0; - /* if hidden but in edit mode, we still display */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { - return 0; - } + /* if hidden but in edit mode, we still display */ + if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { + return 0; + } - return OB_TYPE_SUPPORT_EDITMODE(ob->type); + return OB_TYPE_SUPPORT_EDITMODE(ob->type); } void OBJECT_OT_editmode_toggle(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Editmode"; - ot->description = "Toggle object's editmode"; - ot->idname = "OBJECT_OT_editmode_toggle"; + /* identifiers */ + ot->name = "Toggle Editmode"; + ot->description = "Toggle object's editmode"; + ot->idname = "OBJECT_OT_editmode_toggle"; - /* api callbacks */ - ot->exec = editmode_toggle_exec; - ot->poll = editmode_toggle_poll; + /* api callbacks */ + ot->exec = editmode_toggle_exec; + ot->poll = editmode_toggle_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* *************************** */ static int posemode_exec(bContext *C, wmOperator *op) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Base *base = CTX_data_active_base(C); - - /* If the base is NULL it means we have an active object, but the object itself is hidden. */ - if (base == NULL) { - return OPERATOR_CANCELLED; - } - - Object *obact = base->object; - const int mode_flag = OB_MODE_POSE; - bool is_mode_set = (obact->mode & mode_flag) != 0; - - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } - - if (obact->type != OB_ARMATURE) { - return OPERATOR_PASS_THROUGH; - } - - if (obact == CTX_data_edit_object(C)) { - ED_object_editmode_exit(C, EM_FREEDATA); - is_mode_set = false; - } - - if (is_mode_set) { - bool ok = ED_object_posemode_exit(C, obact); - if (ok) { - struct Main *bmain = CTX_data_main(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - FOREACH_OBJECT_BEGIN(view_layer, ob) - { - if ((ob != obact) && - (ob->type == OB_ARMATURE) && - (ob->mode & mode_flag)) - { - ED_object_posemode_exit_ex(bmain, ob); - } - } - FOREACH_OBJECT_END; - } - } - else { - bool ok = ED_object_posemode_enter(C, obact); - if (ok) { - struct Main *bmain = CTX_data_main(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob) - { - if ((ob != obact) && - (ob->type == OB_ARMATURE) && - (ob->mode == OB_MODE_OBJECT) && - (!ID_IS_LINKED(ob))) - { - ED_object_posemode_enter_ex(bmain, ob); - } - } - FOREACH_SELECTED_OBJECT_END; - } - } - - WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); - - if (G.background == false) { - WM_toolsystem_update_from_context_view3d(C); - } - - return OPERATOR_FINISHED; + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Base *base = CTX_data_active_base(C); + + /* If the base is NULL it means we have an active object, but the object itself is hidden. */ + if (base == NULL) { + return OPERATOR_CANCELLED; + } + + Object *obact = base->object; + const int mode_flag = OB_MODE_POSE; + bool is_mode_set = (obact->mode & mode_flag) != 0; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (obact->type != OB_ARMATURE) { + return OPERATOR_PASS_THROUGH; + } + + if (obact == CTX_data_edit_object(C)) { + ED_object_editmode_exit(C, EM_FREEDATA); + is_mode_set = false; + } + + if (is_mode_set) { + bool ok = ED_object_posemode_exit(C, obact); + if (ok) { + struct Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_BEGIN (view_layer, ob) { + if ((ob != obact) && (ob->type == OB_ARMATURE) && (ob->mode & mode_flag)) { + ED_object_posemode_exit_ex(bmain, ob); + } + } + FOREACH_OBJECT_END; + } + } + else { + bool ok = ED_object_posemode_enter(C, obact); + if (ok) { + struct Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + FOREACH_SELECTED_OBJECT_BEGIN (view_layer, v3d, ob) { + if ((ob != obact) && (ob->type == OB_ARMATURE) && (ob->mode == OB_MODE_OBJECT) && + (!ID_IS_LINKED(ob))) { + ED_object_posemode_enter_ex(bmain, ob); + } + } + FOREACH_SELECTED_OBJECT_END; + } + } + + WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); + + if (G.background == false) { + WM_toolsystem_update_from_context_view3d(C); + } + + return OPERATOR_FINISHED; } void OBJECT_OT_posemode_toggle(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Pose Mode"; - ot->idname = "OBJECT_OT_posemode_toggle"; - ot->description = "Enable or disable posing/selecting bones"; + /* identifiers */ + ot->name = "Toggle Pose Mode"; + ot->idname = "OBJECT_OT_posemode_toggle"; + ot->description = "Enable or disable posing/selecting bones"; - /* api callbacks */ - ot->exec = posemode_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->exec = posemode_exec; + ot->poll = ED_operator_object_active_editable; - /* flag */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flag */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************* force field toggle operator ***************** */ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) { - PartDeflect *pd = object->pd; - ModifierData *md = modifiers_findByType(object, eModifierType_Surface); - - /* add/remove modifier as needed */ - if (!md) { - if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && !ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { - if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) { - ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); - } - } - } - else { - if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) || ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { - ED_object_modifier_remove(NULL, bmain, object, md); - } - } + PartDeflect *pd = object->pd; + ModifierData *md = modifiers_findByType(object, eModifierType_Surface); + + /* add/remove modifier as needed */ + if (!md) { + if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && + !ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { + if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) { + ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); + } + } + } + else { + if (!pd || (pd->shape != PFIELD_SHAPE_SURFACE) || + ELEM(pd->forcefield, 0, PFIELD_GUIDE, PFIELD_TEXTURE)) { + ED_object_modifier_remove(NULL, bmain, object, md); + } + } } static int forcefield_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (ob->pd == NULL) - ob->pd = BKE_partdeflect_new(PFIELD_FORCE); - else if (ob->pd->forcefield == 0) - ob->pd->forcefield = PFIELD_FORCE; - else - ob->pd->forcefield = 0; + if (ob->pd == NULL) + ob->pd = BKE_partdeflect_new(PFIELD_FORCE); + else if (ob->pd->forcefield == 0) + ob->pd->forcefield = PFIELD_FORCE; + else + ob->pd->forcefield = 0; - ED_object_check_force_modifiers(CTX_data_main(C), CTX_data_scene(C), ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + ED_object_check_force_modifiers(CTX_data_main(C), CTX_data_scene(C), ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_forcefield_toggle(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Force Field"; - ot->description = "Toggle object's force field"; - ot->idname = "OBJECT_OT_forcefield_toggle"; + /* identifiers */ + ot->name = "Toggle Force Field"; + ot->description = "Toggle object's force field"; + ot->idname = "OBJECT_OT_forcefield_toggle"; - /* api callbacks */ - ot->exec = forcefield_toggle_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->exec = forcefield_toggle_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ********************************************** */ @@ -892,156 +897,166 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot) */ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only) { - /* Transform doesn't always have context available to do update. */ - if (C == NULL) { - return; - } - - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ListBase targets = {NULL, NULL}; - - /* loop over objects in scene */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - /* set flag to force recalc, then grab path(s) from object */ - ob->avs.recalc |= ANIMVIZ_RECALC_PATHS; - animviz_get_object_motionpaths(ob, &targets); - } - CTX_DATA_END; - - /* recalculate paths, then free */ - animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only); - BLI_freelistN(&targets); - - if (!current_frame_only) { - /* Tag objects for copy on write - so paths will draw/redraw - * For currently frame only we update evaluated object directly. */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - if (ob->mpath) { - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - } - } - CTX_DATA_END; - } + /* Transform doesn't always have context available to do update. */ + if (C == NULL) { + return; + } + + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ListBase targets = {NULL, NULL}; + + /* loop over objects in scene */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + /* set flag to force recalc, then grab path(s) from object */ + ob->avs.recalc |= ANIMVIZ_RECALC_PATHS; + animviz_get_object_motionpaths(ob, &targets); + } + CTX_DATA_END; + + /* recalculate paths, then free */ + animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only); + BLI_freelistN(&targets); + + if (!current_frame_only) { + /* Tag objects for copy on write - so paths will draw/redraw + * For currently frame only we update evaluated object directly. */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob->mpath) { + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + } + } + CTX_DATA_END; + } } - /* show popup to determine settings */ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (ob == NULL) - return OPERATOR_CANCELLED; + if (ob == NULL) + return OPERATOR_CANCELLED; - /* set default settings from existing/stored settings */ - { - bAnimVizSettings *avs = &ob->avs; + /* set default settings from existing/stored settings */ + { + bAnimVizSettings *avs = &ob->avs; - RNA_int_set(op->ptr, "start_frame", avs->path_sf); - RNA_int_set(op->ptr, "end_frame", avs->path_ef); - } + RNA_int_set(op->ptr, "start_frame", avs->path_sf); + RNA_int_set(op->ptr, "end_frame", avs->path_ef); + } - /* show popup dialog to allow editing of range... */ - /* FIXME: hardcoded dimensions here are just arbitrary */ - return WM_operator_props_dialog_popup(C, op, 200, 200); + /* show popup dialog to allow editing of range... */ + /* FIXME: hardcoded dimensions here are just arbitrary */ + return WM_operator_props_dialog_popup(C, op, 200, 200); } /* Calculate/recalculate whole paths (avs.path_sf to avs.path_ef) */ static int object_calculate_paths_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - int start = RNA_int_get(op->ptr, "start_frame"); - int end = RNA_int_get(op->ptr, "end_frame"); + Scene *scene = CTX_data_scene(C); + int start = RNA_int_get(op->ptr, "start_frame"); + int end = RNA_int_get(op->ptr, "end_frame"); - /* set up path data for bones being calculated */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - bAnimVizSettings *avs = &ob->avs; + /* set up path data for bones being calculated */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + bAnimVizSettings *avs = &ob->avs; - /* grab baking settings from operator settings */ - avs->path_sf = start; - avs->path_ef = end; + /* grab baking settings from operator settings */ + avs->path_sf = start; + avs->path_ef = end; - /* verify that the selected object has the appropriate settings */ - animviz_verify_motionpaths(op->reports, scene, ob, NULL); - } - CTX_DATA_END; + /* verify that the selected object has the appropriate settings */ + animviz_verify_motionpaths(op->reports, scene, ob, NULL); + } + CTX_DATA_END; - /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene, false); + /* calculate the paths for objects that have them (and are tagged to get refreshed) */ + ED_objects_recalculate_paths(C, scene, false); - /* notifiers for updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_paths_calculate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Calculate Object Paths"; - ot->idname = "OBJECT_OT_paths_calculate"; - ot->description = "Calculate motion paths for the selected objects"; - - /* api callbacks */ - ot->invoke = object_calculate_paths_invoke; - ot->exec = object_calculate_paths_exec; - ot->poll = ED_operator_object_active_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start", - "First frame to calculate object paths on", MINFRAME, MAXFRAME / 2.0); - RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End", - "Last frame to calculate object paths on", MINFRAME, MAXFRAME / 2.0); + /* identifiers */ + ot->name = "Calculate Object Paths"; + ot->idname = "OBJECT_OT_paths_calculate"; + ot->description = "Calculate motion paths for the selected objects"; + + /* api callbacks */ + ot->invoke = object_calculate_paths_invoke; + ot->exec = object_calculate_paths_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, + "start_frame", + 1, + MINAFRAME, + MAXFRAME, + "Start", + "First frame to calculate object paths on", + MINFRAME, + MAXFRAME / 2.0); + RNA_def_int(ot->srna, + "end_frame", + 250, + MINAFRAME, + MAXFRAME, + "End", + "Last frame to calculate object paths on", + MINFRAME, + MAXFRAME / 2.0); } /* --------- */ static bool object_update_paths_poll(bContext *C) { - if (ED_operator_object_active_editable(C)) { - Object *ob = ED_object_active_context(C); - return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0; - } + if (ED_operator_object_active_editable(C)) { + Object *ob = ED_object_active_context(C); + return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0; + } - return false; + return false; } static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); - if (scene == NULL) - return OPERATOR_CANCELLED; + if (scene == NULL) + return OPERATOR_CANCELLED; - /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene, false); + /* calculate the paths for objects that have them (and are tagged to get refreshed) */ + ED_objects_recalculate_paths(C, scene, false); - /* notifiers for updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_paths_update(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Update Object Paths"; - ot->idname = "OBJECT_OT_paths_update"; - ot->description = "Recalculate paths for selected objects"; + /* identifiers */ + ot->name = "Update Object Paths"; + ot->idname = "OBJECT_OT_paths_update"; + ot->description = "Recalculate paths for selected objects"; - /* api callbakcs */ - ot->exec = object_update_paths_exec; - ot->poll = object_update_paths_poll; + /* api callbakcs */ + ot->exec = object_update_paths_exec; + ot->poll = object_update_paths_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* --------- */ @@ -1049,578 +1064,568 @@ void OBJECT_OT_paths_update(wmOperatorType *ot) /* Helper for ED_objects_clear_paths() */ static void object_clear_mpath(Object *ob) { - if (ob->mpath) { - animviz_free_motionpath(ob->mpath); - ob->mpath = NULL; - ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS; - - /* tag object for copy on write - so removed paths don't still show */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - } + if (ob->mpath) { + animviz_free_motionpath(ob->mpath); + ob->mpath = NULL; + ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS; + + /* tag object for copy on write - so removed paths don't still show */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + } } /* Clear motion paths for all objects */ void ED_objects_clear_paths(bContext *C, bool only_selected) { - if (only_selected) { - /* loop over all selected + sedtiable objects in scene */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - object_clear_mpath(ob); - } - CTX_DATA_END; - } - else { - /* loop over all edtiable objects in scene */ - CTX_DATA_BEGIN(C, Object *, ob, editable_objects) - { - object_clear_mpath(ob); - } - CTX_DATA_END; - } + if (only_selected) { + /* loop over all selected + sedtiable objects in scene */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + object_clear_mpath(ob); + } + CTX_DATA_END; + } + else { + /* loop over all edtiable objects in scene */ + CTX_DATA_BEGIN (C, Object *, ob, editable_objects) { + object_clear_mpath(ob); + } + CTX_DATA_END; + } } /* operator callback for this */ static int object_clear_paths_exec(bContext *C, wmOperator *op) { - bool only_selected = RNA_boolean_get(op->ptr, "only_selected"); + bool only_selected = RNA_boolean_get(op->ptr, "only_selected"); - /* use the backend function for this */ - ED_objects_clear_paths(C, only_selected); + /* use the backend function for this */ + ED_objects_clear_paths(C, only_selected); - /* notifiers for updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + /* notifiers for updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* operator callback/wrapper */ static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt) { - if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { - RNA_boolean_set(op->ptr, "only_selected", true); - } - return object_clear_paths_exec(C, op); + if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { + RNA_boolean_set(op->ptr, "only_selected", true); + } + return object_clear_paths_exec(C, op); } void OBJECT_OT_paths_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Object Paths"; - ot->idname = "OBJECT_OT_paths_clear"; - ot->description = "Clear path caches for all objects, hold Shift key for selected objects only"; - - /* api callbacks */ - ot->invoke = object_clear_paths_invoke; - ot->exec = object_clear_paths_exec; - ot->poll = ED_operator_object_active_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", - "Only clear paths from selected objects"); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + /* identifiers */ + ot->name = "Clear Object Paths"; + ot->idname = "OBJECT_OT_paths_clear"; + ot->description = "Clear path caches for all objects, hold Shift key for selected objects only"; + + /* api callbacks */ + ot->invoke = object_clear_paths_invoke; + ot->exec = object_clear_paths_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean( + ot->srna, "only_selected", false, "Only Selected", "Only clear paths from selected objects"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } /* --------- */ static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - - /* loop over all edtiable objects in scene */ - CTX_DATA_BEGIN(C, Object *, ob, editable_objects) - { - /* use Preview Range or Full Frame Range - whichever is in use */ - ob->avs.path_sf = PSFRA; - ob->avs.path_ef = PEFRA; - - /* tag for updates */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - } - CTX_DATA_END; - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + + /* loop over all edtiable objects in scene */ + CTX_DATA_BEGIN (C, Object *, ob, editable_objects) { + /* use Preview Range or Full Frame Range - whichever is in use */ + ob->avs.path_sf = PSFRA; + ob->avs.path_ef = PEFRA; + + /* tag for updates */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + } + CTX_DATA_END; + + return OPERATOR_FINISHED; } void OBJECT_OT_paths_range_update(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Update Range from Scene"; - ot->idname = "OBJECT_OT_paths_range_update"; - ot->description = "Update frame range for motion paths from the Scene's current frame range"; + /* identifiers */ + ot->name = "Update Range from Scene"; + ot->idname = "OBJECT_OT_paths_range_update"; + ot->description = "Update frame range for motion paths from the Scene's current frame range"; - /* callbacks */ - ot->exec = object_update_paths_range_exec; - ot->poll = ED_operator_object_active_editable; + /* callbacks */ + ot->exec = object_update_paths_range_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /********************** Smooth/Flat *********************/ static int shade_smooth_exec(bContext *C, wmOperator *op) { - ID *data; - Curve *cu; - Nurb *nu; - int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat")); - bool done = false, linked_data = false; - - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - data = ob->data; - - if (data && ID_IS_LINKED(data)) { - linked_data = true; - continue; - } - - if (ob->type == OB_MESH) { - BKE_mesh_smooth_flag_set(ob, !clear); - - BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - done = true; - } - else if (ELEM(ob->type, OB_SURF, OB_CURVE)) { - cu = ob->data; - - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (!clear) nu->flag |= ME_SMOOTH; - else nu->flag &= ~ME_SMOOTH; - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - done = true; - } - } - CTX_DATA_END; - - if (linked_data) - BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data"); - - return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + ID *data; + Curve *cu; + Nurb *nu; + int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat")); + bool done = false, linked_data = false; + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + data = ob->data; + + if (data && ID_IS_LINKED(data)) { + linked_data = true; + continue; + } + + if (ob->type == OB_MESH) { + BKE_mesh_smooth_flag_set(ob, !clear); + + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + done = true; + } + else if (ELEM(ob->type, OB_SURF, OB_CURVE)) { + cu = ob->data; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (!clear) + nu->flag |= ME_SMOOTH; + else + nu->flag &= ~ME_SMOOTH; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + done = true; + } + } + CTX_DATA_END; + + if (linked_data) + BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data"); + + return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static bool shade_poll(bContext *C) { - return (CTX_data_edit_object(C) == NULL); + return (CTX_data_edit_object(C) == NULL); } void OBJECT_OT_shade_flat(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Shade Flat"; - ot->description = "Render and display faces uniform, using Face Normals"; - ot->idname = "OBJECT_OT_shade_flat"; + /* identifiers */ + ot->name = "Shade Flat"; + ot->description = "Render and display faces uniform, using Face Normals"; + ot->idname = "OBJECT_OT_shade_flat"; - /* api callbacks */ - ot->poll = shade_poll; - ot->exec = shade_smooth_exec; + /* api callbacks */ + ot->poll = shade_poll; + ot->exec = shade_smooth_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OBJECT_OT_shade_smooth(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Shade Smooth"; - ot->description = "Render and display faces smooth, using interpolated Vertex Normals"; - ot->idname = "OBJECT_OT_shade_smooth"; + /* identifiers */ + ot->name = "Shade Smooth"; + ot->description = "Render and display faces smooth, using interpolated Vertex Normals"; + ot->idname = "OBJECT_OT_shade_smooth"; - /* api callbacks */ - ot->poll = shade_poll; - ot->exec = shade_smooth_exec; + /* api callbacks */ + ot->poll = shade_poll; + ot->exec = shade_smooth_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ********************** */ -static const EnumPropertyItem *object_mode_set_itemsf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - const EnumPropertyItem *input = rna_enum_object_mode_items; - EnumPropertyItem *item = NULL; - Object *ob; - int totitem = 0; - - if (!C) /* needed for docs */ - return rna_enum_object_mode_items; - - ob = CTX_data_active_object(C); - if (ob) { - const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) || - (ob->soft != NULL) || - (modifiers_findByType(ob, eModifierType_Cloth) != NULL); - while (input->identifier) { - if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || - (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || - (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || - (ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, - OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || - (ELEM(input->value, OB_MODE_EDIT_GPENCIL, OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL) && (ob->type == OB_GPENCIL)) || - (input->value == OB_MODE_OBJECT)) - { - RNA_enum_item_add(&item, &totitem, input); - } - input++; - } - } - else { - /* We need at least this one! */ - RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT); - } - - RNA_enum_item_end(&item, &totitem); - - *r_free = true; - - return item; + const EnumPropertyItem *input = rna_enum_object_mode_items; + EnumPropertyItem *item = NULL; + Object *ob; + int totitem = 0; + + if (!C) /* needed for docs */ + return rna_enum_object_mode_items; + + ob = CTX_data_active_object(C); + if (ob) { + const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) || + (ob->soft != NULL) || + (modifiers_findByType(ob, eModifierType_Cloth) != NULL); + while (input->identifier) { + if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || + (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || + (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || + (ELEM(input->value, + OB_MODE_SCULPT, + OB_MODE_VERTEX_PAINT, + OB_MODE_WEIGHT_PAINT, + OB_MODE_TEXTURE_PAINT) && + (ob->type == OB_MESH)) || + (ELEM(input->value, + OB_MODE_EDIT_GPENCIL, + OB_MODE_PAINT_GPENCIL, + OB_MODE_SCULPT_GPENCIL, + OB_MODE_WEIGHT_GPENCIL) && + (ob->type == OB_GPENCIL)) || + (input->value == OB_MODE_OBJECT)) { + RNA_enum_item_add(&item, &totitem, input); + } + input++; + } + } + else { + /* We need at least this one! */ + RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT); + } + + RNA_enum_item_end(&item, &totitem); + + *r_free = true; + + return item; } static bool object_mode_set_poll(bContext *C) { - /* Since Grease Pencil editmode is also handled here, - * we have a special exception for allowing this operator - * to still work in that case when there's no active object - * so that users can exit editmode this way as per normal. - */ - if (ED_operator_object_active_editable(C)) - return true; - else - return (CTX_data_gpencil_data(C) != NULL); + /* Since Grease Pencil editmode is also handled here, + * we have a special exception for allowing this operator + * to still work in that case when there's no active object + * so that users can exit editmode this way as per normal. + */ + if (ED_operator_object_active_editable(C)) + return true; + else + return (CTX_data_gpencil_data(C) != NULL); } static int object_mode_set_exec(bContext *C, wmOperator *op) { - bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode"); - Object *ob = CTX_data_active_object(C); - eObjectMode mode = RNA_enum_get(op->ptr, "mode"); - eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; - const bool toggle = RNA_boolean_get(op->ptr, "toggle"); - - if (use_submode) { - /* When not changing modes use submodes, see: T55162. */ - if (toggle == false) { - if (mode == restore_mode) { - switch (mode) { - case OB_MODE_EDIT: - WM_menu_name_call(C, "VIEW3D_MT_edit_mesh_select_mode", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_INTERFACE; - default: - break; - } - } - } - } - - /* by default the operator assume is a mesh, but if gp object change mode */ - if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { - mode = OB_MODE_EDIT_GPENCIL; - } - - if (!ob || !ED_object_mode_compat_test(ob, mode)) - return OPERATOR_PASS_THROUGH; - - if (ob->mode != mode) { - /* we should be able to remove this call, each operator calls */ - ED_object_mode_compat_set(C, ob, mode, op->reports); - } - - /* Exit current mode if it's not the mode we're setting */ - if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { - /* Enter new mode */ - ED_object_mode_toggle(C, mode); - } - - if (toggle) { - /* Special case for Object mode! */ - if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) { - ED_object_mode_toggle(C, ob->restore_mode); - } - else if (ob->mode == mode) { - /* For toggling, store old mode so we know what to go back to */ - ob->restore_mode = restore_mode; - } - else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { - ED_object_mode_toggle(C, ob->restore_mode); - } - } - - /* if type is OB_GPENCIL, set cursor mode */ - if ((ob) && (ob->type == OB_GPENCIL)) { - if (ob->data) { - bGPdata *gpd = (bGPdata *)ob->data; - ED_gpencil_setup_modes(C, gpd, ob->mode); - } - } - - return OPERATOR_FINISHED; + bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode"); + Object *ob = CTX_data_active_object(C); + eObjectMode mode = RNA_enum_get(op->ptr, "mode"); + eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; + const bool toggle = RNA_boolean_get(op->ptr, "toggle"); + + if (use_submode) { + /* When not changing modes use submodes, see: T55162. */ + if (toggle == false) { + if (mode == restore_mode) { + switch (mode) { + case OB_MODE_EDIT: + WM_menu_name_call(C, "VIEW3D_MT_edit_mesh_select_mode", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_INTERFACE; + default: + break; + } + } + } + } + + /* by default the operator assume is a mesh, but if gp object change mode */ + if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { + mode = OB_MODE_EDIT_GPENCIL; + } + + if (!ob || !ED_object_mode_compat_test(ob, mode)) + return OPERATOR_PASS_THROUGH; + + if (ob->mode != mode) { + /* we should be able to remove this call, each operator calls */ + ED_object_mode_compat_set(C, ob, mode, op->reports); + } + + /* Exit current mode if it's not the mode we're setting */ + if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { + /* Enter new mode */ + ED_object_mode_toggle(C, mode); + } + + if (toggle) { + /* Special case for Object mode! */ + if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && + ob->restore_mode != OB_MODE_OBJECT) { + ED_object_mode_toggle(C, ob->restore_mode); + } + else if (ob->mode == mode) { + /* For toggling, store old mode so we know what to go back to */ + ob->restore_mode = restore_mode; + } + else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { + ED_object_mode_toggle(C, ob->restore_mode); + } + } + + /* if type is OB_GPENCIL, set cursor mode */ + if ((ob) && (ob->type == OB_GPENCIL)) { + if (ob->data) { + bGPdata *gpd = (bGPdata *)ob->data; + ED_gpencil_setup_modes(C, gpd, ob->mode); + } + } + + return OPERATOR_FINISHED; } void OBJECT_OT_mode_set(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Set Object Mode"; - ot->description = "Sets the object interaction mode"; - ot->idname = "OBJECT_OT_mode_set"; + /* identifiers */ + ot->name = "Set Object Mode"; + ot->description = "Sets the object interaction mode"; + ot->idname = "OBJECT_OT_mode_set"; - /* api callbacks */ - ot->exec = object_mode_set_exec; + /* api callbacks */ + ot->exec = object_mode_set_exec; - ot->poll = object_mode_set_poll; //ED_operator_object_active_editable; + ot->poll = object_mode_set_poll; //ED_operator_object_active_editable; - /* flags */ - ot->flag = 0; /* no register/undo here, leave it to operators being called */ + /* flags */ + ot->flag = 0; /* no register/undo here, leave it to operators being called */ - ot->prop = RNA_def_enum(ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); - RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + ot->prop = RNA_def_enum( + ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); + RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Set Object Mode or Submode"; - ot->description = "Sets the object interaction mode"; - ot->idname = "OBJECT_OT_mode_set_or_submode"; + /* identifiers */ + ot->name = "Set Object Mode or Submode"; + ot->description = "Sets the object interaction mode"; + ot->idname = "OBJECT_OT_mode_set_or_submode"; - /* api callbacks */ - ot->exec = object_mode_set_exec; + /* api callbacks */ + ot->exec = object_mode_set_exec; - ot->poll = object_mode_set_poll; //ED_operator_object_active_editable; + ot->poll = object_mode_set_poll; //ED_operator_object_active_editable; - /* flags */ - ot->flag = 0; /* no register/undo here, leave it to operators being called */ + /* flags */ + ot->flag = 0; /* no register/undo here, leave it to operators being called */ - ot->prop = RNA_def_enum(ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); - RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + ot->prop = RNA_def_enum( + ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); + RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static bool move_to_collection_poll(bContext *C) { - if (CTX_wm_space_outliner(C) != NULL) { - return ED_outliner_collections_editor_poll(C); - } - else { - View3D *v3d = CTX_wm_view3d(C); - - if (v3d && v3d->localvd) { - return false; - } - - return ED_operator_object_active_editable(C); - } + if (CTX_wm_space_outliner(C) != NULL) { + return ED_outliner_collections_editor_poll(C); + } + else { + View3D *v3d = CTX_wm_view3d(C); + + if (v3d && v3d->localvd) { + return false; + } + + return ED_operator_object_active_editable(C); + } } static int move_to_collection_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index"); - const bool is_link = STREQ(op->idname, "OBJECT_OT_link_to_collection"); - const bool is_new = RNA_boolean_get(op->ptr, "is_new"); - Collection *collection; - ListBase objects = {NULL}; - - if (!RNA_property_is_set(op->ptr, prop)) { - BKE_report(op->reports, RPT_ERROR, "No collection selected"); - return OPERATOR_CANCELLED; - } - - int collection_index = RNA_property_int_get(op->ptr, prop); - collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); - if (collection == NULL) { - BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); - return OPERATOR_CANCELLED; - } - - if (CTX_wm_space_outliner(C) != NULL) { - ED_outliner_selected_objects_get(C, &objects); - } - else { - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - BLI_addtail(&objects, BLI_genericNodeN(ob)); - } - CTX_DATA_END; - } - - if (is_new) { - char new_collection_name[MAX_NAME]; - RNA_string_get(op->ptr, "new_collection_name", new_collection_name); - collection = BKE_collection_add(bmain, collection, new_collection_name); - } - - Object *single_object = BLI_listbase_is_single(&objects) ? - ((LinkData *)objects.first)->data : NULL; - - if ((single_object != NULL) && - is_link && - BLI_findptr(&collection->gobject, single_object, offsetof(CollectionObject, ob))) - { - BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, collection->id.name + 2); - BLI_freelistN(&objects); - return OPERATOR_CANCELLED; - } - - for (LinkData *link = objects.first; link; link = link->next) { - Object *ob = link->data; - - if (!is_link) { - BKE_collection_object_move(bmain, scene, collection, NULL, ob); - } - else { - BKE_collection_object_add(bmain, collection, ob); - } - } - BLI_freelistN(&objects); - - BKE_reportf(op->reports, - RPT_INFO, - "%s %s to %s", - (single_object != NULL) ? single_object->id.name + 2 : "Objects", - is_link ? "linked" : "moved", - collection->id.name + 2); - - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index"); + const bool is_link = STREQ(op->idname, "OBJECT_OT_link_to_collection"); + const bool is_new = RNA_boolean_get(op->ptr, "is_new"); + Collection *collection; + ListBase objects = {NULL}; + + if (!RNA_property_is_set(op->ptr, prop)) { + BKE_report(op->reports, RPT_ERROR, "No collection selected"); + return OPERATOR_CANCELLED; + } + + int collection_index = RNA_property_int_get(op->ptr, prop); + collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + if (collection == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); + return OPERATOR_CANCELLED; + } + + if (CTX_wm_space_outliner(C) != NULL) { + ED_outliner_selected_objects_get(C, &objects); + } + else { + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + BLI_addtail(&objects, BLI_genericNodeN(ob)); + } + CTX_DATA_END; + } + + if (is_new) { + char new_collection_name[MAX_NAME]; + RNA_string_get(op->ptr, "new_collection_name", new_collection_name); + collection = BKE_collection_add(bmain, collection, new_collection_name); + } + + Object *single_object = BLI_listbase_is_single(&objects) ? ((LinkData *)objects.first)->data : + NULL; + + if ((single_object != NULL) && is_link && + BLI_findptr(&collection->gobject, single_object, offsetof(CollectionObject, ob))) { + BKE_reportf(op->reports, + RPT_ERROR, + "%s already in %s", + single_object->id.name + 2, + collection->id.name + 2); + BLI_freelistN(&objects); + return OPERATOR_CANCELLED; + } + + for (LinkData *link = objects.first; link; link = link->next) { + Object *ob = link->data; + + if (!is_link) { + BKE_collection_object_move(bmain, scene, collection, NULL, ob); + } + else { + BKE_collection_object_add(bmain, collection, ob); + } + } + BLI_freelistN(&objects); + + BKE_reportf(op->reports, + RPT_INFO, + "%s %s to %s", + (single_object != NULL) ? single_object->id.name + 2 : "Objects", + is_link ? "linked" : "moved", + collection->id.name + 2); + + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + + return OPERATOR_FINISHED; } struct MoveToCollectionData { - struct MoveToCollectionData *next, *prev; - int index; - struct Collection *collection; - struct ListBase submenus; - PointerRNA ptr; - struct wmOperatorType *ot; + struct MoveToCollectionData *next, *prev; + int index; + struct Collection *collection; + struct ListBase submenus; + PointerRNA ptr; + struct wmOperatorType *ot; }; static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu) { - int index = menu->index; - for (CollectionChild *child = menu->collection->children.first; - child != NULL; - child = child->next) - { - Collection *collection = child->collection; - MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData), - "MoveToCollectionData submenu - expected memleak"); - BLI_addtail(&menu->submenus, submenu); - submenu->collection = collection; - submenu->index = ++index; - index = move_to_collection_menus_create(op, submenu); - submenu->ot = op->type; - } - return index; + int index = menu->index; + for (CollectionChild *child = menu->collection->children.first; child != NULL; + child = child->next) { + Collection *collection = child->collection; + MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData), + "MoveToCollectionData submenu - expected memleak"); + BLI_addtail(&menu->submenus, submenu); + submenu->collection = collection; + submenu->index = ++index; + index = move_to_collection_menus_create(op, submenu); + submenu->ot = op->type; + } + return index; } static void move_to_collection_menus_free_recursive(MoveToCollectionData *menu) { - for (MoveToCollectionData *submenu = menu->submenus.first; - submenu != NULL; - submenu = submenu->next) - { - move_to_collection_menus_free_recursive(submenu); - } - BLI_freelistN(&menu->submenus); + for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL; + submenu = submenu->next) { + move_to_collection_menus_free_recursive(submenu); + } + BLI_freelistN(&menu->submenus); } static void move_to_collection_menus_free(MoveToCollectionData **menu) { - if (*menu == NULL) { - return; - } + if (*menu == NULL) { + return; + } - move_to_collection_menus_free_recursive(*menu); - MEM_freeN(*menu); - *menu = NULL; + move_to_collection_menus_free_recursive(*menu); + MEM_freeN(*menu); + *menu = NULL; } static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v) { - MoveToCollectionData *menu = menu_v; - const char *name = BKE_collection_ui_name_get(menu->collection); - - uiItemIntO(layout, - name, - ICON_NONE, - menu->ot->idname, - "collection_index", - menu->index); - uiItemS(layout); - - for (MoveToCollectionData *submenu = menu->submenus.first; - submenu != NULL; - submenu = submenu->next) - { - move_to_collection_menus_items(layout, submenu); - } - - uiItemS(layout); - - WM_operator_properties_create_ptr(&menu->ptr, menu->ot); - RNA_int_set(&menu->ptr, "collection_index", menu->index); - RNA_boolean_set(&menu->ptr, "is_new", true); - - uiItemFullO_ptr(layout, - menu->ot, - "New Collection", - ICON_ADD, - menu->ptr.data, - WM_OP_INVOKE_DEFAULT, - 0, - NULL); + MoveToCollectionData *menu = menu_v; + const char *name = BKE_collection_ui_name_get(menu->collection); + + uiItemIntO(layout, name, ICON_NONE, menu->ot->idname, "collection_index", menu->index); + uiItemS(layout); + + for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL; + submenu = submenu->next) { + move_to_collection_menus_items(layout, submenu); + } + + uiItemS(layout); + + WM_operator_properties_create_ptr(&menu->ptr, menu->ot); + RNA_int_set(&menu->ptr, "collection_index", menu->index); + RNA_boolean_set(&menu->ptr, "is_new", true); + + uiItemFullO_ptr( + layout, menu->ot, "New Collection", ICON_ADD, menu->ptr.data, WM_OP_INVOKE_DEFAULT, 0, NULL); } static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu) { - if (BLI_listbase_is_empty(&menu->submenus)) { - uiItemIntO(layout, - menu->collection->id.name + 2, - ICON_NONE, - menu->ot->idname, - "collection_index", - menu->index); - } - else { - uiItemMenuF(layout, - menu->collection->id.name + 2, - ICON_NONE, - move_to_collection_menu_create, - menu); - } + if (BLI_listbase_is_empty(&menu->submenus)) { + uiItemIntO(layout, + menu->collection->id.name + 2, + ICON_NONE, + menu->ot->idname, + "collection_index", + menu->index); + } + else { + uiItemMenuF( + layout, menu->collection->id.name + 2, ICON_NONE, move_to_collection_menu_create, menu); + } } /* This is allocated statically because we need this available for the menus creation callback. */ @@ -1628,116 +1633,138 @@ static MoveToCollectionData *master_collection_menu = NULL; static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Scene *scene = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); - /* Reset the menus data for the current master collection, and free previously allocated data. */ - move_to_collection_menus_free(&master_collection_menu); + /* Reset the menus data for the current master collection, and free previously allocated data. */ + move_to_collection_menus_free(&master_collection_menu); - PropertyRNA *prop; - prop = RNA_struct_find_property(op->ptr, "collection_index"); - if (RNA_property_is_set(op->ptr, prop)) { - int collection_index = RNA_property_int_get(op->ptr, prop); + PropertyRNA *prop; + prop = RNA_struct_find_property(op->ptr, "collection_index"); + if (RNA_property_is_set(op->ptr, prop)) { + int collection_index = RNA_property_int_get(op->ptr, prop); - if (RNA_boolean_get(op->ptr, "is_new")) { - prop = RNA_struct_find_property(op->ptr, "new_collection_name"); - if (!RNA_property_is_set(op->ptr, prop)) { - char name[MAX_NAME]; - Collection *collection; + if (RNA_boolean_get(op->ptr, "is_new")) { + prop = RNA_struct_find_property(op->ptr, "new_collection_name"); + if (!RNA_property_is_set(op->ptr, prop)) { + char name[MAX_NAME]; + Collection *collection; - collection = BKE_collection_from_index(scene, collection_index); - BKE_collection_new_name_get(collection, name); + collection = BKE_collection_from_index(scene, collection_index); + BKE_collection_new_name_get(collection, name); - RNA_property_string_set(op->ptr, prop, name); - return WM_operator_props_dialog_popup(C, op, 200, 100); - } - } - return move_to_collection_exec(C, op); - } + RNA_property_string_set(op->ptr, prop, name); + return WM_operator_props_dialog_popup(C, op, 200, 100); + } + } + return move_to_collection_exec(C, op); + } - Collection *master_collection = BKE_collection_master(scene); + Collection *master_collection = BKE_collection_master(scene); - /* We need the data to be allocated so it's available during menu drawing. - * Technically we could use wmOperator->customdata. However there is no free callback - * called to an operator that exit with OPERATOR_INTERFACE to launch a menu. - * - * So we are left with a memory that will necessarily leak. It's a small leak though.*/ - if (master_collection_menu == NULL) { - master_collection_menu = MEM_callocN(sizeof(MoveToCollectionData), - "MoveToCollectionData menu - expected eventual memleak"); - } + /* We need the data to be allocated so it's available during menu drawing. + * Technically we could use wmOperator->customdata. However there is no free callback + * called to an operator that exit with OPERATOR_INTERFACE to launch a menu. + * + * So we are left with a memory that will necessarily leak. It's a small leak though.*/ + if (master_collection_menu == NULL) { + master_collection_menu = MEM_callocN(sizeof(MoveToCollectionData), + "MoveToCollectionData menu - expected eventual memleak"); + } - master_collection_menu->collection = master_collection; - master_collection_menu->ot = op->type; - move_to_collection_menus_create(op, master_collection_menu); + master_collection_menu->collection = master_collection; + master_collection_menu->ot = op->type; + move_to_collection_menus_create(op, master_collection_menu); - uiPopupMenu *pup; - uiLayout *layout; + uiPopupMenu *pup; + uiLayout *layout; - /* Build the menus. */ - const char *title = CTX_IFACE_(op->type->translation_context, op->type->name); - pup = UI_popup_menu_begin(C, title, ICON_NONE); - layout = UI_popup_menu_layout(pup); + /* Build the menus. */ + const char *title = CTX_IFACE_(op->type->translation_context, op->type->name); + pup = UI_popup_menu_begin(C, title, ICON_NONE); + layout = UI_popup_menu_layout(pup); - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); - move_to_collection_menu_create(C, layout, master_collection_menu); + move_to_collection_menu_create(C, layout, master_collection_menu); - UI_popup_menu_end(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } void OBJECT_OT_move_to_collection(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Move to Collection"; - ot->description = "Move objects to a scene collection"; - ot->idname = "OBJECT_OT_move_to_collection"; - - /* api callbacks */ - ot->exec = move_to_collection_exec; - ot->invoke = move_to_collection_invoke; - ot->poll = move_to_collection_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, - "Collection Index", "Index of the collection to move to", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name", - "Name of the newly added collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Move to Collection"; + ot->description = "Move objects to a scene collection"; + ot->idname = "OBJECT_OT_move_to_collection"; + + /* api callbacks */ + ot->exec = move_to_collection_exec; + ot->invoke = move_to_collection_invoke; + ot->poll = move_to_collection_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, + "collection_index", + COLLECTION_INVALID_INDEX, + COLLECTION_INVALID_INDEX, + INT_MAX, + "Collection Index", + "Index of the collection to move to", + 0, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_string(ot->srna, + "new_collection_name", + NULL, + MAX_NAME, + "Name", + "Name of the newly added collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = prop; } void OBJECT_OT_link_to_collection(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Link to Collection"; - ot->description = "Link objects to a collection"; - ot->idname = "OBJECT_OT_link_to_collection"; - - /* api callbacks */ - ot->exec = move_to_collection_exec; - ot->invoke = move_to_collection_invoke; - ot->poll = move_to_collection_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, - "Collection Index", "Index of the collection to move to", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name", - "Name of the newly added collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Link to Collection"; + ot->description = "Link objects to a collection"; + ot->idname = "OBJECT_OT_link_to_collection"; + + /* api callbacks */ + ot->exec = move_to_collection_exec; + ot->invoke = move_to_collection_invoke; + ot->poll = move_to_collection_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, + "collection_index", + COLLECTION_INVALID_INDEX, + COLLECTION_INVALID_INDEX, + INT_MAX, + "Collection Index", + "Index of the collection to move to", + 0, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_string(ot->srna, + "new_collection_name", + NULL, + MAX_NAME, + "Name", + "Name of the newly added collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index c46310c8c9d..a77cfab031d 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -55,438 +55,437 @@ /* called while not in editmode */ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum) { - int fmap_nr; - if (GS(((ID *)ob->data)->name) != ID_ME) - return; + int fmap_nr; + if (GS(((ID *)ob->data)->name) != ID_ME) + return; - /* get the face map number, exit if it can't be found */ - fmap_nr = BLI_findindex(&ob->fmaps, fmap); + /* get the face map number, exit if it can't be found */ + fmap_nr = BLI_findindex(&ob->fmaps, fmap); - if (fmap_nr != -1) { - int *facemap; - Mesh *me = ob->data; + if (fmap_nr != -1) { + int *facemap; + Mesh *me = ob->data; - /* if there's is no facemap layer then create one */ - if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) - facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + /* if there's is no facemap layer then create one */ + if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) + facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); - facemap[facenum] = fmap_nr; - } + facemap[facenum] = fmap_nr; + } } /* called while not in editmode */ void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum) { - int fmap_nr; - if (GS(((ID *)ob->data)->name) != ID_ME) - return; + int fmap_nr; + if (GS(((ID *)ob->data)->name) != ID_ME) + return; - /* get the face map number, exit if it can't be found */ - fmap_nr = BLI_findindex(&ob->fmaps, fmap); + /* get the face map number, exit if it can't be found */ + fmap_nr = BLI_findindex(&ob->fmaps, fmap); - if (fmap_nr != -1) { - int *facemap; - Mesh *me = ob->data; + if (fmap_nr != -1) { + int *facemap; + Mesh *me = ob->data; - if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) - return; + if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) + return; - facemap[facenum] = -1; - } + facemap[facenum] = -1; + } } static void object_fmap_swap_edit_mode(Object *ob, int num1, int num2) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); - - if (cd_fmap_offset != -1) { - BMFace *efa; - BMIter iter; - int *map; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); - - if (map) { - if (num1 != -1) { - if (*map == num1) - *map = num2; - else if (*map == num2) - *map = num1; - } - } - } - } - } - } + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + if (cd_fmap_offset != -1) { + BMFace *efa; + BMIter iter; + int *map; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (map) { + if (num1 != -1) { + if (*map == num1) + *map = num2; + else if (*map == num2) + *map = num1; + } + } + } + } + } + } } static void object_fmap_swap_object_mode(Object *ob, int num1, int num2) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP); - int i; - - if (map) { - for (i = 0; i < me->totpoly; i++) { - if (num1 != -1) { - if (map[i] == num1) - map[i] = num2; - else if (map[i] == num2) - map[i] = num1; - } - } - } - } - } + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) { + int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP); + int i; + + if (map) { + for (i = 0; i < me->totpoly; i++) { + if (num1 != -1) { + if (map[i] == num1) + map[i] = num2; + else if (map[i] == num2) + map[i] = num1; + } + } + } + } + } } static void object_facemap_swap(Object *ob, int num1, int num2) { - if (BKE_object_is_in_editmode(ob)) - object_fmap_swap_edit_mode(ob, num1, num2); - else - object_fmap_swap_object_mode(ob, num1, num2); + if (BKE_object_is_in_editmode(ob)) + object_fmap_swap_edit_mode(ob, num1, num2); + else + object_fmap_swap_object_mode(ob, num1, num2); } static bool face_map_supported_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); } static bool face_map_supported_edit_mode_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) { - if (ob->mode == OB_MODE_EDIT) { - return true; - } - } - return false; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) { + if (ob->mode == OB_MODE_EDIT) { + return true; + } + } + return false; } static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - BKE_object_facemap_add(ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + BKE_object_facemap_add(ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_add(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Face Map"; - ot->idname = "OBJECT_OT_face_map_add"; - ot->description = "Add a new face map to the active object"; + /* identifiers */ + ot->name = "Add Face Map"; + ot->idname = "OBJECT_OT_face_map_add"; + ot->description = "Add a new face map to the active object"; - /* api callbacks */ - ot->poll = face_map_supported_poll; - ot->exec = face_map_add_exec; + /* api callbacks */ + ot->poll = face_map_supported_poll; + ot->exec = face_map_add_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int face_map_remove_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - - if (fmap) { - BKE_object_facemap_remove(ob, fmap); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + + if (fmap) { + BKE_object_facemap_remove(ob, fmap); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_remove(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Face Map"; - ot->idname = "OBJECT_OT_face_map_remove"; - ot->description = "Remove a face map from the active object"; + /* identifiers */ + ot->name = "Remove Face Map"; + ot->idname = "OBJECT_OT_face_map_remove"; + ot->description = "Remove a face map from the active object"; - /* api callbacks */ - ot->poll = face_map_supported_poll; - ot->exec = face_map_remove_exec; + /* api callbacks */ + ot->poll = face_map_supported_poll; + ot->exec = face_map_remove_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int face_map_assign_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - - if (fmap) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMFace *efa; - BMIter iter; - int *map; - int cd_fmap_offset; - - if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) - BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP); - - cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); - - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - *map = ob->actfmap - 1; - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + + if (fmap) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMFace *efa; + BMIter iter; + int *map; + int cd_fmap_offset; + + if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) + BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP); + + cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + *map = ob->actfmap - 1; + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_assign(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Assign Face Map"; - ot->idname = "OBJECT_OT_face_map_assign"; - ot->description = "Assign faces to a face map"; + /* identifiers */ + ot->name = "Assign Face Map"; + ot->idname = "OBJECT_OT_face_map_assign"; + ot->description = "Assign faces to a face map"; - /* api callbacks */ - ot->poll = face_map_supported_edit_mode_poll; - ot->exec = face_map_assign_exec; + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_assign_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int face_map_remove_from_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - - if (fmap) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMFace *efa; - BMIter iter; - int *map; - int cd_fmap_offset; - int mapindex = ob->actfmap - 1; - - if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) - return OPERATOR_CANCELLED; - - cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); - - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && *map == mapindex) { - *map = -1; - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + + if (fmap) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMFace *efa; + BMIter iter; + int *map; + int cd_fmap_offset; + int mapindex = ob->actfmap - 1; + + if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) + return OPERATOR_CANCELLED; + + cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && *map == mapindex) { + *map = -1; + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove From Face Map"; - ot->idname = "OBJECT_OT_face_map_remove_from"; - ot->description = "Remove faces from a face map"; + /* identifiers */ + ot->name = "Remove From Face Map"; + ot->idname = "OBJECT_OT_face_map_remove_from"; + ot->description = "Remove faces from a face map"; - /* api callbacks */ - ot->poll = face_map_supported_edit_mode_poll; - ot->exec = face_map_remove_from_exec; + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_remove_from_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static void fmap_select(Object *ob, bool select) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMFace *efa; - BMIter iter; - int *map; - int cd_fmap_offset; - int mapindex = ob->actfmap - 1; - - if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) - BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP); - - cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); - - if (*map == mapindex) { - BM_face_select_set(em->bm, efa, select); - } - } + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMFace *efa; + BMIter iter; + int *map; + int cd_fmap_offset; + int mapindex = ob->actfmap - 1; + + if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) + BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP); + + cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (*map == mapindex) { + BM_face_select_set(em->bm, efa, select); + } + } } static int face_map_select_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - if (fmap) { - fmap_select(ob, true); + if (fmap) { + fmap_select(ob, true); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - return OPERATOR_FINISHED; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_select(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Face Map Faces"; - ot->idname = "OBJECT_OT_face_map_select"; - ot->description = "Select faces belonging to a face map"; + /* identifiers */ + ot->name = "Select Face Map Faces"; + ot->idname = "OBJECT_OT_face_map_select"; + ot->description = "Select faces belonging to a face map"; - /* api callbacks */ - ot->poll = face_map_supported_edit_mode_poll; - ot->exec = face_map_select_exec; + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_select_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int face_map_deselect_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + Object *ob = ED_object_context(C); + bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - if (fmap) { - fmap_select(ob, false); + if (fmap) { + fmap_select(ob, false); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - return OPERATOR_FINISHED; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + return OPERATOR_FINISHED; } void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Deselect Face Map Faces"; - ot->idname = "OBJECT_OT_face_map_deselect"; - ot->description = "Deselect faces belonging to a face map"; + /* identifiers */ + ot->name = "Deselect Face Map Faces"; + ot->idname = "OBJECT_OT_face_map_deselect"; + ot->description = "Deselect faces belonging to a face map"; - /* api callbacks */ - ot->poll = face_map_supported_edit_mode_poll; - ot->exec = face_map_deselect_exec; + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_deselect_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int face_map_move_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - bFaceMap *fmap; - int dir = RNA_enum_get(op->ptr, "direction"); - int pos1, pos2 = -1, count; - - fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); - if (!fmap) { - return OPERATOR_CANCELLED; - } - - count = BLI_listbase_count(&ob->fmaps); - pos1 = BLI_findindex(&ob->fmaps, fmap); - - if (dir == 1) { /*up*/ - void *prev = fmap->prev; - - if (prev) { - pos2 = pos1 - 1; - } - else { - pos2 = count - 1; - } - - BLI_remlink(&ob->fmaps, fmap); - BLI_insertlinkbefore(&ob->fmaps, prev, fmap); - } - else { /*down*/ - void *next = fmap->next; - - if (next) { - pos2 = pos1 + 1; - } - else { - pos2 = 0; - } - - BLI_remlink(&ob->fmaps, fmap); - BLI_insertlinkafter(&ob->fmaps, next, fmap); - } - - /* iterate through mesh and substitute the indices as necessary */ - object_facemap_swap(ob, pos2, pos1); - - ob->actfmap = pos2 + 1; - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); - - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + bFaceMap *fmap; + int dir = RNA_enum_get(op->ptr, "direction"); + int pos1, pos2 = -1, count; + + fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1); + if (!fmap) { + return OPERATOR_CANCELLED; + } + + count = BLI_listbase_count(&ob->fmaps); + pos1 = BLI_findindex(&ob->fmaps, fmap); + + if (dir == 1) { /*up*/ + void *prev = fmap->prev; + + if (prev) { + pos2 = pos1 - 1; + } + else { + pos2 = count - 1; + } + + BLI_remlink(&ob->fmaps, fmap); + BLI_insertlinkbefore(&ob->fmaps, prev, fmap); + } + else { /*down*/ + void *next = fmap->next; + + if (next) { + pos2 = pos1 + 1; + } + else { + pos2 = 0; + } + + BLI_remlink(&ob->fmaps, fmap); + BLI_insertlinkafter(&ob->fmaps, next, fmap); + } + + /* iterate through mesh and substitute the indices as necessary */ + object_facemap_swap(ob, pos2, pos1); + + ob->actfmap = pos2 + 1; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); + + return OPERATOR_FINISHED; } - void OBJECT_OT_face_map_move(wmOperatorType *ot) { - static EnumPropertyItem fmap_slot_move[] = { - {1, "UP", 0, "Up", ""}, - {-1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Move Face Map"; - ot->idname = "OBJECT_OT_face_map_move"; - ot->description = "Move the active face map up/down in the list"; - - /* api callbacks */ - ot->poll = face_map_supported_poll; - ot->exec = face_map_move_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "direction", fmap_slot_move, 0, "Direction", "Direction to move, UP or DOWN"); + static EnumPropertyItem fmap_slot_move[] = { + {1, "UP", 0, "Up", ""}, + {-1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Move Face Map"; + ot->idname = "OBJECT_OT_face_map_move"; + ot->description = "Move the active face map up/down in the list"; + + /* api callbacks */ + ot->poll = face_map_supported_poll; + ot->exec = face_map_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum( + ot->srna, "direction", fmap_slot_move, 0, "Direction", "Direction to move, UP or DOWN"); } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index a1f529b3bde..a726e2c9f00 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -63,572 +62,611 @@ /******************************** API ****************************/ GpencilModifierData *ED_object_gpencil_modifier_add( - ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) + ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) { - GpencilModifierData *new_md = NULL; - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); - - if (ob->type != OB_GPENCIL) { - BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); - return NULL; - } + GpencilModifierData *new_md = NULL; + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); - if (mti->flags & eGpencilModifierTypeFlag_Single) { - if (BKE_gpencil_modifiers_findByType(ob, type)) { - BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); - return NULL; - } - } + if (ob->type != OB_GPENCIL) { + BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); + return NULL; + } - /* get new modifier data to add */ - new_md = BKE_gpencil_modifier_new(type); + if (mti->flags & eGpencilModifierTypeFlag_Single) { + if (BKE_gpencil_modifiers_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); + return NULL; + } + } - BLI_addtail(&ob->greasepencil_modifiers, new_md); + /* get new modifier data to add */ + new_md = BKE_gpencil_modifier_new(type); - if (name) { - BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name)); - } + BLI_addtail(&ob->greasepencil_modifiers, new_md); - /* make sure modifier data has unique name */ - BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md); + if (name) { + BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name)); + } + /* make sure modifier data has unique name */ + BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md); - bGPdata *gpd = ob->data; - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); - return new_md; + return new_md; } /* Return true if the object has a modifier of type 'type' other than * the modifier pointed to be 'exclude', otherwise returns false. */ -static bool UNUSED_FUNCTION(gpencil_object_has_modifier)( - const Object *ob, const GpencilModifierData *exclude, - GpencilModifierType type) +static bool UNUSED_FUNCTION(gpencil_object_has_modifier)(const Object *ob, + const GpencilModifierData *exclude, + GpencilModifierType type) { - GpencilModifierData *md; + GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if ((md != exclude) && (md->type == type)) - return true; - } + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if ((md != exclude) && (md->type == type)) + return true; + } - return false; + return false; } -static bool gpencil_object_modifier_remove( - Main *bmain, Object *ob, GpencilModifierData *md, - bool *UNUSED(r_sort_depsgraph)) +static bool gpencil_object_modifier_remove(Main *bmain, + Object *ob, + GpencilModifierData *md, + bool *UNUSED(r_sort_depsgraph)) { - /* It seems on rapid delete it is possible to - * get called twice on same modifier, so make - * sure it is in list. */ - if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) { - return 0; - } + /* It seems on rapid delete it is possible to + * get called twice on same modifier, so make + * sure it is in list. */ + if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) { + return 0; + } - DEG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); - BLI_remlink(&ob->greasepencil_modifiers, md); - BKE_gpencil_modifier_free(md); - BKE_object_free_derived_caches(ob); + BLI_remlink(&ob->greasepencil_modifiers, md); + BKE_gpencil_modifier_free(md); + BKE_object_free_derived_caches(ob); - return 1; + return 1; } -bool ED_object_gpencil_modifier_remove(ReportList *reports, Main *bmain, Object *ob, GpencilModifierData *md) +bool ED_object_gpencil_modifier_remove(ReportList *reports, + Main *bmain, + Object *ob, + GpencilModifierData *md) { - bool sort_depsgraph = false; - bool ok; + bool sort_depsgraph = false; + bool ok; - ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); + ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name); - return 0; - } + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name); + return 0; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); - return 1; + return 1; } void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob) { - GpencilModifierData *md = ob->greasepencil_modifiers.first; - bool sort_depsgraph = false; + GpencilModifierData *md = ob->greasepencil_modifiers.first; + bool sort_depsgraph = false; - if (!md) - return; + if (!md) + return; - while (md) { - GpencilModifierData *next_md; + while (md) { + GpencilModifierData *next_md; - next_md = md->next; + next_md = md->next; - gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); + gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); - md = next_md; - } + md = next_md; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); } -int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md) +int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports), + Object *ob, + GpencilModifierData *md) { - if (md->prev) { - BLI_remlink(&ob->greasepencil_modifiers, md); - BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md); - } + if (md->prev) { + BLI_remlink(&ob->greasepencil_modifiers, md); + BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md); + } - return 1; + return 1; } -int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md) +int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), + Object *ob, + GpencilModifierData *md) { - if (md->next) { - BLI_remlink(&ob->greasepencil_modifiers, md); - BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md); - } + if (md->next) { + BLI_remlink(&ob->greasepencil_modifiers, md); + BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md); + } - return 1; + return 1; } static int gpencil_modifier_apply_obdata( - ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md) -{ - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - - if (mti->isDisabled && mti->isDisabled(md, 0)) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); - return 0; - } - - if (ob->type == OB_GPENCIL) { - if (ELEM(NULL, ob, ob->data)) { - return 0; - } - else if (mti->bakeModifier == NULL) { - BKE_report(reports, RPT_ERROR, "Not implemented"); - return 0; - } - mti->bakeModifier(bmain, depsgraph, md, ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - else { - BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); - return 0; - } - - return 1; -} - -int ED_object_gpencil_modifier_apply( - Main *bmain, ReportList *reports, Depsgraph *depsgraph, - Object *ob, GpencilModifierData *md, int UNUSED(mode)) -{ - - if (ob->type == OB_GPENCIL) { - if (ob->mode != OB_MODE_OBJECT) { - BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode"); - return 0; - } - - if (((ID *)ob->data)->us > 1) { - BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); - return 0; - } - } - else if (((ID *)ob->data)->us > 1) { - BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); - return 0; - } - - if (md != ob->greasepencil_modifiers.first) - BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); - - if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) { - return 0; - } - - BLI_remlink(&ob->greasepencil_modifiers, md); - BKE_gpencil_modifier_free(md); - - return 1; + ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->isDisabled && mti->isDisabled(md, 0)) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + return 0; + } + + if (ob->type == OB_GPENCIL) { + if (ELEM(NULL, ob, ob->data)) { + return 0; + } + else if (mti->bakeModifier == NULL) { + BKE_report(reports, RPT_ERROR, "Not implemented"); + return 0; + } + mti->bakeModifier(bmain, depsgraph, md, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + + return 1; +} + +int ED_object_gpencil_modifier_apply(Main *bmain, + ReportList *reports, + Depsgraph *depsgraph, + Object *ob, + GpencilModifierData *md, + int UNUSED(mode)) +{ + + if (ob->type == OB_GPENCIL) { + if (ob->mode != OB_MODE_OBJECT) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode"); + return 0; + } + + if (((ID *)ob->data)->us > 1) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); + return 0; + } + } + else if (((ID *)ob->data)->us > 1) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); + return 0; + } + + if (md != ob->greasepencil_modifiers.first) + BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); + + if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) { + return 0; + } + + BLI_remlink(&ob->greasepencil_modifiers, md); + BKE_gpencil_modifier_free(md); + + return 1; } int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md) { - GpencilModifierData *nmd; - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - GpencilModifierType type = md->type; + GpencilModifierData *nmd; + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + GpencilModifierType type = md->type; - if (mti->flags & eGpencilModifierTypeFlag_Single) { - if (BKE_gpencil_modifiers_findByType(ob, type)) { - BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); - return 0; - } - } + if (mti->flags & eGpencilModifierTypeFlag_Single) { + if (BKE_gpencil_modifiers_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); + return 0; + } + } - nmd = BKE_gpencil_modifier_new(md->type); - BKE_gpencil_modifier_copyData(md, nmd); - BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd); - BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd); + nmd = BKE_gpencil_modifier_new(md->type); + BKE_gpencil_modifier_copyData(md, nmd); + BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd); + BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd); - return 1; + return 1; } /************************ add modifier operator *********************/ static int gpencil_modifier_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - int type = RNA_enum_get(op->ptr, "type"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); - if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) - return OPERATOR_CANCELLED; + if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static const EnumPropertyItem *gpencil_modifier_add_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *ob = ED_object_active_context(C); - EnumPropertyItem *item = NULL; - const EnumPropertyItem *md_item, *group_item = NULL; - const GpencilModifierTypeInfo *mti; - int totitem = 0, a; + Object *ob = ED_object_active_context(C); + EnumPropertyItem *item = NULL; + const EnumPropertyItem *md_item, *group_item = NULL; + const GpencilModifierTypeInfo *mti; + int totitem = 0, a; - if (!ob) - return rna_enum_object_greasepencil_modifier_type_items; + if (!ob) + return rna_enum_object_greasepencil_modifier_type_items; - for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) { - md_item = &rna_enum_object_greasepencil_modifier_type_items[a]; - if (md_item->identifier[0]) { - mti = BKE_gpencil_modifierType_getInfo(md_item->value); + for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) { + md_item = &rna_enum_object_greasepencil_modifier_type_items[a]; + if (md_item->identifier[0]) { + mti = BKE_gpencil_modifierType_getInfo(md_item->value); - if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) - continue; - } - else { - group_item = md_item; - md_item = NULL; + if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) + continue; + } + else { + group_item = md_item; + md_item = NULL; - continue; - } + continue; + } - if (group_item) { - RNA_enum_item_add(&item, &totitem, group_item); - group_item = NULL; - } + if (group_item) { + RNA_enum_item_add(&item, &totitem, group_item); + group_item = NULL; + } - RNA_enum_item_add(&item, &totitem, md_item); - } + RNA_enum_item_add(&item, &totitem, md_item); + } - RNA_enum_item_end(&item, &totitem); - *r_free = true; + RNA_enum_item_end(&item, &totitem); + *r_free = true; - return item; + return item; } void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Add Grease Pencil Modifier"; - ot->description = "Add a procedural operation/effect to the active grease pencil object"; - ot->idname = "OBJECT_OT_gpencil_modifier_add"; + /* identifiers */ + ot->name = "Add Grease Pencil Modifier"; + ot->description = "Add a procedural operation/effect to the active grease pencil object"; + ot->idname = "OBJECT_OT_gpencil_modifier_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = gpencil_modifier_add_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = gpencil_modifier_add_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eGpencilModifierType_Thick, "Type", ""); - RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf); - ot->prop = prop; + /* properties */ + prop = RNA_def_enum(ot->srna, + "type", + rna_enum_object_modifier_type_items, + eGpencilModifierType_Thick, + "Type", + ""); + RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf); + ot->prop = prop; } /************************ generic functions for operators using mod names and data context *********************/ static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); - Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - if (!ob || ID_IS_LINKED(ob)) return 0; - if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; - if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0; + if (!ob || ID_IS_LINKED(ob)) + return 0; + if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) + return 0; + if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) + return 0; - if (ID_IS_STATIC_OVERRIDE(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override"); - return (((GpencilModifierData *)ptr.data)->flag & eGpencilModifierFlag_StaticOverride_Local) != 0; - } + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override"); + return (((GpencilModifierData *)ptr.data)->flag & eGpencilModifierFlag_StaticOverride_Local) != + 0; + } - return 1; + return 1; } static bool gpencil_edit_modifier_poll(bContext *C) { - return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0); + return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0); } static void gpencil_edit_modifier_properties(wmOperatorType *ot) { - PropertyRNA *prop = RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_def_string( + ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); + RNA_def_property_flag(prop, PROP_HIDDEN); } static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op) { - GpencilModifierData *md; + GpencilModifierData *md; - if (RNA_struct_property_is_set(op->ptr, "modifier")) { - return true; - } - else { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier); - if (ptr.data) { - md = ptr.data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; - } - } + if (RNA_struct_property_is_set(op->ptr, "modifier")) { + return true; + } + else { + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier); + if (ptr.data) { + md = ptr.data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + } - return false; + return false; } -static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type) +static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, + Object *ob, + int type) { - char modifier_name[MAX_NAME]; - GpencilModifierData *md; - RNA_string_get(op->ptr, "modifier", modifier_name); + char modifier_name[MAX_NAME]; + GpencilModifierData *md; + RNA_string_get(op->ptr, "modifier", modifier_name); - md = BKE_gpencil_modifiers_findByName(ob, modifier_name); + md = BKE_gpencil_modifiers_findByName(ob, modifier_name); - if (md && type != 0 && md->type != type) - md = NULL; + if (md && type != 0 && md->type != type) + md = NULL; - return md; + return md; } /************************ remove modifier operator *********************/ static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int gpencil_modifier_remove_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (gpencil_edit_modifier_invoke_properties(C, op)) - return gpencil_modifier_remove_exec(C, op); - else - return OPERATOR_CANCELLED; + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_remove_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot) { - ot->name = "Remove Grease Pencil Modifier"; - ot->description = "Remove a modifier from the active grease pencil object"; - ot->idname = "OBJECT_OT_gpencil_modifier_remove"; + ot->name = "Remove Grease Pencil Modifier"; + ot->description = "Remove a modifier from the active grease pencil object"; + ot->idname = "OBJECT_OT_gpencil_modifier_remove"; - ot->invoke = gpencil_modifier_remove_invoke; - ot->exec = gpencil_modifier_remove_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->invoke = gpencil_modifier_remove_invoke; + ot->exec = gpencil_modifier_remove_exec; + ot->poll = gpencil_edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - gpencil_edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); } /************************ move up modifier operator *********************/ static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int gpencil_modifier_move_up_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (gpencil_edit_modifier_invoke_properties(C, op)) - return gpencil_modifier_move_up_exec(C, op); - else - return OPERATOR_CANCELLED; + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot) { - ot->name = "Move Up Modifier"; - ot->description = "Move modifier up in the stack"; - ot->idname = "OBJECT_OT_gpencil_modifier_move_up"; + ot->name = "Move Up Modifier"; + ot->description = "Move modifier up in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_move_up"; - ot->invoke = gpencil_modifier_move_up_invoke; - ot->exec = gpencil_modifier_move_up_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->invoke = gpencil_modifier_move_up_invoke; + ot->exec = gpencil_modifier_move_up_exec; + ot->poll = gpencil_edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - gpencil_edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); } /************************ move down modifier operator *********************/ static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int gpencil_modifier_move_down_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (gpencil_edit_modifier_invoke_properties(C, op)) - return gpencil_modifier_move_down_exec(C, op); - else - return OPERATOR_CANCELLED; + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot) { - ot->name = "Move Down Modifier"; - ot->description = "Move modifier down in the stack"; - ot->idname = "OBJECT_OT_gpencil_modifier_move_down"; + ot->name = "Move Down Modifier"; + ot->description = "Move modifier down in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_move_down"; - ot->invoke = gpencil_modifier_move_down_invoke; - ot->exec = gpencil_modifier_move_down_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->invoke = gpencil_modifier_move_down_invoke; + ot->exec = gpencil_modifier_move_down_exec; + ot->poll = gpencil_edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - gpencil_edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); } /************************ apply modifier operator *********************/ static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *ob = ED_object_active_context(C); - GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - int apply_as = RNA_enum_get(op->ptr, "apply_as"); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + int apply_as = RNA_enum_get(op->ptr, "apply_as"); - if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { - return OPERATOR_CANCELLED; - } + if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { + return OPERATOR_CANCELLED; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (gpencil_edit_modifier_invoke_properties(C, op)) - return gpencil_modifier_apply_exec(C, op); - else - return OPERATOR_CANCELLED; + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_apply_exec(C, op); + else + return OPERATOR_CANCELLED; } static const EnumPropertyItem gpencil_modifier_apply_as_items[] = { - {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"}, - {MODIFIER_APPLY_SHAPE, "SHAPE", 0, "New Shape", "Apply deform-only modifier to a new shape on this object"}, - {0, NULL, 0, NULL, NULL}, + {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"}, + {MODIFIER_APPLY_SHAPE, + "SHAPE", + 0, + "New Shape", + "Apply deform-only modifier to a new shape on this object"}, + {0, NULL, 0, NULL, NULL}, }; void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot) { - ot->name = "Apply Modifier"; - ot->description = "Apply modifier and remove from the stack"; - ot->idname = "OBJECT_OT_gpencil_modifier_apply"; + ot->name = "Apply Modifier"; + ot->description = "Apply modifier and remove from the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_apply"; - ot->invoke = gpencil_modifier_apply_invoke; - ot->exec = gpencil_modifier_apply_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->invoke = gpencil_modifier_apply_invoke; + ot->exec = gpencil_modifier_apply_exec; + ot->poll = gpencil_edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - RNA_def_enum(ot->srna, "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry"); - gpencil_edit_modifier_properties(ot); + RNA_def_enum(ot->srna, + "apply_as", + gpencil_modifier_apply_as_items, + MODIFIER_APPLY_DATA, + "Apply as", + "How to apply the modifier to the geometry"); + gpencil_edit_modifier_properties(ot); } /************************ copy modifier operator *********************/ static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (gpencil_edit_modifier_invoke_properties(C, op)) - return gpencil_modifier_copy_exec(C, op); - else - return OPERATOR_CANCELLED; + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_copy_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot) { - ot->name = "Copy Modifier"; - ot->description = "Duplicate modifier at the same position in the stack"; - ot->idname = "OBJECT_OT_gpencil_modifier_copy"; + ot->name = "Copy Modifier"; + ot->description = "Duplicate modifier at the same position in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_copy"; - ot->invoke = gpencil_modifier_copy_invoke; - ot->exec = gpencil_modifier_copy_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->invoke = gpencil_modifier_copy_invoke; + ot->exec = gpencil_modifier_copy_exec; + ot->poll = gpencil_edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - gpencil_edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 401260df406..d4e5ba42be2 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdlib.h> #include <string.h> @@ -69,857 +68,897 @@ #include "object_intern.h" -static int return_editmesh_indexar( - BMEditMesh *em, - int *r_tot, int **r_indexar, float r_cent[3]) +static int return_editmesh_indexar(BMEditMesh *em, int *r_tot, int **r_indexar, float r_cent[3]) { - BMVert *eve; - BMIter iter; - int *index, nr, totvert = 0; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++; - } - if (totvert == 0) return 0; - - *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar"); - *r_tot = totvert; - nr = 0; - zero_v3(r_cent); - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - *index = nr; index++; - add_v3_v3(r_cent, eve->co); - } - nr++; - } - - mul_v3_fl(r_cent, 1.0f / (float)totvert); - - return totvert; + BMVert *eve; + BMIter iter; + int *index, nr, totvert = 0; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) + totvert++; + } + if (totvert == 0) + return 0; + + *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar"); + *r_tot = totvert; + nr = 0; + zero_v3(r_cent); + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + *index = nr; + index++; + add_v3_v3(r_cent, eve->co); + } + nr++; + } + + mul_v3_fl(r_cent, 1.0f / (float)totvert); + + return totvert; } static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3]) { - const int cd_dvert_offset = obedit->actdef ? CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) : -1; - - zero_v3(r_cent); - - if (cd_dvert_offset != -1) { - const int defgrp_index = obedit->actdef - 1; - int totvert = 0; - - MDeformVert *dvert; - BMVert *eve; - BMIter iter; - - /* find the vertices */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - - if (defvert_find_weight(dvert, defgrp_index) > 0.0f) { - add_v3_v3(r_cent, eve->co); - totvert++; - } - } - if (totvert) { - bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index); - BLI_strncpy(r_name, dg->name, sizeof(dg->name)); - mul_v3_fl(r_cent, 1.0f / (float)totvert); - return true; - } - } - - return false; + const int cd_dvert_offset = obedit->actdef ? + CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) : + -1; + + zero_v3(r_cent); + + if (cd_dvert_offset != -1) { + const int defgrp_index = obedit->actdef - 1; + int totvert = 0; + + MDeformVert *dvert; + BMVert *eve; + BMIter iter; + + /* find the vertices */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + + if (defvert_find_weight(dvert, defgrp_index) > 0.0f) { + add_v3_v3(r_cent, eve->co); + totvert++; + } + } + if (totvert) { + bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index); + BLI_strncpy(r_name, dg->name, sizeof(dg->name)); + mul_v3_fl(r_cent, 1.0f / (float)totvert); + return true; + } + } + + return false; } static void select_editbmesh_hook(Object *ob, HookModifierData *hmd) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMVert *eve; - BMIter iter; - int index = 0, nr = 0; - - if (hmd->indexar == NULL) - return; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (nr == hmd->indexar[index]) { - BM_vert_select_set(em->bm, eve, true); - if (index < hmd->totindex - 1) index++; - } - - nr++; - } - - EDBM_select_flush(em); + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMVert *eve; + BMIter iter; + int index = 0, nr = 0; + + if (hmd->indexar == NULL) + return; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (nr == hmd->indexar[index]) { + BM_vert_select_set(em->bm, eve, true); + if (index < hmd->totindex - 1) + index++; + } + + nr++; + } + + EDBM_select_flush(em); } -static int return_editlattice_indexar( - Lattice *editlatt, - int *r_tot, int **r_indexar, float r_cent[3]) +static int return_editlattice_indexar(Lattice *editlatt, + int *r_tot, + int **r_indexar, + float r_cent[3]) { - BPoint *bp; - int *index, nr, totvert = 0, a; - - /* count */ - a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw; - bp = editlatt->def; - while (a--) { - if (bp->f1 & SELECT) { - if (bp->hide == 0) totvert++; - } - bp++; - } - - if (totvert == 0) return 0; - - *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar"); - *r_tot = totvert; - nr = 0; - zero_v3(r_cent); - - a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw; - bp = editlatt->def; - while (a--) { - if (bp->f1 & SELECT) { - if (bp->hide == 0) { - *index = nr; index++; - add_v3_v3(r_cent, bp->vec); - } - } - bp++; - nr++; - } - - mul_v3_fl(r_cent, 1.0f / (float)totvert); - - return totvert; + BPoint *bp; + int *index, nr, totvert = 0, a; + + /* count */ + a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw; + bp = editlatt->def; + while (a--) { + if (bp->f1 & SELECT) { + if (bp->hide == 0) + totvert++; + } + bp++; + } + + if (totvert == 0) + return 0; + + *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar"); + *r_tot = totvert; + nr = 0; + zero_v3(r_cent); + + a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw; + bp = editlatt->def; + while (a--) { + if (bp->f1 & SELECT) { + if (bp->hide == 0) { + *index = nr; + index++; + add_v3_v3(r_cent, bp->vec); + } + } + bp++; + nr++; + } + + mul_v3_fl(r_cent, 1.0f / (float)totvert); + + return totvert; } static void select_editlattice_hook(Object *obedit, HookModifierData *hmd) { - Lattice *lt = obedit->data, *editlt; - BPoint *bp; - int index = 0, nr = 0, a; - - editlt = lt->editlatt->latt; - /* count */ - a = editlt->pntsu * editlt->pntsv * editlt->pntsw; - bp = editlt->def; - while (a--) { - if (hmd->indexar[index] == nr) { - bp->f1 |= SELECT; - if (index < hmd->totindex - 1) index++; - } - nr++; - bp++; - } + Lattice *lt = obedit->data, *editlt; + BPoint *bp; + int index = 0, nr = 0, a; + + editlt = lt->editlatt->latt; + /* count */ + a = editlt->pntsu * editlt->pntsv * editlt->pntsw; + bp = editlt->def; + while (a--) { + if (hmd->indexar[index] == nr) { + bp->f1 |= SELECT; + if (index < hmd->totindex - 1) + index++; + } + nr++; + bp++; + } } -static int return_editcurve_indexar( - Object *obedit, - int *r_tot, int **r_indexar, float r_cent[3]) +static int return_editcurve_indexar(Object *obedit, int *r_tot, int **r_indexar, float r_cent[3]) { - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BPoint *bp; - BezTriple *bezt; - int *index, a, nr, totvert = 0; - - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (bezt->f1 & SELECT) totvert++; - if (bezt->f2 & SELECT) totvert++; - if (bezt->f3 & SELECT) totvert++; - bezt++; - } - } - else { - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->f1 & SELECT) totvert++; - bp++; - } - } - } - if (totvert == 0) return 0; - - *r_indexar = index = MEM_mallocN(sizeof(*index) * totvert, "hook indexar"); - *r_tot = totvert; - nr = 0; - zero_v3(r_cent); - - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (bezt->f1 & SELECT) { - *index = nr; index++; - add_v3_v3(r_cent, bezt->vec[0]); - } - nr++; - if (bezt->f2 & SELECT) { - *index = nr; index++; - add_v3_v3(r_cent, bezt->vec[1]); - } - nr++; - if (bezt->f3 & SELECT) { - *index = nr; index++; - add_v3_v3(r_cent, bezt->vec[2]); - } - nr++; - bezt++; - } - } - else { - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->f1 & SELECT) { - *index = nr; index++; - add_v3_v3(r_cent, bp->vec); - } - nr++; - bp++; - } - } - } - - mul_v3_fl(r_cent, 1.0f / (float)totvert); - - return totvert; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int *index, a, nr, totvert = 0; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (bezt->f1 & SELECT) + totvert++; + if (bezt->f2 & SELECT) + totvert++; + if (bezt->f3 & SELECT) + totvert++; + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->f1 & SELECT) + totvert++; + bp++; + } + } + } + if (totvert == 0) + return 0; + + *r_indexar = index = MEM_mallocN(sizeof(*index) * totvert, "hook indexar"); + *r_tot = totvert; + nr = 0; + zero_v3(r_cent); + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (bezt->f1 & SELECT) { + *index = nr; + index++; + add_v3_v3(r_cent, bezt->vec[0]); + } + nr++; + if (bezt->f2 & SELECT) { + *index = nr; + index++; + add_v3_v3(r_cent, bezt->vec[1]); + } + nr++; + if (bezt->f3 & SELECT) { + *index = nr; + index++; + add_v3_v3(r_cent, bezt->vec[2]); + } + nr++; + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->f1 & SELECT) { + *index = nr; + index++; + add_v3_v3(r_cent, bp->vec); + } + nr++; + bp++; + } + } + } + + mul_v3_fl(r_cent, 1.0f / (float)totvert); + + return totvert; } -static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit, - int *r_tot, int **r_indexar, char *r_name, float r_cent[3]) +static bool object_hook_index_array(Main *bmain, + Scene *scene, + Object *obedit, + int *r_tot, + int **r_indexar, + char *r_name, + float r_cent[3]) { - *r_indexar = NULL; - *r_tot = 0; - r_name[0] = 0; - - switch (obedit->type) { - case OB_MESH: - { - Mesh *me = obedit->data; - - BMEditMesh *em; - - EDBM_mesh_load(bmain, obedit); - EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); - - DEG_id_tag_update(obedit->data, 0); - - em = me->edit_mesh; - - EDBM_mesh_normals_update(em); - BKE_editmesh_tessface_calc(em); - - /* check selected vertices first */ - if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) { - return return_editmesh_vgroup(obedit, em, r_name, r_cent); - } - return true; - } - case OB_CURVE: - case OB_SURF: - ED_curve_editnurb_load(bmain, obedit); - ED_curve_editnurb_make(obedit); - return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent); - case OB_LATTICE: - { - Lattice *lt = obedit->data; - return return_editlattice_indexar(lt->editlatt->latt, r_tot, r_indexar, r_cent); - } - default: - return false; - } + *r_indexar = NULL; + *r_tot = 0; + r_name[0] = 0; + + switch (obedit->type) { + case OB_MESH: { + Mesh *me = obedit->data; + + BMEditMesh *em; + + EDBM_mesh_load(bmain, obedit); + EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); + + DEG_id_tag_update(obedit->data, 0); + + em = me->edit_mesh; + + EDBM_mesh_normals_update(em); + BKE_editmesh_tessface_calc(em); + + /* check selected vertices first */ + if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) { + return return_editmesh_vgroup(obedit, em, r_name, r_cent); + } + return true; + } + case OB_CURVE: + case OB_SURF: + ED_curve_editnurb_load(bmain, obedit); + ED_curve_editnurb_make(obedit); + return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent); + case OB_LATTICE: { + Lattice *lt = obedit->data; + return return_editlattice_indexar(lt->editlatt->latt, r_tot, r_indexar, r_cent); + } + default: + return false; + } } static void select_editcurve_hook(Object *obedit, HookModifierData *hmd) { - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BPoint *bp; - BezTriple *bezt; - int index = 0, a, nr = 0; - - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (nr == hmd->indexar[index]) { - bezt->f1 |= SELECT; - if (index < hmd->totindex - 1) index++; - } - nr++; - if (nr == hmd->indexar[index]) { - bezt->f2 |= SELECT; - if (index < hmd->totindex - 1) index++; - } - nr++; - if (nr == hmd->indexar[index]) { - bezt->f3 |= SELECT; - if (index < hmd->totindex - 1) index++; - } - nr++; - - bezt++; - } - } - else { - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - if (nr == hmd->indexar[index]) { - bp->f1 |= SELECT; - if (index < hmd->totindex - 1) index++; - } - nr++; - bp++; - } - } - } + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int index = 0, a, nr = 0; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (nr == hmd->indexar[index]) { + bezt->f1 |= SELECT; + if (index < hmd->totindex - 1) + index++; + } + nr++; + if (nr == hmd->indexar[index]) { + bezt->f2 |= SELECT; + if (index < hmd->totindex - 1) + index++; + } + nr++; + if (nr == hmd->indexar[index]) { + bezt->f3 |= SELECT; + if (index < hmd->totindex - 1) + index++; + } + nr++; + + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (nr == hmd->indexar[index]) { + bp->f1 |= SELECT; + if (index < hmd->totindex - 1) + index++; + } + nr++; + bp++; + } + } + } } -static void object_hook_from_context(bContext *C, PointerRNA *ptr, const int num, - Object **r_ob, HookModifierData **r_hmd) +static void object_hook_from_context( + bContext *C, PointerRNA *ptr, const int num, Object **r_ob, HookModifierData **r_hmd) { - Object *ob; - HookModifierData *hmd; - - if (ptr->data) { /* if modifier context is available, use that */ - ob = ptr->id.data; - hmd = ptr->data; - } - else { /* use the provided property */ - ob = CTX_data_edit_object(C); - hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); - } - - if (ob && hmd && (hmd->modifier.type == eModifierType_Hook)) { - *r_ob = ob; - *r_hmd = hmd; - } - else { - *r_ob = NULL; - *r_hmd = NULL; - } + Object *ob; + HookModifierData *hmd; + + if (ptr->data) { /* if modifier context is available, use that */ + ob = ptr->id.data; + hmd = ptr->data; + } + else { /* use the provided property */ + ob = CTX_data_edit_object(C); + hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); + } + + if (ob && hmd && (hmd->modifier.type == eModifierType_Hook)) { + *r_ob = ob; + *r_hmd = hmd; + } + else { + *r_ob = NULL; + *r_hmd = NULL; + } } static void object_hook_select(Object *ob, HookModifierData *hmd) { - if (hmd->indexar == NULL) - return; - - if (ob->type == OB_MESH) select_editbmesh_hook(ob, hmd); - else if (ob->type == OB_LATTICE) select_editlattice_hook(ob, hmd); - else if (ob->type == OB_CURVE) select_editcurve_hook(ob, hmd); - else if (ob->type == OB_SURF) select_editcurve_hook(ob, hmd); + if (hmd->indexar == NULL) + return; + + if (ob->type == OB_MESH) + select_editbmesh_hook(ob, hmd); + else if (ob->type == OB_LATTICE) + select_editlattice_hook(ob, hmd); + else if (ob->type == OB_CURVE) + select_editcurve_hook(ob, hmd); + else if (ob->type == OB_SURF) + select_editcurve_hook(ob, hmd); } /* special poll operators for hook operators */ /* TODO: check for properties window modifier context too as alternative? */ static bool hook_op_edit_poll(bContext *C) { - Object *obedit = CTX_data_edit_object(C); - - if (obedit) { - if (ED_operator_editmesh(C)) return 1; - if (ED_operator_editsurfcurve(C)) return 1; - if (ED_operator_editlattice(C)) return 1; - //if (ED_operator_editmball(C)) return 1; - } - - return 0; + Object *obedit = CTX_data_edit_object(C); + + if (obedit) { + if (ED_operator_editmesh(C)) + return 1; + if (ED_operator_editsurfcurve(C)) + return 1; + if (ED_operator_editlattice(C)) + return 1; + //if (ED_operator_editmball(C)) return 1; + } + + return 0; } -static Object *add_hook_object_new(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, Object *obedit) +static Object *add_hook_object_new( + Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, Object *obedit) { - Base *basedit; - Object *ob; + Base *basedit; + Object *ob; - ob = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); + ob = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); - basedit = BKE_view_layer_base_find(view_layer, obedit); - BLI_assert(view_layer->basact->object == ob); + basedit = BKE_view_layer_base_find(view_layer, obedit); + BLI_assert(view_layer->basact->object == ob); - if (v3d && v3d->localvd) { - view_layer->basact->local_view_bits |= v3d->local_view_uuid; - } + if (v3d && v3d->localvd) { + view_layer->basact->local_view_bits |= v3d->local_view_uuid; + } - /* icky, BKE_object_add sets new base as active. - * so set it back to the original edit object */ - view_layer->basact = basedit; + /* icky, BKE_object_add sets new base as active. + * so set it back to the original edit object */ + view_layer->basact = basedit; - return ob; + return ob; } -static int add_hook_object( - const bContext *C, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - View3D *v3d, - Object *obedit, - Object *ob, - int mode, - ReportList *reports) +static int add_hook_object(const bContext *C, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + View3D *v3d, + Object *obedit, + Object *ob, + int mode, + ReportList *reports) { - ModifierData *md = NULL; - HookModifierData *hmd = NULL; - float cent[3]; - float pose_mat[4][4]; - int tot, ok, *indexar; - char name[MAX_NAME]; - - ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent); - - if (!ok) { - BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group"); - return false; - } - - if (mode == OBJECT_ADDHOOK_NEWOB && !ob) { - - ob = add_hook_object_new(bmain, scene, view_layer, v3d, obedit); - - /* transform cent to global coords for loc */ - mul_v3_m4v3(ob->loc, obedit->obmat, cent); - } - - md = obedit->modifiers.first; - while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) { - md = md->next; - } - - hmd = (HookModifierData *) modifier_new(eModifierType_Hook); - BLI_insertlinkbefore(&obedit->modifiers, md, hmd); - BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2); - modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd); - - hmd->object = ob; - hmd->indexar = indexar; - copy_v3_v3(hmd->cent, cent); - hmd->totindex = tot; - BLI_strncpy(hmd->name, name, sizeof(hmd->name)); - - unit_m4(pose_mat); - - invert_m4_m4(obedit->imat, obedit->obmat); - if (mode == OBJECT_ADDHOOK_NEWOB) { - /* pass */ - } - else { - /* may overwrite with pose-bone location, below */ - mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]); - } - - if (mode == OBJECT_ADDHOOK_SELOB_BONE) { - bArmature *arm = ob->data; - BLI_assert(ob->type == OB_ARMATURE); - if (arm->act_bone) { - bPoseChannel *pchan_act; - - BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget)); - - pchan_act = BKE_pose_channel_active(ob); - if (LIKELY(pchan_act)) { - invert_m4_m4(pose_mat, pchan_act->pose_mat); - mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); - mul_v3_m4v3(cent, obedit->imat, cent); - } - } - else { - BKE_report(reports, RPT_WARNING, "Armature has no active object bone"); - } - } - - copy_v3_v3(hmd->cent, cent); - - - /* matrix calculus */ - /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ - /* (parentinv ) */ - BKE_object_where_is_calc(CTX_data_depsgraph(C), scene, ob); - - invert_m4_m4(ob->imat, ob->obmat); - /* apparently this call goes from right to left... */ - mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat); - - DEG_relations_tag_update(bmain); - - return true; + ModifierData *md = NULL; + HookModifierData *hmd = NULL; + float cent[3]; + float pose_mat[4][4]; + int tot, ok, *indexar; + char name[MAX_NAME]; + + ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent); + + if (!ok) { + BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group"); + return false; + } + + if (mode == OBJECT_ADDHOOK_NEWOB && !ob) { + + ob = add_hook_object_new(bmain, scene, view_layer, v3d, obedit); + + /* transform cent to global coords for loc */ + mul_v3_m4v3(ob->loc, obedit->obmat, cent); + } + + md = obedit->modifiers.first; + while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) { + md = md->next; + } + + hmd = (HookModifierData *)modifier_new(eModifierType_Hook); + BLI_insertlinkbefore(&obedit->modifiers, md, hmd); + BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2); + modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd); + + hmd->object = ob; + hmd->indexar = indexar; + copy_v3_v3(hmd->cent, cent); + hmd->totindex = tot; + BLI_strncpy(hmd->name, name, sizeof(hmd->name)); + + unit_m4(pose_mat); + + invert_m4_m4(obedit->imat, obedit->obmat); + if (mode == OBJECT_ADDHOOK_NEWOB) { + /* pass */ + } + else { + /* may overwrite with pose-bone location, below */ + mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]); + } + + if (mode == OBJECT_ADDHOOK_SELOB_BONE) { + bArmature *arm = ob->data; + BLI_assert(ob->type == OB_ARMATURE); + if (arm->act_bone) { + bPoseChannel *pchan_act; + + BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget)); + + pchan_act = BKE_pose_channel_active(ob); + if (LIKELY(pchan_act)) { + invert_m4_m4(pose_mat, pchan_act->pose_mat); + mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); + mul_v3_m4v3(cent, obedit->imat, cent); + } + } + else { + BKE_report(reports, RPT_WARNING, "Armature has no active object bone"); + } + } + + copy_v3_v3(hmd->cent, cent); + + /* matrix calculus */ + /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ + /* (parentinv ) */ + BKE_object_where_is_calc(CTX_data_depsgraph(C), scene, ob); + + invert_m4_m4(ob->imat, ob->obmat); + /* apparently this call goes from right to left... */ + mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat); + + DEG_relations_tag_update(bmain); + + return true; } static int object_add_hook_selob_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - Object *obsel = NULL; - const bool use_bone = RNA_boolean_get(op->ptr, "use_bone"); - const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - if (ob != obedit) { - obsel = ob; - break; - } - } - CTX_DATA_END; - - if (!obsel) { - BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects"); - return OPERATOR_CANCELLED; - } - - if (use_bone && obsel->type != OB_ARMATURE) { - BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object"); - return OPERATOR_CANCELLED; - } - - if (add_hook_object(C, bmain, scene, view_layer, NULL, obedit, obsel, mode, op->reports)) { - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + Object *obsel = NULL; + const bool use_bone = RNA_boolean_get(op->ptr, "use_bone"); + const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob != obedit) { + obsel = ob; + break; + } + } + CTX_DATA_END; + + if (!obsel) { + BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects"); + return OPERATOR_CANCELLED; + } + + if (use_bone && obsel->type != OB_ARMATURE) { + BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object"); + return OPERATOR_CANCELLED; + } + + if (add_hook_object(C, bmain, scene, view_layer, NULL, obedit, obsel, mode, op->reports)) { + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_hook_add_selob(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hook to Selected Object"; - ot->description = "Hook selected vertices to the first selected object"; - ot->idname = "OBJECT_OT_hook_add_selob"; - - /* api callbacks */ - ot->exec = object_add_hook_selob_exec; - ot->poll = hook_op_edit_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "use_bone", false, "Active Bone", - "Assign the hook to the hook objects active bone"); + /* identifiers */ + ot->name = "Hook to Selected Object"; + ot->description = "Hook selected vertices to the first selected object"; + ot->idname = "OBJECT_OT_hook_add_selob"; + + /* api callbacks */ + ot->exec = object_add_hook_selob_exec; + ot->poll = hook_op_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, + "use_bone", + false, + "Active Bone", + "Assign the hook to the hook objects active bone"); } static int object_add_hook_newob_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Object *obedit = CTX_data_edit_object(C); - - if (add_hook_object(C, bmain, scene, view_layer, v3d, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Object *obedit = CTX_data_edit_object(C); + + if (add_hook_object( + C, bmain, scene, view_layer, v3d, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_hook_add_newob(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hook to New Object"; - ot->description = "Hook selected vertices to a newly created object"; - ot->idname = "OBJECT_OT_hook_add_newob"; + /* identifiers */ + ot->name = "Hook to New Object"; + ot->description = "Hook selected vertices to a newly created object"; + ot->idname = "OBJECT_OT_hook_add_newob"; - /* api callbacks */ - ot->exec = object_add_hook_newob_exec; - ot->poll = hook_op_edit_poll; + /* api callbacks */ + ot->exec = object_add_hook_newob_exec; + ot->poll = hook_op_edit_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int object_hook_remove_exec(bContext *C, wmOperator *op) { - int num = RNA_enum_get(op->ptr, "modifier"); - Object *ob = CTX_data_edit_object(C); - HookModifierData *hmd = NULL; + int num = RNA_enum_get(op->ptr, "modifier"); + Object *ob = CTX_data_edit_object(C); + HookModifierData *hmd = NULL; - hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); - if (!hmd) { - BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); - return OPERATOR_CANCELLED; - } + hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); + if (!hmd) { + BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); + return OPERATOR_CANCELLED; + } - /* remove functionality */ + /* remove functionality */ - BLI_remlink(&ob->modifiers, (ModifierData *)hmd); - modifier_free((ModifierData *)hmd); + BLI_remlink(&ob->modifiers, (ModifierData *)hmd); + modifier_free((ModifierData *)hmd); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static const EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *hook_mod_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *ob = CTX_data_edit_object(C); - EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; - ModifierData *md = NULL; - int a, totitem = 0; - - if (!ob) - return DummyRNA_NULL_items; - - for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) { - if (md->type == eModifierType_Hook) { - tmp.value = a; - tmp.icon = ICON_HOOK; - tmp.identifier = md->name; - tmp.name = md->name; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Object *ob = CTX_data_edit_object(C); + EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem *item = NULL; + ModifierData *md = NULL; + int a, totitem = 0; + + if (!ob) + return DummyRNA_NULL_items; + + for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) { + if (md->type == eModifierType_Hook) { + tmp.value = a; + tmp.icon = ICON_HOOK; + tmp.identifier = md->name; + tmp.name = md->name; + RNA_enum_item_add(&item, &totitem, &tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } void OBJECT_OT_hook_remove(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Remove Hook"; - ot->idname = "OBJECT_OT_hook_remove"; - ot->description = "Remove a hook from the active object"; - - /* api callbacks */ - ot->exec = object_hook_remove_exec; - ot->invoke = WM_menu_invoke; - ot->poll = hook_op_edit_poll; - - /* flags */ - /* this operator removes modifier which isn't stored in local undo stack, - * so redoing it from redo panel gives totally weird results */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove"); - RNA_def_enum_funcs(prop, hook_mod_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Remove Hook"; + ot->idname = "OBJECT_OT_hook_remove"; + ot->description = "Remove a hook from the active object"; + + /* api callbacks */ + ot->exec = object_hook_remove_exec; + ot->invoke = WM_menu_invoke; + ot->poll = hook_op_edit_poll; + + /* flags */ + /* this operator removes modifier which isn't stored in local undo stack, + * so redoing it from redo panel gives totally weird results */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum( + ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove"); + RNA_def_enum_funcs(prop, hook_mod_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static int object_hook_reset_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); - int num = RNA_enum_get(op->ptr, "modifier"); - Object *ob = NULL; - HookModifierData *hmd = NULL; + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); + int num = RNA_enum_get(op->ptr, "modifier"); + Object *ob = NULL; + HookModifierData *hmd = NULL; - object_hook_from_context(C, &ptr, num, &ob, &hmd); - if (hmd == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); - return OPERATOR_CANCELLED; - } + object_hook_from_context(C, &ptr, num, &ob, &hmd); + if (hmd == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); + return OPERATOR_CANCELLED; + } - BKE_object_modifier_hook_reset(ob, hmd); + BKE_object_modifier_hook_reset(ob, hmd); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_hook_reset(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Reset Hook"; - ot->description = "Recalculate and clear offset transformation"; - ot->idname = "OBJECT_OT_hook_reset"; + /* identifiers */ + ot->name = "Reset Hook"; + ot->description = "Recalculate and clear offset transformation"; + ot->idname = "OBJECT_OT_hook_reset"; - /* callbacks */ - ot->exec = object_hook_reset_exec; - ot->poll = hook_op_edit_poll; + /* callbacks */ + ot->exec = object_hook_reset_exec; + ot->poll = hook_op_edit_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); - RNA_def_enum_funcs(prop, hook_mod_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + /* properties */ + prop = RNA_def_enum( + ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); + RNA_def_enum_funcs(prop, hook_mod_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); } static int object_hook_recenter_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); - int num = RNA_enum_get(op->ptr, "modifier"); - Object *ob = NULL; - HookModifierData *hmd = NULL; - Scene *scene = CTX_data_scene(C); - float bmat[3][3], imat[3][3]; - - object_hook_from_context(C, &ptr, num, &ob, &hmd); - if (hmd == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); - return OPERATOR_CANCELLED; - } - - /* recenter functionality */ - copy_m3_m4(bmat, ob->obmat); - invert_m3_m3(imat, bmat); - - sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]); - mul_m3_v3(imat, hmd->cent); - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - - return OPERATOR_FINISHED; + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); + int num = RNA_enum_get(op->ptr, "modifier"); + Object *ob = NULL; + HookModifierData *hmd = NULL; + Scene *scene = CTX_data_scene(C); + float bmat[3][3], imat[3][3]; + + object_hook_from_context(C, &ptr, num, &ob, &hmd); + if (hmd == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); + return OPERATOR_CANCELLED; + } + + /* recenter functionality */ + copy_m3_m4(bmat, ob->obmat); + invert_m3_m3(imat, bmat); + + sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]); + mul_m3_v3(imat, hmd->cent); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; } void OBJECT_OT_hook_recenter(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Recenter Hook"; - ot->description = "Set hook center to cursor position"; - ot->idname = "OBJECT_OT_hook_recenter"; + /* identifiers */ + ot->name = "Recenter Hook"; + ot->description = "Set hook center to cursor position"; + ot->idname = "OBJECT_OT_hook_recenter"; - /* callbacks */ - ot->exec = object_hook_recenter_exec; - ot->poll = hook_op_edit_poll; + /* callbacks */ + ot->exec = object_hook_recenter_exec; + ot->poll = hook_op_edit_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); - RNA_def_enum_funcs(prop, hook_mod_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + /* properties */ + prop = RNA_def_enum( + ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); + RNA_def_enum_funcs(prop, hook_mod_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); } static int object_hook_assign_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); - int num = RNA_enum_get(op->ptr, "modifier"); - Object *ob = NULL; - HookModifierData *hmd = NULL; - float cent[3]; - char name[MAX_NAME]; - int *indexar, tot; - - object_hook_from_context(C, &ptr, num, &ob, &hmd); - if (hmd == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); - return OPERATOR_CANCELLED; - } - - /* assign functionality */ - - if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) { - BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group"); - return OPERATOR_CANCELLED; - } - if (hmd->indexar) - MEM_freeN(hmd->indexar); - - copy_v3_v3(hmd->cent, cent); - hmd->indexar = indexar; - hmd->totindex = tot; - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); + int num = RNA_enum_get(op->ptr, "modifier"); + Object *ob = NULL; + HookModifierData *hmd = NULL; + float cent[3]; + char name[MAX_NAME]; + int *indexar, tot; + + object_hook_from_context(C, &ptr, num, &ob, &hmd); + if (hmd == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); + return OPERATOR_CANCELLED; + } + + /* assign functionality */ + + if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) { + BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group"); + return OPERATOR_CANCELLED; + } + if (hmd->indexar) + MEM_freeN(hmd->indexar); + + copy_v3_v3(hmd->cent, cent); + hmd->indexar = indexar; + hmd->totindex = tot; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; } void OBJECT_OT_hook_assign(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Assign to Hook"; - ot->description = "Assign the selected vertices to a hook"; - ot->idname = "OBJECT_OT_hook_assign"; - - /* callbacks */ - ot->exec = object_hook_assign_exec; - ot->poll = hook_op_edit_poll; - - /* flags */ - /* this operator changes data stored in modifier which doesn't get pushed to undo stack, - * so redoing it from redo panel gives totally weird results */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); - RNA_def_enum_funcs(prop, hook_mod_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Assign to Hook"; + ot->description = "Assign the selected vertices to a hook"; + ot->idname = "OBJECT_OT_hook_assign"; + + /* callbacks */ + ot->exec = object_hook_assign_exec; + ot->poll = hook_op_edit_poll; + + /* flags */ + /* this operator changes data stored in modifier which doesn't get pushed to undo stack, + * so redoing it from redo panel gives totally weird results */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum( + ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to"); + RNA_def_enum_funcs(prop, hook_mod_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); } static int object_hook_select_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); - int num = RNA_enum_get(op->ptr, "modifier"); - Object *ob = NULL; - HookModifierData *hmd = NULL; + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); + int num = RNA_enum_get(op->ptr, "modifier"); + Object *ob = NULL; + HookModifierData *hmd = NULL; - object_hook_from_context(C, &ptr, num, &ob, &hmd); - if (hmd == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); - return OPERATOR_CANCELLED; - } + object_hook_from_context(C, &ptr, num, &ob, &hmd); + if (hmd == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier"); + return OPERATOR_CANCELLED; + } - /* select functionality */ - object_hook_select(ob, hmd); + /* select functionality */ + object_hook_select(ob, hmd); - DEG_id_tag_update(ob->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); + DEG_id_tag_update(ob->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_hook_select(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Hook"; - ot->description = "Select affected vertices on mesh"; - ot->idname = "OBJECT_OT_hook_select"; + /* identifiers */ + ot->name = "Select Hook"; + ot->description = "Select affected vertices on mesh"; + ot->idname = "OBJECT_OT_hook_select"; - /* callbacks */ - ot->exec = object_hook_select_exec; - ot->poll = hook_op_edit_poll; + /* callbacks */ + ot->exec = object_hook_select_exec; + ot->poll = hook_op_edit_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove"); - RNA_def_enum_funcs(prop, hook_mod_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + /* properties */ + prop = RNA_def_enum( + ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove"); + RNA_def_enum_funcs(prop, hook_mod_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 33f821126a2..d17b6515dbb 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -34,9 +34,9 @@ struct ModifierData; /* add hook menu */ enum eObject_Hook_Add_Mode { - OBJECT_ADDHOOK_NEWOB = 1, - OBJECT_ADDHOOK_SELOB, - OBJECT_ADDHOOK_SELOB_BONE, + OBJECT_ADDHOOK_NEWOB = 1, + OBJECT_ADDHOOK_SELOB, + OBJECT_ADDHOOK_SELOB_BONE, }; /* internal exports only */ @@ -141,7 +141,9 @@ bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, bool edit_modifier_poll(struct bContext *C); void edit_modifier_properties(struct wmOperatorType *ot); int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op); -struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type); +struct ModifierData *edit_modifier_property_get(struct wmOperator *op, + struct Object *ob, + int type); void OBJECT_OT_modifier_add(struct wmOperatorType *ot); void OBJECT_OT_modifier_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index dd0a37b4498..7c881aa7cab 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -45,7 +45,7 @@ #include "ED_armature.h" #include "ED_screen.h" -#include "ED_object.h" /* own include */ +#include "ED_object.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name High Level Mode Operations @@ -54,29 +54,29 @@ static const char *object_mode_op_string(eObjectMode mode) { - if (mode & OB_MODE_EDIT) - return "OBJECT_OT_editmode_toggle"; - if (mode == OB_MODE_SCULPT) - return "SCULPT_OT_sculptmode_toggle"; - if (mode == OB_MODE_VERTEX_PAINT) - return "PAINT_OT_vertex_paint_toggle"; - if (mode == OB_MODE_WEIGHT_PAINT) - return "PAINT_OT_weight_paint_toggle"; - if (mode == OB_MODE_TEXTURE_PAINT) - return "PAINT_OT_texture_paint_toggle"; - if (mode == OB_MODE_PARTICLE_EDIT) - return "PARTICLE_OT_particle_edit_toggle"; - if (mode == OB_MODE_POSE) - return "OBJECT_OT_posemode_toggle"; - if (mode == OB_MODE_EDIT_GPENCIL) - return "GPENCIL_OT_editmode_toggle"; - if (mode == OB_MODE_PAINT_GPENCIL) - return "GPENCIL_OT_paintmode_toggle"; - if (mode == OB_MODE_SCULPT_GPENCIL) - return "GPENCIL_OT_sculptmode_toggle"; - if (mode == OB_MODE_WEIGHT_GPENCIL) - return "GPENCIL_OT_weightmode_toggle"; - return NULL; + if (mode & OB_MODE_EDIT) + return "OBJECT_OT_editmode_toggle"; + if (mode == OB_MODE_SCULPT) + return "SCULPT_OT_sculptmode_toggle"; + if (mode == OB_MODE_VERTEX_PAINT) + return "PAINT_OT_vertex_paint_toggle"; + if (mode == OB_MODE_WEIGHT_PAINT) + return "PAINT_OT_weight_paint_toggle"; + if (mode == OB_MODE_TEXTURE_PAINT) + return "PAINT_OT_texture_paint_toggle"; + if (mode == OB_MODE_PARTICLE_EDIT) + return "PARTICLE_OT_particle_edit_toggle"; + if (mode == OB_MODE_POSE) + return "OBJECT_OT_posemode_toggle"; + if (mode == OB_MODE_EDIT_GPENCIL) + return "GPENCIL_OT_editmode_toggle"; + if (mode == OB_MODE_PAINT_GPENCIL) + return "GPENCIL_OT_paintmode_toggle"; + if (mode == OB_MODE_SCULPT_GPENCIL) + return "GPENCIL_OT_sculptmode_toggle"; + if (mode == OB_MODE_WEIGHT_GPENCIL) + return "GPENCIL_OT_weightmode_toggle"; + return NULL; } /** @@ -85,44 +85,42 @@ static const char *object_mode_op_string(eObjectMode mode) */ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) { - if (ob) { - if (mode == OB_MODE_OBJECT) - return true; + if (ob) { + if (mode == OB_MODE_OBJECT) + return true; - switch (ob->type) { - case OB_MESH: - if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | - OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) - { - return true; - } - break; - case OB_CURVE: - case OB_SURF: - case OB_FONT: - case OB_MBALL: - if (mode & (OB_MODE_EDIT)) - return true; - break; - case OB_LATTICE: - if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) - return true; - break; - case OB_ARMATURE: - if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) - return true; - break; - case OB_GPENCIL: - if (mode & (OB_MODE_EDIT | OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL | - OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL)) - { - return true; - } - break; - } - } + switch (ob->type) { + case OB_MESH: + if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | + OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) { + return true; + } + break; + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_MBALL: + if (mode & (OB_MODE_EDIT)) + return true; + break; + case OB_LATTICE: + if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) + return true; + break; + case OB_ARMATURE: + if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) + return true; + break; + case OB_GPENCIL: + if (mode & (OB_MODE_EDIT | OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL | + OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL)) { + return true; + } + break; + } + } - return false; + return false; } /** @@ -132,68 +130,66 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) */ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports) { - bool ok; - if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { - const char *opstring = object_mode_op_string(ob->mode); + bool ok; + if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { + const char *opstring = object_mode_op_string(ob->mode); - WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); - ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); - if (!ok) { - wmOperatorType *ot = WM_operatortype_find(opstring, false); - BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); - } - } - else { - ok = true; - } + WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); + if (!ok) { + wmOperatorType *ot = WM_operatortype_find(opstring, false); + BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); + } + } + else { + ok = true; + } - return ok; + return ok; } void ED_object_mode_toggle(bContext *C, eObjectMode mode) { - if (mode != OB_MODE_OBJECT) { - const char *opstring = object_mode_op_string(mode); + if (mode != OB_MODE_OBJECT) { + const char *opstring = object_mode_op_string(mode); - if (opstring) { - wmOperatorType *ot = WM_operatortype_find(opstring, false); - if (ot->flag & OPTYPE_USE_EVAL_DATA) { - /* We need to force refresh of depsgraph after undo step, - * redoing the operator *may* rely on some valid evaluated data. */ - struct Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer); - } - WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL); - } - } + if (opstring) { + wmOperatorType *ot = WM_operatortype_find(opstring, false); + if (ot->flag & OPTYPE_USE_EVAL_DATA) { + /* We need to force refresh of depsgraph after undo step, + * redoing the operator *may* rely on some valid evaluated data. */ + struct Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer); + } + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL); + } + } } - /* Wrapper for operator */ void ED_object_mode_set(bContext *C, eObjectMode mode) { - wmWindowManager *wm = CTX_wm_manager(C); - wm->op_undo_depth++; - /* needed so we don't do undo pushes. */ - ED_object_mode_generic_enter(C, mode); - wm->op_undo_depth--; + wmWindowManager *wm = CTX_wm_manager(C); + wm->op_undo_depth++; + /* needed so we don't do undo pushes. */ + ED_object_mode_generic_enter(C, mode); + wm->op_undo_depth--; } void ED_object_mode_exit(bContext *C) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - struct Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - FOREACH_OBJECT_BEGIN(view_layer, ob) - { - if (ob->mode & OB_MODE_ALL_MODE_DATA) { - ED_object_mode_generic_exit(bmain, depsgraph, scene, ob); - } - } - FOREACH_OBJECT_END; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + struct Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + FOREACH_OBJECT_BEGIN (view_layer, ob) { + if (ob->mode & OB_MODE_ALL_MODE_DATA) { + ED_object_mode_generic_exit(bmain, depsgraph, scene, ob); + } + } + FOREACH_OBJECT_END; } /** \} */ @@ -206,100 +202,97 @@ void ED_object_mode_exit(bContext *C) * * \{ */ -bool ED_object_mode_generic_enter( - struct bContext *C, eObjectMode object_mode) +bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - if (ob == NULL) { - return (object_mode == OB_MODE_OBJECT); - } - if (ob->mode == object_mode) { - return true; - } - wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_enum_set(&ptr, "mode", object_mode); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); - return (ob->mode == object_mode); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + if (ob == NULL) { + return (object_mode == OB_MODE_OBJECT); + } + if (ob->mode == object_mode) { + return true; + } + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_enum_set(&ptr, "mode", object_mode); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + return (ob->mode == object_mode); } /** * Use for changing works-paces or changing active object. * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run. */ -static bool ed_object_mode_generic_exit_ex( - struct Main *bmain, - struct Depsgraph *depsgraph, - struct Scene *scene, struct Object *ob, - bool only_test) +static bool ed_object_mode_generic_exit_ex(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + bool only_test) { - BLI_assert((bmain == NULL) == only_test); - if (ob->mode & OB_MODE_EDIT) { - if (BKE_object_is_in_editmode(ob)) { - if (only_test) { - return true; - } - ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); - } - } - else if (ob->mode & OB_MODE_VERTEX_PAINT) { - if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) { - if (only_test) { - return true; - } - ED_object_vpaintmode_exit_ex(ob); - } - } - else if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) { - if (only_test) { - return true; - } - ED_object_wpaintmode_exit_ex(ob); - } - } - else if (ob->mode & OB_MODE_SCULPT) { - if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) { - if (only_test) { - return true; - } - ED_object_sculptmode_exit_ex(depsgraph, scene, ob); - } - } - else if (ob->mode & OB_MODE_POSE) { - if (ob->pose != NULL) { - if (only_test) { - return true; - } - ED_object_posemode_exit_ex(bmain, ob); - } - } - else { - if (only_test) { - return false; - } - BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0); - } + BLI_assert((bmain == NULL) == only_test); + if (ob->mode & OB_MODE_EDIT) { + if (BKE_object_is_in_editmode(ob)) { + if (only_test) { + return true; + } + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); + } + } + else if (ob->mode & OB_MODE_VERTEX_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) { + if (only_test) { + return true; + } + ED_object_vpaintmode_exit_ex(ob); + } + } + else if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) { + if (only_test) { + return true; + } + ED_object_wpaintmode_exit_ex(ob); + } + } + else if (ob->mode & OB_MODE_SCULPT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) { + if (only_test) { + return true; + } + ED_object_sculptmode_exit_ex(depsgraph, scene, ob); + } + } + else if (ob->mode & OB_MODE_POSE) { + if (ob->pose != NULL) { + if (only_test) { + return true; + } + ED_object_posemode_exit_ex(bmain, ob); + } + } + else { + if (only_test) { + return false; + } + BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0); + } - return false; + return false; } -void ED_object_mode_generic_exit( - struct Main *bmain, - struct Depsgraph *depsgraph, - struct Scene *scene, struct Object *ob) +void ED_object_mode_generic_exit(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob) { - ed_object_mode_generic_exit_ex(bmain, depsgraph, scene, ob, false); + ed_object_mode_generic_exit_ex(bmain, depsgraph, scene, ob, false); } -bool ED_object_mode_generic_has_data( - struct Depsgraph *depsgraph, - struct Object *ob) +bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, struct Object *ob) { - return ed_object_mode_generic_exit_ex(NULL, depsgraph, NULL, ob, true); + return ed_object_mode_generic_exit_ex(NULL, depsgraph, NULL, ob, true); } /** \} */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 9576cbe6fa1..7aae0a41c85 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -95,133 +94,132 @@ static void modifier_skin_customdata_delete(struct Object *ob); static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *ob) { - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - BKE_object_eval_reset(ob_eval); - if (ob->type == OB_MESH) { - Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - BKE_id_free(NULL, me_eval); - } - else if (ob->type == OB_LATTICE) { - BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval); - } - else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(depsgraph, scene_eval, ob_eval); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false, NULL); - } -} - -static void object_force_modifier_bind_simple_options( - Depsgraph *depsgraph, - Object *object, - ModifierData *md) -{ - ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md); - const int mode = md_eval->mode; - md_eval->mode |= eModifierMode_Realtime; - object_force_modifier_update_for_bind(depsgraph, object); - md_eval->mode = mode; -} - -ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type) -{ - ModifierData *md = NULL, *new_md = NULL; - const ModifierTypeInfo *mti = modifierType_getInfo(type); - - /* Check compatibility of modifier [T25291, T50373]. */ - if (!BKE_object_support_modifier_type_check(ob, type)) { - BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); - return NULL; - } - - if (mti->flags & eModifierTypeFlag_Single) { - if (modifiers_findByType(ob, type)) { - BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); - return NULL; - } - } - - if (type == eModifierType_ParticleSystem) { - /* don't need to worry about the new modifier's name, since that is set to the number - * of particle systems which shouldn't have too many duplicates - */ - new_md = object_add_particle_system(bmain, scene, ob, name); - } - else { - /* get new modifier data to add */ - new_md = modifier_new(type); - - if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { - md = ob->modifiers.first; - - while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) - md = md->next; - - BLI_insertlinkbefore(&ob->modifiers, md, new_md); - } - else - BLI_addtail(&ob->modifiers, new_md); - - if (name) { - BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name)); - } - - /* make sure modifier data has unique name */ - - modifier_unique_name(&ob->modifiers, new_md); - - /* special cases */ - if (type == eModifierType_Softbody) { - if (!ob->soft) { - ob->soft = sbNew(scene); - ob->softflag |= OB_SB_GOAL | OB_SB_EDGES; - } - } - else if (type == eModifierType_Collision) { - if (!ob->pd) - ob->pd = BKE_partdeflect_new(0); - - ob->pd->deflect = 1; - } - else if (type == eModifierType_Surface) { - /* pass */ - } - else if (type == eModifierType_Multires) { - /* set totlvl from existing MDISPS layer if object already had it */ - multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob); - - if (ob->mode & OB_MODE_SCULPT) { - /* ensure that grid paint mask layer is created */ - BKE_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md); - } - } - else if (type == eModifierType_Skin) { - /* ensure skin-node customdata exists */ - BKE_mesh_ensure_skin_customdata(ob->data); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); - - return new_md; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_eval_reset(ob_eval); + if (ob->type == OB_MESH) { + Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + BKE_id_free(NULL, me_eval); + } + else if (ob->type == OB_LATTICE) { + BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval); + } + else if (ob->type == OB_MBALL) { + BKE_displist_make_mball(depsgraph, scene_eval, ob_eval); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false, NULL); + } +} + +static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph, + Object *object, + ModifierData *md) +{ + ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md); + const int mode = md_eval->mode; + md_eval->mode |= eModifierMode_Realtime; + object_force_modifier_update_for_bind(depsgraph, object); + md_eval->mode = mode; +} + +ModifierData *ED_object_modifier_add( + ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type) +{ + ModifierData *md = NULL, *new_md = NULL; + const ModifierTypeInfo *mti = modifierType_getInfo(type); + + /* Check compatibility of modifier [T25291, T50373]. */ + if (!BKE_object_support_modifier_type_check(ob, type)) { + BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); + return NULL; + } + + if (mti->flags & eModifierTypeFlag_Single) { + if (modifiers_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); + return NULL; + } + } + + if (type == eModifierType_ParticleSystem) { + /* don't need to worry about the new modifier's name, since that is set to the number + * of particle systems which shouldn't have too many duplicates + */ + new_md = object_add_particle_system(bmain, scene, ob, name); + } + else { + /* get new modifier data to add */ + new_md = modifier_new(type); + + if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { + md = ob->modifiers.first; + + while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) + md = md->next; + + BLI_insertlinkbefore(&ob->modifiers, md, new_md); + } + else + BLI_addtail(&ob->modifiers, new_md); + + if (name) { + BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name)); + } + + /* make sure modifier data has unique name */ + + modifier_unique_name(&ob->modifiers, new_md); + + /* special cases */ + if (type == eModifierType_Softbody) { + if (!ob->soft) { + ob->soft = sbNew(scene); + ob->softflag |= OB_SB_GOAL | OB_SB_EDGES; + } + } + else if (type == eModifierType_Collision) { + if (!ob->pd) + ob->pd = BKE_partdeflect_new(0); + + ob->pd->deflect = 1; + } + else if (type == eModifierType_Surface) { + /* pass */ + } + else if (type == eModifierType_Multires) { + /* set totlvl from existing MDISPS layer if object already had it */ + multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob); + + if (ob->mode & OB_MODE_SCULPT) { + /* ensure that grid paint mask layer is created */ + BKE_sculpt_mask_layers_ensure(ob, (MultiresModifierData *)new_md); + } + } + else if (type == eModifierType_Skin) { + /* ensure skin-node customdata exists */ + BKE_mesh_ensure_skin_customdata(ob->data); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); + + return new_md; } /* Return true if the object has a modifier of type 'type' other than * the modifier pointed to be 'exclude', otherwise returns false. */ -static bool object_has_modifier(const Object *ob, const ModifierData *exclude, - ModifierType type) +static bool object_has_modifier(const Object *ob, const ModifierData *exclude, ModifierType type) { - ModifierData *md; + ModifierData *md; - for (md = ob->modifiers.first; md; md = md->next) { - if ((md != exclude) && (md->type == type)) - return true; - } + for (md = ob->modifiers.first; md; md = md->next) { + if ((md != exclude) && (md->type == type)) + return true; + } - return false; + return false; } /* If the object data of 'orig_ob' has other users, run 'callback' on @@ -232,47 +230,44 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, * If the callback ever returns true, iteration will stop and the * function value will be true. Otherwise the function returns false. */ -bool ED_object_iter_other( - Main *bmain, Object *orig_ob, const bool include_orig, - bool (*callback)(Object *ob, void *callback_data), - void *callback_data) -{ - ID *ob_data_id = orig_ob->data; - int users = ob_data_id->us; - - if (ob_data_id->flag & LIB_FAKEUSER) - users--; - - /* First check that the object's data has multiple users */ - if (users > 1) { - Object *ob; - int totfound = include_orig ? 0 : 1; - - for (ob = bmain->objects.first; ob && totfound < users; - ob = ob->id.next) - { - if (((ob != orig_ob) || include_orig) && - (ob->data == orig_ob->data)) - { - if (callback(ob, callback_data)) - return true; - - totfound++; - } - } - } - else if (include_orig) { - return callback(orig_ob, callback_data); - } - - return false; +bool ED_object_iter_other(Main *bmain, + Object *orig_ob, + const bool include_orig, + bool (*callback)(Object *ob, void *callback_data), + void *callback_data) +{ + ID *ob_data_id = orig_ob->data; + int users = ob_data_id->us; + + if (ob_data_id->flag & LIB_FAKEUSER) + users--; + + /* First check that the object's data has multiple users */ + if (users > 1) { + Object *ob; + int totfound = include_orig ? 0 : 1; + + for (ob = bmain->objects.first; ob && totfound < users; ob = ob->id.next) { + if (((ob != orig_ob) || include_orig) && (ob->data == orig_ob->data)) { + if (callback(ob, callback_data)) + return true; + + totfound++; + } + } + } + else if (include_orig) { + return callback(orig_ob, callback_data); + } + + return false; } static bool object_has_modifier_cb(Object *ob, void *data) { - ModifierType type = *((ModifierType *)data); + ModifierType type = *((ModifierType *)data); - return object_has_modifier(ob, NULL, type); + return object_has_modifier(ob, NULL, type); } /* Use with ED_object_iter_other(). Sets the total number of levels @@ -280,2145 +275,2167 @@ static bool object_has_modifier_cb(Object *ob, void *data) * callback_data. */ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) { - ModifierData *md; - int totlevel = *((char *)totlevel_v); + ModifierData *md; + int totlevel = *((char *)totlevel_v); - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Multires) { - multires_set_tot_level(ob, (MultiresModifierData *)md, totlevel); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - } - return false; + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Multires) { + multires_set_tot_level(ob, (MultiresModifierData *)md, totlevel); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + } + return false; } /* Return true if no modifier of type 'type' other than 'exclude' */ -static bool object_modifier_safe_to_delete(Main *bmain, Object *ob, - ModifierData *exclude, - ModifierType type) -{ - return (!object_has_modifier(ob, exclude, type) && - !ED_object_iter_other(bmain, ob, false, object_has_modifier_cb, &type)); -} - -static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, - bool *r_sort_depsgraph) -{ - /* It seems on rapid delete it is possible to - * get called twice on same modifier, so make - * sure it is in list. */ - if (BLI_findindex(&ob->modifiers, md) == -1) { - return 0; - } - - /* special cases */ - if (md->type == eModifierType_ParticleSystem) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - - BLI_remlink(&ob->particlesystem, psmd->psys); - psys_free(ob, psmd->psys); - psmd->psys = NULL; - } - else if (md->type == eModifierType_Softbody) { - if (ob->soft) { - sbFree(ob); - ob->softflag = 0; /* TODO(Sybren): this should probably be moved into sbFree() */ - } - } - else if (md->type == eModifierType_Collision) { - if (ob->pd) - ob->pd->deflect = 0; - - *r_sort_depsgraph = true; - } - else if (md->type == eModifierType_Surface) { - *r_sort_depsgraph = true; - } - else if (md->type == eModifierType_Multires) { - /* Delete MDisps layer if not used by another multires modifier */ - if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Multires)) - multires_customdata_delete(ob->data); - } - else if (md->type == eModifierType_Skin) { - /* Delete MVertSkin layer if not used by another skin modifier */ - if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Skin)) - modifier_skin_customdata_delete(ob); - } - - if (ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && - BLI_listbase_is_empty(&ob->particlesystem)) - { - ob->mode &= ~OB_MODE_PARTICLE_EDIT; - } - - BLI_remlink(&ob->modifiers, md); - modifier_free(md); - BKE_object_free_derived_caches(ob); - - return 1; +static bool object_modifier_safe_to_delete(Main *bmain, + Object *ob, + ModifierData *exclude, + ModifierType type) +{ + return (!object_has_modifier(ob, exclude, type) && + !ED_object_iter_other(bmain, ob, false, object_has_modifier_cb, &type)); +} + +static bool object_modifier_remove(Main *bmain, + Object *ob, + ModifierData *md, + bool *r_sort_depsgraph) +{ + /* It seems on rapid delete it is possible to + * get called twice on same modifier, so make + * sure it is in list. */ + if (BLI_findindex(&ob->modifiers, md) == -1) { + return 0; + } + + /* special cases */ + if (md->type == eModifierType_ParticleSystem) { + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + + BLI_remlink(&ob->particlesystem, psmd->psys); + psys_free(ob, psmd->psys); + psmd->psys = NULL; + } + else if (md->type == eModifierType_Softbody) { + if (ob->soft) { + sbFree(ob); + ob->softflag = 0; /* TODO(Sybren): this should probably be moved into sbFree() */ + } + } + else if (md->type == eModifierType_Collision) { + if (ob->pd) + ob->pd->deflect = 0; + + *r_sort_depsgraph = true; + } + else if (md->type == eModifierType_Surface) { + *r_sort_depsgraph = true; + } + else if (md->type == eModifierType_Multires) { + /* Delete MDisps layer if not used by another multires modifier */ + if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Multires)) + multires_customdata_delete(ob->data); + } + else if (md->type == eModifierType_Skin) { + /* Delete MVertSkin layer if not used by another skin modifier */ + if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Skin)) + modifier_skin_customdata_delete(ob); + } + + if (ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && + BLI_listbase_is_empty(&ob->particlesystem)) { + ob->mode &= ~OB_MODE_PARTICLE_EDIT; + } + + BLI_remlink(&ob->modifiers, md); + modifier_free(md); + BKE_object_free_derived_caches(ob); + + return 1; } bool ED_object_modifier_remove(ReportList *reports, Main *bmain, Object *ob, ModifierData *md) { - bool sort_depsgraph = false; - bool ok; + bool sort_depsgraph = false; + bool ok; - ok = object_modifier_remove(bmain, ob, md, &sort_depsgraph); + ok = object_modifier_remove(bmain, ob, md, &sort_depsgraph); - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name); - return 0; - } + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name); + return 0; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); - return 1; + return 1; } void ED_object_modifier_clear(Main *bmain, Object *ob) { - ModifierData *md = ob->modifiers.first; - bool sort_depsgraph = false; + ModifierData *md = ob->modifiers.first; + bool sort_depsgraph = false; - if (!md) - return; + if (!md) + return; - while (md) { - ModifierData *next_md; + while (md) { + ModifierData *next_md; - next_md = md->next; + next_md = md->next; - object_modifier_remove(bmain, ob, md, &sort_depsgraph); + object_modifier_remove(bmain, ob, md, &sort_depsgraph); - md = next_md; - } + md = next_md; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); } int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md) { - if (md->prev) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if (md->prev) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->type != eModifierTypeType_OnlyDeform) { - const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type); + if (mti->type != eModifierTypeType_OnlyDeform) { + const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type); - if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) { - BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data"); - return 0; - } - } + if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) { + BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data"); + return 0; + } + } - BLI_remlink(&ob->modifiers, md); - BLI_insertlinkbefore(&ob->modifiers, md->prev, md); - } + BLI_remlink(&ob->modifiers, md); + BLI_insertlinkbefore(&ob->modifiers, md->prev, md); + } - return 1; + return 1; } int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md) { - if (md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if (md->next) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { - const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type); + if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { + const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type); - if (nmti->type != eModifierTypeType_OnlyDeform) { - BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier"); - return 0; - } - } + if (nmti->type != eModifierTypeType_OnlyDeform) { + BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier"); + return 0; + } + } - BLI_remlink(&ob->modifiers, md); - BLI_insertlinkafter(&ob->modifiers, md->next, md); - } + BLI_remlink(&ob->modifiers, md); + BLI_insertlinkafter(&ob->modifiers, md->next, md); + } - return 1; + return 1; } int ED_object_modifier_convert(ReportList *UNUSED(reports), - Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, - Object *ob, ModifierData *md) -{ - Object *obn; - ParticleSystem *psys_orig, *psys_eval; - ParticleCacheKey *key, **cache; - ParticleSettings *part; - Mesh *me; - MVert *mvert; - MEdge *medge; - int a, k, kmax; - int totvert = 0, totedge = 0, cvert = 0; - int totpart = 0, totchild = 0; - - if (md->type != eModifierType_ParticleSystem) return 0; - if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) return 0; - - psys_orig = ((ParticleSystemModifierData *)md)->psys; - part = psys_orig->part; - - if (part->ren_as != PART_DRAW_PATH) { - return 0; - } - psys_eval = psys_eval_get(depsgraph, ob, psys_orig); - if (psys_eval->pathcache == NULL) { - return 0; - } - - totpart = psys_eval->totcached; - totchild = psys_eval->totchildcache; - - if (totchild && (part->draw & PART_DRAW_PARENT) == 0) - totpart = 0; - - /* count */ - cache = psys_eval->pathcache; - for (a = 0; a < totpart; a++) { - key = cache[a]; - - if (key->segments > 0) { - totvert += key->segments + 1; - totedge += key->segments; - } - } - - cache = psys_eval->childcache; - for (a = 0; a < totchild; a++) { - key = cache[a]; - - if (key->segments > 0) { - totvert += key->segments + 1; - totedge += key->segments; - } - } - - if (totvert == 0) return 0; - - /* add new mesh */ - obn = BKE_object_add(bmain, scene, view_layer, OB_MESH, NULL); - me = obn->data; - - me->totvert = totvert; - me->totedge = totedge; - - me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, totedge); - me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, 0); - - mvert = me->mvert; - medge = me->medge; - - /* copy coordinates */ - cache = psys_eval->pathcache; - for (a = 0; a < totpart; a++) { - key = cache[a]; - kmax = key->segments; - for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { - copy_v3_v3(mvert->co, key->co); - if (k) { - medge->v1 = cvert - 1; - medge->v2 = cvert; - medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; - medge++; - } - else { - /* cheap trick to select the roots */ - mvert->flag |= SELECT; - } - } - } - - cache = psys_eval->childcache; - for (a = 0; a < totchild; a++) { - key = cache[a]; - kmax = key->segments; - for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { - copy_v3_v3(mvert->co, key->co); - if (k) { - medge->v1 = cvert - 1; - medge->v2 = cvert; - medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; - medge++; - } - else { - /* cheap trick to select the roots */ - mvert->flag |= SELECT; - } - } - } - - DEG_relations_tag_update(bmain); - - return 1; + Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + ViewLayer *view_layer, + Object *ob, + ModifierData *md) +{ + Object *obn; + ParticleSystem *psys_orig, *psys_eval; + ParticleCacheKey *key, **cache; + ParticleSettings *part; + Mesh *me; + MVert *mvert; + MEdge *medge; + int a, k, kmax; + int totvert = 0, totedge = 0, cvert = 0; + int totpart = 0, totchild = 0; + + if (md->type != eModifierType_ParticleSystem) + return 0; + if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) + return 0; + + psys_orig = ((ParticleSystemModifierData *)md)->psys; + part = psys_orig->part; + + if (part->ren_as != PART_DRAW_PATH) { + return 0; + } + psys_eval = psys_eval_get(depsgraph, ob, psys_orig); + if (psys_eval->pathcache == NULL) { + return 0; + } + + totpart = psys_eval->totcached; + totchild = psys_eval->totchildcache; + + if (totchild && (part->draw & PART_DRAW_PARENT) == 0) + totpart = 0; + + /* count */ + cache = psys_eval->pathcache; + for (a = 0; a < totpart; a++) { + key = cache[a]; + + if (key->segments > 0) { + totvert += key->segments + 1; + totedge += key->segments; + } + } + + cache = psys_eval->childcache; + for (a = 0; a < totchild; a++) { + key = cache[a]; + + if (key->segments > 0) { + totvert += key->segments + 1; + totedge += key->segments; + } + } + + if (totvert == 0) + return 0; + + /* add new mesh */ + obn = BKE_object_add(bmain, scene, view_layer, OB_MESH, NULL); + me = obn->data; + + me->totvert = totvert; + me->totedge = totedge; + + me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, totvert); + me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, totedge); + me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, 0); + + mvert = me->mvert; + medge = me->medge; + + /* copy coordinates */ + cache = psys_eval->pathcache; + for (a = 0; a < totpart; a++) { + key = cache[a]; + kmax = key->segments; + for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { + copy_v3_v3(mvert->co, key->co); + if (k) { + medge->v1 = cvert - 1; + medge->v2 = cvert; + medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; + medge++; + } + else { + /* cheap trick to select the roots */ + mvert->flag |= SELECT; + } + } + } + + cache = psys_eval->childcache; + for (a = 0; a < totchild; a++) { + key = cache[a]; + kmax = key->segments; + for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { + copy_v3_v3(mvert->co, key->co); + if (k) { + medge->v1 = cvert - 1; + medge->v2 = cvert; + medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; + medge++; + } + else { + /* cheap trick to select the roots */ + mvert->flag |= SELECT; + } + } + } + + DEG_relations_tag_update(bmain); + + return 1; } /* Gets mesh for the modifier which corresponds to an evaluated state. */ -static Mesh *modifier_apply_create_mesh_for_modifier( - Depsgraph *depsgraph, - Scene *UNUSED(scene), - Object *object, - ModifierData *md, - bool build_shapekey_layers) -{ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *object_eval = DEG_get_evaluated_object(depsgraph, object); - ModifierData *md_eval = modifiers_findByName(object_eval, md->name); - Mesh *mesh_applied = BKE_mesh_create_derived_for_modifier( - depsgraph, scene_eval, object_eval, md_eval, build_shapekey_layers); - return mesh_applied; -} - -static int modifier_apply_shape( - Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) -{ - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); - return 0; - } - - /* - * It should be ridiculously easy to extract the original verts that we want - * and form the shape data. We can probably use the CD KEYINDEX layer (or - * whatever I ended up calling it, too tired to check now), though this would - * by necessity have to make some potentially ugly assumptions about the order - * of the mesh data :-/ you can probably assume in 99% of cases that the first - * element of a given index is the original, and any subsequent duplicates are - * copies/interpolates, but that's an assumption that would need to be tested - * and then predominantly stated in comments in a half dozen headers. - */ - - if (ob->type == OB_MESH) { - Mesh *mesh_applied; - Mesh *me = ob->data; - Key *key = me->key; - KeyBlock *kb; - - if (!modifier_isSameTopology(md) || mti->type == eModifierTypeType_NonGeometrical) { - BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to shapes"); - return 0; - } - - mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, scene, ob, md, false); - if (!mesh_applied) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); - return 0; - } - - if (key == NULL) { - key = me->key = BKE_key_add(bmain, (ID *)me); - key->type = KEY_RELATIVE; - /* if that was the first key block added, then it was the basis. - * Initialize it with the mesh, and add another for the modifier */ - kb = BKE_keyblock_add(key, NULL); - BKE_keyblock_convert_from_mesh(me, key, kb); - } - - kb = BKE_keyblock_add(key, md->name); - BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb); - - BKE_id_free(NULL, mesh_applied); - } - else { - BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); - return 0; - } - return 1; -} - -static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) -{ - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { - BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); - return 0; - } - - if (ob->type == OB_MESH) { - Mesh *mesh_applied; - Mesh *me = ob->data; - MultiresModifierData *mmd = find_multires_modifier_before(scene, md); - - if (me->key && mti->type != eModifierTypeType_NonGeometrical) { - BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to a mesh with shape keys"); - return 0; - } - - /* Multires: ensure that recent sculpting is applied */ - if (md->type == eModifierType_Multires) - multires_force_update(ob); - - if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { - if (!multiresModifier_reshapeFromDeformModifier(depsgraph, mmd, ob, md)) { - BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply"); - return 0; - } - } - else { - mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, scene, ob, md, true); - if (!mesh_applied) { - BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); - return 0; - } - - BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true); - - if (md->type == eModifierType_Multires) - multires_customdata_delete(me); - } - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - Curve *curve = ob->data; - Curve *curve_eval = (Curve *)object_eval->data; - int numVerts; - float (*vertexCos)[3]; - ModifierEvalContext mectx = {depsgraph, object_eval, 0}; - - if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) { - BKE_report(reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers"); - return 0; - } - - BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices"); - - vertexCos = BKE_curve_nurbs_vertexCos_get(&curve_eval->nurb, &numVerts); - mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts); - BK_curve_nurbs_vertexCos_apply(&curve->nurb, vertexCos); - - MEM_freeN(vertexCos); - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - else { - BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); - return 0; - } - - /* lattice modifier can be applied to particle system too */ - if (ob->particlesystem.first) { - - ParticleSystem *psys = ob->particlesystem.first; - - for (; psys; psys = psys->next) { - - if (psys->part->type != PART_HAIR) - continue; - - psys_apply_hair_lattice(depsgraph, scene, ob, psys); - } - } - - return 1; -} - -int ED_object_modifier_apply( - Main *bmain, ReportList *reports, Depsgraph *depsgraph, - Scene *scene, Object *ob, ModifierData *md, int mode) -{ - int prev_mode; - - if (BKE_object_is_in_editmode(ob)) { - BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode"); - return 0; - } - else if (((ID *) ob->data)->us > 1) { - BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); - return 0; - } - else if ((ob->mode & OB_MODE_SCULPT) && - (find_multires_modifier_before(scene, md)) && - (modifier_isSameTopology(md) == false)) - { - BKE_report(reports, RPT_ERROR, "Constructive modifier cannot be applied to multi-res data in sculpt mode"); - return 0; - } - - if (md != ob->modifiers.first) - BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); - - /* Get evaluated modifier, so object links pointer to evaluated data, - * but still use original object it is applied to the original mesh. */ - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md; - - /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ - prev_mode = md_eval->mode; - md_eval->mode |= eModifierMode_Realtime; - - if (mode == MODIFIER_APPLY_SHAPE) { - if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) { - md_eval->mode = prev_mode; - return 0; - } - } - else { - if (!modifier_apply_obdata(reports, depsgraph, scene, ob, md_eval)) { - md_eval->mode = prev_mode; - return 0; - } - } - - md_eval->mode = prev_mode; - BLI_remlink(&ob->modifiers, md); - modifier_free(md); - - BKE_object_free_derived_caches(ob); - - return 1; +static Mesh *modifier_apply_create_mesh_for_modifier(Depsgraph *depsgraph, + Scene *UNUSED(scene), + Object *object, + ModifierData *md, + bool build_shapekey_layers) +{ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + ModifierData *md_eval = modifiers_findByName(object_eval, md->name); + Mesh *mesh_applied = BKE_mesh_create_derived_for_modifier( + depsgraph, scene_eval, object_eval, md_eval, build_shapekey_layers); + return mesh_applied; +} + +static int modifier_apply_shape(Main *bmain, + ReportList *reports, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + ModifierData *md) +{ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + return 0; + } + + /* + * It should be ridiculously easy to extract the original verts that we want + * and form the shape data. We can probably use the CD KEYINDEX layer (or + * whatever I ended up calling it, too tired to check now), though this would + * by necessity have to make some potentially ugly assumptions about the order + * of the mesh data :-/ you can probably assume in 99% of cases that the first + * element of a given index is the original, and any subsequent duplicates are + * copies/interpolates, but that's an assumption that would need to be tested + * and then predominantly stated in comments in a half dozen headers. + */ + + if (ob->type == OB_MESH) { + Mesh *mesh_applied; + Mesh *me = ob->data; + Key *key = me->key; + KeyBlock *kb; + + if (!modifier_isSameTopology(md) || mti->type == eModifierTypeType_NonGeometrical) { + BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to shapes"); + return 0; + } + + mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, scene, ob, md, false); + if (!mesh_applied) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); + return 0; + } + + if (key == NULL) { + key = me->key = BKE_key_add(bmain, (ID *)me); + key->type = KEY_RELATIVE; + /* if that was the first key block added, then it was the basis. + * Initialize it with the mesh, and add another for the modifier */ + kb = BKE_keyblock_add(key, NULL); + BKE_keyblock_convert_from_mesh(me, key, kb); + } + + kb = BKE_keyblock_add(key, md->name); + BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb); + + BKE_id_free(NULL, mesh_applied); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + return 1; +} + +static int modifier_apply_obdata( + ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) +{ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + return 0; + } + + if (ob->type == OB_MESH) { + Mesh *mesh_applied; + Mesh *me = ob->data; + MultiresModifierData *mmd = find_multires_modifier_before(scene, md); + + if (me->key && mti->type != eModifierTypeType_NonGeometrical) { + BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to a mesh with shape keys"); + return 0; + } + + /* Multires: ensure that recent sculpting is applied */ + if (md->type == eModifierType_Multires) + multires_force_update(ob); + + if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { + if (!multiresModifier_reshapeFromDeformModifier(depsgraph, mmd, ob, md)) { + BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply"); + return 0; + } + } + else { + mesh_applied = modifier_apply_create_mesh_for_modifier(depsgraph, scene, ob, md, true); + if (!mesh_applied) { + BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); + return 0; + } + + BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true); + + if (md->type == eModifierType_Multires) + multires_customdata_delete(me); + } + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); + Curve *curve = ob->data; + Curve *curve_eval = (Curve *)object_eval->data; + int numVerts; + float(*vertexCos)[3]; + ModifierEvalContext mectx = {depsgraph, object_eval, 0}; + + if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) { + BKE_report( + reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers"); + return 0; + } + + BKE_report(reports, + RPT_INFO, + "Applied modifier only changed CV points, not tessellated/bevel vertices"); + + vertexCos = BKE_curve_nurbs_vertexCos_get(&curve_eval->nurb, &numVerts); + mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts); + BK_curve_nurbs_vertexCos_apply(&curve->nurb, vertexCos); + + MEM_freeN(vertexCos); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + + /* lattice modifier can be applied to particle system too */ + if (ob->particlesystem.first) { + + ParticleSystem *psys = ob->particlesystem.first; + + for (; psys; psys = psys->next) { + + if (psys->part->type != PART_HAIR) + continue; + + psys_apply_hair_lattice(depsgraph, scene, ob, psys); + } + } + + return 1; +} + +int ED_object_modifier_apply(Main *bmain, + ReportList *reports, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + ModifierData *md, + int mode) +{ + int prev_mode; + + if (BKE_object_is_in_editmode(ob)) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode"); + return 0; + } + else if (((ID *)ob->data)->us > 1) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); + return 0; + } + else if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) && + (modifier_isSameTopology(md) == false)) { + BKE_report(reports, + RPT_ERROR, + "Constructive modifier cannot be applied to multi-res data in sculpt mode"); + return 0; + } + + if (md != ob->modifiers.first) + BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); + + /* Get evaluated modifier, so object links pointer to evaluated data, + * but still use original object it is applied to the original mesh. */ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md; + + /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ + prev_mode = md_eval->mode; + md_eval->mode |= eModifierMode_Realtime; + + if (mode == MODIFIER_APPLY_SHAPE) { + if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) { + md_eval->mode = prev_mode; + return 0; + } + } + else { + if (!modifier_apply_obdata(reports, depsgraph, scene, ob, md_eval)) { + md_eval->mode = prev_mode; + return 0; + } + } + + md_eval->mode = prev_mode; + BLI_remlink(&ob->modifiers, md); + modifier_free(md); + + BKE_object_free_derived_caches(ob); + + return 1; } int ED_object_modifier_copy(ReportList *UNUSED(reports), Object *ob, ModifierData *md) { - ModifierData *nmd; + ModifierData *nmd; - nmd = modifier_new(md->type); - modifier_copyData(md, nmd); - BLI_insertlinkafter(&ob->modifiers, md, nmd); - modifier_unique_name(&ob->modifiers, nmd); + nmd = modifier_new(md->type); + modifier_copyData(md, nmd); + BLI_insertlinkafter(&ob->modifiers, md, nmd); + modifier_unique_name(&ob->modifiers, nmd); - return 1; + return 1; } /************************ add modifier operator *********************/ static int modifier_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - int type = RNA_enum_get(op->ptr, "type"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); - if (!ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, type)) - return OPERATOR_CANCELLED; + if (!ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, type)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static const EnumPropertyItem *modifier_add_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *modifier_add_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *ob = ED_object_active_context(C); - EnumPropertyItem *item = NULL; - const EnumPropertyItem *md_item, *group_item = NULL; - const ModifierTypeInfo *mti; - int totitem = 0, a; + Object *ob = ED_object_active_context(C); + EnumPropertyItem *item = NULL; + const EnumPropertyItem *md_item, *group_item = NULL; + const ModifierTypeInfo *mti; + int totitem = 0, a; - if (!ob) - return rna_enum_object_modifier_type_items; + if (!ob) + return rna_enum_object_modifier_type_items; - for (a = 0; rna_enum_object_modifier_type_items[a].identifier; a++) { - md_item = &rna_enum_object_modifier_type_items[a]; + for (a = 0; rna_enum_object_modifier_type_items[a].identifier; a++) { + md_item = &rna_enum_object_modifier_type_items[a]; - if (md_item->identifier[0]) { - mti = modifierType_getInfo(md_item->value); + if (md_item->identifier[0]) { + mti = modifierType_getInfo(md_item->value); - if (mti->flags & eModifierTypeFlag_NoUserAdd) - continue; + if (mti->flags & eModifierTypeFlag_NoUserAdd) + continue; - if (!BKE_object_support_modifier_type_check(ob, md_item->value)) - continue; - } - else { - group_item = md_item; - md_item = NULL; + if (!BKE_object_support_modifier_type_check(ob, md_item->value)) + continue; + } + else { + group_item = md_item; + md_item = NULL; - continue; - } + continue; + } - if (group_item) { - RNA_enum_item_add(&item, &totitem, group_item); - group_item = NULL; - } + if (group_item) { + RNA_enum_item_add(&item, &totitem, group_item); + group_item = NULL; + } - RNA_enum_item_add(&item, &totitem, md_item); - } + RNA_enum_item_add(&item, &totitem, md_item); + } - RNA_enum_item_end(&item, &totitem); - *r_free = true; + RNA_enum_item_end(&item, &totitem); + *r_free = true; - return item; + return item; } void OBJECT_OT_modifier_add(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Add Modifier"; - ot->description = "Add a procedural operation/effect to the active object"; - ot->idname = "OBJECT_OT_modifier_add"; + /* identifiers */ + ot->name = "Add Modifier"; + ot->description = "Add a procedural operation/effect to the active object"; + ot->idname = "OBJECT_OT_modifier_add"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = modifier_add_exec; - ot->poll = ED_operator_object_active_editable; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = modifier_add_exec; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eModifierType_Subsurf, "Type", ""); - RNA_def_enum_funcs(prop, modifier_add_itemf); - ot->prop = prop; + /* properties */ + prop = RNA_def_enum( + ot->srna, "type", rna_enum_object_modifier_type_items, eModifierType_Subsurf, "Type", ""); + RNA_def_enum_funcs(prop, modifier_add_itemf); + ot->prop = prop; } /************************ generic functions for operators using mod names and data context *********************/ bool edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); - Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - if (!ob || ID_IS_LINKED(ob)) return 0; - if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; - if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0; + if (!ob || ID_IS_LINKED(ob)) + return 0; + if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) + return 0; + if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) + return 0; - if (ID_IS_STATIC_OVERRIDE(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override"); - return (((ModifierData *)ptr.data)->flag & eModifierFlag_StaticOverride_Local) != 0; - } + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override"); + return (((ModifierData *)ptr.data)->flag & eModifierFlag_StaticOverride_Local) != 0; + } - return 1; + return 1; } bool edit_modifier_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_Modifier, 0); + return edit_modifier_poll_generic(C, &RNA_Modifier, 0); } void edit_modifier_properties(wmOperatorType *ot) { - PropertyRNA *prop = RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_def_string( + ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); + RNA_def_property_flag(prop, PROP_HIDDEN); } int edit_modifier_invoke_properties(bContext *C, wmOperator *op) { - ModifierData *md; + ModifierData *md; - if (RNA_struct_property_is_set(op->ptr, "modifier")) { - return true; - } - else { - PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier); - if (ptr.data) { - md = ptr.data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; - } - } + if (RNA_struct_property_is_set(op->ptr, "modifier")) { + return true; + } + else { + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier); + if (ptr.data) { + md = ptr.data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + } - return false; + return false; } ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) { - char modifier_name[MAX_NAME]; - ModifierData *md; - RNA_string_get(op->ptr, "modifier", modifier_name); + char modifier_name[MAX_NAME]; + ModifierData *md; + RNA_string_get(op->ptr, "modifier", modifier_name); - md = modifiers_findByName(ob, modifier_name); + md = modifiers_findByName(ob, modifier_name); - if (md && type != 0 && md->type != type) - md = NULL; + if (md && type != 0 && md->type != type) + md = NULL; - return md; + return md; } /************************ remove modifier operator *********************/ static int modifier_remove_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); - int mode_orig = ob->mode; + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); + int mode_orig = ob->mode; - if (!md || !ED_object_modifier_remove(op->reports, bmain, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_modifier_remove(op->reports, bmain, ob, md)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - /* if cloth/softbody was removed, particle mode could be cleared */ - if (mode_orig & OB_MODE_PARTICLE_EDIT) { - if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) { - if (ob == OBACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); - } - } - } - return OPERATOR_FINISHED; + /* if cloth/softbody was removed, particle mode could be cleared */ + if (mode_orig & OB_MODE_PARTICLE_EDIT) { + if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) { + if (ob == OBACT(view_layer)) { + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + } + } + } + return OPERATOR_FINISHED; } static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_remove_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_remove_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_remove(wmOperatorType *ot) { - ot->name = "Remove Modifier"; - ot->description = "Remove a modifier from the active object"; - ot->idname = "OBJECT_OT_modifier_remove"; + ot->name = "Remove Modifier"; + ot->description = "Remove a modifier from the active object"; + ot->idname = "OBJECT_OT_modifier_remove"; - ot->invoke = modifier_remove_invoke; - ot->exec = modifier_remove_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_remove_invoke; + ot->exec = modifier_remove_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ move up modifier operator *********************/ static int modifier_move_up_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_move_up(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_modifier_move_up(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_move_up_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_move_up(wmOperatorType *ot) { - ot->name = "Move Up Modifier"; - ot->description = "Move modifier up in the stack"; - ot->idname = "OBJECT_OT_modifier_move_up"; + ot->name = "Move Up Modifier"; + ot->description = "Move modifier up in the stack"; + ot->idname = "OBJECT_OT_modifier_move_up"; - ot->invoke = modifier_move_up_invoke; - ot->exec = modifier_move_up_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_move_up_invoke; + ot->exec = modifier_move_up_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ move down modifier operator *********************/ static int modifier_move_down_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_move_down(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_modifier_move_down(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_move_down_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_move_down(wmOperatorType *ot) { - ot->name = "Move Down Modifier"; - ot->description = "Move modifier down in the stack"; - ot->idname = "OBJECT_OT_modifier_move_down"; + ot->name = "Move Down Modifier"; + ot->description = "Move modifier down in the stack"; + ot->idname = "OBJECT_OT_modifier_move_down"; - ot->invoke = modifier_move_down_invoke; - ot->exec = modifier_move_down_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_move_down_invoke; + ot->exec = modifier_move_down_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ apply modifier operator *********************/ static int modifier_apply_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); - int apply_as = RNA_enum_get(op->ptr, "apply_as"); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); + int apply_as = RNA_enum_get(op->ptr, "apply_as"); - if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) { - return OPERATOR_CANCELLED; - } + if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) { + return OPERATOR_CANCELLED; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_apply_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_apply_exec(C, op); + else + return OPERATOR_CANCELLED; } static const EnumPropertyItem modifier_apply_as_items[] = { - {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"}, - {MODIFIER_APPLY_SHAPE, "SHAPE", 0, "New Shape", "Apply deform-only modifier to a new shape on this object"}, - {0, NULL, 0, NULL, NULL}, + {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"}, + {MODIFIER_APPLY_SHAPE, + "SHAPE", + 0, + "New Shape", + "Apply deform-only modifier to a new shape on this object"}, + {0, NULL, 0, NULL, NULL}, }; void OBJECT_OT_modifier_apply(wmOperatorType *ot) { - ot->name = "Apply Modifier"; - ot->description = "Apply modifier and remove from the stack"; - ot->idname = "OBJECT_OT_modifier_apply"; + ot->name = "Apply Modifier"; + ot->description = "Apply modifier and remove from the stack"; + ot->idname = "OBJECT_OT_modifier_apply"; - ot->invoke = modifier_apply_invoke; - ot->exec = modifier_apply_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_apply_invoke; + ot->exec = modifier_apply_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - RNA_def_enum(ot->srna, "apply_as", modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry"); - edit_modifier_properties(ot); + RNA_def_enum(ot->srna, + "apply_as", + modifier_apply_as_items, + MODIFIER_APPLY_DATA, + "Apply as", + "How to apply the modifier to the geometry"); + edit_modifier_properties(ot); } /************************ convert modifier operator *********************/ static int modifier_convert_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_convert(op->reports, bmain, depsgraph, scene, view_layer, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_modifier_convert(op->reports, bmain, depsgraph, scene, view_layer, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_convert_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_convert_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_convert(wmOperatorType *ot) { - ot->name = "Convert Modifier"; - ot->description = "Convert particles to a mesh object"; - ot->idname = "OBJECT_OT_modifier_convert"; + ot->name = "Convert Modifier"; + ot->description = "Convert particles to a mesh object"; + ot->idname = "OBJECT_OT_modifier_convert"; - ot->invoke = modifier_convert_invoke; - ot->exec = modifier_convert_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_convert_invoke; + ot->exec = modifier_convert_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ copy modifier operator *********************/ static int modifier_copy_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ModifierData *md = edit_modifier_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_copy(op->reports, ob, md)) - return OPERATOR_CANCELLED; + if (!md || !ED_object_modifier_copy(op->reports, ob, md)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return modifier_copy_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return modifier_copy_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_copy(wmOperatorType *ot) { - ot->name = "Copy Modifier"; - ot->description = "Duplicate modifier at the same position in the stack"; - ot->idname = "OBJECT_OT_modifier_copy"; + ot->name = "Copy Modifier"; + ot->description = "Duplicate modifier at the same position in the stack"; + ot->idname = "OBJECT_OT_modifier_copy"; - ot->invoke = modifier_copy_invoke; - ot->exec = modifier_copy_exec; - ot->poll = edit_modifier_poll; + ot->invoke = modifier_copy_invoke; + ot->exec = modifier_copy_exec; + ot->poll = edit_modifier_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************* multires delete higher levels operator ****************/ static bool multires_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_MultiresModifier, (1 << OB_MESH)); + return edit_modifier_poll_generic(C, &RNA_MultiresModifier, (1 << OB_MESH)); } static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Multires); - if (!mmd) - return OPERATOR_CANCELLED; + if (!mmd) + return OPERATOR_CANCELLED; - multiresModifier_del_levels(mmd, scene, ob, 1); + multiresModifier_del_levels(mmd, scene, ob, 1); - ED_object_iter_other( - CTX_data_main(C), ob, true, - ED_object_multires_update_totlevels_cb, - &mmd->totlvl); + ED_object_iter_other( + CTX_data_main(C), ob, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int multires_higher_levels_delete_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return multires_higher_levels_delete_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return multires_higher_levels_delete_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot) { - ot->name = "Delete Higher Levels"; - ot->description = "Deletes the higher resolution mesh, potential loss of detail"; - ot->idname = "OBJECT_OT_multires_higher_levels_delete"; + ot->name = "Delete Higher Levels"; + ot->description = "Deletes the higher resolution mesh, potential loss of detail"; + ot->idname = "OBJECT_OT_multires_higher_levels_delete"; - ot->poll = multires_poll; - ot->invoke = multires_higher_levels_delete_invoke; - ot->exec = multires_higher_levels_delete_exec; + ot->poll = multires_poll; + ot->invoke = multires_higher_levels_delete_invoke; + ot->exec = multires_higher_levels_delete_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /****************** multires subdivide operator *********************/ static int multires_subdivide_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Multires); - if (!mmd) - return OPERATOR_CANCELLED; + if (!mmd) + return OPERATOR_CANCELLED; - multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple); + multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple); - ED_object_iter_other( - CTX_data_main(C), ob, true, - ED_object_multires_update_totlevels_cb, - &mmd->totlvl); + ED_object_iter_other( + CTX_data_main(C), ob, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - if (ob->mode & OB_MODE_SCULPT) { - /* ensure that grid paint mask layer is created */ - BKE_sculpt_mask_layers_ensure(ob, mmd); - } + if (ob->mode & OB_MODE_SCULPT) { + /* ensure that grid paint mask layer is created */ + BKE_sculpt_mask_layers_ensure(ob, mmd); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return multires_subdivide_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return multires_subdivide_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_multires_subdivide(wmOperatorType *ot) { - ot->name = "Multires Subdivide"; - ot->description = "Add a new level of subdivision"; - ot->idname = "OBJECT_OT_multires_subdivide"; + ot->name = "Multires Subdivide"; + ot->description = "Add a new level of subdivision"; + ot->idname = "OBJECT_OT_multires_subdivide"; - ot->poll = multires_poll; - ot->invoke = multires_subdivide_invoke; - ot->exec = multires_subdivide_exec; + ot->poll = multires_poll; + ot->invoke = multires_subdivide_invoke; + ot->exec = multires_subdivide_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /****************** multires reshape operator *********************/ static int multires_reshape_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *ob = ED_object_active_context(C), *secondob = NULL; - MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = ED_object_active_context(C), *secondob = NULL; + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Multires); - if (!mmd) - return OPERATOR_CANCELLED; + if (!mmd) + return OPERATOR_CANCELLED; - if (mmd->lvl == 0) { - BKE_report(op->reports, RPT_ERROR, "Reshape can work only with higher levels of subdivisions"); - return OPERATOR_CANCELLED; - } + if (mmd->lvl == 0) { + BKE_report(op->reports, RPT_ERROR, "Reshape can work only with higher levels of subdivisions"); + return OPERATOR_CANCELLED; + } - CTX_DATA_BEGIN(C, Object *, selob, selected_editable_objects) - { - if (selob->type == OB_MESH && selob != ob) { - secondob = selob; - break; - } - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Object *, selob, selected_editable_objects) { + if (selob->type == OB_MESH && selob != ob) { + secondob = selob; + break; + } + } + CTX_DATA_END; - if (!secondob) { - BKE_report(op->reports, RPT_ERROR, "Second selected mesh object required to copy shape from"); - return OPERATOR_CANCELLED; - } + if (!secondob) { + BKE_report(op->reports, RPT_ERROR, "Second selected mesh object required to copy shape from"); + return OPERATOR_CANCELLED; + } - if (!multiresModifier_reshapeFromObject(depsgraph, mmd, ob, secondob)) { - BKE_report(op->reports, RPT_ERROR, "Objects do not have the same number of vertices"); - return OPERATOR_CANCELLED; - } + if (!multiresModifier_reshapeFromObject(depsgraph, mmd, ob, secondob)) { + BKE_report(op->reports, RPT_ERROR, "Objects do not have the same number of vertices"); + return OPERATOR_CANCELLED; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return multires_reshape_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return multires_reshape_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_multires_reshape(wmOperatorType *ot) { - ot->name = "Multires Reshape"; - ot->description = "Copy vertex coordinates from other object"; - ot->idname = "OBJECT_OT_multires_reshape"; + ot->name = "Multires Reshape"; + ot->description = "Copy vertex coordinates from other object"; + ot->idname = "OBJECT_OT_multires_reshape"; - ot->poll = multires_poll; - ot->invoke = multires_reshape_invoke; - ot->exec = multires_reshape_exec; + ot->poll = multires_poll; + ot->invoke = multires_reshape_invoke; + ot->exec = multires_reshape_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } - - /****************** multires save external operator *********************/ static int multires_external_save_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - Mesh *me = (ob) ? ob->data : op->customdata; - char path[FILE_MAX]; - const bool relative = RNA_boolean_get(op->ptr, "relative_path"); + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + Mesh *me = (ob) ? ob->data : op->customdata; + char path[FILE_MAX]; + const bool relative = RNA_boolean_get(op->ptr, "relative_path"); - if (!me) - return OPERATOR_CANCELLED; + if (!me) + return OPERATOR_CANCELLED; - if (CustomData_external_test(&me->ldata, CD_MDISPS)) - return OPERATOR_CANCELLED; + if (CustomData_external_test(&me->ldata, CD_MDISPS)) + return OPERATOR_CANCELLED; - RNA_string_get(op->ptr, "filepath", path); + RNA_string_get(op->ptr, "filepath", path); - if (relative) - BLI_path_rel(path, BKE_main_blendfile_path(bmain)); + if (relative) + BLI_path_rel(path, BKE_main_blendfile_path(bmain)); - CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path); - CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH.lmask, me->totloop, 0); + CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path); + CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH.lmask, me->totloop, 0); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int multires_external_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Object *ob = ED_object_active_context(C); - MultiresModifierData *mmd; - Mesh *me = ob->data; - char path[FILE_MAX]; + Object *ob = ED_object_active_context(C); + MultiresModifierData *mmd; + Mesh *me = ob->data; + char path[FILE_MAX]; - if (!edit_modifier_invoke_properties(C, op)) - return OPERATOR_CANCELLED; + if (!edit_modifier_invoke_properties(C, op)) + return OPERATOR_CANCELLED; - mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); + mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); - if (!mmd) - return OPERATOR_CANCELLED; + if (!mmd) + return OPERATOR_CANCELLED; - if (CustomData_external_test(&me->ldata, CD_MDISPS)) - return OPERATOR_CANCELLED; + if (CustomData_external_test(&me->ldata, CD_MDISPS)) + return OPERATOR_CANCELLED; - if (RNA_struct_property_is_set(op->ptr, "filepath")) - return multires_external_save_exec(C, op); + if (RNA_struct_property_is_set(op->ptr, "filepath")) + return multires_external_save_exec(C, op); - op->customdata = me; + op->customdata = me; - BLI_snprintf(path, sizeof(path), "//%s.btx", me->id.name + 2); - RNA_string_set(op->ptr, "filepath", path); + BLI_snprintf(path, sizeof(path), "//%s.btx", me->id.name + 2); + RNA_string_set(op->ptr, "filepath", path); - WM_event_add_fileselect(C, op); + WM_event_add_fileselect(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } void OBJECT_OT_multires_external_save(wmOperatorType *ot) { - ot->name = "Multires Save External"; - ot->description = "Save displacements to an external file"; - ot->idname = "OBJECT_OT_multires_external_save"; + ot->name = "Multires Save External"; + ot->description = "Save displacements to an external file"; + ot->idname = "OBJECT_OT_multires_external_save"; - /* XXX modifier no longer in context after file browser .. ot->poll = multires_poll; */ - ot->exec = multires_external_save_exec; - ot->invoke = multires_external_save_invoke; - ot->poll = multires_poll; + /* XXX modifier no longer in context after file browser .. ot->poll = multires_poll; */ + ot->exec = multires_external_save_exec; + ot->invoke = multires_external_save_invoke; + ot->poll = multires_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); - edit_modifier_properties(ot); + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_BTX, + FILE_SPECIAL, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + edit_modifier_properties(ot); } /****************** multires pack operator *********************/ static int multires_external_pack_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_active_context(C); - Mesh *me = ob->data; + Object *ob = ED_object_active_context(C); + Mesh *me = ob->data; - if (!CustomData_external_test(&me->ldata, CD_MDISPS)) - return OPERATOR_CANCELLED; + if (!CustomData_external_test(&me->ldata, CD_MDISPS)) + return OPERATOR_CANCELLED; - /* XXX don't remove.. */ - CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); + /* XXX don't remove.. */ + CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_multires_external_pack(wmOperatorType *ot) { - ot->name = "Multires Pack External"; - ot->description = "Pack displacements from an external file"; - ot->idname = "OBJECT_OT_multires_external_pack"; + ot->name = "Multires Pack External"; + ot->description = "Pack displacements from an external file"; + ot->idname = "OBJECT_OT_multires_external_pack"; - ot->poll = multires_poll; - ot->exec = multires_external_pack_exec; + ot->poll = multires_poll; + ot->exec = multires_external_pack_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /********************* multires apply base ***********************/ static int multires_base_apply_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Multires); - if (!mmd) - return OPERATOR_CANCELLED; + if (!mmd) + return OPERATOR_CANCELLED; - multiresModifier_base_apply(mmd, scene, ob); + multiresModifier_base_apply(mmd, scene, ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return multires_base_apply_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return multires_base_apply_exec(C, op); + else + return OPERATOR_CANCELLED; } - void OBJECT_OT_multires_base_apply(wmOperatorType *ot) { - ot->name = "Multires Apply Base"; - ot->description = "Modify the base mesh to conform to the displaced mesh"; - ot->idname = "OBJECT_OT_multires_base_apply"; + ot->name = "Multires Apply Base"; + ot->description = "Modify the base mesh to conform to the displaced mesh"; + ot->idname = "OBJECT_OT_multires_base_apply"; - ot->poll = multires_poll; - ot->invoke = multires_base_apply_invoke; - ot->exec = multires_base_apply_exec; + ot->poll = multires_poll; + ot->invoke = multires_base_apply_invoke; + ot->exec = multires_base_apply_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } - /************************** skin modifier ***********************/ static void modifier_skin_customdata_delete(Object *ob) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; - if (em) - BM_data_layer_free(em->bm, &em->bm->vdata, CD_MVERT_SKIN); - else - CustomData_free_layer_active(&me->vdata, CD_MVERT_SKIN, me->totvert); + if (em) + BM_data_layer_free(em->bm, &em->bm->vdata, CD_MVERT_SKIN); + else + CustomData_free_layer_active(&me->vdata, CD_MVERT_SKIN, me->totvert); } static bool skin_poll(bContext *C) { - return (!CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); + return (!CTX_data_edit_object(C) && + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); } static bool skin_edit_poll(bContext *C) { - return (CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); + return (CTX_data_edit_object(C) && + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); } static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset) { - BMEdge *bm_edge; - BMIter bm_iter; + BMEdge *bm_edge; + BMIter bm_iter; - BM_ITER_ELEM (bm_edge, &bm_iter, bm_vert, BM_EDGES_OF_VERT) { - BMVert *v2 = BM_edge_other_vert(bm_edge, bm_vert); + BM_ITER_ELEM (bm_edge, &bm_iter, bm_vert, BM_EDGES_OF_VERT) { + BMVert *v2 = BM_edge_other_vert(bm_edge, bm_vert); - if (BLI_gset_add(visited, v2)) { - MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(v2, cd_vert_skin_offset); + if (BLI_gset_add(visited, v2)) { + MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(v2, cd_vert_skin_offset); - /* clear vertex root flag and add to visited set */ - vs->flag &= ~MVERT_SKIN_ROOT; + /* clear vertex root flag and add to visited set */ + vs->flag &= ~MVERT_SKIN_ROOT; - skin_root_clear(v2, visited, cd_vert_skin_offset); - } - } + skin_root_clear(v2, visited, cd_vert_skin_offset); + } + } } static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - BMVert *bm_vert; - BMIter bm_iter; - GSet *visited; + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + BMVert *bm_vert; + BMIter bm_iter; + GSet *visited; - visited = BLI_gset_ptr_new(__func__); + visited = BLI_gset_ptr_new(__func__); - BKE_mesh_ensure_skin_customdata(ob->data); + BKE_mesh_ensure_skin_customdata(ob->data); - const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); + const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); - BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) && - BLI_gset_add(visited, bm_vert)) - { - MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset); + BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) && BLI_gset_add(visited, bm_vert)) { + MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset); - /* mark vertex as root and add to visited set */ - vs->flag |= MVERT_SKIN_ROOT; + /* mark vertex as root and add to visited set */ + vs->flag |= MVERT_SKIN_ROOT; - /* clear root flag from all connected vertices (recursively) */ - skin_root_clear(bm_vert, visited, cd_vert_skin_offset); - } - } + /* clear root flag from all connected vertices (recursively) */ + skin_root_clear(bm_vert, visited, cd_vert_skin_offset); + } + } - BLI_gset_free(visited, NULL); + BLI_gset_free(visited, NULL); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_skin_root_mark(wmOperatorType *ot) { - ot->name = "Skin Root Mark"; - ot->description = "Mark selected vertices as roots"; - ot->idname = "OBJECT_OT_skin_root_mark"; + ot->name = "Skin Root Mark"; + ot->description = "Mark selected vertices as roots"; + ot->idname = "OBJECT_OT_skin_root_mark"; - ot->poll = skin_edit_poll; - ot->exec = skin_root_mark_exec; + ot->poll = skin_edit_poll; + ot->exec = skin_root_mark_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } typedef enum { - SKIN_LOOSE_MARK, - SKIN_LOOSE_CLEAR, + SKIN_LOOSE_MARK, + SKIN_LOOSE_CLEAR, } SkinLooseAction; static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - BMVert *bm_vert; - BMIter bm_iter; - SkinLooseAction action = RNA_enum_get(op->ptr, "action"); - - if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { - return OPERATOR_CANCELLED; - } - - BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { - MVertSkin *vs = CustomData_bmesh_get( - &bm->vdata, - bm_vert->head.data, - CD_MVERT_SKIN); - - switch (action) { - case SKIN_LOOSE_MARK: - vs->flag |= MVERT_SKIN_LOOSE; - break; - case SKIN_LOOSE_CLEAR: - vs->flag &= ~MVERT_SKIN_LOOSE; - break; - } - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - - return OPERATOR_FINISHED; + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + BMVert *bm_vert; + BMIter bm_iter; + SkinLooseAction action = RNA_enum_get(op->ptr, "action"); + + if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { + return OPERATOR_CANCELLED; + } + + BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { + MVertSkin *vs = CustomData_bmesh_get(&bm->vdata, bm_vert->head.data, CD_MVERT_SKIN); + + switch (action) { + case SKIN_LOOSE_MARK: + vs->flag |= MVERT_SKIN_LOOSE; + break; + case SKIN_LOOSE_CLEAR: + vs->flag &= ~MVERT_SKIN_LOOSE; + break; + } + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; } void OBJECT_OT_skin_loose_mark_clear(wmOperatorType *ot) { - static const EnumPropertyItem action_items[] = { - {SKIN_LOOSE_MARK, "MARK", 0, "Mark", "Mark selected vertices as loose"}, - {SKIN_LOOSE_CLEAR, "CLEAR", 0, "Clear", "Set selected vertices as not loose"}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem action_items[] = { + {SKIN_LOOSE_MARK, "MARK", 0, "Mark", "Mark selected vertices as loose"}, + {SKIN_LOOSE_CLEAR, "CLEAR", 0, "Clear", "Set selected vertices as not loose"}, + {0, NULL, 0, NULL, NULL}, + }; - ot->name = "Skin Mark/Clear Loose"; - ot->description = "Mark/clear selected vertices as loose"; - ot->idname = "OBJECT_OT_skin_loose_mark_clear"; + ot->name = "Skin Mark/Clear Loose"; + ot->description = "Mark/clear selected vertices as loose"; + ot->idname = "OBJECT_OT_skin_loose_mark_clear"; - ot->poll = skin_edit_poll; - ot->exec = skin_loose_mark_clear_exec; + ot->poll = skin_edit_poll; + ot->exec = skin_loose_mark_clear_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "action", action_items, SKIN_LOOSE_MARK, "Action", NULL); + RNA_def_enum(ot->srna, "action", action_items, SKIN_LOOSE_MARK, "Action", NULL); } static int skin_radii_equalize_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em->bm; - BMVert *bm_vert; - BMIter bm_iter; + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + BMVert *bm_vert; + BMIter bm_iter; - if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { - return OPERATOR_CANCELLED; - } + if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { + return OPERATOR_CANCELLED; + } - BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { - MVertSkin *vs = CustomData_bmesh_get( - &bm->vdata, - bm_vert->head.data, - CD_MVERT_SKIN); - float avg = (vs->radius[0] + vs->radius[1]) * 0.5f; + BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { + MVertSkin *vs = CustomData_bmesh_get(&bm->vdata, bm_vert->head.data, CD_MVERT_SKIN); + float avg = (vs->radius[0] + vs->radius[1]) * 0.5f; - vs->radius[0] = vs->radius[1] = avg; - } - } + vs->radius[0] = vs->radius[1] = avg; + } + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot) { - ot->name = "Skin Radii Equalize"; - ot->description = "Make skin radii of selected vertices equal on each axis"; - ot->idname = "OBJECT_OT_skin_radii_equalize"; + ot->name = "Skin Radii Equalize"; + ot->description = "Make skin radii of selected vertices equal on each axis"; + ot->idname = "OBJECT_OT_skin_radii_equalize"; - ot->poll = skin_edit_poll; - ot->exec = skin_radii_equalize_exec; + ot->poll = skin_edit_poll; + ot->exec = skin_radii_equalize_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static void skin_armature_bone_create(Object *skin_ob, - MVert *mvert, MEdge *medge, - bArmature *arm, - BLI_bitmap *edges_visited, - const MeshElemMap *emap, - EditBone *parent_bone, - int parent_v) -{ - int i; - - for (i = 0; i < emap[parent_v].count; i++) { - int endx = emap[parent_v].indices[i]; - const MEdge *e = &medge[endx]; - EditBone *bone; - bDeformGroup *dg; - int v; - - /* ignore edge if already visited */ - if (BLI_BITMAP_TEST(edges_visited, endx)) - continue; - BLI_BITMAP_ENABLE(edges_visited, endx); - - v = (e->v1 == parent_v ? e->v2 : e->v1); - - bone = ED_armature_ebone_add(arm, "Bone"); - - bone->parent = parent_bone; - bone->flag |= BONE_CONNECTED; - - copy_v3_v3(bone->head, mvert[parent_v].co); - copy_v3_v3(bone->tail, mvert[v].co); - bone->rad_head = bone->rad_tail = 0.25; - BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx); - - /* add bDeformGroup */ - if ((dg = BKE_object_defgroup_add_name(skin_ob, bone->name))) { - ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE); - ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE); - } - - skin_armature_bone_create( - skin_ob, - mvert, medge, - arm, - edges_visited, - emap, - bone, - v); - } -} - -static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *skin_ob) -{ - BLI_bitmap *edges_visited; - Mesh *me_eval_deform; - MVert *mvert; - Mesh *me = skin_ob->data; - Object *arm_ob; - bArmature *arm; - MVertSkin *mvert_skin; - MeshElemMap *emap; - int *emap_mem; - int v; - - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, skin_ob); - - me_eval_deform = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); - mvert = me_eval_deform->mvert; - - /* add vertex weights to original mesh */ - CustomData_add_layer( - &me->vdata, - CD_MDEFORMVERT, - CD_CALLOC, - NULL, - me->totvert); - - ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL); - BKE_object_transform_copy(arm_ob, skin_ob); - arm = arm_ob->data; - arm->layer = 1; - arm_ob->dtx |= OB_DRAWXRAY; - arm->drawtype = ARM_LINE; - arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature"); - - mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN); - BKE_mesh_vert_edge_map_create( - &emap, &emap_mem, - me->medge, me->totvert, me->totedge); - - edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); - - /* note: we use EditBones here, easier to set them up and use - * edit-armature functions to convert back to regular bones */ - for (v = 0; v < me->totvert; v++) { - if (mvert_skin[v].flag & MVERT_SKIN_ROOT) { - EditBone *bone = NULL; - - /* Unless the skin root has just one adjacent edge, create - * a fake root bone (have it going off in the Y direction - * (arbitrary) */ - if (emap[v].count > 1) { - bone = ED_armature_ebone_add(arm, "Bone"); - - copy_v3_v3(bone->head, me->mvert[v].co); - copy_v3_v3(bone->tail, me->mvert[v].co); - - bone->head[1] = 1.0f; - bone->rad_head = bone->rad_tail = 0.25; - } - - if (emap[v].count >= 1) { - skin_armature_bone_create( - skin_ob, - mvert, me->medge, - arm, - edges_visited, - emap, - bone, - v); - } - } - } - - MEM_freeN(edges_visited); - MEM_freeN(emap); - MEM_freeN(emap_mem); - - ED_armature_from_edit(bmain, arm); - ED_armature_edit_free(arm); - - return arm_ob; + MVert *mvert, + MEdge *medge, + bArmature *arm, + BLI_bitmap *edges_visited, + const MeshElemMap *emap, + EditBone *parent_bone, + int parent_v) +{ + int i; + + for (i = 0; i < emap[parent_v].count; i++) { + int endx = emap[parent_v].indices[i]; + const MEdge *e = &medge[endx]; + EditBone *bone; + bDeformGroup *dg; + int v; + + /* ignore edge if already visited */ + if (BLI_BITMAP_TEST(edges_visited, endx)) + continue; + BLI_BITMAP_ENABLE(edges_visited, endx); + + v = (e->v1 == parent_v ? e->v2 : e->v1); + + bone = ED_armature_ebone_add(arm, "Bone"); + + bone->parent = parent_bone; + bone->flag |= BONE_CONNECTED; + + copy_v3_v3(bone->head, mvert[parent_v].co); + copy_v3_v3(bone->tail, mvert[v].co); + bone->rad_head = bone->rad_tail = 0.25; + BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx); + + /* add bDeformGroup */ + if ((dg = BKE_object_defgroup_add_name(skin_ob, bone->name))) { + ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE); + ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE); + } + + skin_armature_bone_create(skin_ob, mvert, medge, arm, edges_visited, emap, bone, v); + } +} + +static Object *modifier_skin_armature_create(Depsgraph *depsgraph, + Main *bmain, + Scene *scene, + Object *skin_ob) +{ + BLI_bitmap *edges_visited; + Mesh *me_eval_deform; + MVert *mvert; + Mesh *me = skin_ob->data; + Object *arm_ob; + bArmature *arm; + MVertSkin *mvert_skin; + MeshElemMap *emap; + int *emap_mem; + int v; + + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, skin_ob); + + me_eval_deform = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + mvert = me_eval_deform->mvert; + + /* add vertex weights to original mesh */ + CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); + + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL); + BKE_object_transform_copy(arm_ob, skin_ob); + arm = arm_ob->data; + arm->layer = 1; + arm_ob->dtx |= OB_DRAWXRAY; + arm->drawtype = ARM_LINE; + arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature"); + + mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN); + BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge); + + edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); + + /* note: we use EditBones here, easier to set them up and use + * edit-armature functions to convert back to regular bones */ + for (v = 0; v < me->totvert; v++) { + if (mvert_skin[v].flag & MVERT_SKIN_ROOT) { + EditBone *bone = NULL; + + /* Unless the skin root has just one adjacent edge, create + * a fake root bone (have it going off in the Y direction + * (arbitrary) */ + if (emap[v].count > 1) { + bone = ED_armature_ebone_add(arm, "Bone"); + + copy_v3_v3(bone->head, me->mvert[v].co); + copy_v3_v3(bone->tail, me->mvert[v].co); + + bone->head[1] = 1.0f; + bone->rad_head = bone->rad_tail = 0.25; + } + + if (emap[v].count >= 1) { + skin_armature_bone_create(skin_ob, mvert, me->medge, arm, edges_visited, emap, bone, v); + } + } + } + + MEM_freeN(edges_visited); + MEM_freeN(emap); + MEM_freeN(emap_mem); + + ED_armature_from_edit(bmain, arm); + ED_armature_edit_free(arm); + + return arm_ob; } static int skin_armature_create_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C), *arm_ob; - Mesh *me = ob->data; - ModifierData *skin_md; - ArmatureModifierData *arm_md; + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C), *arm_ob; + Mesh *me = ob->data; + ModifierData *skin_md; + ArmatureModifierData *arm_md; - if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { - BKE_reportf(op->reports, RPT_WARNING, "Mesh '%s' has no skin vertex data", me->id.name + 2); - return OPERATOR_CANCELLED; - } + if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { + BKE_reportf(op->reports, RPT_WARNING, "Mesh '%s' has no skin vertex data", me->id.name + 2); + return OPERATOR_CANCELLED; + } - /* create new armature */ - arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob); + /* create new armature */ + arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob); - /* add a modifier to connect the new armature to the mesh */ - arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature); - if (arm_md) { - skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin); - BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md); + /* add a modifier to connect the new armature to the mesh */ + arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature); + if (arm_md) { + skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin); + BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md); - arm_md->object = arm_ob; - arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION; - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } + arm_md->object = arm_ob; + arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION; + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int skin_armature_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return skin_armature_create_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return skin_armature_create_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_skin_armature_create(wmOperatorType *ot) { - ot->name = "Skin Armature Create"; - ot->description = "Create an armature that parallels the skin layout"; - ot->idname = "OBJECT_OT_skin_armature_create"; + ot->name = "Skin Armature Create"; + ot->description = "Create an armature that parallels the skin layout"; + ot->idname = "OBJECT_OT_skin_armature_create"; - ot->poll = skin_poll; - ot->invoke = skin_armature_create_invoke; - ot->exec = skin_armature_create_exec; + ot->poll = skin_poll; + ot->invoke = skin_armature_create_invoke; + ot->exec = skin_armature_create_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ delta mush bind operator *********************/ static bool correctivesmooth_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0); + return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0); } static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth); - bool is_bind; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get( + op, ob, eModifierType_CorrectiveSmooth); + bool is_bind; - if (!csmd) { - return OPERATOR_CANCELLED; - } + if (!csmd) { + return OPERATOR_CANCELLED; + } - if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) { - BKE_report(op->reports, RPT_ERROR, "Modifier is disabled"); - return OPERATOR_CANCELLED; - } + if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) { + BKE_report(op->reports, RPT_ERROR, "Modifier is disabled"); + return OPERATOR_CANCELLED; + } - is_bind = (csmd->bind_coords != NULL); + is_bind = (csmd->bind_coords != NULL); - MEM_SAFE_FREE(csmd->bind_coords); - MEM_SAFE_FREE(csmd->delta_cache); + MEM_SAFE_FREE(csmd->bind_coords); + MEM_SAFE_FREE(csmd->delta_cache); - if (is_bind) { - /* toggle off */ - csmd->bind_coords_num = 0; - } - else { - /* Signal to modifier to recalculate. */ - CorrectiveSmoothModifierData *csmd_eval = - (CorrectiveSmoothModifierData *)modifier_get_evaluated(depsgraph, ob, &csmd->modifier); - csmd_eval->bind_coords_num = (unsigned int)-1; + if (is_bind) { + /* toggle off */ + csmd->bind_coords_num = 0; + } + else { + /* Signal to modifier to recalculate. */ + CorrectiveSmoothModifierData *csmd_eval = (CorrectiveSmoothModifierData *) + modifier_get_evaluated(depsgraph, ob, &csmd->modifier); + csmd_eval->bind_coords_num = (unsigned int)-1; - /* Force modifier to run, it will call binding routine - * (this has to happen outside of depsgraph evaluation). */ - object_force_modifier_bind_simple_options(depsgraph, ob, &csmd->modifier); - } + /* Force modifier to run, it will call binding routine + * (this has to happen outside of depsgraph evaluation). */ + object_force_modifier_bind_simple_options(depsgraph, ob, &csmd->modifier); + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return correctivesmooth_bind_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return correctivesmooth_bind_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Corrective Smooth Bind"; - ot->description = "Bind base pose in Corrective Smooth modifier"; - ot->idname = "OBJECT_OT_correctivesmooth_bind"; + /* identifiers */ + ot->name = "Corrective Smooth Bind"; + ot->description = "Bind base pose in Corrective Smooth modifier"; + ot->idname = "OBJECT_OT_correctivesmooth_bind"; - /* api callbacks */ - ot->poll = correctivesmooth_poll; - ot->invoke = correctivesmooth_bind_invoke; - ot->exec = correctivesmooth_bind_exec; + /* api callbacks */ + ot->poll = correctivesmooth_poll; + ot->invoke = correctivesmooth_bind_invoke; + ot->exec = correctivesmooth_bind_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ mdef bind operator *********************/ static bool meshdeform_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_MeshDeformModifier, 0); + return edit_modifier_poll_generic(C, &RNA_MeshDeformModifier, 0); } static int meshdeform_bind_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *ob = ED_object_active_context(C); - MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_MeshDeform); - - if (mmd == NULL) { - return OPERATOR_CANCELLED; - } - - if (mmd->bindcagecos != NULL) { - MEM_SAFE_FREE(mmd->bindcagecos); - MEM_SAFE_FREE(mmd->dyngrid); - MEM_SAFE_FREE(mmd->dyninfluences); - MEM_SAFE_FREE(mmd->bindinfluences); - MEM_SAFE_FREE(mmd->bindoffsets); - MEM_SAFE_FREE(mmd->dynverts); - MEM_SAFE_FREE(mmd->bindweights); /* Deprecated */ - MEM_SAFE_FREE(mmd->bindcos); /* Deprecated */ - mmd->totvert = 0; - mmd->totcagevert = 0; - mmd->totinfluence = 0; - } - else { - /* Force modifier to run, it will call binding routine (this has to happen outside of depsgraph evaluation). */ - MeshDeformModifierData *mmd_eval = - (MeshDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &mmd->modifier); - mmd_eval->bindfunc = ED_mesh_deform_bind_callback; - object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier); - mmd_eval->bindfunc = NULL; - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = ED_object_active_context(C); + MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get( + op, ob, eModifierType_MeshDeform); + + if (mmd == NULL) { + return OPERATOR_CANCELLED; + } + + if (mmd->bindcagecos != NULL) { + MEM_SAFE_FREE(mmd->bindcagecos); + MEM_SAFE_FREE(mmd->dyngrid); + MEM_SAFE_FREE(mmd->dyninfluences); + MEM_SAFE_FREE(mmd->bindinfluences); + MEM_SAFE_FREE(mmd->bindoffsets); + MEM_SAFE_FREE(mmd->dynverts); + MEM_SAFE_FREE(mmd->bindweights); /* Deprecated */ + MEM_SAFE_FREE(mmd->bindcos); /* Deprecated */ + mmd->totvert = 0; + mmd->totcagevert = 0; + mmd->totinfluence = 0; + } + else { + /* Force modifier to run, it will call binding routine (this has to happen outside of depsgraph evaluation). */ + MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)modifier_get_evaluated( + depsgraph, ob, &mmd->modifier); + mmd_eval->bindfunc = ED_mesh_deform_bind_callback; + object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier); + mmd_eval->bindfunc = NULL; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + return OPERATOR_FINISHED; } static int meshdeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return meshdeform_bind_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return meshdeform_bind_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_meshdeform_bind(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mesh Deform Bind"; - ot->description = "Bind mesh to cage in mesh deform modifier"; - ot->idname = "OBJECT_OT_meshdeform_bind"; + /* identifiers */ + ot->name = "Mesh Deform Bind"; + ot->description = "Bind mesh to cage in mesh deform modifier"; + ot->idname = "OBJECT_OT_meshdeform_bind"; - /* api callbacks */ - ot->poll = meshdeform_poll; - ot->invoke = meshdeform_bind_invoke; - ot->exec = meshdeform_bind_exec; + /* api callbacks */ + ot->poll = meshdeform_poll; + ot->invoke = meshdeform_bind_invoke; + ot->exec = meshdeform_bind_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /****************** explode refresh operator *********************/ static bool explode_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_ExplodeModifier, 0); + return edit_modifier_poll_generic(C, &RNA_ExplodeModifier, 0); } static int explode_refresh_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ExplodeModifierData *emd = (ExplodeModifierData *)edit_modifier_property_get(op, ob, eModifierType_Explode); + Object *ob = ED_object_active_context(C); + ExplodeModifierData *emd = (ExplodeModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Explode); - if (!emd) - return OPERATOR_CANCELLED; + if (!emd) + return OPERATOR_CANCELLED; - emd->flag |= eExplodeFlag_CalcFaces; + emd->flag |= eExplodeFlag_CalcFaces; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int explode_refresh_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return explode_refresh_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return explode_refresh_exec(C, op); + else + return OPERATOR_CANCELLED; } - void OBJECT_OT_explode_refresh(wmOperatorType *ot) { - ot->name = "Explode Refresh"; - ot->description = "Refresh data in the Explode modifier"; - ot->idname = "OBJECT_OT_explode_refresh"; + ot->name = "Explode Refresh"; + ot->description = "Refresh data in the Explode modifier"; + ot->idname = "OBJECT_OT_explode_refresh"; - ot->poll = explode_poll; - ot->invoke = explode_refresh_invoke; - ot->exec = explode_refresh_exec; + ot->poll = explode_poll; + ot->invoke = explode_refresh_invoke; + ot->exec = explode_refresh_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } - /****************** ocean bake operator *********************/ static bool ocean_bake_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0); + return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0); } typedef struct OceanBakeJob { - /* from wmJob */ - struct Object *owner; - short *stop, *do_update; - float *progress; - int current_frame; - struct OceanCache *och; - struct Ocean *ocean; - struct OceanModifierData *omd; + /* from wmJob */ + struct Object *owner; + short *stop, *do_update; + float *progress; + int current_frame; + struct OceanCache *och; + struct Ocean *ocean; + struct OceanModifierData *omd; } OceanBakeJob; static void oceanbake_free(void *customdata) { - OceanBakeJob *oj = customdata; - MEM_freeN(oj); + OceanBakeJob *oj = customdata; + MEM_freeN(oj); } /* called by oceanbake, only to check job 'stop' value */ static int oceanbake_breakjob(void *UNUSED(customdata)) { - //OceanBakeJob *ob = (OceanBakeJob *)customdata; - //return *(ob->stop); + //OceanBakeJob *ob = (OceanBakeJob *)customdata; + //return *(ob->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... */ - return (G.is_break); + /* 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... */ + return (G.is_break); } /* called by oceanbake, wmJob sends notifier */ static void oceanbake_update(void *customdata, float progress, int *cancel) { - OceanBakeJob *oj = customdata; + OceanBakeJob *oj = customdata; - if (oceanbake_breakjob(oj)) - *cancel = 1; + if (oceanbake_breakjob(oj)) + *cancel = 1; - *(oj->do_update) = true; - *(oj->progress) = progress; + *(oj->do_update) = true; + *(oj->progress) = progress; } static void oceanbake_startjob(void *customdata, short *stop, short *do_update, float *progress) { - OceanBakeJob *oj = customdata; + OceanBakeJob *oj = customdata; - oj->stop = stop; - oj->do_update = do_update; - oj->progress = progress; + oj->stop = stop; + oj->do_update = do_update; + oj->progress = progress; - G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ + G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ - BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj); + BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj); - *do_update = true; - *stop = 0; + *do_update = true; + *stop = 0; } static void oceanbake_endjob(void *customdata) { - OceanBakeJob *oj = customdata; + OceanBakeJob *oj = customdata; - if (oj->ocean) { - BKE_ocean_free(oj->ocean); - oj->ocean = NULL; - } + if (oj->ocean) { + BKE_ocean_free(oj->ocean); + oj->ocean = NULL; + } - oj->omd->oceancache = oj->och; - oj->omd->cached = true; + oj->omd->oceancache = oj->och; + oj->omd->cached = true; - Object *ob = oj->owner; - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + Object *ob = oj->owner; + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); } static int ocean_bake_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get(op, ob, eModifierType_Ocean); - Scene *scene = CTX_data_scene(C); - OceanCache *och; - struct Ocean *ocean; - int f, cfra, i = 0; - const bool free = RNA_boolean_get(op->ptr, "free"); - - wmJob *wm_job; - OceanBakeJob *oj; - - if (!omd) - return OPERATOR_CANCELLED; - - if (free) { - BKE_ocean_free_modifier_cache(omd); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; - } - - och = BKE_ocean_init_cache( - omd->cachepath, modifier_path_relbase(bmain, ob), - omd->bakestart, omd->bakeend, omd->wave_scale, - omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); - - och->time = MEM_mallocN(och->duration * sizeof(float), "foam bake time"); - - cfra = scene->r.cfra; - - /* precalculate time variable before baking */ - for (f = omd->bakestart; f <= omd->bakeend; f++) { - /* For now only simple animation of time value is supported, nothing else. - * No drivers or other modifier parameters. */ - BKE_animsys_evaluate_animdata(CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); - - och->time[i] = omd->time; - i++; - } - - /* make a copy of ocean to use for baking - threadsafety */ - ocean = BKE_ocean_add(); - BKE_ocean_init_from_modifier(ocean, omd); + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get( + op, ob, eModifierType_Ocean); + Scene *scene = CTX_data_scene(C); + OceanCache *och; + struct Ocean *ocean; + int f, cfra, i = 0; + const bool free = RNA_boolean_get(op->ptr, "free"); + + wmJob *wm_job; + OceanBakeJob *oj; + + if (!omd) + return OPERATOR_CANCELLED; + + if (free) { + BKE_ocean_free_modifier_cache(omd); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + return OPERATOR_FINISHED; + } + + och = BKE_ocean_init_cache(omd->cachepath, + modifier_path_relbase(bmain, ob), + omd->bakestart, + omd->bakeend, + omd->wave_scale, + omd->chop_amount, + omd->foam_coverage, + omd->foam_fade, + omd->resolution); + + och->time = MEM_mallocN(och->duration * sizeof(float), "foam bake time"); + + cfra = scene->r.cfra; + + /* precalculate time variable before baking */ + for (f = omd->bakestart; f <= omd->bakeend; f++) { + /* For now only simple animation of time value is supported, nothing else. + * No drivers or other modifier parameters. */ + BKE_animsys_evaluate_animdata( + CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); + + och->time[i] = omd->time; + i++; + } + + /* make a copy of ocean to use for baking - threadsafety */ + ocean = BKE_ocean_add(); + BKE_ocean_init_from_modifier(ocean, omd); #if 0 - BKE_ocean_bake(ocean, och); + BKE_ocean_bake(ocean, och); - omd->oceancache = och; - omd->cached = true; + omd->oceancache = och; + omd->cached = true; - scene->r.cfra = cfra; + scene->r.cfra = cfra; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); #endif - /* job stuff */ + /* job stuff */ - scene->r.cfra = cfra; + scene->r.cfra = cfra; - /* setup job */ - wm_job = WM_jobs_get( - CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", - WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN); - oj = MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); - oj->owner = ob; - oj->ocean = ocean; - oj->och = och; - oj->omd = omd; + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Ocean Simulation", + WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_SIM_OCEAN); + oj = MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); + oj->owner = ob; + oj->ocean = ocean; + oj->och = och; + oj->omd = omd; - WM_jobs_customdata_set(wm_job, oj, oceanbake_free); - WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); - WM_jobs_callbacks(wm_job, oceanbake_startjob, NULL, NULL, oceanbake_endjob); + WM_jobs_customdata_set(wm_job, oj, oceanbake_free); + WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); + WM_jobs_callbacks(wm_job, oceanbake_startjob, NULL, NULL, oceanbake_endjob); - WM_jobs_start(CTX_wm_manager(C), wm_job); + WM_jobs_start(CTX_wm_manager(C), wm_job); - - - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int ocean_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return ocean_bake_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return ocean_bake_exec(C, op); + else + return OPERATOR_CANCELLED; } - void OBJECT_OT_ocean_bake(wmOperatorType *ot) { - ot->name = "Bake Ocean"; - ot->description = "Bake an image sequence of ocean data"; - ot->idname = "OBJECT_OT_ocean_bake"; + ot->name = "Bake Ocean"; + ot->description = "Bake an image sequence of ocean data"; + ot->idname = "OBJECT_OT_ocean_bake"; - ot->poll = ocean_bake_poll; - ot->invoke = ocean_bake_invoke; - ot->exec = ocean_bake_exec; + ot->poll = ocean_bake_poll; + ot->invoke = ocean_bake_invoke; + ot->exec = ocean_bake_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); - RNA_def_boolean(ot->srna, "free", false, "Free", "Free the bake, rather than generating it"); + RNA_def_boolean(ot->srna, "free", false, "Free", "Free the bake, rather than generating it"); } /************************ LaplacianDeform bind operator *********************/ static bool laplaciandeform_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_LaplacianDeformModifier, 0); + return edit_modifier_poll_generic(C, &RNA_LaplacianDeformModifier, 0); } static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_LaplacianDeform); - - if (lmd == NULL) { - return OPERATOR_CANCELLED; - } - - if (lmd->flag & MOD_LAPLACIANDEFORM_BIND) { - lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; - } - else { - lmd->flag |= MOD_LAPLACIANDEFORM_BIND; - } - - LaplacianDeformModifierData *lmd_eval = - (LaplacianDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &lmd->modifier); - lmd_eval->flag = lmd->flag; - - /* Force modifier to run, it will call binding routine - * (this has to happen outside of depsgraph evaluation). */ - object_force_modifier_bind_simple_options(depsgraph, ob, &lmd->modifier); - - /* This is hard to know from the modifier itself whether the evaluation is - * happening for binding or not. So we copy all the required data here. */ - lmd->total_verts = lmd_eval->total_verts; - if (lmd_eval->vertexco == NULL) { - MEM_SAFE_FREE(lmd->vertexco); - } - else { - lmd->vertexco = MEM_dupallocN(lmd_eval->vertexco); - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + Object *ob = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)edit_modifier_property_get( + op, ob, eModifierType_LaplacianDeform); + + if (lmd == NULL) { + return OPERATOR_CANCELLED; + } + + if (lmd->flag & MOD_LAPLACIANDEFORM_BIND) { + lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; + } + else { + lmd->flag |= MOD_LAPLACIANDEFORM_BIND; + } + + LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)modifier_get_evaluated( + depsgraph, ob, &lmd->modifier); + lmd_eval->flag = lmd->flag; + + /* Force modifier to run, it will call binding routine + * (this has to happen outside of depsgraph evaluation). */ + object_force_modifier_bind_simple_options(depsgraph, ob, &lmd->modifier); + + /* This is hard to know from the modifier itself whether the evaluation is + * happening for binding or not. So we copy all the required data here. */ + lmd->total_verts = lmd_eval->total_verts; + if (lmd_eval->vertexco == NULL) { + MEM_SAFE_FREE(lmd->vertexco); + } + else { + lmd->vertexco = MEM_dupallocN(lmd_eval->vertexco); + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + return OPERATOR_FINISHED; } static int laplaciandeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return laplaciandeform_bind_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return laplaciandeform_bind_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_laplaciandeform_bind(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Laplacian Deform Bind"; - ot->description = "Bind mesh to system in laplacian deform modifier"; - ot->idname = "OBJECT_OT_laplaciandeform_bind"; + /* identifiers */ + ot->name = "Laplacian Deform Bind"; + ot->description = "Bind mesh to system in laplacian deform modifier"; + ot->idname = "OBJECT_OT_laplaciandeform_bind"; - /* api callbacks */ - ot->poll = laplaciandeform_poll; - ot->invoke = laplaciandeform_bind_invoke; - ot->exec = laplaciandeform_bind_exec; + /* api callbacks */ + ot->poll = laplaciandeform_poll; + ot->invoke = laplaciandeform_bind_invoke; + ot->exec = laplaciandeform_bind_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } /************************ sdef bind operator *********************/ static bool surfacedeform_bind_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0); + return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0); } static int surfacedeform_bind_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_SurfaceDeform); + Object *ob = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get( + op, ob, eModifierType_SurfaceDeform); - if (smd == NULL) { - return OPERATOR_CANCELLED; - } + if (smd == NULL) { + return OPERATOR_CANCELLED; + } - if (smd->flags & MOD_SDEF_BIND) { - smd->flags &= ~MOD_SDEF_BIND; - } - else if (smd->target) { - smd->flags |= MOD_SDEF_BIND; - } + if (smd->flags & MOD_SDEF_BIND) { + smd->flags &= ~MOD_SDEF_BIND; + } + else if (smd->target) { + smd->flags |= MOD_SDEF_BIND; + } - SurfaceDeformModifierData *smd_eval = - (SurfaceDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &smd->modifier); - smd_eval->flags = smd->flags; + SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)modifier_get_evaluated( + depsgraph, ob, &smd->modifier); + smd_eval->flags = smd->flags; - /* Force modifier to run, it will call binding routine - * (this has to happen outside of depsgraph evaluation). */ - object_force_modifier_bind_simple_options(depsgraph, ob, &smd->modifier); + /* Force modifier to run, it will call binding routine + * (this has to happen outside of depsgraph evaluation). */ + object_force_modifier_bind_simple_options(depsgraph, ob, &smd->modifier); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + return OPERATOR_FINISHED; } static int surfacedeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op)) - return surfacedeform_bind_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_modifier_invoke_properties(C, op)) + return surfacedeform_bind_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Surface Deform Bind"; - ot->description = "Bind mesh to target in surface deform modifier"; - ot->idname = "OBJECT_OT_surfacedeform_bind"; + /* identifiers */ + ot->name = "Surface Deform Bind"; + ot->description = "Bind mesh to target in surface deform modifier"; + ot->idname = "OBJECT_OT_surfacedeform_bind"; - /* api callbacks */ - ot->poll = surfacedeform_bind_poll; - ot->invoke = surfacedeform_bind_invoke; - ot->exec = surfacedeform_bind_exec; + /* api callbacks */ + ot->poll = surfacedeform_bind_poll; + ot->invoke = surfacedeform_bind_invoke; + ot->exec = surfacedeform_bind_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_modifier_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 024fa24480a..8e3f916b2e4 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdlib.h> #include <math.h> @@ -46,262 +45,263 @@ #include "object_intern.h" - /* ************************** registration **********************************/ - void ED_operatortypes_object(void) { - WM_operatortype_append(OBJECT_OT_location_clear); - WM_operatortype_append(OBJECT_OT_rotation_clear); - WM_operatortype_append(OBJECT_OT_scale_clear); - WM_operatortype_append(OBJECT_OT_origin_clear); - WM_operatortype_append(OBJECT_OT_visual_transform_apply); - WM_operatortype_append(OBJECT_OT_transform_apply); - WM_operatortype_append(OBJECT_OT_transform_axis_target); - WM_operatortype_append(OBJECT_OT_origin_set); - - WM_operatortype_append(OBJECT_OT_mode_set); - WM_operatortype_append(OBJECT_OT_mode_set_or_submode); - WM_operatortype_append(OBJECT_OT_editmode_toggle); - WM_operatortype_append(OBJECT_OT_posemode_toggle); - WM_operatortype_append(OBJECT_OT_proxy_make); - WM_operatortype_append(OBJECT_OT_shade_smooth); - WM_operatortype_append(OBJECT_OT_shade_flat); - WM_operatortype_append(OBJECT_OT_paths_calculate); - WM_operatortype_append(OBJECT_OT_paths_update); - WM_operatortype_append(OBJECT_OT_paths_clear); - WM_operatortype_append(OBJECT_OT_paths_range_update); - WM_operatortype_append(OBJECT_OT_forcefield_toggle); - - WM_operatortype_append(OBJECT_OT_parent_set); - WM_operatortype_append(OBJECT_OT_parent_no_inverse_set); - WM_operatortype_append(OBJECT_OT_parent_clear); - WM_operatortype_append(OBJECT_OT_vertex_parent_set); - WM_operatortype_append(OBJECT_OT_track_set); - WM_operatortype_append(OBJECT_OT_track_clear); - WM_operatortype_append(OBJECT_OT_make_local); - WM_operatortype_append(OBJECT_OT_make_override_static); - WM_operatortype_append(OBJECT_OT_make_single_user); - WM_operatortype_append(OBJECT_OT_make_links_scene); - WM_operatortype_append(OBJECT_OT_make_links_data); - - WM_operatortype_append(OBJECT_OT_select_random); - WM_operatortype_append(OBJECT_OT_select_all); - WM_operatortype_append(OBJECT_OT_select_same_collection); - WM_operatortype_append(OBJECT_OT_select_by_type); - WM_operatortype_append(OBJECT_OT_select_linked); - WM_operatortype_append(OBJECT_OT_select_grouped); - WM_operatortype_append(OBJECT_OT_select_mirror); - WM_operatortype_append(OBJECT_OT_select_more); - WM_operatortype_append(OBJECT_OT_select_less); - - WM_operatortype_append(COLLECTION_OT_create); - WM_operatortype_append(COLLECTION_OT_objects_remove_all); - WM_operatortype_append(COLLECTION_OT_objects_remove); - WM_operatortype_append(COLLECTION_OT_objects_add_active); - WM_operatortype_append(COLLECTION_OT_objects_remove_active); - - WM_operatortype_append(OBJECT_OT_delete); - WM_operatortype_append(OBJECT_OT_text_add); - WM_operatortype_append(OBJECT_OT_armature_add); - WM_operatortype_append(OBJECT_OT_empty_add); - WM_operatortype_append(OBJECT_OT_lightprobe_add); - WM_operatortype_append(OBJECT_OT_drop_named_image); - WM_operatortype_append(OBJECT_OT_gpencil_add); - WM_operatortype_append(OBJECT_OT_light_add); - WM_operatortype_append(OBJECT_OT_camera_add); - WM_operatortype_append(OBJECT_OT_speaker_add); - WM_operatortype_append(OBJECT_OT_add); - WM_operatortype_append(OBJECT_OT_add_named); - WM_operatortype_append(OBJECT_OT_effector_add); - WM_operatortype_append(OBJECT_OT_collection_instance_add); - WM_operatortype_append(OBJECT_OT_metaball_add); - WM_operatortype_append(OBJECT_OT_duplicates_make_real); - WM_operatortype_append(OBJECT_OT_duplicate); - WM_operatortype_append(OBJECT_OT_join); - WM_operatortype_append(OBJECT_OT_join_shapes); - WM_operatortype_append(OBJECT_OT_convert); - - WM_operatortype_append(OBJECT_OT_modifier_add); - WM_operatortype_append(OBJECT_OT_modifier_remove); - WM_operatortype_append(OBJECT_OT_modifier_move_up); - WM_operatortype_append(OBJECT_OT_modifier_move_down); - WM_operatortype_append(OBJECT_OT_modifier_apply); - WM_operatortype_append(OBJECT_OT_modifier_convert); - WM_operatortype_append(OBJECT_OT_modifier_copy); - WM_operatortype_append(OBJECT_OT_multires_subdivide); - WM_operatortype_append(OBJECT_OT_multires_reshape); - WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete); - WM_operatortype_append(OBJECT_OT_multires_base_apply); - WM_operatortype_append(OBJECT_OT_multires_external_save); - WM_operatortype_append(OBJECT_OT_multires_external_pack); - WM_operatortype_append(OBJECT_OT_skin_root_mark); - WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear); - WM_operatortype_append(OBJECT_OT_skin_radii_equalize); - WM_operatortype_append(OBJECT_OT_skin_armature_create); - - /* grease pencil modifiers */ - WM_operatortype_append(OBJECT_OT_gpencil_modifier_add); - WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove); - WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up); - WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down); - WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply); - WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy); - - /* shader fx */ - WM_operatortype_append(OBJECT_OT_shaderfx_add); - WM_operatortype_append(OBJECT_OT_shaderfx_remove); - WM_operatortype_append(OBJECT_OT_shaderfx_move_up); - WM_operatortype_append(OBJECT_OT_shaderfx_move_down); - - WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); - WM_operatortype_append(OBJECT_OT_meshdeform_bind); - WM_operatortype_append(OBJECT_OT_explode_refresh); - WM_operatortype_append(OBJECT_OT_ocean_bake); - - WM_operatortype_append(OBJECT_OT_constraint_add); - WM_operatortype_append(OBJECT_OT_constraint_add_with_targets); - WM_operatortype_append(POSE_OT_constraint_add); - WM_operatortype_append(POSE_OT_constraint_add_with_targets); - WM_operatortype_append(OBJECT_OT_constraints_copy); - WM_operatortype_append(POSE_OT_constraints_copy); - WM_operatortype_append(OBJECT_OT_constraints_clear); - WM_operatortype_append(POSE_OT_constraints_clear); - WM_operatortype_append(POSE_OT_ik_add); - WM_operatortype_append(POSE_OT_ik_clear); - WM_operatortype_append(CONSTRAINT_OT_delete); - WM_operatortype_append(CONSTRAINT_OT_move_up); - WM_operatortype_append(CONSTRAINT_OT_move_down); - WM_operatortype_append(CONSTRAINT_OT_stretchto_reset); - WM_operatortype_append(CONSTRAINT_OT_limitdistance_reset); - WM_operatortype_append(CONSTRAINT_OT_childof_set_inverse); - WM_operatortype_append(CONSTRAINT_OT_childof_clear_inverse); - WM_operatortype_append(CONSTRAINT_OT_objectsolver_set_inverse); - WM_operatortype_append(CONSTRAINT_OT_objectsolver_clear_inverse); - WM_operatortype_append(CONSTRAINT_OT_followpath_path_animate); - - WM_operatortype_append(OBJECT_OT_vertex_group_add); - WM_operatortype_append(OBJECT_OT_vertex_group_remove); - WM_operatortype_append(OBJECT_OT_vertex_group_assign); - WM_operatortype_append(OBJECT_OT_vertex_group_assign_new); - WM_operatortype_append(OBJECT_OT_vertex_group_remove_from); - WM_operatortype_append(OBJECT_OT_vertex_group_select); - WM_operatortype_append(OBJECT_OT_vertex_group_deselect); - WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked); - WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected); - WM_operatortype_append(OBJECT_OT_vertex_group_copy); - WM_operatortype_append(OBJECT_OT_vertex_group_normalize); - WM_operatortype_append(OBJECT_OT_vertex_group_normalize_all); - WM_operatortype_append(OBJECT_OT_vertex_group_lock); - WM_operatortype_append(OBJECT_OT_vertex_group_fix); - WM_operatortype_append(OBJECT_OT_vertex_group_invert); - WM_operatortype_append(OBJECT_OT_vertex_group_levels); - WM_operatortype_append(OBJECT_OT_vertex_group_smooth); - WM_operatortype_append(OBJECT_OT_vertex_group_clean); - WM_operatortype_append(OBJECT_OT_vertex_group_quantize); - WM_operatortype_append(OBJECT_OT_vertex_group_limit_total); - WM_operatortype_append(OBJECT_OT_vertex_group_mirror); - WM_operatortype_append(OBJECT_OT_vertex_group_set_active); - WM_operatortype_append(OBJECT_OT_vertex_group_sort); - WM_operatortype_append(OBJECT_OT_vertex_group_move); - WM_operatortype_append(OBJECT_OT_vertex_weight_paste); - WM_operatortype_append(OBJECT_OT_vertex_weight_delete); - WM_operatortype_append(OBJECT_OT_vertex_weight_set_active); - WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active_vertex); - WM_operatortype_append(OBJECT_OT_vertex_weight_copy); - - WM_operatortype_append(OBJECT_OT_face_map_add); - WM_operatortype_append(OBJECT_OT_face_map_remove); - WM_operatortype_append(OBJECT_OT_face_map_assign); - WM_operatortype_append(OBJECT_OT_face_map_remove_from); - WM_operatortype_append(OBJECT_OT_face_map_select); - WM_operatortype_append(OBJECT_OT_face_map_deselect); - WM_operatortype_append(OBJECT_OT_face_map_move); - - WM_operatortype_append(TRANSFORM_OT_vertex_warp); - - WM_operatortype_append(OBJECT_OT_move_to_collection); - WM_operatortype_append(OBJECT_OT_link_to_collection); - - WM_operatortype_append(OBJECT_OT_shape_key_add); - WM_operatortype_append(OBJECT_OT_shape_key_remove); - WM_operatortype_append(OBJECT_OT_shape_key_clear); - WM_operatortype_append(OBJECT_OT_shape_key_retime); - WM_operatortype_append(OBJECT_OT_shape_key_mirror); - WM_operatortype_append(OBJECT_OT_shape_key_move); - - WM_operatortype_append(OBJECT_OT_collection_add); - WM_operatortype_append(OBJECT_OT_collection_link); - WM_operatortype_append(OBJECT_OT_collection_remove); - WM_operatortype_append(OBJECT_OT_collection_unlink); - WM_operatortype_append(OBJECT_OT_collection_objects_select); - - WM_operatortype_append(OBJECT_OT_hook_add_selob); - WM_operatortype_append(OBJECT_OT_hook_add_newob); - WM_operatortype_append(OBJECT_OT_hook_remove); - WM_operatortype_append(OBJECT_OT_hook_select); - WM_operatortype_append(OBJECT_OT_hook_assign); - WM_operatortype_append(OBJECT_OT_hook_reset); - WM_operatortype_append(OBJECT_OT_hook_recenter); - - WM_operatortype_append(OBJECT_OT_bake_image); - WM_operatortype_append(OBJECT_OT_bake); - WM_operatortype_append(OBJECT_OT_drop_named_material); - WM_operatortype_append(OBJECT_OT_unlink_data); - WM_operatortype_append(OBJECT_OT_laplaciandeform_bind); - - WM_operatortype_append(TRANSFORM_OT_vertex_random); - - WM_operatortype_append(OBJECT_OT_data_transfer); - WM_operatortype_append(OBJECT_OT_datalayout_transfer); - WM_operatortype_append(OBJECT_OT_surfacedeform_bind); - - WM_operatortype_append(OBJECT_OT_hide_view_clear); - WM_operatortype_append(OBJECT_OT_hide_view_set); - WM_operatortype_append(OBJECT_OT_hide_collection); + WM_operatortype_append(OBJECT_OT_location_clear); + WM_operatortype_append(OBJECT_OT_rotation_clear); + WM_operatortype_append(OBJECT_OT_scale_clear); + WM_operatortype_append(OBJECT_OT_origin_clear); + WM_operatortype_append(OBJECT_OT_visual_transform_apply); + WM_operatortype_append(OBJECT_OT_transform_apply); + WM_operatortype_append(OBJECT_OT_transform_axis_target); + WM_operatortype_append(OBJECT_OT_origin_set); + + WM_operatortype_append(OBJECT_OT_mode_set); + WM_operatortype_append(OBJECT_OT_mode_set_or_submode); + WM_operatortype_append(OBJECT_OT_editmode_toggle); + WM_operatortype_append(OBJECT_OT_posemode_toggle); + WM_operatortype_append(OBJECT_OT_proxy_make); + WM_operatortype_append(OBJECT_OT_shade_smooth); + WM_operatortype_append(OBJECT_OT_shade_flat); + WM_operatortype_append(OBJECT_OT_paths_calculate); + WM_operatortype_append(OBJECT_OT_paths_update); + WM_operatortype_append(OBJECT_OT_paths_clear); + WM_operatortype_append(OBJECT_OT_paths_range_update); + WM_operatortype_append(OBJECT_OT_forcefield_toggle); + + WM_operatortype_append(OBJECT_OT_parent_set); + WM_operatortype_append(OBJECT_OT_parent_no_inverse_set); + WM_operatortype_append(OBJECT_OT_parent_clear); + WM_operatortype_append(OBJECT_OT_vertex_parent_set); + WM_operatortype_append(OBJECT_OT_track_set); + WM_operatortype_append(OBJECT_OT_track_clear); + WM_operatortype_append(OBJECT_OT_make_local); + WM_operatortype_append(OBJECT_OT_make_override_static); + WM_operatortype_append(OBJECT_OT_make_single_user); + WM_operatortype_append(OBJECT_OT_make_links_scene); + WM_operatortype_append(OBJECT_OT_make_links_data); + + WM_operatortype_append(OBJECT_OT_select_random); + WM_operatortype_append(OBJECT_OT_select_all); + WM_operatortype_append(OBJECT_OT_select_same_collection); + WM_operatortype_append(OBJECT_OT_select_by_type); + WM_operatortype_append(OBJECT_OT_select_linked); + WM_operatortype_append(OBJECT_OT_select_grouped); + WM_operatortype_append(OBJECT_OT_select_mirror); + WM_operatortype_append(OBJECT_OT_select_more); + WM_operatortype_append(OBJECT_OT_select_less); + + WM_operatortype_append(COLLECTION_OT_create); + WM_operatortype_append(COLLECTION_OT_objects_remove_all); + WM_operatortype_append(COLLECTION_OT_objects_remove); + WM_operatortype_append(COLLECTION_OT_objects_add_active); + WM_operatortype_append(COLLECTION_OT_objects_remove_active); + + WM_operatortype_append(OBJECT_OT_delete); + WM_operatortype_append(OBJECT_OT_text_add); + WM_operatortype_append(OBJECT_OT_armature_add); + WM_operatortype_append(OBJECT_OT_empty_add); + WM_operatortype_append(OBJECT_OT_lightprobe_add); + WM_operatortype_append(OBJECT_OT_drop_named_image); + WM_operatortype_append(OBJECT_OT_gpencil_add); + WM_operatortype_append(OBJECT_OT_light_add); + WM_operatortype_append(OBJECT_OT_camera_add); + WM_operatortype_append(OBJECT_OT_speaker_add); + WM_operatortype_append(OBJECT_OT_add); + WM_operatortype_append(OBJECT_OT_add_named); + WM_operatortype_append(OBJECT_OT_effector_add); + WM_operatortype_append(OBJECT_OT_collection_instance_add); + WM_operatortype_append(OBJECT_OT_metaball_add); + WM_operatortype_append(OBJECT_OT_duplicates_make_real); + WM_operatortype_append(OBJECT_OT_duplicate); + WM_operatortype_append(OBJECT_OT_join); + WM_operatortype_append(OBJECT_OT_join_shapes); + WM_operatortype_append(OBJECT_OT_convert); + + WM_operatortype_append(OBJECT_OT_modifier_add); + WM_operatortype_append(OBJECT_OT_modifier_remove); + WM_operatortype_append(OBJECT_OT_modifier_move_up); + WM_operatortype_append(OBJECT_OT_modifier_move_down); + WM_operatortype_append(OBJECT_OT_modifier_apply); + WM_operatortype_append(OBJECT_OT_modifier_convert); + WM_operatortype_append(OBJECT_OT_modifier_copy); + WM_operatortype_append(OBJECT_OT_multires_subdivide); + WM_operatortype_append(OBJECT_OT_multires_reshape); + WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete); + WM_operatortype_append(OBJECT_OT_multires_base_apply); + WM_operatortype_append(OBJECT_OT_multires_external_save); + WM_operatortype_append(OBJECT_OT_multires_external_pack); + WM_operatortype_append(OBJECT_OT_skin_root_mark); + WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear); + WM_operatortype_append(OBJECT_OT_skin_radii_equalize); + WM_operatortype_append(OBJECT_OT_skin_armature_create); + + /* grease pencil modifiers */ + WM_operatortype_append(OBJECT_OT_gpencil_modifier_add); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy); + + /* shader fx */ + WM_operatortype_append(OBJECT_OT_shaderfx_add); + WM_operatortype_append(OBJECT_OT_shaderfx_remove); + WM_operatortype_append(OBJECT_OT_shaderfx_move_up); + WM_operatortype_append(OBJECT_OT_shaderfx_move_down); + + WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); + WM_operatortype_append(OBJECT_OT_meshdeform_bind); + WM_operatortype_append(OBJECT_OT_explode_refresh); + WM_operatortype_append(OBJECT_OT_ocean_bake); + + WM_operatortype_append(OBJECT_OT_constraint_add); + WM_operatortype_append(OBJECT_OT_constraint_add_with_targets); + WM_operatortype_append(POSE_OT_constraint_add); + WM_operatortype_append(POSE_OT_constraint_add_with_targets); + WM_operatortype_append(OBJECT_OT_constraints_copy); + WM_operatortype_append(POSE_OT_constraints_copy); + WM_operatortype_append(OBJECT_OT_constraints_clear); + WM_operatortype_append(POSE_OT_constraints_clear); + WM_operatortype_append(POSE_OT_ik_add); + WM_operatortype_append(POSE_OT_ik_clear); + WM_operatortype_append(CONSTRAINT_OT_delete); + WM_operatortype_append(CONSTRAINT_OT_move_up); + WM_operatortype_append(CONSTRAINT_OT_move_down); + WM_operatortype_append(CONSTRAINT_OT_stretchto_reset); + WM_operatortype_append(CONSTRAINT_OT_limitdistance_reset); + WM_operatortype_append(CONSTRAINT_OT_childof_set_inverse); + WM_operatortype_append(CONSTRAINT_OT_childof_clear_inverse); + WM_operatortype_append(CONSTRAINT_OT_objectsolver_set_inverse); + WM_operatortype_append(CONSTRAINT_OT_objectsolver_clear_inverse); + WM_operatortype_append(CONSTRAINT_OT_followpath_path_animate); + + WM_operatortype_append(OBJECT_OT_vertex_group_add); + WM_operatortype_append(OBJECT_OT_vertex_group_remove); + WM_operatortype_append(OBJECT_OT_vertex_group_assign); + WM_operatortype_append(OBJECT_OT_vertex_group_assign_new); + WM_operatortype_append(OBJECT_OT_vertex_group_remove_from); + WM_operatortype_append(OBJECT_OT_vertex_group_select); + WM_operatortype_append(OBJECT_OT_vertex_group_deselect); + WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_linked); + WM_operatortype_append(OBJECT_OT_vertex_group_copy_to_selected); + WM_operatortype_append(OBJECT_OT_vertex_group_copy); + WM_operatortype_append(OBJECT_OT_vertex_group_normalize); + WM_operatortype_append(OBJECT_OT_vertex_group_normalize_all); + WM_operatortype_append(OBJECT_OT_vertex_group_lock); + WM_operatortype_append(OBJECT_OT_vertex_group_fix); + WM_operatortype_append(OBJECT_OT_vertex_group_invert); + WM_operatortype_append(OBJECT_OT_vertex_group_levels); + WM_operatortype_append(OBJECT_OT_vertex_group_smooth); + WM_operatortype_append(OBJECT_OT_vertex_group_clean); + WM_operatortype_append(OBJECT_OT_vertex_group_quantize); + WM_operatortype_append(OBJECT_OT_vertex_group_limit_total); + WM_operatortype_append(OBJECT_OT_vertex_group_mirror); + WM_operatortype_append(OBJECT_OT_vertex_group_set_active); + WM_operatortype_append(OBJECT_OT_vertex_group_sort); + WM_operatortype_append(OBJECT_OT_vertex_group_move); + WM_operatortype_append(OBJECT_OT_vertex_weight_paste); + WM_operatortype_append(OBJECT_OT_vertex_weight_delete); + WM_operatortype_append(OBJECT_OT_vertex_weight_set_active); + WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active_vertex); + WM_operatortype_append(OBJECT_OT_vertex_weight_copy); + + WM_operatortype_append(OBJECT_OT_face_map_add); + WM_operatortype_append(OBJECT_OT_face_map_remove); + WM_operatortype_append(OBJECT_OT_face_map_assign); + WM_operatortype_append(OBJECT_OT_face_map_remove_from); + WM_operatortype_append(OBJECT_OT_face_map_select); + WM_operatortype_append(OBJECT_OT_face_map_deselect); + WM_operatortype_append(OBJECT_OT_face_map_move); + + WM_operatortype_append(TRANSFORM_OT_vertex_warp); + + WM_operatortype_append(OBJECT_OT_move_to_collection); + WM_operatortype_append(OBJECT_OT_link_to_collection); + + WM_operatortype_append(OBJECT_OT_shape_key_add); + WM_operatortype_append(OBJECT_OT_shape_key_remove); + WM_operatortype_append(OBJECT_OT_shape_key_clear); + WM_operatortype_append(OBJECT_OT_shape_key_retime); + WM_operatortype_append(OBJECT_OT_shape_key_mirror); + WM_operatortype_append(OBJECT_OT_shape_key_move); + + WM_operatortype_append(OBJECT_OT_collection_add); + WM_operatortype_append(OBJECT_OT_collection_link); + WM_operatortype_append(OBJECT_OT_collection_remove); + WM_operatortype_append(OBJECT_OT_collection_unlink); + WM_operatortype_append(OBJECT_OT_collection_objects_select); + + WM_operatortype_append(OBJECT_OT_hook_add_selob); + WM_operatortype_append(OBJECT_OT_hook_add_newob); + WM_operatortype_append(OBJECT_OT_hook_remove); + WM_operatortype_append(OBJECT_OT_hook_select); + WM_operatortype_append(OBJECT_OT_hook_assign); + WM_operatortype_append(OBJECT_OT_hook_reset); + WM_operatortype_append(OBJECT_OT_hook_recenter); + + WM_operatortype_append(OBJECT_OT_bake_image); + WM_operatortype_append(OBJECT_OT_bake); + WM_operatortype_append(OBJECT_OT_drop_named_material); + WM_operatortype_append(OBJECT_OT_unlink_data); + WM_operatortype_append(OBJECT_OT_laplaciandeform_bind); + + WM_operatortype_append(TRANSFORM_OT_vertex_random); + + WM_operatortype_append(OBJECT_OT_data_transfer); + WM_operatortype_append(OBJECT_OT_datalayout_transfer); + WM_operatortype_append(OBJECT_OT_surfacedeform_bind); + + WM_operatortype_append(OBJECT_OT_hide_view_clear); + WM_operatortype_append(OBJECT_OT_hide_view_set); + WM_operatortype_append(OBJECT_OT_hide_collection); } void ED_operatormacros_object(void) { - wmOperatorType *ot; - wmOperatorTypeMacro *otmacro; - - ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move", "Duplicate Objects", - "Duplicate selected objects and move them", OPTYPE_UNDO | OPTYPE_REGISTER); - if (ot) { - WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); - } - - /* grr, should be able to pass options on... */ - ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked", "Duplicate Linked", - "Duplicate selected objects and move them", OPTYPE_UNDO | OPTYPE_REGISTER); - if (ot) { - otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); - RNA_boolean_set(otmacro->ptr, "linked", true); - otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); - RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); - } - + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move", + "Duplicate Objects", + "Duplicate selected objects and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); + if (ot) { + WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); + } + + /* grr, should be able to pass options on... */ + ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked", + "Duplicate Linked", + "Duplicate selected objects and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); + if (ot) { + otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate"); + RNA_boolean_set(otmacro->ptr, "linked", true); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); + } } static bool object_mode_poll(bContext *C) { - Object *ob = CTX_data_active_object(C); - return (!ob || ob->mode == OB_MODE_OBJECT); + Object *ob = CTX_data_active_object(C); + return (!ob || ob->mode == OB_MODE_OBJECT); } void ED_keymap_object(wmKeyConfig *keyconf) { - wmKeyMap *keymap; + wmKeyMap *keymap; - /* Objects, Regardless of Mode -------------------------------------------------- */ - keymap = WM_keymap_ensure(keyconf, "Object Non-modal", 0, 0); + /* Objects, Regardless of Mode -------------------------------------------------- */ + keymap = WM_keymap_ensure(keyconf, "Object Non-modal", 0, 0); - /* Object Mode ---------------------------------------------------------------- */ - /* Note: this keymap gets disabled in non-objectmode, */ - keymap = WM_keymap_ensure(keyconf, "Object Mode", 0, 0); - keymap->poll = object_mode_poll; + /* Object Mode ---------------------------------------------------------------- */ + /* Note: this keymap gets disabled in non-objectmode, */ + keymap = WM_keymap_ensure(keyconf, "Object Mode", 0, 0); + keymap->poll = object_mode_poll; } diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c index 7c176318c57..c151f565ecb 100644 --- a/source/blender/editors/object/object_random.c +++ b/source/blender/editors/object/object_random.c @@ -29,7 +29,6 @@ #include "BLI_math.h" #include "BLI_rand.h" - #include "BKE_context.h" #include "BKE_layer.h" @@ -43,127 +42,142 @@ #include "object_intern.h" - /** * Generic randomize vertices function */ -static bool object_rand_transverts( - TransVertStore *tvs, - const float offset, const float uniform, const float normal_factor, - const unsigned int seed) +static bool object_rand_transverts(TransVertStore *tvs, + const float offset, + const float uniform, + const float normal_factor, + const unsigned int seed) { - bool use_normal = (normal_factor != 0.0f); - struct RNG *rng; - TransVert *tv; - int a; + bool use_normal = (normal_factor != 0.0f); + struct RNG *rng; + TransVert *tv; + int a; - if (!tvs || !(tvs->transverts)) { - return false; - } + if (!tvs || !(tvs->transverts)) { + return false; + } - rng = BLI_rng_new(seed); + rng = BLI_rng_new(seed); - tv = tvs->transverts; - for (a = 0; a < tvs->transverts_tot; a++, tv++) { - const float t = max_ff(0.0f, uniform + ((1.0f - uniform) * BLI_rng_get_float(rng))); - float vec[3]; - BLI_rng_get_float_unit_v3(rng, vec); + tv = tvs->transverts; + for (a = 0; a < tvs->transverts_tot; a++, tv++) { + const float t = max_ff(0.0f, uniform + ((1.0f - uniform) * BLI_rng_get_float(rng))); + float vec[3]; + BLI_rng_get_float_unit_v3(rng, vec); - if (use_normal && (tv->flag & TX_VERT_USE_NORMAL)) { - float no[3]; + if (use_normal && (tv->flag & TX_VERT_USE_NORMAL)) { + float no[3]; - /* avoid >90d rotation to align with normal */ - if (dot_v3v3(vec, tv->normal) < 0.0f) { - negate_v3_v3(no, tv->normal); - } - else { - copy_v3_v3(no, tv->normal); - } + /* avoid >90d rotation to align with normal */ + if (dot_v3v3(vec, tv->normal) < 0.0f) { + negate_v3_v3(no, tv->normal); + } + else { + copy_v3_v3(no, tv->normal); + } - interp_v3_v3v3_slerp_safe(vec, vec, no, normal_factor); - } + interp_v3_v3v3_slerp_safe(vec, vec, no, normal_factor); + } - madd_v3_v3fl(tv->loc, vec, offset * t); - } + madd_v3_v3fl(tv->loc, vec, offset * t); + } - BLI_rng_free(rng); + BLI_rng_free(rng); - return true; + return true; } static int object_rand_verts_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob_active = CTX_data_edit_object(C); - const int ob_mode = ob_active->mode; - - const float offset = RNA_float_get(op->ptr, "offset"); - const float uniform = RNA_float_get(op->ptr, "uniform"); - const float normal_factor = RNA_float_get(op->ptr, "normal"); - const unsigned int seed = RNA_int_get(op->ptr, "seed"); - - bool changed_multi = false; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, ob_mode); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - - TransVertStore tvs = { NULL }; - - if (ob_iter) { - int mode = TM_ALL_JOINTS; - - if (normal_factor != 0.0f) { - mode |= TX_VERT_USE_NORMAL; - } - - ED_transverts_create_from_obedit(&tvs, ob_iter, mode); - if (tvs.transverts_tot == 0) { - continue; - } - - int seed_iter = seed; - /* This gives a consistent result regardless of object order. */ - if (ob_index) { - seed_iter += BLI_ghashutil_strhash_p(ob_iter->id.name); - } - - object_rand_transverts(&tvs, offset, uniform, normal_factor, seed_iter); - - ED_transverts_update_obedit(&tvs, ob_iter); - ED_transverts_free(&tvs); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); - changed_multi = true; - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_active = CTX_data_edit_object(C); + const int ob_mode = ob_active->mode; + + const float offset = RNA_float_get(op->ptr, "offset"); + const float uniform = RNA_float_get(op->ptr, "uniform"); + const float normal_factor = RNA_float_get(op->ptr, "normal"); + const unsigned int seed = RNA_int_get(op->ptr, "seed"); + + bool changed_multi = false; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len, ob_mode); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + + TransVertStore tvs = {NULL}; + + if (ob_iter) { + int mode = TM_ALL_JOINTS; + + if (normal_factor != 0.0f) { + mode |= TX_VERT_USE_NORMAL; + } + + ED_transverts_create_from_obedit(&tvs, ob_iter, mode); + if (tvs.transverts_tot == 0) { + continue; + } + + int seed_iter = seed; + /* This gives a consistent result regardless of object order. */ + if (ob_index) { + seed_iter += BLI_ghashutil_strhash_p(ob_iter->id.name); + } + + object_rand_transverts(&tvs, offset, uniform, normal_factor, seed_iter); + + ED_transverts_update_obedit(&tvs, ob_iter); + ED_transverts_free(&tvs); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); + changed_multi = true; + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Randomize"; - ot->description = "Randomize vertices"; - ot->idname = "TRANSFORM_OT_vertex_random"; - - /* api callbacks */ - ot->exec = object_rand_verts_exec; - ot->poll = ED_transverts_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - ot->prop = RNA_def_float_distance( - ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, - "Amount", "Distance to offset", -10.0f, 10.0f); - RNA_def_float_factor(ot->srna, "uniform", 0.0f, 0.0f, 1.0f, "Uniform", - "Increase for uniform offset distance", 0.0f, 1.0f); - RNA_def_float_factor(ot->srna, "normal", 0.0f, 0.0f, 1.0f, "Normal", - "Align offset direction to normals", 0.0f, 1.0f); - RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50); + /* identifiers */ + ot->name = "Randomize"; + ot->description = "Randomize vertices"; + ot->idname = "TRANSFORM_OT_vertex_random"; + + /* api callbacks */ + ot->exec = object_rand_verts_exec; + ot->poll = ED_transverts_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + ot->prop = RNA_def_float_distance( + ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f); + RNA_def_float_factor(ot->srna, + "uniform", + 0.0f, + 0.0f, + 1.0f, + "Uniform", + "Increase for uniform offset distance", + 0.0f, + 1.0f); + RNA_def_float_factor(ot->srna, + "normal", + 0.0f, + 0.0f, + 1.0f, + "Normal", + "Align offset direction to normals", + 0.0f, + 1.0f); + RNA_def_int( + ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50); } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a9b00e7bbdd..3744632be3d 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -116,177 +115,196 @@ static bool vertex_parent_set_poll(bContext *C) { - return ED_operator_editmesh(C) || ED_operator_editsurfcurve(C) || ED_operator_editlattice(C); + return ED_operator_editmesh(C) || ED_operator_editsurfcurve(C) || ED_operator_editlattice(C); } static int vertex_parent_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - BMVert *eve; - BMIter iter; - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - Object *par; - int a, v1 = 0, v2 = 0, v3 = 0, v4 = 0, nr = 1; - - /* we need 1 to 3 selected vertices */ - - if (obedit->type == OB_MESH) { - Mesh *me = obedit->data; - BMEditMesh *em; - - EDBM_mesh_load(bmain, obedit); - EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); - - DEG_id_tag_update(obedit->data, 0); - - em = me->edit_mesh; - - EDBM_mesh_normals_update(em); - BKE_editmesh_tessface_calc(em); - - /* Make sure the evaluated mesh is updated. - * - * Most reliable way is to update the tagged objects, which will ensure - * proper copy-on-write update, but also will make sure all dependent - * objects are also up to date. */ - BKE_scene_graph_update_tagged(depsgraph, bmain); - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - if (v1 == 0) v1 = nr; - else if (v2 == 0) v2 = nr; - else if (v3 == 0) v3 = nr; - else if (v4 == 0) v4 = nr; - else break; - } - nr++; - } - } - else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) { - ListBase *editnurb = object_editcurve_get(obedit); - - nu = editnurb->first; - while (nu) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) { - if (v1 == 0) v1 = nr; - else if (v2 == 0) v2 = nr; - else if (v3 == 0) v3 = nr; - else if (v4 == 0) v4 = nr; - else break; - } - nr++; - bezt++; - } - } - else { - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->f1 & SELECT) { - if (v1 == 0) v1 = nr; - else if (v2 == 0) v2 = nr; - else if (v3 == 0) v3 = nr; - else if (v4 == 0) v4 = nr; - else break; - } - nr++; - bp++; - } - } - nu = nu->next; - } - } - else if (obedit->type == OB_LATTICE) { - Lattice *lt = obedit->data; - - a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; - bp = lt->editlatt->latt->def; - while (a--) { - if (bp->f1 & SELECT) { - if (v1 == 0) v1 = nr; - else if (v2 == 0) v2 = nr; - else if (v3 == 0) v3 = nr; - else if (v4 == 0) v4 = nr; - else break; - } - nr++; - bp++; - } - } - - if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) { - BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to"); - return OPERATOR_CANCELLED; - } - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob != obedit) { - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - par = obedit->parent; - - if (BKE_object_parent_loop_check(par, ob)) { - BKE_report(op->reports, RPT_ERROR, "Loop in parents"); - } - else { - Object workob; - - ob->parent = BASACT(view_layer)->object; - if (v3) { - ob->partype = PARVERT3; - ob->par1 = v1 - 1; - ob->par2 = v2 - 1; - ob->par3 = v3 - 1; - - /* inverse parent matrix */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - } - else { - ob->partype = PARVERT1; - ob->par1 = v1 - 1; - - /* inverse parent matrix */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - } - } - } - } - CTX_DATA_END; - - DEG_relations_tag_update(bmain); - - WM_event_add_notifier(C, NC_OBJECT, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + BMVert *eve; + BMIter iter; + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + Object *par; + int a, v1 = 0, v2 = 0, v3 = 0, v4 = 0, nr = 1; + + /* we need 1 to 3 selected vertices */ + + if (obedit->type == OB_MESH) { + Mesh *me = obedit->data; + BMEditMesh *em; + + EDBM_mesh_load(bmain, obedit); + EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); + + DEG_id_tag_update(obedit->data, 0); + + em = me->edit_mesh; + + EDBM_mesh_normals_update(em); + BKE_editmesh_tessface_calc(em); + + /* Make sure the evaluated mesh is updated. + * + * Most reliable way is to update the tagged objects, which will ensure + * proper copy-on-write update, but also will make sure all dependent + * objects are also up to date. */ + BKE_scene_graph_update_tagged(depsgraph, bmain); + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (v1 == 0) + v1 = nr; + else if (v2 == 0) + v2 = nr; + else if (v3 == 0) + v3 = nr; + else if (v4 == 0) + v4 = nr; + else + break; + } + nr++; + } + } + else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) { + ListBase *editnurb = object_editcurve_get(obedit); + + nu = editnurb->first; + while (nu) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) { + if (v1 == 0) + v1 = nr; + else if (v2 == 0) + v2 = nr; + else if (v3 == 0) + v3 = nr; + else if (v4 == 0) + v4 = nr; + else + break; + } + nr++; + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->f1 & SELECT) { + if (v1 == 0) + v1 = nr; + else if (v2 == 0) + v2 = nr; + else if (v3 == 0) + v3 = nr; + else if (v4 == 0) + v4 = nr; + else + break; + } + nr++; + bp++; + } + } + nu = nu->next; + } + } + else if (obedit->type == OB_LATTICE) { + Lattice *lt = obedit->data; + + a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; + bp = lt->editlatt->latt->def; + while (a--) { + if (bp->f1 & SELECT) { + if (v1 == 0) + v1 = nr; + else if (v2 == 0) + v2 = nr; + else if (v3 == 0) + v3 = nr; + else if (v4 == 0) + v4 = nr; + else + break; + } + nr++; + bp++; + } + } + + if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) { + BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob != obedit) { + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + par = obedit->parent; + + if (BKE_object_parent_loop_check(par, ob)) { + BKE_report(op->reports, RPT_ERROR, "Loop in parents"); + } + else { + Object workob; + + ob->parent = BASACT(view_layer)->object; + if (v3) { + ob->partype = PARVERT3; + ob->par1 = v1 - 1; + ob->par2 = v2 - 1; + ob->par3 = v3 - 1; + + /* inverse parent matrix */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + } + else { + ob->partype = PARVERT1; + ob->par1 = v1 - 1; + + /* inverse parent matrix */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + } + } + } + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + + WM_event_add_notifier(C, NC_OBJECT, NULL); + + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_parent_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Vertex Parent"; - ot->description = "Parent selected objects to the selected vertices"; - ot->idname = "OBJECT_OT_vertex_parent_set"; - - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->poll = vertex_parent_set_poll; - ot->exec = vertex_parent_set_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Make Vertex Parent"; + ot->description = "Parent selected objects to the selected vertices"; + ot->idname = "OBJECT_OT_vertex_parent_set"; + + /* api callbacks */ + ot->invoke = WM_operator_confirm; + ot->poll = vertex_parent_set_poll; + ot->exec = vertex_parent_set_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /********************** Make Proxy Operator *************************/ @@ -294,991 +312,1026 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot) /* set the object to proxify */ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - - /* sanity checks */ - if (!scene || ID_IS_LINKED(scene) || !ob) - return OPERATOR_CANCELLED; - - /* Get object to work on - use a menu if we need to... */ - if (ob->instance_collection && ID_IS_LINKED(ob->instance_collection)) { - /* gives menu with list of objects in group */ - /* proxy_group_objects_menu(C, op, ob, ob->instance_collection); */ - WM_enum_search_invoke(C, op, event); - return OPERATOR_CANCELLED; - } - else if (ID_IS_LINKED(ob)) { - uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); - uiLayout *layout = UI_popup_menu_layout(pup); - - /* create operator menu item with relevant properties filled in */ - PointerRNA opptr_dummy; - uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, - WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); - - /* present the menu and be done... */ - UI_popup_menu_end(C, pup); - - /* this invoke just calls another instance of this operator... */ - return OPERATOR_INTERFACE; - } - else { - /* error.. cannot continue */ - BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); - return OPERATOR_CANCELLED; - } - + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + + /* sanity checks */ + if (!scene || ID_IS_LINKED(scene) || !ob) + return OPERATOR_CANCELLED; + + /* Get object to work on - use a menu if we need to... */ + if (ob->instance_collection && ID_IS_LINKED(ob->instance_collection)) { + /* gives menu with list of objects in group */ + /* proxy_group_objects_menu(C, op, ob, ob->instance_collection); */ + WM_enum_search_invoke(C, op, event); + return OPERATOR_CANCELLED; + } + else if (ID_IS_LINKED(ob)) { + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* create operator menu item with relevant properties filled in */ + PointerRNA opptr_dummy; + uiItemFullO_ptr( + layout, op->type, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); + + /* present the menu and be done... */ + UI_popup_menu_end(C, pup); + + /* this invoke just calls another instance of this operator... */ + return OPERATOR_INTERFACE; + } + else { + /* error.. cannot continue */ + BKE_report( + op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); + return OPERATOR_CANCELLED; + } } static int make_proxy_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob, *gob = ED_object_active_context(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - if (gob->instance_collection != NULL) { - const ListBase instance_collection_objects = BKE_collection_object_cache_get(gob->instance_collection); - Base *base = BLI_findlink(&instance_collection_objects, RNA_enum_get(op->ptr, "object")); - ob = base->object; - } - else { - ob = gob; - } - - if (ob) { - Object *newob; - char name[MAX_ID_NAME + 4]; - - BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2); - - /* Add new object for the proxy */ - newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob); - - /* set layers OK */ - BKE_object_make_proxy(bmain, newob, ob, gob); - - /* Set back pointer immediately so dependency graph knows that this is - * is a proxy and will act accordingly. Otherwise correctness of graph - * will depend on order of bases. - * - * TODO(sergey): We really need to get rid of this bi-directional links - * in proxies with something like static overrides. - */ - newob->proxy->proxy_from = newob; - - /* depsgraph flushes are needed for the new data */ - DEG_relations_tag_update(bmain); - DEG_id_tag_update(&newob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob); - } - else { - BKE_report(op->reports, RPT_ERROR, "No object to make proxy for"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Object *ob, *gob = ED_object_active_context(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + if (gob->instance_collection != NULL) { + const ListBase instance_collection_objects = BKE_collection_object_cache_get( + gob->instance_collection); + Base *base = BLI_findlink(&instance_collection_objects, RNA_enum_get(op->ptr, "object")); + ob = base->object; + } + else { + ob = gob; + } + + if (ob) { + Object *newob; + char name[MAX_ID_NAME + 4]; + + BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2); + + /* Add new object for the proxy */ + newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob); + + /* set layers OK */ + BKE_object_make_proxy(bmain, newob, ob, gob); + + /* Set back pointer immediately so dependency graph knows that this is + * is a proxy and will act accordingly. Otherwise correctness of graph + * will depend on order of bases. + * + * TODO(sergey): We really need to get rid of this bi-directional links + * in proxies with something like static overrides. + */ + newob->proxy->proxy_from = newob; + + /* depsgraph flushes are needed for the new data */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&newob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob); + } + else { + BKE_report(op->reports, RPT_ERROR, "No object to make proxy for"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } /* Generic itemf's for operators that take library args */ -static const EnumPropertyItem *proxy_collection_object_itemf( - bContext *C, PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *proxy_collection_object_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - EnumPropertyItem item_tmp = {0}, *item = NULL; - int totitem = 0; - int i = 0; - Object *ob = ED_object_active_context(C); - - if (!ob || !ob->instance_collection) - return DummyRNA_DEFAULT_items; - - /* find the object to affect */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->instance_collection, object) - { - item_tmp.identifier = item_tmp.name = object->id.name + 2; - item_tmp.value = i++; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + EnumPropertyItem item_tmp = {0}, *item = NULL; + int totitem = 0; + int i = 0; + Object *ob = ED_object_active_context(C); + + if (!ob || !ob->instance_collection) + return DummyRNA_DEFAULT_items; + + /* find the object to affect */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (ob->instance_collection, object) { + item_tmp.identifier = item_tmp.name = object->id.name + 2; + item_tmp.value = i++; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } void OBJECT_OT_proxy_make(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Make Proxy"; - ot->idname = "OBJECT_OT_proxy_make"; - ot->description = "Add empty object to become local replacement data of a library-linked object"; - - /* callbacks */ - ot->invoke = make_proxy_invoke; - ot->exec = make_proxy_exec; - ot->poll = ED_operator_object_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - /* XXX, relies on hard coded ID at the moment */ - prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/collection object to make a proxy for"); - RNA_def_enum_funcs(prop, proxy_collection_object_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Make Proxy"; + ot->idname = "OBJECT_OT_proxy_make"; + ot->description = "Add empty object to become local replacement data of a library-linked object"; + + /* callbacks */ + ot->invoke = make_proxy_invoke; + ot->exec = make_proxy_exec; + ot->poll = ED_operator_object_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + /* XXX, relies on hard coded ID at the moment */ + prop = RNA_def_enum(ot->srna, + "object", + DummyRNA_DEFAULT_items, + 0, + "Proxy Object", + "Name of lib-linked/collection object to make a proxy for"); + RNA_def_enum_funcs(prop, proxy_collection_object_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } /********************** Clear Parent Operator ******************* */ typedef enum eObClearParentTypes { - CLEAR_PARENT_ALL = 0, - CLEAR_PARENT_KEEP_TRANSFORM, - CLEAR_PARENT_INVERSE, + CLEAR_PARENT_ALL = 0, + CLEAR_PARENT_KEEP_TRANSFORM, + CLEAR_PARENT_INVERSE, } eObClearParentTypes; EnumPropertyItem prop_clear_parent_types[] = { - {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", - "Completely clear the parenting relationship, including involved modifiers if any"}, - {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", - "As 'Clear Parent', but keep the current visual transformations of the object"}, - {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", - "Reset the transform corrections applied to the parenting relationship, does not remove parenting itself"}, - {0, NULL, 0, NULL, NULL}, + {CLEAR_PARENT_ALL, + "CLEAR", + 0, + "Clear Parent", + "Completely clear the parenting relationship, including involved modifiers if any"}, + {CLEAR_PARENT_KEEP_TRANSFORM, + "CLEAR_KEEP_TRANSFORM", + 0, + "Clear and Keep Transformation", + "As 'Clear Parent', but keep the current visual transformations of the object"}, + {CLEAR_PARENT_INVERSE, + "CLEAR_INVERSE", + 0, + "Clear Parent Inverse", + "Reset the transform corrections applied to the parenting relationship, does not remove " + "parenting itself"}, + {0, NULL, 0, NULL, NULL}, }; /* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par) { - if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { - ModifierData *md, *mdn; - - /* assume that we only need to remove the first instance of matching deform modifier here */ - for (md = ob->modifiers.first; md; md = mdn) { - bool free = false; - - mdn = md->next; - - /* need to match types (modifier + parent) and references */ - if ((md->type == eModifierType_Armature) && (par->type == OB_ARMATURE)) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->object == par) { - free = true; - } - } - else if ((md->type == eModifierType_Lattice) && (par->type == OB_LATTICE)) { - LatticeModifierData *lmd = (LatticeModifierData *)md; - if (lmd->object == par) { - free = true; - } - } - else if ((md->type == eModifierType_Curve) && (par->type == OB_CURVE)) { - CurveModifierData *cmd = (CurveModifierData *)md; - if (cmd->object == par) { - free = true; - } - } - - /* free modifier if match */ - if (free) { - BLI_remlink(&ob->modifiers, md); - modifier_free(md); - } - } - } + if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { + ModifierData *md, *mdn; + + /* assume that we only need to remove the first instance of matching deform modifier here */ + for (md = ob->modifiers.first; md; md = mdn) { + bool free = false; + + mdn = md->next; + + /* need to match types (modifier + parent) and references */ + if ((md->type == eModifierType_Armature) && (par->type == OB_ARMATURE)) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object == par) { + free = true; + } + } + else if ((md->type == eModifierType_Lattice) && (par->type == OB_LATTICE)) { + LatticeModifierData *lmd = (LatticeModifierData *)md; + if (lmd->object == par) { + free = true; + } + } + else if ((md->type == eModifierType_Curve) && (par->type == OB_CURVE)) { + CurveModifierData *cmd = (CurveModifierData *)md; + if (cmd->object == par) { + free = true; + } + } + + /* free modifier if match */ + if (free) { + BLI_remlink(&ob->modifiers, md); + modifier_free(md); + } + } + } } void ED_object_parent_clear(Object *ob, const int type) { - if (ob->parent == NULL) - return; - - switch (type) { - case CLEAR_PARENT_ALL: - { - /* for deformers, remove corresponding modifiers to prevent - * a large number of modifiers building up */ - object_remove_parent_deform_modifiers(ob, ob->parent); - - /* clear parenting relationship completely */ - ob->parent = NULL; - break; - } - case CLEAR_PARENT_KEEP_TRANSFORM: - { - /* remove parent, and apply the parented transform - * result as object's local transforms */ - ob->parent = NULL; - BKE_object_apply_mat4(ob, ob->obmat, true, false); - break; - } - case CLEAR_PARENT_INVERSE: - { - /* object stays parented, but the parent inverse - * (i.e. offset from parent to retain binding state) - * is cleared. In other words: nothing to do here! */ - break; - } - } - - /* Always clear parentinv matrix for sake of consistency, see T41950. */ - unit_m4(ob->parentinv); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + if (ob->parent == NULL) + return; + + switch (type) { + case CLEAR_PARENT_ALL: { + /* for deformers, remove corresponding modifiers to prevent + * a large number of modifiers building up */ + object_remove_parent_deform_modifiers(ob, ob->parent); + + /* clear parenting relationship completely */ + ob->parent = NULL; + break; + } + case CLEAR_PARENT_KEEP_TRANSFORM: { + /* remove parent, and apply the parented transform + * result as object's local transforms */ + ob->parent = NULL; + BKE_object_apply_mat4(ob, ob->obmat, true, false); + break; + } + case CLEAR_PARENT_INVERSE: { + /* object stays parented, but the parent inverse + * (i.e. offset from parent to retain binding state) + * is cleared. In other words: nothing to do here! */ + break; + } + } + + /* Always clear parentinv matrix for sake of consistency, see T41950. */ + unit_m4(ob->parentinv); + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); } /* note, poll should check for editable scene */ static int parent_clear_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - const int type = RNA_enum_get(op->ptr, "type"); - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - ED_object_parent_clear(ob, type); - } - CTX_DATA_END; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + const int type = RNA_enum_get(op->ptr, "type"); + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + ED_object_parent_clear(ob, type); + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + return OPERATOR_FINISHED; } void OBJECT_OT_parent_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Parent"; - ot->description = "Clear the object's parenting"; - ot->idname = "OBJECT_OT_parent_clear"; + /* identifiers */ + ot->name = "Clear Parent"; + ot->description = "Clear the object's parenting"; + ot->idname = "OBJECT_OT_parent_clear"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = parent_clear_exec; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = parent_clear_exec; - ot->poll = ED_operator_object_active_editable; + ot->poll = ED_operator_object_active_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, CLEAR_PARENT_ALL, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, CLEAR_PARENT_ALL, "Type", ""); } /* ******************** Make Parent Operator *********************** */ void ED_object_parent(Object *ob, Object *par, const int type, const char *substr) { - /* Always clear parentinv matrix for sake of consistency, see T41950. */ - unit_m4(ob->parentinv); + /* Always clear parentinv matrix for sake of consistency, see T41950. */ + unit_m4(ob->parentinv); - if (!par || BKE_object_parent_loop_check(par, ob)) { - ob->parent = NULL; - ob->partype = PAROBJECT; - ob->parsubstr[0] = 0; - return; - } + if (!par || BKE_object_parent_loop_check(par, ob)) { + ob->parent = NULL; + ob->partype = PAROBJECT; + ob->parsubstr[0] = 0; + return; + } - /* Other partypes are deprecated, do not use here! */ - BLI_assert(ELEM(type & PARTYPE, PAROBJECT, PARSKEL, PARVERT1, PARVERT3, PARBONE)); + /* Other partypes are deprecated, do not use here! */ + BLI_assert(ELEM(type & PARTYPE, PAROBJECT, PARSKEL, PARVERT1, PARVERT3, PARBONE)); - /* this could use some more checks */ + /* this could use some more checks */ - ob->parent = par; - ob->partype &= ~PARTYPE; - ob->partype |= type; - BLI_strncpy(ob->parsubstr, substr, sizeof(ob->parsubstr)); + ob->parent = par; + ob->partype &= ~PARTYPE; + ob->partype |= type; + BLI_strncpy(ob->parsubstr, substr, sizeof(ob->parsubstr)); } /* Operator Property */ EnumPropertyItem prop_make_parent_types[] = { - {PAR_OBJECT, "OBJECT", 0, "Object", ""}, - {PAR_ARMATURE, "ARMATURE", 0, "Armature Deform", ""}, - {PAR_ARMATURE_NAME, "ARMATURE_NAME", 0, " With Empty Groups", ""}, - {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, " With Automatic Weights", ""}, - {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, " With Envelope Weights", ""}, - {PAR_BONE, "BONE", 0, "Bone", ""}, - {PAR_BONE_RELATIVE, "BONE_RELATIVE", 0, "Bone Relative", ""}, - {PAR_CURVE, "CURVE", 0, "Curve Deform", ""}, - {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""}, - {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""}, - {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""}, - {PAR_VERTEX, "VERTEX", 0, "Vertex", ""}, - {PAR_VERTEX_TRI, "VERTEX_TRI", 0, "Vertex (Triangle)", ""}, - {0, NULL, 0, NULL, NULL}, + {PAR_OBJECT, "OBJECT", 0, "Object", ""}, + {PAR_ARMATURE, "ARMATURE", 0, "Armature Deform", ""}, + {PAR_ARMATURE_NAME, "ARMATURE_NAME", 0, " With Empty Groups", ""}, + {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, " With Automatic Weights", ""}, + {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, " With Envelope Weights", ""}, + {PAR_BONE, "BONE", 0, "Bone", ""}, + {PAR_BONE_RELATIVE, "BONE_RELATIVE", 0, "Bone Relative", ""}, + {PAR_CURVE, "CURVE", 0, "Curve Deform", ""}, + {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""}, + {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""}, + {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""}, + {PAR_VERTEX, "VERTEX", 0, "Vertex", ""}, + {PAR_VERTEX_TRI, "VERTEX_TRI", 0, "Vertex (Triangle)", ""}, + {0, NULL, 0, NULL, NULL}, }; -bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, Object *ob, Object *par, - int partype, const bool xmirror, const bool keep_transform, const int vert_par[3]) +bool ED_object_parent_set(ReportList *reports, + const bContext *C, + Scene *scene, + Object *ob, + Object *par, + int partype, + const bool xmirror, + const bool keep_transform, + const int vert_par[3]) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - bPoseChannel *pchan = NULL; - bPoseChannel *pchan_eval = NULL; - const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); - Object *parent_eval = DEG_get_evaluated_object(depsgraph, par); - - DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - /* preconditions */ - if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) { - if (par->type != OB_CURVE) - return 0; - else { - Curve *cu = par->data; - Curve *cu_eval = parent_eval->data; - if ((cu->flag & CU_PATH) == 0) { - cu->flag |= CU_PATH | CU_FOLLOW; - cu_eval->flag |= CU_PATH | CU_FOLLOW; - /* force creation of path data */ - BKE_displist_make_curveTypes(depsgraph, scene, par, false, false, NULL); - } - else { - cu->flag |= CU_FOLLOW; - cu_eval->flag |= CU_FOLLOW; - } - - /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ - if (partype == PAR_FOLLOW) { - /* get or create F-Curve */ - bAction *act = verify_adt_action(bmain, &cu->id, 1); - FCurve *fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1); - - /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */ - if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); - } - - /* fall back on regular parenting now (for follow only) */ - if (partype == PAR_FOLLOW) - partype = PAR_OBJECT; - } - } - else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) { - pchan = BKE_pose_channel_active(par); - pchan_eval = BKE_pose_channel_active(parent_eval); - - if (pchan == NULL) { - BKE_report(reports, RPT_ERROR, "No active bone"); - return false; - } - } - - if (ob != par) { - if (BKE_object_parent_loop_check(par, ob)) { - BKE_report(reports, RPT_ERROR, "Loop in parents"); - return false; - } - else { - Object workob; - - /* apply transformation of previous parenting */ - if (keep_transform) { - /* was removed because of bug [#23577], - * but this can be handy in some cases too [#32616], so make optional */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); - } - - /* set the parent (except for follow-path constraint option) */ - if (partype != PAR_PATH_CONST) { - ob->parent = par; - /* Always clear parentinv matrix for sake of consistency, see T41950. */ - unit_m4(ob->parentinv); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - - /* handle types */ - if (pchan) - BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr)); - else - ob->parsubstr[0] = 0; - - if (partype == PAR_PATH_CONST) { - /* don't do anything here, since this is not technically "parenting" */ - } - else if (ELEM(partype, PAR_CURVE, PAR_LATTICE) || (pararm)) { - /* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created - * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers - */ - ob->partype = PAROBJECT; /* note, dna define, not operator property */ - /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */ - - /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses - * - We need to ensure that the modifier we're adding doesn't already exist, so we check this by - * assuming that the parent is selected too... - */ - /* XXX currently this should only happen for meshes, curves, surfaces, - * and lattices - this stuff isn't available for metas yet */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { - ModifierData *md; - - switch (partype) { - case PAR_CURVE: /* curve deform */ - if (modifiers_isDeformedByCurve(ob) != par) { - md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve); - if (md) { - ((CurveModifierData *)md)->object = par; - } - if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { - DEG_id_tag_update(&par->id, ID_RECALC_GEOMETRY); - } - } - break; - case PAR_LATTICE: /* lattice deform */ - if (modifiers_isDeformedByLattice(ob) != par) { - md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Lattice); - if (md) { - ((LatticeModifierData *)md)->object = par; - } - } - break; - default: /* armature deform */ - if (modifiers_isDeformedByArmature(ob) != par) { - md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Armature); - if (md) { - ((ArmatureModifierData *)md)->object = par; - } - } - break; - } - } - } - else if (partype == PAR_BONE) { - ob->partype = PARBONE; /* note, dna define, not operator property */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_RELATIVE_PARENTING; - pchan_eval->bone->flag &= ~BONE_RELATIVE_PARENTING; - } - } - else if (partype == PAR_BONE_RELATIVE) { - ob->partype = PARBONE; /* note, dna define, not operator property */ - if (pchan->bone) { - pchan->bone->flag |= BONE_RELATIVE_PARENTING; - pchan_eval->bone->flag |= BONE_RELATIVE_PARENTING; - } - } - else if (partype == PAR_VERTEX) { - ob->partype = PARVERT1; - ob->par1 = vert_par[0]; - } - else if (partype == PAR_VERTEX_TRI) { - ob->partype = PARVERT3; - copy_v3_v3_int(&ob->par1, vert_par); - } - else { - ob->partype = PAROBJECT; /* note, dna define, not operator property */ - } - - /* constraint */ - if (partype == PAR_PATH_CONST) { - bConstraint *con; - bFollowPathConstraint *data; - float cmat[4][4], vec[3]; - - con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); - - data = con->data; - data->tar = par; - - BKE_constraint_target_matrix_get(depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); - sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); - - copy_v3_v3(ob->loc, vec); - } - else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) { - if (partype == PAR_ARMATURE_NAME) { - ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false); - } - else if (partype == PAR_ARMATURE_ENVELOPE) { - ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); - } - else if (partype == PAR_ARMATURE_AUTO) { - WM_cursor_wait(1); - ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror); - WM_cursor_wait(0); - } - /* get corrected inverse */ - ob->partype = PAROBJECT; - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - - invert_m4_m4(ob->parentinv, workob.obmat); - } - else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { - if (partype == PAR_ARMATURE_NAME) { - ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); - } - else if ((partype == PAR_ARMATURE_AUTO) || - (partype == PAR_ARMATURE_ENVELOPE)) - { - WM_cursor_wait(1); - ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); - WM_cursor_wait(0); - } - /* get corrected inverse */ - ob->partype = PAROBJECT; - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - - invert_m4_m4(ob->parentinv, workob.obmat); - } - else { - /* calculate inverse parent matrix */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - } - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - } - } - - return true; + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + bPoseChannel *pchan = NULL; + bPoseChannel *pchan_eval = NULL; + const bool pararm = ELEM( + partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); + Object *parent_eval = DEG_get_evaluated_object(depsgraph, par); + + DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + /* preconditions */ + if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) { + if (par->type != OB_CURVE) + return 0; + else { + Curve *cu = par->data; + Curve *cu_eval = parent_eval->data; + if ((cu->flag & CU_PATH) == 0) { + cu->flag |= CU_PATH | CU_FOLLOW; + cu_eval->flag |= CU_PATH | CU_FOLLOW; + /* force creation of path data */ + BKE_displist_make_curveTypes(depsgraph, scene, par, false, false, NULL); + } + else { + cu->flag |= CU_FOLLOW; + cu_eval->flag |= CU_FOLLOW; + } + + /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ + if (partype == PAR_FOLLOW) { + /* get or create F-Curve */ + bAction *act = verify_adt_action(bmain, &cu->id, 1); + FCurve *fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1); + + /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */ + if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); + } + + /* fall back on regular parenting now (for follow only) */ + if (partype == PAR_FOLLOW) + partype = PAR_OBJECT; + } + } + else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) { + pchan = BKE_pose_channel_active(par); + pchan_eval = BKE_pose_channel_active(parent_eval); + + if (pchan == NULL) { + BKE_report(reports, RPT_ERROR, "No active bone"); + return false; + } + } + + if (ob != par) { + if (BKE_object_parent_loop_check(par, ob)) { + BKE_report(reports, RPT_ERROR, "Loop in parents"); + return false; + } + else { + Object workob; + + /* apply transformation of previous parenting */ + if (keep_transform) { + /* was removed because of bug [#23577], + * but this can be handy in some cases too [#32616], so make optional */ + BKE_object_apply_mat4(ob, ob->obmat, false, false); + } + + /* set the parent (except for follow-path constraint option) */ + if (partype != PAR_PATH_CONST) { + ob->parent = par; + /* Always clear parentinv matrix for sake of consistency, see T41950. */ + unit_m4(ob->parentinv); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + + /* handle types */ + if (pchan) + BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr)); + else + ob->parsubstr[0] = 0; + + if (partype == PAR_PATH_CONST) { + /* don't do anything here, since this is not technically "parenting" */ + } + else if (ELEM(partype, PAR_CURVE, PAR_LATTICE) || (pararm)) { + /* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created + * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers + */ + ob->partype = PAROBJECT; /* note, dna define, not operator property */ + /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */ + + /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses + * - We need to ensure that the modifier we're adding doesn't already exist, so we check this by + * assuming that the parent is selected too... + */ + /* XXX currently this should only happen for meshes, curves, surfaces, + * and lattices - this stuff isn't available for metas yet */ + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + ModifierData *md; + + switch (partype) { + case PAR_CURVE: /* curve deform */ + if (modifiers_isDeformedByCurve(ob) != par) { + md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve); + if (md) { + ((CurveModifierData *)md)->object = par; + } + if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { + DEG_id_tag_update(&par->id, ID_RECALC_GEOMETRY); + } + } + break; + case PAR_LATTICE: /* lattice deform */ + if (modifiers_isDeformedByLattice(ob) != par) { + md = ED_object_modifier_add( + reports, bmain, scene, ob, NULL, eModifierType_Lattice); + if (md) { + ((LatticeModifierData *)md)->object = par; + } + } + break; + default: /* armature deform */ + if (modifiers_isDeformedByArmature(ob) != par) { + md = ED_object_modifier_add( + reports, bmain, scene, ob, NULL, eModifierType_Armature); + if (md) { + ((ArmatureModifierData *)md)->object = par; + } + } + break; + } + } + } + else if (partype == PAR_BONE) { + ob->partype = PARBONE; /* note, dna define, not operator property */ + if (pchan->bone) { + pchan->bone->flag &= ~BONE_RELATIVE_PARENTING; + pchan_eval->bone->flag &= ~BONE_RELATIVE_PARENTING; + } + } + else if (partype == PAR_BONE_RELATIVE) { + ob->partype = PARBONE; /* note, dna define, not operator property */ + if (pchan->bone) { + pchan->bone->flag |= BONE_RELATIVE_PARENTING; + pchan_eval->bone->flag |= BONE_RELATIVE_PARENTING; + } + } + else if (partype == PAR_VERTEX) { + ob->partype = PARVERT1; + ob->par1 = vert_par[0]; + } + else if (partype == PAR_VERTEX_TRI) { + ob->partype = PARVERT3; + copy_v3_v3_int(&ob->par1, vert_par); + } + else { + ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } + + /* constraint */ + if (partype == PAR_PATH_CONST) { + bConstraint *con; + bFollowPathConstraint *data; + float cmat[4][4], vec[3]; + + con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); + + data = con->data; + data->tar = par; + + BKE_constraint_target_matrix_get( + depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); + + copy_v3_v3(ob->loc, vec); + } + else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) { + if (partype == PAR_ARMATURE_NAME) { + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false); + } + else if (partype == PAR_ARMATURE_ENVELOPE) { + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); + } + else if (partype == PAR_ARMATURE_AUTO) { + WM_cursor_wait(1); + ED_object_vgroup_calc_from_armature( + reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror); + WM_cursor_wait(0); + } + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + + invert_m4_m4(ob->parentinv, workob.obmat); + } + else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { + if (partype == PAR_ARMATURE_NAME) { + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); + } + else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) { + WM_cursor_wait(1); + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); + WM_cursor_wait(0); + } + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + + invert_m4_m4(ob->parentinv, workob.obmat); + } + else { + /* calculate inverse parent matrix */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + } + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } + } + + return true; } - - static void parent_set_vert_find(KDTree_3d *tree, Object *child, int vert_par[3], bool is_tri) { - const float *co_find = child->obmat[3]; - if (is_tri) { - KDTreeNearest_3d nearest[3]; - int tot; - - tot = BLI_kdtree_3d_find_nearest_n(tree, co_find, nearest, 3); - BLI_assert(tot == 3); - UNUSED_VARS(tot); - - vert_par[0] = nearest[0].index; - vert_par[1] = nearest[1].index; - vert_par[2] = nearest[2].index; - - BLI_assert(min_iii(UNPACK3(vert_par)) >= 0); - } - else { - vert_par[0] = BLI_kdtree_3d_find_nearest(tree, co_find, NULL); - BLI_assert(vert_par[0] >= 0); - vert_par[1] = 0; - vert_par[2] = 0; - } + const float *co_find = child->obmat[3]; + if (is_tri) { + KDTreeNearest_3d nearest[3]; + int tot; + + tot = BLI_kdtree_3d_find_nearest_n(tree, co_find, nearest, 3); + BLI_assert(tot == 3); + UNUSED_VARS(tot); + + vert_par[0] = nearest[0].index; + vert_par[1] = nearest[1].index; + vert_par[2] = nearest[2].index; + + BLI_assert(min_iii(UNPACK3(vert_par)) >= 0); + } + else { + vert_par[0] = BLI_kdtree_3d_find_nearest(tree, co_find, NULL); + BLI_assert(vert_par[0] >= 0); + vert_par[1] = 0; + vert_par[2] = 0; + } } static int parent_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *par = ED_object_active_context(C); - int partype = RNA_enum_get(op->ptr, "type"); - const bool xmirror = RNA_boolean_get(op->ptr, "xmirror"); - const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); - bool ok = true; - - /* vertex parent (kdtree) */ - const bool is_vert_par = ELEM(partype, PAR_VERTEX, PAR_VERTEX_TRI); - const bool is_tri = partype == PAR_VERTEX_TRI; - int tree_tot; - struct KDTree_3d *tree = NULL; - int vert_par[3] = {0, 0, 0}; - const int *vert_par_p = is_vert_par ? vert_par : NULL; - - - if (is_vert_par) { - tree = BKE_object_as_kdtree(par, &tree_tot); - BLI_assert(tree != NULL); - - if (tree_tot < (is_tri ? 3 : 1)) { - BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent"); - ok = false; - } - } - - if (ok) { - /* Non vertex-parent */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (is_vert_par) { - parent_set_vert_find(tree, ob, vert_par, is_tri); - } - - if (!ED_object_parent_set(op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { - ok = false; - break; - } - } - CTX_DATA_END; - } - - if (is_vert_par) { - BLI_kdtree_3d_free(tree); - } - - if (!ok) - return OPERATOR_CANCELLED; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *par = ED_object_active_context(C); + int partype = RNA_enum_get(op->ptr, "type"); + const bool xmirror = RNA_boolean_get(op->ptr, "xmirror"); + const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); + bool ok = true; + + /* vertex parent (kdtree) */ + const bool is_vert_par = ELEM(partype, PAR_VERTEX, PAR_VERTEX_TRI); + const bool is_tri = partype == PAR_VERTEX_TRI; + int tree_tot; + struct KDTree_3d *tree = NULL; + int vert_par[3] = {0, 0, 0}; + const int *vert_par_p = is_vert_par ? vert_par : NULL; + + if (is_vert_par) { + tree = BKE_object_as_kdtree(par, &tree_tot); + BLI_assert(tree != NULL); + + if (tree_tot < (is_tri ? 3 : 1)) { + BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent"); + ok = false; + } + } + + if (ok) { + /* Non vertex-parent */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (is_vert_par) { + parent_set_vert_find(tree, ob, vert_par, is_tri); + } + + if (!ED_object_parent_set( + op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { + ok = false; + break; + } + } + CTX_DATA_END; + } + + if (is_vert_par) { + BLI_kdtree_3d_free(tree); + } + + if (!ok) + return OPERATOR_CANCELLED; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + + return OPERATOR_FINISHED; } - static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - Object *parent = ED_object_active_context(C); - uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); + Object *parent = ED_object_active_context(C); + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); - wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_parent_set", true); - PointerRNA opptr; + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_parent_set", true); + PointerRNA opptr; #if 0 - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_OBJECT); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_OBJECT); #else - uiItemFullO_ptr(layout, ot, IFACE_("Object"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "type", PAR_OBJECT); - RNA_boolean_set(&opptr, "keep_transform", false); - - uiItemFullO_ptr( - layout, ot, IFACE_("Object (Keep Transform)"), ICON_NONE, - NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); - RNA_enum_set(&opptr, "type", PAR_OBJECT); - RNA_boolean_set(&opptr, "keep_transform", true); + uiItemFullO_ptr(layout, ot, IFACE_("Object"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); + RNA_enum_set(&opptr, "type", PAR_OBJECT); + RNA_boolean_set(&opptr, "keep_transform", false); + + uiItemFullO_ptr(layout, + ot, + IFACE_("Object (Keep Transform)"), + ICON_NONE, + NULL, + WM_OP_EXEC_DEFAULT, + 0, + &opptr); + RNA_enum_set(&opptr, "type", PAR_OBJECT); + RNA_boolean_set(&opptr, "keep_transform", true); #endif - uiItemO(layout, IFACE_("Object (Without Inverse)"), ICON_NONE, "OBJECT_OT_parent_no_inverse_set"); - - struct { - bool mesh, gpencil; - } has_children_of_type = { 0 }; - - CTX_DATA_BEGIN (C, Object *, child, selected_editable_objects) - { - if (child == parent) { - continue; - } - if (child->type == OB_MESH) { - has_children_of_type.mesh = true; - } - if (child->type == OB_GPENCIL) { - has_children_of_type.gpencil = true; - } - } - CTX_DATA_END; - - if (parent->type == OB_ARMATURE) { - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_NAME); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_ENVELOPE); - if (has_children_of_type.mesh || has_children_of_type.gpencil) { - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_AUTO); - } - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE_RELATIVE); - } - else if (parent->type == OB_CURVE) { - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_CURVE); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_FOLLOW); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_PATH_CONST); - } - else if (parent->type == OB_LATTICE) { - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE); - } - - /* vertex parenting */ - if (OB_TYPE_SUPPORT_PARVERT(parent->type)) { - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX); - uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX_TRI); - } - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; + uiItemO( + layout, IFACE_("Object (Without Inverse)"), ICON_NONE, "OBJECT_OT_parent_no_inverse_set"); + + struct { + bool mesh, gpencil; + } has_children_of_type = {0}; + + CTX_DATA_BEGIN (C, Object *, child, selected_editable_objects) { + if (child == parent) { + continue; + } + if (child->type == OB_MESH) { + has_children_of_type.mesh = true; + } + if (child->type == OB_GPENCIL) { + has_children_of_type.gpencil = true; + } + } + CTX_DATA_END; + + if (parent->type == OB_ARMATURE) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_NAME); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_ENVELOPE); + if (has_children_of_type.mesh || has_children_of_type.gpencil) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_ARMATURE_AUTO); + } + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_BONE_RELATIVE); + } + else if (parent->type == OB_CURVE) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_CURVE); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_FOLLOW); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_PATH_CONST); + } + else if (parent->type == OB_LATTICE) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE); + } + + /* vertex parenting */ + if (OB_TYPE_SUPPORT_PARVERT(parent->type)) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX_TRI); + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; } -static bool parent_set_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +static bool parent_set_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { - const char *prop_id = RNA_property_identifier(prop); - - /* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */ - if (STREQ(prop_id, "xmirror")) { - const int type = RNA_enum_get(op->ptr, "type"); - if (ELEM(type, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO)) - return true; - else - return false; - } - - return true; + const char *prop_id = RNA_property_identifier(prop); + + /* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */ + if (STREQ(prop_id, "xmirror")) { + const int type = RNA_enum_get(op->ptr, "type"); + if (ELEM(type, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO)) + return true; + else + return false; + } + + return true; } void OBJECT_OT_parent_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Parent"; - ot->description = "Set the object's parenting"; - ot->idname = "OBJECT_OT_parent_set"; - - /* api callbacks */ - ot->invoke = parent_set_invoke; - ot->exec = parent_set_exec; - ot->poll = ED_operator_object_active; - ot->poll_property = parent_set_poll_property; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); - RNA_def_boolean(ot->srna, "xmirror", false, "X Mirror", - "Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation"); - RNA_def_boolean(ot->srna, "keep_transform", false, "Keep Transform", - "Apply transformation before parenting"); + /* identifiers */ + ot->name = "Make Parent"; + ot->description = "Set the object's parenting"; + ot->idname = "OBJECT_OT_parent_set"; + + /* api callbacks */ + ot->invoke = parent_set_invoke; + ot->exec = parent_set_exec; + ot->poll = ED_operator_object_active; + ot->poll_property = parent_set_poll_property; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); + RNA_def_boolean( + ot->srna, + "xmirror", + false, + "X Mirror", + "Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation"); + RNA_def_boolean(ot->srna, + "keep_transform", + false, + "Keep Transform", + "Apply transformation before parenting"); } /* ************ Make Parent Without Inverse Operator ******************* */ static int parent_noinv_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *par = ED_object_active_context(C); - - DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM); - - /* context iterator */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob != par) { - if (BKE_object_parent_loop_check(par, ob)) { - BKE_report(op->reports, RPT_ERROR, "Loop in parents"); - } - else { - /* clear inverse matrix and also the object location */ - unit_m4(ob->parentinv); - memset(ob->loc, 0, 3 * sizeof(float)); - - /* set recalc flags */ - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - /* set parenting type for object - object only... */ - ob->parent = par; - ob->partype = PAROBJECT; /* note, dna define, not operator property */ - } - } - } - CTX_DATA_END; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Object *par = ED_object_active_context(C); + + DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM); + + /* context iterator */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob != par) { + if (BKE_object_parent_loop_check(par, ob)) { + BKE_report(op->reports, RPT_ERROR, "Loop in parents"); + } + else { + /* clear inverse matrix and also the object location */ + unit_m4(ob->parentinv); + memset(ob->loc, 0, 3 * sizeof(float)); + + /* set recalc flags */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + /* set parenting type for object - object only... */ + ob->parent = par; + ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } + } + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; } void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Parent without Inverse"; - ot->description = "Set the object's parenting without setting the inverse parent correction"; - ot->idname = "OBJECT_OT_parent_no_inverse_set"; - - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = parent_noinv_set_exec; - ot->poll = ED_operator_object_active_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Make Parent without Inverse"; + ot->description = "Set the object's parenting without setting the inverse parent correction"; + ot->idname = "OBJECT_OT_parent_no_inverse_set"; + + /* api callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = parent_noinv_set_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Clear Track Operator ******************* */ enum { - CLEAR_TRACK = 1, - CLEAR_TRACK_KEEP_TRANSFORM = 2, + CLEAR_TRACK = 1, + CLEAR_TRACK_KEEP_TRANSFORM = 2, }; static const EnumPropertyItem prop_clear_track_types[] = { - {CLEAR_TRACK, "CLEAR", 0, "Clear Track", ""}, - {CLEAR_TRACK_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""}, - {0, NULL, 0, NULL, NULL}, + {CLEAR_TRACK, "CLEAR", 0, "Clear Track", ""}, + {CLEAR_TRACK_KEEP_TRANSFORM, + "CLEAR_KEEP_TRANSFORM", + 0, + "Clear and Keep Transformation (Clear Track)", + ""}, + {0, NULL, 0, NULL, NULL}, }; /* note, poll should check for editable scene */ static int object_track_clear_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - const int type = RNA_enum_get(op->ptr, "type"); - - if (CTX_data_edit_object(C)) { - BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode"); - return OPERATOR_CANCELLED; - } - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - bConstraint *con, *pcon; - - /* remove track-object for old track */ - ob->track = NULL; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* also remove all tracking constraints */ - for (con = ob->constraints.last; con; con = pcon) { - pcon = con->prev; - if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) - BKE_constraint_remove(&ob->constraints, con); - } - - if (type == CLEAR_TRACK_KEEP_TRANSFORM) - BKE_object_apply_mat4(ob, ob->obmat, true, true); - } - CTX_DATA_END; - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + const int type = RNA_enum_get(op->ptr, "type"); + + if (CTX_data_edit_object(C)) { + BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode"); + return OPERATOR_CANCELLED; + } + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + bConstraint *con, *pcon; + + /* remove track-object for old track */ + ob->track = NULL; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + + /* also remove all tracking constraints */ + for (con = ob->constraints.last; con; con = pcon) { + pcon = con->prev; + if (ELEM(con->type, + CONSTRAINT_TYPE_TRACKTO, + CONSTRAINT_TYPE_LOCKTRACK, + CONSTRAINT_TYPE_DAMPTRACK)) + BKE_constraint_remove(&ob->constraints, con); + } + + if (type == CLEAR_TRACK_KEEP_TRANSFORM) + BKE_object_apply_mat4(ob, ob->obmat, true, true); + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; } void OBJECT_OT_track_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Track"; - ot->description = "Clear tracking constraint or flag from object"; - ot->idname = "OBJECT_OT_track_clear"; + /* identifiers */ + ot->name = "Clear Track"; + ot->description = "Clear tracking constraint or flag from object"; + ot->idname = "OBJECT_OT_track_clear"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_track_clear_exec; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_track_clear_exec; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", ""); } /************************** Make Track Operator *****************************/ enum { - CREATE_TRACK_DAMPTRACK = 1, - CREATE_TRACK_TRACKTO = 2, - CREATE_TRACK_LOCKTRACK = 3, + CREATE_TRACK_DAMPTRACK = 1, + CREATE_TRACK_TRACKTO = 2, + CREATE_TRACK_LOCKTRACK = 3, }; static const EnumPropertyItem prop_make_track_types[] = { - {CREATE_TRACK_DAMPTRACK, "DAMPTRACK", 0, "Damped Track Constraint", ""}, - {CREATE_TRACK_TRACKTO, "TRACKTO", 0, "Track To Constraint", ""}, - {CREATE_TRACK_LOCKTRACK, "LOCKTRACK", 0, "Lock Track Constraint", ""}, - {0, NULL, 0, NULL, NULL}, + {CREATE_TRACK_DAMPTRACK, "DAMPTRACK", 0, "Damped Track Constraint", ""}, + {CREATE_TRACK_TRACKTO, "TRACKTO", 0, "Track To Constraint", ""}, + {CREATE_TRACK_LOCKTRACK, "LOCKTRACK", 0, "Lock Track Constraint", ""}, + {0, NULL, 0, NULL, NULL}, }; static int track_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *obact = ED_object_active_context(C); - - const int type = RNA_enum_get(op->ptr, "type"); - - switch (type) { - case CREATE_TRACK_DAMPTRACK: - { - bConstraint *con; - bDampTrackConstraint *data; - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob != obact) { - con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); - - data = con->data; - data->tar = obact; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* Light, Camera and Speaker track differently by default */ - if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { - data->trackflag = TRACK_nZ; - } - } - } - CTX_DATA_END; - break; - } - case CREATE_TRACK_TRACKTO: - { - bConstraint *con; - bTrackToConstraint *data; - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob != obact) { - con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); - - data = con->data; - data->tar = obact; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* Light, Camera and Speaker track differently by default */ - if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { - data->reserved1 = TRACK_nZ; - data->reserved2 = UP_Y; - } - } - } - CTX_DATA_END; - break; - } - case CREATE_TRACK_LOCKTRACK: - { - bConstraint *con; - bLockTrackConstraint *data; - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob != obact) { - con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); - - data = con->data; - data->tar = obact; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* Light, Camera and Speaker track differently by default */ - if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { - data->trackflag = TRACK_nZ; - data->lockflag = LOCK_Y; - } - } - } - CTX_DATA_END; - break; - } - } - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Object *obact = ED_object_active_context(C); + + const int type = RNA_enum_get(op->ptr, "type"); + + switch (type) { + case CREATE_TRACK_DAMPTRACK: { + bConstraint *con; + bDampTrackConstraint *data; + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob != obact) { + con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); + + data = con->data; + data->tar = obact; + DEG_id_tag_update(&ob->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + + /* Light, Camera and Speaker track differently by default */ + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + data->trackflag = TRACK_nZ; + } + } + } + CTX_DATA_END; + break; + } + case CREATE_TRACK_TRACKTO: { + bConstraint *con; + bTrackToConstraint *data; + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob != obact) { + con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); + + data = con->data; + data->tar = obact; + DEG_id_tag_update(&ob->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + + /* Light, Camera and Speaker track differently by default */ + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + data->reserved1 = TRACK_nZ; + data->reserved2 = UP_Y; + } + } + } + CTX_DATA_END; + break; + } + case CREATE_TRACK_LOCKTRACK: { + bConstraint *con; + bLockTrackConstraint *data; + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob != obact) { + con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); + + data = con->data; + data->tar = obact; + DEG_id_tag_update(&ob->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + + /* Light, Camera and Speaker track differently by default */ + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + data->trackflag = TRACK_nZ; + data->lockflag = LOCK_Y; + } + } + } + CTX_DATA_END; + break; + } + } + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; } void OBJECT_OT_track_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Track"; - ot->description = "Make the object track another object, using various methods/constraints"; - ot->idname = "OBJECT_OT_track_set"; + /* identifiers */ + ot->name = "Make Track"; + ot->description = "Make the object track another object, using various methods/constraints"; + ot->idname = "OBJECT_OT_track_set"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = track_set_exec; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = track_set_exec; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", ""); + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", ""); } /************************** Link to Scene Operator *****************************/ @@ -1286,1296 +1339,1315 @@ void OBJECT_OT_track_set(wmOperatorType *ot) #if 0 static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr)) { - Scene *sce = (Scene *) BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1); - Base *base, *nbase; - - if (sce == NULL) return; - if (sce->id.lib) return; - - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_SELECTED(v3d, base)) { - nbase = MEM_mallocN(sizeof(Base), "newbase"); - *nbase = *base; - BLI_addhead(&(sce->base), nbase); - id_us_plus((ID *)base->object); - } - } + Scene *sce = (Scene *) BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1); + Base *base, *nbase; + + if (sce == NULL) return; + if (sce->id.lib) return; + + for (base = FIRSTBASE; base; base = base->next) { + if (BASE_SELECTED(v3d, base)) { + nbase = MEM_mallocN(sizeof(Base), "newbase"); + *nbase = *base; + BLI_addhead(&(sce->base), nbase); + id_us_plus((ID *)base->object); + } + } } #endif static int make_links_scene_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene_to = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")); - - if (scene_to == NULL) { - BKE_report(op->reports, RPT_ERROR, "Could not find scene"); - return OPERATOR_CANCELLED; - } - - if (scene_to == CTX_data_scene(C)) { - BKE_report(op->reports, RPT_ERROR, "Cannot link objects into the same scene"); - return OPERATOR_CANCELLED; - } - - if (ID_IS_LINKED(scene_to)) { - BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene"); - return OPERATOR_CANCELLED; - } - - Collection *collection_to = BKE_collection_master(scene_to); - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - BKE_collection_object_add(bmain, collection_to, base->object); - } - CTX_DATA_END; - - DEG_relations_tag_update(bmain); - - /* redraw the 3D view because the object center points are colored differently */ - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - - /* one day multiple scenes will be visible, then we should have some update function for them */ - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene_to = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")); + + if (scene_to == NULL) { + BKE_report(op->reports, RPT_ERROR, "Could not find scene"); + return OPERATOR_CANCELLED; + } + + if (scene_to == CTX_data_scene(C)) { + BKE_report(op->reports, RPT_ERROR, "Cannot link objects into the same scene"); + return OPERATOR_CANCELLED; + } + + if (ID_IS_LINKED(scene_to)) { + BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene"); + return OPERATOR_CANCELLED; + } + + Collection *collection_to = BKE_collection_master(scene_to); + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { + BKE_collection_object_add(bmain, collection_to, base->object); + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + + /* redraw the 3D view because the object center points are colored differently */ + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + /* one day multiple scenes will be visible, then we should have some update function for them */ + return OPERATOR_FINISHED; } enum { - MAKE_LINKS_OBDATA = 1, - MAKE_LINKS_MATERIALS = 2, - MAKE_LINKS_ANIMDATA = 3, - MAKE_LINKS_GROUP = 4, - MAKE_LINKS_DUPLICOLLECTION = 5, - MAKE_LINKS_MODIFIERS = 6, - MAKE_LINKS_FONTS = 7, + MAKE_LINKS_OBDATA = 1, + MAKE_LINKS_MATERIALS = 2, + MAKE_LINKS_ANIMDATA = 3, + MAKE_LINKS_GROUP = 4, + MAKE_LINKS_DUPLICOLLECTION = 5, + MAKE_LINKS_MODIFIERS = 6, + MAKE_LINKS_FONTS = 7, }; /* Return true if make link data is allowed, false otherwise */ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst) { - switch (type) { - case MAKE_LINKS_OBDATA: - if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY) { - return true; - } - break; - case MAKE_LINKS_MATERIALS: - if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) && OB_TYPE_SUPPORT_MATERIAL(ob_dst->type)) { - return true; - } - break; - case MAKE_LINKS_DUPLICOLLECTION: - if (ob_dst->type == OB_EMPTY) { - return true; - } - break; - case MAKE_LINKS_ANIMDATA: - case MAKE_LINKS_GROUP: - return true; - case MAKE_LINKS_MODIFIERS: - if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) { - return true; - } - break; - case MAKE_LINKS_FONTS: - if ((ob_src->data != ob_dst->data) && (ob_src->type == OB_FONT) && (ob_dst->type == OB_FONT)) { - return true; - } - break; - } - return false; + switch (type) { + case MAKE_LINKS_OBDATA: + if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY) { + return true; + } + break; + case MAKE_LINKS_MATERIALS: + if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) && OB_TYPE_SUPPORT_MATERIAL(ob_dst->type)) { + return true; + } + break; + case MAKE_LINKS_DUPLICOLLECTION: + if (ob_dst->type == OB_EMPTY) { + return true; + } + break; + case MAKE_LINKS_ANIMDATA: + case MAKE_LINKS_GROUP: + return true; + case MAKE_LINKS_MODIFIERS: + if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) { + return true; + } + break; + case MAKE_LINKS_FONTS: + if ((ob_src->data != ob_dst->data) && (ob_src->type == OB_FONT) && + (ob_dst->type == OB_FONT)) { + return true; + } + break; + } + return false; } static int make_links_data_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Main *bmain = CTX_data_main(C); - const int type = RNA_enum_get(op->ptr, "type"); - Object *ob_src; - ID *obdata_id; - int a; - - /* collection */ - LinkNode *ob_collections = NULL; - bool is_cycle = false; - bool is_lib = false; - - ob_src = ED_object_active_context(C); - - /* avoid searching all collections in source object each time */ - if (type == MAKE_LINKS_GROUP) { - ob_collections = BKE_object_groups(bmain, scene, ob_src); - } - - CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases) - { - Object *ob_dst = base_dst->object; - - if (ob_src != ob_dst) { - if (allow_make_links_data(type, ob_src, ob_dst)) { - obdata_id = ob_dst->data; - - switch (type) { - case MAKE_LINKS_OBDATA: /* obdata */ - id_us_min(obdata_id); - - obdata_id = ob_src->data; - id_us_plus(obdata_id); - ob_dst->data = obdata_id; - - /* if amount of material indices changed: */ - test_object_materials(bmain, ob_dst, ob_dst->data); - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - break; - case MAKE_LINKS_MATERIALS: - /* new approach, using functions from kernel */ - for (a = 0; a < ob_src->totcol; a++) { - Material *ma = give_current_material(ob_src, a + 1); - /* also works with `ma == NULL` */ - assign_material(bmain, ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); - } - DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); - break; - case MAKE_LINKS_ANIMDATA: - BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, 0); - if (ob_dst->data && ob_src->data) { - if (ID_IS_LINKED(obdata_id)) { - is_lib = true; - break; - } - BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, 0); - } - DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - break; - case MAKE_LINKS_GROUP: - { - LinkNode *collection_node; - - /* first clear collections */ - BKE_object_groups_clear(bmain, scene, ob_dst); - - /* now add in the collections from the link nodes */ - for (collection_node = ob_collections; collection_node; collection_node = collection_node->next) { - if (ob_dst->instance_collection != collection_node->link) { - BKE_collection_object_add(bmain, collection_node->link, ob_dst); - } - else { - is_cycle = true; - } - } - break; - } - case MAKE_LINKS_DUPLICOLLECTION: - ob_dst->instance_collection = ob_src->instance_collection; - if (ob_dst->instance_collection) { - id_us_plus(&ob_dst->instance_collection->id); - ob_dst->transflag |= OB_DUPLICOLLECTION; - } - break; - case MAKE_LINKS_MODIFIERS: - BKE_object_link_modifiers(scene, ob_dst, ob_src); - DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - break; - case MAKE_LINKS_FONTS: - { - Curve *cu_src = ob_src->data; - Curve *cu_dst = ob_dst->data; - - if (ID_IS_LINKED(obdata_id)) { - is_lib = true; - break; - } - - if (cu_dst->vfont) - id_us_min(&cu_dst->vfont->id); - cu_dst->vfont = cu_src->vfont; - id_us_plus((ID *)cu_dst->vfont); - if (cu_dst->vfontb) - id_us_min(&cu_dst->vfontb->id); - cu_dst->vfontb = cu_src->vfontb; - id_us_plus((ID *)cu_dst->vfontb); - if (cu_dst->vfonti) - id_us_min(&cu_dst->vfonti->id); - cu_dst->vfonti = cu_src->vfonti; - id_us_plus((ID *)cu_dst->vfonti); - if (cu_dst->vfontbi) - id_us_min(&cu_dst->vfontbi->id); - cu_dst->vfontbi = cu_src->vfontbi; - id_us_plus((ID *)cu_dst->vfontbi); - - DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - break; - } - } - } - } - } - CTX_DATA_END; - - if (type == MAKE_LINKS_GROUP) { - if (ob_collections) { - BLI_linklist_free(ob_collections, NULL); - } - - if (is_cycle) { - BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); - } - } - - if (is_lib) { - BKE_report(op->reports, RPT_WARNING, "Skipped editing library object data"); - } - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C)); - WM_event_add_notifier(C, NC_OBJECT, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); + const int type = RNA_enum_get(op->ptr, "type"); + Object *ob_src; + ID *obdata_id; + int a; + + /* collection */ + LinkNode *ob_collections = NULL; + bool is_cycle = false; + bool is_lib = false; + + ob_src = ED_object_active_context(C); + + /* avoid searching all collections in source object each time */ + if (type == MAKE_LINKS_GROUP) { + ob_collections = BKE_object_groups(bmain, scene, ob_src); + } + + CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases) { + Object *ob_dst = base_dst->object; + + if (ob_src != ob_dst) { + if (allow_make_links_data(type, ob_src, ob_dst)) { + obdata_id = ob_dst->data; + + switch (type) { + case MAKE_LINKS_OBDATA: /* obdata */ + id_us_min(obdata_id); + + obdata_id = ob_src->data; + id_us_plus(obdata_id); + ob_dst->data = obdata_id; + + /* if amount of material indices changed: */ + test_object_materials(bmain, ob_dst, ob_dst->data); + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + break; + case MAKE_LINKS_MATERIALS: + /* new approach, using functions from kernel */ + for (a = 0; a < ob_src->totcol; a++) { + Material *ma = give_current_material(ob_src, a + 1); + /* also works with `ma == NULL` */ + assign_material(bmain, ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); + } + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + break; + case MAKE_LINKS_ANIMDATA: + BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, 0); + if (ob_dst->data && ob_src->data) { + if (ID_IS_LINKED(obdata_id)) { + is_lib = true; + break; + } + BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, 0); + } + DEG_id_tag_update(&ob_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + break; + case MAKE_LINKS_GROUP: { + LinkNode *collection_node; + + /* first clear collections */ + BKE_object_groups_clear(bmain, scene, ob_dst); + + /* now add in the collections from the link nodes */ + for (collection_node = ob_collections; collection_node; + collection_node = collection_node->next) { + if (ob_dst->instance_collection != collection_node->link) { + BKE_collection_object_add(bmain, collection_node->link, ob_dst); + } + else { + is_cycle = true; + } + } + break; + } + case MAKE_LINKS_DUPLICOLLECTION: + ob_dst->instance_collection = ob_src->instance_collection; + if (ob_dst->instance_collection) { + id_us_plus(&ob_dst->instance_collection->id); + ob_dst->transflag |= OB_DUPLICOLLECTION; + } + break; + case MAKE_LINKS_MODIFIERS: + BKE_object_link_modifiers(scene, ob_dst, ob_src); + DEG_id_tag_update(&ob_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + break; + case MAKE_LINKS_FONTS: { + Curve *cu_src = ob_src->data; + Curve *cu_dst = ob_dst->data; + + if (ID_IS_LINKED(obdata_id)) { + is_lib = true; + break; + } + + if (cu_dst->vfont) + id_us_min(&cu_dst->vfont->id); + cu_dst->vfont = cu_src->vfont; + id_us_plus((ID *)cu_dst->vfont); + if (cu_dst->vfontb) + id_us_min(&cu_dst->vfontb->id); + cu_dst->vfontb = cu_src->vfontb; + id_us_plus((ID *)cu_dst->vfontb); + if (cu_dst->vfonti) + id_us_min(&cu_dst->vfonti->id); + cu_dst->vfonti = cu_src->vfonti; + id_us_plus((ID *)cu_dst->vfonti); + if (cu_dst->vfontbi) + id_us_min(&cu_dst->vfontbi->id); + cu_dst->vfontbi = cu_src->vfontbi; + id_us_plus((ID *)cu_dst->vfontbi); + + DEG_id_tag_update(&ob_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + break; + } + } + } + } + } + CTX_DATA_END; + + if (type == MAKE_LINKS_GROUP) { + if (ob_collections) { + BLI_linklist_free(ob_collections, NULL); + } + + if (is_cycle) { + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); + } + } + + if (is_lib) { + BKE_report(op->reports, RPT_WARNING, "Skipped editing library object data"); + } + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_OBJECT, NULL); + + return OPERATOR_FINISHED; } - void OBJECT_OT_make_links_scene(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Link Objects to Scene"; - ot->description = "Link selection to another scene"; - ot->idname = "OBJECT_OT_make_links_scene"; - - /* api callbacks */ - ot->invoke = WM_enum_search_invoke; - ot->exec = make_links_scene_exec; - /* better not run the poll check */ - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", ""); - RNA_def_enum_funcs(prop, RNA_scene_local_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Link Objects to Scene"; + ot->description = "Link selection to another scene"; + ot->idname = "OBJECT_OT_make_links_scene"; + + /* api callbacks */ + ot->invoke = WM_enum_search_invoke; + ot->exec = make_links_scene_exec; + /* better not run the poll check */ + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", ""); + RNA_def_enum_funcs(prop, RNA_scene_local_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } void OBJECT_OT_make_links_data(wmOperatorType *ot) { - static const EnumPropertyItem make_links_items[] = { - {MAKE_LINKS_OBDATA, "OBDATA", 0, "Object Data", ""}, - {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""}, - {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""}, - {MAKE_LINKS_GROUP, "GROUPS", 0, "Collection", ""}, - {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "Instance Collection", ""}, - {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, - {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Link Data"; - ot->description = "Apply active object links to other selected objects"; - ot->idname = "OBJECT_OT_make_links_data"; - - /* api callbacks */ - ot->exec = make_links_data_exec; - ot->poll = ED_operator_object_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", make_links_items, 0, "Type", ""); + static const EnumPropertyItem make_links_items[] = { + {MAKE_LINKS_OBDATA, "OBDATA", 0, "Object Data", ""}, + {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""}, + {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""}, + {MAKE_LINKS_GROUP, "GROUPS", 0, "Collection", ""}, + {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "Instance Collection", ""}, + {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, + {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Link Data"; + ot->description = "Apply active object links to other selected objects"; + ot->idname = "OBJECT_OT_make_links_data"; + + /* api callbacks */ + ot->exec = make_links_data_exec; + ot->poll = ED_operator_object_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", make_links_items, 0, "Type", ""); } - /**************************** Make Single User ********************************/ static void libblock_relink_collection(Collection *collection) { - BKE_libblock_relink_to_newid(&collection->id); + BKE_libblock_relink_to_newid(&collection->id); - for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { - BKE_libblock_relink_to_newid(&cob->ob->id); - } + for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { + BKE_libblock_relink_to_newid(&cob->ob->id); + } - for (CollectionChild *child = collection->children.first; child; child = child->next) { - libblock_relink_collection(child->collection); - } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + libblock_relink_collection(child->collection); + } } -static Collection *single_object_users_collection( - Main *bmain, Scene *scene, Collection *collection, - const int flag, const bool copy_collections, const bool is_master_collection) +static Collection *single_object_users_collection(Main *bmain, + Scene *scene, + Collection *collection, + const int flag, + const bool copy_collections, + const bool is_master_collection) { - /* Generate new copies for objects in given collection and all its children, - * and optionnaly also copy collections themselves. */ - if (copy_collections && !is_master_collection) { - collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); - } - - /* We do not remap to new objects here, this is done in separate step. */ - for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { - Object *ob = cob->ob; - /* an object may be in more than one collection */ - if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { - if (!ID_IS_LINKED(ob) && BKE_object_scenes_users_get(bmain, ob) > 1) { - ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - } - } - } - - /* Since master collection has already be duplicated as part of scene copy, we do not duplictae it here. - * However, this means its children need to be re-added manually here, otherwise their parent lists are empty - * (which will lead to crashes, see T63101). */ - CollectionChild *child_next, *child = collection->children.first; - CollectionChild *orig_child_last = collection->children.last; - for (; child != NULL; child = child_next) { - child_next = child->next; - Collection *collection_child_new = single_object_users_collection( - bmain, scene, child->collection, flag, copy_collections, false); - if (is_master_collection && copy_collections && child->collection != collection_child_new) { - BKE_collection_child_add(bmain, collection, collection_child_new); - BLI_remlink(&collection->children, child); - MEM_freeN(child); - if (child == orig_child_last) { - break; - } - } - } - - return collection; + /* Generate new copies for objects in given collection and all its children, + * and optionnaly also copy collections themselves. */ + if (copy_collections && !is_master_collection) { + collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); + } + + /* We do not remap to new objects here, this is done in separate step. */ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Object *ob = cob->ob; + /* an object may be in more than one collection */ + if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { + if (!ID_IS_LINKED(ob) && BKE_object_scenes_users_get(bmain, ob) > 1) { + ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + } + } + } + + /* Since master collection has already be duplicated as part of scene copy, we do not duplictae it here. + * However, this means its children need to be re-added manually here, otherwise their parent lists are empty + * (which will lead to crashes, see T63101). */ + CollectionChild *child_next, *child = collection->children.first; + CollectionChild *orig_child_last = collection->children.last; + for (; child != NULL; child = child_next) { + child_next = child->next; + Collection *collection_child_new = single_object_users_collection( + bmain, scene, child->collection, flag, copy_collections, false); + if (is_master_collection && copy_collections && child->collection != collection_child_new) { + BKE_collection_child_add(bmain, collection, collection_child_new); + BLI_remlink(&collection->children, child); + MEM_freeN(child); + if (child == orig_child_last) { + break; + } + } + } + + return collection; } /* Warning, sets ID->newid pointers of objects and collections, but does not clear them. */ -static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections) +static void single_object_users( + Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections) { - /* duplicate all the objects of the scene (and matching collections, if required). */ - Collection *master_collection = BKE_collection_master(scene); - single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); - - /* duplicate collections that consist entirely of duplicated objects */ - /* XXX I guess that was designed for calls from 'make single user' operator... But since copy_collection is - * always false then, was not doing anything. And that kind of behavior should be added at operator level, - * not in a utility function also used by rather different code... */ + /* duplicate all the objects of the scene (and matching collections, if required). */ + Collection *master_collection = BKE_collection_master(scene); + single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); + + /* duplicate collections that consist entirely of duplicated objects */ + /* XXX I guess that was designed for calls from 'make single user' operator... But since copy_collection is + * always false then, was not doing anything. And that kind of behavior should be added at operator level, + * not in a utility function also used by rather different code... */ #if 0 - if (copy_collections) { - Collection *collection, *collectionn; - for (collection = bmain->collections.first; collection; collection = collection->id.next) { - bool all_duplicated = true; - bool any_duplicated = false; - - for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { - any_duplicated = true; - if (cob->ob->id.newid == NULL) { - all_duplicated = false; - break; - } - } - - if (any_duplicated && all_duplicated) { - // TODO: test if this works, with child collections .. - collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); - - for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) { - cob->ob = (Object *)cob->ob->id.newid; - } - } - } - } + if (copy_collections) { + Collection *collection, *collectionn; + for (collection = bmain->collections.first; collection; collection = collection->id.next) { + bool all_duplicated = true; + bool any_duplicated = false; + + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + any_duplicated = true; + if (cob->ob->id.newid == NULL) { + all_duplicated = false; + break; + } + } + + if (any_duplicated && all_duplicated) { + // TODO: test if this works, with child collections .. + collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); + + for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) { + cob->ob = (Object *)cob->ob->id.newid; + } + } + } + } #endif - /* Collection and object pointers in collections */ - libblock_relink_collection(master_collection); + /* Collection and object pointers in collections */ + libblock_relink_collection(master_collection); - /* collection pointers in scene */ - BKE_scene_groups_relink(scene); + /* collection pointers in scene */ + BKE_scene_groups_relink(scene); - /* active camera */ - ID_NEW_REMAP(scene->camera); - if (v3d) { - ID_NEW_REMAP(v3d->camera); - } + /* active camera */ + ID_NEW_REMAP(scene->camera); + if (v3d) { + ID_NEW_REMAP(v3d->camera); + } - /* Making single user may affect other scenes if they share with current one some collections in their ViewLayer. */ - BKE_main_collection_sync(bmain); + /* Making single user may affect other scenes if they share with current one some collections in their ViewLayer. */ + BKE_main_collection_sync(bmain); } /* not an especially efficient function, only added so the single user * button can be functional.*/ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) { - FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) - { - ob_iter->flag &= ~OB_DONE; - } - FOREACH_SCENE_OBJECT_END; + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) { + ob_iter->flag &= ~OB_DONE; + } + FOREACH_SCENE_OBJECT_END; - /* tag only the one object */ - ob->flag |= OB_DONE; + /* tag only the one object */ + ob->flag |= OB_DONE; - single_object_users(bmain, scene, NULL, OB_DONE, false); - BKE_main_id_clear_newpoins(bmain); + single_object_users(bmain, scene, NULL, OB_DONE, false); + BKE_main_id_clear_newpoins(bmain); } static void new_id_matar(Main *bmain, Material **matar, const int totcol) { - ID *id; - int a; - - for (a = 0; a < totcol; a++) { - id = (ID *)matar[a]; - if (id && !ID_IS_LINKED(id)) { - if (id->newid) { - matar[a] = (Material *)id->newid; - id_us_plus(id->newid); - id_us_min(id); - } - else if (id->us > 1) { - matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a])); - id_us_min(id); - } - } - } + ID *id; + int a; + + for (a = 0; a < totcol; a++) { + id = (ID *)matar[a]; + if (id && !ID_IS_LINKED(id)) { + if (id->newid) { + matar[a] = (Material *)id->newid; + id_us_plus(id->newid); + id_us_min(id); + } + else if (id->us > 1) { + matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a])); + id_us_min(id); + } + } + } } -static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) +static void single_obdata_users( + Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) { - Light *la; - Curve *cu; - /* Camera *cam; */ - Mesh *me; - Lattice *lat; - ID *id; - - FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, v3d, flag, ob) - { - if (!ID_IS_LINKED(ob)) { - id = ob->data; - - if (id && id->us > 1 && !ID_IS_LINKED(id)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - - switch (ob->type) { - case OB_LAMP: - ob->data = la = ID_NEW_SET(ob->data, BKE_light_copy(bmain, ob->data)); - break; - case OB_CAMERA: - ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); - break; - case OB_MESH: - /* Needed to remap texcomesh below. */ - me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data)); - if (me->key) /* We do not need to set me->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)me->key, false); - break; - case OB_MBALL: - ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data)); - break; - case OB_CURVE: - case OB_SURF: - case OB_FONT: - ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data)); - ID_NEW_REMAP(cu->bevobj); - ID_NEW_REMAP(cu->taperobj); - if (cu->key) /* We do not need to set cu->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)cu->key, false); - break; - case OB_LATTICE: - ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data)); - if (lat->key) /* We do not need to set lat->key->id.newid here... */ - BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false); - break; - case OB_ARMATURE: - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); - BKE_pose_rebuild(bmain, ob, ob->data, true); - break; - case OB_SPEAKER: - ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); - break; - case OB_LIGHTPROBE: - ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); - break; - case OB_GPENCIL: - ob->data = ID_NEW_SET(ob->data, BKE_gpencil_copy(bmain, ob->data)); - break; - default: - printf("ERROR %s: can't copy %s\n", __func__, id->name); - BLI_assert(!"This should never happen."); - - /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */ - BKE_scene_objects_iterator_end(&iter_macro); - return; - } - - /* Copy animation data after object data became local, - * otherwise old and new object data will share the same - * AnimData structure, which is not what we want. - * (sergey) - */ - BKE_animdata_copy_id_action(bmain, (ID *)ob->data, false); - - id_us_min(id); - } - } - } - FOREACH_OBJECT_FLAG_END; - - me = bmain->meshes.first; - while (me) { - ID_NEW_REMAP(me->texcomesh); - me = me->id.next; - } + Light *la; + Curve *cu; + /* Camera *cam; */ + Mesh *me; + Lattice *lat; + ID *id; + + FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { + if (!ID_IS_LINKED(ob)) { + id = ob->data; + + if (id && id->us > 1 && !ID_IS_LINKED(id)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + + switch (ob->type) { + case OB_LAMP: + ob->data = la = ID_NEW_SET(ob->data, BKE_light_copy(bmain, ob->data)); + break; + case OB_CAMERA: + ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); + break; + case OB_MESH: + /* Needed to remap texcomesh below. */ + me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data)); + if (me->key) /* We do not need to set me->key->id.newid here... */ + BKE_animdata_copy_id_action(bmain, (ID *)me->key, false); + break; + case OB_MBALL: + ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data)); + break; + case OB_CURVE: + case OB_SURF: + case OB_FONT: + ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data)); + ID_NEW_REMAP(cu->bevobj); + ID_NEW_REMAP(cu->taperobj); + if (cu->key) /* We do not need to set cu->key->id.newid here... */ + BKE_animdata_copy_id_action(bmain, (ID *)cu->key, false); + break; + case OB_LATTICE: + ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data)); + if (lat->key) /* We do not need to set lat->key->id.newid here... */ + BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false); + break; + case OB_ARMATURE: + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); + BKE_pose_rebuild(bmain, ob, ob->data, true); + break; + case OB_SPEAKER: + ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); + break; + case OB_LIGHTPROBE: + ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); + break; + case OB_GPENCIL: + ob->data = ID_NEW_SET(ob->data, BKE_gpencil_copy(bmain, ob->data)); + break; + default: + printf("ERROR %s: can't copy %s\n", __func__, id->name); + BLI_assert(!"This should never happen."); + + /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */ + BKE_scene_objects_iterator_end(&iter_macro); + return; + } + + /* Copy animation data after object data became local, + * otherwise old and new object data will share the same + * AnimData structure, which is not what we want. + * (sergey) + */ + BKE_animdata_copy_id_action(bmain, (ID *)ob->data, false); + + id_us_min(id); + } + } + } + FOREACH_OBJECT_FLAG_END; + + me = bmain->meshes.first; + while (me) { + ID_NEW_REMAP(me->texcomesh); + me = me->id.next; + } } -static void single_object_action_users(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) +static void single_object_action_users( + Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) { - FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, v3d, flag, ob) - { - if (!ID_IS_LINKED(ob)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - BKE_animdata_copy_id_action(bmain, &ob->id, false); - } - } - FOREACH_OBJECT_FLAG_END; + FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { + if (!ID_IS_LINKED(ob)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + BKE_animdata_copy_id_action(bmain, &ob->id, false); + } + } + FOREACH_OBJECT_FLAG_END; } -static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) +static void single_mat_users( + Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, const int flag) { - Material *ma, *man; - int a; - - FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, v3d, flag, ob) - { - if (!ID_IS_LINKED(ob)) { - for (a = 1; a <= ob->totcol; a++) { - ma = give_current_material(ob, a); - if (ma) { - /* do not test for LIB_TAG_NEW or use newid: - * this functions guaranteed delivers single_users! */ - - if (ma->id.us > 1) { - man = BKE_material_copy(bmain, ma); - BKE_animdata_copy_id_action(bmain, &man->id, false); - if (man->nodetree != NULL) { - BKE_animdata_copy_id_action(bmain, &man->nodetree->id, false); - } - - man->id.us = 0; - assign_material(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); - } - } - } - } - } - FOREACH_OBJECT_FLAG_END; + Material *ma, *man; + int a; + + FOREACH_OBJECT_FLAG_BEGIN (scene, view_layer, v3d, flag, ob) { + if (!ID_IS_LINKED(ob)) { + for (a = 1; a <= ob->totcol; a++) { + ma = give_current_material(ob, a); + if (ma) { + /* do not test for LIB_TAG_NEW or use newid: + * this functions guaranteed delivers single_users! */ + + if (ma->id.us > 1) { + man = BKE_material_copy(bmain, ma); + BKE_animdata_copy_id_action(bmain, &man->id, false); + if (man->nodetree != NULL) { + BKE_animdata_copy_id_action(bmain, &man->nodetree->id, false); + } + + man->id.us = 0; + assign_material(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); + } + } + } + } + } + FOREACH_OBJECT_FLAG_END; } static void single_mat_users_expand(Main *bmain) { - /* only when 'parent' blocks are LIB_TAG_NEW */ - Object *ob; - Mesh *me; - Curve *cu; - MetaBall *mb; - bGPdata *gpd; - - for (ob = bmain->objects.first; ob; ob = ob->id.next) - if (ob->id.tag & LIB_TAG_NEW) - new_id_matar(bmain, ob->mat, ob->totcol); - - for (me = bmain->meshes.first; me; me = me->id.next) - if (me->id.tag & LIB_TAG_NEW) - new_id_matar(bmain, me->mat, me->totcol); - - for (cu = bmain->curves.first; cu; cu = cu->id.next) - if (cu->id.tag & LIB_TAG_NEW) - new_id_matar(bmain, cu->mat, cu->totcol); - - for (mb = bmain->metaballs.first; mb; mb = mb->id.next) - if (mb->id.tag & LIB_TAG_NEW) - new_id_matar(bmain, mb->mat, mb->totcol); - - for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) - if (gpd->id.tag & LIB_TAG_NEW) - new_id_matar(bmain, gpd->mat, gpd->totcol); + /* only when 'parent' blocks are LIB_TAG_NEW */ + Object *ob; + Mesh *me; + Curve *cu; + MetaBall *mb; + bGPdata *gpd; + + for (ob = bmain->objects.first; ob; ob = ob->id.next) + if (ob->id.tag & LIB_TAG_NEW) + new_id_matar(bmain, ob->mat, ob->totcol); + + for (me = bmain->meshes.first; me; me = me->id.next) + if (me->id.tag & LIB_TAG_NEW) + new_id_matar(bmain, me->mat, me->totcol); + + for (cu = bmain->curves.first; cu; cu = cu->id.next) + if (cu->id.tag & LIB_TAG_NEW) + new_id_matar(bmain, cu->mat, cu->totcol); + + for (mb = bmain->metaballs.first; mb; mb = mb->id.next) + if (mb->id.tag & LIB_TAG_NEW) + new_id_matar(bmain, mb->mat, mb->totcol); + + for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) + if (gpd->id.tag & LIB_TAG_NEW) + new_id_matar(bmain, gpd->mat, gpd->totcol); } /* used for copying scenes */ -void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_collections) +void ED_object_single_users(Main *bmain, + Scene *scene, + const bool full, + const bool copy_collections) { - single_object_users(bmain, scene, NULL, 0, copy_collections); - - if (full) { - single_obdata_users(bmain, scene, NULL, NULL, 0); - single_object_action_users(bmain, scene, NULL, NULL, 0); - single_mat_users_expand(bmain); - } - - /* Relink nodetrees' pointers that have been duplicated. */ - FOREACH_NODETREE_BEGIN(bmain, ntree, id) - { - /* This is a bit convoluted, we want to root ntree of copied IDs and only those, - * so we first check that old ID has been copied and that ntree is root tree of old ID, - * then get root tree of new ID and remap its pointers to new ID... */ - if (id->newid && (&ntree->id != id)) { - ntree = ntreeFromID(id->newid); - BKE_libblock_relink_to_newid(&ntree->id); - } - } FOREACH_NODETREE_END; - - /* Relink datablock pointer properties */ - { - IDP_RelinkProperty(scene->id.properties); - - FOREACH_SCENE_OBJECT_BEGIN(scene, ob) - { - if (!ID_IS_LINKED(ob)) { - IDP_RelinkProperty(ob->id.properties); - } - } - FOREACH_SCENE_OBJECT_END; - - if (scene->nodetree) { - IDP_RelinkProperty(scene->nodetree->id.properties); - for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) { - IDP_RelinkProperty(node->prop); - } - } - - if (scene->world) { - IDP_RelinkProperty(scene->world->id.properties); - } - - if (scene->clip) { - IDP_RelinkProperty(scene->clip->id.properties); - } - } - BKE_main_id_clear_newpoins(bmain); - DEG_relations_tag_update(bmain); + single_object_users(bmain, scene, NULL, 0, copy_collections); + + if (full) { + single_obdata_users(bmain, scene, NULL, NULL, 0); + single_object_action_users(bmain, scene, NULL, NULL, 0); + single_mat_users_expand(bmain); + } + + /* Relink nodetrees' pointers that have been duplicated. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + /* This is a bit convoluted, we want to root ntree of copied IDs and only those, + * so we first check that old ID has been copied and that ntree is root tree of old ID, + * then get root tree of new ID and remap its pointers to new ID... */ + if (id->newid && (&ntree->id != id)) { + ntree = ntreeFromID(id->newid); + BKE_libblock_relink_to_newid(&ntree->id); + } + } + FOREACH_NODETREE_END; + + /* Relink datablock pointer properties */ + { + IDP_RelinkProperty(scene->id.properties); + + FOREACH_SCENE_OBJECT_BEGIN (scene, ob) { + if (!ID_IS_LINKED(ob)) { + IDP_RelinkProperty(ob->id.properties); + } + } + FOREACH_SCENE_OBJECT_END; + + if (scene->nodetree) { + IDP_RelinkProperty(scene->nodetree->id.properties); + for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) { + IDP_RelinkProperty(node->prop); + } + } + + if (scene->world) { + IDP_RelinkProperty(scene->world->id.properties); + } + + if (scene->clip) { + IDP_RelinkProperty(scene->clip->id.properties); + } + } + BKE_main_id_clear_newpoins(bmain); + DEG_relations_tag_update(bmain); } /******************************* Make Local ***********************************/ enum { - MAKE_LOCAL_SELECT_OB = 1, - MAKE_LOCAL_SELECT_OBDATA = 2, - MAKE_LOCAL_SELECT_OBDATA_MATERIAL = 3, - MAKE_LOCAL_ALL = 4, + MAKE_LOCAL_SELECT_OB = 1, + MAKE_LOCAL_SELECT_OBDATA = 2, + MAKE_LOCAL_SELECT_OBDATA_MATERIAL = 3, + MAKE_LOCAL_ALL = 4, }; -static int tag_localizable_looper( - void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cb_flag)) +static int tag_localizable_looper(void *UNUSED(user_data), + ID *UNUSED(self_id), + ID **id_pointer, + const int UNUSED(cb_flag)) { - if (*id_pointer) { - (*id_pointer)->tag &= ~LIB_TAG_DOIT; - } + if (*id_pointer) { + (*id_pointer)->tag &= ~LIB_TAG_DOIT; + } - return IDWALK_RET_NOP; + return IDWALK_RET_NOP; } static void tag_localizable_objects(bContext *C, const int mode) { - Main *bmain = CTX_data_main(C); - - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - /* Set LIB_TAG_DOIT flag for all selected objects, so next we can check whether - * object is gonna to become local or not. - */ - CTX_DATA_BEGIN (C, Object *, object, selected_objects) - { - object->id.tag |= LIB_TAG_DOIT; - - /* If data is also gonna to become local, mark data we're interested in - * as gonna-to-be-local. - */ - if (mode == MAKE_LOCAL_SELECT_OBDATA && object->data) { - ID *data_id = (ID *) object->data; - data_id->tag |= LIB_TAG_DOIT; - } - } - CTX_DATA_END; - - /* Also forbid making objects local if other library objects are using - * them for modifiers or constraints. - */ - for (Object *object = bmain->objects.first; object; object = object->id.next) { - if ((object->id.tag & LIB_TAG_DOIT) == 0) { - BKE_library_foreach_ID_link(NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY); - } - if (object->data) { - ID *data_id = (ID *) object->data; - if ((data_id->tag & LIB_TAG_DOIT) == 0) { - BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY); - } - } - } - - /* TODO(sergey): Drivers targets? */ + Main *bmain = CTX_data_main(C); + + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* Set LIB_TAG_DOIT flag for all selected objects, so next we can check whether + * object is gonna to become local or not. + */ + CTX_DATA_BEGIN (C, Object *, object, selected_objects) { + object->id.tag |= LIB_TAG_DOIT; + + /* If data is also gonna to become local, mark data we're interested in + * as gonna-to-be-local. + */ + if (mode == MAKE_LOCAL_SELECT_OBDATA && object->data) { + ID *data_id = (ID *)object->data; + data_id->tag |= LIB_TAG_DOIT; + } + } + CTX_DATA_END; + + /* Also forbid making objects local if other library objects are using + * them for modifiers or constraints. + */ + for (Object *object = bmain->objects.first; object; object = object->id.next) { + if ((object->id.tag & LIB_TAG_DOIT) == 0) { + BKE_library_foreach_ID_link( + NULL, &object->id, tag_localizable_looper, NULL, IDWALK_READONLY); + } + if (object->data) { + ID *data_id = (ID *)object->data; + if ((data_id->tag & LIB_TAG_DOIT) == 0) { + BKE_library_foreach_ID_link(NULL, data_id, tag_localizable_looper, NULL, IDWALK_READONLY); + } + } + } + + /* TODO(sergey): Drivers targets? */ } /** * Instance indirectly referenced zero user objects, * otherwise they're lost on reload, see T40595. */ -static bool make_local_all__instance_indirect_unused(Main *bmain, ViewLayer *view_layer, Collection *collection) +static bool make_local_all__instance_indirect_unused(Main *bmain, + ViewLayer *view_layer, + Collection *collection) { - Object *ob; - bool changed = false; + Object *ob; + bool changed = false; - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ID_IS_LINKED(ob) && (ob->id.us == 0)) { - Base *base; + for (ob = bmain->objects.first; ob; ob = ob->id.next) { + if (ID_IS_LINKED(ob) && (ob->id.us == 0)) { + Base *base; - id_us_plus(&ob->id); + id_us_plus(&ob->id); - BKE_collection_object_add(bmain, collection, ob); - base = BKE_view_layer_base_find(view_layer, ob); - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + BKE_collection_object_add(bmain, collection, ob); + base = BKE_view_layer_base_find(view_layer, ob); + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - changed = true; - } - } + changed = true; + } + } - return changed; + return changed; } static void make_local_animdata_tag_strips(ListBase *strips) { - NlaStrip *strip; + NlaStrip *strip; - for (strip = strips->first; strip; strip = strip->next) { - if (strip->act) { - strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING; - } + for (strip = strips->first; strip; strip = strip->next) { + if (strip->act) { + strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING; + } - make_local_animdata_tag_strips(&strip->strips); - } + make_local_animdata_tag_strips(&strip->strips); + } } /* Tag all actions used by given animdata to be made local. */ static void make_local_animdata_tag(AnimData *adt) { - if (adt) { - /* Actions - Active and Temp */ - if (adt->action) { - adt->action->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - if (adt->tmpact) { - adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - - /* Drivers */ - /* TODO: need to handle the ID-targets too? */ - - /* NLA Data */ - for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - make_local_animdata_tag_strips(&nlt->strips); - } - } + if (adt) { + /* Actions - Active and Temp */ + if (adt->action) { + adt->action->id.tag &= ~LIB_TAG_PRE_EXISTING; + } + if (adt->tmpact) { + adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING; + } + + /* Drivers */ + /* TODO: need to handle the ID-targets too? */ + + /* NLA Data */ + for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + make_local_animdata_tag_strips(&nlt->strips); + } + } } static void make_local_material_tag(Material *ma) { - if (ma) { - ma->id.tag &= ~LIB_TAG_PRE_EXISTING; - make_local_animdata_tag(BKE_animdata_from_id(&ma->id)); + if (ma) { + ma->id.tag &= ~LIB_TAG_PRE_EXISTING; + make_local_animdata_tag(BKE_animdata_from_id(&ma->id)); - /* About nodetrees: root one is made local together with material, others we keep linked for now... */ - } + /* About nodetrees: root one is made local together with material, others we keep linked for now... */ + } } static int make_local_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - ParticleSystem *psys; - Material *ma, ***matarar; - const int mode = RNA_enum_get(op->ptr, "type"); - int a; - - /* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */ - if (mode == MAKE_LOCAL_ALL) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Collection *collection = CTX_data_collection(C); - - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* De-select so the user can differentiate newly instanced from existing objects. */ - BKE_view_layer_base_deselect_all(view_layer); - - if (make_local_all__instance_indirect_unused(bmain, view_layer, collection)) { - BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss"); - } - } - else { - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - tag_localizable_objects(C, mode); - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - continue; - } - - ob->id.tag &= ~LIB_TAG_PRE_EXISTING; - make_local_animdata_tag(BKE_animdata_from_id(&ob->id)); - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - psys->part->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - - if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) { - for (a = 0; a < ob->totcol; a++) { - ma = ob->mat[a]; - if (ma) { - make_local_material_tag(ma); - } - } - - matarar = (Material ***)give_matarar(ob); - if (matarar) { - for (a = 0; a < ob->totcol; a++) { - ma = (*matarar)[a]; - if (ma) { - make_local_material_tag(ma); - } - } - } - } - - if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) { - ID *ob_data = ob->data; - ob_data->tag &= ~LIB_TAG_PRE_EXISTING; - make_local_animdata_tag(BKE_animdata_from_id(ob_data)); - } - } - CTX_DATA_END; - } - - BKE_library_make_local(bmain, NULL, NULL, true, false); /* NULL is all libs */ - - WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + ParticleSystem *psys; + Material *ma, ***matarar; + const int mode = RNA_enum_get(op->ptr, "type"); + int a; + + /* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */ + if (mode == MAKE_LOCAL_ALL) { + ViewLayer *view_layer = CTX_data_view_layer(C); + Collection *collection = CTX_data_collection(C); + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* De-select so the user can differentiate newly instanced from existing objects. */ + BKE_view_layer_base_deselect_all(view_layer); + + if (make_local_all__instance_indirect_unused(bmain, view_layer, collection)) { + BKE_report(op->reports, + RPT_INFO, + "Orphan library objects added to the current scene to avoid loss"); + } + } + else { + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + tag_localizable_objects(C, mode); + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if ((ob->id.tag & LIB_TAG_DOIT) == 0) { + continue; + } + + ob->id.tag &= ~LIB_TAG_PRE_EXISTING; + make_local_animdata_tag(BKE_animdata_from_id(&ob->id)); + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + psys->part->id.tag &= ~LIB_TAG_PRE_EXISTING; + } + + if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) { + for (a = 0; a < ob->totcol; a++) { + ma = ob->mat[a]; + if (ma) { + make_local_material_tag(ma); + } + } + + matarar = (Material ***)give_matarar(ob); + if (matarar) { + for (a = 0; a < ob->totcol; a++) { + ma = (*matarar)[a]; + if (ma) { + make_local_material_tag(ma); + } + } + } + } + + if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && + ob->data != NULL) { + ID *ob_data = ob->data; + ob_data->tag &= ~LIB_TAG_PRE_EXISTING; + make_local_animdata_tag(BKE_animdata_from_id(ob_data)); + } + } + CTX_DATA_END; + } + + BKE_library_make_local(bmain, NULL, NULL, true, false); /* NULL is all libs */ + + WM_event_add_notifier(C, NC_WINDOW, NULL); + return OPERATOR_FINISHED; } void OBJECT_OT_make_local(wmOperatorType *ot) { - static const EnumPropertyItem type_items[] = { - {MAKE_LOCAL_SELECT_OB, "SELECT_OBJECT", 0, "Selected Objects", ""}, - {MAKE_LOCAL_SELECT_OBDATA, "SELECT_OBDATA", 0, "Selected Objects and Data", ""}, - {MAKE_LOCAL_SELECT_OBDATA_MATERIAL, "SELECT_OBDATA_MATERIAL", 0, "Selected Objects, Data and Materials", ""}, - {MAKE_LOCAL_ALL, "ALL", 0, "All", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Make Local"; - ot->description = "Make library linked data-blocks local to this file"; - ot->idname = "OBJECT_OT_make_local"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = make_local_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); + static const EnumPropertyItem type_items[] = { + {MAKE_LOCAL_SELECT_OB, "SELECT_OBJECT", 0, "Selected Objects", ""}, + {MAKE_LOCAL_SELECT_OBDATA, "SELECT_OBDATA", 0, "Selected Objects and Data", ""}, + {MAKE_LOCAL_SELECT_OBDATA_MATERIAL, + "SELECT_OBDATA_MATERIAL", + 0, + "Selected Objects, Data and Materials", + ""}, + {MAKE_LOCAL_ALL, "ALL", 0, "All", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Make Local"; + ot->description = "Make library linked data-blocks local to this file"; + ot->idname = "OBJECT_OT_make_local"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = make_local_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } - static void make_override_static_tag_object(Object *obact, Object *ob) { - if (ob == obact) { - return; - } - - if (!ID_IS_LINKED(ob)) { - return; - } - - /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full - * 'automatic', generic handling of all this, - * will probably require adding some override-aware stuff to library_query code... */ - - if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { - for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { - if (md->type == eModifierType_Armature) { - ArmatureModifierData *amd = (ArmatureModifierData *)md; - if (amd->object == obact) { - ob->id.tag |= LIB_TAG_DOIT; - break; - } - } - } - } - else if (ob->parent == obact) { - ob->id.tag |= LIB_TAG_DOIT; - } - - if (ob->id.tag & LIB_TAG_DOIT) { - printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); - } + if (ob == obact) { + return; + } + + if (!ID_IS_LINKED(ob)) { + return; + } + + /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full + * 'automatic', generic handling of all this, + * will probably require adding some override-aware stuff to library_query code... */ + + if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { + for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object == obact) { + ob->id.tag |= LIB_TAG_DOIT; + break; + } + } + } + } + else if (ob->parent == obact) { + ob->id.tag |= LIB_TAG_DOIT; + } + + if (ob->id.tag & LIB_TAG_DOIT) { + printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); + } } static void make_override_static_tag_collections(Collection *collection) { - collection->id.tag |= LIB_TAG_DOIT; - for (CollectionChild *coll_child = collection->children.first; coll_child != NULL; coll_child = coll_child->next) { - make_override_static_tag_collections(coll_child->collection); - } + collection->id.tag |= LIB_TAG_DOIT; + for (CollectionChild *coll_child = collection->children.first; coll_child != NULL; + coll_child = coll_child->next) { + make_override_static_tag_collections(coll_child->collection); + } } /* Set the object to override. */ static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Scene *scene = CTX_data_scene(C); - Object *obact = ED_object_active_context(C); - - /* Sanity checks. */ - if (!scene || ID_IS_LINKED(scene) || !obact) { - return OPERATOR_CANCELLED; - } - - /* Get object to work on - use a menu if we need to... */ - if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && ID_IS_LINKED(obact->instance_collection)) { - /* Gives menu with list of objects in group. */ - WM_enum_search_invoke(C, op, event); - return OPERATOR_CANCELLED; - } - else if (ID_IS_LINKED(obact)) { - uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); - uiLayout *layout = UI_popup_menu_layout(pup); - - /* Create operator menu item with relevant properties filled in. */ - PointerRNA opptr_dummy; - uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, - WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); - - /* Present the menu and be done... */ - UI_popup_menu_end(C, pup); - - /* This invoke just calls another instance of this operator... */ - return OPERATOR_INTERFACE; - } - else { - /* Error.. cannot continue. */ - BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or collection"); - return OPERATOR_CANCELLED; - } - + Scene *scene = CTX_data_scene(C); + Object *obact = ED_object_active_context(C); + + /* Sanity checks. */ + if (!scene || ID_IS_LINKED(scene) || !obact) { + return OPERATOR_CANCELLED; + } + + /* Get object to work on - use a menu if we need to... */ + if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && + ID_IS_LINKED(obact->instance_collection)) { + /* Gives menu with list of objects in group. */ + WM_enum_search_invoke(C, op, event); + return OPERATOR_CANCELLED; + } + else if (ID_IS_LINKED(obact)) { + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* Create operator menu item with relevant properties filled in. */ + PointerRNA opptr_dummy; + uiItemFullO_ptr( + layout, op->type, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); + + /* Present the menu and be done... */ + UI_popup_menu_end(C, pup); + + /* This invoke just calls another instance of this operator... */ + return OPERATOR_INTERFACE; + } + else { + /* Error.. cannot continue. */ + BKE_report(op->reports, + RPT_ERROR, + "Can only make static override for a referenced object or collection"); + return OPERATOR_CANCELLED; + } } static int make_override_static_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *obact = CTX_data_active_object(C); - - bool success = false; - - if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && ID_IS_LINKED(obact->instance_collection)) { - Object *obcollection = obact; - Collection *collection = obcollection->instance_collection; - - const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); - Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); - obact = base->object; - - /* First, we make a static override of the linked collection itself, and all its children. */ - make_override_static_tag_collections(collection); - - /* Then, we make static override of the whole set of objects in the Collection. */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob) - { - ob->id.tag |= LIB_TAG_DOIT; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* Then, we remove (untag) bone shape objects, you shall never want to override those (hopefully)... */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob) - { - if (ob->type == OB_ARMATURE && ob->pose != NULL) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL) { - pchan->custom->id.tag &= ~ LIB_TAG_DOIT; - } - } - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - success = BKE_override_static_create_from_tag(bmain); - - /* Instantiate our newly overridden objects in scene, if not yet done. */ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Collection *new_collection = (Collection *)collection->id.newid; - - BKE_collection_child_add(bmain, scene->master_collection, new_collection); - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob) - { - if (new_ob != NULL && new_ob->id.override_static != NULL) { - if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { - BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); - base = BKE_view_layer_base_find(view_layer, new_ob); - DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); - } - /* parent to 'collection' empty */ - if (new_ob->parent == NULL) { - new_ob->parent = obcollection; - } - if (new_ob == (Object *)obact->id.newid) { - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); - } - else { - /* Disable auto-override tags for non-active objects, will help with performaces... */ - new_ob->id.override_static->flag &= ~STATICOVERRIDE_AUTO; - } - /* We still want to store all objects' current override status (i.e. change of parent). */ - BKE_override_static_operations_create(bmain, &new_ob->id, true); - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* obcollection is no more duplicollection-ing, - * it merely parents whole collection of overriding instantiated objects. */ - obcollection->instance_collection = NULL; - - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ - - DEG_id_tag_update(&scene->id, 0); - - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false); - } - /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ - else if (obact->type == OB_ARMATURE) { - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - obact->id.tag |= LIB_TAG_DOIT; - - for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) { - make_override_static_tag_object(obact, ob); - } - - success = BKE_override_static_create_from_tag(bmain); - - /* Also, we'd likely want to lock by default things like - * transformations of implicitly overridden objects? */ - - /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false); - } - /* TODO: probably more cases where we want to do automated smart things in the future! */ - else { - success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL); - } - - WM_event_add_notifier(C, NC_WINDOW, NULL); - - return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Main *bmain = CTX_data_main(C); + Object *obact = CTX_data_active_object(C); + + bool success = false; + + if (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && + ID_IS_LINKED(obact->instance_collection)) { + Object *obcollection = obact; + Collection *collection = obcollection->instance_collection; + + const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); + Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); + obact = base->object; + + /* First, we make a static override of the linked collection itself, and all its children. */ + make_override_static_tag_collections(collection); + + /* Then, we make static override of the whole set of objects in the Collection. */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { + ob->id.tag |= LIB_TAG_DOIT; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + /* Then, we remove (untag) bone shape objects, you shall never want to override those (hopefully)... */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { + if (ob->type == OB_ARMATURE && ob->pose != NULL) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + if (pchan->custom != NULL) { + pchan->custom->id.tag &= ~LIB_TAG_DOIT; + } + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + success = BKE_override_static_create_from_tag(bmain); + + /* Instantiate our newly overridden objects in scene, if not yet done. */ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Collection *new_collection = (Collection *)collection->id.newid; + + BKE_collection_child_add(bmain, scene->master_collection, new_collection); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) { + if (new_ob != NULL && new_ob->id.override_static != NULL) { + if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { + BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); + base = BKE_view_layer_base_find(view_layer, new_ob); + DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + } + /* parent to 'collection' empty */ + if (new_ob->parent == NULL) { + new_ob->parent = obcollection; + } + if (new_ob == (Object *)obact->id.newid) { + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + } + else { + /* Disable auto-override tags for non-active objects, will help with performaces... */ + new_ob->id.override_static->flag &= ~STATICOVERRIDE_AUTO; + } + /* We still want to store all objects' current override status (i.e. change of parent). */ + BKE_override_static_operations_create(bmain, &new_ob->id, true); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + /* obcollection is no more duplicollection-ing, + * it merely parents whole collection of overriding instantiated objects. */ + obcollection->instance_collection = NULL; + + /* Also, we'd likely want to lock by default things like + * transformations of implicitly overridden objects? */ + + DEG_id_tag_update(&scene->id, 0); + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false); + } + /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ + else if (obact->type == OB_ARMATURE) { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + obact->id.tag |= LIB_TAG_DOIT; + + for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) { + make_override_static_tag_object(obact, ob); + } + + success = BKE_override_static_create_from_tag(bmain); + + /* Also, we'd likely want to lock by default things like + * transformations of implicitly overridden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, false); + } + /* TODO: probably more cases where we want to do automated smart things in the future! */ + else { + success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL); + } + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static bool make_override_static_poll(bContext *C) { - Object *obact = CTX_data_active_object(C); + Object *obact = CTX_data_active_object(C); - /* Object must be directly linked to be overridable. */ - return (BKE_override_static_is_enabled() && - ED_operator_objectmode(C) && obact != NULL && - ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || - (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && ID_IS_LINKED(obact->instance_collection)))); + /* Object must be directly linked to be overridable. */ + return (BKE_override_static_is_enabled() && ED_operator_objectmode(C) && obact != NULL && + ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || + (!ID_IS_LINKED(obact) && obact->instance_collection != NULL && + ID_IS_LINKED(obact->instance_collection)))); } void OBJECT_OT_make_override_static(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Static Override"; - ot->description = "Make local override of this library linked data-block"; - ot->idname = "OBJECT_OT_make_override_static"; - - /* api callbacks */ - ot->invoke = make_override_static_invoke; - ot->exec = make_override_static_exec; - ot->poll = make_override_static_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop; - prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Override Object", - "Name of lib-linked/collection object to make an override from"); - RNA_def_enum_funcs(prop, proxy_collection_object_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + /* identifiers */ + ot->name = "Make Static Override"; + ot->description = "Make local override of this library linked data-block"; + ot->idname = "OBJECT_OT_make_override_static"; + + /* api callbacks */ + ot->invoke = make_override_static_invoke; + ot->exec = make_override_static_exec; + ot->poll = make_override_static_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, + "object", + DummyRNA_DEFAULT_items, + 0, + "Override Object", + "Name of lib-linked/collection object to make an override from"); + RNA_def_enum_funcs(prop, proxy_collection_object_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } enum { - MAKE_SINGLE_USER_ALL = 1, - MAKE_SINGLE_USER_SELECTED = 2, + MAKE_SINGLE_USER_ALL = 1, + MAKE_SINGLE_USER_SELECTED = 2, }; static int make_single_user_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ - const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; - const bool copy_collections = false; - bool update_deps = false; - - if (RNA_boolean_get(op->ptr, "object")) { - if (flag == SELECT) { - BKE_view_layer_selected_objects_tag(view_layer, OB_DONE); - single_object_users(bmain, scene, v3d, OB_DONE, copy_collections); - } - else { - single_object_users(bmain, scene, v3d, 0, copy_collections); - } - - /* needed since object relationships may have changed */ - update_deps = true; - } - - if (RNA_boolean_get(op->ptr, "obdata")) { - single_obdata_users(bmain, scene, view_layer, v3d, flag); - } - - if (RNA_boolean_get(op->ptr, "material")) { - single_mat_users(bmain, scene, view_layer, v3d, flag); - } - - if (RNA_boolean_get(op->ptr, "animation")) { - single_object_action_users(bmain, scene, view_layer, v3d, flag); - } - - BKE_main_id_clear_newpoins(bmain); - - WM_event_add_notifier(C, NC_WINDOW, NULL); - - if (update_deps) { - DEG_relations_tag_update(bmain); - } - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ + const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; + const bool copy_collections = false; + bool update_deps = false; + + if (RNA_boolean_get(op->ptr, "object")) { + if (flag == SELECT) { + BKE_view_layer_selected_objects_tag(view_layer, OB_DONE); + single_object_users(bmain, scene, v3d, OB_DONE, copy_collections); + } + else { + single_object_users(bmain, scene, v3d, 0, copy_collections); + } + + /* needed since object relationships may have changed */ + update_deps = true; + } + + if (RNA_boolean_get(op->ptr, "obdata")) { + single_obdata_users(bmain, scene, view_layer, v3d, flag); + } + + if (RNA_boolean_get(op->ptr, "material")) { + single_mat_users(bmain, scene, view_layer, v3d, flag); + } + + if (RNA_boolean_get(op->ptr, "animation")) { + single_object_action_users(bmain, scene, view_layer, v3d, flag); + } + + BKE_main_id_clear_newpoins(bmain); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + if (update_deps) { + DEG_relations_tag_update(bmain); + } + + return OPERATOR_FINISHED; } void OBJECT_OT_make_single_user(wmOperatorType *ot) { - static const EnumPropertyItem type_items[] = { - {MAKE_SINGLE_USER_SELECTED, "SELECTED_OBJECTS", 0, "Selected Objects", ""}, - {MAKE_SINGLE_USER_ALL, "ALL", 0, "All", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Make Single User"; - ot->description = "Make linked data local to each object"; - ot->idname = "OBJECT_OT_make_single_user"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = make_single_user_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, MAKE_SINGLE_USER_SELECTED, "Type", ""); - - RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects"); - RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data"); - RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block"); - RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); + static const EnumPropertyItem type_items[] = { + {MAKE_SINGLE_USER_SELECTED, "SELECTED_OBJECTS", 0, "Selected Objects", ""}, + {MAKE_SINGLE_USER_ALL, "ALL", 0, "All", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Make Single User"; + ot->description = "Make linked data local to each object"; + ot->idname = "OBJECT_OT_make_single_user"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = make_single_user_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", type_items, MAKE_SINGLE_USER_SELECTED, "Type", ""); + + RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects"); + RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data"); + RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block"); + RNA_def_boolean( + ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); } static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Main *bmain = CTX_data_main(C); - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); - Material *ma; - char name[MAX_ID_NAME - 2]; + Main *bmain = CTX_data_main(C); + Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + Material *ma; + char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "name", name); - ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name); - if (base == NULL || ma == NULL) - return OPERATOR_CANCELLED; + RNA_string_get(op->ptr, "name", name); + ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name); + if (base == NULL || ma == NULL) + return OPERATOR_CANCELLED; - assign_material(CTX_data_main(C), base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF); + assign_material(CTX_data_main(C), base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF); - DEG_id_tag_update(&base->object->id, ID_RECALC_TRANSFORM); + DEG_id_tag_update(&base->object->id, ID_RECALC_TRANSFORM); - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* used for dropbox */ /* assigns to object under cursor, only first material slot */ void OBJECT_OT_drop_named_material(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Drop Named Material on Object"; - ot->idname = "OBJECT_OT_drop_named_material"; + /* identifiers */ + ot->name = "Drop Named Material on Object"; + ot->idname = "OBJECT_OT_drop_named_material"; - /* api callbacks */ - ot->invoke = drop_named_material_invoke; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->invoke = drop_named_material_invoke; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign"); + /* properties */ + RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign"); } static int object_unlink_data_exec(bContext *C, wmOperator *op) { - ID *id; - PropertyPointerRNA pprop; + ID *id; + PropertyPointerRNA pprop; - UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); + UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); - if (pprop.prop == NULL) { - BKE_report(op->reports, RPT_ERROR, "Incorrect context for running object data unlink"); - return OPERATOR_CANCELLED; - } + if (pprop.prop == NULL) { + BKE_report(op->reports, RPT_ERROR, "Incorrect context for running object data unlink"); + return OPERATOR_CANCELLED; + } - id = pprop.ptr.id.data; + id = pprop.ptr.id.data; - if (GS(id->name) == ID_OB) { - Object *ob = (Object *)id; - if (ob->data) { - ID *id_data = ob->data; + if (GS(id->name) == ID_OB) { + Object *ob = (Object *)id; + if (ob->data) { + ID *id_data = ob->data; - if (GS(id_data->name) == ID_IM) { - id_us_min(id_data); - ob->data = NULL; - } - else { - BKE_report(op->reports, RPT_ERROR, "Can't unlink this object data"); - return OPERATOR_CANCELLED; - } - } - } + if (GS(id_data->name) == ID_IM) { + id_us_min(id_data); + ob->data = NULL; + } + else { + BKE_report(op->reports, RPT_ERROR, "Can't unlink this object data"); + return OPERATOR_CANCELLED; + } + } + } - RNA_property_update(C, &pprop.ptr, pprop.prop); + RNA_property_update(C, &pprop.ptr, pprop.prop); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /** @@ -2583,13 +2655,13 @@ static int object_unlink_data_exec(bContext *C, wmOperator *op) */ void OBJECT_OT_unlink_data(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Unlink"; - ot->idname = "OBJECT_OT_unlink_data"; + /* identifiers */ + ot->name = "Unlink"; + ot->idname = "OBJECT_OT_unlink_data"; - /* api callbacks */ - ot->exec = object_unlink_data_exec; + /* api callbacks */ + ot->exec = object_unlink_data_exec; - /* flags */ - ot->flag = OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_INTERNAL; } diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 919055aa668..06bd4d76973 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -96,26 +96,26 @@ */ void ED_object_base_select(Base *base, eObjectSelect_Mode mode) { - if (mode == BA_INVERT) { - mode = (base->flag & BASE_SELECTED) != 0 ? BA_DESELECT : BA_SELECT; - } - - if (base) { - switch (mode) { - case BA_SELECT: - if ((base->flag & BASE_SELECTABLE) != 0) { - base->flag |= BASE_SELECTED; - } - break; - case BA_DESELECT: - base->flag &= ~BASE_SELECTED; - break; - case BA_INVERT: - /* Never happens. */ - break; - } - BKE_scene_object_base_flag_sync_from_base(base); - } + if (mode == BA_INVERT) { + mode = (base->flag & BASE_SELECTED) != 0 ? BA_DESELECT : BA_SELECT; + } + + if (base) { + switch (mode) { + case BA_SELECT: + if ((base->flag & BASE_SELECTABLE) != 0) { + base->flag |= BASE_SELECTED; + } + break; + case BA_DESELECT: + base->flag &= ~BASE_SELECTED; + break; + case BA_INVERT: + /* Never happens. */ + break; + } + BKE_scene_object_base_flag_sync_from_base(base); + } } /** @@ -123,75 +123,77 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode) */ void ED_object_base_activate(bContext *C, Base *base) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - view_layer->basact = base; - - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_SELECT); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + view_layer->basact = base; + + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_SELECT); } -bool ED_object_base_deselect_all_ex(ViewLayer *view_layer, View3D *v3d, int action, bool *r_any_visible) +bool ED_object_base_deselect_all_ex(ViewLayer *view_layer, + View3D *v3d, + int action, + bool *r_any_visible) { - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - FOREACH_VISIBLE_BASE_BEGIN(view_layer, v3d, base) { - if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) { - continue; - } - if ((base->flag & BASE_SELECTED) != 0) { - action = SEL_DESELECT; - break; - } - } - FOREACH_VISIBLE_BASE_END; - } - - bool any_visible = false; - bool changed = false; - FOREACH_VISIBLE_BASE_BEGIN(view_layer, v3d, base) { - if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) { - continue; - } - switch (action) { - case SEL_SELECT: - if ((base->flag & BASE_SELECTED) == 0) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - break; - case SEL_DESELECT: - if ((base->flag & BASE_SELECTED) != 0) { - ED_object_base_select(base, BA_DESELECT); - changed = true; - } - break; - case SEL_INVERT: - if ((base->flag & BASE_SELECTED) != 0) { - ED_object_base_select(base, BA_DESELECT); - changed = true; - } - else { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - break; - } - any_visible = true; - } - FOREACH_VISIBLE_BASE_END; - if (r_any_visible) { - *r_any_visible = any_visible; - } - return changed; + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base) { + if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) { + continue; + } + if ((base->flag & BASE_SELECTED) != 0) { + action = SEL_DESELECT; + break; + } + } + FOREACH_VISIBLE_BASE_END; + } + + bool any_visible = false; + bool changed = false; + FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base) { + if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) { + continue; + } + switch (action) { + case SEL_SELECT: + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + break; + case SEL_DESELECT: + if ((base->flag & BASE_SELECTED) != 0) { + ED_object_base_select(base, BA_DESELECT); + changed = true; + } + break; + case SEL_INVERT: + if ((base->flag & BASE_SELECTED) != 0) { + ED_object_base_select(base, BA_DESELECT); + changed = true; + } + else { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + break; + } + any_visible = true; + } + FOREACH_VISIBLE_BASE_END; + if (r_any_visible) { + *r_any_visible = any_visible; + } + return changed; } - bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action) { - return ED_object_base_deselect_all_ex(view_layer, v3d, action, NULL); + return ED_object_base_deselect_all_ex(view_layer, v3d, action, NULL); } /** \} */ @@ -202,17 +204,17 @@ bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action) static int get_base_select_priority(Base *base) { - if (base->flag & BASE_VISIBLE) { - if (base->flag & BASE_SELECTABLE) { - return 3; - } - else { - return 2; - } - } - else { - return 1; - } + if (base->flag & BASE_VISIBLE) { + if (base->flag & BASE_SELECTABLE) { + return 3; + } + else { + return 2; + } + } + else { + return 1; + } } /** @@ -221,36 +223,36 @@ static int get_base_select_priority(Base *base) */ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id) { - BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); - - /* Try active object. */ - Base *basact = view_layer->basact; - - if (basact && basact->object && basact->object->data == id) { - return basact; - } - - /* Try all objects. */ - Base *base_best = NULL; - int priority_best = 0; - - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (base->object && base->object->data == id) { - if (base->flag & BASE_SELECTED) { - return base; - } - else { - int priority_test = get_base_select_priority(base); - - if (priority_test > priority_best) { - priority_best = priority_test; - base_best = base; - } - } - } - } - - return base_best; + BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); + + /* Try active object. */ + Base *basact = view_layer->basact; + + if (basact && basact->object && basact->object->data == id) { + return basact; + } + + /* Try all objects. */ + Base *base_best = NULL; + int priority_best = 0; + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object && base->object->data == id) { + if (base->flag & BASE_SELECTED) { + return base; + } + else { + int priority_test = get_base_select_priority(base); + + if (priority_test > priority_best) { + priority_best = priority_test; + base_best = base; + } + } + } + } + + return base_best; } /** @@ -259,36 +261,35 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id) * * \returns false if not found in current view layer */ -bool ED_object_jump_to_object( - bContext *C, Object *ob, const bool UNUSED(reveal_hidden)) +bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_hidden)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Base *base = BKE_view_layer_base_find(view_layer, ob); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base == NULL) { - return false; - } + if (base == NULL) { + return false; + } - /* TODO, use 'reveal_hidden', as is done with bones. */ + /* TODO, use 'reveal_hidden', as is done with bones. */ - if (view_layer->basact != base || !(base->flag & BASE_SELECTED)) { - /* Select if not selected. */ - if (!(base->flag & BASE_SELECTED)) { - ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); + if (view_layer->basact != base || !(base->flag & BASE_SELECTED)) { + /* Select if not selected. */ + if (!(base->flag & BASE_SELECTED)) { + ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - if (base->flag & BASE_VISIBLE) { - ED_object_base_select(base, BA_SELECT); - } + if (base->flag & BASE_VISIBLE) { + ED_object_base_select(base, BA_SELECT); + } - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); - } + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + } - /* Make active if not active. */ - ED_object_base_activate(C, base); - } + /* Make active if not active. */ + ED_object_base_activate(C, base); + } - return true; + return true; } /** @@ -298,79 +299,80 @@ bool ED_object_jump_to_object( * * \returns false if object not in layer, bone not found, or other error */ -bool ED_object_jump_to_bone( - bContext *C, Object *ob, const char *bone_name, - const bool reveal_hidden) +bool ED_object_jump_to_bone(bContext *C, + Object *ob, + const char *bone_name, + const bool reveal_hidden) { - /* Verify it's a valid armature object. */ - if (ob == NULL || ob->type != OB_ARMATURE) { - return false; - } - - bArmature *arm = ob->data; - - /* Activate the armature object. */ - if (!ED_object_jump_to_object(C, ob, reveal_hidden)) { - return false; - } - - /* Switch to pose mode from object mode. */ - if (!ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_POSE)) { - ED_object_mode_set(C, OB_MODE_POSE); - } - - if (ob->mode == OB_MODE_EDIT && arm->edbo != NULL) { - /* In Edit mode select and activate the target Edit-Bone. */ - EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, bone_name); - if (ebone != NULL) { - if (reveal_hidden) { - /* Unhide the bone. */ - ebone->flag &= ~BONE_HIDDEN_A; - - if ((arm->layer & ebone->layer) == 0) { - arm->layer |= 1U << bitscan_forward_uint(ebone->layer); - } - } - - /* Select it. */ - ED_armature_edit_deselect_all(ob); - - if (EBONE_SELECTABLE(arm, ebone)) { - ED_armature_ebone_select_set(ebone, true); - ED_armature_edit_sync_selection(arm->edbo); - } - - arm->act_edbone = ebone; - - ED_pose_bone_select_tag_update(ob); - return true; - } - } - else if (ob->mode == OB_MODE_POSE && ob->pose != NULL) { - /* In Pose mode select and activate the target Bone/Pose-Channel. */ - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (pchan != NULL) { - if (reveal_hidden) { - /* Unhide the bone. */ - pchan->bone->flag &= ~BONE_HIDDEN_P; - - if ((arm->layer & pchan->bone->layer) == 0) { - arm->layer |= 1U << bitscan_forward_uint(pchan->bone->layer); - } - } - - /* Select it. */ - ED_pose_deselect_all(ob, SEL_DESELECT, true); - ED_pose_bone_select(ob, pchan, true); - - arm->act_bone = pchan->bone; - - ED_pose_bone_select_tag_update(ob); - return true; - } - } - - return false; + /* Verify it's a valid armature object. */ + if (ob == NULL || ob->type != OB_ARMATURE) { + return false; + } + + bArmature *arm = ob->data; + + /* Activate the armature object. */ + if (!ED_object_jump_to_object(C, ob, reveal_hidden)) { + return false; + } + + /* Switch to pose mode from object mode. */ + if (!ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_POSE)) { + ED_object_mode_set(C, OB_MODE_POSE); + } + + if (ob->mode == OB_MODE_EDIT && arm->edbo != NULL) { + /* In Edit mode select and activate the target Edit-Bone. */ + EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, bone_name); + if (ebone != NULL) { + if (reveal_hidden) { + /* Unhide the bone. */ + ebone->flag &= ~BONE_HIDDEN_A; + + if ((arm->layer & ebone->layer) == 0) { + arm->layer |= 1U << bitscan_forward_uint(ebone->layer); + } + } + + /* Select it. */ + ED_armature_edit_deselect_all(ob); + + if (EBONE_SELECTABLE(arm, ebone)) { + ED_armature_ebone_select_set(ebone, true); + ED_armature_edit_sync_selection(arm->edbo); + } + + arm->act_edbone = ebone; + + ED_pose_bone_select_tag_update(ob); + return true; + } + } + else if (ob->mode == OB_MODE_POSE && ob->pose != NULL) { + /* In Pose mode select and activate the target Bone/Pose-Channel. */ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (pchan != NULL) { + if (reveal_hidden) { + /* Unhide the bone. */ + pchan->bone->flag &= ~BONE_HIDDEN_P; + + if ((arm->layer & pchan->bone->layer) == 0) { + arm->layer |= 1U << bitscan_forward_uint(pchan->bone->layer); + } + } + + /* Select it. */ + ED_pose_deselect_all(ob, SEL_DESELECT, true); + ED_pose_bone_select(ob, pchan, true); + + arm->act_bone = pchan->bone; + + ED_pose_bone_select_tag_update(ob); + return true; + } + } + + return false; } /** \} */ @@ -381,16 +383,16 @@ bool ED_object_jump_to_bone( static bool objects_selectable_poll(bContext *C) { - /* we don't check for linked scenes here, selection is - * still allowed then for inspection of scene */ - Object *obact = CTX_data_active_object(C); + /* we don't check for linked scenes here, selection is + * still allowed then for inspection of scene */ + Object *obact = CTX_data_active_object(C); - if (CTX_data_edit_object(C)) - return 0; - if (obact && obact->mode) - return 0; + if (CTX_data_edit_object(C)) + return 0; + if (obact && obact->mode) + return 0; - return 1; + return 1; } /** \} */ @@ -401,51 +403,54 @@ static bool objects_selectable_poll(bContext *C) static int object_select_by_type_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - short obtype, extend; - - obtype = RNA_enum_get(op->ptr, "type"); - extend = RNA_boolean_get(op->ptr, "extend"); - - if (extend == 0) { - ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - } - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (base->object->type == obtype) { - ED_object_base_select(base, BA_SELECT); - } - } - CTX_DATA_END; - - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + short obtype, extend; + + obtype = RNA_enum_get(op->ptr, "type"); + extend = RNA_boolean_get(op->ptr, "extend"); + + if (extend == 0) { + ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); + } + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (base->object->type == obtype) { + ED_object_base_select(base, BA_SELECT); + } + } + CTX_DATA_END; + + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } void OBJECT_OT_select_by_type(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select By Type"; - ot->description = "Select all visible objects that are of a type"; - ot->idname = "OBJECT_OT_select_by_type"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_select_by_type_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 1, "Type", ""); - RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID); + /* identifiers */ + ot->name = "Select By Type"; + ot->description = "Select all visible objects that are of a type"; + ot->idname = "OBJECT_OT_select_by_type"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_select_by_type_exec; + ot->poll = objects_selectable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + false, + "Extend", + "Extend selection instead of deselecting everything first"); + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 1, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID); } /** \} */ @@ -455,270 +460,273 @@ void OBJECT_OT_select_by_type(wmOperatorType *ot) * \{ */ enum { - OBJECT_SELECT_LINKED_IPO = 1, - OBJECT_SELECT_LINKED_OBDATA, - OBJECT_SELECT_LINKED_MATERIAL, - OBJECT_SELECT_LINKED_DUPGROUP, - OBJECT_SELECT_LINKED_PARTICLE, - OBJECT_SELECT_LINKED_LIBRARY, - OBJECT_SELECT_LINKED_LIBRARY_OBDATA, + OBJECT_SELECT_LINKED_IPO = 1, + OBJECT_SELECT_LINKED_OBDATA, + OBJECT_SELECT_LINKED_MATERIAL, + OBJECT_SELECT_LINKED_DUPGROUP, + OBJECT_SELECT_LINKED_PARTICLE, + OBJECT_SELECT_LINKED_LIBRARY, + OBJECT_SELECT_LINKED_LIBRARY_OBDATA, }; static const EnumPropertyItem prop_select_linked_types[] = { - //{OBJECT_SELECT_LINKED_IPO, "IPO", 0, "Object IPO", ""}, // XXX deprecated animation system stuff... - {OBJECT_SELECT_LINKED_OBDATA, "OBDATA", 0, "Object Data", ""}, - {OBJECT_SELECT_LINKED_MATERIAL, "MATERIAL", 0, "Material", ""}, - {OBJECT_SELECT_LINKED_DUPGROUP, "DUPGROUP", 0, "Instanced Collection", ""}, - {OBJECT_SELECT_LINKED_PARTICLE, "PARTICLE", 0, "Particle System", ""}, - {OBJECT_SELECT_LINKED_LIBRARY, "LIBRARY", 0, "Library", ""}, - {OBJECT_SELECT_LINKED_LIBRARY_OBDATA, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""}, - {0, NULL, 0, NULL, NULL}, + //{OBJECT_SELECT_LINKED_IPO, "IPO", 0, "Object IPO", ""}, // XXX deprecated animation system stuff... + {OBJECT_SELECT_LINKED_OBDATA, "OBDATA", 0, "Object Data", ""}, + {OBJECT_SELECT_LINKED_MATERIAL, "MATERIAL", 0, "Material", ""}, + {OBJECT_SELECT_LINKED_DUPGROUP, "DUPGROUP", 0, "Instanced Collection", ""}, + {OBJECT_SELECT_LINKED_PARTICLE, "PARTICLE", 0, "Particle System", ""}, + {OBJECT_SELECT_LINKED_LIBRARY, "LIBRARY", 0, "Library", ""}, + {OBJECT_SELECT_LINKED_LIBRARY_OBDATA, "LIBRARY_OBDATA", 0, "Library (Object Data)", ""}, + {0, NULL, 0, NULL, NULL}, }; static bool object_select_all_by_obdata(bContext *C, void *obdata) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (base->object->data == obdata) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (base->object->data == obdata) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + + return changed; } static bool object_select_all_by_material(bContext *C, Material *mat) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - Object *ob = base->object; - Material *mat1; - int a; - - for (a = 1; a <= ob->totcol; a++) { - mat1 = give_current_material(ob, a); - - if (mat1 == mat) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - } - CTX_DATA_END; - - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + Object *ob = base->object; + Material *mat1; + int a; + + for (a = 1; a <= ob->totcol; a++) { + mat1 = give_current_material(ob, a); + + if (mat1 == mat) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + } + CTX_DATA_END; + + return changed; } static bool object_select_all_by_instance_collection(bContext *C, Object *ob) { - bool changed = false; - Collection *instance_collection = (ob->transflag & OB_DUPLICOLLECTION) ? ob->instance_collection : NULL; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - Collection *instance_collection_other = (base->object->transflag & OB_DUPLICOLLECTION) ? base->object->instance_collection : NULL; - if (instance_collection == instance_collection_other) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - - return changed; + bool changed = false; + Collection *instance_collection = (ob->transflag & OB_DUPLICOLLECTION) ? + ob->instance_collection : + NULL; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + Collection *instance_collection_other = (base->object->transflag & OB_DUPLICOLLECTION) ? + base->object->instance_collection : + NULL; + if (instance_collection == instance_collection_other) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + + return changed; } static bool object_select_all_by_particle(bContext *C, Object *ob) { - ParticleSystem *psys_act = psys_get_current(ob); - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - /* loop through other particles*/ - ParticleSystem *psys; - - for (psys = base->object->particlesystem.first; psys; psys = psys->next) { - if (psys->part == psys_act->part) { - ED_object_base_select(base, BA_SELECT); - changed = true; - break; - } - - if (base->flag & BASE_SELECTED) { - break; - } - } - } - } - CTX_DATA_END; - - return changed; + ParticleSystem *psys_act = psys_get_current(ob); + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + /* loop through other particles*/ + ParticleSystem *psys; + + for (psys = base->object->particlesystem.first; psys; psys = psys->next) { + if (psys->part == psys_act->part) { + ED_object_base_select(base, BA_SELECT); + changed = true; + break; + } + + if (base->flag & BASE_SELECTED) { + break; + } + } + } + } + CTX_DATA_END; + + return changed; } static bool object_select_all_by_library(bContext *C, Library *lib) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (lib == base->object->id.lib) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (lib == base->object->id.lib) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + + return changed; } static bool object_select_all_by_library_obdata(bContext *C, Library *lib) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (base->object->data && lib == ((ID *)base->object->data)->lib) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (base->object->data && lib == ((ID *)base->object->data)->lib) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + + return changed; } void ED_object_select_linked_by_id(bContext *C, ID *id) { - int idtype = GS(id->name); - bool changed = false; - - if (OB_DATA_SUPPORT_ID(idtype)) { - changed = object_select_all_by_obdata(C, id); - } - else if (idtype == ID_MA) { - changed = object_select_all_by_material(C, (Material *)id); - } - else if (idtype == ID_LI) { - changed = object_select_all_by_library(C, (Library *) id); - } - - if (changed) { - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + int idtype = GS(id->name); + bool changed = false; + + if (OB_DATA_SUPPORT_ID(idtype)) { + changed = object_select_all_by_obdata(C, id); + } + else if (idtype == ID_MA) { + changed = object_select_all_by_material(C, (Material *)id); + } + else if (idtype == ID_LI) { + changed = object_select_all_by_library(C, (Library *)id); + } + + if (changed) { + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } } static int object_select_linked_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Object *ob; - int nr = RNA_enum_get(op->ptr, "type"); - bool changed = false, extend; - - extend = RNA_boolean_get(op->ptr, "extend"); - - if (extend == 0) { - ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - } - - ob = OBACT(view_layer); - if (ob == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active object"); - return OPERATOR_CANCELLED; - } - - if (nr == OBJECT_SELECT_LINKED_IPO) { - // XXX old animation system - //if (ob->ipo == 0) return OPERATOR_CANCELLED; - //object_select_all_by_ipo(C, ob->ipo) - return OPERATOR_CANCELLED; - } - else if (nr == OBJECT_SELECT_LINKED_OBDATA) { - if (ob->data == NULL) - return OPERATOR_CANCELLED; - - changed = object_select_all_by_obdata(C, ob->data); - } - else if (nr == OBJECT_SELECT_LINKED_MATERIAL) { - Material *mat = NULL; - - mat = give_current_material(ob, ob->actcol); - if (mat == NULL) return OPERATOR_CANCELLED; - - changed = object_select_all_by_material(C, mat); - } - else if (nr == OBJECT_SELECT_LINKED_DUPGROUP) { - if (ob->instance_collection == NULL) - return OPERATOR_CANCELLED; - - changed = object_select_all_by_instance_collection(C, ob); - } - else if (nr == OBJECT_SELECT_LINKED_PARTICLE) { - if (BLI_listbase_is_empty(&ob->particlesystem)) - return OPERATOR_CANCELLED; - - changed = object_select_all_by_particle(C, ob); - } - else if (nr == OBJECT_SELECT_LINKED_LIBRARY) { - /* do nothing */ - changed = object_select_all_by_library(C, ob->id.lib); - } - else if (nr == OBJECT_SELECT_LINKED_LIBRARY_OBDATA) { - if (ob->data == NULL) - return OPERATOR_CANCELLED; - - changed = object_select_all_by_library_obdata(C, ((ID *) ob->data)->lib); - } - else - return OPERATOR_CANCELLED; - - if (changed) { - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Object *ob; + int nr = RNA_enum_get(op->ptr, "type"); + bool changed = false, extend; + + extend = RNA_boolean_get(op->ptr, "extend"); + + if (extend == 0) { + ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); + } + + ob = OBACT(view_layer); + if (ob == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active object"); + return OPERATOR_CANCELLED; + } + + if (nr == OBJECT_SELECT_LINKED_IPO) { + // XXX old animation system + //if (ob->ipo == 0) return OPERATOR_CANCELLED; + //object_select_all_by_ipo(C, ob->ipo) + return OPERATOR_CANCELLED; + } + else if (nr == OBJECT_SELECT_LINKED_OBDATA) { + if (ob->data == NULL) + return OPERATOR_CANCELLED; + + changed = object_select_all_by_obdata(C, ob->data); + } + else if (nr == OBJECT_SELECT_LINKED_MATERIAL) { + Material *mat = NULL; + + mat = give_current_material(ob, ob->actcol); + if (mat == NULL) + return OPERATOR_CANCELLED; + + changed = object_select_all_by_material(C, mat); + } + else if (nr == OBJECT_SELECT_LINKED_DUPGROUP) { + if (ob->instance_collection == NULL) + return OPERATOR_CANCELLED; + + changed = object_select_all_by_instance_collection(C, ob); + } + else if (nr == OBJECT_SELECT_LINKED_PARTICLE) { + if (BLI_listbase_is_empty(&ob->particlesystem)) + return OPERATOR_CANCELLED; + + changed = object_select_all_by_particle(C, ob); + } + else if (nr == OBJECT_SELECT_LINKED_LIBRARY) { + /* do nothing */ + changed = object_select_all_by_library(C, ob->id.lib); + } + else if (nr == OBJECT_SELECT_LINKED_LIBRARY_OBDATA) { + if (ob->data == NULL) + return OPERATOR_CANCELLED; + + changed = object_select_all_by_library_obdata(C, ((ID *)ob->data)->lib); + } + else + return OPERATOR_CANCELLED; + + if (changed) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } void OBJECT_OT_select_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Linked"; - ot->description = "Select all visible objects that are linked"; - ot->idname = "OBJECT_OT_select_linked"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_select_linked_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - ot->prop = RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", ""); + /* identifiers */ + ot->name = "Select Linked"; + ot->description = "Select all visible objects that are linked"; + ot->idname = "OBJECT_OT_select_linked"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_select_linked_exec; + ot->poll = objects_selectable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + false, + "Extend", + "Extend selection instead of deselecting everything first"); + ot->prop = RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", ""); } /** \} */ @@ -728,371 +736,379 @@ void OBJECT_OT_select_linked(wmOperatorType *ot) * \{ */ enum { - OBJECT_GRPSEL_CHILDREN_RECURSIVE = 0, - OBJECT_GRPSEL_CHILDREN = 1, - OBJECT_GRPSEL_PARENT = 2, - OBJECT_GRPSEL_SIBLINGS = 3, - OBJECT_GRPSEL_TYPE = 4, - OBJECT_GRPSEL_COLLECTION = 5, - OBJECT_GRPSEL_HOOK = 7, - OBJECT_GRPSEL_PASS = 8, - OBJECT_GRPSEL_COLOR = 9, - OBJECT_GRPSEL_KEYINGSET = 10, - OBJECT_GRPSEL_LIGHT_TYPE = 11, + OBJECT_GRPSEL_CHILDREN_RECURSIVE = 0, + OBJECT_GRPSEL_CHILDREN = 1, + OBJECT_GRPSEL_PARENT = 2, + OBJECT_GRPSEL_SIBLINGS = 3, + OBJECT_GRPSEL_TYPE = 4, + OBJECT_GRPSEL_COLLECTION = 5, + OBJECT_GRPSEL_HOOK = 7, + OBJECT_GRPSEL_PASS = 8, + OBJECT_GRPSEL_COLOR = 9, + OBJECT_GRPSEL_KEYINGSET = 10, + OBJECT_GRPSEL_LIGHT_TYPE = 11, }; static const EnumPropertyItem prop_select_grouped_types[] = { - {OBJECT_GRPSEL_CHILDREN_RECURSIVE, "CHILDREN_RECURSIVE", 0, "Children", ""}, - {OBJECT_GRPSEL_CHILDREN, "CHILDREN", 0, "Immediate Children", ""}, - {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, - {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, - {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, - {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, - {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, - {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, - {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"}, - {OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, - {OBJECT_GRPSEL_LIGHT_TYPE, "LIGHT_TYPE", 0, "Light Type", "Matching light types"}, - {0, NULL, 0, NULL, NULL}, + {OBJECT_GRPSEL_CHILDREN_RECURSIVE, "CHILDREN_RECURSIVE", 0, "Children", ""}, + {OBJECT_GRPSEL_CHILDREN, "CHILDREN", 0, "Immediate Children", ""}, + {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""}, + {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, + {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, + {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, + {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, + {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, + {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"}, + {OBJECT_GRPSEL_KEYINGSET, + "KEYINGSET", + 0, + "Keying Set", + "Objects included in active Keying Set"}, + {OBJECT_GRPSEL_LIGHT_TYPE, "LIGHT_TYPE", 0, "Light Type", "Matching light types"}, + {0, NULL, 0, NULL, NULL}, }; static bool select_grouped_children(bContext *C, Object *ob, const bool recursive) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if (ob == base->object->parent) { - if ((base->flag & BASE_SELECTED) == 0) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - - if (recursive) { - changed |= select_grouped_children(C, base->object, 1); - } - } - } - CTX_DATA_END; - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if (ob == base->object->parent) { + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + + if (recursive) { + changed |= select_grouped_children(C, base->object, 1); + } + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */ { - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Base *baspar, *basact = CTX_data_active_base(C); - bool changed = false; - - if (!basact || !(basact->object->parent)) { - return 0; /* we know OBACT is valid */ - } - - baspar = BKE_view_layer_base_find(view_layer, basact->object->parent); - - /* can be NULL if parent in other scene */ - if (baspar && BASE_SELECTABLE(v3d, baspar)) { - ED_object_base_select(baspar, BA_SELECT); - ED_object_base_activate(C, baspar); - changed = true; - } - return changed; + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Base *baspar, *basact = CTX_data_active_base(C); + bool changed = false; + + if (!basact || !(basact->object->parent)) { + return 0; /* we know OBACT is valid */ + } + + baspar = BKE_view_layer_base_find(view_layer, basact->object->parent); + + /* can be NULL if parent in other scene */ + if (baspar && BASE_SELECTABLE(v3d, baspar)) { + ED_object_base_select(baspar, BA_SELECT); + ED_object_base_activate(C, baspar); + changed = true; + } + return changed; } - -#define COLLECTION_MENU_MAX 24 +#define COLLECTION_MENU_MAX 24 /* Select objects in the same group as the active */ static bool select_grouped_collection(bContext *C, Object *ob) { - bool changed = false; - Collection *collection, *ob_collections[COLLECTION_MENU_MAX]; - int collection_count = 0, i; - uiPopupMenu *pup; - uiLayout *layout; - - for (collection = CTX_data_main(C)->collections.first; collection && collection_count < COLLECTION_MENU_MAX; collection = collection->id.next) { - if (BKE_collection_has_object(collection, ob)) { - ob_collections[collection_count] = collection; - collection_count++; - } - } - - if (!collection_count) - return 0; - else if (collection_count == 1) { - collection = ob_collections[0]; - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (BKE_collection_has_object(collection, base->object)) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - return changed; - } - - /* build the menu. */ - pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - for (i = 0; i < collection_count; i++) { - collection = ob_collections[i]; - uiItemStringO(layout, collection->id.name + 2, 0, "OBJECT_OT_select_same_collection", "collection", collection->id.name + 2); - } - - UI_popup_menu_end(C, pup); - return changed; /* The operator already handle this! */ + bool changed = false; + Collection *collection, *ob_collections[COLLECTION_MENU_MAX]; + int collection_count = 0, i; + uiPopupMenu *pup; + uiLayout *layout; + + for (collection = CTX_data_main(C)->collections.first; + collection && collection_count < COLLECTION_MENU_MAX; + collection = collection->id.next) { + if (BKE_collection_has_object(collection, ob)) { + ob_collections[collection_count] = collection; + collection_count++; + } + } + + if (!collection_count) + return 0; + else if (collection_count == 1) { + collection = ob_collections[0]; + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (BKE_collection_has_object(collection, base->object)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + return changed; + } + + /* build the menu. */ + pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + + for (i = 0; i < collection_count; i++) { + collection = ob_collections[i]; + uiItemStringO(layout, + collection->id.name + 2, + 0, + "OBJECT_OT_select_same_collection", + "collection", + collection->id.name + 2); + } + + UI_popup_menu_end(C, pup); + return changed; /* The operator already handle this! */ } static bool select_grouped_object_hooks(bContext *C, Object *ob) { - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - - bool changed = false; - Base *base; - ModifierData *md; - HookModifierData *hmd; - - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - hmd = (HookModifierData *) md; - if (hmd->object) { - base = BKE_view_layer_base_find(view_layer, hmd->object); - if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(v3d, base))) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - } - return changed; + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + + bool changed = false; + Base *base; + ModifierData *md; + HookModifierData *hmd; + + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Hook) { + hmd = (HookModifierData *)md; + if (hmd->object) { + base = BKE_view_layer_base_find(view_layer, hmd->object); + if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(v3d, base))) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + } + return changed; } /* Select objects with the same parent as the active (siblings), * parent can be NULL also */ static bool select_grouped_siblings(bContext *C, Object *ob) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if ((base->object->parent == ob->parent) && ((base->flag & BASE_SELECTED) == 0)) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if ((base->object->parent == ob->parent) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_lighttype(bContext *C, Object *ob) { - Light *la = ob->data; - - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if (base->object->type == OB_LAMP) { - Light *la_test = base->object->data; - if ((la->type == la_test->type) && ((base->flag & BASE_SELECTED) == 0)) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - } - CTX_DATA_END; - return changed; + Light *la = ob->data; + + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if (base->object->type == OB_LAMP) { + Light *la_test = base->object->data; + if ((la->type == la_test->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_type(bContext *C, Object *ob) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_index_object(bContext *C, Object *ob) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_color(bContext *C, Object *ob) { - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && (compare_v3v3(base->object->color, ob->color, 0.005f))) { - ED_object_base_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; + bool changed = false; + + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if (((base->flag & BASE_SELECTED) == 0) && + (compare_v3v3(base->object->color, ob->color, 0.005f))) { + ED_object_base_select(base, BA_SELECT); + changed = true; + } + } + CTX_DATA_END; + return changed; } static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList *reports) { - KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C)); - bool changed = false; - - /* firstly, validate KeyingSet */ - if (ks == NULL) { - BKE_report(reports, RPT_ERROR, "No active Keying Set to use"); - return false; - } - else if (ANIM_validate_keyingset(C, NULL, ks) != 0) { - if (ks->paths.first == NULL) { - if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - BKE_report(reports, RPT_ERROR, - "Use another Keying Set, as the active one depends on the currently " - "selected objects or cannot find any targets due to unsuitable context"); - } - else { - BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths"); - } - } - return false; - } - - /* select each object that Keying Set refers to */ - /* TODO: perhaps to be more in line with the rest of these, we should only take objects - * if the passed in object is included in this too */ - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - /* only check for this object if it isn't selected already, to limit time wasted */ - if ((base->flag & BASE_SELECTED) == 0) { - KS_Path *ksp; - - /* this is the slow way... we could end up with > 500 items here, - * with none matching, but end up doing this on 1000 objects... - */ - for (ksp = ks->paths.first; ksp; ksp = ksp->next) { - /* if id matches, select then stop looping (match found) */ - if (ksp->id == (ID *)base->object) { - ED_object_base_select(base, BA_SELECT); - changed = true; - break; - } - } - } - } - CTX_DATA_END; - - return changed; + KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C)); + bool changed = false; + + /* firstly, validate KeyingSet */ + if (ks == NULL) { + BKE_report(reports, RPT_ERROR, "No active Keying Set to use"); + return false; + } + else if (ANIM_validate_keyingset(C, NULL, ks) != 0) { + if (ks->paths.first == NULL) { + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { + BKE_report(reports, + RPT_ERROR, + "Use another Keying Set, as the active one depends on the currently " + "selected objects or cannot find any targets due to unsuitable context"); + } + else { + BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths"); + } + } + return false; + } + + /* select each object that Keying Set refers to */ + /* TODO: perhaps to be more in line with the rest of these, we should only take objects + * if the passed in object is included in this too */ + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + /* only check for this object if it isn't selected already, to limit time wasted */ + if ((base->flag & BASE_SELECTED) == 0) { + KS_Path *ksp; + + /* this is the slow way... we could end up with > 500 items here, + * with none matching, but end up doing this on 1000 objects... + */ + for (ksp = ks->paths.first; ksp; ksp = ksp->next) { + /* if id matches, select then stop looping (match found) */ + if (ksp->id == (ID *)base->object) { + ED_object_base_select(base, BA_SELECT); + changed = true; + break; + } + } + } + } + CTX_DATA_END; + + return changed; } static int object_select_grouped_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - Object *ob; - const int type = RNA_enum_get(op->ptr, "type"); - bool changed = false, extend; - - extend = RNA_boolean_get(op->ptr, "extend"); - - if (extend == 0) { - changed = ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - } - - ob = OBACT(view_layer); - if (ob == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active object"); - return OPERATOR_CANCELLED; - } - - switch (type) { - case OBJECT_GRPSEL_CHILDREN_RECURSIVE: - changed |= select_grouped_children(C, ob, true); - break; - case OBJECT_GRPSEL_CHILDREN: - changed |= select_grouped_children(C, ob, false); - break; - case OBJECT_GRPSEL_PARENT: - changed |= select_grouped_parent(C); - break; - case OBJECT_GRPSEL_SIBLINGS: - changed |= select_grouped_siblings(C, ob); - break; - case OBJECT_GRPSEL_TYPE: - changed |= select_grouped_type(C, ob); - break; - case OBJECT_GRPSEL_COLLECTION: - changed |= select_grouped_collection(C, ob); - break; - case OBJECT_GRPSEL_HOOK: - changed |= select_grouped_object_hooks(C, ob); - break; - case OBJECT_GRPSEL_PASS: - changed |= select_grouped_index_object(C, ob); - break; - case OBJECT_GRPSEL_COLOR: - changed |= select_grouped_color(C, ob); - break; - case OBJECT_GRPSEL_KEYINGSET: - changed |= select_grouped_keyingset(C, ob, op->reports); - break; - case OBJECT_GRPSEL_LIGHT_TYPE: - if (ob->type != OB_LAMP) { - BKE_report(op->reports, RPT_ERROR, "Active object must be a light"); - break; - } - changed |= select_grouped_lighttype(C, ob); - break; - default: - break; - } - - if (changed) { - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Object *ob; + const int type = RNA_enum_get(op->ptr, "type"); + bool changed = false, extend; + + extend = RNA_boolean_get(op->ptr, "extend"); + + if (extend == 0) { + changed = ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); + } + + ob = OBACT(view_layer); + if (ob == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active object"); + return OPERATOR_CANCELLED; + } + + switch (type) { + case OBJECT_GRPSEL_CHILDREN_RECURSIVE: + changed |= select_grouped_children(C, ob, true); + break; + case OBJECT_GRPSEL_CHILDREN: + changed |= select_grouped_children(C, ob, false); + break; + case OBJECT_GRPSEL_PARENT: + changed |= select_grouped_parent(C); + break; + case OBJECT_GRPSEL_SIBLINGS: + changed |= select_grouped_siblings(C, ob); + break; + case OBJECT_GRPSEL_TYPE: + changed |= select_grouped_type(C, ob); + break; + case OBJECT_GRPSEL_COLLECTION: + changed |= select_grouped_collection(C, ob); + break; + case OBJECT_GRPSEL_HOOK: + changed |= select_grouped_object_hooks(C, ob); + break; + case OBJECT_GRPSEL_PASS: + changed |= select_grouped_index_object(C, ob); + break; + case OBJECT_GRPSEL_COLOR: + changed |= select_grouped_color(C, ob); + break; + case OBJECT_GRPSEL_KEYINGSET: + changed |= select_grouped_keyingset(C, ob, op->reports); + break; + case OBJECT_GRPSEL_LIGHT_TYPE: + if (ob->type != OB_LAMP) { + BKE_report(op->reports, RPT_ERROR, "Active object must be a light"); + break; + } + changed |= select_grouped_lighttype(C, ob); + break; + default: + break; + } + + if (changed) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } void OBJECT_OT_select_grouped(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Grouped"; - ot->description = "Select all visible objects grouped by various properties"; - ot->idname = "OBJECT_OT_select_grouped"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_select_grouped_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); + /* identifiers */ + ot->name = "Select Grouped"; + ot->description = "Select all visible objects grouped by various properties"; + ot->idname = "OBJECT_OT_select_grouped"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_select_grouped_exec; + ot->poll = objects_selectable_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + false, + "Extend", + "Extend selection instead of deselecting everything first"); + ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); } /** \} */ @@ -1103,46 +1119,46 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot) static int object_select_all_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - int action = RNA_enum_get(op->ptr, "action"); - bool any_visible = false; - - bool changed = ED_object_base_deselect_all_ex(view_layer, v3d, action, &any_visible); - - if (changed) { - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; - } - else if (any_visible == false) { - /* TODO(campbell): Looks like we could remove this, - * if not comment should say why its needed. */ - return OPERATOR_PASS_THROUGH; - } - else { - return OPERATOR_CANCELLED; - } + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + int action = RNA_enum_get(op->ptr, "action"); + bool any_visible = false; + + bool changed = ED_object_base_deselect_all_ex(view_layer, v3d, action, &any_visible); + + if (changed) { + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; + } + else if (any_visible == false) { + /* TODO(campbell): Looks like we could remove this, + * if not comment should say why its needed. */ + return OPERATOR_PASS_THROUGH; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select All"; - ot->description = "Change selection of all visible objects in scene"; - ot->idname = "OBJECT_OT_select_all"; + /* identifiers */ + ot->name = "(De)select All"; + ot->description = "Change selection of all visible objects in scene"; + ot->idname = "OBJECT_OT_select_all"; - /* api callbacks */ - ot->exec = object_select_all_exec; - ot->poll = objects_selectable_poll; + /* api callbacks */ + ot->exec = object_select_all_exec; + ot->poll = objects_selectable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_select_all(ot); + WM_operator_properties_select_all(ot); } /** \} */ @@ -1153,54 +1169,55 @@ void OBJECT_OT_select_all(wmOperatorType *ot) static int object_select_same_collection_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Collection *collection; - char collection_name[MAX_ID_NAME]; + Main *bmain = CTX_data_main(C); + Collection *collection; + char collection_name[MAX_ID_NAME]; - /* passthrough if no objects are visible */ - if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; + /* passthrough if no objects are visible */ + if (CTX_DATA_COUNT(C, visible_bases) == 0) + return OPERATOR_PASS_THROUGH; - RNA_string_get(op->ptr, "collection", collection_name); + RNA_string_get(op->ptr, "collection", collection_name); - collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, collection_name); + collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, collection_name); - if (!collection) { - return OPERATOR_PASS_THROUGH; - } + if (!collection) { + return OPERATOR_PASS_THROUGH; + } - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { - if (BKE_collection_has_object(collection, base->object)) { - ED_object_base_select(base, BA_SELECT); - } - } - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Base *, base, visible_bases) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + if (BKE_collection_has_object(collection, base->object)) { + ED_object_base_select(base, BA_SELECT); + } + } + } + CTX_DATA_END; - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_select_same_collection(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Same Collection"; - ot->description = "Select object in the same collection"; - ot->idname = "OBJECT_OT_select_same_collection"; + /* identifiers */ + ot->name = "Select Same Collection"; + ot->description = "Select object in the same collection"; + ot->idname = "OBJECT_OT_select_same_collection"; - /* api callbacks */ - ot->exec = object_select_same_collection_exec; - ot->poll = objects_selectable_poll; + /* api callbacks */ + ot->exec = object_select_same_collection_exec; + ot->poll = objects_selectable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_string(ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select"); + RNA_def_string( + ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select"); } /** \} */ @@ -1211,58 +1228,58 @@ void OBJECT_OT_select_same_collection(wmOperatorType *ot) static int object_select_mirror_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - bool extend; - - extend = RNA_boolean_get(op->ptr, "extend"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + bool extend; - CTX_DATA_BEGIN (C, Base *, primbase, selected_bases) - { - char name_flip[MAXBONENAME]; + extend = RNA_boolean_get(op->ptr, "extend"); - BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip)); + CTX_DATA_BEGIN (C, Base *, primbase, selected_bases) { + char name_flip[MAXBONENAME]; - if (!STREQ(name_flip, primbase->object->id.name + 2)) { - Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip); - if (ob) { - Base *secbase = BKE_view_layer_base_find(view_layer, ob); + BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip)); - if (secbase) { - ED_object_base_select(secbase, BA_SELECT); - } - } - } + if (!STREQ(name_flip, primbase->object->id.name + 2)) { + Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip); + if (ob) { + Base *secbase = BKE_view_layer_base_find(view_layer, ob); - if (extend == false) ED_object_base_select(primbase, BA_DESELECT); + if (secbase) { + ED_object_base_select(secbase, BA_SELECT); + } + } + } - } - CTX_DATA_END; + if (extend == false) + ED_object_base_select(primbase, BA_DESELECT); + } + CTX_DATA_END; - /* undo? */ - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + /* undo? */ + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_select_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Mirror"; - ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword"; - ot->idname = "OBJECT_OT_select_mirror"; + /* identifiers */ + ot->name = "Select Mirror"; + ot->description = "Select the Mirror objects of the selected object eg. L.sword -> R.sword"; + ot->idname = "OBJECT_OT_select_mirror"; - /* api callbacks */ - ot->exec = object_select_mirror_exec; - ot->poll = objects_selectable_poll; + /* api callbacks */ + ot->exec = object_select_mirror_exec; + ot->poll = objects_selectable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); + RNA_def_boolean( + ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); } /** \} */ @@ -1273,116 +1290,114 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) static bool object_select_more_less(bContext *C, const bool select) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - Object *ob = base->object; - ob->flag &= ~OB_DONE; - ob->id.tag &= ~LIB_TAG_DOIT; - /* parent may be in another scene */ - if (ob->parent) { - ob->parent->flag &= ~OB_DONE; - ob->parent->id.tag &= ~LIB_TAG_DOIT; - } - } - - ListBase ctx_base_list; - CollectionPointerLink *ctx_base; - CTX_data_selectable_bases(C, &ctx_base_list); - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - ob->flag |= OB_DONE; - } - CTX_DATA_END; - - - for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { - Object *ob = ((Base *)ctx_base->ptr.data)->object; - if (ob->parent) { - if ((ob->flag & OB_DONE) != (ob->parent->flag & OB_DONE)) { - ob->id.tag |= LIB_TAG_DOIT; - ob->parent->id.tag |= LIB_TAG_DOIT; - } - } - } - - bool changed = false; - const short select_mode = select ? BA_SELECT : BA_DESELECT; - const short select_flag = select ? BASE_SELECTED : 0; - - for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { - Base *base = ctx_base->ptr.data; - Object *ob = base->object; - if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) { - ED_object_base_select(base, select_mode); - changed = true; - } - } - - BLI_freelistN(&ctx_base_list); - - return changed; + ViewLayer *view_layer = CTX_data_view_layer(C); + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + Object *ob = base->object; + ob->flag &= ~OB_DONE; + ob->id.tag &= ~LIB_TAG_DOIT; + /* parent may be in another scene */ + if (ob->parent) { + ob->parent->flag &= ~OB_DONE; + ob->parent->id.tag &= ~LIB_TAG_DOIT; + } + } + + ListBase ctx_base_list; + CollectionPointerLink *ctx_base; + CTX_data_selectable_bases(C, &ctx_base_list); + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + ob->flag |= OB_DONE; + } + CTX_DATA_END; + + for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { + Object *ob = ((Base *)ctx_base->ptr.data)->object; + if (ob->parent) { + if ((ob->flag & OB_DONE) != (ob->parent->flag & OB_DONE)) { + ob->id.tag |= LIB_TAG_DOIT; + ob->parent->id.tag |= LIB_TAG_DOIT; + } + } + } + + bool changed = false; + const short select_mode = select ? BA_SELECT : BA_DESELECT; + const short select_flag = select ? BASE_SELECTED : 0; + + for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { + Base *base = ctx_base->ptr.data; + Object *ob = base->object; + if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) { + ED_object_base_select(base, select_mode); + changed = true; + } + } + + BLI_freelistN(&ctx_base_list); + + return changed; } static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op)) { - bool changed = object_select_more_less(C, true); - - if (changed) { - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + bool changed = object_select_more_less(C, true); + + if (changed) { + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_select_more(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select More"; - ot->idname = "OBJECT_OT_select_more"; - ot->description = "Select connected parent/child objects"; + /* identifiers */ + ot->name = "Select More"; + ot->idname = "OBJECT_OT_select_more"; + ot->description = "Select connected parent/child objects"; - /* api callbacks */ - ot->exec = object_select_more_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_select_more_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { - bool changed = object_select_more_less(C, false); - - if (changed) { - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + bool changed = object_select_more_less(C, false); + + if (changed) { + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_select_less(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Less"; - ot->idname = "OBJECT_OT_select_less"; - ot->description = "Deselect objects at the boundaries of parent/child relationships"; + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "OBJECT_OT_select_less"; + ot->description = "Deselect objects at the boundaries of parent/child relationships"; - /* api callbacks */ - ot->exec = object_select_less_exec; - ot->poll = ED_operator_objectmode; + /* api callbacks */ + ot->exec = object_select_less_exec; + ot->poll = ED_operator_objectmode; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -1393,46 +1408,45 @@ void OBJECT_OT_select_less(wmOperatorType *ot) static int object_select_random_exec(bContext *C, wmOperator *op) { - const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; - const int seed = WM_operator_properties_select_random_seed_increment_get(op); - const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + const int seed = WM_operator_properties_select_random_seed_increment_get(op); + const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); - RNG *rng = BLI_rng_new_srandom(seed); + RNG *rng = BLI_rng_new_srandom(seed); - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if (BLI_rng_get_float(rng) < randfac) { - ED_object_base_select(base, select); - } - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { + if (BLI_rng_get_float(rng) < randfac) { + ED_object_base_select(base, select); + } + } + CTX_DATA_END; - BLI_rng_free(rng); + BLI_rng_free(rng); - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_select_random(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Random"; - ot->description = "Set select on random visible objects"; - ot->idname = "OBJECT_OT_select_random"; + /* identifiers */ + ot->name = "Select Random"; + ot->description = "Set select on random visible objects"; + ot->idname = "OBJECT_OT_select_random"; - /* api callbacks */ - /*ot->invoke = object_select_random_invoke XXX - need a number popup ;*/ - ot->exec = object_select_random_exec; - ot->poll = objects_selectable_poll; + /* api callbacks */ + /*ot->invoke = object_select_random_invoke XXX - need a number popup ;*/ + ot->exec = object_select_random_exec; + ot->poll = objects_selectable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_select_random(ot); + /* properties */ + WM_operator_properties_select_random(ot); } /** \} */ diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index 8580ea10d35..64535d8f281 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -63,400 +62,410 @@ /******************************** API ****************************/ -ShaderFxData *ED_object_shaderfx_add(ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) +ShaderFxData *ED_object_shaderfx_add( + ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) { - ShaderFxData *new_fx = NULL; - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + ShaderFxData *new_fx = NULL; + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); - if (ob->type != OB_GPENCIL) { - BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2); - return NULL; - } + if (ob->type != OB_GPENCIL) { + BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2); + return NULL; + } - if (fxi->flags & eShaderFxTypeFlag_Single) { - if (BKE_shaderfx_findByType(ob, type)) { - BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed"); - return NULL; - } - } + if (fxi->flags & eShaderFxTypeFlag_Single) { + if (BKE_shaderfx_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed"); + return NULL; + } + } - /* get new effect data to add */ - new_fx = BKE_shaderfx_new(type); + /* get new effect data to add */ + new_fx = BKE_shaderfx_new(type); - BLI_addtail(&ob->shader_fx, new_fx); + BLI_addtail(&ob->shader_fx, new_fx); - if (name) { - BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name)); - } + if (name) { + BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name)); + } - /* make sure effect data has unique name */ - BKE_shaderfx_unique_name(&ob->shader_fx, new_fx); + /* make sure effect data has unique name */ + BKE_shaderfx_unique_name(&ob->shader_fx, new_fx); - bGPdata *gpd = ob->data; - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); - return new_fx; + return new_fx; } /* Return true if the object has a effect of type 'type' other than * the shaderfx pointed to be 'exclude', otherwise returns false. */ -static bool UNUSED_FUNCTION(object_has_shaderfx)( - const Object *ob, const ShaderFxData *exclude, - ShaderFxType type) +static bool UNUSED_FUNCTION(object_has_shaderfx)(const Object *ob, + const ShaderFxData *exclude, + ShaderFxType type) { - ShaderFxData *fx; + ShaderFxData *fx; - for (fx = ob->shader_fx.first; fx; fx = fx->next) { - if ((fx != exclude) && (fx->type == type)) - return true; - } + for (fx = ob->shader_fx.first; fx; fx = fx->next) { + if ((fx != exclude) && (fx->type == type)) + return true; + } - return false; + return false; } -static bool object_shaderfx_remove( - Main *bmain, Object *ob, ShaderFxData *fx, - bool *UNUSED(r_sort_depsgraph)) +static bool object_shaderfx_remove(Main *bmain, + Object *ob, + ShaderFxData *fx, + bool *UNUSED(r_sort_depsgraph)) { - /* It seems on rapid delete it is possible to - * get called twice on same effect, so make - * sure it is in list. */ - if (BLI_findindex(&ob->shader_fx, fx) == -1) { - return 0; - } + /* It seems on rapid delete it is possible to + * get called twice on same effect, so make + * sure it is in list. */ + if (BLI_findindex(&ob->shader_fx, fx) == -1) { + return 0; + } - DEG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); - BLI_remlink(&ob->shader_fx, fx); - BKE_shaderfx_free(fx); - BKE_object_free_derived_caches(ob); + BLI_remlink(&ob->shader_fx, fx); + BKE_shaderfx_free(fx); + BKE_object_free_derived_caches(ob); - return 1; + return 1; } bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx) { - bool sort_depsgraph = false; - bool ok; + bool sort_depsgraph = false; + bool ok; - ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); + ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); - if (!ok) { - BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name); - return 0; - } + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name); + return 0; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); - return 1; + return 1; } void ED_object_shaderfx_clear(Main *bmain, Object *ob) { - ShaderFxData *fx = ob->shader_fx.first; - bool sort_depsgraph = false; + ShaderFxData *fx = ob->shader_fx.first; + bool sort_depsgraph = false; - if (!fx) - return; + if (!fx) + return; - while (fx) { - ShaderFxData *next_fx; + while (fx) { + ShaderFxData *next_fx; - next_fx = fx->next; + next_fx = fx->next; - object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); + object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); - fx = next_fx; - } + fx = next_fx; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(bmain); } int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx) { - if (fx->prev) { - BLI_remlink(&ob->shader_fx, fx); - BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx); - } + if (fx->prev) { + BLI_remlink(&ob->shader_fx, fx); + BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx); + } - return 1; + return 1; } int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx) { - if (fx->next) { - BLI_remlink(&ob->shader_fx, fx); - BLI_insertlinkafter(&ob->shader_fx, fx->next, fx); - } + if (fx->next) { + BLI_remlink(&ob->shader_fx, fx); + BLI_insertlinkafter(&ob->shader_fx, fx->next, fx); + } - return 1; + return 1; } /************************ add effect operator *********************/ static int shaderfx_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); - int type = RNA_enum_get(op->ptr, "type"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); - if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type)) - return OPERATOR_CANCELLED; + if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static const EnumPropertyItem *shaderfx_add_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *shaderfx_add_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *ob = ED_object_active_context(C); - EnumPropertyItem *item = NULL; - const EnumPropertyItem *fx_item, *group_item = NULL; - const ShaderFxTypeInfo *mti; - int totitem = 0, a; - - if (!ob) - return rna_enum_object_shaderfx_type_items; - - for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) { - fx_item = &rna_enum_object_shaderfx_type_items[a]; - if (fx_item->identifier[0]) { - mti = BKE_shaderfxType_getInfo(fx_item->value); - - if (mti->flags & eShaderFxTypeFlag_NoUserAdd) - continue; - } - else { - group_item = fx_item; - fx_item = NULL; - - continue; - } - - if (group_item) { - RNA_enum_item_add(&item, &totitem, group_item); - group_item = NULL; - } - - RNA_enum_item_add(&item, &totitem, fx_item); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Object *ob = ED_object_active_context(C); + EnumPropertyItem *item = NULL; + const EnumPropertyItem *fx_item, *group_item = NULL; + const ShaderFxTypeInfo *mti; + int totitem = 0, a; + + if (!ob) + return rna_enum_object_shaderfx_type_items; + + for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) { + fx_item = &rna_enum_object_shaderfx_type_items[a]; + if (fx_item->identifier[0]) { + mti = BKE_shaderfxType_getInfo(fx_item->value); + + if (mti->flags & eShaderFxTypeFlag_NoUserAdd) + continue; + } + else { + group_item = fx_item; + fx_item = NULL; + + continue; + } + + if (group_item) { + RNA_enum_item_add(&item, &totitem, group_item); + group_item = NULL; + } + + RNA_enum_item_add(&item, &totitem, fx_item); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } void OBJECT_OT_shaderfx_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Effect"; - ot->description = "Add a visual effect to the active object"; - ot->idname = "OBJECT_OT_shaderfx_add"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = shaderfx_add_exec; - ot->poll = ED_operator_object_active_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", ""); - RNA_def_enum_funcs(ot->prop, shaderfx_add_itemf); - RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID); /* Abused, for "Light"... */ + /* identifiers */ + ot->name = "Add Effect"; + ot->description = "Add a visual effect to the active object"; + ot->idname = "OBJECT_OT_shaderfx_add"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = shaderfx_add_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum( + ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", ""); + RNA_def_enum_funcs(ot->prop, shaderfx_add_itemf); + RNA_def_property_translation_context(ot->prop, + BLT_I18NCONTEXT_ID_ID); /* Abused, for "Light"... */ } /************************ generic functions for operators using names and data context *********************/ static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) { - PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type); - Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - - if (!ptr.data) { - CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'"); - return 0; - } - - if (!ob || ID_IS_LINKED(ob)) return 0; - if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; - if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0; - - if (ID_IS_STATIC_OVERRIDE(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from static override"); - return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0; - } - - return 1; + PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + + if (!ptr.data) { + CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'"); + return 0; + } + + if (!ob || ID_IS_LINKED(ob)) + return 0; + if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) + return 0; + if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) + return 0; + + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from static override"); + return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0; + } + + return 1; } static bool edit_shaderfx_poll(bContext *C) { - return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); + return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); } static void edit_shaderfx_properties(wmOperatorType *ot) { - PropertyRNA *prop = RNA_def_string(ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_def_string( + ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit"); + RNA_def_property_flag(prop, PROP_HIDDEN); } static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op) { - ShaderFxData *fx; - - if (RNA_struct_property_is_set(op->ptr, "shaderfx")) { - return true; - } - else { - PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx); - if (ptr.data) { - fx = ptr.data; - RNA_string_set(op->ptr, "shaderfx", fx->name); - return true; - } - } - - return false; + ShaderFxData *fx; + + if (RNA_struct_property_is_set(op->ptr, "shaderfx")) { + return true; + } + else { + PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx); + if (ptr.data) { + fx = ptr.data; + RNA_string_set(op->ptr, "shaderfx", fx->name); + return true; + } + } + + return false; } static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type) { - char shaderfx_name[MAX_NAME]; - ShaderFxData *fx; - RNA_string_get(op->ptr, "shaderfx", shaderfx_name); + char shaderfx_name[MAX_NAME]; + ShaderFxData *fx; + RNA_string_get(op->ptr, "shaderfx", shaderfx_name); - fx = BKE_shaderfx_findByName(ob, shaderfx_name); + fx = BKE_shaderfx_findByName(ob, shaderfx_name); - if (fx && type != 0 && fx->type != type) - fx = NULL; + if (fx && type != 0 && fx->type != type) + fx = NULL; - return fx; + return fx; } /************************ remove shaderfx operator *********************/ static int shaderfx_remove_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_active_context(C); - ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); - if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) - return OPERATOR_CANCELLED; + if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_shaderfx_invoke_properties(C, op)) - return shaderfx_remove_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_remove_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_shaderfx_remove(wmOperatorType *ot) { - ot->name = "Remove Grease Pencil Modifier"; - ot->description = "Remove a shaderfx from the active grease pencil object"; - ot->idname = "OBJECT_OT_shaderfx_remove"; + ot->name = "Remove Grease Pencil Modifier"; + ot->description = "Remove a shaderfx from the active grease pencil object"; + ot->idname = "OBJECT_OT_shaderfx_remove"; - ot->invoke = shaderfx_remove_invoke; - ot->exec = shaderfx_remove_exec; - ot->poll = edit_shaderfx_poll; + ot->invoke = shaderfx_remove_invoke; + ot->exec = shaderfx_remove_exec; + ot->poll = edit_shaderfx_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_shaderfx_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); } /************************ move up shaderfx operator *********************/ static int shaderfx_move_up_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); - if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) - return OPERATOR_CANCELLED; + if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_shaderfx_invoke_properties(C, op)) - return shaderfx_move_up_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot) { - ot->name = "Move Up Modifier"; - ot->description = "Move shaderfx up in the stack"; - ot->idname = "OBJECT_OT_shaderfx_move_up"; + ot->name = "Move Up Modifier"; + ot->description = "Move shaderfx up in the stack"; + ot->idname = "OBJECT_OT_shaderfx_move_up"; - ot->invoke = shaderfx_move_up_invoke; - ot->exec = shaderfx_move_up_exec; - ot->poll = edit_shaderfx_poll; + ot->invoke = shaderfx_move_up_invoke; + ot->exec = shaderfx_move_up_exec; + ot->poll = edit_shaderfx_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_shaderfx_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); } /************************ move down shaderfx operator *********************/ static int shaderfx_move_down_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); - if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) - return OPERATOR_CANCELLED; + if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) + return OPERATOR_CANCELLED; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_shaderfx_invoke_properties(C, op)) - return shaderfx_move_down_exec(C, op); - else - return OPERATOR_CANCELLED; + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; } void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot) { - ot->name = "Move Down Modifier"; - ot->description = "Move shaderfx down in the stack"; - ot->idname = "OBJECT_OT_shaderfx_move_down"; + ot->name = "Move Down Modifier"; + ot->description = "Move shaderfx down in the stack"; + ot->idname = "OBJECT_OT_shaderfx_move_down"; - ot->invoke = shaderfx_move_down_invoke; - ot->exec = shaderfx_move_down_exec; - ot->poll = edit_shaderfx_poll; + ot->invoke = shaderfx_move_down_invoke; + ot->exec = shaderfx_move_down_exec; + ot->poll = edit_shaderfx_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - edit_shaderfx_properties(ot); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); } diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index d445177f236..aa0c6cbeef4 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -21,14 +21,13 @@ * \ingroup edobj */ - #include <math.h> #include <string.h> #ifndef WIN32 -#include <unistd.h> +# include <unistd.h> #else -#include <io.h> +# include <io.h> #endif #include "MEM_guardedalloc.h" @@ -54,7 +53,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "BLI_sys_types.h" // for intptr_t support +#include "BLI_sys_types.h" // for intptr_t support #include "ED_object.h" #include "ED_mesh.h" @@ -71,429 +70,434 @@ static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix) { - Main *bmain = CTX_data_main(C); - KeyBlock *kb; - if ((kb = BKE_object_shapekey_insert(bmain, ob, NULL, from_mix))) { - Key *key = BKE_key_from_object(ob); - /* for absolute shape keys, new keys may not be added last */ - ob->shapenr = BLI_findindex(&key->block, kb) + 1; - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } + Main *bmain = CTX_data_main(C); + KeyBlock *kb; + if ((kb = BKE_object_shapekey_insert(bmain, ob, NULL, from_mix))) { + Key *key = BKE_key_from_object(ob); + /* for absolute shape keys, new keys may not be added last */ + ob->shapenr = BLI_findindex(&key->block, kb) + 1; + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } } /*********************** remove shape key ***********************/ static bool object_shapekey_remove(Main *bmain, Object *ob) { - KeyBlock *kb; - Key *key = BKE_key_from_object(ob); + KeyBlock *kb; + Key *key = BKE_key_from_object(ob); - if (key == NULL) { - return false; - } + if (key == NULL) { + return false; + } - kb = BLI_findlink(&key->block, ob->shapenr - 1); - if (kb) { - return BKE_object_shapekey_remove(bmain, ob, kb); - } + kb = BLI_findlink(&key->block, ob->shapenr - 1); + if (kb) { + return BKE_object_shapekey_remove(bmain, ob, kb); + } - return false; + return false; } -static bool object_shape_key_mirror(bContext *C, Object *ob, - int *r_totmirr, int *r_totfail, bool use_topology) +static bool object_shape_key_mirror( + bContext *C, Object *ob, int *r_totmirr, int *r_totfail, bool use_topology) { - KeyBlock *kb; - Key *key; - int totmirr = 0, totfail = 0; - - *r_totmirr = *r_totfail = 0; - - key = BKE_key_from_object(ob); - if (key == NULL) - return 0; - - kb = BLI_findlink(&key->block, ob->shapenr - 1); - - if (kb) { - char *tag_elem = MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror"); - - - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - MVert *mv; - int i1, i2; - float *fp1, *fp2; - float tvec[3]; - - ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); - - for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) { - i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology); - if (i2 == i1) { - fp1 = ((float *)kb->data) + i1 * 3; - fp1[0] = -fp1[0]; - tag_elem[i1] = 1; - totmirr++; - } - else if (i2 != -1) { - if (tag_elem[i1] == 0 && tag_elem[i2] == 0) { - fp1 = ((float *)kb->data) + i1 * 3; - fp2 = ((float *)kb->data) + i2 * 3; - - copy_v3_v3(tvec, fp1); - copy_v3_v3(fp1, fp2); - copy_v3_v3(fp2, tvec); - - /* flip x axis */ - fp1[0] = -fp1[0]; - fp2[0] = -fp2[0]; - totmirr++; - } - tag_elem[i1] = tag_elem[i2] = 1; - } - else { - totfail++; - } - } - - ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e'); - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - int i1, i2; - float *fp1, *fp2; - int u, v, w; - /* half but found up odd value */ - const int pntsu_half = (lt->pntsu / 2) + (lt->pntsu % 2); - - /* currently editmode isn't supported by mesh so - * ignore here for now too */ - - /* if (lt->editlatt) lt = lt->editlatt->latt; */ - - for (w = 0; w < lt->pntsw; w++) { - for (v = 0; v < lt->pntsv; v++) { - for (u = 0; u < pntsu_half; u++) { - int u_inv = (lt->pntsu - 1) - u; - float tvec[3]; - if (u == u_inv) { - i1 = BKE_lattice_index_from_uvw(lt, u, v, w); - fp1 = ((float *)kb->data) + i1 * 3; - fp1[0] = -fp1[0]; - totmirr++; - } - else { - i1 = BKE_lattice_index_from_uvw(lt, u, v, w); - i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); - - fp1 = ((float *)kb->data) + i1 * 3; - fp2 = ((float *)kb->data) + i2 * 3; - - copy_v3_v3(tvec, fp1); - copy_v3_v3(fp1, fp2); - copy_v3_v3(fp2, tvec); - fp1[0] = -fp1[0]; - fp2[0] = -fp2[0]; - totmirr++; - } - } - } - } - } - - MEM_freeN(tag_elem); - } - - *r_totmirr = totmirr; - *r_totfail = totfail; - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return 1; + KeyBlock *kb; + Key *key; + int totmirr = 0, totfail = 0; + + *r_totmirr = *r_totfail = 0; + + key = BKE_key_from_object(ob); + if (key == NULL) + return 0; + + kb = BLI_findlink(&key->block, ob->shapenr - 1); + + if (kb) { + char *tag_elem = MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror"); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + MVert *mv; + int i1, i2; + float *fp1, *fp2; + float tvec[3]; + + ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); + + for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) { + i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology); + if (i2 == i1) { + fp1 = ((float *)kb->data) + i1 * 3; + fp1[0] = -fp1[0]; + tag_elem[i1] = 1; + totmirr++; + } + else if (i2 != -1) { + if (tag_elem[i1] == 0 && tag_elem[i2] == 0) { + fp1 = ((float *)kb->data) + i1 * 3; + fp2 = ((float *)kb->data) + i2 * 3; + + copy_v3_v3(tvec, fp1); + copy_v3_v3(fp1, fp2); + copy_v3_v3(fp2, tvec); + + /* flip x axis */ + fp1[0] = -fp1[0]; + fp2[0] = -fp2[0]; + totmirr++; + } + tag_elem[i1] = tag_elem[i2] = 1; + } + else { + totfail++; + } + } + + ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e'); + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ob->data; + int i1, i2; + float *fp1, *fp2; + int u, v, w; + /* half but found up odd value */ + const int pntsu_half = (lt->pntsu / 2) + (lt->pntsu % 2); + + /* currently editmode isn't supported by mesh so + * ignore here for now too */ + + /* if (lt->editlatt) lt = lt->editlatt->latt; */ + + for (w = 0; w < lt->pntsw; w++) { + for (v = 0; v < lt->pntsv; v++) { + for (u = 0; u < pntsu_half; u++) { + int u_inv = (lt->pntsu - 1) - u; + float tvec[3]; + if (u == u_inv) { + i1 = BKE_lattice_index_from_uvw(lt, u, v, w); + fp1 = ((float *)kb->data) + i1 * 3; + fp1[0] = -fp1[0]; + totmirr++; + } + else { + i1 = BKE_lattice_index_from_uvw(lt, u, v, w); + i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); + + fp1 = ((float *)kb->data) + i1 * 3; + fp2 = ((float *)kb->data) + i2 * 3; + + copy_v3_v3(tvec, fp1); + copy_v3_v3(fp1, fp2); + copy_v3_v3(fp2, tvec); + fp1[0] = -fp1[0]; + fp2[0] = -fp2[0]; + totmirr++; + } + } + } + } + } + + MEM_freeN(tag_elem); + } + + *r_totmirr = totmirr; + *r_totfail = totfail; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return 1; } /********************** shape key operators *********************/ static bool shape_key_mode_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT); } static bool shape_key_mode_exists_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; - /* same as shape_key_mode_poll */ - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT) && - /* check a keyblock exists */ - (BKE_keyblock_from_object(ob) != NULL); + /* same as shape_key_mode_poll */ + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT) && + /* check a keyblock exists */ + (BKE_keyblock_from_object(ob) != NULL); } static bool shape_key_move_poll(bContext *C) { - /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */ - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - Key *key = BKE_key_from_object(ob); + /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */ + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + Key *key = BKE_key_from_object(ob); - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && - ob->mode != OB_MODE_EDIT && key && key->totkey > 1); + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->mode != OB_MODE_EDIT && + key && key->totkey > 1); } static bool shape_key_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)); } static int shape_key_add_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - const bool from_mix = RNA_boolean_get(op->ptr, "from_mix"); + Object *ob = ED_object_context(C); + const bool from_mix = RNA_boolean_get(op->ptr, "from_mix"); - ED_object_shape_key_add(C, ob, from_mix); + ED_object_shape_key_add(C, ob, from_mix); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(CTX_data_main(C)); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_shape_key_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Shape Key"; - ot->idname = "OBJECT_OT_shape_key_add"; - ot->description = "Add shape key to the object"; - - /* api callbacks */ - ot->poll = shape_key_mode_poll; - ot->exec = shape_key_add_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "from_mix", true, "From Mix", "Create the new shape key from the existing mix of keys"); + /* identifiers */ + ot->name = "Add Shape Key"; + ot->idname = "OBJECT_OT_shape_key_add"; + ot->description = "Add shape key to the object"; + + /* api callbacks */ + ot->poll = shape_key_mode_poll; + ot->exec = shape_key_add_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, + "from_mix", + true, + "From Mix", + "Create the new shape key from the existing mix of keys"); } static int shape_key_remove_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *ob = ED_object_context(C); - bool changed = false; - - if (RNA_boolean_get(op->ptr, "all")) { - changed = BKE_object_shapekey_free(bmain, ob); - } - else { - changed = object_shapekey_remove(bmain, ob); - } - - if (changed) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_context(C); + bool changed = false; + + if (RNA_boolean_get(op->ptr, "all")) { + changed = BKE_object_shapekey_free(bmain, ob); + } + else { + changed = object_shapekey_remove(bmain, ob); + } + + if (changed) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_shape_key_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Shape Key"; - ot->idname = "OBJECT_OT_shape_key_remove"; - ot->description = "Remove shape key from the object"; + /* identifiers */ + ot->name = "Remove Shape Key"; + ot->idname = "OBJECT_OT_shape_key_remove"; + ot->description = "Remove shape key from the object"; - /* api callbacks */ - ot->poll = shape_key_mode_exists_poll; - ot->exec = shape_key_remove_exec; + /* api callbacks */ + ot->poll = shape_key_mode_exists_poll; + ot->exec = shape_key_remove_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys"); } static int shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Key *key = BKE_key_from_object(ob); - KeyBlock *kb = BKE_keyblock_from_object(ob); + Object *ob = ED_object_context(C); + Key *key = BKE_key_from_object(ob); + KeyBlock *kb = BKE_keyblock_from_object(ob); - if (!key || !kb) - return OPERATOR_CANCELLED; + if (!key || !kb) + return OPERATOR_CANCELLED; - for (kb = key->block.first; kb; kb = kb->next) - kb->curval = 0.0f; + for (kb = key->block.first; kb; kb = kb->next) + kb->curval = 0.0f; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_shape_key_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Shape Keys"; - ot->description = "Clear weights for all shape keys"; - ot->idname = "OBJECT_OT_shape_key_clear"; + /* identifiers */ + ot->name = "Clear Shape Keys"; + ot->description = "Clear weights for all shape keys"; + ot->idname = "OBJECT_OT_shape_key_clear"; - /* api callbacks */ - ot->poll = shape_key_poll; - ot->exec = shape_key_clear_exec; + /* api callbacks */ + ot->poll = shape_key_poll; + ot->exec = shape_key_clear_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* starting point and step size could be optional */ static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Key *key = BKE_key_from_object(ob); - KeyBlock *kb = BKE_keyblock_from_object(ob); - float cfra = 0.0f; + Object *ob = ED_object_context(C); + Key *key = BKE_key_from_object(ob); + KeyBlock *kb = BKE_keyblock_from_object(ob); + float cfra = 0.0f; - if (!key || !kb) - return OPERATOR_CANCELLED; + if (!key || !kb) + return OPERATOR_CANCELLED; - for (kb = key->block.first; kb; kb = kb->next) { - kb->pos = cfra; - cfra += 0.1f; - } + for (kb = key->block.first; kb; kb = kb->next) { + kb->pos = cfra; + cfra += 0.1f; + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_shape_key_retime(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Re-Time Shape Keys"; - ot->description = "Resets the timing for absolute shape keys"; - ot->idname = "OBJECT_OT_shape_key_retime"; + /* identifiers */ + ot->name = "Re-Time Shape Keys"; + ot->description = "Resets the timing for absolute shape keys"; + ot->idname = "OBJECT_OT_shape_key_retime"; - /* api callbacks */ - ot->poll = shape_key_poll; - ot->exec = shape_key_retime_exec; + /* api callbacks */ + ot->poll = shape_key_poll; + ot->exec = shape_key_retime_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int shape_key_mirror_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - int totmirr = 0, totfail = 0; - bool use_topology = RNA_boolean_get(op->ptr, "use_topology"); + Object *ob = ED_object_context(C); + int totmirr = 0, totfail = 0; + bool use_topology = RNA_boolean_get(op->ptr, "use_topology"); - if (!object_shape_key_mirror(C, ob, &totmirr, &totfail, use_topology)) - return OPERATOR_CANCELLED; + if (!object_shape_key_mirror(C, ob, &totmirr, &totfail, use_topology)) + return OPERATOR_CANCELLED; - ED_mesh_report_mirror(op, totmirr, totfail); + ED_mesh_report_mirror(op, totmirr, totfail); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_shape_key_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mirror Shape Key"; - ot->idname = "OBJECT_OT_shape_key_mirror"; - ot->description = "Mirror the current shape key along the local X axis"; - - /* api callbacks */ - ot->poll = shape_key_mode_poll; - ot->exec = shape_key_mirror_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "use_topology", 0, "Topology Mirror", - "Use topology based mirroring (for when both sides of mesh have matching, unique topology)"); + /* identifiers */ + ot->name = "Mirror Shape Key"; + ot->idname = "OBJECT_OT_shape_key_mirror"; + ot->description = "Mirror the current shape key along the local X axis"; + + /* api callbacks */ + ot->poll = shape_key_mode_poll; + ot->exec = shape_key_mirror_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean( + ot->srna, + "use_topology", + 0, + "Topology Mirror", + "Use topology based mirroring (for when both sides of mesh have matching, unique topology)"); } - enum { - KB_MOVE_TOP = -2, - KB_MOVE_UP = -1, - KB_MOVE_DOWN = 1, - KB_MOVE_BOTTOM = 2, + KB_MOVE_TOP = -2, + KB_MOVE_UP = -1, + KB_MOVE_DOWN = 1, + KB_MOVE_BOTTOM = 2, }; static int shape_key_move_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - - Key *key = BKE_key_from_object(ob); - const int type = RNA_enum_get(op->ptr, "type"); - const int totkey = key->totkey; - const int act_index = ob->shapenr - 1; - int new_index; - - switch (type) { - case KB_MOVE_TOP: - /* Replace the ref key only if we're at the top already (only for relative keys) */ - new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1; - break; - case KB_MOVE_BOTTOM: - new_index = totkey - 1; - break; - case KB_MOVE_UP: - case KB_MOVE_DOWN: - default: - new_index = (totkey + act_index + type) % totkey; - break; - } - - if (!BKE_keyblock_move(ob, act_index, new_index)) { - return OPERATOR_CANCELLED; - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + + Key *key = BKE_key_from_object(ob); + const int type = RNA_enum_get(op->ptr, "type"); + const int totkey = key->totkey; + const int act_index = ob->shapenr - 1; + int new_index; + + switch (type) { + case KB_MOVE_TOP: + /* Replace the ref key only if we're at the top already (only for relative keys) */ + new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1; + break; + case KB_MOVE_BOTTOM: + new_index = totkey - 1; + break; + case KB_MOVE_UP: + case KB_MOVE_DOWN: + default: + new_index = (totkey + act_index + type) % totkey; + break; + } + + if (!BKE_keyblock_move(ob, act_index, new_index)) { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; } void OBJECT_OT_shape_key_move(wmOperatorType *ot) { - static const EnumPropertyItem slot_move[] = { - {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"}, - {KB_MOVE_UP, "UP", 0, "Up", ""}, - {KB_MOVE_DOWN, "DOWN", 0, "Down", ""}, - {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"}, - { 0, NULL, 0, NULL, NULL } - }; - - /* identifiers */ - ot->name = "Move Shape Key"; - ot->idname = "OBJECT_OT_shape_key_move"; - ot->description = "Move the active shape key up/down in the list"; - - /* api callbacks */ - ot->poll = shape_key_move_poll; - ot->exec = shape_key_move_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); + static const EnumPropertyItem slot_move[] = { + {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"}, + {KB_MOVE_UP, "UP", 0, "Up", ""}, + {KB_MOVE_DOWN, "DOWN", 0, "Down", ""}, + {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name = "Move Shape Key"; + ot->idname = "OBJECT_OT_shape_key_move"; + ot->description = "Move the active shape key up/down in the list"; + + /* api callbacks */ + ot->poll = shape_key_move_poll; + ot->exec = shape_key_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); } diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index f7a49f3fcb7..f2f6afcac81 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -21,7 +21,6 @@ * \ingroup edobj */ - #include <stdlib.h> #include <string.h> @@ -80,321 +79,353 @@ /* clear location of object */ static void object_clear_loc(Object *ob, const bool clear_delta) { - /* clear location if not locked */ - if ((ob->protectflag & OB_LOCK_LOCX) == 0) { - ob->loc[0] = 0.0f; - if (clear_delta) ob->dloc[0] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_LOCY) == 0) { - ob->loc[1] = 0.0f; - if (clear_delta) ob->dloc[1] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_LOCZ) == 0) { - ob->loc[2] = 0.0f; - if (clear_delta) ob->dloc[2] = 0.0f; - } + /* clear location if not locked */ + if ((ob->protectflag & OB_LOCK_LOCX) == 0) { + ob->loc[0] = 0.0f; + if (clear_delta) + ob->dloc[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_LOCY) == 0) { + ob->loc[1] = 0.0f; + if (clear_delta) + ob->dloc[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_LOCZ) == 0) { + ob->loc[2] = 0.0f; + if (clear_delta) + ob->dloc[2] = 0.0f; + } } /* clear rotation of object */ static void object_clear_rot(Object *ob, const bool clear_delta) { - /* clear rotations that aren't locked */ - if (ob->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) { - if (ob->protectflag & OB_LOCK_ROT4D) { - /* perform clamping on a component by component basis */ - if (ob->rotmode == ROT_MODE_AXISANGLE) { - if ((ob->protectflag & OB_LOCK_ROTW) == 0) { - ob->rotAngle = 0.0f; - if (clear_delta) ob->drotAngle = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTX) == 0) { - ob->rotAxis[0] = 0.0f; - if (clear_delta) ob->drotAxis[0] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTY) == 0) { - ob->rotAxis[1] = 0.0f; - if (clear_delta) ob->drotAxis[1] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { - ob->rotAxis[2] = 0.0f; - if (clear_delta) ob->drotAxis[2] = 0.0f; - } - - /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ - if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2])) - ob->rotAxis[1] = 1.0f; - if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]) && clear_delta) - ob->drotAxis[1] = 1.0f; - } - else if (ob->rotmode == ROT_MODE_QUAT) { - if ((ob->protectflag & OB_LOCK_ROTW) == 0) { - ob->quat[0] = 1.0f; - if (clear_delta) ob->dquat[0] = 1.0f; - } - if ((ob->protectflag & OB_LOCK_ROTX) == 0) { - ob->quat[1] = 0.0f; - if (clear_delta) ob->dquat[1] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTY) == 0) { - ob->quat[2] = 0.0f; - if (clear_delta) ob->dquat[2] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { - ob->quat[3] = 0.0f; - if (clear_delta) ob->dquat[3] = 0.0f; - } - /* TODO: does this quat need normalizing now? */ - } - else { - /* the flag may have been set for the other modes, so just ignore the extra flag... */ - if ((ob->protectflag & OB_LOCK_ROTX) == 0) { - ob->rot[0] = 0.0f; - if (clear_delta) ob->drot[0] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTY) == 0) { - ob->rot[1] = 0.0f; - if (clear_delta) ob->drot[1] = 0.0f; - } - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { - ob->rot[2] = 0.0f; - if (clear_delta) ob->drot[2] = 0.0f; - } - } - } - else { - /* perform clamping using euler form (3-components) */ - /* FIXME: deltas are not handled for these cases yet... */ - float eul[3], oldeul[3], quat1[4] = {0}; - - if (ob->rotmode == ROT_MODE_QUAT) { - copy_qt_qt(quat1, ob->quat); - quat_to_eul(oldeul, ob->quat); - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle); - } - else { - copy_v3_v3(oldeul, ob->rot); - } - - eul[0] = eul[1] = eul[2] = 0.0f; - - if (ob->protectflag & OB_LOCK_ROTX) - eul[0] = oldeul[0]; - if (ob->protectflag & OB_LOCK_ROTY) - eul[1] = oldeul[1]; - if (ob->protectflag & OB_LOCK_ROTZ) - eul[2] = oldeul[2]; - - if (ob->rotmode == ROT_MODE_QUAT) { - eul_to_quat(ob->quat, eul); - /* quaternions flip w sign to accumulate rotations correctly */ - if ((quat1[0] < 0.0f && ob->quat[0] > 0.0f) || (quat1[0] > 0.0f && ob->quat[0] < 0.0f)) { - mul_qt_fl(ob->quat, -1.0f); - } - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle, eul, EULER_ORDER_DEFAULT); - } - else { - copy_v3_v3(ob->rot, eul); - } - } - } // Duplicated in source/blender/editors/armature/editarmature.c - else { - if (ob->rotmode == ROT_MODE_QUAT) { - unit_qt(ob->quat); - if (clear_delta) unit_qt(ob->dquat); - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - unit_axis_angle(ob->rotAxis, &ob->rotAngle); - if (clear_delta) unit_axis_angle(ob->drotAxis, &ob->drotAngle); - } - else { - zero_v3(ob->rot); - if (clear_delta) zero_v3(ob->drot); - } - } + /* clear rotations that aren't locked */ + if (ob->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) { + if (ob->protectflag & OB_LOCK_ROT4D) { + /* perform clamping on a component by component basis */ + if (ob->rotmode == ROT_MODE_AXISANGLE) { + if ((ob->protectflag & OB_LOCK_ROTW) == 0) { + ob->rotAngle = 0.0f; + if (clear_delta) + ob->drotAngle = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->rotAxis[0] = 0.0f; + if (clear_delta) + ob->drotAxis[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->rotAxis[1] = 0.0f; + if (clear_delta) + ob->drotAxis[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->rotAxis[2] = 0.0f; + if (clear_delta) + ob->drotAxis[2] = 0.0f; + } + + /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ + if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2])) + ob->rotAxis[1] = 1.0f; + if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]) && + clear_delta) + ob->drotAxis[1] = 1.0f; + } + else if (ob->rotmode == ROT_MODE_QUAT) { + if ((ob->protectflag & OB_LOCK_ROTW) == 0) { + ob->quat[0] = 1.0f; + if (clear_delta) + ob->dquat[0] = 1.0f; + } + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->quat[1] = 0.0f; + if (clear_delta) + ob->dquat[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->quat[2] = 0.0f; + if (clear_delta) + ob->dquat[2] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->quat[3] = 0.0f; + if (clear_delta) + ob->dquat[3] = 0.0f; + } + /* TODO: does this quat need normalizing now? */ + } + else { + /* the flag may have been set for the other modes, so just ignore the extra flag... */ + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->rot[0] = 0.0f; + if (clear_delta) + ob->drot[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->rot[1] = 0.0f; + if (clear_delta) + ob->drot[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->rot[2] = 0.0f; + if (clear_delta) + ob->drot[2] = 0.0f; + } + } + } + else { + /* perform clamping using euler form (3-components) */ + /* FIXME: deltas are not handled for these cases yet... */ + float eul[3], oldeul[3], quat1[4] = {0}; + + if (ob->rotmode == ROT_MODE_QUAT) { + copy_qt_qt(quat1, ob->quat); + quat_to_eul(oldeul, ob->quat); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle); + } + else { + copy_v3_v3(oldeul, ob->rot); + } + + eul[0] = eul[1] = eul[2] = 0.0f; + + if (ob->protectflag & OB_LOCK_ROTX) + eul[0] = oldeul[0]; + if (ob->protectflag & OB_LOCK_ROTY) + eul[1] = oldeul[1]; + if (ob->protectflag & OB_LOCK_ROTZ) + eul[2] = oldeul[2]; + + if (ob->rotmode == ROT_MODE_QUAT) { + eul_to_quat(ob->quat, eul); + /* quaternions flip w sign to accumulate rotations correctly */ + if ((quat1[0] < 0.0f && ob->quat[0] > 0.0f) || (quat1[0] > 0.0f && ob->quat[0] < 0.0f)) { + mul_qt_fl(ob->quat, -1.0f); + } + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle, eul, EULER_ORDER_DEFAULT); + } + else { + copy_v3_v3(ob->rot, eul); + } + } + } // Duplicated in source/blender/editors/armature/editarmature.c + else { + if (ob->rotmode == ROT_MODE_QUAT) { + unit_qt(ob->quat); + if (clear_delta) + unit_qt(ob->dquat); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + unit_axis_angle(ob->rotAxis, &ob->rotAngle); + if (clear_delta) + unit_axis_angle(ob->drotAxis, &ob->drotAngle); + } + else { + zero_v3(ob->rot); + if (clear_delta) + zero_v3(ob->drot); + } + } } /* clear scale of object */ static void object_clear_scale(Object *ob, const bool clear_delta) { - /* clear scale factors which are not locked */ - if ((ob->protectflag & OB_LOCK_SCALEX) == 0) { - ob->scale[0] = 1.0f; - if (clear_delta) ob->dscale[0] = 1.0f; - } - if ((ob->protectflag & OB_LOCK_SCALEY) == 0) { - ob->scale[1] = 1.0f; - if (clear_delta) ob->dscale[1] = 1.0f; - } - if ((ob->protectflag & OB_LOCK_SCALEZ) == 0) { - ob->scale[2] = 1.0f; - if (clear_delta) ob->dscale[2] = 1.0f; - } + /* clear scale factors which are not locked */ + if ((ob->protectflag & OB_LOCK_SCALEX) == 0) { + ob->scale[0] = 1.0f; + if (clear_delta) + ob->dscale[0] = 1.0f; + } + if ((ob->protectflag & OB_LOCK_SCALEY) == 0) { + ob->scale[1] = 1.0f; + if (clear_delta) + ob->dscale[1] = 1.0f; + } + if ((ob->protectflag & OB_LOCK_SCALEZ) == 0) { + ob->scale[2] = 1.0f; + if (clear_delta) + ob->dscale[2] = 1.0f; + } } /* --------------- */ /* generic exec for clear-transform operators */ -static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, +static int object_clear_transform_generic_exec(bContext *C, + wmOperator *op, void (*clear_func)(Object *, const bool), const char default_ksName[]) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks; - const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta"); - - /* sanity checks */ - if (ELEM(NULL, clear_func, default_ksName)) { - BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name"); - return OPERATOR_CANCELLED; - } - - /* get KeyingSet to use */ - ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); - - /* operate on selected objects only if they aren't in weight-paint mode - * (so that object-transform clearing won't be applied at same time as bone-clearing) - */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) { - /* run provided clearing function */ - clear_func(ob, clear_delta); - - ED_autokeyframe_object(C, scene, ob, ks); - - /* tag for updates */ - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - } - CTX_DATA_END; - - /* this is needed so children are also updated */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks; + const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta"); + + /* sanity checks */ + if (ELEM(NULL, clear_func, default_ksName)) { + BKE_report(op->reports, + RPT_ERROR, + "Programming error: missing clear transform function or keying set name"); + return OPERATOR_CANCELLED; + } + + /* get KeyingSet to use */ + ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); + + /* operate on selected objects only if they aren't in weight-paint mode + * (so that object-transform clearing won't be applied at same time as bone-clearing) + */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) { + /* run provided clearing function */ + clear_func(ob, clear_delta); + + ED_autokeyframe_object(C, scene, ob, ks); + + /* tag for updates */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + } + CTX_DATA_END; + + /* this is needed so children are also updated */ + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; } /* --------------- */ - static int object_location_clear_exec(bContext *C, wmOperator *op) { - return object_clear_transform_generic_exec(C, op, object_clear_loc, ANIM_KS_LOCATION_ID); + return object_clear_transform_generic_exec(C, op, object_clear_loc, ANIM_KS_LOCATION_ID); } void OBJECT_OT_location_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Location"; - ot->description = "Clear the object's location"; - ot->idname = "OBJECT_OT_location_clear"; - - /* api callbacks */ - ot->exec = object_location_clear_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - - /* properties */ - ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", - "Clear delta location in addition to clearing the normal location transform"); + /* identifiers */ + ot->name = "Clear Location"; + ot->description = "Clear the object's location"; + ot->idname = "OBJECT_OT_location_clear"; + + /* api callbacks */ + ot->exec = object_location_clear_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean( + ot->srna, + "clear_delta", + false, + "Clear Delta", + "Clear delta location in addition to clearing the normal location transform"); } static int object_rotation_clear_exec(bContext *C, wmOperator *op) { - return object_clear_transform_generic_exec(C, op, object_clear_rot, ANIM_KS_ROTATION_ID); + return object_clear_transform_generic_exec(C, op, object_clear_rot, ANIM_KS_ROTATION_ID); } void OBJECT_OT_rotation_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Rotation"; - ot->description = "Clear the object's rotation"; - ot->idname = "OBJECT_OT_rotation_clear"; - - /* api callbacks */ - ot->exec = object_rotation_clear_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", - "Clear delta rotation in addition to clearing the normal rotation transform"); + /* identifiers */ + ot->name = "Clear Rotation"; + ot->description = "Clear the object's rotation"; + ot->idname = "OBJECT_OT_rotation_clear"; + + /* api callbacks */ + ot->exec = object_rotation_clear_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean( + ot->srna, + "clear_delta", + false, + "Clear Delta", + "Clear delta rotation in addition to clearing the normal rotation transform"); } static int object_scale_clear_exec(bContext *C, wmOperator *op) { - return object_clear_transform_generic_exec(C, op, object_clear_scale, ANIM_KS_SCALING_ID); + return object_clear_transform_generic_exec(C, op, object_clear_scale, ANIM_KS_SCALING_ID); } void OBJECT_OT_scale_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Scale"; - ot->description = "Clear the object's scale"; - ot->idname = "OBJECT_OT_scale_clear"; - - /* api callbacks */ - ot->exec = object_scale_clear_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", - "Clear delta scale in addition to clearing the normal scale transform"); + /* identifiers */ + ot->name = "Clear Scale"; + ot->description = "Clear the object's scale"; + ot->idname = "OBJECT_OT_scale_clear"; + + /* api callbacks */ + ot->exec = object_scale_clear_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean( + ot->srna, + "clear_delta", + false, + "Clear Delta", + "Clear delta scale in addition to clearing the normal scale transform"); } /* --------------- */ static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - float *v1, *v3; - float mat[3][3]; + float *v1, *v3; + float mat[3][3]; - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ob->parent) { - /* vectors pointed to by v1 and v3 will get modified */ - v1 = ob->loc; - v3 = ob->parentinv[3]; + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ob->parent) { + /* vectors pointed to by v1 and v3 will get modified */ + v1 = ob->loc; + v3 = ob->parentinv[3]; - copy_m3_m4(mat, ob->parentinv); - negate_v3_v3(v3, v1); - mul_m3_v3(mat, v3); - } + copy_m3_m4(mat, ob->parentinv); + negate_v3_v3(v3, v1); + mul_m3_v3(mat, v3); + } - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - CTX_DATA_END; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + CTX_DATA_END; - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_origin_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Origin"; - ot->description = "Clear the object's origin"; - ot->idname = "OBJECT_OT_origin_clear"; + /* identifiers */ + ot->name = "Clear Origin"; + ot->description = "Clear the object's origin"; + ot->idname = "OBJECT_OT_origin_clear"; - /* api callbacks */ - ot->exec = object_origin_clear_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = object_origin_clear_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /*************************** Apply Transformation ****************************/ @@ -403,885 +434,947 @@ void OBJECT_OT_origin_clear(wmOperatorType *ot) * should stay in the same place, e.g. for apply-size-rot or object center */ static void ignore_parent_tx(const bContext *C, Main *bmain, Scene *scene, Object *ob) { - Object workob; - Object *ob_child; - Depsgraph *depsgraph = CTX_data_depsgraph(C); - - /* a change was made, adjust the children to compensate */ - for (ob_child = bmain->objects.first; ob_child; ob_child = ob_child->id.next) { - if (ob_child->parent == ob) { - BKE_object_apply_mat4(ob_child, ob_child->obmat, true, false); - BKE_object_workob_calc_parent(depsgraph, scene, ob_child, &workob); - invert_m4_m4(ob_child->parentinv, workob.obmat); - } - } + Object workob; + Object *ob_child; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + /* a change was made, adjust the children to compensate */ + for (ob_child = bmain->objects.first; ob_child; ob_child = ob_child->id.next) { + if (ob_child->parent == ob) { + BKE_object_apply_mat4(ob_child, ob_child->obmat, true, false); + BKE_object_workob_calc_parent(depsgraph, scene, ob_child, &workob); + invert_m4_m4(ob_child->parentinv, workob.obmat); + } + } } -static int apply_objects_internal( - bContext *C, ReportList *reports, - bool apply_loc, bool apply_rot, bool apply_scale, - bool do_props) +static int apply_objects_internal(bContext *C, + ReportList *reports, + bool apply_loc, + bool apply_rot, + bool apply_scale, + bool do_props) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; - bool changed = true; - - /* first check if we can execute */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) { - ID *obdata = ob->data; - if (ID_REAL_USERS(obdata) > 1) { - BKE_reportf(reports, RPT_ERROR, - "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); - changed = false; - } - - if (ID_IS_LINKED(obdata)) { - BKE_reportf(reports, RPT_ERROR, - "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); - changed = false; - } - } - - if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - ID *obdata = ob->data; - Curve *cu; - - cu = ob->data; - - if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { - BKE_reportf(reports, RPT_ERROR, - "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); - changed = false; - } - if (cu->key) { - BKE_reportf(reports, RPT_ERROR, - "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); - changed = false; - } - } - - if (ob->type == OB_FONT) { - if (apply_rot || apply_loc) { - BKE_reportf(reports, RPT_ERROR, - "Font's can only have scale applied: \"%s\"", - ob->id.name + 2); - changed = false; - } - } - - if (ob->type == OB_GPENCIL) { - bGPdata *gpd = ob->data; - if (gpd) { - if (gpd->layers.first) { - /* Unsupported configuration */ - bool has_unparented_layers = false; - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* Parented layers aren't supported as we can't easily re-evaluate - * the scene to sample parent movement */ - if (gpl->parent == NULL) { - has_unparented_layers = true; - break; - } - } - - if (has_unparented_layers == false) { - BKE_reportf(reports, RPT_ERROR, - "Can't apply to a GP datablock where all layers are parented: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2); - changed = false; - } - } - else { - /* No layers/data */ - BKE_reportf(reports, RPT_ERROR, - "Can't apply to GP datablock with no layers: Object \"%s\", %s \"%s\", aborting", - ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2); - } - } - } - - if (ob->type == OB_LAMP) { - Light *la = ob->data; - if (la->type == LA_AREA) { - if (apply_rot || apply_loc) { - BKE_reportf(reports, RPT_ERROR, - "Area Lights can only have scale applied: \"%s\"", - ob->id.name + 2); - changed = false; - } - } - } - } - CTX_DATA_END; - - if (!changed) - return OPERATOR_CANCELLED; - - changed = false; - - /* now execute */ - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - - /* calculate rotation/scale matrix */ - if (apply_scale && apply_rot) - BKE_object_to_mat3(ob, rsmat); - else if (apply_scale) - BKE_object_scale_to_mat3(ob, rsmat); - else if (apply_rot) { - float tmat[3][3], timat[3][3]; - - /* simple rotation matrix */ - BKE_object_rot_to_mat3(ob, rsmat, true); - - /* correct for scale, note mul_m3_m3m3 has swapped args! */ - BKE_object_scale_to_mat3(ob, tmat); - invert_m3_m3(timat, tmat); - mul_m3_m3m3(rsmat, timat, rsmat); - mul_m3_m3m3(rsmat, rsmat, tmat); - } - else - unit_m3(rsmat); - - copy_m4_m3(mat, rsmat); - - /* calculate translation */ - if (apply_loc) { - copy_v3_v3(mat[3], ob->loc); - - if (!(apply_scale && apply_rot)) { - float tmat[3][3]; - /* correct for scale and rotation that is still applied */ - BKE_object_to_mat3(ob, obmat); - invert_m3_m3(iobmat, obmat); - mul_m3_m3m3(tmat, rsmat, iobmat); - mul_m3_v3(tmat, mat[3]); - } - } - - /* apply to object data */ - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (apply_scale) - multiresModifier_scale_disp(depsgraph, scene, ob); - - /* adjust data */ - BKE_mesh_transform(me, mat, true); - - /* update normals */ - BKE_mesh_calc_normals(me); - } - else if (ob->type == OB_ARMATURE) { - ED_armature_transform_apply(bmain, ob, mat, do_props); - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - - BKE_lattice_transform(lt, mat, true); - } - else if (ob->type == OB_MBALL) { - MetaBall *mb = ob->data; - BKE_mball_transform(mb, mat, do_props); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; - scale = mat3_to_scale(rsmat); - BKE_curve_transform_ex(cu, mat, true, do_props, scale); - } - else if (ob->type == OB_FONT) { - Curve *cu = ob->data; - int i; - - scale = mat3_to_scale(rsmat); - - for (i = 0; i < cu->totbox; i++) { - TextBox *tb = &cu->tb[i]; - tb->x *= scale; - tb->y *= scale; - tb->w *= scale; - tb->h *= scale; - } - - if (do_props) { - cu->fsize *= scale; - } - } - else if (ob->type == OB_GPENCIL) { - bGPdata *gpd = ob->data; - BKE_gpencil_transform(gpd, mat); - } - else if (ob->type == OB_CAMERA) { - MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); - - /* applying scale on camera actually scales clip's reconstruction. - * of there's clip assigned to camera nothing to do actually. - */ - if (!clip) - continue; - - if (apply_scale) - BKE_tracking_reconstruction_scale(&clip->tracking, ob->scale); - } - else if (ob->type == OB_EMPTY) { - /* It's possible for empties too, even though they don't - * really have obdata, since we can simply apply the maximum - * scaling to the empty's drawsize. - * - * Core Assumptions: - * 1) Most scaled empties have uniform scaling - * (i.e. for visibility reasons), AND/OR - * 2) Preserving non-uniform scaling is not that important, - * and is something that many users would be willing to - * sacrifice for having an easy way to do this. - */ - - if ((apply_loc == false) && - (apply_rot == false) && - (apply_scale == true)) - { - float max_scale = max_fff(fabsf(ob->scale[0]), fabsf(ob->scale[1]), fabsf(ob->scale[2])); - ob->empty_drawsize *= max_scale; - } - } - else if (ob->type == OB_LAMP) { - Light *la = ob->data; - if (la->type != LA_AREA) { - continue; - } - - bool keeps_aspect_ratio = compare_ff_relative(rsmat[0][0], rsmat[1][1], FLT_EPSILON, 64); - if ((la->area_shape == LA_AREA_SQUARE) && !keeps_aspect_ratio) { - la->area_shape = LA_AREA_RECT; - la->area_sizey = la->area_size; - } - else if ((la->area_shape == LA_AREA_DISK) && !keeps_aspect_ratio) { - la->area_shape = LA_AREA_ELLIPSE; - la->area_sizey = la->area_size; - } - - la->area_size *= rsmat[0][0]; - la->area_sizey *= rsmat[1][1]; - la->area_sizez *= rsmat[2][2]; - } - else { - continue; - } - - if (apply_loc) - zero_v3(ob->loc); - if (apply_scale) - ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f; - if (apply_rot) { - zero_v3(ob->rot); - unit_qt(ob->quat); - unit_axis_angle(ob->rotAxis, &ob->rotAngle); - } - - BKE_object_where_is_calc(depsgraph, scene, ob); - if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ - } - - ignore_parent_tx(C, bmain, scene, ob); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - changed = true; - } - CTX_DATA_END; - - if (!changed) { - BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); - return OPERATOR_CANCELLED; - } - - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; + bool changed = true; + + /* first check if we can execute */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (ELEM(ob->type, + OB_MESH, + OB_ARMATURE, + OB_LATTICE, + OB_MBALL, + OB_CURVE, + OB_SURF, + OB_FONT, + OB_GPENCIL)) { + ID *obdata = ob->data; + if (ID_REAL_USERS(obdata) > 1) { + BKE_reportf(reports, + RPT_ERROR, + "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(GS(obdata->name)), + obdata->name + 2); + changed = false; + } + + if (ID_IS_LINKED(obdata)) { + BKE_reportf(reports, + RPT_ERROR, + "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(GS(obdata->name)), + obdata->name + 2); + changed = false; + } + } + + if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + ID *obdata = ob->data; + Curve *cu; + + cu = ob->data; + + if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { + BKE_reportf( + reports, + RPT_ERROR, + "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(GS(obdata->name)), + obdata->name + 2); + changed = false; + } + if (cu->key) { + BKE_reportf(reports, + RPT_ERROR, + "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(GS(obdata->name)), + obdata->name + 2); + changed = false; + } + } + + if (ob->type == OB_FONT) { + if (apply_rot || apply_loc) { + BKE_reportf( + reports, RPT_ERROR, "Font's can only have scale applied: \"%s\"", ob->id.name + 2); + changed = false; + } + } + + if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + if (gpd) { + if (gpd->layers.first) { + /* Unsupported configuration */ + bool has_unparented_layers = false; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* Parented layers aren't supported as we can't easily re-evaluate + * the scene to sample parent movement */ + if (gpl->parent == NULL) { + has_unparented_layers = true; + break; + } + } + + if (has_unparented_layers == false) { + BKE_reportf(reports, + RPT_ERROR, + "Can't apply to a GP datablock where all layers are parented: Object " + "\"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(ID_GD), + gpd->id.name + 2); + changed = false; + } + } + else { + /* No layers/data */ + BKE_reportf( + reports, + RPT_ERROR, + "Can't apply to GP datablock with no layers: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, + BKE_idcode_to_name(ID_GD), + gpd->id.name + 2); + } + } + } + + if (ob->type == OB_LAMP) { + Light *la = ob->data; + if (la->type == LA_AREA) { + if (apply_rot || apply_loc) { + BKE_reportf(reports, + RPT_ERROR, + "Area Lights can only have scale applied: \"%s\"", + ob->id.name + 2); + changed = false; + } + } + } + } + CTX_DATA_END; + + if (!changed) + return OPERATOR_CANCELLED; + + changed = false; + + /* now execute */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + + /* calculate rotation/scale matrix */ + if (apply_scale && apply_rot) + BKE_object_to_mat3(ob, rsmat); + else if (apply_scale) + BKE_object_scale_to_mat3(ob, rsmat); + else if (apply_rot) { + float tmat[3][3], timat[3][3]; + + /* simple rotation matrix */ + BKE_object_rot_to_mat3(ob, rsmat, true); + + /* correct for scale, note mul_m3_m3m3 has swapped args! */ + BKE_object_scale_to_mat3(ob, tmat); + invert_m3_m3(timat, tmat); + mul_m3_m3m3(rsmat, timat, rsmat); + mul_m3_m3m3(rsmat, rsmat, tmat); + } + else + unit_m3(rsmat); + + copy_m4_m3(mat, rsmat); + + /* calculate translation */ + if (apply_loc) { + copy_v3_v3(mat[3], ob->loc); + + if (!(apply_scale && apply_rot)) { + float tmat[3][3]; + /* correct for scale and rotation that is still applied */ + BKE_object_to_mat3(ob, obmat); + invert_m3_m3(iobmat, obmat); + mul_m3_m3m3(tmat, rsmat, iobmat); + mul_m3_v3(tmat, mat[3]); + } + } + + /* apply to object data */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (apply_scale) + multiresModifier_scale_disp(depsgraph, scene, ob); + + /* adjust data */ + BKE_mesh_transform(me, mat, true); + + /* update normals */ + BKE_mesh_calc_normals(me); + } + else if (ob->type == OB_ARMATURE) { + ED_armature_transform_apply(bmain, ob, mat, do_props); + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ob->data; + + BKE_lattice_transform(lt, mat, true); + } + else if (ob->type == OB_MBALL) { + MetaBall *mb = ob->data; + BKE_mball_transform(mb, mat, do_props); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu = ob->data; + scale = mat3_to_scale(rsmat); + BKE_curve_transform_ex(cu, mat, true, do_props, scale); + } + else if (ob->type == OB_FONT) { + Curve *cu = ob->data; + int i; + + scale = mat3_to_scale(rsmat); + + for (i = 0; i < cu->totbox; i++) { + TextBox *tb = &cu->tb[i]; + tb->x *= scale; + tb->y *= scale; + tb->w *= scale; + tb->h *= scale; + } + + if (do_props) { + cu->fsize *= scale; + } + } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + BKE_gpencil_transform(gpd, mat); + } + else if (ob->type == OB_CAMERA) { + MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); + + /* applying scale on camera actually scales clip's reconstruction. + * of there's clip assigned to camera nothing to do actually. + */ + if (!clip) + continue; + + if (apply_scale) + BKE_tracking_reconstruction_scale(&clip->tracking, ob->scale); + } + else if (ob->type == OB_EMPTY) { + /* It's possible for empties too, even though they don't + * really have obdata, since we can simply apply the maximum + * scaling to the empty's drawsize. + * + * Core Assumptions: + * 1) Most scaled empties have uniform scaling + * (i.e. for visibility reasons), AND/OR + * 2) Preserving non-uniform scaling is not that important, + * and is something that many users would be willing to + * sacrifice for having an easy way to do this. + */ + + if ((apply_loc == false) && (apply_rot == false) && (apply_scale == true)) { + float max_scale = max_fff(fabsf(ob->scale[0]), fabsf(ob->scale[1]), fabsf(ob->scale[2])); + ob->empty_drawsize *= max_scale; + } + } + else if (ob->type == OB_LAMP) { + Light *la = ob->data; + if (la->type != LA_AREA) { + continue; + } + + bool keeps_aspect_ratio = compare_ff_relative(rsmat[0][0], rsmat[1][1], FLT_EPSILON, 64); + if ((la->area_shape == LA_AREA_SQUARE) && !keeps_aspect_ratio) { + la->area_shape = LA_AREA_RECT; + la->area_sizey = la->area_size; + } + else if ((la->area_shape == LA_AREA_DISK) && !keeps_aspect_ratio) { + la->area_shape = LA_AREA_ELLIPSE; + la->area_sizey = la->area_size; + } + + la->area_size *= rsmat[0][0]; + la->area_sizey *= rsmat[1][1]; + la->area_sizez *= rsmat[2][2]; + } + else { + continue; + } + + if (apply_loc) + zero_v3(ob->loc); + if (apply_scale) + ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f; + if (apply_rot) { + zero_v3(ob->rot); + unit_qt(ob->quat); + unit_axis_angle(ob->rotAxis, &ob->rotAngle); + } + + BKE_object_where_is_calc(depsgraph, scene, ob); + if (ob->type == OB_ARMATURE) { + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + } + + ignore_parent_tx(C, bmain, scene, ob); + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + changed = true; + } + CTX_DATA_END; + + if (!changed) { + BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); + return OPERATOR_CANCELLED; + } + + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + return OPERATOR_FINISHED; } static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - bool changed = false; + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + bool changed = false; - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - BKE_object_where_is_calc(depsgraph, scene, ob); - BKE_object_apply_mat4(ob, ob->obmat, true, true); - BKE_object_where_is_calc(depsgraph, scene, ob); + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + BKE_object_where_is_calc(depsgraph, scene, ob); + BKE_object_apply_mat4(ob, ob->obmat, true, true); + BKE_object_where_is_calc(depsgraph, scene, ob); - /* update for any children that may get moved */ - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + /* update for any children that may get moved */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - changed = true; - } - CTX_DATA_END; + changed = true; + } + CTX_DATA_END; - if (!changed) - return OPERATOR_CANCELLED; + if (!changed) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - return OPERATOR_FINISHED; + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + return OPERATOR_FINISHED; } void OBJECT_OT_visual_transform_apply(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Apply Visual Transform"; - ot->description = "Apply the object's visual transformation to its data"; - ot->idname = "OBJECT_OT_visual_transform_apply"; + /* identifiers */ + ot->name = "Apply Visual Transform"; + ot->description = "Apply the object's visual transformation to its data"; + ot->idname = "OBJECT_OT_visual_transform_apply"; - /* api callbacks */ - ot->exec = visual_transform_apply_exec; - ot->poll = ED_operator_scene_editable; + /* api callbacks */ + ot->exec = visual_transform_apply_exec; + ot->poll = ED_operator_scene_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int object_transform_apply_exec(bContext *C, wmOperator *op) { - const bool loc = RNA_boolean_get(op->ptr, "location"); - const bool rot = RNA_boolean_get(op->ptr, "rotation"); - const bool sca = RNA_boolean_get(op->ptr, "scale"); - const bool do_props = RNA_boolean_get(op->ptr, "properties"); - - if (loc || rot || sca) { - return apply_objects_internal(C, op->reports, loc, rot, sca, do_props); - } - else { - /* allow for redo */ - return OPERATOR_FINISHED; - } + const bool loc = RNA_boolean_get(op->ptr, "location"); + const bool rot = RNA_boolean_get(op->ptr, "rotation"); + const bool sca = RNA_boolean_get(op->ptr, "scale"); + const bool do_props = RNA_boolean_get(op->ptr, "properties"); + + if (loc || rot || sca) { + return apply_objects_internal(C, op->reports, loc, rot, sca, do_props); + } + else { + /* allow for redo */ + return OPERATOR_FINISHED; + } } void OBJECT_OT_transform_apply(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Apply Object Transform"; - ot->description = "Apply the object's transformation to its data"; - ot->idname = "OBJECT_OT_transform_apply"; - - /* api callbacks */ - ot->exec = object_transform_apply_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "location", true, "Location", ""); - RNA_def_boolean(ot->srna, "rotation", true, "Rotation", ""); - RNA_def_boolean(ot->srna, "scale", true, "Scale", ""); - RNA_def_boolean(ot->srna, "properties", true, "Apply Properties", - "Modify properties such as curve vertex radius, font size and bone envelope"); + /* identifiers */ + ot->name = "Apply Object Transform"; + ot->description = "Apply the object's transformation to its data"; + ot->idname = "OBJECT_OT_transform_apply"; + + /* api callbacks */ + ot->exec = object_transform_apply_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "location", true, "Location", ""); + RNA_def_boolean(ot->srna, "rotation", true, "Rotation", ""); + RNA_def_boolean(ot->srna, "scale", true, "Scale", ""); + RNA_def_boolean(ot->srna, + "properties", + true, + "Apply Properties", + "Modify properties such as curve vertex radius, font size and bone envelope"); } /********************* Set Object Center ************************/ enum { - GEOMETRY_TO_ORIGIN = 0, - ORIGIN_TO_GEOMETRY, - ORIGIN_TO_CURSOR, - ORIGIN_TO_CENTER_OF_MASS_SURFACE, - ORIGIN_TO_CENTER_OF_MASS_VOLUME, + GEOMETRY_TO_ORIGIN = 0, + ORIGIN_TO_GEOMETRY, + ORIGIN_TO_CURSOR, + ORIGIN_TO_CENTER_OF_MASS_SURFACE, + ORIGIN_TO_CENTER_OF_MASS_VOLUME, }; static int object_origin_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *tob; - float cent[3], cent_neg[3], centn[3]; - const float *cursor = scene->cursor.location; - int centermode = RNA_enum_get(op->ptr, "type"); - - ListBase ctx_data_list; - CollectionPointerLink *ctx_ob; - CollectionPointerLink *ctx_ob_act = NULL; - - /* keep track of what is changed */ - int tot_change = 0, tot_lib_error = 0, tot_multiuser_arm_error = 0; - - if (obedit && centermode != GEOMETRY_TO_ORIGIN) { - BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode"); - return OPERATOR_CANCELLED; - } - - int around; - { - PropertyRNA *prop_center = RNA_struct_find_property(op->ptr, "center"); - if (RNA_property_is_set(op->ptr, prop_center)) { - around = RNA_property_enum_get(op->ptr, prop_center); - } - else { - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) { - around = V3D_AROUND_CENTER_BOUNDS; - } - else { - around = V3D_AROUND_CENTER_MEDIAN; - } - RNA_property_enum_set(op->ptr, prop_center, around); - } - } - - zero_v3(cent); - - if (obedit) { - if (obedit->type == OB_MESH) { - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_mesh; - BMVert *eve; - BMIter iter; - - if (centermode == ORIGIN_TO_CURSOR) { - copy_v3_v3(cent, cursor); - invert_m4_m4(obedit->imat, obedit->obmat); - mul_m4_v3(obedit->imat, cent); - } - else { - if (around == V3D_AROUND_CENTER_MEDIAN) { - if (em->bm->totvert) { - const float total_div = 1.0f / (float)em->bm->totvert; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - madd_v3_v3fl(cent, eve->co, total_div); - } - } - } - else { - float min[3], max[3]; - INIT_MINMAX(min, max); - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(min, max, eve->co); - } - mid_v3_v3v3(cent, min, max); - } - } - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - sub_v3_v3(eve->co, cent); - } - - EDBM_mesh_normals_update(em); - tot_change++; - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - } - - CTX_data_selected_editable_objects(C, &ctx_data_list); - - /* reset flags */ - for (ctx_ob = ctx_data_list.first; - ctx_ob; - ctx_ob = ctx_ob->next) - { - Object *ob = ctx_ob->ptr.data; - ob->flag &= ~OB_DONE; - - /* move active first */ - if (ob == obact) { - ctx_ob_act = ctx_ob; - } - } - - if (ctx_ob_act) { - BLI_listbase_rotate_first(&ctx_data_list, (LinkData *)ctx_ob_act); - } - - for (tob = bmain->objects.first; tob; tob = tob->id.next) { - if (tob->data) - ((ID *)tob->data)->tag &= ~LIB_TAG_DOIT; - if (tob->instance_collection) - ((ID *)tob->instance_collection)->tag &= ~LIB_TAG_DOIT; - } - - for (ctx_ob = ctx_data_list.first; - ctx_ob; - ctx_ob = ctx_ob->next) - { - Object *ob = ctx_ob->ptr.data; - - if ((ob->flag & OB_DONE) == 0) { - bool do_inverse_offset = false; - ob->flag |= OB_DONE; - - if (centermode == ORIGIN_TO_CURSOR) { - copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, cent); - } - - if (ob->data == NULL) { - /* special support for dupligroups */ - if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection && (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) { - if (ID_IS_LINKED(ob->instance_collection)) { - tot_lib_error++; - } - else { - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else { - float min[3], max[3]; - /* only bounds support */ - INIT_MINMAX(min, max); - BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); - mid_v3_v3v3(cent, min, max); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, cent); - } - - add_v3_v3(ob->instance_collection->instance_offset, cent); - - tot_change++; - ob->instance_collection->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - } - } - else if (ID_IS_LINKED(ob->data)) { - tot_lib_error++; - } - - if (obedit == NULL && ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) { - BKE_mesh_center_of_surface(me, cent); - } - else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) { - BKE_mesh_center_of_volume(me, cent); - } - else if (around == V3D_AROUND_CENTER_MEDIAN) { - BKE_mesh_center_median(me, cent); - } - else { - BKE_mesh_center_bounds(me, cent); - } - - negate_v3_v3(cent_neg, cent); - BKE_mesh_translate(me, cent_neg, 1); - - tot_change++; - me->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; - - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { BKE_curve_center_median(cu, cent); } - else { BKE_curve_center_bounds(cu, cent); } - - /* don't allow Z change if curve is 2D */ - if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) - cent[2] = 0.0; - - negate_v3_v3(cent_neg, cent); - BKE_curve_translate(cu, cent_neg, 1); - - tot_change++; - cu->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - - if (obedit) { - if (centermode == GEOMETRY_TO_ORIGIN) { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - break; - } - } - else if (ob->type == OB_FONT) { - /* get from bb */ - - Curve *cu = ob->data; - - if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) { - /* do nothing*/ - } - else { - if (centermode == ORIGIN_TO_CURSOR) { - /* done */ - } - else { - /* extra 0.5 is the height o above line */ - cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]); - cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]); - } - - cent[2] = 0.0f; - - cu->xof = cu->xof - cent[0]; - cu->yof = cu->yof - cent[1]; - - tot_change++; - cu->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - } - else if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; - - if (ID_REAL_USERS(arm) > 1) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *obact = CTX_data_active_object(C); + Object *obedit = CTX_data_edit_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *tob; + float cent[3], cent_neg[3], centn[3]; + const float *cursor = scene->cursor.location; + int centermode = RNA_enum_get(op->ptr, "type"); + + ListBase ctx_data_list; + CollectionPointerLink *ctx_ob; + CollectionPointerLink *ctx_ob_act = NULL; + + /* keep track of what is changed */ + int tot_change = 0, tot_lib_error = 0, tot_multiuser_arm_error = 0; + + if (obedit && centermode != GEOMETRY_TO_ORIGIN) { + BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode"); + return OPERATOR_CANCELLED; + } + + int around; + { + PropertyRNA *prop_center = RNA_struct_find_property(op->ptr, "center"); + if (RNA_property_is_set(op->ptr, prop_center)) { + around = RNA_property_enum_get(op->ptr, prop_center); + } + else { + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) { + around = V3D_AROUND_CENTER_BOUNDS; + } + else { + around = V3D_AROUND_CENTER_MEDIAN; + } + RNA_property_enum_set(op->ptr, prop_center, around); + } + } + + zero_v3(cent); + + if (obedit) { + if (obedit->type == OB_MESH) { + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_mesh; + BMVert *eve; + BMIter iter; + + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(cent, cursor); + invert_m4_m4(obedit->imat, obedit->obmat); + mul_m4_v3(obedit->imat, cent); + } + else { + if (around == V3D_AROUND_CENTER_MEDIAN) { + if (em->bm->totvert) { + const float total_div = 1.0f / (float)em->bm->totvert; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + madd_v3_v3fl(cent, eve->co, total_div); + } + } + } + else { + float min[3], max[3]; + INIT_MINMAX(min, max); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + minmax_v3v3_v3(min, max, eve->co); + } + mid_v3_v3v3(cent, min, max); + } + } + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + sub_v3_v3(eve->co, cent); + } + + EDBM_mesh_normals_update(em); + tot_change++; + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } + } + + CTX_data_selected_editable_objects(C, &ctx_data_list); + + /* reset flags */ + for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + ob->flag &= ~OB_DONE; + + /* move active first */ + if (ob == obact) { + ctx_ob_act = ctx_ob; + } + } + + if (ctx_ob_act) { + BLI_listbase_rotate_first(&ctx_data_list, (LinkData *)ctx_ob_act); + } + + for (tob = bmain->objects.first; tob; tob = tob->id.next) { + if (tob->data) + ((ID *)tob->data)->tag &= ~LIB_TAG_DOIT; + if (tob->instance_collection) + ((ID *)tob->instance_collection)->tag &= ~LIB_TAG_DOIT; + } + + for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + + if ((ob->flag & OB_DONE) == 0) { + bool do_inverse_offset = false; + ob->flag |= OB_DONE; + + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(cent, cursor); + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->imat, cent); + } + + if (ob->data == NULL) { + /* special support for dupligroups */ + if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection && + (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) { + if (ID_IS_LINKED(ob->instance_collection)) { + tot_lib_error++; + } + else { + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + else { + float min[3], max[3]; + /* only bounds support */ + INIT_MINMAX(min, max); + BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); + mid_v3_v3v3(cent, min, max); + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->imat, cent); + } + + add_v3_v3(ob->instance_collection->instance_offset, cent); + + tot_change++; + ob->instance_collection->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + } + } + else if (ID_IS_LINKED(ob->data)) { + tot_lib_error++; + } + + if (obedit == NULL && ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_SURFACE) { + BKE_mesh_center_of_surface(me, cent); + } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS_VOLUME) { + BKE_mesh_center_of_volume(me, cent); + } + else if (around == V3D_AROUND_CENTER_MEDIAN) { + BKE_mesh_center_median(me, cent); + } + else { + BKE_mesh_center_bounds(me, cent); + } + + negate_v3_v3(cent_neg, cent); + BKE_mesh_translate(me, cent_neg, 1); + + tot_change++; + me->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + Curve *cu = ob->data; + + if (centermode == ORIGIN_TO_CURSOR) { /* done */ + } + else if (around == V3D_AROUND_CENTER_MEDIAN) { + BKE_curve_center_median(cu, cent); + } + else { + BKE_curve_center_bounds(cu, cent); + } + + /* don't allow Z change if curve is 2D */ + if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) + cent[2] = 0.0; + + negate_v3_v3(cent_neg, cent); + BKE_curve_translate(cu, cent_neg, 1); + + tot_change++; + cu->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + + if (obedit) { + if (centermode == GEOMETRY_TO_ORIGIN) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } + break; + } + } + else if (ob->type == OB_FONT) { + /* get from bb */ + + Curve *cu = ob->data; + + if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) { + /* do nothing*/ + } + else { + if (centermode == ORIGIN_TO_CURSOR) { + /* done */ + } + else { + /* extra 0.5 is the height o above line */ + cent[0] = 0.5f * (ob->runtime.bb->vec[4][0] + ob->runtime.bb->vec[0][0]); + cent[1] = 0.5f * (ob->runtime.bb->vec[0][1] + ob->runtime.bb->vec[2][1]); + } + + cent[2] = 0.0f; + + cu->xof = cu->xof - cent[0]; + cu->yof = cu->yof - cent[1]; + + tot_change++; + cu->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + } + else if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; + + if (ID_REAL_USERS(arm) > 1) { #if 0 - BKE_report(op->reports, RPT_ERROR, "Cannot apply to a multi user armature"); - return; + BKE_report(op->reports, RPT_ERROR, "Cannot apply to a multi user armature"); + return; #endif - tot_multiuser_arm_error++; - } - else { - /* Function to recenter armatures in editarmature.c - * Bone + object locations are handled there. - */ - ED_armature_origin_set(bmain, ob, cursor, centermode, around); - - tot_change++; - arm->id.tag |= LIB_TAG_DOIT; - /* do_inverse_offset = true; */ /* docenter_armature() handles this */ - - BKE_object_where_is_calc(depsgraph, scene, ob); - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ - - ignore_parent_tx(C, bmain, scene, ob); - - if (obedit) - break; - } - } - else if (ob->type == OB_MBALL) { - MetaBall *mb = ob->data; - - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { BKE_mball_center_median(mb, cent); } - else { BKE_mball_center_bounds(mb, cent); } - - negate_v3_v3(cent_neg, cent); - BKE_mball_translate(mb, cent_neg); - - tot_change++; - mb->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - - if (obedit) { - if (centermode == GEOMETRY_TO_ORIGIN) { - DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); - } - break; - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_AROUND_CENTER_MEDIAN) { BKE_lattice_center_median(lt, cent); } - else { BKE_lattice_center_bounds(lt, cent); } - - negate_v3_v3(cent_neg, cent); - BKE_lattice_translate(lt, cent_neg, 1); - - tot_change++; - lt->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - else if (ob->type == OB_GPENCIL) { - bGPdata *gpd = ob->data; - float gpcenter[3]; - if (gpd) { - if (centermode == ORIGIN_TO_GEOMETRY) { - zero_v3(gpcenter); - BKE_gpencil_centroid_3d(gpd, gpcenter); - add_v3_v3(gpcenter, ob->obmat[3]); - } - if (centermode == ORIGIN_TO_CURSOR) { - copy_v3_v3(gpcenter, cursor); - } - if ((centermode == ORIGIN_TO_GEOMETRY) || (centermode == ORIGIN_TO_CURSOR)) { - bGPDspoint *pt; - float imat[3][3], bmat[3][3]; - float offset_global[3]; - float offset_local[3]; - int i; - - sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); - copy_m3_m4(bmat, obact->obmat); - invert_m3_m3(imat, bmat); - mul_m3_v3(imat, offset_global); - mul_v3_m3v3(offset_local, imat, offset_global); - - float diff_mat[4][4]; - float inverse_diff_mat[4][4]; - - /* recalculate all strokes - * (all layers are considered without evaluating lock attributes) */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); - /* undo matrix */ - invert_m4_m4(inverse_diff_mat, diff_mat); - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; - - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - float mpt[3]; - mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); - sub_v3_v3(mpt, offset_local); - mul_v3_m4v3(&pt->x, diff_mat, mpt); - } - } - } - } - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - tot_change++; - if (centermode == ORIGIN_TO_GEOMETRY) { - copy_v3_v3(ob->loc, gpcenter); - } - ob->id.tag |= LIB_TAG_DOIT; - do_inverse_offset = true; - } - else { - BKE_report(op->reports, RPT_WARNING, "Grease Pencil Object does not support this set origin option"); - } - } - } - - /* offset other selected objects */ - if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { - CollectionPointerLink *ctx_link_other; - float obmat[4][4]; - - /* was the object data modified - * note: the functions above must set 'cent' */ - - /* convert the offset to parent space */ - BKE_object_to_mat4(ob, obmat); - mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */ - - add_v3_v3(ob->loc, centn); - - BKE_object_where_is_calc(depsgraph, scene, ob); - if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ - } - - ignore_parent_tx(C, bmain, scene, ob); - - /* other users? */ - //CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects) - //{ - - /* use existing context looper */ - for (ctx_link_other = ctx_data_list.first; - ctx_link_other; - ctx_link_other = ctx_link_other->next) - { - Object *ob_other = ctx_link_other->ptr.data; - - if ((ob_other->flag & OB_DONE) == 0 && - ((ob->data && (ob->data == ob_other->data)) || - (ob->instance_collection == ob_other->instance_collection && - (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) - { - ob_other->flag |= OB_DONE; - DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ - add_v3_v3(ob_other->loc, centn); - - BKE_object_where_is_calc(depsgraph, scene, ob_other); - if (ob_other->type == OB_ARMATURE) { - /* needed for bone parents */ - BKE_pose_where_is(depsgraph, scene, ob_other); - } - ignore_parent_tx(C, bmain, scene, ob_other); - } - } - //CTX_DATA_END; - } - } - } - BLI_freelistN(&ctx_data_list); - - for (tob = bmain->objects.first; tob; tob = tob->id.next) { - if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT)) { - BKE_object_batch_cache_dirty_tag(tob); - DEG_id_tag_update(&tob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - } - } - - if (tot_change) { - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - } - - /* Warn if any errors occurred */ - if (tot_lib_error + tot_multiuser_arm_error) { - BKE_reportf(op->reports, RPT_WARNING, "%i object(s) not centered, %i changed:", tot_lib_error + tot_multiuser_arm_error, tot_change); - if (tot_lib_error) - BKE_reportf(op->reports, RPT_WARNING, "|%i linked library object(s)", tot_lib_error); - if (tot_multiuser_arm_error) - BKE_reportf(op->reports, RPT_WARNING, "|%i multiuser armature object(s)", tot_multiuser_arm_error); - } - - return OPERATOR_FINISHED; + tot_multiuser_arm_error++; + } + else { + /* Function to recenter armatures in editarmature.c + * Bone + object locations are handled there. + */ + ED_armature_origin_set(bmain, ob, cursor, centermode, around); + + tot_change++; + arm->id.tag |= LIB_TAG_DOIT; + /* do_inverse_offset = true; */ /* docenter_armature() handles this */ + + BKE_object_where_is_calc(depsgraph, scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + + ignore_parent_tx(C, bmain, scene, ob); + + if (obedit) + break; + } + } + else if (ob->type == OB_MBALL) { + MetaBall *mb = ob->data; + + if (centermode == ORIGIN_TO_CURSOR) { /* done */ + } + else if (around == V3D_AROUND_CENTER_MEDIAN) { + BKE_mball_center_median(mb, cent); + } + else { + BKE_mball_center_bounds(mb, cent); + } + + negate_v3_v3(cent_neg, cent); + BKE_mball_translate(mb, cent_neg); + + tot_change++; + mb->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + + if (obedit) { + if (centermode == GEOMETRY_TO_ORIGIN) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } + break; + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = ob->data; + + if (centermode == ORIGIN_TO_CURSOR) { /* done */ + } + else if (around == V3D_AROUND_CENTER_MEDIAN) { + BKE_lattice_center_median(lt, cent); + } + else { + BKE_lattice_center_bounds(lt, cent); + } + + negate_v3_v3(cent_neg, cent); + BKE_lattice_translate(lt, cent_neg, 1); + + tot_change++; + lt->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + float gpcenter[3]; + if (gpd) { + if (centermode == ORIGIN_TO_GEOMETRY) { + zero_v3(gpcenter); + BKE_gpencil_centroid_3d(gpd, gpcenter); + add_v3_v3(gpcenter, ob->obmat[3]); + } + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(gpcenter, cursor); + } + if ((centermode == ORIGIN_TO_GEOMETRY) || (centermode == ORIGIN_TO_CURSOR)) { + bGPDspoint *pt; + float imat[3][3], bmat[3][3]; + float offset_global[3]; + float offset_local[3]; + int i; + + sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); + copy_m3_m4(bmat, obact->obmat); + invert_m3_m3(imat, bmat); + mul_m3_v3(imat, offset_global); + mul_v3_m3v3(offset_local, imat, offset_global); + + float diff_mat[4][4]; + float inverse_diff_mat[4][4]; + + /* recalculate all strokes + * (all layers are considered without evaluating lock attributes) */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + /* undo matrix */ + invert_m4_m4(inverse_diff_mat, diff_mat); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(&pt->x, diff_mat, mpt); + } + } + } + } + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + tot_change++; + if (centermode == ORIGIN_TO_GEOMETRY) { + copy_v3_v3(ob->loc, gpcenter); + } + ob->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else { + BKE_report(op->reports, + RPT_WARNING, + "Grease Pencil Object does not support this set origin option"); + } + } + } + + /* offset other selected objects */ + if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { + CollectionPointerLink *ctx_link_other; + float obmat[4][4]; + + /* was the object data modified + * note: the functions above must set 'cent' */ + + /* convert the offset to parent space */ + BKE_object_to_mat4(ob, obmat); + mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */ + + add_v3_v3(ob->loc, centn); + + BKE_object_where_is_calc(depsgraph, scene, ob); + if (ob->type == OB_ARMATURE) { + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + } + + ignore_parent_tx(C, bmain, scene, ob); + + /* other users? */ + //CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects) + //{ + + /* use existing context looper */ + for (ctx_link_other = ctx_data_list.first; ctx_link_other; + ctx_link_other = ctx_link_other->next) { + Object *ob_other = ctx_link_other->ptr.data; + + if ((ob_other->flag & OB_DONE) == 0 && + ((ob->data && (ob->data == ob_other->data)) || + (ob->instance_collection == ob_other->instance_collection && + (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) { + ob_other->flag |= OB_DONE; + DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ + add_v3_v3(ob_other->loc, centn); + + BKE_object_where_is_calc(depsgraph, scene, ob_other); + if (ob_other->type == OB_ARMATURE) { + /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob_other); + } + ignore_parent_tx(C, bmain, scene, ob_other); + } + } + //CTX_DATA_END; + } + } + } + BLI_freelistN(&ctx_data_list); + + for (tob = bmain->objects.first; tob; tob = tob->id.next) { + if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT)) { + BKE_object_batch_cache_dirty_tag(tob); + DEG_id_tag_update(&tob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } + } + + if (tot_change) { + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + } + + /* Warn if any errors occurred */ + if (tot_lib_error + tot_multiuser_arm_error) { + BKE_reportf(op->reports, + RPT_WARNING, + "%i object(s) not centered, %i changed:", + tot_lib_error + tot_multiuser_arm_error, + tot_change); + if (tot_lib_error) + BKE_reportf(op->reports, RPT_WARNING, "|%i linked library object(s)", tot_lib_error); + if (tot_multiuser_arm_error) + BKE_reportf( + op->reports, RPT_WARNING, "|%i multiuser armature object(s)", tot_multiuser_arm_error); + } + + return OPERATOR_FINISHED; } void OBJECT_OT_origin_set(wmOperatorType *ot) { - static const EnumPropertyItem prop_set_center_types[] = { - {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"}, - {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", - "Calculate the center of geometry based on the current pivot point (median, otherwise bounding-box)"}, - {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", - "Move object origin to position of the 3D cursor"}, - /* Intentional naming mismatch since some scripts refer to this. */ - {ORIGIN_TO_CENTER_OF_MASS_SURFACE, "ORIGIN_CENTER_OF_MASS", 0, "Origin to Center of Mass (Surface)", - "Calculate the center of mass from the surface area"}, - {ORIGIN_TO_CENTER_OF_MASS_VOLUME, "ORIGIN_CENTER_OF_VOLUME", 0, "Origin to Center of Mass (Volume)", - "Calculate the center of mass from the volume (must be manifold geometry with consistent normals)"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem prop_set_bounds_types[] = { - {V3D_AROUND_CENTER_MEDIAN, "MEDIAN", 0, "Median Center", ""}, - {V3D_AROUND_CENTER_BOUNDS, "BOUNDS", 0, "Bounds Center", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Set Origin"; - ot->description = "Set the object's origin, by either moving the data, or set to center of data, or use 3D cursor"; - ot->idname = "OBJECT_OT_origin_set"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = object_origin_set_exec; - - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", ""); - RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEDIAN, "Center", ""); + static const EnumPropertyItem prop_set_center_types[] = { + {GEOMETRY_TO_ORIGIN, + "GEOMETRY_ORIGIN", + 0, + "Geometry to Origin", + "Move object geometry to object origin"}, + {ORIGIN_TO_GEOMETRY, + "ORIGIN_GEOMETRY", + 0, + "Origin to Geometry", + "Calculate the center of geometry based on the current pivot point (median, otherwise " + "bounding-box)"}, + {ORIGIN_TO_CURSOR, + "ORIGIN_CURSOR", + 0, + "Origin to 3D Cursor", + "Move object origin to position of the 3D cursor"}, + /* Intentional naming mismatch since some scripts refer to this. */ + {ORIGIN_TO_CENTER_OF_MASS_SURFACE, + "ORIGIN_CENTER_OF_MASS", + 0, + "Origin to Center of Mass (Surface)", + "Calculate the center of mass from the surface area"}, + {ORIGIN_TO_CENTER_OF_MASS_VOLUME, + "ORIGIN_CENTER_OF_VOLUME", + 0, + "Origin to Center of Mass (Volume)", + "Calculate the center of mass from the volume (must be manifold geometry with consistent " + "normals)"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem prop_set_bounds_types[] = { + {V3D_AROUND_CENTER_MEDIAN, "MEDIAN", 0, "Median Center", ""}, + {V3D_AROUND_CENTER_BOUNDS, "BOUNDS", 0, "Bounds Center", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Set Origin"; + ot->description = + "Set the object's origin, by either moving the data, or set to center of data, or use 3D " + "cursor"; + ot->idname = "OBJECT_OT_origin_set"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_origin_set_exec; + + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", ""); + RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEDIAN, "Center", ""); } /* -------------------------------------------------------------------- */ @@ -1300,431 +1393,429 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) #define USE_FAKE_DEPTH_INIT struct XFormAxisItem { - Object *ob; - float rot_mat[3][3]; - void *obtfm; - float xform_dist; + Object *ob; + float rot_mat[3][3]; + void *obtfm; + float xform_dist; #ifdef USE_RELATIVE_ROTATION - /* use when translating multiple */ - float xform_rot_offset[3][3]; + /* use when translating multiple */ + float xform_rot_offset[3][3]; #endif }; struct XFormAxisData { - ViewContext vc; - struct { - float depth; - float normal[3]; - bool is_depth_valid; - bool is_normal_valid; - } prev; - - struct XFormAxisItem *object_data; - uint object_data_len; - bool is_translate; - - int init_event; + ViewContext vc; + struct { + float depth; + float normal[3]; + bool is_depth_valid; + bool is_normal_valid; + } prev; + + struct XFormAxisItem *object_data; + uint object_data_len; + bool is_translate; + + int init_event; }; #ifdef USE_FAKE_DEPTH_INIT -static void object_transform_axis_target_calc_depth_init(struct XFormAxisData *xfd, const int mval[2]) +static void object_transform_axis_target_calc_depth_init(struct XFormAxisData *xfd, + const int mval[2]) { - struct XFormAxisItem *item = xfd->object_data; - float view_co_a[3], view_co_b[3]; - const float mval_fl[2] = {UNPACK2(mval)}; - ED_view3d_win_to_ray(xfd->vc.ar, mval_fl, view_co_a, view_co_b); - add_v3_v3(view_co_b, view_co_a); - float center[3] = {0.0f}; - int center_tot = 0; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - const Object *ob = item->ob; - const float *ob_co_a = ob->obmat[3]; - float ob_co_b[3]; - add_v3_v3v3(ob_co_b, ob->obmat[3], ob->obmat[2]); - float view_isect[3], ob_isect[3]; - if (isect_line_line_v3(view_co_a, view_co_b, ob_co_a, ob_co_b, view_isect, ob_isect)) { - add_v3_v3(center, view_isect); - center_tot += 1; - } - } - if (center_tot) { - mul_v3_fl(center, 1.0f / center_tot); - float center_proj[3]; - ED_view3d_project(xfd->vc.ar, center, center_proj); - xfd->prev.depth = center_proj[2]; - xfd->prev.is_depth_valid = true; - } + struct XFormAxisItem *item = xfd->object_data; + float view_co_a[3], view_co_b[3]; + const float mval_fl[2] = {UNPACK2(mval)}; + ED_view3d_win_to_ray(xfd->vc.ar, mval_fl, view_co_a, view_co_b); + add_v3_v3(view_co_b, view_co_a); + float center[3] = {0.0f}; + int center_tot = 0; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + const Object *ob = item->ob; + const float *ob_co_a = ob->obmat[3]; + float ob_co_b[3]; + add_v3_v3v3(ob_co_b, ob->obmat[3], ob->obmat[2]); + float view_isect[3], ob_isect[3]; + if (isect_line_line_v3(view_co_a, view_co_b, ob_co_a, ob_co_b, view_isect, ob_isect)) { + add_v3_v3(center, view_isect); + center_tot += 1; + } + } + if (center_tot) { + mul_v3_fl(center, 1.0f / center_tot); + float center_proj[3]; + ED_view3d_project(xfd->vc.ar, center, center_proj); + xfd->prev.depth = center_proj[2]; + xfd->prev.is_depth_valid = true; + } } -#endif /* USE_FAKE_DEPTH_INIT */ +#endif /* USE_FAKE_DEPTH_INIT */ static bool object_is_target_compat(const Object *ob) { - if (ob->type == OB_LAMP) { - const Light *la = ob->data; - if (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA)) { - return true; - } - } - /* We might want to enable this later, for now just lights. */ + if (ob->type == OB_LAMP) { + const Light *la = ob->data; + if (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA)) { + return true; + } + } + /* We might want to enable this later, for now just lights. */ #if 0 - else if (ob->type == OB_CAMERA) { - return true; - } + else if (ob->type == OB_CAMERA) { + return true; + } #endif - return false; + return false; } static void object_transform_axis_target_free_data(wmOperator *op) { - struct XFormAxisData *xfd = op->customdata; - struct XFormAxisItem *item = xfd->object_data; + struct XFormAxisData *xfd = op->customdata; + struct XFormAxisItem *item = xfd->object_data; #ifdef USE_RENDER_OVERRIDE - if (xfd->vc.rv3d->depths) { - xfd->vc.rv3d->depths->damaged = true; - } + if (xfd->vc.rv3d->depths) { + xfd->vc.rv3d->depths->damaged = true; + } #endif - for (int i = 0; i < xfd->object_data_len; i++, item++) { - MEM_freeN(item->obtfm); - } - MEM_freeN(xfd->object_data); - MEM_freeN(xfd); - op->customdata = NULL; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + MEM_freeN(item->obtfm); + } + MEM_freeN(xfd->object_data); + MEM_freeN(xfd); + op->customdata = NULL; } /* We may want to expose as alternative to: BKE_object_apply_rotation */ static void object_apply_rotation(Object *ob, const float rmat[3][3]) { - float size[3]; - float loc[3]; - float rmat4[4][4]; - copy_m4_m3(rmat4, rmat); - - copy_v3_v3(size, ob->scale); - copy_v3_v3(loc, ob->loc); - BKE_object_apply_mat4(ob, rmat4, true, true); - copy_v3_v3(ob->scale, size); - copy_v3_v3(ob->loc, loc); + float size[3]; + float loc[3]; + float rmat4[4][4]; + copy_m4_m3(rmat4, rmat); + + copy_v3_v3(size, ob->scale); + copy_v3_v3(loc, ob->loc); + BKE_object_apply_mat4(ob, rmat4, true, true); + copy_v3_v3(ob->scale, size); + copy_v3_v3(ob->loc, loc); } /* We may want to extract this to: BKE_object_apply_location */ static void object_apply_location(Object *ob, const float loc[3]) { - /* quick but weak */ - Object ob_prev = *ob; - float mat[4][4]; - copy_m4_m4(mat, ob->obmat); - copy_v3_v3(mat[3], loc); - BKE_object_apply_mat4(ob, mat, true, true); - copy_v3_v3(mat[3], ob->loc); - *ob = ob_prev; - copy_v3_v3(ob->loc, mat[3]); + /* quick but weak */ + Object ob_prev = *ob; + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + copy_v3_v3(mat[3], loc); + BKE_object_apply_mat4(ob, mat, true, true); + copy_v3_v3(mat[3], ob->loc); + *ob = ob_prev; + copy_v3_v3(ob->loc, mat[3]); } -static void object_orient_to_location( - Object *ob, float rot_orig[3][3], const float axis[3], const float location[3]) +static void object_orient_to_location(Object *ob, + float rot_orig[3][3], + const float axis[3], + const float location[3]) { - float delta[3]; - sub_v3_v3v3(delta, ob->obmat[3], location); - if (normalize_v3(delta) != 0.0f) { - if (len_squared_v3v3(delta, axis) > FLT_EPSILON) { - float delta_rot[3][3]; - float final_rot[3][3]; - rotation_between_vecs_to_mat3(delta_rot, axis, delta); + float delta[3]; + sub_v3_v3v3(delta, ob->obmat[3], location); + if (normalize_v3(delta) != 0.0f) { + if (len_squared_v3v3(delta, axis) > FLT_EPSILON) { + float delta_rot[3][3]; + float final_rot[3][3]; + rotation_between_vecs_to_mat3(delta_rot, axis, delta); - mul_m3_m3m3(final_rot, delta_rot, rot_orig); + mul_m3_m3m3(final_rot, delta_rot, rot_orig); - object_apply_rotation(ob, final_rot); + object_apply_rotation(ob, final_rot); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - } + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + } } static void object_transform_axis_target_cancel(bContext *C, wmOperator *op) { - struct XFormAxisData *xfd = op->customdata; - struct XFormAxisItem *item = xfd->object_data; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - BKE_object_tfm_restore(item->ob, item->obtfm); - DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); - } - - object_transform_axis_target_free_data(op); + struct XFormAxisData *xfd = op->customdata; + struct XFormAxisItem *item = xfd->object_data; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + BKE_object_tfm_restore(item->ob, item->obtfm); + DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); + } + + object_transform_axis_target_free_data(op); } static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); - - if (vc.obact == NULL || !object_is_target_compat(vc.obact)) { - /* Falls back to texture space transform. */ - return OPERATOR_PASS_THROUGH; - } + ViewContext vc; + ED_view3d_viewcontext_init(C, &vc); + if (vc.obact == NULL || !object_is_target_compat(vc.obact)) { + /* Falls back to texture space transform. */ + return OPERATOR_PASS_THROUGH; + } #ifdef USE_RENDER_OVERRIDE - int flag2_prev = vc.v3d->flag2; - vc.v3d->flag2 |= V3D_HIDE_OVERLAYS; + int flag2_prev = vc.v3d->flag2; + vc.v3d->flag2 |= V3D_HIDE_OVERLAYS; #endif - ED_view3d_autodist_init(vc.depsgraph, vc.ar, vc.v3d, 0); + ED_view3d_autodist_init(vc.depsgraph, vc.ar, vc.v3d, 0); - if (vc.rv3d->depths != NULL) { - vc.rv3d->depths->damaged = true; - } - ED_view3d_depth_update(vc.ar); + if (vc.rv3d->depths != NULL) { + vc.rv3d->depths->damaged = true; + } + ED_view3d_depth_update(vc.ar); #ifdef USE_RENDER_OVERRIDE - vc.v3d->flag2 = flag2_prev; + vc.v3d->flag2 = flag2_prev; #endif - if (vc.rv3d->depths == NULL) { - BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane"); - return OPERATOR_CANCELLED; - } + if (vc.rv3d->depths == NULL) { + BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane"); + return OPERATOR_CANCELLED; + } - ED_region_tag_redraw(vc.ar); + ED_region_tag_redraw(vc.ar); - struct XFormAxisData *xfd; - xfd = op->customdata = MEM_callocN(sizeof(struct XFormAxisData), __func__); + struct XFormAxisData *xfd; + xfd = op->customdata = MEM_callocN(sizeof(struct XFormAxisData), __func__); - /* Don't change this at runtime. */ - xfd->vc = vc; - xfd->vc.mval[0] = event->mval[0]; - xfd->vc.mval[1] = event->mval[1]; + /* Don't change this at runtime. */ + xfd->vc = vc; + xfd->vc.mval[0] = event->mval[0]; + xfd->vc.mval[1] = event->mval[1]; - xfd->prev.depth = 1.0f; - xfd->prev.is_depth_valid = false; - xfd->prev.is_normal_valid = false; - xfd->is_translate = false; + xfd->prev.depth = 1.0f; + xfd->prev.is_depth_valid = false; + xfd->prev.is_normal_valid = false; + xfd->is_translate = false; - xfd->init_event = WM_userdef_event_type_from_keymap_type(event->type); + xfd->init_event = WM_userdef_event_type_from_keymap_type(event->type); - { - struct XFormAxisItem *object_data = NULL; - BLI_array_declare(object_data); + { + struct XFormAxisItem *object_data = NULL; + BLI_array_declare(object_data); - struct XFormAxisItem *item = BLI_array_append_ret(object_data); - item->ob = xfd->vc.obact; + struct XFormAxisItem *item = BLI_array_append_ret(object_data); + item->ob = xfd->vc.obact; - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) { - item = BLI_array_append_ret(object_data); - item->ob = ob; - } - } - CTX_DATA_END; + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) { + item = BLI_array_append_ret(object_data); + item->ob = ob; + } + } + CTX_DATA_END; - xfd->object_data = object_data; - xfd->object_data_len = BLI_array_len(object_data); + xfd->object_data = object_data; + xfd->object_data_len = BLI_array_len(object_data); - if (xfd->object_data_len != BLI_array_len(object_data)) { - xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data)); - } - } + if (xfd->object_data_len != BLI_array_len(object_data)) { + xfd->object_data = MEM_reallocN(xfd->object_data, + xfd->object_data_len * sizeof(*xfd->object_data)); + } + } - { - struct XFormAxisItem *item = xfd->object_data; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - item->obtfm = BKE_object_tfm_backup(item->ob); - BKE_object_rot_to_mat3(item->ob, item->rot_mat, true); - } - } + { + struct XFormAxisItem *item = xfd->object_data; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + item->obtfm = BKE_object_tfm_backup(item->ob); + BKE_object_rot_to_mat3(item->ob, item->rot_mat, true); + } + } - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const wmEvent *event) { - struct XFormAxisData *xfd = op->customdata; - ARegion *ar = xfd->vc.ar; - - view3d_operator_needs_opengl(C); - - const bool is_translate = (event->ctrl != 0); - const bool is_translate_init = is_translate && (xfd->is_translate != is_translate); - - if (event->type == MOUSEMOVE || is_translate_init) { - const ViewDepths *depths = xfd->vc.rv3d->depths; - if (depths && - ((unsigned int)event->mval[0] < depths->w) && - ((unsigned int)event->mval[1] < depths->h)) - { - double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval); - float location_world[3]; - if (depth == 1.0f) { - if (xfd->prev.is_depth_valid) { - depth = (double)xfd->prev.depth; - } - } + struct XFormAxisData *xfd = op->customdata; + ARegion *ar = xfd->vc.ar; + + view3d_operator_needs_opengl(C); + + const bool is_translate = (event->ctrl != 0); + const bool is_translate_init = is_translate && (xfd->is_translate != is_translate); + + if (event->type == MOUSEMOVE || is_translate_init) { + const ViewDepths *depths = xfd->vc.rv3d->depths; + if (depths && ((unsigned int)event->mval[0] < depths->w) && + ((unsigned int)event->mval[1] < depths->h)) { + double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval); + float location_world[3]; + if (depth == 1.0f) { + if (xfd->prev.is_depth_valid) { + depth = (double)xfd->prev.depth; + } + } #ifdef USE_FAKE_DEPTH_INIT - /* First time only. */ - if (depth == 1.0f) { - if (xfd->prev.is_depth_valid == false) { - object_transform_axis_target_calc_depth_init(xfd, event->mval); - if (xfd->prev.is_depth_valid) { - depth = (double)xfd->prev.depth; - } - } - } + /* First time only. */ + if (depth == 1.0f) { + if (xfd->prev.is_depth_valid == false) { + object_transform_axis_target_calc_depth_init(xfd, event->mval); + if (xfd->prev.is_depth_valid) { + depth = (double)xfd->prev.depth; + } + } + } #endif - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - xfd->prev.depth = depth; - xfd->prev.is_depth_valid = true; - if (ED_view3d_depth_unproject(ar, event->mval, depth, location_world)) { - if (is_translate) { - - float normal[3]; - bool normal_found = false; - if (ED_view3d_depth_read_cached_normal(&xfd->vc, event->mval, normal)) { - normal_found = true; - - /* cheap attempt to smooth normals out a bit! */ - const uint ofs = 2; - for (uint x = -ofs; x <= ofs; x += ofs / 2) { - for (uint y = -ofs; y <= ofs; y += ofs / 2) { - if (x != 0 && y != 0) { - int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y}; - float n[3]; - if (ED_view3d_depth_read_cached_normal( - &xfd->vc, mval_ofs, n)) - { - add_v3_v3(normal, n); - } - } - } - } - normalize_v3(normal); - } - else if (xfd->prev.is_normal_valid) { - copy_v3_v3(normal, xfd->prev.normal); - normal_found = true; - } - - if (normal_found) { + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + xfd->prev.depth = depth; + xfd->prev.is_depth_valid = true; + if (ED_view3d_depth_unproject(ar, event->mval, depth, location_world)) { + if (is_translate) { + + float normal[3]; + bool normal_found = false; + if (ED_view3d_depth_read_cached_normal(&xfd->vc, event->mval, normal)) { + normal_found = true; + + /* cheap attempt to smooth normals out a bit! */ + const uint ofs = 2; + for (uint x = -ofs; x <= ofs; x += ofs / 2) { + for (uint y = -ofs; y <= ofs; y += ofs / 2) { + if (x != 0 && y != 0) { + int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y}; + float n[3]; + if (ED_view3d_depth_read_cached_normal(&xfd->vc, mval_ofs, n)) { + add_v3_v3(normal, n); + } + } + } + } + normalize_v3(normal); + } + else if (xfd->prev.is_normal_valid) { + copy_v3_v3(normal, xfd->prev.normal); + normal_found = true; + } + + if (normal_found) { #ifdef USE_RELATIVE_ROTATION - if (is_translate_init && xfd->object_data_len > 1) { - float xform_rot_offset_inv_first[3][3]; - struct XFormAxisItem *item = xfd->object_data; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - copy_m3_m4(item->xform_rot_offset, item->ob->obmat); - normalize_m3(item->xform_rot_offset); - - if (i == 0) { - invert_m3_m3(xform_rot_offset_inv_first, xfd->object_data[0].xform_rot_offset); - } - else { - mul_m3_m3m3(item->xform_rot_offset, - item->xform_rot_offset, - xform_rot_offset_inv_first); - } - } - } + if (is_translate_init && xfd->object_data_len > 1) { + float xform_rot_offset_inv_first[3][3]; + struct XFormAxisItem *item = xfd->object_data; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + copy_m3_m4(item->xform_rot_offset, item->ob->obmat); + normalize_m3(item->xform_rot_offset); + + if (i == 0) { + invert_m3_m3(xform_rot_offset_inv_first, xfd->object_data[0].xform_rot_offset); + } + else { + mul_m3_m3m3(item->xform_rot_offset, + item->xform_rot_offset, + xform_rot_offset_inv_first); + } + } + } #endif - struct XFormAxisItem *item = xfd->object_data; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - if (is_translate_init) { - float ob_axis[3]; - item->xform_dist = len_v3v3(item->ob->obmat[3], location_world); - normalize_v3_v3(ob_axis, item->ob->obmat[2]); - /* Scale to avoid adding distance when moving between surfaces. */ - float scale = fabsf(dot_v3v3(ob_axis, normal)); - item->xform_dist *= scale; - } + struct XFormAxisItem *item = xfd->object_data; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + if (is_translate_init) { + float ob_axis[3]; + item->xform_dist = len_v3v3(item->ob->obmat[3], location_world); + normalize_v3_v3(ob_axis, item->ob->obmat[2]); + /* Scale to avoid adding distance when moving between surfaces. */ + float scale = fabsf(dot_v3v3(ob_axis, normal)); + item->xform_dist *= scale; + } - float target_normal[3]; - copy_v3_v3(target_normal, normal); + float target_normal[3]; + copy_v3_v3(target_normal, normal); #ifdef USE_RELATIVE_ROTATION - if (i != 0) { - mul_m3_v3(item->xform_rot_offset, target_normal); - } + if (i != 0) { + mul_m3_v3(item->xform_rot_offset, target_normal); + } #endif - { - float loc[3]; - - copy_v3_v3(loc, location_world); - madd_v3_v3fl(loc, target_normal, item->xform_dist); - object_apply_location(item->ob, loc); - /* so orient behaves as expected */ - copy_v3_v3(item->ob->obmat[3], loc); - } - - object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); - } - copy_v3_v3(xfd->prev.normal, normal); - xfd->prev.is_normal_valid = true; - } - } - else { - struct XFormAxisItem *item = xfd->object_data; - for (int i = 0; i < xfd->object_data_len; i++, item++) { - object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); - } - xfd->prev.is_normal_valid = false; - } - } - } - } - xfd->is_translate = is_translate; - - ED_region_tag_redraw(xfd->vc.ar); - } - - bool is_finished = false; - - if (ISMOUSE(xfd->init_event)) { - if ((event->type == xfd->init_event) && (event->val == KM_RELEASE)) { - is_finished = true; - } - } - else { - if (ELEM(event->type, LEFTMOUSE, RETKEY, PADENTER)) { - is_finished = true; - } - } - - if (is_finished) { - object_transform_axis_target_free_data(op); - return OPERATOR_FINISHED; - } - else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) { - object_transform_axis_target_cancel(C, op); - return OPERATOR_CANCELLED; - } - - - return OPERATOR_RUNNING_MODAL; + { + float loc[3]; + + copy_v3_v3(loc, location_world); + madd_v3_v3fl(loc, target_normal, item->xform_dist); + object_apply_location(item->ob, loc); + /* so orient behaves as expected */ + copy_v3_v3(item->ob->obmat[3], loc); + } + + object_orient_to_location( + item->ob, item->rot_mat, item->rot_mat[2], location_world); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); + } + copy_v3_v3(xfd->prev.normal, normal); + xfd->prev.is_normal_valid = true; + } + } + else { + struct XFormAxisItem *item = xfd->object_data; + for (int i = 0; i < xfd->object_data_len; i++, item++) { + object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); + } + xfd->prev.is_normal_valid = false; + } + } + } + } + xfd->is_translate = is_translate; + + ED_region_tag_redraw(xfd->vc.ar); + } + + bool is_finished = false; + + if (ISMOUSE(xfd->init_event)) { + if ((event->type == xfd->init_event) && (event->val == KM_RELEASE)) { + is_finished = true; + } + } + else { + if (ELEM(event->type, LEFTMOUSE, RETKEY, PADENTER)) { + is_finished = true; + } + } + + if (is_finished) { + object_transform_axis_target_free_data(op); + return OPERATOR_FINISHED; + } + else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) { + object_transform_axis_target_cancel(C, op); + return OPERATOR_CANCELLED; + } + + return OPERATOR_RUNNING_MODAL; } void OBJECT_OT_transform_axis_target(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Interactive Light Track to Cursor"; - ot->description = "Interactively point cameras and lights to a location (Ctrl translates)"; - ot->idname = "OBJECT_OT_transform_axis_target"; - - /* api callbacks */ - ot->invoke = object_transform_axis_target_invoke; - ot->cancel = object_transform_axis_target_cancel; - ot->modal = object_transform_axis_target_modal; - ot->poll = ED_operator_region_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + /* identifiers */ + ot->name = "Interactive Light Track to Cursor"; + ot->description = "Interactively point cameras and lights to a location (Ctrl translates)"; + ot->idname = "OBJECT_OT_transform_axis_target"; + + /* api callbacks */ + ot->invoke = object_transform_axis_target_invoke; + ot->cancel = object_transform_axis_target_cancel; + ot->modal = object_transform_axis_target_modal; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; } #undef USE_RELATIVE_ROTATION diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 39f5dad7698..06a755c30bd 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -39,111 +39,106 @@ #include "ED_armature.h" #include "ED_curve.h" -#include "ED_object.h" /* own include */ - +#include "ED_object.h" /* own include */ /* -------------------------------------------------------------------- */ /** \name Active Element Center * \{ */ -bool ED_object_calc_active_center_for_editmode( - Object *obedit, const bool select_only, float r_center[3]) +bool ED_object_calc_active_center_for_editmode(Object *obedit, + const bool select_only, + float r_center[3]) { - switch (obedit->type) { - case OB_MESH: - { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMEditSelection ese; - - if (BM_select_history_active_get(em->bm, &ese)) { - BM_editselection_center(&ese, r_center); - return true; - } - break; - } - case OB_ARMATURE: - { - bArmature *arm = obedit->data; - EditBone *ebo = arm->act_edbone; - - if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) { - copy_v3_v3(r_center, ebo->head); - return true; - } - - break; - } - case OB_CURVE: - case OB_SURF: - { - Curve *cu = obedit->data; - - if (ED_curve_active_center(cu, r_center)) { - return true; - } - break; - } - case OB_MBALL: - { - MetaBall *mb = obedit->data; - MetaElem *ml_act = mb->lastelem; - - if (ml_act && (!select_only || (ml_act->flag & SELECT))) { - copy_v3_v3(r_center, &ml_act->x); - return true; - } - break; - } - case OB_LATTICE: - { - BPoint *actbp = BKE_lattice_active_point_get(obedit->data); - - if (actbp) { - copy_v3_v3(r_center, actbp->vec); - return true; - } - break; - } - } - - return false; + switch (obedit->type) { + case OB_MESH: { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMEditSelection ese; + + if (BM_select_history_active_get(em->bm, &ese)) { + BM_editselection_center(&ese, r_center); + return true; + } + break; + } + case OB_ARMATURE: { + bArmature *arm = obedit->data; + EditBone *ebo = arm->act_edbone; + + if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) { + copy_v3_v3(r_center, ebo->head); + return true; + } + + break; + } + case OB_CURVE: + case OB_SURF: { + Curve *cu = obedit->data; + + if (ED_curve_active_center(cu, r_center)) { + return true; + } + break; + } + case OB_MBALL: { + MetaBall *mb = obedit->data; + MetaElem *ml_act = mb->lastelem; + + if (ml_act && (!select_only || (ml_act->flag & SELECT))) { + copy_v3_v3(r_center, &ml_act->x); + return true; + } + break; + } + case OB_LATTICE: { + BPoint *actbp = BKE_lattice_active_point_get(obedit->data); + + if (actbp) { + copy_v3_v3(r_center, actbp->vec); + return true; + } + break; + } + } + + return false; } -bool ED_object_calc_active_center_for_posemode( - Object *ob, const bool select_only, float r_center[3]) +bool ED_object_calc_active_center_for_posemode(Object *ob, + const bool select_only, + float r_center[3]) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); - if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { - copy_v3_v3(r_center, pchan->pose_head); - return true; - } - return false; + bPoseChannel *pchan = BKE_pose_channel_active(ob); + if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { + copy_v3_v3(r_center, pchan->pose_head); + return true; + } + return false; } -bool ED_object_calc_active_center( - Object *ob, const bool select_only, float r_center[3]) +bool ED_object_calc_active_center(Object *ob, const bool select_only, float r_center[3]) { - if (ob->mode & OB_MODE_EDIT) { - if (ED_object_calc_active_center_for_editmode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); - return true; - } - return false; - } - else if (ob->mode & OB_MODE_POSE) { - if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); - return true; - } - return false; - } - else { - if (!select_only || (ob->flag & SELECT)) { - copy_v3_v3(r_center, ob->obmat[3]); - return true; - } - return false; - } + if (ob->mode & OB_MODE_EDIT) { + if (ED_object_calc_active_center_for_editmode(ob, select_only, r_center)) { + mul_m4_v3(ob->obmat, r_center); + return true; + } + return false; + } + else if (ob->mode & OB_MODE_POSE) { + if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { + mul_m4_v3(ob->obmat, r_center); + return true; + } + return false; + } + else { + if (!select_only || (ob->flag & SELECT)) { + copy_v3_v3(r_center, ob->obmat[3]); + return true; + } + return false; + } } /** \} */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index cd8b7d082ef..9af0b64bde2 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -44,7 +44,6 @@ #include "BLI_utildefines.h" #include "BLI_utildefines_stack.h" - #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -78,40 +77,39 @@ /************************ Exported Functions **********************/ static bool vertex_group_use_vert_sel(Object *ob) { - if (ob->mode == OB_MODE_EDIT) { - return true; - } - else if ((ob->type == OB_MESH) && - ((Mesh *)ob->data)->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) - { - return true; - } - else { - return false; - } + if (ob->mode == OB_MODE_EDIT) { + return true; + } + else if ((ob->type == OB_MESH) && + ((Mesh *)ob->data)->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) { + return true; + } + else { + return false; + } } static Lattice *vgroup_edit_lattice(Object *ob) { - Lattice *lt = ob->data; - BLI_assert(ob->type == OB_LATTICE); - return (lt->editlatt) ? lt->editlatt->latt : lt; + Lattice *lt = ob->data; + BLI_assert(ob->type == OB_LATTICE); + return (lt->editlatt) ? lt->editlatt->latt : lt; } bool ED_vgroup_sync_from_pose(Object *ob) { - Object *armobj = BKE_object_pose_armature_get(ob); - if (armobj && (armobj->mode & OB_MODE_POSE)) { - struct bArmature *arm = armobj->data; - if (arm->act_bone) { - int def_num = defgroup_name_index(ob, arm->act_bone->name); - if (def_num != -1) { - ob->actdef = def_num + 1; - return true; - } - } - } - return false; + Object *armobj = BKE_object_pose_armature_get(ob); + if (armobj && (armobj->mode & OB_MODE_POSE)) { + struct bArmature *arm = armobj->data; + if (arm->act_bone) { + int def_num = defgroup_name_index(ob, arm->act_bone->name); + if (def_num != -1) { + ob->actdef = def_num + 1; + return true; + } + } + } + return false; } /** @@ -119,128 +117,128 @@ bool ED_vgroup_sync_from_pose(Object *ob) */ void ED_vgroup_data_clamp_range(ID *id, const int total) { - MDeformVert **dvert_arr; - int dvert_tot; - - if (ED_vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) { - int i; - for (i = 0; i < dvert_tot; i++) { - MDeformVert *dv = dvert_arr[i]; - int j; - for (j = 0; j < dv->totweight; j++) { - if (dv->dw[j].def_nr >= total) { - defvert_remove_group(dv, &dv->dw[j]); - j--; - } - } - } - } -} - -bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel) -{ - *dvert_tot = 0; - *dvert_arr = NULL; - - if (id) { - switch (GS(id->name)) { - case ID_ME: - { - Mesh *me = (Mesh *)id; - - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - BMesh *bm = em->bm; - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - BMIter iter; - BMVert *eve; - int i; - - if (cd_dvert_offset == -1) { - return false; - } - - i = em->bm->totvert; - - *dvert_arr = MEM_mallocN(sizeof(void *) * i, "vgroup parray from me"); - *dvert_tot = i; - - i = 0; - if (use_vert_sel) { - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ? - BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset) : NULL; - i++; - } - } - else { - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - (*dvert_arr)[i] = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - i++; - } - } - - return true; - } - else if (me->dvert) { - MVert *mvert = me->mvert; - MDeformVert *dvert = me->dvert; - int i; - - *dvert_tot = me->totvert; - *dvert_arr = MEM_mallocN(sizeof(void *) * me->totvert, "vgroup parray from me"); - - if (use_vert_sel) { - for (i = 0; i < me->totvert; i++) { - (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? - &dvert[i] : NULL; - } - } - else { - for (i = 0; i < me->totvert; i++) { - (*dvert_arr)[i] = me->dvert + i; - } - } - - return true; - } - return false; - } - case ID_LT: - { - int i = 0; - - Lattice *lt = (Lattice *)id; - lt = (lt->editlatt) ? lt->editlatt->latt : lt; - - if (lt->dvert) { - BPoint *def = lt->def; - *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; - *dvert_arr = MEM_mallocN(sizeof(void *) * (*dvert_tot), "vgroup parray from me"); - - if (use_vert_sel) { - for (i = 0; i < *dvert_tot; i++) { - (*dvert_arr)[i] = (def->f1 & SELECT) ? - <->dvert[i] : NULL; - } - } - else { - for (i = 0; i < *dvert_tot; i++) { - (*dvert_arr)[i] = lt->dvert + i; - } - } - - return true; - } - return false; - } - - default: - break; - } - } - - return false; + MDeformVert **dvert_arr; + int dvert_tot; + + if (ED_vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) { + int i; + for (i = 0; i < dvert_tot; i++) { + MDeformVert *dv = dvert_arr[i]; + int j; + for (j = 0; j < dv->totweight; j++) { + if (dv->dw[j].def_nr >= total) { + defvert_remove_group(dv, &dv->dw[j]); + j--; + } + } + } + } +} + +bool ED_vgroup_parray_alloc(ID *id, + MDeformVert ***dvert_arr, + int *dvert_tot, + const bool use_vert_sel) +{ + *dvert_tot = 0; + *dvert_arr = NULL; + + if (id) { + switch (GS(id->name)) { + case ID_ME: { + Mesh *me = (Mesh *)id; + + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + BMesh *bm = em->bm; + const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + BMIter iter; + BMVert *eve; + int i; + + if (cd_dvert_offset == -1) { + return false; + } + + i = em->bm->totvert; + + *dvert_arr = MEM_mallocN(sizeof(void *) * i, "vgroup parray from me"); + *dvert_tot = i; + + i = 0; + if (use_vert_sel) { + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ? + BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset) : + NULL; + i++; + } + } + else { + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + (*dvert_arr)[i] = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + i++; + } + } + + return true; + } + else if (me->dvert) { + MVert *mvert = me->mvert; + MDeformVert *dvert = me->dvert; + int i; + + *dvert_tot = me->totvert; + *dvert_arr = MEM_mallocN(sizeof(void *) * me->totvert, "vgroup parray from me"); + + if (use_vert_sel) { + for (i = 0; i < me->totvert; i++) { + (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? &dvert[i] : NULL; + } + } + else { + for (i = 0; i < me->totvert; i++) { + (*dvert_arr)[i] = me->dvert + i; + } + } + + return true; + } + return false; + } + case ID_LT: { + int i = 0; + + Lattice *lt = (Lattice *)id; + lt = (lt->editlatt) ? lt->editlatt->latt : lt; + + if (lt->dvert) { + BPoint *def = lt->def; + *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw; + *dvert_arr = MEM_mallocN(sizeof(void *) * (*dvert_tot), "vgroup parray from me"); + + if (use_vert_sel) { + for (i = 0; i < *dvert_tot; i++) { + (*dvert_arr)[i] = (def->f1 & SELECT) ? <->dvert[i] : NULL; + } + } + else { + for (i = 0; i < *dvert_tot; i++) { + (*dvert_arr)[i] = lt->dvert + i; + } + } + + return true; + } + return false; + } + + default: + break; + } + } + + return false; } /** @@ -249,45 +247,46 @@ bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, co * * \note \a dvert_array has mirrored weights filled in, in case cleanup operations are needed on both. */ -void ED_vgroup_parray_mirror_sync( - Object *ob, - MDeformVert **dvert_array, const int dvert_tot, - const bool *vgroup_validmap, const int vgroup_tot) -{ - BMEditMesh *em = BKE_editmesh_from_object(ob); - MDeformVert **dvert_array_all = NULL; - int dvert_tot_all; - - /* get an array of all verts, not only selected */ - if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { - BLI_assert(0); - return; - } - if (em) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - - int flip_map_len; - const int *flip_map = defgroup_flip_map(ob, &flip_map_len, true); - - for (int i_src = 0; i_src < dvert_tot; i_src++) { - if (dvert_array[i_src] != NULL) { - /* its selected, check if its mirror exists */ - int i_dst = ED_mesh_mirror_get_vert(ob, i_src); - if (i_dst != -1 && dvert_array_all[i_dst] != NULL) { - /* we found a match! */ - const MDeformVert *dv_src = dvert_array[i_src]; - MDeformVert *dv_dst = dvert_array_all[i_dst]; - - defvert_mirror_subset(dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len); - - dvert_array[i_dst] = dvert_array_all[i_dst]; - } - } - } - - MEM_freeN((void *)flip_map); - MEM_freeN(dvert_array_all); +void ED_vgroup_parray_mirror_sync(Object *ob, + MDeformVert **dvert_array, + const int dvert_tot, + const bool *vgroup_validmap, + const int vgroup_tot) +{ + BMEditMesh *em = BKE_editmesh_from_object(ob); + MDeformVert **dvert_array_all = NULL; + int dvert_tot_all; + + /* get an array of all verts, not only selected */ + if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + BLI_assert(0); + return; + } + if (em) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + + int flip_map_len; + const int *flip_map = defgroup_flip_map(ob, &flip_map_len, true); + + for (int i_src = 0; i_src < dvert_tot; i_src++) { + if (dvert_array[i_src] != NULL) { + /* its selected, check if its mirror exists */ + int i_dst = ED_mesh_mirror_get_vert(ob, i_src); + if (i_dst != -1 && dvert_array_all[i_dst] != NULL) { + /* we found a match! */ + const MDeformVert *dv_src = dvert_array[i_src]; + MDeformVert *dv_dst = dvert_array_all[i_dst]; + + defvert_mirror_subset(dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len); + + dvert_array[i_dst] = dvert_array_all[i_dst]; + } + } + } + + MEM_freeN((void *)flip_map); + MEM_freeN(dvert_array_all); } /** @@ -295,247 +294,252 @@ void ED_vgroup_parray_mirror_sync( * * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points. */ -void ED_vgroup_parray_mirror_assign( - Object *ob, - MDeformVert **dvert_array, const int dvert_tot) -{ - BMEditMesh *em = BKE_editmesh_from_object(ob); - MDeformVert **dvert_array_all = NULL; - int dvert_tot_all; - int i; - - /* get an array of all verts, not only selected */ - if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { - BLI_assert(0); - return; - } - BLI_assert(dvert_tot == dvert_tot_all); - if (em) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - - for (i = 0; i < dvert_tot; i++) { - if (dvert_array[i] == NULL) { - /* its unselected, check if its mirror is */ - int i_sel = ED_mesh_mirror_get_vert(ob, i); - if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) { - /* we found a match! */ - dvert_array[i] = dvert_array_all[i]; - } - } - } - - MEM_freeN(dvert_array_all); -} - -void ED_vgroup_parray_remove_zero( - MDeformVert **dvert_array, const int dvert_tot, - const bool *vgroup_validmap, const int vgroup_tot, - const float epsilon, const bool keep_single) -{ - MDeformVert *dv; - int i; - - for (i = 0; i < dvert_tot; i++) { - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - j = dv->totweight; - - while (j--) { - MDeformWeight *dw; - - if (keep_single && dv->totweight == 1) - break; - - dw = dv->dw + j; - if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { - if (dw->weight <= epsilon) { - defvert_remove_group(dv, dw); - } - } - } - } +void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot) +{ + BMEditMesh *em = BKE_editmesh_from_object(ob); + MDeformVert **dvert_array_all = NULL; + int dvert_tot_all; + int i; + + /* get an array of all verts, not only selected */ + if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + BLI_assert(0); + return; + } + BLI_assert(dvert_tot == dvert_tot_all); + if (em) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + + for (i = 0; i < dvert_tot; i++) { + if (dvert_array[i] == NULL) { + /* its unselected, check if its mirror is */ + int i_sel = ED_mesh_mirror_get_vert(ob, i); + if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) { + /* we found a match! */ + dvert_array[i] = dvert_array_all[i]; + } + } + } + + MEM_freeN(dvert_array_all); +} + +void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, + const int dvert_tot, + const bool *vgroup_validmap, + const int vgroup_tot, + const float epsilon, + const bool keep_single) +{ + MDeformVert *dv; + int i; + + for (i = 0; i < dvert_tot; i++) { + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + j = dv->totweight; + + while (j--) { + MDeformWeight *dw; + + if (keep_single && dv->totweight == 1) + break; + + dw = dv->dw + j; + if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { + if (dw->weight <= epsilon) { + defvert_remove_group(dv, dw); + } + } + } + } } /* matching index only */ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) { - MDeformVert **dvert_array_from = NULL, **dvf; - MDeformVert **dvert_array = NULL, **dv; - int dvert_tot_from; - int dvert_tot; - int i; - int defbase_tot_from = BLI_listbase_count(&ob_from->defbase); - int defbase_tot = BLI_listbase_count(&ob->defbase); - bool new_vgroup = false; - - if (ob == ob_from) - return true; - - /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */ - if (ob->data != ob_from->data) { - ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - - if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) { - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - new_vgroup = true; - } - - if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) { - if (dvert_array) - MEM_freeN(dvert_array); - if (dvert_array_from) - MEM_freeN(dvert_array_from); - - if (new_vgroup == true) { - /* free the newly added vgroup since it wasn't compatible */ - BKE_object_defgroup_remove_all(ob); - } - - /* if true: both are 0 and nothing needs changing, consider this a success */ - return (dvert_tot == dvert_tot_from); - } - } - - /* do the copy */ - BLI_freelistN(&ob->defbase); - BLI_duplicatelist(&ob->defbase, &ob_from->defbase); - ob->actdef = ob_from->actdef; - - if (defbase_tot_from < defbase_tot) { - /* correct vgroup indices because the number of vgroups is being reduced. */ - int *remap = MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__); - for (i = 0; i <= defbase_tot_from; i++) remap[i] = i; - for (; i <= defbase_tot; i++) remap[i] = 0; /* can't use these, so disable */ - - BKE_object_defgroup_remap_update_users(ob, remap); - MEM_freeN(remap); - } - - if (dvert_array_from != NULL && dvert_array != NULL) { - dvf = dvert_array_from; - dv = dvert_array; - - for (i = 0; i < dvert_tot; i++, dvf++, dv++) { - MEM_SAFE_FREE((*dv)->dw); - *(*dv) = *(*dvf); - - if ((*dv)->dw) { - (*dv)->dw = MEM_dupallocN((*dv)->dw); - } - } - - MEM_freeN(dvert_array); - MEM_freeN(dvert_array_from); - } - - return true; -} - -void ED_vgroup_parray_to_weight_array( - const MDeformVert **dvert_array, const int dvert_tot, - float *dvert_weights, const int def_nr) -{ - int i; - - for (i = 0; i < dvert_tot; i++) { - const MDeformVert *dv = dvert_array[i]; - dvert_weights[i] = dv ? defvert_find_weight(dv, def_nr) : 0.0f; - } -} - -void ED_vgroup_parray_from_weight_array( - MDeformVert **dvert_array, const int dvert_tot, - const float *dvert_weights, const int def_nr, const bool remove_zero) -{ - int i; - - for (i = 0; i < dvert_tot; i++) { - MDeformVert *dv = dvert_array[i]; - if (dv) { - if (dvert_weights[i] > 0.0f) { - MDeformWeight *dw = defvert_verify_index(dv, def_nr); - BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f)); - dw->weight = dvert_weights[i]; - } - else { - MDeformWeight *dw = defvert_find_index(dv, def_nr); - if (dw) { - if (remove_zero) { - defvert_remove_group(dv, dw); - } - else { - dw->weight = 0.0f; - } - } - } - } - } + MDeformVert **dvert_array_from = NULL, **dvf; + MDeformVert **dvert_array = NULL, **dv; + int dvert_tot_from; + int dvert_tot; + int i; + int defbase_tot_from = BLI_listbase_count(&ob_from->defbase); + int defbase_tot = BLI_listbase_count(&ob->defbase); + bool new_vgroup = false; + + if (ob == ob_from) + return true; + + /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */ + if (ob->data != ob_from->data) { + ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + + if ((dvert_array == NULL) && (dvert_array_from != NULL) && + BKE_object_defgroup_data_create(ob->data)) { + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + new_vgroup = true; + } + + if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || + dvert_array == NULL) { + if (dvert_array) + MEM_freeN(dvert_array); + if (dvert_array_from) + MEM_freeN(dvert_array_from); + + if (new_vgroup == true) { + /* free the newly added vgroup since it wasn't compatible */ + BKE_object_defgroup_remove_all(ob); + } + + /* if true: both are 0 and nothing needs changing, consider this a success */ + return (dvert_tot == dvert_tot_from); + } + } + + /* do the copy */ + BLI_freelistN(&ob->defbase); + BLI_duplicatelist(&ob->defbase, &ob_from->defbase); + ob->actdef = ob_from->actdef; + + if (defbase_tot_from < defbase_tot) { + /* correct vgroup indices because the number of vgroups is being reduced. */ + int *remap = MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__); + for (i = 0; i <= defbase_tot_from; i++) + remap[i] = i; + for (; i <= defbase_tot; i++) + remap[i] = 0; /* can't use these, so disable */ + + BKE_object_defgroup_remap_update_users(ob, remap); + MEM_freeN(remap); + } + + if (dvert_array_from != NULL && dvert_array != NULL) { + dvf = dvert_array_from; + dv = dvert_array; + + for (i = 0; i < dvert_tot; i++, dvf++, dv++) { + MEM_SAFE_FREE((*dv)->dw); + *(*dv) = *(*dvf); + + if ((*dv)->dw) { + (*dv)->dw = MEM_dupallocN((*dv)->dw); + } + } + + MEM_freeN(dvert_array); + MEM_freeN(dvert_array_from); + } + + return true; } +void ED_vgroup_parray_to_weight_array(const MDeformVert **dvert_array, + const int dvert_tot, + float *dvert_weights, + const int def_nr) +{ + int i; -/* TODO, cache flip data to speedup calls within a loop. */ -static void mesh_defvert_mirror_update_internal( - Object *ob, - MDeformVert *dvert_dst, MDeformVert *dvert_src, - const int def_nr) -{ - if (def_nr == -1) { - /* all vgroups, add groups where needed */ - int flip_map_len; - int *flip_map = defgroup_flip_map(ob, &flip_map_len, true); - defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true); - MEM_freeN(flip_map); - } - else { - /* single vgroup */ - MDeformWeight *dw = defvert_verify_index(dvert_dst, defgroup_flip_index(ob, def_nr, 1)); - if (dw) { - dw->weight = defvert_find_weight(dvert_src, def_nr); - } - } + for (i = 0; i < dvert_tot; i++) { + const MDeformVert *dv = dvert_array[i]; + dvert_weights[i] = dv ? defvert_find_weight(dv, def_nr) : 0.0f; + } } -static void ED_mesh_defvert_mirror_update_em( - Object *ob, BMVert *eve, int def_nr, int vidx, - const int cd_dvert_offset) +void ED_vgroup_parray_from_weight_array(MDeformVert **dvert_array, + const int dvert_tot, + const float *dvert_weights, + const int def_nr, + const bool remove_zero) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMVert *eve_mirr; - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + int i; + + for (i = 0; i < dvert_tot; i++) { + MDeformVert *dv = dvert_array[i]; + if (dv) { + if (dvert_weights[i] > 0.0f) { + MDeformWeight *dw = defvert_verify_index(dv, def_nr); + BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f)); + dw->weight = dvert_weights[i]; + } + else { + MDeformWeight *dw = defvert_find_index(dv, def_nr); + if (dw) { + if (remove_zero) { + defvert_remove_group(dv, dw); + } + else { + dw->weight = 0.0f; + } + } + } + } + } +} - eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology); +/* TODO, cache flip data to speedup calls within a loop. */ +static void mesh_defvert_mirror_update_internal(Object *ob, + MDeformVert *dvert_dst, + MDeformVert *dvert_src, + const int def_nr) +{ + if (def_nr == -1) { + /* all vgroups, add groups where needed */ + int flip_map_len; + int *flip_map = defgroup_flip_map(ob, &flip_map_len, true); + defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true); + MEM_freeN(flip_map); + } + else { + /* single vgroup */ + MDeformWeight *dw = defvert_verify_index(dvert_dst, defgroup_flip_index(ob, def_nr, 1)); + if (dw) { + dw->weight = defvert_find_weight(dvert_src, def_nr); + } + } +} - if (eve_mirr && eve_mirr != eve) { - MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); - mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr); - } +static void ED_mesh_defvert_mirror_update_em( + Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset) +{ + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMVert *eve_mirr; + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + + eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, vidx, use_topology); + + if (eve_mirr && eve_mirr != eve) { + MDeformVert *dvert_src = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); + mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr); + } } static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx) { - int vidx_mirr; - Mesh *me = ob->data; - bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + int vidx_mirr; + Mesh *me = ob->data; + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - if (vidx == -1) - return; + if (vidx == -1) + return; - vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology); + vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology); - if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) { - MDeformVert *dvert_src = &me->dvert[vidx]; - MDeformVert *dvert_dst = &me->dvert[vidx_mirr]; - mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr); - } + if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) { + MDeformVert *dvert_src = &me->dvert[vidx]; + MDeformVert *dvert_dst = &me->dvert[vidx_mirr]; + mesh_defvert_mirror_update_internal(ob, dvert_dst, dvert_src, def_nr); + } } /** @@ -543,420 +547,426 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx) */ void ED_vgroup_vert_active_mirror(Object *ob, int def_nr) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - MDeformVert *dvert_act; - - if (me->editflag & ME_EDIT_MIRROR_X) { - if (em) { - BMVert *eve_act; - dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); - if (dvert_act) { - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset); - } - } - else { - int v_act; - dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); - if (dvert_act) { - ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act); - } - } - } + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + MDeformVert *dvert_act; + + if (me->editflag & ME_EDIT_MIRROR_X) { + if (em) { + BMVert *eve_act; + dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); + if (dvert_act) { + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + ED_mesh_defvert_mirror_update_em(ob, eve_act, def_nr, -1, cd_dvert_offset); + } + } + else { + int v_act; + dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); + if (dvert_act) { + ED_mesh_defvert_mirror_update_ob(ob, def_nr, v_act); + } + } + } } static void vgroup_remove_weight(Object *ob, const int def_nr) { - MDeformVert *dvert_act; - MDeformWeight *dw; - - dvert_act = ED_mesh_active_dvert_get_only(ob); + MDeformVert *dvert_act; + MDeformWeight *dw; - dw = defvert_find_index(dvert_act, def_nr); - defvert_remove_group(dvert_act, dw); + dvert_act = ED_mesh_active_dvert_get_only(ob); + dw = defvert_find_index(dvert_act, def_nr); + defvert_remove_group(dvert_act, dw); } static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - BMVert *eve_act; - int v_act; - MDeformVert *dvert_act; - int subset_count, vgroup_tot; - const bool *vgroup_validmap; - - - if (em) { - dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); - } - else { - dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); - } - - if (dvert_act == NULL) { - return false; - } - - vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot); - MEM_freeN((void *)vgroup_validmap); - - if (me->editflag & ME_EDIT_MIRROR_X) { - if (em) { - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset); - } - else { - ED_mesh_defvert_mirror_update_ob(ob, -1, v_act); - } - } - - return true; + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + BMVert *eve_act; + int v_act; + MDeformVert *dvert_act; + int subset_count, vgroup_tot; + const bool *vgroup_validmap; + + if (em) { + dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); + } + else { + dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); + } + + if (dvert_act == NULL) { + return false; + } + + vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + defvert_normalize_subset(dvert_act, vgroup_validmap, vgroup_tot); + MEM_freeN((void *)vgroup_validmap); + + if (me->editflag & ME_EDIT_MIRROR_X) { + if (em) { + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset); + } + else { + ED_mesh_defvert_mirror_update_ob(ob, -1, v_act); + } + } + + return true; } static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - MDeformVert *dvert_act; - int i, vgroup_tot, subset_count; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - - - if (em) { - BMIter iter; - BMVert *eve, *eve_act; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); - if (dvert_act) { - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot); - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); - } - } - } - } - } - else { - MDeformVert *dv; - int v_act; - - dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); - if (dvert_act) { - dv = me->dvert; - for (i = 0; i < me->totvert; i++, dv++) { - if ((me->mvert[i].flag & SELECT) && dv != dvert_act) { - defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot); - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_ob(ob, -1, i); - } - } - } - } - } - - MEM_freeN((void *)vgroup_validmap); + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + MDeformVert *dvert_act; + int i, vgroup_tot, subset_count; + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + + if (em) { + BMIter iter; + BMVert *eve, *eve_act; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); + if (dvert_act) { + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) { + MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot); + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); + } + } + } + } + } + else { + MDeformVert *dv; + int v_act; + + dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); + if (dvert_act) { + dv = me->dvert; + for (i = 0; i < me->totvert; i++, dv++) { + if ((me->mvert[i].flag & SELECT) && dv != dvert_act) { + defvert_copy_subset(dv, dvert_act, vgroup_validmap, vgroup_tot); + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_ob(ob, -1, i); + } + } + } + } + } + + MEM_freeN((void *)vgroup_validmap); } /***********************Start weight transfer (WT)*********************************/ static const EnumPropertyItem WT_vertex_group_select_item[] = { - {WT_VGROUP_ACTIVE, - "ACTIVE", 0, "Active Group", "The active Vertex Group"}, - {WT_VGROUP_BONE_SELECT, - "BONE_SELECT", 0, "Selected Pose Bones", "All Vertex Groups assigned to Selection"}, - {WT_VGROUP_BONE_DEFORM, - "BONE_DEFORM", 0, "Deform Pose Bones", "All Vertex Groups assigned to Deform Bones"}, - {WT_VGROUP_ALL, - "ALL", 0, "All Groups", "All Vertex Groups"}, - {0, NULL, 0, NULL, NULL}, + {WT_VGROUP_ACTIVE, "ACTIVE", 0, "Active Group", "The active Vertex Group"}, + {WT_VGROUP_BONE_SELECT, + "BONE_SELECT", + 0, + "Selected Pose Bones", + "All Vertex Groups assigned to Selection"}, + {WT_VGROUP_BONE_DEFORM, + "BONE_DEFORM", + 0, + "Deform Pose Bones", + "All Vertex Groups assigned to Deform Bones"}, + {WT_VGROUP_ALL, "ALL", 0, "All Groups", "All Vertex Groups"}, + {0, NULL, 0, NULL, NULL}, }; -const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper( - const bContext *C, PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free, const unsigned int selection_mask) +const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free, + const unsigned int selection_mask) { - Object *ob; - EnumPropertyItem *item = NULL; - int totitem = 0; - - if (C == NULL) { - /* needed for docs and i18n tools */ - return WT_vertex_group_select_item; - } - - ob = CTX_data_active_object(C); - if (selection_mask & (1 << WT_VGROUP_ACTIVE)) - RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ACTIVE); - - if (BKE_object_pose_armature_get(ob)) { - if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) - RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); - if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) - RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); - } - - if (selection_mask & (1 << WT_VGROUP_ALL)) - RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ALL); - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Object *ob; + EnumPropertyItem *item = NULL; + int totitem = 0; + + if (C == NULL) { + /* needed for docs and i18n tools */ + return WT_vertex_group_select_item; + } + + ob = CTX_data_active_object(C); + if (selection_mask & (1 << WT_VGROUP_ACTIVE)) + RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ACTIVE); + + if (BKE_object_pose_armature_get(ob)) { + if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); + if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); + } + + if (selection_mask & (1 << WT_VGROUP_ALL)) + RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ALL); + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } -static const EnumPropertyItem *rna_vertex_group_with_single_itemf( - bContext *C, PointerRNA *ptr, - PropertyRNA *prop, bool *r_free) +static const EnumPropertyItem *rna_vertex_group_with_single_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *prop, + bool *r_free) { - return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, r_free, WT_VGROUP_MASK_ALL); + return ED_object_vgroup_selection_itemf_helper(C, ptr, prop, r_free, WT_VGROUP_MASK_ALL); } -static const EnumPropertyItem *rna_vertex_group_select_itemf( - bContext *C, PointerRNA *ptr, - PropertyRNA *prop, bool *r_free) +static const EnumPropertyItem *rna_vertex_group_select_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *prop, + bool *r_free) { - return ED_object_vgroup_selection_itemf_helper( - C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE)); + return ED_object_vgroup_selection_itemf_helper( + C, ptr, prop, r_free, WT_VGROUP_MASK_ALL & ~(1 << WT_VGROUP_ACTIVE)); } static void vgroup_operator_subset_select_props(wmOperatorType *ot, bool use_active) { - PropertyRNA *prop; - - prop = RNA_def_enum( - ot->srna, - "group_select_mode", DummyRNA_NULL_items, - use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL, "Subset", - "Define which subset of Groups shall be used"); - - if (use_active) { - RNA_def_enum_funcs(prop, rna_vertex_group_with_single_itemf); - } - else { - RNA_def_enum_funcs(prop, rna_vertex_group_select_itemf); - } - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + prop = RNA_def_enum(ot->srna, + "group_select_mode", + DummyRNA_NULL_items, + use_active ? WT_VGROUP_ACTIVE : WT_VGROUP_ALL, + "Subset", + "Define which subset of Groups shall be used"); + + if (use_active) { + RNA_def_enum_funcs(prop, rna_vertex_group_with_single_itemf); + } + else { + RNA_def_enum_funcs(prop, rna_vertex_group_select_itemf); + } + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } - /***********************End weight transfer (WT)***********************************/ /* for Mesh in Object mode */ /* allows editmode for Lattice */ static void ED_vgroup_nr_vert_add( - Object *ob, - const int def_nr, const int vertnum, - const float weight, const int assignmode) -{ - /* add the vert to the deform group with the - * specified number - */ - MDeformVert *dvert = NULL; - int tot; - - /* get the vert */ - BKE_object_defgroup_array_get(ob->data, &dvert, &tot); - - if (dvert == NULL) - return; - - /* check that vertnum is valid before trying to get the relevant dvert */ - if ((vertnum < 0) || (vertnum >= tot)) - return; - - - if (dvert) { - MDeformVert *dv = &dvert[vertnum]; - MDeformWeight *dw; - - /* Lets first check to see if this vert is - * already in the weight group -- if so - * lets update it - */ - - dw = defvert_find_index(dv, def_nr); - - if (dw) { - switch (assignmode) { - case WEIGHT_REPLACE: - dw->weight = weight; - break; - case WEIGHT_ADD: - dw->weight += weight; - if (dw->weight >= 1.0f) - dw->weight = 1.0f; - break; - case WEIGHT_SUBTRACT: - dw->weight -= weight; - /* if the weight is zero or less than - * remove the vert from the deform group - */ - if (dw->weight <= 0.0f) { - defvert_remove_group(dv, dw); - } - break; - } - } - else { - /* if the vert wasn't in the deform group then - * we must take a different form of action ... - */ - - switch (assignmode) { - case WEIGHT_SUBTRACT: - /* if we are subtracting then we don't - * need to do anything - */ - return; - - case WEIGHT_REPLACE: - case WEIGHT_ADD: - /* if we are doing an additive assignment, then - * we need to create the deform weight - */ - - /* we checked if the vertex was added before so no need to test again, simply add */ - defvert_add_index_notest(dv, def_nr, weight); - break; - } - } - } + Object *ob, const int def_nr, const int vertnum, const float weight, const int assignmode) +{ + /* add the vert to the deform group with the + * specified number + */ + MDeformVert *dvert = NULL; + int tot; + + /* get the vert */ + BKE_object_defgroup_array_get(ob->data, &dvert, &tot); + + if (dvert == NULL) + return; + + /* check that vertnum is valid before trying to get the relevant dvert */ + if ((vertnum < 0) || (vertnum >= tot)) + return; + + if (dvert) { + MDeformVert *dv = &dvert[vertnum]; + MDeformWeight *dw; + + /* Lets first check to see if this vert is + * already in the weight group -- if so + * lets update it + */ + + dw = defvert_find_index(dv, def_nr); + + if (dw) { + switch (assignmode) { + case WEIGHT_REPLACE: + dw->weight = weight; + break; + case WEIGHT_ADD: + dw->weight += weight; + if (dw->weight >= 1.0f) + dw->weight = 1.0f; + break; + case WEIGHT_SUBTRACT: + dw->weight -= weight; + /* if the weight is zero or less than + * remove the vert from the deform group + */ + if (dw->weight <= 0.0f) { + defvert_remove_group(dv, dw); + } + break; + } + } + else { + /* if the vert wasn't in the deform group then + * we must take a different form of action ... + */ + + switch (assignmode) { + case WEIGHT_SUBTRACT: + /* if we are subtracting then we don't + * need to do anything + */ + return; + + case WEIGHT_REPLACE: + case WEIGHT_ADD: + /* if we are doing an additive assignment, then + * we need to create the deform weight + */ + + /* we checked if the vertex was added before so no need to test again, simply add */ + defvert_add_index_notest(dv, def_nr, weight); + break; + } + } + } } /* called while not in editmode */ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode) { - /* add the vert to the deform group with the - * specified assign mode - */ - const int def_nr = BLI_findindex(&ob->defbase, dg); - - MDeformVert *dv = NULL; - int tot; - - /* get the deform group number, exit if - * it can't be found - */ - if (def_nr != -1) { - - /* if there's no deform verts then create some, - */ - if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) - BKE_object_defgroup_data_create(ob->data); - - /* call another function to do the work - */ - ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode); - } + /* add the vert to the deform group with the + * specified assign mode + */ + const int def_nr = BLI_findindex(&ob->defbase, dg); + + MDeformVert *dv = NULL; + int tot; + + /* get the deform group number, exit if + * it can't be found + */ + if (def_nr != -1) { + + /* if there's no deform verts then create some, + */ + if (BKE_object_defgroup_array_get(ob->data, &dv, &tot) && dv == NULL) + BKE_object_defgroup_data_create(ob->data); + + /* call another function to do the work + */ + ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode); + } } /* mesh object mode, lattice can be in editmode */ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) { - /* This routine removes the vertex from the specified - * deform group. - */ - - /* TODO, this is slow in a loop, better pass def_nr directly, but leave for later... - campbell */ - const int def_nr = BLI_findindex(&ob->defbase, dg); - - if (def_nr != -1) { - MDeformVert *dvert = NULL; - int tot; - - /* get the deform vertices corresponding to the - * vertnum - */ - BKE_object_defgroup_array_get(ob->data, &dvert, &tot); - - if (dvert) { - MDeformVert *dv = &dvert[vertnum]; - MDeformWeight *dw; - - dw = defvert_find_index(dv, def_nr); - defvert_remove_group(dv, dw); /* dw can be NULL */ - } - } + /* This routine removes the vertex from the specified + * deform group. + */ + + /* TODO, this is slow in a loop, better pass def_nr directly, but leave for later... - campbell */ + const int def_nr = BLI_findindex(&ob->defbase, dg); + + if (def_nr != -1) { + MDeformVert *dvert = NULL; + int tot; + + /* get the deform vertices corresponding to the + * vertnum + */ + BKE_object_defgroup_array_get(ob->data, &dvert, &tot); + + if (dvert) { + MDeformVert *dv = &dvert[vertnum]; + MDeformWeight *dw; + + dw = defvert_find_index(dv, def_nr); + defvert_remove_group(dv, dw); /* dw can be NULL */ + } + } } static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) { - MDeformVert *dv = NULL; - - /* get the deform vertices corresponding to the vertnum */ - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - /* warning, this lookup is _not_ fast */ - - if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) { - BMVert *eve; - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - eve = BM_vert_at_index(em->bm, vertnum); - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - } - else { - return 0.0f; - } - } - else { - if (me->dvert) { - if (vertnum >= me->totvert) { - return 0.0f; - } - dv = &me->dvert[vertnum]; - } - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - - if (lt->dvert) { - if (vertnum >= lt->pntsu * lt->pntsv * lt->pntsw) { - return 0.0f; - } - dv = <->dvert[vertnum]; - } - } - - if (dv) { - MDeformWeight *dw = defvert_find_index(dv, def_nr); - if (dw) { - return dw->weight; - } - } - - return -1; + MDeformVert *dv = NULL; + + /* get the deform vertices corresponding to the vertnum */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + /* warning, this lookup is _not_ fast */ + + if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) { + BMVert *eve; + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + eve = BM_vert_at_index(em->bm, vertnum); + dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + } + else { + return 0.0f; + } + } + else { + if (me->dvert) { + if (vertnum >= me->totvert) { + return 0.0f; + } + dv = &me->dvert[vertnum]; + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = vgroup_edit_lattice(ob); + + if (lt->dvert) { + if (vertnum >= lt->pntsu * lt->pntsv * lt->pntsw) { + return 0.0f; + } + dv = <->dvert[vertnum]; + } + } + + if (dv) { + MDeformWeight *dw = defvert_find_index(dv, def_nr); + if (dw) { + return dw->weight; + } + } + + return -1; } float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum) { - const int def_nr = BLI_findindex(&ob->defbase, dg); + const int def_nr = BLI_findindex(&ob->defbase, dg); - if (def_nr == -1) { - return -1; - } + if (def_nr == -1) { + return -1; + } - return get_vert_def_nr(ob, def_nr, vertnum); + return get_vert_def_nr(ob, def_nr, vertnum); } void ED_vgroup_select_by_name(Object *ob, const char *name) { - /* note: ob->actdef==0 signals on painting to create a new one, + /* note: ob->actdef==0 signals on painting to create a new one, * if a bone in posemode is selected */ - ob->actdef = defgroup_name_index(ob, name) + 1; + ob->actdef = defgroup_name_index(ob, name) + 1; } /********************** Operator Implementations *********************/ @@ -964,186 +974,192 @@ void ED_vgroup_select_by_name(Object *ob, const char *name) /* only in editmode */ static void vgroup_select_verts(Object *ob, int select) { - const int def_nr = ob->actdef - 1; - - if (!BLI_findlink(&ob->defbase, def_nr)) { - return; - } - - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - if (cd_dvert_offset != -1) { - BMIter iter; - BMVert *eve; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - if (defvert_find_index(dv, def_nr)) { - BM_vert_select_set(em->bm, eve, select); - } - } - } - - /* this has to be called, because this function operates on vertices only */ - if (select) EDBM_select_flush(em); /* vertices to edges/faces */ - else EDBM_deselect_flush(em); - } - } - else { - if (me->dvert) { - MVert *mv; - MDeformVert *dv; - int i; - - mv = me->mvert; - dv = me->dvert; - - for (i = 0; i < me->totvert; i++, mv++, dv++) { - if (!(mv->flag & ME_HIDE)) { - if (defvert_find_index(dv, def_nr)) { - if (select) mv->flag |= SELECT; - else mv->flag &= ~SELECT; - } - } - } - - paintvert_flush_flags(ob); - } - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - - if (lt->dvert) { - MDeformVert *dv; - BPoint *bp, *actbp = BKE_lattice_active_point_get(lt); - int a, tot; - - dv = lt->dvert; - - tot = lt->pntsu * lt->pntsv * lt->pntsw; - for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) { - if (defvert_find_index(dv, def_nr)) { - if (select) bp->f1 |= SELECT; - else { - bp->f1 &= ~SELECT; - if (actbp && bp == actbp) lt->actbp = LT_ACTBP_NONE; - } - } - } - } - } + const int def_nr = ob->actdef - 1; + + if (!BLI_findlink(&ob->defbase, def_nr)) { + return; + } + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset != -1) { + BMIter iter; + BMVert *eve; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + if (defvert_find_index(dv, def_nr)) { + BM_vert_select_set(em->bm, eve, select); + } + } + } + + /* this has to be called, because this function operates on vertices only */ + if (select) + EDBM_select_flush(em); /* vertices to edges/faces */ + else + EDBM_deselect_flush(em); + } + } + else { + if (me->dvert) { + MVert *mv; + MDeformVert *dv; + int i; + + mv = me->mvert; + dv = me->dvert; + + for (i = 0; i < me->totvert; i++, mv++, dv++) { + if (!(mv->flag & ME_HIDE)) { + if (defvert_find_index(dv, def_nr)) { + if (select) + mv->flag |= SELECT; + else + mv->flag &= ~SELECT; + } + } + } + + paintvert_flush_flags(ob); + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = vgroup_edit_lattice(ob); + + if (lt->dvert) { + MDeformVert *dv; + BPoint *bp, *actbp = BKE_lattice_active_point_get(lt); + int a, tot; + + dv = lt->dvert; + + tot = lt->pntsu * lt->pntsv * lt->pntsw; + for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) { + if (defvert_find_index(dv, def_nr)) { + if (select) + bp->f1 |= SELECT; + else { + bp->f1 &= ~SELECT; + if (actbp && bp == actbp) + lt->actbp = LT_ACTBP_NONE; + } + } + } + } + } } static void vgroup_duplicate(Object *ob) { - bDeformGroup *dg, *cdg; - char name[sizeof(dg->name)]; - MDeformWeight *dw_org, *dw_cpy; - MDeformVert **dvert_array = NULL; - int i, idg, icdg, dvert_tot = 0; - - dg = BLI_findlink(&ob->defbase, (ob->actdef - 1)); - if (!dg) - return; - - if (!strstr(dg->name, "_copy")) { - BLI_snprintf(name, sizeof(name), "%s_copy", dg->name); - } - else { - BLI_strncpy(name, dg->name, sizeof(name)); - } - - cdg = defgroup_duplicate(dg); - BLI_strncpy(cdg->name, name, sizeof(cdg->name)); - defgroup_unique_name(cdg, ob); - - BLI_addtail(&ob->defbase, cdg); - - idg = (ob->actdef - 1); - ob->actdef = BLI_listbase_count(&ob->defbase); - icdg = (ob->actdef - 1); - - /* TODO, we might want to allow only copy selected verts here? - campbell */ - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - - if (dvert_array) { - for (i = 0; i < dvert_tot; i++) { - MDeformVert *dv = dvert_array[i]; - dw_org = defvert_find_index(dv, idg); - if (dw_org) { - /* defvert_verify_index re-allocs org so need to store the weight first */ - const float weight = dw_org->weight; - dw_cpy = defvert_verify_index(dv, icdg); - dw_cpy->weight = weight; - } - } - - MEM_freeN(dvert_array); - } + bDeformGroup *dg, *cdg; + char name[sizeof(dg->name)]; + MDeformWeight *dw_org, *dw_cpy; + MDeformVert **dvert_array = NULL; + int i, idg, icdg, dvert_tot = 0; + + dg = BLI_findlink(&ob->defbase, (ob->actdef - 1)); + if (!dg) + return; + + if (!strstr(dg->name, "_copy")) { + BLI_snprintf(name, sizeof(name), "%s_copy", dg->name); + } + else { + BLI_strncpy(name, dg->name, sizeof(name)); + } + + cdg = defgroup_duplicate(dg); + BLI_strncpy(cdg->name, name, sizeof(cdg->name)); + defgroup_unique_name(cdg, ob); + + BLI_addtail(&ob->defbase, cdg); + + idg = (ob->actdef - 1); + ob->actdef = BLI_listbase_count(&ob->defbase); + icdg = (ob->actdef - 1); + + /* TODO, we might want to allow only copy selected verts here? - campbell */ + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + + if (dvert_array) { + for (i = 0; i < dvert_tot; i++) { + MDeformVert *dv = dvert_array[i]; + dw_org = defvert_find_index(dv, idg); + if (dw_org) { + /* defvert_verify_index re-allocs org so need to store the weight first */ + const float weight = dw_org->weight; + dw_cpy = defvert_verify_index(dv, icdg); + dw_cpy->weight = weight; + } + } + + MEM_freeN(dvert_array); + } } static bool vgroup_normalize(Object *ob) { - MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; - int i, dvert_tot = 0; - const int def_nr = ob->actdef - 1; + MDeformWeight *dw; + MDeformVert *dv, **dvert_array = NULL; + int i, dvert_tot = 0; + const int def_nr = ob->actdef - 1; - const int use_vert_sel = vertex_group_use_vert_sel(ob); + const int use_vert_sel = vertex_group_use_vert_sel(ob); - if (!BLI_findlink(&ob->defbase, def_nr)) { - return false; - } + if (!BLI_findlink(&ob->defbase, def_nr)) { + return false; + } - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - if (dvert_array) { - float weight_max = 0.0f; + if (dvert_array) { + float weight_max = 0.0f; - for (i = 0; i < dvert_tot; i++) { + for (i = 0; i < dvert_tot; i++) { - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } - dw = defvert_find_index(dv, def_nr); - if (dw) { - weight_max = max_ff(dw->weight, weight_max); - } - } + dw = defvert_find_index(dv, def_nr); + if (dw) { + weight_max = max_ff(dw->weight, weight_max); + } + } - if (weight_max > 0.0f) { - for (i = 0; i < dvert_tot; i++) { + if (weight_max > 0.0f) { + for (i = 0; i < dvert_tot; i++) { - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } - dw = defvert_find_index(dv, def_nr); - if (dw) { - dw->weight /= weight_max; + dw = defvert_find_index(dv, def_nr); + if (dw) { + dw->weight /= weight_max; - /* in case of division errors with very low weights */ - CLAMP(dw->weight, 0.0f, 1.0f); - } - } - } + /* in case of division errors with very low weights */ + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } - MEM_freeN(dvert_array); + MEM_freeN(dvert_array); - return true; - } + return true; + } - return false; + return false; } /* This finds all of the vertices face-connected to vert by an edge and returns a @@ -1151,64 +1167,64 @@ static bool vgroup_normalize(Object *ob) * count is an int passed by reference so it can be assigned the value of the length here. */ static int *getSurroundingVerts(Mesh *me, int vert, int *count) { - MPoly *mp = me->mpoly; - int i = me->totpoly; - /* Instead of looping twice on all polys and loops, and use a temp array, let's rather - * use a BLI_array, with a reasonable starting/reserved size (typically, there are not - * many vertices face-linked to another one, even 8 might be too high...). */ - int *verts = NULL; - BLI_array_declare(verts); - - BLI_array_reserve(verts, 8); - while (i--) { - int j = mp->totloop; - int first_l = mp->totloop - 1; - MLoop *ml = &me->mloop[mp->loopstart]; - while (j--) { - /* XXX This assume a vert can only be once in a poly, even though - * it seems logical to me, not totally sure of that. */ - if (ml->v == vert) { - int a, b, k; - if (j == first_l) { - /* We are on the first corner. */ - a = ml[1].v; - b = ml[j].v; - } - else if (!j) { - /* We are on the last corner. */ - a = (ml - 1)->v; - b = me->mloop[mp->loopstart].v; - } - else { - a = (ml - 1)->v; - b = (ml + 1)->v; - } - - /* Append a and b verts to array, if not yet present. */ - k = BLI_array_len(verts); - /* XXX Maybe a == b is enough? */ - while (k-- && !(a == b && a == -1)) { - if (verts[k] == a) - a = -1; - else if (verts[k] == b) - b = -1; - } - if (a != -1) - BLI_array_append(verts, a); - if (b != -1) - BLI_array_append(verts, b); - - /* Vert found in this poly, we can go to next one! */ - break; - } - ml++; - } - mp++; - } - - /* Do not free the array! */ - *count = BLI_array_len(verts); - return verts; + MPoly *mp = me->mpoly; + int i = me->totpoly; + /* Instead of looping twice on all polys and loops, and use a temp array, let's rather + * use a BLI_array, with a reasonable starting/reserved size (typically, there are not + * many vertices face-linked to another one, even 8 might be too high...). */ + int *verts = NULL; + BLI_array_declare(verts); + + BLI_array_reserve(verts, 8); + while (i--) { + int j = mp->totloop; + int first_l = mp->totloop - 1; + MLoop *ml = &me->mloop[mp->loopstart]; + while (j--) { + /* XXX This assume a vert can only be once in a poly, even though + * it seems logical to me, not totally sure of that. */ + if (ml->v == vert) { + int a, b, k; + if (j == first_l) { + /* We are on the first corner. */ + a = ml[1].v; + b = ml[j].v; + } + else if (!j) { + /* We are on the last corner. */ + a = (ml - 1)->v; + b = me->mloop[mp->loopstart].v; + } + else { + a = (ml - 1)->v; + b = (ml + 1)->v; + } + + /* Append a and b verts to array, if not yet present. */ + k = BLI_array_len(verts); + /* XXX Maybe a == b is enough? */ + while (k-- && !(a == b && a == -1)) { + if (verts[k] == a) + a = -1; + else if (verts[k] == b) + b = -1; + } + if (a != -1) + BLI_array_append(verts, a); + if (b != -1) + BLI_array_append(verts, b); + + /* Vert found in this poly, we can go to next one! */ + break; + } + ml++; + } + mp++; + } + + /* Do not free the array! */ + *count = BLI_array_len(verts); + return verts; } /* get a single point in space by averaging a point cloud (vectors of size 3) @@ -1216,40 +1232,45 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) */ static void getSingleCoordinate(MVert *points, int count, float coord[3]) { - int i; - zero_v3(coord); - for (i = 0; i < count; i++) { - add_v3_v3(coord, points[i].co); - } - mul_v3_fl(coord, 1.0f / count); + int i; + zero_v3(coord); + for (i = 0; i < count; i++) { + add_v3_v3(coord, points[i].co); + } + mul_v3_fl(coord, 1.0f / count); } /* given a plane and a start and end position, * compute the amount of vertical distance relative to the plane and store it in dists, * then get the horizontal and vertical change and store them in changes */ -static void getVerticalAndHorizontalChange( - const float norm[3], float d, const float coord[3], - const float start[3], float distToStart, - float *end, float (*changes)[2], float *dists, int index) -{ - /* A = Q - ((Q - P).N)N - * D = (a * x0 + b * y0 +c * z0 + d) */ - float projA[3], projB[3]; - float plane[4]; - - plane_from_point_normal_v3(plane, coord, norm); - - closest_to_plane_normalized_v3(projA, plane, start); - closest_to_plane_normalized_v3(projB, plane, end); - /* (vertical and horizontal refer to the plane's y and xz respectively) - * vertical distance */ - dists[index] = dot_v3v3(norm, end) + d; - /* vertical change */ - changes[index][0] = dists[index] - distToStart; - //printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]); - /* horizontal change */ - changes[index][1] = len_v3v3(projA, projB); +static void getVerticalAndHorizontalChange(const float norm[3], + float d, + const float coord[3], + const float start[3], + float distToStart, + float *end, + float (*changes)[2], + float *dists, + int index) +{ + /* A = Q - ((Q - P).N)N + * D = (a * x0 + b * y0 +c * z0 + d) */ + float projA[3], projB[3]; + float plane[4]; + + plane_from_point_normal_v3(plane, coord, norm); + + closest_to_plane_normalized_v3(projA, plane, start); + closest_to_plane_normalized_v3(projB, plane, end); + /* (vertical and horizontal refer to the plane's y and xz respectively) + * vertical distance */ + dists[index] = dot_v3v3(norm, end) + d; + /* vertical change */ + changes[index][0] = dists[index] - distToStart; + //printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]); + /* horizontal change */ + changes[index][1] = len_v3v3(projA, projB); } /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to @@ -1261,2336 +1282,2435 @@ static void getVerticalAndHorizontalChange( * norm and d are the plane's properties for the equation: ax + by + cz + d = 0 * coord is a point on the plane */ -static void moveCloserToDistanceFromPlane( - Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, int index, float norm[3], - float coord[3], float d, float distToBe, float strength, float cp) -{ - Mesh *me_deform; - MDeformWeight *dw; - MVert m; - MDeformVert *dvert = me->dvert + index; - int totweight = dvert->totweight; - float oldw = 0; - float oldPos[3] = {0}; - float vc, hc, dist = 0.0f; - int i, k; - float (*changes)[2] = MEM_mallocN(sizeof(float *) * totweight * 2, "vertHorzChange"); - float *dists = MEM_mallocN(sizeof(float) * totweight, "distance"); - - /* track if up or down moved it closer for each bone */ - int *upDown = MEM_callocN(sizeof(int) * totweight, "upDownTracker"); - - int *dwIndices = MEM_callocN(sizeof(int) * totweight, "dwIndexTracker"); - float distToStart; - int bestIndex = 0; - bool wasChange; - char wasUp; - int lastIndex = -1; - float originalDistToBe = distToBe; - do { - wasChange = false; - me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); - m = me_deform->mvert[index]; - copy_v3_v3(oldPos, m.co); - distToStart = dot_v3v3(norm, oldPos) + d; - - if (distToBe == originalDistToBe) { - distToBe += distToStart - distToStart * strength; - } - for (i = 0; i < totweight; i++) { - dwIndices[i] = i; - dw = (dvert->dw + i); - vc = hc = 0; - if (!dw->weight) { - changes[i][0] = 0; - changes[i][1] = 0; - dists[i] = distToStart; - continue; - } - for (k = 0; k < 2; k++) { - if (me_deform) { - /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs! - * Better to over-free and recompute a bit. */ - BKE_object_free_derived_caches(ob); - } - oldw = dw->weight; - if (k) { - dw->weight *= 1 + cp; - } - else { - dw->weight /= 1 + cp; - } - if (dw->weight == oldw) { - changes[i][0] = 0; - changes[i][1] = 0; - dists[i] = distToStart; - break; - } - if (dw->weight > 1) { - dw->weight = 1; - } - me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); - m = me_deform->mvert[index]; - getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i); - dw->weight = oldw; - if (!k) { - vc = changes[i][0]; - hc = changes[i][1]; - dist = dists[i]; - } - else { - if (fabsf(dist - distToBe) < fabsf(dists[i] - distToBe)) { - upDown[i] = 0; - changes[i][0] = vc; - changes[i][1] = hc; - dists[i] = dist; - } - else { - upDown[i] = 1; - } - if (fabsf(dists[i] - distToBe) > fabsf(distToStart - distToBe)) { - changes[i][0] = 0; - changes[i][1] = 0; - dists[i] = distToStart; - } - } - } - } - /* sort the changes by the vertical change */ - for (k = 0; k < totweight; k++) { - float tf; - int ti; - bestIndex = k; - for (i = k + 1; i < totweight; i++) { - dist = dists[i]; - - if (fabsf(dist) > fabsf(dists[i])) { - bestIndex = i; - } - } - /* switch with k */ - if (bestIndex != k) { - ti = upDown[k]; - upDown[k] = upDown[bestIndex]; - upDown[bestIndex] = ti; - - ti = dwIndices[k]; - dwIndices[k] = dwIndices[bestIndex]; - dwIndices[bestIndex] = ti; - - tf = changes[k][0]; - changes[k][0] = changes[bestIndex][0]; - changes[bestIndex][0] = tf; - - tf = changes[k][1]; - changes[k][1] = changes[bestIndex][1]; - changes[bestIndex][1] = tf; - - tf = dists[k]; - dists[k] = dists[bestIndex]; - dists[bestIndex] = tf; - } - } - bestIndex = -1; - /* find the best change with an acceptable horizontal change */ - for (i = 0; i < totweight; i++) { - if (fabsf(changes[i][0]) > fabsf(changes[i][1] * 2.0f)) { - bestIndex = i; - break; - } - } - if (bestIndex != -1) { - wasChange = true; - /* it is a good place to stop if it tries to move the opposite direction - * (relative to the plane) of last time */ - if (lastIndex != -1) { - if (wasUp != upDown[bestIndex]) { - wasChange = false; - } - } - lastIndex = bestIndex; - wasUp = upDown[bestIndex]; - dw = (dvert->dw + dwIndices[bestIndex]); - oldw = dw->weight; - if (upDown[bestIndex]) { - dw->weight *= 1 + cp; - } - else { - dw->weight /= 1 + cp; - } - if (dw->weight > 1) { - dw->weight = 1; - } - if (oldw == dw->weight) { - wasChange = false; - } - if (me_deform) { - /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs! - * Better to over-free and recompute a bit. */ - BKE_object_free_derived_caches(ob); - } - } - } while (wasChange && ((distToStart - distToBe) / fabsf(distToStart - distToBe) == - (dists[bestIndex] - distToBe) / fabsf(dists[bestIndex] - distToBe))); - - MEM_freeN(upDown); - MEM_freeN(changes); - MEM_freeN(dists); - MEM_freeN(dwIndices); +static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + Mesh *me, + int index, + float norm[3], + float coord[3], + float d, + float distToBe, + float strength, + float cp) +{ + Mesh *me_deform; + MDeformWeight *dw; + MVert m; + MDeformVert *dvert = me->dvert + index; + int totweight = dvert->totweight; + float oldw = 0; + float oldPos[3] = {0}; + float vc, hc, dist = 0.0f; + int i, k; + float(*changes)[2] = MEM_mallocN(sizeof(float *) * totweight * 2, "vertHorzChange"); + float *dists = MEM_mallocN(sizeof(float) * totweight, "distance"); + + /* track if up or down moved it closer for each bone */ + int *upDown = MEM_callocN(sizeof(int) * totweight, "upDownTracker"); + + int *dwIndices = MEM_callocN(sizeof(int) * totweight, "dwIndexTracker"); + float distToStart; + int bestIndex = 0; + bool wasChange; + char wasUp; + int lastIndex = -1; + float originalDistToBe = distToBe; + do { + wasChange = false; + me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); + m = me_deform->mvert[index]; + copy_v3_v3(oldPos, m.co); + distToStart = dot_v3v3(norm, oldPos) + d; + + if (distToBe == originalDistToBe) { + distToBe += distToStart - distToStart * strength; + } + for (i = 0; i < totweight; i++) { + dwIndices[i] = i; + dw = (dvert->dw + i); + vc = hc = 0; + if (!dw->weight) { + changes[i][0] = 0; + changes[i][1] = 0; + dists[i] = distToStart; + continue; + } + for (k = 0; k < 2; k++) { + if (me_deform) { + /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs! + * Better to over-free and recompute a bit. */ + BKE_object_free_derived_caches(ob); + } + oldw = dw->weight; + if (k) { + dw->weight *= 1 + cp; + } + else { + dw->weight /= 1 + cp; + } + if (dw->weight == oldw) { + changes[i][0] = 0; + changes[i][1] = 0; + dists[i] = distToStart; + break; + } + if (dw->weight > 1) { + dw->weight = 1; + } + me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); + m = me_deform->mvert[index]; + getVerticalAndHorizontalChange( + norm, d, coord, oldPos, distToStart, m.co, changes, dists, i); + dw->weight = oldw; + if (!k) { + vc = changes[i][0]; + hc = changes[i][1]; + dist = dists[i]; + } + else { + if (fabsf(dist - distToBe) < fabsf(dists[i] - distToBe)) { + upDown[i] = 0; + changes[i][0] = vc; + changes[i][1] = hc; + dists[i] = dist; + } + else { + upDown[i] = 1; + } + if (fabsf(dists[i] - distToBe) > fabsf(distToStart - distToBe)) { + changes[i][0] = 0; + changes[i][1] = 0; + dists[i] = distToStart; + } + } + } + } + /* sort the changes by the vertical change */ + for (k = 0; k < totweight; k++) { + float tf; + int ti; + bestIndex = k; + for (i = k + 1; i < totweight; i++) { + dist = dists[i]; + + if (fabsf(dist) > fabsf(dists[i])) { + bestIndex = i; + } + } + /* switch with k */ + if (bestIndex != k) { + ti = upDown[k]; + upDown[k] = upDown[bestIndex]; + upDown[bestIndex] = ti; + + ti = dwIndices[k]; + dwIndices[k] = dwIndices[bestIndex]; + dwIndices[bestIndex] = ti; + + tf = changes[k][0]; + changes[k][0] = changes[bestIndex][0]; + changes[bestIndex][0] = tf; + + tf = changes[k][1]; + changes[k][1] = changes[bestIndex][1]; + changes[bestIndex][1] = tf; + + tf = dists[k]; + dists[k] = dists[bestIndex]; + dists[bestIndex] = tf; + } + } + bestIndex = -1; + /* find the best change with an acceptable horizontal change */ + for (i = 0; i < totweight; i++) { + if (fabsf(changes[i][0]) > fabsf(changes[i][1] * 2.0f)) { + bestIndex = i; + break; + } + } + if (bestIndex != -1) { + wasChange = true; + /* it is a good place to stop if it tries to move the opposite direction + * (relative to the plane) of last time */ + if (lastIndex != -1) { + if (wasUp != upDown[bestIndex]) { + wasChange = false; + } + } + lastIndex = bestIndex; + wasUp = upDown[bestIndex]; + dw = (dvert->dw + dwIndices[bestIndex]); + oldw = dw->weight; + if (upDown[bestIndex]) { + dw->weight *= 1 + cp; + } + else { + dw->weight /= 1 + cp; + } + if (dw->weight > 1) { + dw->weight = 1; + } + if (oldw == dw->weight) { + wasChange = false; + } + if (me_deform) { + /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs! + * Better to over-free and recompute a bit. */ + BKE_object_free_derived_caches(ob); + } + } + } while (wasChange && ((distToStart - distToBe) / fabsf(distToStart - distToBe) == + (dists[bestIndex] - distToBe) / fabsf(dists[bestIndex] - distToBe))); + + MEM_freeN(upDown); + MEM_freeN(changes); + MEM_freeN(dists); + MEM_freeN(dwIndices); } /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex * but it could be used to raise or lower an existing 'bump.' */ -static void vgroup_fix(const bContext *C, Scene *scene, Object *ob, float distToBe, float strength, float cp) -{ - Depsgraph *depsgraph = CTX_data_depsgraph(C); - int i; - - Mesh *me = ob->data; - MVert *mvert = me->mvert; - int *verts = NULL; - if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) - return; - for (i = 0; i < me->totvert && mvert; i++, mvert++) { - if (mvert->flag & SELECT) { - int count = 0; - if ((verts = getSurroundingVerts(me, i, &count))) { - MVert m; - MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints"); - int k; - - Mesh *me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); - k = count; - while (k--) { - p[k] = me_deform->mvert[verts[k]]; - } - - if (count >= 3) { - float d /*, dist */ /* UNUSED */, mag; - float coord[3]; - float norm[3]; - getSingleCoordinate(p, count, coord); - m = me_deform->mvert[i]; - sub_v3_v3v3(norm, m.co, coord); - mag = normalize_v3(norm); - if (mag) { /* zeros fix */ - d = -dot_v3v3(norm, coord); - /* dist = (dot_v3v3(norm, m.co) + d); */ /* UNUSED */ - moveCloserToDistanceFromPlane(depsgraph, scene, ob, me, i, norm, coord, d, distToBe, strength, cp); - } - } - - MEM_freeN(verts); - MEM_freeN(p); - } - } - } -} - -static void vgroup_levels_subset( - Object *ob, const bool *vgroup_validmap, const int vgroup_tot, - const int UNUSED(subset_count), - const float offset, const float gain) -{ - MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; - int i, dvert_tot = 0; - - const bool use_vert_sel = vertex_group_use_vert_sel(ob); - const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - - for (i = 0; i < dvert_tot; i++) { - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - j = vgroup_tot; - while (j--) { - if (vgroup_validmap[j]) { - dw = defvert_find_index(dv, j); - if (dw) { - dw->weight = gain * (dw->weight + offset); - - CLAMP(dw->weight, 0.0f, 1.0f); - } - } - } - } - - if (use_mirror && use_vert_sel) { - ED_vgroup_parray_mirror_sync( - ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); - } - - MEM_freeN(dvert_array); - } -} - -static bool vgroup_normalize_all( - Object *ob, - const bool *vgroup_validmap, - const int vgroup_tot, - const int subset_count, - const bool lock_active, - ReportList *reports) -{ - MDeformVert *dv, **dvert_array = NULL; - int i, dvert_tot = 0; - const int def_nr = ob->actdef - 1; - - const int use_vert_sel = vertex_group_use_vert_sel(ob); - - if (subset_count == 0) { - BKE_report(reports, RPT_ERROR, "No vertex groups to operate on"); - return false; - } - - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - const int defbase_tot = BLI_listbase_count(&ob->defbase); - bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot); - bool changed = false; - - if ((lock_active == true) && - (lock_flags != NULL) && - (def_nr < defbase_tot)) - { - lock_flags[def_nr] = true; - } - - if (lock_flags) { - for (i = 0; i < defbase_tot; i++) { - if (lock_flags[i] == false) { - break; - } - } - - if (i == defbase_tot) { - BKE_report(reports, RPT_ERROR, "All groups are locked"); - goto finally; - } - } - - for (i = 0; i < dvert_tot; i++) { - /* in case its not selected */ - if ((dv = dvert_array[i])) { - if (lock_flags) { - defvert_normalize_lock_map( - dv, vgroup_validmap, vgroup_tot, - lock_flags, defbase_tot); - } - else if (lock_active) { - defvert_normalize_lock_single( - dv, vgroup_validmap, vgroup_tot, - def_nr); - } - else { - defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot); - } - } - } - - changed = true; - -finally: - if (lock_flags) { - MEM_freeN(lock_flags); - } - - MEM_freeN(dvert_array); - - return changed; - } - - return false; +static void vgroup_fix( + const bContext *C, Scene *scene, Object *ob, float distToBe, float strength, float cp) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int i; + + Mesh *me = ob->data; + MVert *mvert = me->mvert; + int *verts = NULL; + if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) + return; + for (i = 0; i < me->totvert && mvert; i++, mvert++) { + if (mvert->flag & SELECT) { + int count = 0; + if ((verts = getSurroundingVerts(me, i, &count))) { + MVert m; + MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints"); + int k; + + Mesh *me_deform = mesh_get_eval_deform(depsgraph, scene, ob, &CD_MASK_BAREMESH); + k = count; + while (k--) { + p[k] = me_deform->mvert[verts[k]]; + } + + if (count >= 3) { + float d /*, dist */ /* UNUSED */, mag; + float coord[3]; + float norm[3]; + getSingleCoordinate(p, count, coord); + m = me_deform->mvert[i]; + sub_v3_v3v3(norm, m.co, coord); + mag = normalize_v3(norm); + if (mag) { /* zeros fix */ + d = -dot_v3v3(norm, coord); + /* dist = (dot_v3v3(norm, m.co) + d); */ /* UNUSED */ + moveCloserToDistanceFromPlane( + depsgraph, scene, ob, me, i, norm, coord, d, distToBe, strength, cp); + } + } + + MEM_freeN(verts); + MEM_freeN(p); + } + } + } +} + +static void vgroup_levels_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int UNUSED(subset_count), + const float offset, + const float gain) +{ + MDeformWeight *dw; + MDeformVert *dv, **dvert_array = NULL; + int i, dvert_tot = 0; + + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? + (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : + false; + + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + + for (i = 0; i < dvert_tot; i++) { + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + j = vgroup_tot; + while (j--) { + if (vgroup_validmap[j]) { + dw = defvert_find_index(dv, j); + if (dw) { + dw->weight = gain * (dw->weight + offset); + + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } + } + + if (use_mirror && use_vert_sel) { + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot); + } + + MEM_freeN(dvert_array); + } +} + +static bool vgroup_normalize_all(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int subset_count, + const bool lock_active, + ReportList *reports) +{ + MDeformVert *dv, **dvert_array = NULL; + int i, dvert_tot = 0; + const int def_nr = ob->actdef - 1; + + const int use_vert_sel = vertex_group_use_vert_sel(ob); + + if (subset_count == 0) { + BKE_report(reports, RPT_ERROR, "No vertex groups to operate on"); + return false; + } + + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + const int defbase_tot = BLI_listbase_count(&ob->defbase); + bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot); + bool changed = false; + + if ((lock_active == true) && (lock_flags != NULL) && (def_nr < defbase_tot)) { + lock_flags[def_nr] = true; + } + + if (lock_flags) { + for (i = 0; i < defbase_tot; i++) { + if (lock_flags[i] == false) { + break; + } + } + + if (i == defbase_tot) { + BKE_report(reports, RPT_ERROR, "All groups are locked"); + goto finally; + } + } + + for (i = 0; i < dvert_tot; i++) { + /* in case its not selected */ + if ((dv = dvert_array[i])) { + if (lock_flags) { + defvert_normalize_lock_map(dv, vgroup_validmap, vgroup_tot, lock_flags, defbase_tot); + } + else if (lock_active) { + defvert_normalize_lock_single(dv, vgroup_validmap, vgroup_tot, def_nr); + } + else { + defvert_normalize_subset(dv, vgroup_validmap, vgroup_tot); + } + } + } + + changed = true; + + finally: + if (lock_flags) { + MEM_freeN(lock_flags); + } + + MEM_freeN(dvert_array); + + return changed; + } + + return false; } enum { - VGROUP_TOGGLE, - VGROUP_LOCK, - VGROUP_UNLOCK, - VGROUP_INVERT, + VGROUP_TOGGLE, + VGROUP_LOCK, + VGROUP_UNLOCK, + VGROUP_INVERT, }; static const EnumPropertyItem vgroup_lock_actions[] = { - {VGROUP_TOGGLE, "TOGGLE", 0, "Toggle", "Unlock all vertex groups if there is at least one locked group, lock all in other case"}, - {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"}, - {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"}, - {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"}, - {0, NULL, 0, NULL, NULL}, + {VGROUP_TOGGLE, + "TOGGLE", + 0, + "Toggle", + "Unlock all vertex groups if there is at least one locked group, lock all in other case"}, + {VGROUP_LOCK, "LOCK", 0, "Lock", "Lock all vertex groups"}, + {VGROUP_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock all vertex groups"}, + {VGROUP_INVERT, "INVERT", 0, "Invert", "Invert the lock state of all vertex groups"}, + {0, NULL, 0, NULL, NULL}, }; static void vgroup_lock_all(Object *ob, int action) { - bDeformGroup *dg; - - if (action == VGROUP_TOGGLE) { - action = VGROUP_LOCK; - for (dg = ob->defbase.first; dg; dg = dg->next) { - if (dg->flag & DG_LOCK_WEIGHT) { - action = VGROUP_UNLOCK; - break; - } - } - } - - for (dg = ob->defbase.first; dg; dg = dg->next) { - switch (action) { - case VGROUP_LOCK: - dg->flag |= DG_LOCK_WEIGHT; - break; - case VGROUP_UNLOCK: - dg->flag &= ~DG_LOCK_WEIGHT; - break; - case VGROUP_INVERT: - dg->flag ^= DG_LOCK_WEIGHT; - break; - } - } -} - -static void vgroup_invert_subset( - Object *ob, - const bool *vgroup_validmap, const int vgroup_tot, - const int UNUSED(subset_count), const bool auto_assign, const bool auto_remove) -{ - MDeformWeight *dw; - MDeformVert *dv, **dvert_array = NULL; - int i, dvert_tot = 0; - const bool use_vert_sel = vertex_group_use_vert_sel(ob); - const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - for (i = 0; i < dvert_tot; i++) { - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - j = vgroup_tot; - while (j--) { - - if (vgroup_validmap[j]) { - if (auto_assign) { - dw = defvert_verify_index(dv, j); - } - else { - dw = defvert_find_index(dv, j); - } - - if (dw) { - dw->weight = 1.0f - dw->weight; - CLAMP(dw->weight, 0.0f, 1.0f); - } - } - } - } - - if (use_mirror && use_vert_sel) { - ED_vgroup_parray_mirror_sync( - ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); - } - - if (auto_remove) { - ED_vgroup_parray_remove_zero( - dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot, - 0.0f, false); - } - - MEM_freeN(dvert_array); - } -} - -static void vgroup_smooth_subset( - Object *ob, const bool *vgroup_validmap, const int vgroup_tot, - const int subset_count, - const float fac, const int repeat, - const float fac_expand) -{ - const float ifac = 1.0f - fac; - MDeformVert **dvert_array = NULL; - int dvert_tot = 0; - int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); - float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); - const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - const bool use_select = vertex_group_use_vert_sel(ob); - const bool use_hide = use_select; - - const int expand_sign = signum_i(fac_expand); - const float expand = fabsf(fac_expand); - const float iexpand = 1.0f - expand; - - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em ? em->bm : NULL; - Mesh *me = em ? NULL : ob->data; - - MeshElemMap *emap; - int *emap_mem; - - float *weight_accum_prev; - float *weight_accum_curr; - - unsigned int subset_index; - - /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */ - unsigned int *verts_used; - STACK_DECLARE(verts_used); - - - BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map); - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count); - - if (bm) { - BM_mesh_elem_table_ensure(bm, BM_VERT); - BM_mesh_elem_index_ensure(bm, BM_VERT); - - emap = NULL; - emap_mem = NULL; - } - else { - BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge); - } - - weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__); - weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__); - - verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__); - STACK_INIT(verts_used, dvert_tot); - -#define IS_BM_VERT_READ(v) \ - (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true) -#define IS_BM_VERT_WRITE(v) \ - (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true) - -#define IS_ME_VERT_READ(v) \ - (use_hide ? (((v)->flag & ME_HIDE) == 0) : true) -#define IS_ME_VERT_WRITE(v) \ - (use_select ? (((v)->flag & SELECT) != 0) : true) - - /* initialize used verts */ - if (bm) { - for (int i = 0; i < dvert_tot; i++) { - BMVert *v = BM_vert_at_index(bm, i); - if (IS_BM_VERT_WRITE(v)) { - BMIter eiter; - BMEdge *e; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMVert *v_other = BM_edge_other_vert(e, v); - if (IS_BM_VERT_READ(v_other)) { - STACK_PUSH(verts_used, i); - break; - } - } - } - } - } - else { - for (int i = 0; i < dvert_tot; i++) { - const MVert *v = &me->mvert[i]; - if (IS_ME_VERT_WRITE(v)) { - for (int j = 0; j < emap[i].count; j++) { - const MEdge *e = &me->medge[emap[i].indices[j]]; - const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1]; - if (IS_ME_VERT_READ(v_other)) { - STACK_PUSH(verts_used, i); - break; - } - } - } - } - } - - for (subset_index = 0; subset_index < subset_count; subset_index++) { - const int def_nr = vgroup_subset_map[subset_index]; - int iter; - - ED_vgroup_parray_to_weight_array((const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr); - memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot); - - for (iter = 0; iter < repeat; iter++) { - unsigned *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used); - - /* avoid looping over all verts */ - // for (i = 0; i < dvert_tot; i++) - for (vi_step = verts_used; vi_step != vi_end; vi_step++) { - const unsigned int i = *vi_step; - float weight_tot = 0.0f; - float weight = 0.0f; + bDeformGroup *dg; + + if (action == VGROUP_TOGGLE) { + action = VGROUP_LOCK; + for (dg = ob->defbase.first; dg; dg = dg->next) { + if (dg->flag & DG_LOCK_WEIGHT) { + action = VGROUP_UNLOCK; + break; + } + } + } + + for (dg = ob->defbase.first; dg; dg = dg->next) { + switch (action) { + case VGROUP_LOCK: + dg->flag |= DG_LOCK_WEIGHT; + break; + case VGROUP_UNLOCK: + dg->flag &= ~DG_LOCK_WEIGHT; + break; + case VGROUP_INVERT: + dg->flag ^= DG_LOCK_WEIGHT; + break; + } + } +} + +static void vgroup_invert_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int UNUSED(subset_count), + const bool auto_assign, + const bool auto_remove) +{ + MDeformWeight *dw; + MDeformVert *dv, **dvert_array = NULL; + int i, dvert_tot = 0; + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? + (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : + false; + + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + for (i = 0; i < dvert_tot; i++) { + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + j = vgroup_tot; + while (j--) { + + if (vgroup_validmap[j]) { + if (auto_assign) { + dw = defvert_verify_index(dv, j); + } + else { + dw = defvert_find_index(dv, j); + } + + if (dw) { + dw->weight = 1.0f - dw->weight; + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } + } + + if (use_mirror && use_vert_sel) { + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot); + } + + if (auto_remove) { + ED_vgroup_parray_remove_zero( + dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, 0.0f, false); + } + + MEM_freeN(dvert_array); + } +} + +static void vgroup_smooth_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int subset_count, + const float fac, + const int repeat, + const float fac_expand) +{ + const float ifac = 1.0f - fac; + MDeformVert **dvert_array = NULL; + int dvert_tot = 0; + int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); + float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); + const bool use_mirror = (ob->type == OB_MESH) ? + (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : + false; + const bool use_select = vertex_group_use_vert_sel(ob); + const bool use_hide = use_select; + + const int expand_sign = signum_i(fac_expand); + const float expand = fabsf(fac_expand); + const float iexpand = 1.0f - expand; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em ? em->bm : NULL; + Mesh *me = em ? NULL : ob->data; + + MeshElemMap *emap; + int *emap_mem; + + float *weight_accum_prev; + float *weight_accum_curr; + + unsigned int subset_index; + + /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */ + unsigned int *verts_used; + STACK_DECLARE(verts_used); + + BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + memset(vgroup_subset_weights, 0, sizeof(*vgroup_subset_weights) * subset_count); + + if (bm) { + BM_mesh_elem_table_ensure(bm, BM_VERT); + BM_mesh_elem_index_ensure(bm, BM_VERT); + + emap = NULL; + emap_mem = NULL; + } + else { + BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge); + } + + weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__); + weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__); + + verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__); + STACK_INIT(verts_used, dvert_tot); + +#define IS_BM_VERT_READ(v) (use_hide ? (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == 0) : true) +#define IS_BM_VERT_WRITE(v) (use_select ? (BM_elem_flag_test(v, BM_ELEM_SELECT) != 0) : true) + +#define IS_ME_VERT_READ(v) (use_hide ? (((v)->flag & ME_HIDE) == 0) : true) +#define IS_ME_VERT_WRITE(v) (use_select ? (((v)->flag & SELECT) != 0) : true) + + /* initialize used verts */ + if (bm) { + for (int i = 0; i < dvert_tot; i++) { + BMVert *v = BM_vert_at_index(bm, i); + if (IS_BM_VERT_WRITE(v)) { + BMIter eiter; + BMEdge *e; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMVert *v_other = BM_edge_other_vert(e, v); + if (IS_BM_VERT_READ(v_other)) { + STACK_PUSH(verts_used, i); + break; + } + } + } + } + } + else { + for (int i = 0; i < dvert_tot; i++) { + const MVert *v = &me->mvert[i]; + if (IS_ME_VERT_WRITE(v)) { + for (int j = 0; j < emap[i].count; j++) { + const MEdge *e = &me->medge[emap[i].indices[j]]; + const MVert *v_other = &me->mvert[(e->v1 == i) ? e->v2 : e->v1]; + if (IS_ME_VERT_READ(v_other)) { + STACK_PUSH(verts_used, i); + break; + } + } + } + } + } + + for (subset_index = 0; subset_index < subset_count; subset_index++) { + const int def_nr = vgroup_subset_map[subset_index]; + int iter; + + ED_vgroup_parray_to_weight_array( + (const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr); + memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot); + + for (iter = 0; iter < repeat; iter++) { + unsigned *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used); + + /* avoid looping over all verts */ + // for (i = 0; i < dvert_tot; i++) + for (vi_step = verts_used; vi_step != vi_end; vi_step++) { + const unsigned int i = *vi_step; + float weight_tot = 0.0f; + float weight = 0.0f; #define WEIGHT_ACCUMULATE \ - { \ - float weight_other = weight_accum_prev[i_other]; \ - float tot_factor = 1.0f; \ - if (expand_sign == 1) { /* expand */ \ - if (weight_other < weight_accum_prev[i]) { \ - weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \ - tot_factor = iexpand; \ - } \ - } \ - else if (expand_sign == -1) { /* contract */ \ - if (weight_other > weight_accum_prev[i]) { \ - weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \ - tot_factor = iexpand; \ - } \ - } \ - weight += tot_factor * weight_other; \ - weight_tot += tot_factor; \ - } ((void)0) - - - if (bm) { - BMVert *v = BM_vert_at_index(bm, i); - BMIter eiter; - BMEdge *e; - - /* checked already */ - BLI_assert(IS_BM_VERT_WRITE(v)); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMVert *v_other = BM_edge_other_vert(e, v); - if (IS_BM_VERT_READ(v_other)) { - const int i_other = BM_elem_index_get(v_other); - - WEIGHT_ACCUMULATE; - } - } - } - else { - int j; - - /* checked already */ - BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i])); - - for (j = 0; j < emap[i].count; j++) { - MEdge *e = &me->medge[emap[i].indices[j]]; - const int i_other = (e->v1 == i ? e->v2 : e->v1); - MVert *v_other = &me->mvert[i_other]; - - if (IS_ME_VERT_READ(v_other)) { - WEIGHT_ACCUMULATE; - } - } - } + { \ + float weight_other = weight_accum_prev[i_other]; \ + float tot_factor = 1.0f; \ + if (expand_sign == 1) { /* expand */ \ + if (weight_other < weight_accum_prev[i]) { \ + weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \ + tot_factor = iexpand; \ + } \ + } \ + else if (expand_sign == -1) { /* contract */ \ + if (weight_other > weight_accum_prev[i]) { \ + weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \ + tot_factor = iexpand; \ + } \ + } \ + weight += tot_factor * weight_other; \ + weight_tot += tot_factor; \ + } \ + ((void)0) + + if (bm) { + BMVert *v = BM_vert_at_index(bm, i); + BMIter eiter; + BMEdge *e; + + /* checked already */ + BLI_assert(IS_BM_VERT_WRITE(v)); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMVert *v_other = BM_edge_other_vert(e, v); + if (IS_BM_VERT_READ(v_other)) { + const int i_other = BM_elem_index_get(v_other); + + WEIGHT_ACCUMULATE; + } + } + } + else { + int j; + + /* checked already */ + BLI_assert(IS_ME_VERT_WRITE(&me->mvert[i])); + + for (j = 0; j < emap[i].count; j++) { + MEdge *e = &me->medge[emap[i].indices[j]]; + const int i_other = (e->v1 == i ? e->v2 : e->v1); + MVert *v_other = &me->mvert[i_other]; + + if (IS_ME_VERT_READ(v_other)) { + WEIGHT_ACCUMULATE; + } + } + } #undef WEIGHT_ACCUMULATE - if (weight_tot != 0.0f) { - weight /= weight_tot; - weight = (weight_accum_prev[i] * ifac) + (weight * fac); + if (weight_tot != 0.0f) { + weight /= weight_tot; + weight = (weight_accum_prev[i] * ifac) + (weight * fac); - /* should be within range, just clamp because of float precision */ - CLAMP(weight, 0.0f, 1.0f); - weight_accum_curr[i] = weight; - } - } + /* should be within range, just clamp because of float precision */ + CLAMP(weight, 0.0f, 1.0f); + weight_accum_curr[i] = weight; + } + } - SWAP(float *, weight_accum_curr, weight_accum_prev); - } + SWAP(float *, weight_accum_curr, weight_accum_prev); + } - ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true); - } + ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true); + } #undef IS_BM_VERT_READ #undef IS_BM_VERT_WRITE #undef IS_ME_VERT_READ #undef IS_ME_VERT_WRITE - MEM_freeN(weight_accum_curr); - MEM_freeN(weight_accum_prev); - MEM_freeN(verts_used); - - if (bm) { - /* pass */ - } - else { - MEM_freeN(emap); - MEM_freeN(emap_mem); - } - - if (dvert_array) - MEM_freeN(dvert_array); - - /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */ - if (use_mirror) { - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true); - ED_vgroup_parray_mirror_sync( - ob, dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot); - if (dvert_array) - MEM_freeN(dvert_array); - } + MEM_freeN(weight_accum_curr); + MEM_freeN(weight_accum_prev); + MEM_freeN(verts_used); + + if (bm) { + /* pass */ + } + else { + MEM_freeN(emap); + MEM_freeN(emap_mem); + } + + if (dvert_array) + MEM_freeN(dvert_array); + + /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */ + if (use_mirror) { + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true); + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, vgroup_validmap, vgroup_tot); + if (dvert_array) + MEM_freeN(dvert_array); + } } static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2) { - /* qsort sorts in ascending order. We want descending order to save a memcopy - * so this compare function is inverted from the standard greater than comparison qsort needs. - * A normal compare function is called with two pointer arguments and should return an integer - * less than, equal to, or greater than zero corresponding to whether its first argument is - * considered less than, equal to, or greater than its second argument. - * This does the opposite. */ - const struct MDeformWeight *dw1 = a1, *dw2 = a2; - - if (dw1->weight < dw2->weight) return 1; - else if (dw1->weight > dw2->weight) return -1; - else if (&dw1 < &dw2) return 1; /* compare address for stable sort algorithm */ - else return -1; + /* qsort sorts in ascending order. We want descending order to save a memcopy + * so this compare function is inverted from the standard greater than comparison qsort needs. + * A normal compare function is called with two pointer arguments and should return an integer + * less than, equal to, or greater than zero corresponding to whether its first argument is + * considered less than, equal to, or greater than its second argument. + * This does the opposite. */ + const struct MDeformWeight *dw1 = a1, *dw2 = a2; + + if (dw1->weight < dw2->weight) + return 1; + else if (dw1->weight > dw2->weight) + return -1; + else if (&dw1 < &dw2) + return 1; /* compare address for stable sort algorithm */ + else + return -1; } /* Used for limiting the number of influencing bones per vertex when exporting * skinned meshes. if all_deform_weights is True, limit all deform modifiers * to max_weights regardless of type, otherwise, * only limit the number of influencing bones per vertex. */ -static int vgroup_limit_total_subset( - Object *ob, - const bool *vgroup_validmap, - const int vgroup_tot, - const int subset_count, - const int max_weights) -{ - MDeformVert *dv, **dvert_array = NULL; - int i, dvert_tot = 0; - const int use_vert_sel = vertex_group_use_vert_sel(ob); - int remove_tot = 0; - - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - int num_to_drop = 0; - - for (i = 0; i < dvert_tot; i++) { - - MDeformWeight *dw_temp; - int bone_count = 0, non_bone_count = 0; - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - num_to_drop = subset_count - max_weights; - - /* first check if we even need to test further */ - if (num_to_drop > 0) { - /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end - * sort the tail, then copy only the truncated array back to dv->dw */ - dw_temp = MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__); - bone_count = 0; non_bone_count = 0; - for (j = 0; j < dv->totweight; j++) { - if (LIKELY(dv->dw[j].def_nr < vgroup_tot) && - vgroup_validmap[dv->dw[j].def_nr]) - { - dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j]; - bone_count += 1; - } - else { - dw_temp[non_bone_count] = dv->dw[j]; - non_bone_count += 1; - } - } - BLI_assert(bone_count + non_bone_count == dv->totweight); - num_to_drop = bone_count - max_weights; - if (num_to_drop > 0) { - qsort(&dw_temp[non_bone_count], bone_count, sizeof(MDeformWeight), inv_cmp_mdef_vert_weights); - dv->totweight -= num_to_drop; - /* Do we want to clean/normalize here? */ - MEM_freeN(dv->dw); - dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight); - remove_tot += num_to_drop; - } - else { - MEM_freeN(dw_temp); - } - } - - } - MEM_freeN(dvert_array); - - } - - return remove_tot; -} - - -static void vgroup_clean_subset( - Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), - const float epsilon, const bool keep_single) -{ - MDeformVert **dvert_array = NULL; - int dvert_tot = 0; - const bool use_vert_sel = vertex_group_use_vert_sel(ob); - const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - if (use_mirror && use_vert_sel) { - /* correct behavior in this case isn't well defined - * for now assume both sides are mirrored correctly, - * so cleaning one side also cleans the other */ - ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); - } - - ED_vgroup_parray_remove_zero( - dvert_array, dvert_tot, - vgroup_validmap, vgroup_tot, - epsilon, keep_single); - - MEM_freeN(dvert_array); - } -} - -static void vgroup_quantize_subset( - Object *ob, const bool *vgroup_validmap, const int vgroup_tot, const int UNUSED(subset_count), - const int steps) -{ - MDeformVert **dvert_array = NULL; - int dvert_tot = 0; - const bool use_vert_sel = vertex_group_use_vert_sel(ob); - const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); - - if (dvert_array) { - const float steps_fl = steps; - MDeformVert *dv; - int i; - - if (use_mirror && use_vert_sel) { - ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); - } - - for (i = 0; i < dvert_tot; i++) { - MDeformWeight *dw; - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) { - if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { - dw->weight = floorf((dw->weight * steps_fl) + 0.5f) / steps_fl; - CLAMP(dw->weight, 0.0f, 1.0f); - } - } - } - - MEM_freeN(dvert_array); - } -} - -static void dvert_mirror_op( - MDeformVert *dvert, MDeformVert *dvert_mirr, - const char sel, const char sel_mirr, - const int *flip_map, const int flip_map_len, - const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, - const int act_vgroup) -{ - BLI_assert(sel || sel_mirr); - - if (sel_mirr && sel) { - /* swap */ - if (mirror_weights) { - if (all_vgroups) { - SWAP(MDeformVert, *dvert, *dvert_mirr); - } - else { - MDeformWeight *dw = defvert_find_index(dvert, act_vgroup); - MDeformWeight *dw_mirr = defvert_find_index(dvert_mirr, act_vgroup); - - if (dw && dw_mirr) { - SWAP(float, dw->weight, dw_mirr->weight); - } - else if (dw) { - dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup); - dw_mirr->weight = dw->weight; - defvert_remove_group(dvert, dw); - } - else if (dw_mirr) { - dw = defvert_verify_index(dvert, act_vgroup); - dw->weight = dw_mirr->weight; - defvert_remove_group(dvert_mirr, dw_mirr); - } - } - } - - if (flip_vgroups) { - defvert_flip(dvert, flip_map, flip_map_len); - defvert_flip(dvert_mirr, flip_map, flip_map_len); - } - } - else { - /* dvert should always be the target, only swaps pointer */ - if (sel_mirr) { - SWAP(MDeformVert *, dvert, dvert_mirr); - } - - if (mirror_weights) { - if (all_vgroups) { - defvert_copy(dvert, dvert_mirr); - } - else { - defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup); - } - } - - /* flip map already modified for 'all_vgroups' */ - if (flip_vgroups) { - defvert_flip(dvert, flip_map, flip_map_len); - } - } +static int vgroup_limit_total_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int subset_count, + const int max_weights) +{ + MDeformVert *dv, **dvert_array = NULL; + int i, dvert_tot = 0; + const int use_vert_sel = vertex_group_use_vert_sel(ob); + int remove_tot = 0; + + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + int num_to_drop = 0; + + for (i = 0; i < dvert_tot; i++) { + + MDeformWeight *dw_temp; + int bone_count = 0, non_bone_count = 0; + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + num_to_drop = subset_count - max_weights; + + /* first check if we even need to test further */ + if (num_to_drop > 0) { + /* re-pack dw array so that non-bone weights are first, bone-weighted verts at end + * sort the tail, then copy only the truncated array back to dv->dw */ + dw_temp = MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, __func__); + bone_count = 0; + non_bone_count = 0; + for (j = 0; j < dv->totweight; j++) { + if (LIKELY(dv->dw[j].def_nr < vgroup_tot) && vgroup_validmap[dv->dw[j].def_nr]) { + dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j]; + bone_count += 1; + } + else { + dw_temp[non_bone_count] = dv->dw[j]; + non_bone_count += 1; + } + } + BLI_assert(bone_count + non_bone_count == dv->totweight); + num_to_drop = bone_count - max_weights; + if (num_to_drop > 0) { + qsort(&dw_temp[non_bone_count], + bone_count, + sizeof(MDeformWeight), + inv_cmp_mdef_vert_weights); + dv->totweight -= num_to_drop; + /* Do we want to clean/normalize here? */ + MEM_freeN(dv->dw); + dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight); + remove_tot += num_to_drop; + } + else { + MEM_freeN(dw_temp); + } + } + } + MEM_freeN(dvert_array); + } + + return remove_tot; +} + +static void vgroup_clean_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int UNUSED(subset_count), + const float epsilon, + const bool keep_single) +{ + MDeformVert **dvert_array = NULL; + int dvert_tot = 0; + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? + (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : + false; + + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + if (use_mirror && use_vert_sel) { + /* correct behavior in this case isn't well defined + * for now assume both sides are mirrored correctly, + * so cleaning one side also cleans the other */ + ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); + } + + ED_vgroup_parray_remove_zero( + dvert_array, dvert_tot, vgroup_validmap, vgroup_tot, epsilon, keep_single); + + MEM_freeN(dvert_array); + } +} + +static void vgroup_quantize_subset(Object *ob, + const bool *vgroup_validmap, + const int vgroup_tot, + const int UNUSED(subset_count), + const int steps) +{ + MDeformVert **dvert_array = NULL; + int dvert_tot = 0; + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? + (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : + false; + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + + if (dvert_array) { + const float steps_fl = steps; + MDeformVert *dv; + int i; + + if (use_mirror && use_vert_sel) { + ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); + } + + for (i = 0; i < dvert_tot; i++) { + MDeformWeight *dw; + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) { + if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { + dw->weight = floorf((dw->weight * steps_fl) + 0.5f) / steps_fl; + CLAMP(dw->weight, 0.0f, 1.0f); + } + } + } + + MEM_freeN(dvert_array); + } +} + +static void dvert_mirror_op(MDeformVert *dvert, + MDeformVert *dvert_mirr, + const char sel, + const char sel_mirr, + const int *flip_map, + const int flip_map_len, + const bool mirror_weights, + const bool flip_vgroups, + const bool all_vgroups, + const int act_vgroup) +{ + BLI_assert(sel || sel_mirr); + + if (sel_mirr && sel) { + /* swap */ + if (mirror_weights) { + if (all_vgroups) { + SWAP(MDeformVert, *dvert, *dvert_mirr); + } + else { + MDeformWeight *dw = defvert_find_index(dvert, act_vgroup); + MDeformWeight *dw_mirr = defvert_find_index(dvert_mirr, act_vgroup); + + if (dw && dw_mirr) { + SWAP(float, dw->weight, dw_mirr->weight); + } + else if (dw) { + dw_mirr = defvert_verify_index(dvert_mirr, act_vgroup); + dw_mirr->weight = dw->weight; + defvert_remove_group(dvert, dw); + } + else if (dw_mirr) { + dw = defvert_verify_index(dvert, act_vgroup); + dw->weight = dw_mirr->weight; + defvert_remove_group(dvert_mirr, dw_mirr); + } + } + } + + if (flip_vgroups) { + defvert_flip(dvert, flip_map, flip_map_len); + defvert_flip(dvert_mirr, flip_map, flip_map_len); + } + } + else { + /* dvert should always be the target, only swaps pointer */ + if (sel_mirr) { + SWAP(MDeformVert *, dvert, dvert_mirr); + } + + if (mirror_weights) { + if (all_vgroups) { + defvert_copy(dvert, dvert_mirr); + } + else { + defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup); + } + } + + /* flip map already modified for 'all_vgroups' */ + if (flip_vgroups) { + defvert_flip(dvert, flip_map, flip_map_len); + } + } } /* TODO, vgroup locking */ /* TODO, face masking */ -void ED_vgroup_mirror( - Object *ob, - const bool mirror_weights, const bool flip_vgroups, - const bool all_vgroups, const bool use_topology, - int *r_totmirr, int *r_totfail) -{ - -#define VGROUP_MIRR_OP \ - dvert_mirror_op(dvert, dvert_mirr, \ - sel, sel_mirr, \ - flip_map, flip_map_len, \ - mirror_weights, flip_vgroups, \ - all_vgroups, def_nr \ - ) - - BMVert *eve, *eve_mirr; - MDeformVert *dvert, *dvert_mirr; - char sel, sel_mirr; - int *flip_map = NULL, flip_map_len; - const int def_nr = ob->actdef - 1; - int totmirr = 0, totfail = 0; - - *r_totmirr = *r_totfail = 0; - - if ((mirror_weights == false && flip_vgroups == false) || - (BLI_findlink(&ob->defbase, def_nr) == NULL)) - { - return; - } - - if (flip_vgroups) { - flip_map = all_vgroups ? - defgroup_flip_map(ob, &flip_map_len, false) : - defgroup_flip_map_single(ob, &flip_map_len, false, def_nr); - - BLI_assert(flip_map != NULL); - - if (flip_map == NULL) { - /* something went wrong!, possibly no groups */ - return; - } - } - else { - flip_map = NULL; - flip_map_len = 0; - } - - /* only the active group */ - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - - if (em) { - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - BMIter iter; - - if (cd_dvert_offset == -1) { - goto cleanup; - } - - EDBM_verts_mirror_cache_begin(em, 0, true, false, use_topology); - - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - /* Go through the list of editverts and assign them */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) { - if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) { - if (eve_mirr != eve) { - if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) { - sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); - sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); - - if ((sel || sel_mirr) && (eve != eve_mirr)) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); - - VGROUP_MIRR_OP; - totmirr++; - } - - /* don't use these again */ - BM_elem_flag_enable(eve, BM_ELEM_TAG); - BM_elem_flag_enable(eve_mirr, BM_ELEM_TAG); - } - } - } - else { - totfail++; - } - } - } - EDBM_verts_mirror_cache_end(em); - } - else { - /* object mode / weight paint */ - MVert *mv, *mv_mirr; - int vidx, vidx_mirr; - const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; - - if (me->dvert == NULL) { - goto cleanup; - } - - if (!use_vert_sel) { - sel = sel_mirr = true; - } - - /* tag verts we have used */ - for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { - mv->flag &= ~ME_VERT_TMP_TAG; - } - - for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { - if ((mv->flag & ME_VERT_TMP_TAG) == 0) { - if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) { - if (vidx != vidx_mirr) { - mv_mirr = &me->mvert[vidx_mirr]; - if ((mv_mirr->flag & ME_VERT_TMP_TAG) == 0) { - - if (use_vert_sel) { - sel = mv->flag & SELECT; - sel_mirr = mv_mirr->flag & SELECT; - } - - if (sel || sel_mirr) { - dvert = &me->dvert[vidx]; - dvert_mirr = &me->dvert[vidx_mirr]; - - VGROUP_MIRR_OP; - totmirr++; - } - - mv->flag |= ME_VERT_TMP_TAG; - mv_mirr->flag |= ME_VERT_TMP_TAG; - } - } - } - else { - totfail++; - } - } - } - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - int i1, i2; - int u, v, w; - int pntsu_half; - /* half but found up odd value */ - - if (lt->pntsu == 1 || lt->dvert == NULL) { - goto cleanup; - } - - /* unlike editmesh we know that by only looping over the first half of - * the 'u' indices it will cover all points except the middle which is - * ok in this case */ - pntsu_half = lt->pntsu / 2; - - for (w = 0; w < lt->pntsw; w++) { - for (v = 0; v < lt->pntsv; v++) { - for (u = 0; u < pntsu_half; u++) { - int u_inv = (lt->pntsu - 1) - u; - if (u != u_inv) { - BPoint *bp, *bp_mirr; - - i1 = BKE_lattice_index_from_uvw(lt, u, v, w); - i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); - - bp = <->def[i1]; - bp_mirr = <->def[i2]; - - sel = bp->f1 & SELECT; - sel_mirr = bp_mirr->f1 & SELECT; - - if (sel || sel_mirr) { - dvert = <->dvert[i1]; - dvert_mirr = <->dvert[i2]; - - VGROUP_MIRR_OP; - totmirr++; - } - } - } - } - } - } - - /* disabled, confusing when you have an active pose bone */ +void ED_vgroup_mirror(Object *ob, + const bool mirror_weights, + const bool flip_vgroups, + const bool all_vgroups, + const bool use_topology, + int *r_totmirr, + int *r_totfail) +{ + +#define VGROUP_MIRR_OP \ + dvert_mirror_op(dvert, \ + dvert_mirr, \ + sel, \ + sel_mirr, \ + flip_map, \ + flip_map_len, \ + mirror_weights, \ + flip_vgroups, \ + all_vgroups, \ + def_nr) + + BMVert *eve, *eve_mirr; + MDeformVert *dvert, *dvert_mirr; + char sel, sel_mirr; + int *flip_map = NULL, flip_map_len; + const int def_nr = ob->actdef - 1; + int totmirr = 0, totfail = 0; + + *r_totmirr = *r_totfail = 0; + + if ((mirror_weights == false && flip_vgroups == false) || + (BLI_findlink(&ob->defbase, def_nr) == NULL)) { + return; + } + + if (flip_vgroups) { + flip_map = all_vgroups ? defgroup_flip_map(ob, &flip_map_len, false) : + defgroup_flip_map_single(ob, &flip_map_len, false, def_nr); + + BLI_assert(flip_map != NULL); + + if (flip_map == NULL) { + /* something went wrong!, possibly no groups */ + return; + } + } + else { + flip_map = NULL; + flip_map_len = 0; + } + + /* only the active group */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + + if (em) { + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + BMIter iter; + + if (cd_dvert_offset == -1) { + goto cleanup; + } + + EDBM_verts_mirror_cache_begin(em, 0, true, false, use_topology); + + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + /* Go through the list of editverts and assign them */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) { + if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) { + if (eve_mirr != eve) { + if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) { + sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); + sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); + + if ((sel || sel_mirr) && (eve != eve_mirr)) { + dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + dvert_mirr = BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset); + + VGROUP_MIRR_OP; + totmirr++; + } + + /* don't use these again */ + BM_elem_flag_enable(eve, BM_ELEM_TAG); + BM_elem_flag_enable(eve_mirr, BM_ELEM_TAG); + } + } + } + else { + totfail++; + } + } + } + EDBM_verts_mirror_cache_end(em); + } + else { + /* object mode / weight paint */ + MVert *mv, *mv_mirr; + int vidx, vidx_mirr; + const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + + if (me->dvert == NULL) { + goto cleanup; + } + + if (!use_vert_sel) { + sel = sel_mirr = true; + } + + /* tag verts we have used */ + for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { + mv->flag &= ~ME_VERT_TMP_TAG; + } + + for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) { + if ((mv->flag & ME_VERT_TMP_TAG) == 0) { + if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) { + if (vidx != vidx_mirr) { + mv_mirr = &me->mvert[vidx_mirr]; + if ((mv_mirr->flag & ME_VERT_TMP_TAG) == 0) { + + if (use_vert_sel) { + sel = mv->flag & SELECT; + sel_mirr = mv_mirr->flag & SELECT; + } + + if (sel || sel_mirr) { + dvert = &me->dvert[vidx]; + dvert_mirr = &me->dvert[vidx_mirr]; + + VGROUP_MIRR_OP; + totmirr++; + } + + mv->flag |= ME_VERT_TMP_TAG; + mv_mirr->flag |= ME_VERT_TMP_TAG; + } + } + } + else { + totfail++; + } + } + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = vgroup_edit_lattice(ob); + int i1, i2; + int u, v, w; + int pntsu_half; + /* half but found up odd value */ + + if (lt->pntsu == 1 || lt->dvert == NULL) { + goto cleanup; + } + + /* unlike editmesh we know that by only looping over the first half of + * the 'u' indices it will cover all points except the middle which is + * ok in this case */ + pntsu_half = lt->pntsu / 2; + + for (w = 0; w < lt->pntsw; w++) { + for (v = 0; v < lt->pntsv; v++) { + for (u = 0; u < pntsu_half; u++) { + int u_inv = (lt->pntsu - 1) - u; + if (u != u_inv) { + BPoint *bp, *bp_mirr; + + i1 = BKE_lattice_index_from_uvw(lt, u, v, w); + i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); + + bp = <->def[i1]; + bp_mirr = <->def[i2]; + + sel = bp->f1 & SELECT; + sel_mirr = bp_mirr->f1 & SELECT; + + if (sel || sel_mirr) { + dvert = <->dvert[i1]; + dvert_mirr = <->dvert[i2]; + + VGROUP_MIRR_OP; + totmirr++; + } + } + } + } + } + } + + /* disabled, confusing when you have an active pose bone */ #if 0 - /* flip active group index */ - if (flip_vgroups && flip_map[def_nr] >= 0) - ob->actdef = flip_map[def_nr] + 1; + /* flip active group index */ + if (flip_vgroups && flip_map[def_nr] >= 0) + ob->actdef = flip_map[def_nr] + 1; #endif cleanup: - *r_totmirr = totmirr; - *r_totfail = totfail; + *r_totmirr = totmirr; + *r_totfail = totfail; - if (flip_map) MEM_freeN(flip_map); + if (flip_map) + MEM_freeN(flip_map); #undef VGROUP_MIRR_OP - } static void vgroup_delete_active(Object *ob) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); - if (!dg) - return; + bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); + if (!dg) + return; - BKE_object_defgroup_remove(ob, dg); + BKE_object_defgroup_remove(ob, dg); } /* only in editmode */ static void vgroup_assign_verts(Object *ob, const float weight) { - const int def_nr = ob->actdef - 1; - - if (!BLI_findlink(&ob->defbase, def_nr)) - return; - - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - int cd_dvert_offset; - - BMIter iter; - BMVert *eve; - - if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) - BM_data_layer_add(em->bm, &em->bm->vdata, CD_MDEFORMVERT); - - cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - /* Go through the list of editverts and assign them */ - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - MDeformVert *dv; - MDeformWeight *dw; - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); /* can be NULL */ - dw = defvert_verify_index(dv, def_nr); - if (dw) { - dw->weight = weight; - } - } - } - } - else { - MVert *mv; - MDeformVert *dv; - int i; - - if (!me->dvert) { - BKE_object_defgroup_data_create(&me->id); - } - - mv = me->mvert; - dv = me->dvert; - - for (i = 0; i < me->totvert; i++, mv++, dv++) { - if (mv->flag & SELECT) { - MDeformWeight *dw; - dw = defvert_verify_index(dv, def_nr); - if (dw) { - dw->weight = weight; - } - } - } - } - } - else if (ob->type == OB_LATTICE) { - Lattice *lt = vgroup_edit_lattice(ob); - MDeformVert *dv; - BPoint *bp; - int a, tot; - - if (lt->dvert == NULL) - BKE_object_defgroup_data_create(<->id); - - dv = lt->dvert; - - tot = lt->pntsu * lt->pntsv * lt->pntsw; - for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) { - if (bp->f1 & SELECT) { - MDeformWeight *dw; - - dw = defvert_verify_index(dv, def_nr); - if (dw) { - dw->weight = weight; - } - } - } - } + const int def_nr = ob->actdef - 1; + + if (!BLI_findlink(&ob->defbase, def_nr)) + return; + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + int cd_dvert_offset; + + BMIter iter; + BMVert *eve; + + if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) + BM_data_layer_add(em->bm, &em->bm->vdata, CD_MDEFORMVERT); + + cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + /* Go through the list of editverts and assign them */ + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + MDeformVert *dv; + MDeformWeight *dw; + dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); /* can be NULL */ + dw = defvert_verify_index(dv, def_nr); + if (dw) { + dw->weight = weight; + } + } + } + } + else { + MVert *mv; + MDeformVert *dv; + int i; + + if (!me->dvert) { + BKE_object_defgroup_data_create(&me->id); + } + + mv = me->mvert; + dv = me->dvert; + + for (i = 0; i < me->totvert; i++, mv++, dv++) { + if (mv->flag & SELECT) { + MDeformWeight *dw; + dw = defvert_verify_index(dv, def_nr); + if (dw) { + dw->weight = weight; + } + } + } + } + } + else if (ob->type == OB_LATTICE) { + Lattice *lt = vgroup_edit_lattice(ob); + MDeformVert *dv; + BPoint *bp; + int a, tot; + + if (lt->dvert == NULL) + BKE_object_defgroup_data_create(<->id); + + dv = lt->dvert; + + tot = lt->pntsu * lt->pntsv * lt->pntsw; + for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) { + if (bp->f1 & SELECT) { + MDeformWeight *dw; + + dw = defvert_verify_index(dv, def_nr); + if (dw) { + dw->weight = weight; + } + } + } + } } /********************** vertex group operators *********************/ static bool vertex_group_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && - data && !ID_IS_LINKED(data) && - OB_TYPE_SUPPORT_VGROUP(ob->type) && - ob->defbase.first); + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && + OB_TYPE_SUPPORT_VGROUP(ob->type) && ob->defbase.first); } static bool vertex_group_supported_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) && - data && !ID_IS_LINKED(data)); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && + !ID_IS_LINKED(data)); } static bool vertex_group_mesh_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && - data && !ID_IS_LINKED(data) && - ob->type == OB_MESH && - ob->defbase.first); + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data) && ob->type == OB_MESH && + ob->defbase.first); } static bool UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + return (ob && !ID_IS_LINKED(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED(data)); } - -static bool UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C) +static bool UNUSED_FUNCTION(vertex_group_poll_edit)(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) - return 0; + if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) + return 0; - return BKE_object_is_in_editmode_vgroup(ob); + return BKE_object_is_in_editmode_vgroup(ob); } /* editmode _or_ weight paint vertex sel */ -static bool vertex_group_vert_poll_ex(bContext *C, const bool needs_select, const short ob_type_flag) -{ - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) - return false; - - if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) { - return false; - } - - if (BKE_object_is_in_editmode_vgroup(ob)) { - return true; - } - else if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (needs_select) { - if (BKE_object_is_in_wpaint_select_vert(ob)) { - return true; - } - else { - CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); - return false; - } - } - else { - return true; - } - } - else { - return false; - } +static bool vertex_group_vert_poll_ex(bContext *C, + const bool needs_select, + const short ob_type_flag) +{ + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + + if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) + return false; + + if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) { + return false; + } + + if (BKE_object_is_in_editmode_vgroup(ob)) { + return true; + } + else if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (needs_select) { + if (BKE_object_is_in_wpaint_select_vert(ob)) { + return true; + } + else { + CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode"); + return false; + } + } + else { + return true; + } + } + else { + return false; + } } #if 0 static bool vertex_group_vert_poll(bContext *C) { - return vertex_group_vert_poll_ex(C, false, 0); + return vertex_group_vert_poll_ex(C, false, 0); } #endif - static bool vertex_group_mesh_vert_poll(bContext *C) { - return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH)); + return vertex_group_vert_poll_ex(C, false, (1 << OB_MESH)); } static bool vertex_group_vert_select_poll(bContext *C) { - return vertex_group_vert_poll_ex(C, true, 0); + return vertex_group_vert_poll_ex(C, true, 0); } #if 0 static bool vertex_group_mesh_vert_select_poll(bContext *C) { - return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH)); + return vertex_group_vert_poll_ex(C, true, (1 << OB_MESH)); } #endif - /* editmode _or_ weight paint vertex sel and active group unlocked */ static bool vertex_group_vert_select_unlocked_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) - return 0; - - if (!(BKE_object_is_in_editmode_vgroup(ob) || - BKE_object_is_in_wpaint_select_vert(ob))) - { - return 0; - } - - if (ob->actdef != 0) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); - if (dg) { - return !(dg->flag & DG_LOCK_WEIGHT); - } - } - return 1; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; + + if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) + return 0; + + if (!(BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob))) { + return 0; + } + + if (ob->actdef != 0) { + bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); + if (dg) { + return !(dg->flag & DG_LOCK_WEIGHT); + } + } + return 1; } static bool vertex_group_vert_select_mesh_poll(bContext *C) { - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; + Object *ob = ED_object_context(C); + ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) - return 0; + if (!(ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data))) + return 0; - /* only difference to #vertex_group_vert_select_poll */ - if (ob->type != OB_MESH) - return 0; + /* only difference to #vertex_group_vert_select_poll */ + if (ob->type != OB_MESH) + return 0; - return (BKE_object_is_in_editmode_vgroup(ob) || - BKE_object_is_in_wpaint_select_vert(ob)); + return (BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob)); } static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - BKE_object_defgroup_add(ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + BKE_object_defgroup_add(ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_add"; - ot->description = "Add a new vertex group to the active object"; + /* identifiers */ + ot->name = "Add Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_add"; + ot->description = "Add a new vertex group to the active object"; - /* api callbacks */ - ot->poll = vertex_group_supported_poll; - ot->exec = vertex_group_add_exec; + /* api callbacks */ + ot->poll = vertex_group_supported_poll; + ot->exec = vertex_group_add_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_remove_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - if (RNA_boolean_get(op->ptr, "all")) - BKE_object_defgroup_remove_all(ob); - else if (RNA_boolean_get(op->ptr, "all_unlocked")) - BKE_object_defgroup_remove_all_ex(ob, true); - else - vgroup_delete_active(ob); + if (RNA_boolean_get(op->ptr, "all")) + BKE_object_defgroup_remove_all(ob); + else if (RNA_boolean_get(op->ptr, "all_unlocked")) + BKE_object_defgroup_remove_all_ex(ob, true); + else + vgroup_delete_active(ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_remove"; - ot->description = "Delete the active or all vertex groups from the active object"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_remove_exec; - - /* flags */ - /* redo operator will fail in this case because vertex groups aren't stored - * in local edit mode stack and toggling "all" property will lead to - * all groups deleted without way to restore them (see [#29527], sergey) */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* identifiers */ + ot->name = "Remove Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_remove"; + ot->description = "Delete the active or all vertex groups from the active object"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_remove_exec; + + /* flags */ + /* redo operator will fail in this case because vertex groups aren't stored + * in local edit mode stack and toggling "all" property will lead to + * all groups deleted without way to restore them (see [#29527], sergey) */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - Object *ob = ED_object_context(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = ED_object_context(C); - vgroup_assign_verts(ob, ts->vgroup_weight); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + vgroup_assign_verts(ob, ts->vgroup_weight); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_assign(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Assign to Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_assign"; - ot->description = "Assign the selected vertices to the active vertex group"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_unlocked_poll; - ot->exec = vertex_group_assign_exec; - - /* flags */ - /* redo operator will fail in this case because vertex group assignment - * isn't stored in local edit mode stack and toggling "new" property will - * lead to creating plenty of new vertex groups (see [#29527], sergey) */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + /* identifiers */ + ot->name = "Assign to Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_assign"; + ot->description = "Assign the selected vertices to the active vertex group"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_unlocked_poll; + ot->exec = vertex_group_assign_exec; + + /* flags */ + /* redo operator will fail in this case because vertex group assignment + * isn't stored in local edit mode stack and toggling "new" property will + * lead to creating plenty of new vertex groups (see [#29527], sergey) */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; } /* NOTE: just a wrapper around vertex_group_assign_exec(), except we add these to a new group */ static int vertex_group_assign_new_exec(bContext *C, wmOperator *op) { - /* create new group... */ - Object *ob = ED_object_context(C); - BKE_object_defgroup_add(ob); + /* create new group... */ + Object *ob = ED_object_context(C); + BKE_object_defgroup_add(ob); - /* assign selection to new group */ - return vertex_group_assign_exec(C, op); + /* assign selection to new group */ + return vertex_group_assign_exec(C, op); } void OBJECT_OT_vertex_group_assign_new(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Assign to New Group"; - ot->idname = "OBJECT_OT_vertex_group_assign_new"; - ot->description = "Assign the selected vertices to a new vertex group"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_poll; - ot->exec = vertex_group_assign_new_exec; - - /* flags */ - /* redo operator will fail in this case because vertex group assignment - * isn't stored in local edit mode stack and toggling "new" property will - * lead to creating plenty of new vertex groups (see [#29527], sergey) */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + /* identifiers */ + ot->name = "Assign to New Group"; + ot->idname = "OBJECT_OT_vertex_group_assign_new"; + ot->description = "Assign the selected vertices to a new vertex group"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_poll; + ot->exec = vertex_group_assign_new_exec; + + /* flags */ + /* redo operator will fail in this case because vertex group assignment + * isn't stored in local edit mode stack and toggling "new" property will + * lead to creating plenty of new vertex groups (see [#29527], sergey) */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; } static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) { - const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups"); - const bool use_all_verts = RNA_boolean_get(op->ptr, "use_all_verts"); + const bool use_all_groups = RNA_boolean_get(op->ptr, "use_all_groups"); + const bool use_all_verts = RNA_boolean_get(op->ptr, "use_all_verts"); - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - if (use_all_groups) { - if (BKE_object_defgroup_clear_all(ob, true) == false) { - return OPERATOR_CANCELLED; - } - } - else { - bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); + if (use_all_groups) { + if (BKE_object_defgroup_clear_all(ob, true) == false) { + return OPERATOR_CANCELLED; + } + } + else { + bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); - if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { - return OPERATOR_CANCELLED; - } - } + if ((dg == NULL) || (BKE_object_defgroup_clear(ob, dg, !use_all_verts) == false)) { + return OPERATOR_CANCELLED; + } + } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "Remove from Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_remove_from"; - ot->description = "Remove the selected vertices from active or all vertex group(s)"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_unlocked_poll; - ot->exec = vertex_group_remove_from_exec; - - /* flags */ - /* redo operator will fail in this case because vertex groups assignment - * isn't stored in local edit mode stack and toggling "all" property will lead to - * removing vertices from all groups (see [#29527], sergey) */ - ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_boolean(ot->srna, "use_all_groups", 0, "All Groups", "Remove from all groups"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "use_all_verts", 0, "All Verts", "Clear the active group"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + /* identifiers */ + ot->name = "Remove from Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_remove_from"; + ot->description = "Remove the selected vertices from active or all vertex group(s)"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_unlocked_poll; + ot->exec = vertex_group_remove_from_exec; + + /* flags */ + /* redo operator will fail in this case because vertex groups assignment + * isn't stored in local edit mode stack and toggling "all" property will lead to + * removing vertices from all groups (see [#29527], sergey) */ + ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "use_all_groups", 0, "All Groups", "Remove from all groups"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_all_verts", 0, "All Verts", "Clear the active group"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - if (!ob || ID_IS_LINKED(ob)) - return OPERATOR_CANCELLED; + if (!ob || ID_IS_LINKED(ob)) + return OPERATOR_CANCELLED; - vgroup_select_verts(ob, 1); - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); + vgroup_select_verts(ob, 1); + DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_select"; - ot->description = "Select all the vertices assigned to the active vertex group"; + /* identifiers */ + ot->name = "Select Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_select"; + ot->description = "Select all the vertices assigned to the active vertex group"; - /* api callbacks */ - ot->poll = vertex_group_vert_select_poll; - ot->exec = vertex_group_select_exec; + /* api callbacks */ + ot->poll = vertex_group_vert_select_poll; + ot->exec = vertex_group_select_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - vgroup_select_verts(ob, 0); - DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); + vgroup_select_verts(ob, 0); + DEG_id_tag_update(ob->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Deselect Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_deselect"; - ot->description = "Deselect all selected vertices assigned to the active vertex group"; + /* identifiers */ + ot->name = "Deselect Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_deselect"; + ot->description = "Deselect all selected vertices assigned to the active vertex group"; - /* api callbacks */ - ot->poll = vertex_group_vert_select_poll; - ot->exec = vertex_group_deselect_exec; + /* api callbacks */ + ot->poll = vertex_group_vert_select_poll; + ot->exec = vertex_group_deselect_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - vgroup_duplicate(ob); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); + vgroup_duplicate(ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_copy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_copy"; - ot->description = "Make a copy of the active vertex group"; + /* identifiers */ + ot->name = "Copy Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_copy"; + ot->description = "Make a copy of the active vertex group"; - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_copy_exec; + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_copy_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_levels_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - float offset = RNA_float_get(op->ptr, "offset"); - float gain = RNA_float_get(op->ptr, "gain"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + float offset = RNA_float_get(op->ptr, "offset"); + float gain = RNA_float_get(op->ptr, "gain"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - int subset_count, vgroup_tot; + int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain); - MEM_freeN((void *)vgroup_validmap); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain); + MEM_freeN((void *)vgroup_validmap); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_levels(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Vertex Group Levels"; - ot->idname = "OBJECT_OT_vertex_group_levels"; - ot->description = "Add some offset and multiply with some gain the weights of the active vertex group"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_levels_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, true); - RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f); - RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f); + /* identifiers */ + ot->name = "Vertex Group Levels"; + ot->idname = "OBJECT_OT_vertex_group_levels"; + ot->description = + "Add some offset and multiply with some gain the weights of the active vertex group"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_levels_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, true); + RNA_def_float( + ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f); + RNA_def_float( + ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f); } static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - bool changed; + Object *ob = ED_object_context(C); + bool changed; - changed = vgroup_normalize(ob); + changed = vgroup_normalize(ob); - if (changed) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + if (changed) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Normalize Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_normalize"; - ot->description = "Normalize weights of the active vertex group, so that the highest ones are now 1.0"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_normalize_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Normalize Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_normalize"; + ot->description = + "Normalize weights of the active vertex group, so that the highest ones are now 1.0"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_normalize_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - bool lock_active = RNA_boolean_get(op->ptr, "lock_active"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - bool changed; - int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - - changed = vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports); - MEM_freeN((void *)vgroup_validmap); - - if (changed) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; - } - else { - /* allow to adjust settings */ - return OPERATOR_FINISHED; - } + Object *ob = ED_object_context(C); + bool lock_active = RNA_boolean_get(op->ptr, "lock_active"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + bool changed; + int subset_count, vgroup_tot; + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + + changed = vgroup_normalize_all( + ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports); + MEM_freeN((void *)vgroup_validmap); + + if (changed) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; + } + else { + /* allow to adjust settings */ + return OPERATOR_FINISHED; + } } void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Normalize All Vertex Groups"; - ot->idname = "OBJECT_OT_vertex_group_normalize_all"; - ot->description = "Normalize all weights of all vertex groups, " - "so that for each vertex, the sum of all weights is 1.0"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_normalize_all_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, false); - RNA_def_boolean(ot->srna, "lock_active", true, "Lock Active", - "Keep the values of the active group while normalizing others"); + /* identifiers */ + ot->name = "Normalize All Vertex Groups"; + ot->idname = "OBJECT_OT_vertex_group_normalize_all"; + ot->description = + "Normalize all weights of all vertex groups, " + "so that for each vertex, the sum of all weights is 1.0"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_normalize_all_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, false); + RNA_def_boolean(ot->srna, + "lock_active", + true, + "Lock Active", + "Keep the values of the active group while normalizing others"); } static int vertex_group_fix_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - Scene *scene = CTX_data_scene(C); - - float distToBe = RNA_float_get(op->ptr, "dist"); - float strength = RNA_float_get(op->ptr, "strength"); - float cp = RNA_float_get(op->ptr, "accuracy"); - ModifierData *md = ob->modifiers.first; - - while (md) { - if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { - break; - } - md = md->next; - } - - if (md && md->type == eModifierType_Mirror) { - BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier"); - return OPERATOR_CANCELLED; - } - vgroup_fix(C, scene, ob, distToBe, strength, cp); - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + + float distToBe = RNA_float_get(op->ptr, "dist"); + float strength = RNA_float_get(op->ptr, "strength"); + float cp = RNA_float_get(op->ptr, "accuracy"); + ModifierData *md = ob->modifiers.first; + + while (md) { + if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) { + break; + } + md = md->next; + } + + if (md && md->type == eModifierType_Mirror) { + BKE_report(op->reports, + RPT_ERROR_INVALID_CONTEXT, + "This operator does not support an active mirror modifier"); + return OPERATOR_CANCELLED; + } + vgroup_fix(C, scene, ob, distToBe, strength, cp); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_fix(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Fix Vertex Group Deform"; - ot->idname = "OBJECT_OT_vertex_group_fix"; - ot->description = "Modify the position of selected vertices by changing only their respective " - "groups' weights (this tool may be slow for many vertices)"; - - /* api callbacks */ - ot->poll = vertex_group_mesh_poll; - ot->exec = vertex_group_fix_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f); - RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength", - "The distance moved can be changed by this multiplier", -2.0f, 2.0f); - RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity", - "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f); + /* identifiers */ + ot->name = "Fix Vertex Group Deform"; + ot->idname = "OBJECT_OT_vertex_group_fix"; + ot->description = + "Modify the position of selected vertices by changing only their respective " + "groups' weights (this tool may be slow for many vertices)"; + + /* api callbacks */ + ot->poll = vertex_group_mesh_poll; + ot->exec = vertex_group_fix_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + RNA_def_float(ot->srna, + "dist", + 0.0f, + -FLT_MAX, + FLT_MAX, + "Distance", + "The distance to move to", + -10.0f, + 10.0f); + RNA_def_float(ot->srna, + "strength", + 1.f, + -2.0f, + FLT_MAX, + "Strength", + "The distance moved can be changed by this multiplier", + -2.0f, + 2.0f); + RNA_def_float( + ot->srna, + "accuracy", + 1.0f, + 0.05f, + FLT_MAX, + "Change Sensitivity", + "Change the amount weights are altered with each iteration: lower values are slower", + 0.05f, + 1.f); } - static int vertex_group_lock_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - int action = RNA_enum_get(op->ptr, "action"); + int action = RNA_enum_get(op->ptr, "action"); - vgroup_lock_all(ob, action); + vgroup_lock_all(ob, action); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Change the Lock On Vertex Groups"; - ot->idname = "OBJECT_OT_vertex_group_lock"; - ot->description = "Change the lock state of all vertex groups of active object"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_lock_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "action", vgroup_lock_actions, VGROUP_TOGGLE, "Action", - "Lock action to execute on vertex groups"); + /* identifiers */ + ot->name = "Change the Lock On Vertex Groups"; + ot->idname = "OBJECT_OT_vertex_group_lock"; + ot->description = "Change the lock state of all vertex groups of active object"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_lock_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, + "action", + vgroup_lock_actions, + VGROUP_TOGGLE, + "Action", + "Lock action to execute on vertex groups"); } static int vertex_group_invert_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign"); - bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove"); + Object *ob = ED_object_context(C); + bool auto_assign = RNA_boolean_get(op->ptr, "auto_assign"); + bool auto_remove = RNA_boolean_get(op->ptr, "auto_remove"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - int subset_count, vgroup_tot; + int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove); - MEM_freeN((void *)vgroup_validmap); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove); + MEM_freeN((void *)vgroup_validmap); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_invert(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Invert Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_invert"; - ot->description = "Invert active vertex group's weights"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_invert_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, true); - RNA_def_boolean(ot->srna, "auto_assign", true, "Add Weights", - "Add verts from groups that have zero weight before inverting"); - RNA_def_boolean(ot->srna, "auto_remove", true, "Remove Weights", - "Remove verts from groups that have zero weight after inverting"); + /* identifiers */ + ot->name = "Invert Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_invert"; + ot->description = "Invert active vertex group's weights"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_invert_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, true); + RNA_def_boolean(ot->srna, + "auto_assign", + true, + "Add Weights", + "Add verts from groups that have zero weight before inverting"); + RNA_def_boolean(ot->srna, + "auto_remove", + true, + "Remove Weights", + "Remove verts from groups that have zero weight after inverting"); } static int vertex_group_smooth_exec(bContext *C, wmOperator *op) { - const float fac = RNA_float_get(op->ptr, "factor"); - const int repeat = RNA_int_get(op->ptr, "repeat"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - const float fac_expand = RNA_float_get(op->ptr, "expand"); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob_ctx = ED_object_context(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, - ob_ctx->mode); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - - int subset_count, vgroup_tot; - - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, - subset_type, - &vgroup_tot, - &subset_count); - - vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand); - MEM_freeN((void *)vgroup_validmap); - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + const float fac = RNA_float_get(op->ptr, "factor"); + const int repeat = RNA_int_get(op->ptr, "repeat"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const float fac_expand = RNA_float_get(op->ptr, "expand"); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_ctx = ED_object_context(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len, ob_ctx->mode); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + int subset_count, vgroup_tot; + + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + + vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand); + MEM_freeN((void *)vgroup_validmap); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Smooth Vertex Weights"; - ot->idname = "OBJECT_OT_vertex_group_smooth"; - ot->description = "Smooth weights for selected vertices"; - - /* api callbacks */ - ot->poll = vertex_group_mesh_vert_poll; - ot->exec = vertex_group_smooth_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, true); - RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f); - RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); - - RNA_def_float(ot->srna, "expand", 0.0f, -1.0f, 1.0, "Expand/Contract", "Expand/contract weights", -1.0f, 1.0f); + /* identifiers */ + ot->name = "Smooth Vertex Weights"; + ot->idname = "OBJECT_OT_vertex_group_smooth"; + ot->description = "Smooth weights for selected vertices"; + + /* api callbacks */ + ot->poll = vertex_group_mesh_vert_poll; + ot->exec = vertex_group_smooth_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, true); + RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); + + RNA_def_float(ot->srna, + "expand", + 0.0f, + -1.0f, + 1.0, + "Expand/Contract", + "Expand/contract weights", + -1.0f, + 1.0f); } static int vertex_group_clean_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - float limit = RNA_float_get(op->ptr, "limit"); - bool keep_single = RNA_boolean_get(op->ptr, "keep_single"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + float limit = RNA_float_get(op->ptr, "limit"); + bool keep_single = RNA_boolean_get(op->ptr, "keep_single"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - int subset_count, vgroup_tot; + int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single); - MEM_freeN((void *)vgroup_validmap); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single); + MEM_freeN((void *)vgroup_validmap); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_clean(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clean Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_clean"; - ot->description = "Remove vertex group assignments which are not required"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_clean_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, true); - RNA_def_float(ot->srna, "limit", 0.0f, 0.0f, 1.0, "Limit", - "Remove vertices which weight is below or equal to this limit", 0.0f, 0.99f); - RNA_def_boolean(ot->srna, "keep_single", false, "Keep Single", - "Keep verts assigned to at least one group when cleaning"); + /* identifiers */ + ot->name = "Clean Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_clean"; + ot->description = "Remove vertex group assignments which are not required"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_clean_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, true); + RNA_def_float(ot->srna, + "limit", + 0.0f, + 0.0f, + 1.0, + "Limit", + "Remove vertices which weight is below or equal to this limit", + 0.0f, + 0.99f); + RNA_def_boolean(ot->srna, + "keep_single", + false, + "Keep Single", + "Keep verts assigned to at least one group when cleaning"); } static int vertex_group_quantize_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - const int steps = RNA_int_get(op->ptr, "steps"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const int steps = RNA_int_get(op->ptr, "steps"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - int subset_count, vgroup_tot; + int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps); - MEM_freeN((void *)vgroup_validmap); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps); + MEM_freeN((void *)vgroup_validmap); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_quantize(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Quantize Vertex Weights"; - ot->idname = "OBJECT_OT_vertex_group_quantize"; - ot->description = "Set weights to a fixed number of steps"; + /* identifiers */ + ot->name = "Quantize Vertex Weights"; + ot->idname = "OBJECT_OT_vertex_group_quantize"; + ot->description = "Set weights to a fixed number of steps"; - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_quantize_exec; + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_quantize_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - vgroup_operator_subset_select_props(ot, true); - RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100); + vgroup_operator_subset_select_props(ot, true); + RNA_def_int(ot->srna, "steps", 4, 1, 1000, "Steps", "Number of steps between 0 and 1", 1, 100); } static int vertex_group_limit_total_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); + Object *ob = ED_object_context(C); - const int limit = RNA_int_get(op->ptr, "limit"); - eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + const int limit = RNA_int_get(op->ptr, "limit"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); - int subset_count, vgroup_tot; + int subset_count, vgroup_tot; - const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count); - int remove_tot = vgroup_limit_total_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit); - MEM_freeN((void *)vgroup_validmap); + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, subset_type, &vgroup_tot, &subset_count); + int remove_tot = vgroup_limit_total_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit); + MEM_freeN((void *)vgroup_validmap); - BKE_reportf(op->reports, remove_tot ? RPT_INFO : RPT_WARNING, "%d vertex weights limited", remove_tot); + BKE_reportf( + op->reports, remove_tot ? RPT_INFO : RPT_WARNING, "%d vertex weights limited", remove_tot); - if (remove_tot) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + if (remove_tot) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; - } - else { - /* note, would normally return canceled, except we want the redo - * UI to show up for users to change */ - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; + } + else { + /* note, would normally return canceled, except we want the redo + * UI to show up for users to change */ + return OPERATOR_FINISHED; + } } void OBJECT_OT_vertex_group_limit_total(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Limit Number of Weights per Vertex"; - ot->idname = "OBJECT_OT_vertex_group_limit_total"; - ot->description = "Limit deform weights associated with a vertex to a specified number by removing lowest weights"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_limit_total_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - vgroup_operator_subset_select_props(ot, false); - RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32); + /* identifiers */ + ot->name = "Limit Number of Weights per Vertex"; + ot->idname = "OBJECT_OT_vertex_group_limit_total"; + ot->description = + "Limit deform weights associated with a vertex to a specified number by removing lowest " + "weights"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_limit_total_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + vgroup_operator_subset_select_props(ot, false); + RNA_def_int(ot->srna, "limit", 4, 1, 32, "Limit", "Maximum number of deform weights", 1, 32); } static int vertex_group_mirror_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - int totmirr = 0, totfail = 0; + Object *ob = ED_object_context(C); + int totmirr = 0, totfail = 0; - ED_vgroup_mirror( - ob, - RNA_boolean_get(op->ptr, "mirror_weights"), - RNA_boolean_get(op->ptr, "flip_group_names"), - RNA_boolean_get(op->ptr, "all_groups"), - RNA_boolean_get(op->ptr, "use_topology"), - &totmirr, &totfail); + ED_vgroup_mirror(ob, + RNA_boolean_get(op->ptr, "mirror_weights"), + RNA_boolean_get(op->ptr, "flip_group_names"), + RNA_boolean_get(op->ptr, "all_groups"), + RNA_boolean_get(op->ptr, "use_topology"), + &totmirr, + &totfail); - ED_mesh_report_mirror(op, totmirr, totfail); + ED_mesh_report_mirror(op, totmirr, totfail); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mirror Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_mirror"; - ot->description = "Mirror vertex group, flip weights and/or names, editing only selected vertices, " - "flipping when both sides are selected otherwise copy from unselected"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_mirror_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "mirror_weights", true, "Mirror Weights", "Mirror weights"); - RNA_def_boolean(ot->srna, "flip_group_names", true, "Flip Group Names", "Flip vertex group names"); - RNA_def_boolean(ot->srna, "all_groups", false, "All Groups", "Mirror all vertex groups weights"); - RNA_def_boolean(ot->srna, "use_topology", 0, "Topology Mirror", - "Use topology based mirroring (for when both sides of mesh have matching, unique topology)"); + /* identifiers */ + ot->name = "Mirror Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_mirror"; + ot->description = + "Mirror vertex group, flip weights and/or names, editing only selected vertices, " + "flipping when both sides are selected otherwise copy from unselected"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_mirror_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "mirror_weights", true, "Mirror Weights", "Mirror weights"); + RNA_def_boolean( + ot->srna, "flip_group_names", true, "Flip Group Names", "Flip vertex group names"); + RNA_def_boolean(ot->srna, "all_groups", false, "All Groups", "Mirror all vertex groups weights"); + RNA_def_boolean( + ot->srna, + "use_topology", + 0, + "Topology Mirror", + "Use topology based mirroring (for when both sides of mesh have matching, unique topology)"); } static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - Object *ob_active = ED_object_context(C); - int retval = OPERATOR_CANCELLED; - - FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) - { - if (ob_iter->type == ob_active->type) { - if (ob_iter != ob_active && ob_iter->data == ob_active->data) { - BLI_freelistN(&ob_iter->defbase); - BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase); - ob_iter->actdef = ob_active->actdef; - - DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data); - - retval = OPERATOR_FINISHED; - } - } - } - FOREACH_SCENE_OBJECT_END; - - return retval; + Scene *scene = CTX_data_scene(C); + Object *ob_active = ED_object_context(C); + int retval = OPERATOR_CANCELLED; + + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) { + if (ob_iter->type == ob_active->type) { + if (ob_iter != ob_active && ob_iter->data == ob_active->data) { + BLI_freelistN(&ob_iter->defbase); + BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase); + ob_iter->actdef = ob_active->actdef; + + DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data); + + retval = OPERATOR_FINISHED; + } + } + } + FOREACH_SCENE_OBJECT_END; + + return retval; } void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Vertex Groups to Linked"; - ot->idname = "OBJECT_OT_vertex_group_copy_to_linked"; - ot->description = "Replace vertex groups of all users of the same geometry data by vertex groups of active object"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_copy_to_linked_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Copy Vertex Groups to Linked"; + ot->idname = "OBJECT_OT_vertex_group_copy_to_linked"; + ot->description = + "Replace vertex groups of all users of the same geometry data by vertex groups of active " + "object"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_copy_to_linked_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) { - Object *obact = ED_object_context(C); - int changed_tot = 0; - int fail = 0; - - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) - { - if (obact != ob) { - if (ED_vgroup_array_copy(ob, obact)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); - changed_tot++; - } - else { - fail++; - } - } - } - CTX_DATA_END; - - if ((changed_tot == 0 && fail == 0) || fail) { - BKE_reportf(op->reports, RPT_ERROR, - "Copy vertex groups to selected: %d done, %d failed (object data must have matching indices)", - changed_tot, fail); - } - - return OPERATOR_FINISHED; + Object *obact = ED_object_context(C); + int changed_tot = 0; + int fail = 0; + + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + if (obact != ob) { + if (ED_vgroup_array_copy(ob, obact)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); + changed_tot++; + } + else { + fail++; + } + } + } + CTX_DATA_END; + + if ((changed_tot == 0 && fail == 0) || fail) { + BKE_reportf(op->reports, + RPT_ERROR, + "Copy vertex groups to selected: %d done, %d failed (object data must have " + "matching indices)", + changed_tot, + fail); + } + + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Vertex Group to Selected"; - ot->idname = "OBJECT_OT_vertex_group_copy_to_selected"; - ot->description = "Replace vertex groups of selected objects by vertex groups of active object"; + /* identifiers */ + ot->name = "Copy Vertex Group to Selected"; + ot->idname = "OBJECT_OT_vertex_group_copy_to_selected"; + ot->description = "Replace vertex groups of selected objects by vertex groups of active object"; - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_copy_to_selected_exec; + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_copy_to_selected_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int set_active_group_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - int nr = RNA_enum_get(op->ptr, "group"); + Object *ob = ED_object_context(C); + int nr = RNA_enum_get(op->ptr, "group"); - BLI_assert(nr + 1 >= 0); - ob->actdef = nr + 1; + BLI_assert(nr + 1 >= 0); + ob->actdef = nr + 1; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static const EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *vgroup_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Object *ob = ED_object_context(C); - EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; - bDeformGroup *def; - int a, totitem = 0; - - if (!ob) - return DummyRNA_NULL_items; - - for (a = 0, def = ob->defbase.first; def; def = def->next, a++) { - tmp.value = a; - tmp.icon = ICON_GROUP_VERTEX; - tmp.identifier = def->name; - tmp.name = def->name; - RNA_enum_item_add(&item, &totitem, &tmp); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Object *ob = ED_object_context(C); + EnumPropertyItem tmp = {0, "", 0, "", ""}; + EnumPropertyItem *item = NULL; + bDeformGroup *def; + int a, totitem = 0; + + if (!ob) + return DummyRNA_NULL_items; + + for (a = 0, def = ob->defbase.first; def; def = def->next, a++) { + tmp.value = a; + tmp.icon = ICON_GROUP_VERTEX; + tmp.identifier = def->name; + tmp.name = def->name; + RNA_enum_item_add(&item, &totitem, &tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Set Active Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_set_active"; - ot->description = "Set the active vertex group"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = set_active_group_exec; - ot->invoke = WM_menu_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "Vertex group to set as active"); - RNA_def_enum_funcs(prop, vgroup_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Set Active Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_set_active"; + ot->description = "Set the active vertex group"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = set_active_group_exec; + ot->invoke = WM_menu_invoke; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum( + ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "Vertex group to set as active"); + RNA_def_enum_funcs(prop, vgroup_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } /* creates the name_array parameter for vgroup_do_remap, call this before fiddling * with the order of vgroups then call vgroup_do_remap after */ static char *vgroup_init_remap(Object *ob) { - bDeformGroup *def; - int defbase_tot = BLI_listbase_count(&ob->defbase); - char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"); - char *name; - - name = name_array; - for (def = ob->defbase.first; def; def = def->next) { - BLI_strncpy(name, def->name, MAX_VGROUP_NAME); - name += MAX_VGROUP_NAME; - } - - return name_array; + bDeformGroup *def; + int defbase_tot = BLI_listbase_count(&ob->defbase); + char *name_array = MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"); + char *name; + + name = name_array; + for (def = ob->defbase.first; def; def = def->next) { + BLI_strncpy(name, def->name, MAX_VGROUP_NAME); + name += MAX_VGROUP_NAME; + } + + return name_array; } static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) { - MDeformVert *dvert = NULL; - bDeformGroup *def; - int defbase_tot = BLI_listbase_count(&ob->defbase); - - /* needs a dummy index at the start*/ - int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); - int *sort_map = sort_map_update + 1; - - const char *name; - int i; - - name = name_array; - for (def = ob->defbase.first, i = 0; def; def = def->next, i++) { - sort_map[i] = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); - name += MAX_VGROUP_NAME; - - BLI_assert(sort_map[i] != -1); - } - - if (ob->mode == OB_MODE_EDIT) { - if (ob->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(ob); - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - - if (cd_dvert_offset != -1) { - BMIter iter; - BMVert *eve; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - if (dvert->totweight) { - defvert_remap(dvert, sort_map, defbase_tot); - } - } - } - } - else { - BKE_report(op->reports, RPT_ERROR, "Editmode lattice is not supported yet"); - MEM_freeN(sort_map_update); - return OPERATOR_CANCELLED; - } - } - else { - int dvert_tot = 0; - - BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot); - - /*create as necessary*/ - if (dvert) { - while (dvert_tot--) { - if (dvert->totweight) - defvert_remap(dvert, sort_map, defbase_tot); - dvert++; - } - } - } - - /* update users */ - for (i = 0; i < defbase_tot; i++) - sort_map[i]++; - - sort_map_update[0] = 0; - BKE_object_defgroup_remap_update_users(ob, sort_map_update); - - BLI_assert(sort_map_update[ob->actdef] >= 0); - ob->actdef = sort_map_update[ob->actdef]; - - MEM_freeN(sort_map_update); - - return OPERATOR_FINISHED; + MDeformVert *dvert = NULL; + bDeformGroup *def; + int defbase_tot = BLI_listbase_count(&ob->defbase); + + /* needs a dummy index at the start*/ + int *sort_map_update = MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); + int *sort_map = sort_map_update + 1; + + const char *name; + int i; + + name = name_array; + for (def = ob->defbase.first, i = 0; def; def = def->next, i++) { + sort_map[i] = BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); + name += MAX_VGROUP_NAME; + + BLI_assert(sort_map[i] != -1); + } + + if (ob->mode == OB_MODE_EDIT) { + if (ob->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(ob); + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset != -1) { + BMIter iter; + BMVert *eve; + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + if (dvert->totweight) { + defvert_remap(dvert, sort_map, defbase_tot); + } + } + } + } + else { + BKE_report(op->reports, RPT_ERROR, "Editmode lattice is not supported yet"); + MEM_freeN(sort_map_update); + return OPERATOR_CANCELLED; + } + } + else { + int dvert_tot = 0; + + BKE_object_defgroup_array_get(ob->data, &dvert, &dvert_tot); + + /*create as necessary*/ + if (dvert) { + while (dvert_tot--) { + if (dvert->totweight) + defvert_remap(dvert, sort_map, defbase_tot); + dvert++; + } + } + } + + /* update users */ + for (i = 0; i < defbase_tot; i++) + sort_map[i]++; + + sort_map_update[0] = 0; + BKE_object_defgroup_remap_update_users(ob, sort_map_update); + + BLI_assert(sort_map_update[ob->actdef] >= 0); + ob->actdef = sort_map_update[ob->actdef]; + + MEM_freeN(sort_map_update); + + return OPERATOR_FINISHED; } static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) { - const bDeformGroup *def_a = def_a_ptr; - const bDeformGroup *def_b = def_b_ptr; + const bDeformGroup *def_a = def_a_ptr; + const bDeformGroup *def_b = def_b_ptr; - return BLI_natstrcmp(def_a->name, def_b->name); + return BLI_natstrcmp(def_a->name, def_b->name); } /** @@ -3599,395 +3719,423 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) */ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { - if (bonebase == NULL) { - Object *armobj = modifiers_isDeformedByArmature(ob); - if (armobj != NULL) { - bArmature *armature = armobj->data; - bonebase = &armature->bonebase; - } - } - - if (bonebase != NULL) { - Bone *bone; - for (bone = bonebase->last; bone; bone = bone->prev) { - bDeformGroup *dg = defgroup_find_name(ob, bone->name); - vgroup_sort_bone_hierarchy(ob, &bone->childbase); - - if (dg != NULL) { - BLI_remlink(&ob->defbase, dg); - BLI_addhead(&ob->defbase, dg); - } - } - } - - return; + if (bonebase == NULL) { + Object *armobj = modifiers_isDeformedByArmature(ob); + if (armobj != NULL) { + bArmature *armature = armobj->data; + bonebase = &armature->bonebase; + } + } + + if (bonebase != NULL) { + Bone *bone; + for (bone = bonebase->last; bone; bone = bone->prev) { + bDeformGroup *dg = defgroup_find_name(ob, bone->name); + vgroup_sort_bone_hierarchy(ob, &bone->childbase); + + if (dg != NULL) { + BLI_remlink(&ob->defbase, dg); + BLI_addhead(&ob->defbase, dg); + } + } + } + + return; } enum { - SORT_TYPE_NAME = 0, - SORT_TYPE_BONEHIERARCHY = 1, + SORT_TYPE_NAME = 0, + SORT_TYPE_BONEHIERARCHY = 1, }; static int vertex_group_sort_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - char *name_array; - int ret; - int sort_type = RNA_enum_get(op->ptr, "sort_type"); - - /*init remapping*/ - name_array = vgroup_init_remap(ob); - - /*sort vgroup names*/ - switch (sort_type) { - case SORT_TYPE_NAME: - BLI_listbase_sort(&ob->defbase, vgroup_sort_name); - break; - case SORT_TYPE_BONEHIERARCHY: - vgroup_sort_bone_hierarchy(ob, NULL); - break; - } - - /*remap vgroup data to map to correct names*/ - ret = vgroup_do_remap(ob, name_array, op); - - if (ret != OPERATOR_CANCELLED) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); - } - - if (name_array) MEM_freeN(name_array); - - return ret; + Object *ob = ED_object_context(C); + char *name_array; + int ret; + int sort_type = RNA_enum_get(op->ptr, "sort_type"); + + /*init remapping*/ + name_array = vgroup_init_remap(ob); + + /*sort vgroup names*/ + switch (sort_type) { + case SORT_TYPE_NAME: + BLI_listbase_sort(&ob->defbase, vgroup_sort_name); + break; + case SORT_TYPE_BONEHIERARCHY: + vgroup_sort_bone_hierarchy(ob, NULL); + break; + } + + /*remap vgroup data to map to correct names*/ + ret = vgroup_do_remap(ob, name_array, op); + + if (ret != OPERATOR_CANCELLED) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); + } + + if (name_array) + MEM_freeN(name_array); + + return ret; } void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) { - static const EnumPropertyItem vgroup_sort_type[] = { - {SORT_TYPE_NAME, "NAME", 0, "Name", ""}, - {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem vgroup_sort_type[] = { + {SORT_TYPE_NAME, "NAME", 0, "Name", ""}, + {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""}, + {0, NULL, 0, NULL, NULL}, + }; - ot->name = "Sort Vertex Groups"; - ot->idname = "OBJECT_OT_vertex_group_sort"; - ot->description = "Sort vertex groups"; + ot->name = "Sort Vertex Groups"; + ot->idname = "OBJECT_OT_vertex_group_sort"; + ot->description = "Sort vertex groups"; - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vertex_group_sort_exec; + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vertex_group_sort_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort type", "Sort type"); + RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort type", "Sort type"); } static int vgroup_move_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - bDeformGroup *def; - char *name_array; - int dir = RNA_enum_get(op->ptr, "direction"); - int ret = OPERATOR_FINISHED; + Object *ob = ED_object_context(C); + bDeformGroup *def; + char *name_array; + int dir = RNA_enum_get(op->ptr, "direction"); + int ret = OPERATOR_FINISHED; - def = BLI_findlink(&ob->defbase, ob->actdef - 1); - if (!def) { - return OPERATOR_CANCELLED; - } + def = BLI_findlink(&ob->defbase, ob->actdef - 1); + if (!def) { + return OPERATOR_CANCELLED; + } - name_array = vgroup_init_remap(ob); + name_array = vgroup_init_remap(ob); - if (BLI_listbase_link_move(&ob->defbase, def, dir)) { - ret = vgroup_do_remap(ob, name_array, op); + if (BLI_listbase_link_move(&ob->defbase, def, dir)) { + ret = vgroup_do_remap(ob, name_array, op); - if (ret != OPERATOR_CANCELLED) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); - } - } + if (ret != OPERATOR_CANCELLED) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); + } + } - if (name_array) MEM_freeN(name_array); + if (name_array) + MEM_freeN(name_array); - return ret; + return ret; } void OBJECT_OT_vertex_group_move(wmOperatorType *ot) { - static const EnumPropertyItem vgroup_slot_move[] = { - {-1, "UP", 0, "Up", ""}, - {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Move Vertex Group"; - ot->idname = "OBJECT_OT_vertex_group_move"; - ot->description = "Move the active vertex group up/down in the list"; - - /* api callbacks */ - ot->poll = vertex_group_poll; - ot->exec = vgroup_move_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", - "Direction to move the active vertex group towards"); + static const EnumPropertyItem vgroup_slot_move[] = { + {-1, "UP", 0, "Up", ""}, + {1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Move Vertex Group"; + ot->idname = "OBJECT_OT_vertex_group_move"; + ot->description = "Move the active vertex group up/down in the list"; + + /* api callbacks */ + ot->poll = vertex_group_poll; + ot->exec = vgroup_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, + "direction", + vgroup_slot_move, + 0, + "Direction", + "Direction to move the active vertex group towards"); } static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) { - MDeformVert *dvert_act; - - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - float weight_act; - int i; - - if (em) { - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - BMIter iter; - BMVert *eve, *eve_act; - - dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); - if (dvert_act == NULL) { - return; - } - weight_act = defvert_find_weight(dvert_act, def_nr); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - MDeformWeight *dw = defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; - - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); - } - } - } - } - - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset); - } - } - else { - MDeformVert *dv; - int v_act; - - dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); - if (dvert_act == NULL) { - return; - } - weight_act = defvert_find_weight(dvert_act, def_nr); - - dv = me->dvert; - for (i = 0; i < me->totvert; i++, dv++) { - if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) { - MDeformWeight *dw = defvert_find_index(dv, def_nr); - if (dw) { - dw->weight = weight_act; - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_ob(ob, -1, i); - } - } - } - } - - if (me->editflag & ME_EDIT_MIRROR_X) { - ED_mesh_defvert_mirror_update_ob(ob, -1, v_act); - } - } + MDeformVert *dvert_act; + + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + float weight_act; + int i; + + if (em) { + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + BMIter iter; + BMVert *eve, *eve_act; + + dvert_act = ED_mesh_active_dvert_get_em(ob, &eve_act); + if (dvert_act == NULL) { + return; + } + weight_act = defvert_find_weight(dvert_act, def_nr); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) { + MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformWeight *dw = defvert_find_index(dv, def_nr); + if (dw) { + dw->weight = weight_act; + + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset); + } + } + } + } + + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_em(ob, eve_act, -1, -1, cd_dvert_offset); + } + } + else { + MDeformVert *dv; + int v_act; + + dvert_act = ED_mesh_active_dvert_get_ob(ob, &v_act); + if (dvert_act == NULL) { + return; + } + weight_act = defvert_find_weight(dvert_act, def_nr); + + dv = me->dvert; + for (i = 0; i < me->totvert; i++, dv++) { + if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) { + MDeformWeight *dw = defvert_find_index(dv, def_nr); + if (dw) { + dw->weight = weight_act; + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_ob(ob, -1, i); + } + } + } + } + + if (me->editflag & ME_EDIT_MIRROR_X) { + ED_mesh_defvert_mirror_update_ob(ob, -1, v_act); + } + } } static bool check_vertex_group_accessible(wmOperator *op, Object *ob, int def_nr) { - bDeformGroup *dg = BLI_findlink(&ob->defbase, def_nr); + bDeformGroup *dg = BLI_findlink(&ob->defbase, def_nr); - if (!dg) { - BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index"); - return false; - } + if (!dg) { + BKE_report(op->reports, RPT_ERROR, "Invalid vertex group index"); + return false; + } - if (dg->flag & DG_LOCK_WEIGHT) { - BKE_report(op->reports, RPT_ERROR, "Vertex group is locked"); - return false; - } + if (dg->flag & DG_LOCK_WEIGHT) { + BKE_report(op->reports, RPT_ERROR, "Vertex group is locked"); + return false; + } - return true; + return true; } static int vertex_weight_paste_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - const int def_nr = RNA_int_get(op->ptr, "weight_group"); + Object *ob = ED_object_context(C); + const int def_nr = RNA_int_get(op->ptr, "weight_group"); - if (!check_vertex_group_accessible(op, ob, def_nr)) { - return OPERATOR_CANCELLED; - } + if (!check_vertex_group_accessible(op, ob, def_nr)) { + return OPERATOR_CANCELLED; + } - vgroup_copy_active_to_sel_single(ob, def_nr); + vgroup_copy_active_to_sel_single(ob, def_nr); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_weight_paste(wmOperatorType *ot) { - PropertyRNA *prop; - - ot->name = "Paste Weight to Selected"; - ot->idname = "OBJECT_OT_vertex_weight_paste"; - ot->description = "Copy this group's weight to other selected verts (disabled if vertex group is locked)"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_mesh_poll; - ot->exec = vertex_weight_paste_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_int(ot->srna, "weight_group", -1, -1, INT_MAX, "Weight Index", - "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + PropertyRNA *prop; + + ot->name = "Paste Weight to Selected"; + ot->idname = "OBJECT_OT_vertex_weight_paste"; + ot->description = + "Copy this group's weight to other selected verts (disabled if vertex group is locked)"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_mesh_poll; + ot->exec = vertex_weight_paste_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, + "weight_group", + -1, + -1, + INT_MAX, + "Weight Index", + "Index of source weight in active vertex group", + -1, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int vertex_weight_delete_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - const int def_nr = RNA_int_get(op->ptr, "weight_group"); + Object *ob = ED_object_context(C); + const int def_nr = RNA_int_get(op->ptr, "weight_group"); - if (!check_vertex_group_accessible(op, ob, def_nr)) { - return OPERATOR_CANCELLED; - } + if (!check_vertex_group_accessible(op, ob, def_nr)) { + return OPERATOR_CANCELLED; + } - vgroup_remove_weight(ob, def_nr); + vgroup_remove_weight(ob, def_nr); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_weight_delete(wmOperatorType *ot) { - PropertyRNA *prop; - - ot->name = "Delete Weight"; - ot->idname = "OBJECT_OT_vertex_weight_delete"; - ot->description = "Delete this weight from the vertex (disabled if vertex group is locked)"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_mesh_poll; - ot->exec = vertex_weight_delete_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_int(ot->srna, "weight_group", -1, -1, INT_MAX, "Weight Index", - "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + PropertyRNA *prop; + + ot->name = "Delete Weight"; + ot->idname = "OBJECT_OT_vertex_weight_delete"; + ot->description = "Delete this weight from the vertex (disabled if vertex group is locked)"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_mesh_poll; + ot->exec = vertex_weight_delete_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, + "weight_group", + -1, + -1, + INT_MAX, + "Weight Index", + "Index of source weight in active vertex group", + -1, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int vertex_weight_set_active_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); - const int wg_index = RNA_int_get(op->ptr, "weight_group"); + Object *ob = ED_object_context(C); + const int wg_index = RNA_int_get(op->ptr, "weight_group"); - if (wg_index != -1) { - ob->actdef = wg_index + 1; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } + if (wg_index != -1) { + ob->actdef = wg_index + 1; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_weight_set_active(wmOperatorType *ot) { - PropertyRNA *prop; - - ot->name = "Set Active Group"; - ot->idname = "OBJECT_OT_vertex_weight_set_active"; - ot->description = "Set as active vertex group"; - - /* api callbacks */ - ot->poll = vertex_group_vert_select_mesh_poll; - ot->exec = vertex_weight_set_active_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_int(ot->srna, "weight_group", -1, -1, INT_MAX, "Weight Index", - "Index of source weight in active vertex group", -1, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + PropertyRNA *prop; + + ot->name = "Set Active Group"; + ot->idname = "OBJECT_OT_vertex_weight_set_active"; + ot->description = "Set as active vertex group"; + + /* api callbacks */ + ot->poll = vertex_group_vert_select_mesh_poll; + ot->exec = vertex_weight_set_active_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, + "weight_group", + -1, + -1, + INT_MAX, + "Weight Index", + "Index of source weight in active vertex group", + -1, + INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - ToolSettings *ts = CTX_data_tool_settings(C); - eVGroupSelect subset_type = ts->vgroupsubset; - bool changed; - - changed = vgroup_normalize_active_vertex(ob, subset_type); - - if (changed) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + Object *ob = ED_object_context(C); + ToolSettings *ts = CTX_data_tool_settings(C); + eVGroupSelect subset_type = ts->vgroupsubset; + bool changed; + + changed = vgroup_normalize_active_vertex(ob, subset_type); + + if (changed) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot) { - ot->name = "Normalize Active"; - ot->idname = "OBJECT_OT_vertex_weight_normalize_active_vertex"; - ot->description = "Normalize active vertex's weights"; + ot->name = "Normalize Active"; + ot->idname = "OBJECT_OT_vertex_weight_normalize_active_vertex"; + ot->description = "Normalize active vertex's weights"; - /* api callbacks */ - ot->poll = vertex_group_vert_select_mesh_poll; - ot->exec = vertex_weight_normalize_active_vertex_exec; + /* api callbacks */ + ot->poll = vertex_group_vert_select_mesh_poll; + ot->exec = vertex_weight_normalize_active_vertex_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - ToolSettings *ts = CTX_data_tool_settings(C); - eVGroupSelect subset_type = ts->vgroupsubset; + Object *ob = ED_object_context(C); + ToolSettings *ts = CTX_data_tool_settings(C); + eVGroupSelect subset_type = ts->vgroupsubset; - vgroup_copy_active_to_sel(ob, subset_type); + vgroup_copy_active_to_sel(ob, subset_type); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OBJECT_OT_vertex_weight_copy(wmOperatorType *ot) { - ot->name = "Copy Active"; - ot->idname = "OBJECT_OT_vertex_weight_copy"; - ot->description = "Copy weights from active to selected"; + ot->name = "Copy Active"; + ot->idname = "OBJECT_OT_vertex_weight_copy"; + ot->description = "Copy weights from active to selected"; - /* api callbacks */ - ot->poll = vertex_group_vert_select_mesh_poll; - ot->exec = vertex_weight_copy_exec; + /* api callbacks */ + ot->poll = vertex_group_vert_select_mesh_poll; + ot->exec = vertex_weight_copy_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index 753e29ca9a7..3a089acb330 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -40,264 +40,275 @@ #include "object_intern.h" - -static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_view[3], - Object *obedit, float viewmat[4][4], const float center[3], +static void object_warp_calc_view_matrix(float r_mat_view[4][4], + float r_center_view[3], + Object *obedit, + float viewmat[4][4], + const float center[3], const float offset_angle) { - float mat_offset[4][4]; - float viewmat_roll[4][4]; + float mat_offset[4][4]; + float viewmat_roll[4][4]; - /* apply the rotation offset by rolling the view */ - axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle); - mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); + /* apply the rotation offset by rolling the view */ + axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle); + mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); - /* apply the view and the object matrix */ - mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->obmat); + /* apply the view and the object matrix */ + mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->obmat); - /* get the view-space cursor */ - mul_v3_m4v3(r_center_view, viewmat_roll, center); + /* get the view-space cursor */ + mul_v3_m4v3(r_center_view, viewmat_roll, center); } - static void object_warp_transverts_minmax_x(TransVertStore *tvs, - float mat_view[4][4], const float center_view[3], - float *r_min, float *r_max) + float mat_view[4][4], + const float center_view[3], + float *r_min, + float *r_max) { - /* no need to apply translation and cursor offset for every vertex, delay this */ - const float x_ofs = (mat_view[3][0] - center_view[0]); - float min = FLT_MAX, max = -FLT_MAX; - - TransVert *tv; - int i; + /* no need to apply translation and cursor offset for every vertex, delay this */ + const float x_ofs = (mat_view[3][0] - center_view[0]); + float min = FLT_MAX, max = -FLT_MAX; + TransVert *tv; + int i; - tv = tvs->transverts; - for (i = 0; i < tvs->transverts_tot; i++, tv++) { - float val; + tv = tvs->transverts; + for (i = 0; i < tvs->transverts_tot; i++, tv++) { + float val; - /* convert objectspace->viewspace */ - val = dot_m4_v3_row_x(mat_view, tv->loc); + /* convert objectspace->viewspace */ + val = dot_m4_v3_row_x(mat_view, tv->loc); - min = min_ff(min, val); - max = max_ff(max, val); - } + min = min_ff(min, val); + max = max_ff(max, val); + } - *r_min = min + x_ofs; - *r_max = max + x_ofs; + *r_min = min + x_ofs; + *r_max = max + x_ofs; } - static void object_warp_transverts(TransVertStore *tvs, - float mat_view[4][4], const float center_view[3], - const float angle_, const float min, const float max) + float mat_view[4][4], + const float center_view[3], + const float angle_, + const float min, + const float max) { - TransVert *tv; - int i; - const float angle = -angle_; - /* cache vars for tiny speedup */ + TransVert *tv; + int i; + const float angle = -angle_; + /* cache vars for tiny speedup */ #if 1 - const float range = max - min; - const float range_inv = 1.0f / range; - const float min_ofs = min + (0.5f * range); + const float range = max - min; + const float range_inv = 1.0f / range; + const float min_ofs = min + (0.5f * range); #endif - float dir_min[2], dir_max[2]; - float imat_view[4][4]; - + float dir_min[2], dir_max[2]; + float imat_view[4][4]; - invert_m4_m4(imat_view, mat_view); + invert_m4_m4(imat_view, mat_view); - /* calculate the direction vectors outside min/max range */ - { - const float phi = angle * 0.5f; + /* calculate the direction vectors outside min/max range */ + { + const float phi = angle * 0.5f; - dir_max[0] = cosf(phi); - dir_max[1] = sinf(phi); + dir_max[0] = cosf(phi); + dir_max[1] = sinf(phi); - dir_min[0] = -dir_max[0]; - dir_min[1] = dir_max[1]; - } + dir_min[0] = -dir_max[0]; + dir_min[1] = dir_max[1]; + } + tv = tvs->transverts; + for (i = 0; i < tvs->transverts_tot; i++, tv++) { + float co[3], co_add[2]; + float val, phi; - tv = tvs->transverts; - for (i = 0; i < tvs->transverts_tot; i++, tv++) { - float co[3], co_add[2]; - float val, phi; + /* convert objectspace->viewspace */ + mul_v3_m4v3(co, mat_view, tv->loc); + sub_v2_v2(co, center_view); - /* convert objectspace->viewspace */ - mul_v3_m4v3(co, mat_view, tv->loc); - sub_v2_v2(co, center_view); + val = co[0]; + /* is overwritten later anyway */ + // co[0] = 0.0f; - val = co[0]; - /* is overwritten later anyway */ - // co[0] = 0.0f; + if (val < min) { + mul_v2_v2fl(co_add, dir_min, min - val); + val = min; + } + else if (val > max) { + mul_v2_v2fl(co_add, dir_max, val - max); + val = max; + } + else { + zero_v2(co_add); + } - if (val < min) { - mul_v2_v2fl(co_add, dir_min, min - val); - val = min; - } - else if (val > max) { - mul_v2_v2fl(co_add, dir_max, val - max); - val = max; - } - else { - zero_v2(co_add); - } - - /* map from x axis to (-0.5 - 0.5) */ + /* map from x axis to (-0.5 - 0.5) */ #if 0 - val = ((val - min) / (max - min)) - 0.5f; + val = ((val - min) / (max - min)) - 0.5f; #else - val = (val - min_ofs) * range_inv; + val = (val - min_ofs) * range_inv; #endif - /* convert the x axis into a rotation */ - phi = val * angle; + /* convert the x axis into a rotation */ + phi = val * angle; - co[0] = -sinf(phi) * co[1]; - co[1] = cosf(phi) * co[1]; + co[0] = -sinf(phi) * co[1]; + co[1] = cosf(phi) * co[1]; - add_v2_v2(co, co_add); + add_v2_v2(co, co_add); - /* convert viewspace->objectspace */ - add_v2_v2(co, center_view); - mul_v3_m4v3(tv->loc, imat_view, co); - } + /* convert viewspace->objectspace */ + add_v2_v2(co, center_view); + mul_v3_m4v3(tv->loc, imat_view, co); + } } static int object_warp_verts_exec(bContext *C, wmOperator *op) { - const float warp_angle = RNA_float_get(op->ptr, "warp_angle"); - const float offset_angle = RNA_float_get(op->ptr, "offset_angle"); - - TransVertStore tvs = {NULL}; - Object *obedit = CTX_data_edit_object(C); - - /* typically from 'rv3d' and 3d cursor */ - float viewmat[4][4]; - float center[3]; - - /* 'viewmat' relative vars */ - float mat_view[4][4]; - float center_view[3]; - - float min, max; - - - ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); - if (tvs.transverts == NULL) { - return OPERATOR_CANCELLED; - } - - - /* get viewmatrix */ - { - PropertyRNA *prop_viewmat = RNA_struct_find_property(op->ptr, "viewmat"); - if (RNA_property_is_set(op->ptr, prop_viewmat)) { - RNA_property_float_get_array(op->ptr, prop_viewmat, (float *)viewmat); - } - else { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - - if (rv3d) { - copy_m4_m4(viewmat, rv3d->viewmat); - } - else { - unit_m4(viewmat); - } - - RNA_property_float_set_array(op->ptr, prop_viewmat, (float *)viewmat); - } - } - - - /* get center */ - { - PropertyRNA *prop_center = RNA_struct_find_property(op->ptr, "center"); - if (RNA_property_is_set(op->ptr, prop_center)) { - RNA_property_float_get_array(op->ptr, prop_center, center); - } - else { - const Scene *scene = CTX_data_scene(C); - copy_v3_v3(center, scene->cursor.location); - - RNA_property_float_set_array(op->ptr, prop_center, center); - } - } - - - object_warp_calc_view_matrix(mat_view, center_view, obedit, viewmat, center, offset_angle); - - - /* get minmax */ - { - PropertyRNA *prop_min = RNA_struct_find_property(op->ptr, "min"); - PropertyRNA *prop_max = RNA_struct_find_property(op->ptr, "max"); - - if (RNA_property_is_set(op->ptr, prop_min) || - RNA_property_is_set(op->ptr, prop_max)) - { - min = RNA_property_float_get(op->ptr, prop_min); - max = RNA_property_float_get(op->ptr, prop_max); - } - else { - /* handy to set the bounds of the mesh */ - object_warp_transverts_minmax_x(&tvs, mat_view, center_view, &min, &max); - - RNA_property_float_set(op->ptr, prop_min, min); - RNA_property_float_set(op->ptr, prop_max, max); - } - - if (min > max) { - SWAP(float, min, max); - } - } - - if (min != max) { - object_warp_transverts(&tvs, mat_view, center_view, warp_angle, min, max); - } - - ED_transverts_update_obedit(&tvs, obedit); - ED_transverts_free(&tvs); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - - return OPERATOR_FINISHED; + const float warp_angle = RNA_float_get(op->ptr, "warp_angle"); + const float offset_angle = RNA_float_get(op->ptr, "offset_angle"); + + TransVertStore tvs = {NULL}; + Object *obedit = CTX_data_edit_object(C); + + /* typically from 'rv3d' and 3d cursor */ + float viewmat[4][4]; + float center[3]; + + /* 'viewmat' relative vars */ + float mat_view[4][4]; + float center_view[3]; + + float min, max; + + ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); + if (tvs.transverts == NULL) { + return OPERATOR_CANCELLED; + } + + /* get viewmatrix */ + { + PropertyRNA *prop_viewmat = RNA_struct_find_property(op->ptr, "viewmat"); + if (RNA_property_is_set(op->ptr, prop_viewmat)) { + RNA_property_float_get_array(op->ptr, prop_viewmat, (float *)viewmat); + } + else { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + if (rv3d) { + copy_m4_m4(viewmat, rv3d->viewmat); + } + else { + unit_m4(viewmat); + } + + RNA_property_float_set_array(op->ptr, prop_viewmat, (float *)viewmat); + } + } + + /* get center */ + { + PropertyRNA *prop_center = RNA_struct_find_property(op->ptr, "center"); + if (RNA_property_is_set(op->ptr, prop_center)) { + RNA_property_float_get_array(op->ptr, prop_center, center); + } + else { + const Scene *scene = CTX_data_scene(C); + copy_v3_v3(center, scene->cursor.location); + + RNA_property_float_set_array(op->ptr, prop_center, center); + } + } + + object_warp_calc_view_matrix(mat_view, center_view, obedit, viewmat, center, offset_angle); + + /* get minmax */ + { + PropertyRNA *prop_min = RNA_struct_find_property(op->ptr, "min"); + PropertyRNA *prop_max = RNA_struct_find_property(op->ptr, "max"); + + if (RNA_property_is_set(op->ptr, prop_min) || RNA_property_is_set(op->ptr, prop_max)) { + min = RNA_property_float_get(op->ptr, prop_min); + max = RNA_property_float_get(op->ptr, prop_max); + } + else { + /* handy to set the bounds of the mesh */ + object_warp_transverts_minmax_x(&tvs, mat_view, center_view, &min, &max); + + RNA_property_float_set(op->ptr, prop_min, min); + RNA_property_float_set(op->ptr, prop_max, max); + } + + if (min > max) { + SWAP(float, min, max); + } + } + + if (min != max) { + object_warp_transverts(&tvs, mat_view, center_view, warp_angle, min, max); + } + + ED_transverts_update_obedit(&tvs, obedit); + ED_transverts_free(&tvs); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + + return OPERATOR_FINISHED; } void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Warp"; - ot->description = "Warp vertices around the cursor"; - ot->idname = "TRANSFORM_OT_vertex_warp"; - - /* api callbacks */ - ot->exec = object_warp_verts_exec; - ot->poll = ED_transverts_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - prop = RNA_def_float(ot->srna, "warp_angle", DEG2RADF(360.0f), -FLT_MAX, FLT_MAX, "Warp Angle", - "Amount to warp about the cursor", DEG2RADF(-360.0f), DEG2RADF(360.0f)); - RNA_def_property_subtype(prop, PROP_ANGLE); - - prop = RNA_def_float(ot->srna, "offset_angle", DEG2RADF(0.0f), -FLT_MAX, FLT_MAX, "Offset Angle", - "Angle to use as the basis for warping", DEG2RADF(-360.0f), DEG2RADF(360.0f)); - RNA_def_property_subtype(prop, PROP_ANGLE); - - prop = RNA_def_float(ot->srna, "min", -1.0f, -FLT_MAX, FLT_MAX, "Min", "", -100.0, 100.0); - prop = RNA_def_float(ot->srna, "max", 1.0f, -FLT_MAX, FLT_MAX, "Max", "", -100.0, 100.0); - - /* hidden props */ - prop = RNA_def_float_matrix(ot->srna, "viewmat", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - prop = RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Warp"; + ot->description = "Warp vertices around the cursor"; + ot->idname = "TRANSFORM_OT_vertex_warp"; + + /* api callbacks */ + ot->exec = object_warp_verts_exec; + ot->poll = ED_transverts_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* props */ + prop = RNA_def_float(ot->srna, + "warp_angle", + DEG2RADF(360.0f), + -FLT_MAX, + FLT_MAX, + "Warp Angle", + "Amount to warp about the cursor", + DEG2RADF(-360.0f), + DEG2RADF(360.0f)); + RNA_def_property_subtype(prop, PROP_ANGLE); + + prop = RNA_def_float(ot->srna, + "offset_angle", + DEG2RADF(0.0f), + -FLT_MAX, + FLT_MAX, + "Offset Angle", + "Angle to use as the basis for warping", + DEG2RADF(-360.0f), + DEG2RADF(360.0f)); + RNA_def_property_subtype(prop, PROP_ANGLE); + + prop = RNA_def_float(ot->srna, "min", -1.0f, -FLT_MAX, FLT_MAX, "Min", "", -100.0, 100.0); + prop = RNA_def_float(ot->srna, "max", 1.0f, -FLT_MAX, FLT_MAX, "Max", "", -100.0, 100.0); + + /* hidden props */ + prop = RNA_def_float_matrix( + ot->srna, "viewmat", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_float_vector_xyz( + ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } |