diff options
Diffstat (limited to 'source/blender/editors/object')
25 files changed, 5892 insertions, 3809 deletions
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 24740a3372b..17359934c6e 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -24,11 +24,15 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../ikplugin ../../imbuf ../../makesdna ../../makesrna + ../../modifiers + ../../gpencil_modifiers + ../../shader_fx ../../python ../../render/extern/include ../../windowmanager @@ -44,13 +48,15 @@ set(SRC object_add.c object_bake.c object_bake_api.c + object_collection.c object_constraint.c object_edit.c - object_group.c + object_facemap_ops.c object_hook.c - object_lod.c object_modes.c object_modifier.c + object_gpencil_modifier.c + object_shader_fx.c object_ops.c object_random.c object_relations.c @@ -70,10 +76,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_GAMEENGINE) - add_definitions(-DWITH_GAMEENGINE) -endif() - if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index efc69c36cc3..8abef6f6793 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -30,13 +30,14 @@ #include <stdlib.h> #include <string.h> +#include <ctype.h> #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" @@ -45,9 +46,9 @@ #include "DNA_object_fluidsim_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" #include "DNA_vfont_types.h" -#include "DNA_actuator_types.h" #include "DNA_gpencil_types.h" #include "BLI_utildefines.h" @@ -63,34 +64,38 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_font.h" -#include "BKE_group.h" +#include "BKE_gpencil.h" +#include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" -#include "BKE_key.h" +#include "BKE_lightprobe.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_nla.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_report.h" -#include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_speaker.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -100,6 +105,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_gpencil.h" #include "ED_mball.h" #include "ED_mesh.h" #include "ED_node.h" @@ -112,19 +118,16 @@ #include "UI_resources.h" -#include "GPU_material.h" - #include "object_intern.h" /* this is an exact copy of the define in rna_lamp.c * kept here because of linking order. * Icons are only defined here */ -const EnumPropertyItem rna_enum_lamp_type_items[] = { - {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source"}, - {LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source"}, - {LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source"}, - {LA_HEMI, "HEMI", ICON_LAMP_HEMI, "Hemi", "180 degree constant light source"}, - {LA_AREA, "AREA", ICON_LAMP_AREA, "Area", "Directional area light source"}, +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} }; @@ -146,17 +149,22 @@ static const EnumPropertyItem field_type_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem lightprobe_type_items[] = { + {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", + "Planar reflection probe"}, + {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Irradiance Volume", + "Irradiance probe to capture diffuse indirect lighting"}, + {0, NULL, 0, NULL, NULL} +}; + /************************** Exported *****************************/ void ED_object_location_from_view(bContext *C, float loc[3]) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const float *cursor; - - cursor = ED_view3d_cursor3d_get(scene, v3d); - - copy_v3_v3(loc, cursor); + 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) @@ -207,6 +215,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], { Object *ob = base->object; Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); if (!scene) return; @@ -216,7 +225,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], if (rot) copy_v3_v3(ob->rot, rot); - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); } /* Uses context to figure out transform for primitive. @@ -261,7 +270,12 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc RNA_struct_idprops_unset(ptr, "rotation"); } -void ED_object_add_unit_props(wmOperatorType *ot) +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); +} + +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); } @@ -287,22 +301,17 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) "Rotation", "Rotation for the newly added object", DEG2RADF(-360.0f), DEG2RADF(360.0f)); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void ED_object_add_mesh_props(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map"); + 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, unsigned int *layer, bool *is_view_aligned) + bool *enter_editmode, bool *is_view_aligned) { - View3D *v3d = CTX_wm_view3d(C); - unsigned int _layer; PropertyRNA *prop; /* Switch to Edit mode? optional prop */ @@ -319,37 +328,6 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view } } - /* Get layers! */ - { - int a; - bool layer_values[20]; - if (!layer) - layer = &_layer; - - prop = RNA_struct_find_property(op->ptr, "layers"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_get_array(op->ptr, prop, layer_values); - *layer = 0; - for (a = 0; a < 20; a++) { - if (layer_values[a]) - *layer |= (1 << a); - } - } - else { - Scene *scene = CTX_data_scene(C); - *layer = BKE_screen_view3d_layer_active_ex(v3d, scene, false); - for (a = 0; a < 20; a++) { - layer_values[a] = (*layer & (1 << a)) != 0; - } - RNA_property_boolean_set_array(op->ptr, prop, layer_values); - } - - /* in local view we additionally add local view layers, - * not part of operator properties */ - if (v3d && v3d->localvd) - *layer |= v3d->lay; - } - /* Location! */ { float _loc[3]; @@ -391,11 +369,6 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view RNA_float_get_array(op->ptr, "rotation", rot); } - if (layer && *layer == 0) { - BKE_report(op->reports, RPT_ERROR, "Property 'layer' has no values set"); - return false; - } - return true; } @@ -405,10 +378,11 @@ Object *ED_object_add_type( bContext *C, int type, const char *name, const float loc[3], const float rot[3], - bool enter_editmode, unsigned int layer) + bool enter_editmode) { 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... */ @@ -416,25 +390,21 @@ Object *ED_object_add_type( ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); } - /* deselects all, sets scene->basact */ - ob = BKE_object_add(bmain, scene, type, name); - BASACT->lay = ob->lay = layer; + /* deselects all, sets active object */ + ob = BKE_object_add(bmain, scene, view_layer, type, name); /* editor level activate, notifiers */ - ED_base_object_activate(C, BASACT); + ED_object_base_activate(C, view_layer->basact); /* more editor stuff */ - ED_object_base_init_transform(C, BASACT, loc, rot); - - /* Ignore collisions by default for non-mesh objects */ - if (type != OB_MESH) { - ob->body_type = OB_BODY_TYPE_NO_COLLISION; - ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */ - } + ED_object_base_init_transform(C, view_layer->basact, loc, rot); - DAG_id_type_tag(bmain, ID_OB); - DAG_relations_tag_update(bmain); - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + /* 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, DEG_TAG_EDITORS_UPDATE); } if (enter_editmode) @@ -442,6 +412,9 @@ Object *ED_object_add_type( 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; } @@ -450,15 +423,14 @@ static int object_add_exec(bContext *C, wmOperator *op) { Object *ob; bool enter_editmode; - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, 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, layer); + ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode); if (ob->type == OB_LATTICE) { /* lattice is a special case! @@ -487,12 +459,94 @@ void OBJECT_OT_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", ""); ED_object_add_generic_props(ot, true); } +/********************** Add Probe Operator **********************/ + +/* for object add operator */ +static const char *get_lightprobe_defname(int type) +{ + switch (type) { + case LIGHTPROBE_TYPE_GRID: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "IrradianceVolume"); + case LIGHTPROBE_TYPE_PLANAR: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "ReflectionPlane"); + case LIGHTPROBE_TYPE_CUBE: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "ReflectionCubemap"); + default: + return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "LightProbe"); + } +} + +static int lightprobe_add_exec(bContext *C, wmOperator *op) +{ + Object *ob; + LightProbe *probe; + int type; + bool enter_editmode; + 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, 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); + BKE_object_obdata_size_init(ob, 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"; + + /* api callbacks */ + ot->exec = lightprobe_add_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* 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); +} + /********************* Add Effector Operator ********************/ /* for object add operator */ @@ -501,13 +555,12 @@ static int effector_add_exec(bContext *C, wmOperator *op) Object *ob; int type; bool enter_editmode; - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL)) return OPERATOR_CANCELLED; type = RNA_enum_get(op->ptr, "type"); @@ -516,7 +569,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) 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, layer); + ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false); cu = ob->data; cu->flag |= CU_PATH | CU_3D; @@ -528,7 +581,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) } else { const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field"); - ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, layer); + ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false); BKE_object_obdata_size_init(ob, dia); if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) ob->empty_drawtype = OB_SINGLE_ARROW; @@ -536,7 +589,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) ob->pd = object_add_collision_fields(type); - DAG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(CTX_data_main(C)); return OPERATOR_FINISHED; } @@ -558,7 +611,7 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", ""); - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, true); } @@ -571,16 +624,15 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) Object *ob; Camera *cam; bool enter_editmode; - unsigned int layer; float loc[3], rot[3]; /* 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL)) return OPERATOR_CANCELLED; - ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, layer); + ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false); if (v3d) { if (v3d->camera == NULL) @@ -627,21 +679,20 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); bool newob = false; bool enter_editmode; - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL)) return OPERATOR_CANCELLED; if (obedit == NULL || obedit->type != OB_MBALL) { - obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, layer); + obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true); newob = true; } else { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); } ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); @@ -676,7 +727,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", ""); - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, true); } @@ -686,17 +737,16 @@ static int object_add_text_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bool enter_editmode; - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, 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, layer); + obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode); BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius")); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); @@ -719,7 +769,7 @@ void OBJECT_OT_text_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, true); } @@ -731,21 +781,20 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) RegionView3D *rv3d = CTX_wm_region_view3d(C); bool newob = false; bool enter_editmode; - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL)) return OPERATOR_CANCELLED; if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) { - obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, layer); + obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true); ED_object_editmode_enter(C, 0); newob = true; } else { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); } if (obedit == NULL) { @@ -780,7 +829,7 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, true); } @@ -790,14 +839,13 @@ static int object_empty_add_exec(bContext *C, wmOperator *op) { Object *ob; int type = RNA_enum_get(op->ptr, "type"); - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL)) return OPERATOR_CANCELLED; - ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer); + ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false); BKE_object_empty_draw_type_set(ob, type); BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); @@ -823,7 +871,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", ""); - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, false); } @@ -831,9 +879,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv { Scene *scene = CTX_data_scene(C); - Base *base = NULL; Image *ima = NULL; - Object *ob = NULL; ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); if (!ima) { @@ -842,26 +888,22 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv /* handled below */ id_us_min((ID *)ima); - base = ED_view3d_give_base_under_cursor(C, event->mval); + Object *ob = NULL; + Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval); - /* if empty under cursor, then set object */ - if (base && base->object->type == OB_EMPTY) { - ob = base->object; + /* 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, DEG_TAG_TRANSFORM); + ob = ob_cursor; } else { - /* add new empty */ - unsigned int layer; - float rot[3]; + ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, NULL, false); - if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &layer, NULL)) - return OPERATOR_CANCELLED; - - ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, layer); - - /* add under the mouse */ ED_object_location_from_view(C, ob->loc); - ED_view3d_cursor3d_position(C, event->mval, 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); @@ -899,41 +941,171 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Lamp Operator ********************/ +/********************* Add Gpencil Operator ********************/ + +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"); + + 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, 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; + } + } + + float radius = RNA_float_get(op->ptr, "radius"); + ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true); + gpd = ob->data; + newob = true; + + BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE * radius); + } + else { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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, 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, 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) { + ED_gpencil_add_defaults(C); + } + + 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"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_gpencil_add_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* 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", ""); +} + +/********************* Add Light Operator ********************/ -static const char *get_lamp_defname(int type) +static const char *get_light_defname(int type) { switch (type) { case LA_LOCAL: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Point"); case LA_SUN: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Sun"); case LA_SPOT: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Spot"); - case LA_HEMI: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Hemi"); case LA_AREA: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Area"); default: - return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Lamp"); + return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Light"); } } -static int object_lamp_add_exec(bContext *C, wmOperator *op) +static int object_light_add_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob; Lamp *la; int type = RNA_enum_get(op->ptr, "type"); - unsigned int layer; 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, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL)) return OPERATOR_CANCELLED; - ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer); - BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); + ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false); + + 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 = (Lamp *)ob->data; la->type = type; - if (BKE_scene_use_new_shading_nodes(scene)) { + if (BKE_scene_uses_cycles(scene)) { ED_node_shader_default(C, &la->id); la->use_nodes = true; } @@ -941,43 +1113,42 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OBJECT_OT_lamp_add(wmOperatorType *ot) +void OBJECT_OT_light_add(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Lamp"; - ot->description = "Add a lamp object to the scene"; - ot->idname = "OBJECT_OT_lamp_add"; + 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_lamp_add_exec; + ot->exec = object_light_add_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_lamp_type_items, 0, "Type", ""); + 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_LAMP); - ED_object_add_unit_props(ot); + ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, false); } -/********************* Add Group Instance Operator ********************/ +/********************* Add Collection Instance Operator ********************/ -static int group_instance_add_exec(bContext *C, wmOperator *op) +static int collection_instance_add_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Group *group; - unsigned int layer; + Collection *collection; 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); - group = (Group *)BKE_libblock_find_name(bmain, ID_GR, 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; @@ -985,26 +1156,34 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) 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, loc); + ED_view3d_cursor3d_position(C, mval, false, loc); RNA_float_set_array(op->ptr, "location", loc); } } else - group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); + collection = BLI_findlink(&CTX_data_main(C)->collection, RNA_enum_get(op->ptr, "collection")); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL)) return OPERATOR_CANCELLED; - if (group) { + if (collection) { Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer); - ob->dup_group = group; - ob->transflag |= OB_DUPLIGROUP; - id_us_plus(&group->id); + ViewLayer *view_layer = CTX_data_view_layer(C); - /* works without this except if you try render right after, see: 22027 */ - DAG_relations_tag_update(bmain); + /* 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); + ob->dup_group = 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, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; @@ -1014,27 +1193,27 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) } /* only used as menu */ -void OBJECT_OT_group_instance_add(wmOperatorType *ot) +void OBJECT_OT_collection_instance_add(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Add Group Instance"; - ot->description = "Add a dupligroup instance"; - ot->idname = "OBJECT_OT_group_instance_add"; + 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 = group_instance_add_exec; + ot->exec = collection_instance_add_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Group name to add"); - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", ""); - RNA_def_enum_funcs(prop, RNA_group_itemf); + 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); @@ -1045,14 +1224,13 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot) static int object_speaker_add_exec(bContext *C, wmOperator *op) { Object *ob; - unsigned int layer; float loc[3], rot[3]; Scene *scene = CTX_data_scene(C); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL)) + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL)) return OPERATOR_CANCELLED; - ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, layer); + ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false); /* 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 @@ -1097,35 +1275,22 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) /**************************** Delete Object *************************/ -static void object_delete_check_glsl_update(Object *ob) -{ - /* some objects could affect on GLSL shading, make sure GLSL settings - * are being tagged to be updated when object is removing from scene - */ - if (ob->type == OB_LAMP) { - if (ob->gpulamp.first) - GPU_lamp_free(ob); - } -} - /* remove base from a specific scene */ /* note: now unlinks constraints as well */ -void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) +void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) { - if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + 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!", - base->object->id.name + 2); + ob->id.name + 2); return; } - BKE_scene_base_unlink(scene, base); - object_delete_check_glsl_update(base->object); - BKE_libblock_free_us(bmain, base->object); - MEM_freeN(base); - DAG_id_type_tag(bmain, ID_OB); + DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE); + + BKE_scene_collections_object_remove(bmain, scene, ob, true); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -1135,34 +1300,40 @@ static int object_delete_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; const bool use_global = RNA_boolean_get(op->ptr, "use_global"); - bool changed = false; + uint changed_count = 0; if (CTX_data_edit_object(C)) return OPERATOR_CANCELLED; - CTX_DATA_BEGIN (C, Base *, base, selected_bases) + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object); - if (base->object->id.tag & LIB_TAG_INDIRECT) { + 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'", base->object->id.name + 2); + 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(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { + 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", - base->object->id.name + 2, scene->id.name + 2); + 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, OB_RECALC_OB | OB_RECALC_DATA); + } + /* 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 && base->object->id.lib == NULL) { + 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_libblock_delete(bmain, &base->object->id); - changed = true; + BKE_libblock_delete(bmain, &ob->id); + changed_count += 1; continue; } @@ -1172,38 +1343,28 @@ static int object_delete_exec(bContext *C, wmOperator *op) for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { if (gpl->parent != NULL) { - Object *ob = gpl->parent; - Object *curob = base->object; - if (ob == curob) { + if (gpl->parent == ob) { gpl->parent = NULL; } } } } - /* deselect object -- it could be used in other scenes */ - base->object->flag &= ~SELECT; - /* remove from current scene only */ - ED_base_object_free_and_unlink(bmain, scene, base); - changed = true; + ED_object_base_free_and_unlink(bmain, scene, ob); + changed_count += 1; if (use_global) { Scene *scene_iter; - Base *base_other; - for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) { if (scene_iter != scene && !ID_IS_LINKED(scene_iter)) { - base_other = BKE_scene_base_find(scene_iter, base->object); - if (base_other) { - if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { - BKE_reportf(op->reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene_iter->id.name + 2); - break; - } - ED_base_object_free_and_unlink(bmain, scene_iter, base_other); + 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); } } } @@ -1211,19 +1372,23 @@ static int object_delete_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - if (!changed) + 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->scene, LIB_TAG_DOIT, true); for (win = wm->windows.first; win; win = win->next) { - scene = win->screen->scene; + scene = WM_window_get_active_scene(win); if (scene->id.tag & LIB_TAG_DOIT) { scene->id.tag &= ~LIB_TAG_DOIT; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } @@ -1240,14 +1405,17 @@ void OBJECT_OT_delete(wmOperatorType *ot) ot->idname = "OBJECT_OT_delete"; /* api callbacks */ - ot->invoke = WM_operator_confirm; + ot->invoke = WM_operator_confirm_or_exec; ot->exec = object_delete_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "use_global", 0, "Delete Globally", "Remove object from all scenes"); + 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 ******************************/ @@ -1263,15 +1431,13 @@ static void copy_object_set_idnew(bContext *C) } CTX_DATA_END; - set_sca_new_poins(); - BKE_main_id_clear_newpoins(bmain); } /********************* Make Duplicates Real ************************/ /** - * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same dupli-group instance. */ static unsigned int dupliobject_group_hash(const void *ptr) @@ -1286,7 +1452,7 @@ static unsigned int dupliobject_group_hash(const void *ptr) } /** - * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, include the first member of #DupliObject.persistent_id * since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face. */ static unsigned int dupliobject_hash(const void *ptr) @@ -1344,6 +1510,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, 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; @@ -1352,11 +1520,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, return; } - lb_duplis = object_duplilist(bmain, bmain->eval_ctx, scene, base->object); + lb_duplis = object_duplilist(depsgraph, scene, base->object); dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - if (base->object->transflag & OB_DUPLIGROUP) { + if (base->object->transflag & OB_DUPLICOLLECTION) { parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); } else { @@ -1376,12 +1544,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->totcol = 0; } - base_dst = MEM_dupallocN(base); - base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP); - ob_dst->flag = base_dst->flag; - base_dst->lay = base->lay; - BLI_addhead(&scene->base, base_dst); /* addhead: othwise eternal loop */ - base_dst->object = ob_dst; + 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); @@ -1394,9 +1561,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->parent = NULL; BKE_constraints_free(&ob_dst->constraints); - ob_dst->curve_cache = NULL; + ob_dst->runtime.curve_cache = NULL; ob_dst->transflag &= ~OB_DUPLI; - ob_dst->lay = base->lay; copy_m4_m4(ob_dst->obmat, dob->mat); BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); @@ -1418,9 +1584,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, /* Remap new object to itself, and clear again newid pointer of orig object. */ BKE_libblock_relink_to_newid(&ob_dst->id); - set_sca_new_poins_ob(ob_dst); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); if (use_hierarchy) { /* original parents */ @@ -1433,7 +1598,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * 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_DUPLIGROUP) { + 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)); @@ -1473,17 +1638,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * still work out ok */ BKE_object_apply_mat4(ob_dst, dob->mat, false, true); - /* to set ob_dst->orig and in case theres any other discrepicies */ - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB); + /* to set ob_dst->orig and in case there's any other discrepancies */ + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB); } } - if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { + if (base->object->transflag & OB_DUPLICOLLECTION && base->object->dup_group) { for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->proxy_group == base->object) { ob->proxy = NULL; ob->proxy_from = NULL; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } } } @@ -1519,7 +1684,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE, scene); WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); @@ -1553,46 +1718,46 @@ static const EnumPropertyItem convert_target_items[] = { {0, NULL, 0, NULL, NULL} }; -static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob) +static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) { - if (ob->curve_cache == NULL) { + 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)) { - BKE_displist_make_curveTypes(scene, ob, false); + /* 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); } else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, ob); + BKE_displist_make_mball(depsgraph, scene, ob); } } } -static void curvetomesh(Main *bmain, Scene *scene, Object *ob) +static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { - convert_ensure_curve_cache(bmain, scene, ob); + 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); - - /* Game engine defaults for mesh objects */ - ob->body_type = OB_BODY_TYPE_STATIC; - ob->gameflag = OB_PROP | OB_COLLISION; } } static bool convert_poll(bContext *C) { - Object *obact = CTX_data_active_object(C); 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 && scene->obedit != obact && - (obact->flag & SELECT) && !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, Base *base, Object *ob) +static Base *duplibase_for_convert(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob) { Object *obn; Base *basen; @@ -1602,27 +1767,23 @@ static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object } obn = BKE_object_copy(bmain, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - - basen = MEM_mallocN(sizeof(Base), "duplibase"); - *basen = *base; - BLI_addhead(&scene->base, basen); /* addhead: otherwise eternal loop */ - basen->object = obn; - basen->flag |= SELECT; - obn->flag |= SELECT; - base->flag &= ~SELECT; - ob->flag &= ~SELECT; + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + 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; } 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 *ob, *ob1, *obact = CTX_data_active_object(C); - DerivedMesh *dm; + Object *ob1, *obact = CTX_data_active_object(C); Curve *cu; Nurb *nu; MetaBall *mb; @@ -1634,13 +1795,11 @@ static int convert_exec(bContext *C, wmOperator *op) /* don't forget multiple users! */ { - Base *base; - - for (base = scene->base.first; base; base = base->next) { - ob = base->object; + FOREACH_SCENE_OBJECT_BEGIN(scene, ob) + { ob->flag &= ~OB_DONE; - /* flag data thats not been edited (only needed for !keep_original) */ + /* flag data that's not been edited (only needed for !keep_original) */ if (ob->data) { ((ID *)ob->data)->tag |= LIB_TAG_DOIT; } @@ -1649,13 +1808,14 @@ static int convert_exec(bContext *C, wmOperator *op) if (ob->type == OB_MBALL && target == OB_MESH) { if (BKE_mball_is_basis(ob) == false) { Object *ob_basis; - ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob); + 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"); @@ -1666,9 +1826,9 @@ static int convert_exec(bContext *C, wmOperator *op) { for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) { Base *base = link->ptr.data; - ob = base->object; + Object *ob = base->object; - /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted + /* The way object type conversion works currently (enforcing conversion of *all* objects using converted * obdata, even some un-selected/hidden/inother scene ones, sounds totally bad to me. * However, changing this is more design than bugfix, not to mention convoluted code below, * so that will be for later. @@ -1679,19 +1839,19 @@ static int convert_exec(bContext *C, wmOperator *op) "Converting some linked object/object data, enforcing 'Keep Original' option to True"); } - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } uint64_t customdata_mask_prev = scene->customdata_mask; scene->customdata_mask |= CD_MASK_MESH; - BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene); + 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; - ob = base->object; + Object *ob = base->object; if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) { if (ob->type != target) { @@ -1706,13 +1866,17 @@ static int convert_exec(bContext *C, wmOperator *op) 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, base, NULL); + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1726,7 +1890,7 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; } - BKE_mesh_to_curve(bmain, scene, newob); + BKE_mesh_to_curve(bmain, depsgraph, scene, newob); if (newob->type == OB_CURVE) { BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ @@ -1737,7 +1901,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1749,26 +1913,25 @@ static int convert_exec(bContext *C, wmOperator *op) } else { newob = ob; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } /* make new mesh data from the original copy */ /* note: get the mesh from the original, not from the copy in some - * cases this doesnt give correct results (when MDEF is used for eg) + * cases this doesn't give correct results (when MDEF is used for eg) */ - dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH); - - DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true); - - /* re-tessellation is called by DM_to_mesh */ - + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, newob, CD_MASK_MESH); + if (newob->runtime.mesh_eval == me_eval) { + newob->runtime.mesh_eval = NULL; + } + 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, base, NULL); + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); newob = basen->object; /* decrement original curve's usage count */ @@ -1787,6 +1950,7 @@ static int convert_exec(bContext *C, wmOperator *op) * 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; @@ -1815,7 +1979,7 @@ static int convert_exec(bContext *C, wmOperator *op) for (ob1 = bmain->object.first; ob1; ob1 = ob1->id.next) { if (ob1->data == ob->data) { ob1->type = OB_CURVE; - DAG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } } @@ -1828,7 +1992,7 @@ static int convert_exec(bContext *C, wmOperator *op) BKE_curve_curve_dimension_update(cu); if (target == OB_MESH) { - curvetomesh(bmain, scene, newob); + curvetomesh(bmain, depsgraph, scene, newob); /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); @@ -1839,7 +2003,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (target == OB_MESH) { if (keep_original) { - basen = duplibase_for_convert(bmain, scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL); newob = basen->object; /* decrement original curve's usage count */ @@ -1852,7 +2016,7 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; } - curvetomesh(bmain, scene, newob); + curvetomesh(bmain, depsgraph, scene, newob); /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); @@ -1861,10 +2025,10 @@ static int convert_exec(bContext *C, wmOperator *op) else if (ob->type == OB_MBALL && target == OB_MESH) { Object *baseob; - base->flag &= ~SELECT; - ob->flag &= ~SELECT; + base->flag &= ~BASE_SELECTED; + ob->base_flag &= ~BASE_SELECTED; - baseob = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob); + baseob = BKE_mball_basis_find(scene, ob); if (ob != baseob) { /* if motherball is converting it would be marked as done later */ @@ -1874,7 +2038,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (!(baseob->flag & OB_DONE)) { baseob->flag |= OB_DONE; - basen = duplibase_for_convert(bmain, scene, base, baseob); + basen = duplibase_for_convert(bmain, scene, view_layer, base, baseob); newob = basen->object; mb = newob->data; @@ -1890,8 +2054,8 @@ static int convert_exec(bContext *C, wmOperator *op) for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]); } - convert_ensure_curve_cache(bmain, scene, baseob); - BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data); + 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; @@ -1922,7 +2086,7 @@ static int convert_exec(bContext *C, wmOperator *op) } if (!keep_original && (ob->flag & OB_DONE)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */ } } @@ -1930,27 +2094,21 @@ static int convert_exec(bContext *C, wmOperator *op) if (!keep_original) { if (mballConverted) { - Base *base, *base_next; - - for (base = scene->base.first; base; base = base_next) { - base_next = base->next; - - ob = base->object; - if (ob->type == OB_MBALL) { - if (ob->flag & OB_DONE) { + 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) || - ((ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob)) && (ob_basis->flag & OB_DONE))) + if (BKE_mball_is_basis(ob_mball) || + ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE))) { - ED_base_object_free_and_unlink(bmain, scene, base); + ED_object_base_free_and_unlink(bmain, scene, ob_mball); } } } } + FOREACH_SCENE_OBJECT_END; } - - /* delete object should renew depsgraph */ - DAG_relations_tag_update(bmain); } // XXX ED_object_editmode_enter(C, 0); @@ -1958,15 +2116,16 @@ static int convert_exec(bContext *C, wmOperator *op) if (basact) { /* active base was changed */ - ED_base_object_activate(C, basact); - BASACT = basact; + ED_object_base_activate(C, basact); + BASACT(view_layer) = basact; } - else if (BASACT->object->flag & OB_DONE) { - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT->object); - WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT->object); + 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); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -2005,39 +2164,44 @@ 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, Base *base, int dupflag) +static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, int dupflag) { #define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } - Base *basen = NULL; + Base *base, *basen = NULL; Material ***matarar; - Object *ob, *obn; + Object *obn; ID *id; int a, didit; - ob = base->object; if (ob->mode & OB_MODE_POSE) { ; /* nothing? */ } else { obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA); - basen = MEM_mallocN(sizeof(Base), "duplibase"); - *basen = *base; - BLI_addhead(&scene->base, basen); /* addhead: prevent eternal loop */ - basen->object = obn; + 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); + basen->local_view_bits = base->local_view_bits; - /* 1) duplis should end up in same group as the original - * 2) Rigid Body sim participants MUST always be part of a group... + /* 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 ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) { - Group *group; - for (group = bmain->group.first; group; group = group->id.next) { - if (BKE_group_object_exists(group, ob)) - BKE_group_object_add(group, obn, scene, basen); + if (ob->rigidbody_object || ob->rigidbody_constraint) { + Collection *collection; + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (BKE_collection_has_object(collection, ob)) + BKE_collection_object_add(bmain, collection, obn); } } @@ -2053,6 +2217,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ID_NEW_REMAP_US(obn->mat[a]) else { obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + /* duplicate grease pencil settings */ + if (ob->mat[a]->gp_style) { + obn->mat[a]->gp_style = MEM_dupallocN(ob->mat[a]->gp_style); + } } id_us_min(id); @@ -2146,14 +2314,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } break; case OB_ARMATURE: - DAG_id_tag_update(&obn->id, OB_RECALC_DATA); + DEG_id_tag_update(&obn->id, OB_RECALC_DATA); if (obn->pose) BKE_pose_tag_recalc(bmain, obn->pose); if (dupflag & USER_DUP_ARM) { ID_NEW_REMAP_US2(obn->data) else { obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); - BKE_pose_rebuild(obn, obn->data); + BKE_pose_rebuild(bmain, obn, obn->data, true); didit = 1; } id_us_min(id); @@ -2179,6 +2347,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id_us_min(id); } break; + case OB_LIGHTPROBE: + if (dupflag != 0) { + ID_NEW_REMAP_US2(obn->data) + else { + obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data)); + didit = 1; + } + id_us_min(id); + } + break; case OB_SPEAKER: if (dupflag != 0) { ID_NEW_REMAP_US2(obn->data) @@ -2189,6 +2367,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base id_us_min(id); } break; + case OB_GPENCIL: + if (dupflag != 0) { + ID_NEW_REMAP_US2(obn->data) + else { + obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data)); + didit = 1; + } + id_us_min(id); + } + break; } /* check if obdata is copied */ @@ -2201,25 +2389,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } if (dupflag & USER_DUP_ACT) { - bActuator *act; - BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true); if (key) { BKE_animdata_copy_id_action(bmain, (ID *)key, true); } - - /* Update the duplicated action in the action actuators */ - /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c), - * and what about other ID pointers of other BGE logic bricks, - * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */ - for (act = obn->actuators.first; act; act = act->next) { - if (act->type == ACT_ACTION) { - bActionActuator *actact = (bActionActuator *) act->data; - if (ob->adt && actact->act == ob->adt->action) { - actact->act = obn->adt->action; - } - } - } } if (dupflag & USER_DUP_MAT) { @@ -2250,14 +2423,12 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base * 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, Base *base, int dupflag) +Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, int dupflag) { Base *basen; Object *ob; - clear_sca_new_poins(); /* BGE logic */ - - basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag); if (basen == NULL) { return NULL; } @@ -2266,12 +2437,11 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag /* link own references to the newly duplicated data [#26816] */ BKE_libblock_relink_to_newid(&ob->id); - set_sca_new_poins_ob(ob); /* DAG_relations_tag_update(bmain); */ /* caller must do */ - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE); } BKE_main_id_clear_newpoins(bmain); @@ -2284,29 +2454,29 @@ 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; - clear_sca_new_poins(); /* BGE logic */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Base *basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + 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_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); + ED_object_base_select(basen, BA_SELECT); if (basen == NULL) { continue; } /* new object becomes active */ - if (BASACT == base) - ED_base_object_activate(C, basen); + if (BASACT(view_layer) == base) + ED_object_base_activate(C, basen); if (basen->object->data) { - DAG_id_tag_update(basen->object->data, 0); + DEG_id_tag_update(basen->object->data, 0); } } CTX_DATA_END; @@ -2315,7 +2485,8 @@ static int duplicate_exec(bContext *C, wmOperator *op) BKE_main_id_clear_newpoins(bmain); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -2351,9 +2522,9 @@ 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); - View3D *v3d = CTX_wm_view3d(C); /* may be NULL */ Scene *scene = CTX_data_scene(C); - Base *basen, *base; + 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; @@ -2368,22 +2539,15 @@ static int add_named_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - base = MEM_callocN(sizeof(Base), "duplibase"); - base->object = ob; - base->flag = ob->flag; - /* prepare dupli */ - clear_sca_new_poins(); /* BGE logic */ - - basen = object_add_duplicate_internal(bmain, scene, base, dupflag); + basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); if (basen == NULL) { - MEM_freeN(base); BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } - basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene); + BKE_scene_object_base_flag_sync_from_object(basen); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2391,20 +2555,20 @@ static int add_named_exec(bContext *C, wmOperator *op) 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, basen->object->loc); + ED_view3d_cursor3d_position(C, mval, false, basen->object->loc); } - ED_base_object_select(basen, BA_SELECT); - ED_base_object_activate(C, basen); + ED_object_base_select(basen, BA_SELECT); + ED_object_base_activate(C, basen); copy_object_set_idnew(C); BKE_main_id_clear_newpoins(bmain); - DAG_relations_tag_update(bmain); - - MEM_freeN(base); + /* TODO(sergey): Only update relations for the current scene. */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -2437,7 +2601,7 @@ static bool join_poll(bContext *C) if (!ob || ID_IS_LINKED(ob)) return 0; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL)) return ED_operator_screenactive(C); else return 0; @@ -2445,10 +2609,9 @@ static bool join_poll(bContext *C) static int join_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); return OPERATOR_CANCELLED; } @@ -2456,6 +2619,13 @@ static int join_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); 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); @@ -2463,6 +2633,8 @@ static int join_exec(bContext *C, wmOperator *op) 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; } @@ -2499,10 +2671,9 @@ static bool join_shapes_poll(bContext *C) static int join_shapes_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - if (scene->obedit) { + if (ob->mode & OB_MODE_EDIT) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index ee0dfe14cd3..5a650d9dc05 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -52,15 +52,17 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_multires.h" #include "BKE_report.h" #include "BKE_cdderivedmesh.h" #include "BKE_modifier.h" #include "BKE_DerivedMesh.h" -#include "BKE_depsgraph.h" #include "BKE_mesh.h" #include "BKE_scene.h" +#include "DEG_depsgraph.h" + #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "RE_multires_bake.h" @@ -77,15 +79,37 @@ #include "ED_object.h" #include "ED_screen.h" +#include "ED_uvedit.h" #include "object_intern.h" +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; +} + +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; +} + /* ****************** multires BAKING ********************** */ /* 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; @@ -94,6 +118,7 @@ typedef struct MultiresBakerJobData { /* data passing to multires-baker job */ typedef struct { + Scene *scene; ListBase data; bool bake_clear; /* Clear the images before baking */ int bake_filter; /* Bake-filter, aka margin */ @@ -101,8 +126,6 @@ typedef struct { bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */ int number_of_rays; /* Number of rays to be cast when doing AO baking */ float bias; /* Bias between object and start ray point when doing AO baking */ - int raytrace_structure; /* Optimization structure to be used for AO baking */ - int octree_resolution; /* Reslution of octotree when using octotree optimization structure */ int threads; /* Number of threads to be used for baking */ float user_scale; /* User scale used to scale displacement when baking derivative map. */ } MultiresBakeJob; @@ -152,7 +175,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op) break; } - if (!me->mtpoly) { + if (!me->mloopuv) { BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking"); ok = false; @@ -160,7 +183,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op) else { a = me->totpoly; while (ok && a--) { - Image *ima = me->mtpoly[a].tpage; + 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"); @@ -207,21 +230,21 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l MultiresModifierData tmp_mmd = *mmd; DerivedMesh *cddm = CDDM_from_mesh(me); - if (mmd->lvl > 0) { - *lvl = mmd->lvl; + DM_set_only_copy(cddm, CD_MASK_BAREMESH); + + if (mmd->lvl == 0) { + dm = CDDM_copy(cddm); } else { - *lvl = 1; - tmp_mmd.simple = true; + tmp_mmd.lvl = mmd->lvl; + tmp_mmd.sculptlvl = mmd->lvl; + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); } - DM_set_only_copy(cddm, CD_MASK_BAREMESH); - - tmp_mmd.lvl = *lvl; - tmp_mmd.sculptlvl = *lvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, 0); cddm->release(cddm); + *lvl = mmd->lvl; + return dm; } @@ -246,7 +269,7 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l tmp_mmd.lvl = mmd->totlvl; tmp_mmd.sculptlvl = mmd->totlvl; - dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, 0); + dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0); cddm->release(cddm); return dm; @@ -283,20 +306,27 @@ static void clear_single_image(Image *image, ClearFlag flag) } } -static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag) +static void clear_images_poly(Image **ob_image_array, int ob_image_array_len, ClearFlag flag) { - int a; - - for (a = 0; a < totpoly; a++) { - mtpoly[a].tpage->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 (a = 0; a < totpoly; a++) { - clear_single_image(mtpoly[a].tpage, flag); + for (int i = 0; i < ob_image_array_len; i++) { + Image *image = ob_image_array[i]; + if (image) { + clear_single_image(image, flag); + } } - for (a = 0; a < totpoly; a++) { - mtpoly[a].tpage->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; + } } } @@ -312,20 +342,23 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - Mesh *me; ClearFlag clear_flag = 0; ob = base->object; - me = (Mesh *)ob->data; + // me = (Mesh *)ob->data; if (scene->r.bake_mode == RE_BAKE_NORMALS) { clear_flag = CLEAR_TANGENT_NORMAL; } - else if (ELEM(scene->r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { + else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) { clear_flag = CLEAR_DISPLACEMENT; } - clear_images_poly(me->mtpoly, me->totpoly, clear_flag); + { + 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; } @@ -339,23 +372,27 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) 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.raytrace_structure = scene->r.raytrace_structure; - bkr.octree_resolution = scene->r.ocres; 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; + 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); + MEM_freeN(bkr.ob_image.array); + BLI_freelistN(&bkr.image); bkr.lores_dm->release(bkr.lores_dm); @@ -378,14 +415,13 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) 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->raytrace_structure = scene->r.raytrace_structure; - bkj->octree_resolution = scene->r.ocres; 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; @@ -401,6 +437,9 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) 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); @@ -421,18 +460,16 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa if (bkj->bake_clear) { /* clear images */ for (data = bkj->data.first; data; data = data->next) { - DerivedMesh *dm = data->lores_dm; - MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY); ClearFlag clear_flag = 0; if (bkj->mode == RE_BAKE_NORMALS) { clear_flag = CLEAR_TANGENT_NORMAL; } - else if (ELEM(bkj->mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { + else if (bkj->mode == RE_BAKE_DISPLACEMENT) { clear_flag = CLEAR_DISPLACEMENT; } - clear_images_poly(mtexpoly, dm->getNumPolys(dm), clear_flag); + clear_images_poly(data->ob_image.array, data->ob_image.len, clear_flag); } } @@ -440,11 +477,14 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa 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; @@ -463,8 +503,6 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa bkr.bias = bkj->bias; bkr.number_of_rays = bkj->number_of_rays; - bkr.raytrace_structure = bkj->raytrace_structure; - bkr.octree_resolution = bkj->octree_resolution; bkr.threads = bkj->threads; RE_multires_bake_images(&bkr); @@ -493,6 +531,8 @@ static void multiresbake_freejob(void *bkv) GPU_free_image(ima); } + MEM_freeN(data->ob_image.array); + BLI_freelistN(&data->images); MEM_freeN(data); @@ -539,201 +579,6 @@ static int multiresbake_image_exec(bContext *C, wmOperator *op) /* ****************** render BAKING ********************** */ -/* threaded break test */ -static int thread_break(void *UNUSED(arg)) -{ - return G.is_break; -} - -typedef struct BakeRender { - Render *re; - Main *main; - Scene *scene; - struct Object *actob; - int result, ready; - - ReportList *reports; - - short *stop; - short *do_update; - float *progress; - - ListBase threads; - - /* backup */ - short prev_wo_amb_occ; - short prev_r_raytrace; - - /* for redrawing */ - ScrArea *sa; -} BakeRender; - -/* use by exec and invoke */ -static int test_bake_internal(bContext *C, ReportList *reports) -{ - Scene *scene = CTX_data_scene(C); - - if ((scene->r.bake_flag & R_BAKE_TO_ACTIVE) && CTX_data_active_object(C) == NULL) { - BKE_report(reports, RPT_ERROR, "No active object"); - } - else if (scene->r.bake_mode == RE_BAKE_AO && scene->world == NULL) { - BKE_report(reports, RPT_ERROR, "No world set up"); - } - else { - return 1; - } - - return 0; -} - -static void init_bake_internal(BakeRender *bkr, bContext *C) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bScreen *sc = CTX_wm_screen(C); - - /* get editmode results */ - ED_object_editmode_load(bmain, CTX_data_edit_object(C)); - - bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; /* can be NULL */ - bkr->main = bmain; - bkr->scene = scene; - bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL; - bkr->re = RE_NewRender("_Bake View_"); - - if (scene->r.bake_mode == RE_BAKE_AO) { - /* If raytracing or AO is disabled, switch it on temporarily for baking. */ - bkr->prev_wo_amb_occ = (scene->world->mode & WO_AMB_OCC) != 0; - scene->world->mode |= WO_AMB_OCC; - } - if (scene->r.bake_mode == RE_BAKE_AO || bkr->actob) { - bkr->prev_r_raytrace = (scene->r.mode & R_RAYTRACE) != 0; - scene->r.mode |= R_RAYTRACE; - } -} - -static void finish_bake_internal(BakeRender *bkr) -{ - Image *ima; - - RE_Database_Free(bkr->re); - - /* restore raytrace and AO */ - if (bkr->scene->r.bake_mode == RE_BAKE_AO) - if (bkr->prev_wo_amb_occ == 0) - bkr->scene->world->mode &= ~WO_AMB_OCC; - - if (bkr->scene->r.bake_mode == RE_BAKE_AO || bkr->actob) - if (bkr->prev_r_raytrace == 0) - bkr->scene->r.mode &= ~R_RAYTRACE; - - /* force OpenGL reload and mipmap recalc */ - if ((bkr->scene->r.bake_flag & R_BAKE_VCOL) == 0) { - for (ima = bkr->main->image.first; ima; ima = ima->id.next) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - /* some of the images could have been changed during bake, - * so recreate mipmaps regardless bake result status - */ - if (ima->ok == IMA_OK_LOADED) { - if (ibuf) { - if (ibuf->userflags & IB_BITMAPDIRTY) { - GPU_free_image(ima); - imb_freemipmapImBuf(ibuf); - } - - /* invalidate display buffers for changed images */ - if (ibuf->userflags & IB_BITMAPDIRTY) - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - } - } - - /* freed when baking is done, but if its canceled we need to free here */ - if (ibuf) { - if (ibuf->userdata) { - BakeImBufuserData *userdata = (BakeImBufuserData *) ibuf->userdata; - if (userdata->mask_buffer) - MEM_freeN(userdata->mask_buffer); - if (userdata->displacement_buffer) - MEM_freeN(userdata->displacement_buffer); - MEM_freeN(userdata); - ibuf->userdata = NULL; - } - } - - BKE_image_release_ibuf(ima, ibuf, NULL); - DAG_id_tag_update(&ima->id, 0); - } - } - - if (bkr->scene->r.bake_flag & R_BAKE_VCOL) { - /* update all tagged meshes */ - Mesh *me; - BLI_assert(BLI_thread_is_main()); - for (me = bkr->main->mesh.first; me; me = me->id.next) { - if (me->id.tag & LIB_TAG_DOIT) { - DAG_id_tag_update(&me->id, OB_RECALC_DATA); - BKE_mesh_tessface_clear(me); - } - } - } - -} - -static void *do_bake_render(void *bake_v) -{ - BakeRender *bkr = bake_v; - - bkr->result = RE_bake_shade_all_selected(bkr->re, bkr->scene->r.bake_mode, bkr->actob, NULL, bkr->progress); - bkr->ready = 1; - - return NULL; -} - -static void bake_startjob(void *bkv, short *stop, short *do_update, float *progress) -{ - BakeRender *bkr = bkv; - Scene *scene = bkr->scene; - Main *bmain = bkr->main; - - bkr->stop = stop; - bkr->do_update = do_update; - bkr->progress = progress; - - RE_test_break_cb(bkr->re, NULL, thread_break); - G.is_break = false; /* BKE_blender_test_break uses this global */ - - RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob); - - /* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */ - bkr->result = RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress); -} - -static void bake_update(void *bkv) -{ - BakeRender *bkr = bkv; - - if (bkr->sa && bkr->sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */ - SpaceImage *sima = bkr->sa->spacedata.first; - if (sima) - sima->image = RE_bake_shade_get_image(); - } -} - -static void bake_freejob(void *bkv) -{ - BakeRender *bkr = bkv; - finish_bake_internal(bkr); - - if (bkr->result == BAKE_RESULT_NO_OBJECTS) - BKE_report(bkr->reports, RPT_ERROR, "No objects or images found to bake to"); - else if (bkr->result == BAKE_RESULT_FEEDBACK_LOOP) - BKE_report(bkr->reports, RPT_WARNING, "Circular reference in texture stack"); - - MEM_freeN(bkr); - G.is_rendering = false; -} - /* catch esc */ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -751,7 +596,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const static bool is_multires_bake(Scene *scene) { - if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO)) + 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; @@ -762,44 +607,7 @@ static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent Scene *scene = CTX_data_scene(C); int result = OPERATOR_CANCELLED; - if (is_multires_bake(scene)) { - result = multiresbake_image_exec(C, op); - } - else { - /* only one render job at a time */ - if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE_TEXTURE)) - return OPERATOR_CANCELLED; - - if (test_bake_internal(C, op->reports) == 0) { - return OPERATOR_CANCELLED; - } - else { - BakeRender *bkr = MEM_callocN(sizeof(BakeRender), "render bake"); - wmJob *wm_job; - - init_bake_internal(bkr, C); - bkr->reports = op->reports; - - /* 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_TEXTURE); - 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, bake_update, NULL); - - G.is_break = false; - G.is_rendering = true; - - 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); - } - - result = OPERATOR_RUNNING_MODAL; - } + result = multiresbake_image_exec(C, op); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); @@ -809,55 +617,15 @@ static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent static int bake_image_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); int result = OPERATOR_CANCELLED; - if (is_multires_bake(scene)) { - result = multiresbake_image_exec_locked(C, op); + if (!is_multires_bake(scene)) { + BLI_assert(0); + return result; } - else { - if (test_bake_internal(C, op->reports) == 0) { - return OPERATOR_CANCELLED; - } - else { - ListBase threads; - BakeRender bkr = {NULL}; - - init_bake_internal(&bkr, C); - bkr.reports = op->reports; - - RE_test_break_cb(bkr.re, NULL, thread_break); - G.is_break = false; /* BKE_blender_test_break uses this global */ - - RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL); - - /* baking itself is threaded, cannot use test_break in threads */ - BLI_threadpool_init(&threads, do_bake_render, 1); - bkr.ready = 0; - BLI_threadpool_insert(&threads, &bkr); - while (bkr.ready == 0) { - PIL_sleep_ms(50); - if (bkr.ready) - break; - - /* used to redraw in 2.4x but this is just for exec in 2.5 */ - if (!G.background) - BKE_blender_test_break(); - } - BLI_threadpool_end(&threads); - - if (bkr.result == BAKE_RESULT_NO_OBJECTS) - BKE_report(op->reports, RPT_ERROR, "No valid images found to bake to"); - else if (bkr.result == BAKE_RESULT_FEEDBACK_LOOP) - BKE_report(op->reports, RPT_ERROR, "Circular reference in texture stack"); - - finish_bake_internal(&bkr); - - result = OPERATOR_FINISHED; - } - } + result = multiresbake_image_exec_locked(C, op); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index c9be331b6d5..2f879937f7a 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -49,15 +49,19 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_report.h" -#include "BKE_modifier.h" -#include "BKE_mesh.h" +#include "BKE_scene.h" #include "BKE_screen.h" -#include "BKE_depsgraph.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -84,6 +88,7 @@ typedef struct BakeAPIRender { Object *ob; Main *main; Scene *scene; + ViewLayer *view_layer; ReportList *reports; ListBase selected_objects; @@ -272,7 +277,7 @@ static void refresh_images(BakeImages *bake_images) Image *ima = bake_images->data[i].image; if (ima->ok == IMA_OK_LOADED) { GPU_free_image(ima); - DAG_id_tag_update(&ima->id, 0); + DEG_id_tag_update(&ima->id, 0); } } } @@ -353,17 +358,24 @@ static bool is_noncolor_pass(eScenePassType pass_type) } /* if all is good tag image and return true */ -static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports) +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 ((ob->lay & scene->lay) == 0) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not on a scene layer", ob->id.name + 2); + 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; @@ -493,7 +505,7 @@ static bool bake_pass_filter_check(eScenePassType pass_type, const int pass_filt } /* before even getting in the bake function we check for some basic errors */ -static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *selected_objects, +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; @@ -504,7 +516,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase * if (is_selected_to_active) { int tot_objects = 0; - if (!bake_object_check(scene, ob, reports)) + if (!bake_object_check(view_layer, ob, reports)) return false; for (link = selected_objects->first; link; link = link->next) { @@ -532,7 +544,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase * } for (link = selected_objects->first; link; link = link->next) { - if (!bake_object_check(scene, link->ptr.data, reports)) + if (!bake_object_check(view_layer, link->ptr.data, reports)) return false; } } @@ -619,11 +631,11 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob) +static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob) { ED_object_editmode_load(bmain, ob); - Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0); + Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, 1, 0); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); } @@ -632,7 +644,8 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob) } static int bake( - Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, + 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, @@ -640,6 +653,8 @@ static int bake( const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { + Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); + int op_result = OPERATOR_CANCELLED; bool ok = false; @@ -777,12 +792,16 @@ static int bake( mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires); if (mmd_low) { mmd_flags_low = mmd_low->flags; - mmd_low->flags |= eMultiresModifierFlag_PlainUv; + mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE; } } + /* Make sure depsgraph is up to date. */ + DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); + BKE_scene_graph_update_tagged(depsgraph, bmain); + /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(bmain, scene, ob_low); + me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) @@ -797,7 +816,7 @@ static int bake( /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(bmain, scene, ob_cage); + me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage); 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 " @@ -829,7 +848,7 @@ static int bake( ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ - me_cage = bake_mesh_new_from_object(bmain, scene, ob_low); + me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -855,7 +874,7 @@ static int bake( tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; - highpoly[i].me = bake_mesh_new_from_object(bmain, scene, highpoly[i].ob); + highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; /* lowpoly to highpoly transformation matrix */ @@ -882,7 +901,7 @@ static int bake( /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { - ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, + 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); @@ -909,7 +928,7 @@ cage_cleanup: ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) { - ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result); + ok = RE_bake_engine(re, depsgraph, ob_low, 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"); @@ -958,7 +977,7 @@ cage_cleanup: md->mode &= ~eModifierMode_Render; } - me_nores = bake_mesh_new_from_object(bmain, scene, ob_low); + me_nores = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low); 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->obmat); @@ -1110,6 +1129,8 @@ cleanup: if (me_cage) BKE_libblock_free(bmain, me_cage); + DEG_graph_free(depsgraph); + return op_result; } @@ -1120,6 +1141,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) 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; @@ -1190,7 +1212,7 @@ static int bake_exec(bContext *C, wmOperator *op) goto finally; } - if (!bake_objects_check(bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { + if (!bake_objects_check(bkr.main, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { goto finally; } @@ -1203,7 +1225,7 @@ static int bake_exec(bContext *C, wmOperator *op) if (bkr.is_selected_to_active) { result = bake( - bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, + 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, @@ -1216,7 +1238,7 @@ static int bake_exec(bContext *C, wmOperator *op) for (link = bkr.selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; result = bake( - bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports, + 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, @@ -1249,7 +1271,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa return; } - if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { + 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; } @@ -1261,7 +1283,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa if (bkr->is_selected_to_active) { bkr->result = bake( - bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, + 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, @@ -1274,7 +1296,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa 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, ob_iter, NULL, bkr->reports, + 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, diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c new file mode 100644 index 00000000000..57f1ad7dea1 --- /dev/null +++ b/source/blender/editors/object/object_collection.c @@ -0,0 +1,600 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_collection.c + * \ingroup edobj + */ + + +#include <string.h> + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_collection_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_collection.h" +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_library_remap.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "ED_screen.h" +#include "ED_object.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "object_intern.h" + +/********************* 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) +{ + Main *bmain = CTX_data_main(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, 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, 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, Object *ob, const int collection_object_index) +{ + Collection *collection = NULL; + int i = 0; + while ((collection = BKE_collection_object_find(bmain, 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); + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index); + Collection *collection; + bool is_cycle = false; + bool updated = false; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + /* now add all selected objects to the collection(s) */ + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + 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, DEG_TAG_COPY_ON_WRITE); + updated = true; + } + else { + is_cycle = true; + } + } + CTX_DATA_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; +} + +static int objects_remove_active_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(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, ob, single_collection_index); + Collection *collection; + 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 */ + + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + 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, DEG_TAG_COPY_ON_WRITE); + ok = 1; + } + CTX_DATA_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; +} + +static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + BKE_object_groups_clear(bmain, base->object); + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + 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"; + + /* api callbacks */ + ot->exec = collection_objects_remove_all_exec; + ot->poll = ED_operator_objectmode; + + /* 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); + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index); + Collection *collection; + bool updated = false; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + 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, DEG_TAG_COPY_ON_WRITE); + updated = true; + } + CTX_DATA_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; +} + +static int collection_create_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + char name[MAX_ID_NAME - 2]; /* id name */ + + RNA_string_get(op->ptr, "name", name); + + 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, DEG_TAG_COPY_ON_WRITE); + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + 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"; + + /* api callbacks */ + ot->exec = collection_create_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + 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); + + 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); + + DEG_id_tag_update(&collection->id, DEG_TAG_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_add(wmOperatorType *ot) +{ + /* 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; + + /* 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->collection, 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, DEG_TAG_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; +} + +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; + + if (!ob || !collection) + return OPERATOR_CANCELLED; + + BKE_collection_object_remove(bmain, collection, ob, false); + + DEG_id_tag_update(&collection->id, DEG_TAG_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_remove(wmOperatorType *ot) +{ + /* 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; + + /* 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; + + if (!collection) + return OPERATOR_CANCELLED; + + BKE_libblock_delete(bmain, collection); + + DEG_relations_tag_update(bmain); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + 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"; + + /* api callbacks */ + ot->exec = collection_unlink_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same collection as the active */ +{ + 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; + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + 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"; + + /* api callbacks */ + ot->exec = select_grouped_exec; + ot->poll = ED_operator_objectmode; + + /* 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 70d3d856599..4aedd6a55d4 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -53,7 +53,6 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_main.h" @@ -62,6 +61,9 @@ #include "BKE_tracking.h" #include "BIK_api.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -428,6 +430,11 @@ static void test_constraint(Main *bmain, Object *owner, bPoseChannel *pchan, bCo 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) */ @@ -471,6 +478,18 @@ static void test_constraint(Main *bmain, Object *owner, bPoseChannel *pchan, bCo } } } + 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 */ @@ -596,6 +615,11 @@ static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type) 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; + } + return 1; } @@ -606,8 +630,11 @@ static bool edit_constraint_poll(bContext *C) static void edit_constraint_properties(wmOperatorType *ot) { - RNA_def_string(ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit"); - RNA_def_enum(ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint"); + 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) @@ -775,8 +802,10 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) /* ------------- Child-Of Constraint ------------------ */ -static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, float invmat[4][4], const int owner) +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); @@ -802,7 +831,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, * to use as baseline ("pmat") to derive delta from. This extra calc saves users * from having pressing "Clear Inverse" first */ - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); copy_m4_m4(pmat, pchan->pose_mat); /* 2. knock out constraints starting from this one */ @@ -819,7 +848,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, } /* 3. solve pose without disabled constraints */ - BKE_pose_where_is(scene, ob); + 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 @@ -842,7 +871,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, } /* 6. recalculate pose with new inv-mat applied */ - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); } } if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { @@ -853,7 +882,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, 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(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(invmat, workob.obmat); } } @@ -875,7 +904,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(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); @@ -986,7 +1015,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) { /* create F-Curve for path animation */ act = verify_adt_action(bmain, &cu->id, 1); - fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1); + fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1); /* standard vertical range - 1:1 = 100 frames */ standardRange = 100.0f; @@ -1011,7 +1040,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) /* create F-Curve for constraint */ act = verify_adt_action(bmain, &ob->id, 1); - fcu = verify_fcurve(act, NULL, NULL, path, 0, 1); + fcu = verify_fcurve(bmain, act, NULL, NULL, path, 0, 1); /* standard vertical range - 0.0 to 1.0 */ standardRange = 1.0f; @@ -1098,7 +1127,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(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); @@ -1199,9 +1228,9 @@ void ED_object_constraint_update(Main *bmain, Object *ob) object_test_constraints(bmain, ob); if (ob->type == OB_ARMATURE) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); else - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } static void object_pose_tag_update(Main *bmain, Object *ob) @@ -1224,7 +1253,7 @@ void ED_object_constraint_dependency_update(Main *bmain, Object *ob) if (ob->pose) { object_pose_tag_update(bmain, ob); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } void ED_object_constraint_tag_update(Main *bmain, Object *ob, bConstraint *con) @@ -1233,12 +1262,19 @@ void ED_object_constraint_tag_update(Main *bmain, Object *ob, bConstraint *con) BKE_pose_tag_update_constraint_flags(ob->pose); } - object_test_constraint(bmain, ob, con); + if (con) { + object_test_constraint(bmain, ob, con); + } if (ob->type == OB_ARMATURE) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); else - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); + + /* Do Copy-on-Write tag here too, otherwise constraint + * influence/mute buttons in UI have no effect + */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con) @@ -1248,7 +1284,7 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr if (ob->pose) { object_pose_tag_update(bmain, ob); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } static bool constraint_poll(bContext *C) @@ -1273,7 +1309,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) ED_object_constraint_update(bmain, ob); /* needed to set the flags on posebones correctly */ /* relatiols */ - DAG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(CTX_data_main(C)); /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); @@ -1404,25 +1440,27 @@ 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 *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + Object *prev_ob = NULL; /* free constraints for all selected bones */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_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, OB_RECALC_DATA); + 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 */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); /* note, calling BIK_clear_data() isn't needed here */ - /* do updates */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); - return OPERATOR_FINISHED; } @@ -1447,12 +1485,12 @@ static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { BKE_constraints_free(&ob->constraints); - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; /* force depsgraph to get recalculated since relationships removed */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); /* do updates */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, NULL); @@ -1478,8 +1516,6 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); bPoseChannel *pchan = CTX_data_active_pose_bone(C); - ListBase lb; - CollectionPointerLink *link; /* don't do anything if bone doesn't exist or doesn't have any constraints */ if (ELEM(NULL, pchan, pchan->constraints.first)) { @@ -1487,26 +1523,28 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* copy all constraints from active posebone to all selected posebones */ - CTX_data_selected_pose_bones(C, &lb); - for (link = lb.first; link; link = link->next) { - Object *ob = link->ptr.id.data; - bPoseChannel *chan = link->ptr.data; + 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; - BKE_pose_tag_recalc(bmain, ob->pose); - DAG_id_tag_update((ID *)ob, OB_RECALC_DATA); + if (prev_ob != ob) { + BKE_pose_tag_recalc(bmain, ob->pose); + DEG_id_tag_update((ID *)ob, OB_RECALC_DATA); + prev_ob = ob; + } } } - BLI_freelistN(&lb); + CTX_DATA_END; /* force depsgraph to get recalculated since new relationships added */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); @@ -1539,13 +1577,13 @@ static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op)) /* 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); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } CTX_DATA_END; /* force depsgraph to get recalculated since new relationships added */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL); @@ -1615,17 +1653,12 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob only_ob = true; add = false; break; - - /* object only - add here is ok? */ - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - only_ob = true; - 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) + 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) { @@ -1686,16 +1719,12 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Base *base = BASACT, *newbase = NULL; + 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, OB_EMPTY, NULL); - - /* set layers OK */ - newbase = BASACT; - newbase->lay = base->lay; - obt->lay = newbase->lay; + obt = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); /* transform cent to global coords for loc */ if (pchanact) { @@ -1712,8 +1741,8 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob } /* restore, BKE_object_add sets active */ - BASACT = base; - base->flag |= SELECT; + BASACT(view_layer) = base; + base->flag |= BASE_SELECTED; /* make our new target the new object */ *tar_ob = obt; @@ -1747,10 +1776,6 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase if (type == CONSTRAINT_TYPE_NULL) { return OPERATOR_CANCELLED; } - if ((type == CONSTRAINT_TYPE_RIGIDBODYJOINT) && (list != &ob->constraints)) { - BKE_report(op->reports, RPT_ERROR, "Rigid Body Joint constraint can only be added to objects"); - 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; @@ -1821,7 +1846,7 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase /* force depsgraph to get recalculated since new relationships added */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); if ((ob->type == OB_ARMATURE) && (pchan)) { BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */ @@ -1831,10 +1856,10 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase * XXX Temp hack until new depsgraph hopefully solves this. */ ob->adt->recalc |= ADT_RECALC_ANIM; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB); } else - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob); @@ -2055,10 +2080,10 @@ 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 *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + Object *prev_ob = NULL; /* only remove IK Constraints */ - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) + CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) { bConstraint *con, *next; @@ -2070,14 +2095,18 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op)) } } pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET); - } - CTX_DATA_END; - /* refresh depsgraph */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + if (prev_ob != ob) { + prev_ob = ob; + + /* Refresh depsgraph. */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + /* Note, notifier might evolve. */ + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + } + } + CTX_DATA_END; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 91081345069..7b65d4c4f47 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -40,13 +40,14 @@ #include "BKE_context.h" #include "BKE_data_transfer.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -95,13 +96,14 @@ static const EnumPropertyItem *dt_layers_select_src_itemf( { EnumPropertyItem *item = NULL, tmp_item = {0}; int totitem = 0; - const int data_type = RNA_enum_get(ptr, "data_type"); if (!C) { /* needed for docs and i18n tools */ return rna_enum_dt_layers_select_src_items; } + Depsgraph *depsgraph = CTX_data_depsgraph(C); + 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); @@ -134,20 +136,17 @@ static const EnumPropertyItem *dt_layers_select_src_itemf( Scene *scene = CTX_data_scene(C); if (ob_src) { - DerivedMesh *dm_src; - CustomData *pdata; + Mesh *me_eval; int num_data, i; - /* XXX Is this OK? */ - dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY); - pdata = dm_src->getPolyDataLayout(dm_src); - num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPUV); + 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(pdata, CD_MTEXPOLY, 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); } } @@ -157,20 +156,17 @@ static const EnumPropertyItem *dt_layers_select_src_itemf( Scene *scene = CTX_data_scene(C); if (ob_src) { - DerivedMesh *dm_src; - CustomData *ldata; + Mesh *me_eval; int num_data, i; - /* XXX Is this OK? */ - dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); - ldata = dm_src->getLoopDataLayout(dm_src); - num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); + 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(ldata, CD_MLOOPCOL, 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); } } @@ -344,6 +340,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob_src = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ListBase ctx_objects; CollectionPointerLink *ctx_ob_dst; @@ -412,7 +409,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op) } if (BKE_object_data_transfer_mesh( - scene, ob_src, ob_dst, data_type, use_create, + depsgraph, scene, ob_src, 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, @@ -423,7 +420,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op) } } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); if (reverse_transfer) { SWAP(Object *, ob_src, ob_dst); @@ -534,7 +531,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) ot->check = data_transfer_check; /* Flags.*/ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; /* Properties.*/ prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer", @@ -610,6 +607,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob_act = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); DataTransferModifierData *dtmd; dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer); @@ -626,10 +624,10 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete, + BKE_object_data_transfer_layout(depsgraph, scene, ob_src, ob_dst, dtmd->data_types, use_delete, dtmd->layers_select_src, dtmd->layers_select_dst); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } else { Object *ob_src = ob_act; @@ -656,11 +654,11 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) 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(scene, ob_src, ob_dst, data_type, use_delete, + BKE_object_data_transfer_layout(depsgraph, scene, ob_src, ob_dst, data_type, use_delete, layers_select_src, layers_select_dst); } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } BLI_freelistN(&ctx_objects); @@ -696,7 +694,7 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot) ot->check = data_transfer_check; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; /* Properties.*/ edit_modifier_properties(ot); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index fc967dc424e..2723198b279 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -46,12 +46,11 @@ #include "BLT_translation.h" #include "DNA_armature_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_gpencil_types.h" -#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_meta_types.h" -#include "DNA_property_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_object_force_types.h" @@ -59,33 +58,37 @@ #include "DNA_vfont_types.h" #include "DNA_mesh_types.h" #include "DNA_lattice_types.h" +#include "DNA_workspace_types.h" #include "IMB_imbuf_types.h" #include "BKE_anim.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_editlattice.h" #include "BKE_effect.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_pointcache.h" -#include "BKE_property.h" -#include "BKE_sca.h" #include "BKE_softbody.h" -#include "BKE_modifier.h" -#include "BKE_editlattice.h" #include "BKE_editmesh.h" #include "BKE_report.h" -#include "BKE_undo_system.h" +#include "BKE_workspace.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "ED_armature.h" #include "ED_curve.h" @@ -93,9 +96,11 @@ #include "ED_mball.h" #include "ED_lattice.h" #include "ED_object.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_undo.h" #include "ED_image.h" +#include "ED_gpencil.h" #include "RNA_access.h" #include "RNA_define.h" @@ -104,11 +109,19 @@ /* for menu/popup icons etc etc*/ #include "UI_interface.h" +#include "UI_resources.h" + #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" +#include "WM_toolsystem.h" #include "object_intern.h" // own include +/* prototypes */ +typedef struct MoveToCollectionData MoveToCollectionData; +static void move_to_collection_menus_items(struct uiLayout *layout, struct MoveToCollectionData *menu); + /* ************* XXX **************** */ static void error(const char *UNUSED(arg)) {} static void waitcursor(int UNUSED(val)) {} @@ -134,95 +147,109 @@ Object *ED_object_active_context(bContext *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); + } +} -/* ********* clear/set restrict view *********/ static int object_hide_view_clear_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; Scene *scene = CTX_data_scene(C); - Base *base; - bool changed = false; + ViewLayer *view_layer = CTX_data_view_layer(C); const bool select = RNA_boolean_get(op->ptr, "select"); + bool changed = false; - /* XXX need a context loop to handle such cases */ - for (base = FIRSTBASE; base; base = base->next) { - if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) { - if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) { - SET_FLAG_FROM_TEST(base->flag, select, SELECT); - } - base->object->flag = base->flag; - base->object->restrictflag &= ~OB_RESTRICT_VIEW; + 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) { + ED_object_base_select(base, BA_SELECT); + } } } - if (changed) { - DAG_id_type_tag(bmain, ID_OB); - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + + if (!changed) { + return OPERATOR_CANCELLED; } + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE); + 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 = "Clear Restrict View"; - ot->description = "Reveal the object by setting the hide flag"; + 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 = ED_operator_view3d_active; + ot->poll = object_hide_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "select", true, "Select", ""); + PropertyRNA *prop = RNA_def_boolean(ot->srna, "select", false, "Select", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } static int object_hide_view_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - bool changed = false; + ViewLayer *view_layer = CTX_data_view_layer(C); const bool unselected = RNA_boolean_get(op->ptr, "unselected"); - CTX_DATA_BEGIN(C, Base *, base, visible_bases) - { + /* Do nothing if no objects was selected. */ + bool have_selected = false; + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->flag & BASE_VISIBLE) { + if (base->flag & BASE_SELECTED) { + have_selected = true; + break; + } + } + } + + if (!have_selected) { + return OPERATOR_CANCELLED; + } + + /* 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 & SELECT) { - base->flag &= ~SELECT; - base->object->flag = base->flag; - base->object->restrictflag |= OB_RESTRICT_VIEW; - changed = true; - if (base == BASACT) { - ED_base_object_activate(C, NULL); - } + if (base->flag & BASE_SELECTED) { + ED_object_base_select(base, BA_DESELECT); + base->flag |= BASE_HIDDEN; } } else { - if (!(base->flag & SELECT)) { - base->object->restrictflag |= OB_RESTRICT_VIEW; - changed = true; - if (base == BASACT) { - ED_base_object_activate(C, NULL); - } + if (!(base->flag & BASE_SELECTED)) { + ED_object_base_select(base, BA_DESELECT); + base->flag |= BASE_HIDDEN; } } } - CTX_DATA_END; - if (changed) { - DAG_id_type_tag(bmain, ID_OB); - DAG_relations_tag_update(bmain); - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - - } + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } @@ -230,95 +257,136 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op) void OBJECT_OT_hide_view_set(wmOperatorType *ot) { /* identifiers */ - ot->name = "Set Restrict View"; - ot->description = "Hide the object by setting the hide flag"; + 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 = ED_operator_view3d_active; + ot->poll = object_hide_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); - + 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); } -/* 99% same as above except no need for scene refreshing (TODO, update render preview) */ -static int object_hide_render_clear_exec(bContext *C, wmOperator *UNUSED(op)) +static int object_hide_collection_exec(bContext *C, wmOperator *op) { - bool changed = false; + wmWindow *win = CTX_wm_window(C); - /* XXX need a context loop to handle such cases */ - CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) - { - if (ob->restrictflag & OB_RESTRICT_RENDER) { - ob->restrictflag &= ~OB_RESTRICT_RENDER; - changed = true; - } + 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; } - CTX_DATA_END; - if (changed) - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + 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; + } + + BKE_layer_collection_set_visible(scene, view_layer, lc, extend); + + DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } -void OBJECT_OT_hide_render_clear(wmOperatorType *ot) +#define COLLECTION_INVALID_INDEX -1 + +void ED_hide_collections_menu_draw(const bContext *C, uiLayout *layout) { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *lc_scene = view_layer->layer_collections.first; - /* identifiers */ - ot->name = "Clear Restrict Render"; - ot->description = "Reveal the render object by setting the hide render flag"; - ot->idname = "OBJECT_OT_hide_render_clear"; + uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); - /* api callbacks */ - ot->exec = object_hide_render_clear_exec; - ot->poll = ED_operator_view3d_active; + 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); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } -static int object_hide_render_set_exec(bContext *C, wmOperator *op) -{ - const bool unselected = RNA_boolean_get(op->ptr, "unselected"); + if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { + continue; + } - CTX_DATA_BEGIN(C, Base *, base, visible_bases) - { - if (!unselected) { - if (base->flag & SELECT) { - base->object->restrictflag |= OB_RESTRICT_RENDER; - } + if ((view_layer->runtime_flag & VIEW_LAYER_HAS_HIDE) && + !(lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS)) + { + uiLayoutSetActive(row, false); } - else { - if (!(base->flag & SELECT)) { - base->object->restrictflag |= OB_RESTRICT_RENDER; - } + + 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); } - CTX_DATA_END; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - return OPERATOR_FINISHED; } -void OBJECT_OT_hide_render_set(wmOperatorType *ot) +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); + } + + /* 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_hide_collections_menu_draw(C, layout); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + +void OBJECT_OT_hide_collection(wmOperatorType *ot) { /* identifiers */ - ot->name = "Set Restrict Render"; - ot->description = "Hide the render object by setting the hide render flag"; - ot->idname = "OBJECT_OT_hide_render_set"; + ot->name = "Hide Objects By Collection"; + ot->description = "Show only objects in collection (Shift to extend)"; + ot->idname = "OBJECT_OT_hide_collection"; /* api callbacks */ - ot->exec = object_hide_render_set_exec; + 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; - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects"); + /* 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 ***************** */ @@ -391,7 +459,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f * to inform dependency graph about this. But is it really the * best place to do this? */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { const Curve *cu = obedit->data; @@ -455,8 +523,8 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f 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(scene->basact && (scene->basact->object->mode & OB_MODE_EDIT))) { - scene->basact->object->mode &= ~OB_MODE_EDIT; + if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { + obedit->mode &= ~OB_MODE_EDIT; } if (flag & EM_WAITCURSOR) waitcursor(0); return true; @@ -467,11 +535,8 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f ListBase pidlist; PTCacheID *pid; - /* for example; displist make is different in editmode */ - scene->obedit = NULL; // XXX for context - /* flag object caches as outdated */ - BKE_ptcache_ids_from_object(bmain, &pidlist, obedit, scene, 0); + BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); for (pid = pidlist.first; pid; pid = pid->next) { if (pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */ pid->cache->flag |= PTCACHE_OUTDATED; @@ -481,7 +546,7 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED); /* also flush ob recalc, doesn't take much overhead, but used for particles */ - DAG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA); WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); @@ -501,43 +566,14 @@ bool ED_object_editmode_exit(bContext *C, int flag) return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); } -bool ED_object_editmode_enter(bContext *C, int flag) +bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Base *base = NULL; - Object *ob; - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = NULL; bool ok = false; - if (ID_IS_LINKED(scene)) { + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob)) { return false; } - if (sa && sa->spacetype == SPACE_VIEW3D) - v3d = sa->spacedata.first; - - if ((flag & EM_IGNORE_LAYER) == 0) { - base = CTX_data_active_base(C); /* active layer checked here for view3d */ - - if ((base == NULL) || - (v3d && (base->lay & v3d->lay) == 0) || - (!v3d && (base->lay & scene->lay) == 0)) - { - return false; - } - } - else { - base = scene->basact; - } - - if (ELEM(NULL, base, base->object, base->object->data)) { - return false; - } - - ob = base->object; - /* this checks actual object->data, for cases when other scenes have it in editmode context */ if (BKE_object_is_in_editmode(ob)) { return true; @@ -552,17 +588,11 @@ bool ED_object_editmode_enter(bContext *C, int flag) ob->restore_mode = ob->mode; - /* note, when switching scenes the object can have editmode data but - * not be scene->obedit: bug 22954, this avoids calling self eternally */ - if ((ob->restore_mode & OB_MODE_EDIT) == 0) - ED_object_mode_toggle(C, ob->mode); - ob->mode = OB_MODE_EDIT; if (ob->type == OB_MESH) { BMEditMesh *em; ok = 1; - scene->obedit = ob; /* context sees this */ const bool use_key_index = mesh_needs_keyindex(bmain, ob->data); @@ -575,53 +605,49 @@ bool ED_object_editmode_enter(bContext *C, int flag) BKE_editmesh_tessface_calc(em); } - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MESH, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL); } else if (ob->type == OB_ARMATURE) { ok = 1; - scene->obedit = ob; ED_armature_to_edit(ob->data); /* to ensure all goes in restposition and without striding */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */ + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */ - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene); } else if (ob->type == OB_FONT) { - scene->obedit = ob; /* XXX for context */ ok = 1; ED_curve_editfont_make(ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); } else if (ob->type == OB_MBALL) { - scene->obedit = ob; /* XXX for context */ ok = 1; ED_mball_editmball_make(ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); } else if (ob->type == OB_LATTICE) { - scene->obedit = ob; /* XXX for context */ ok = 1; BKE_editlattice_make(ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene); } else if (ob->type == OB_SURF || ob->type == OB_CURVE) { ok = 1; - scene->obedit = ob; /* XXX for context */ ED_curve_editnurb_make(ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene); + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene); } if (ok) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { - scene->obedit = NULL; /* XXX for context */ - ob->mode &= ~OB_MODE_EDIT; - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); + if ((flag & EM_NO_CONTEXT) == 0) { + ob->mode &= ~OB_MODE_EDIT; + } + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); } if (flag & EM_WAITCURSOR) waitcursor(0); @@ -629,28 +655,75 @@ bool ED_object_editmode_enter(bContext *C, int flag) return (ob->mode & OB_MODE_EDIT) != 0; } -static int editmode_toggle_exec(bContext *C, wmOperator *op) +bool ED_object_editmode_enter(bContext *C, int flag) { Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob; + + if ((flag & EM_IGNORE_LAYER) == 0) { + ob = CTX_data_active_object(C); /* active layer checked here for view3d */ + } + else { + ob = view_layer->basact->object; + } + 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) { - Object *ob = CTX_data_active_object(C); - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { return OPERATOR_CANCELLED; } } if (!is_mode_set) { ED_object_editmode_enter(C, EM_WAITCURSOR); + 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_WAITCURSOR | EM_NO_CONTEXT); + } + } + FOREACH_SELECTED_OBJECT_END; + } } else { ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); + 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 | EM_WAITCURSOR); + } + } + 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; } @@ -663,8 +736,9 @@ static bool editmode_toggle_poll(bContext *C) return 0; /* if hidden but in edit mode, we still display */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) + if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { return 0; + } return OB_TYPE_SUPPORT_EDITMODE(ob->type); } @@ -689,34 +763,71 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) static int posemode_exec(bContext *C, wmOperator *op) { + struct wmMsgBus *mbus = CTX_wm_message_bus(C); Base *base = CTX_data_active_base(C); - Object *ob = base->object; + Object *obact = base->object; const int mode_flag = OB_MODE_POSE; - bool is_mode_set = (ob->mode & mode_flag) != 0; + bool is_mode_set = (obact->mode & mode_flag) != 0; if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) { return OPERATOR_CANCELLED; } } - if (ob->type == OB_ARMATURE) { - if (ob == CTX_data_edit_object(C)) { - ED_object_editmode_exit(C, EM_FREEDATA); - is_mode_set = false; - } + 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) { - ED_object_posemode_exit(C, ob); + 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 { - ED_object_posemode_enter(C, ob); + } + 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; } + } - return OPERATOR_FINISHED; + WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode); + + if (G.background == false) { + WM_toolsystem_update_from_context_view3d(C); } - return OPERATOR_PASS_THROUGH; + return OPERATOR_FINISHED; } void OBJECT_OT_posemode_toggle(wmOperatorType *ot) @@ -734,102 +845,6 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob) -{ -//XXX no longer used - to be removed - replaced by game_properties_copy_exec - bProperty *prop; - Base *base; - int nr, tot = 0; - char *str; - - prop = ob->prop.first; - while (prop) { - tot++; - prop = prop->next; - } - - str = MEM_callocN(50 + 33 * tot, "copymenu prop"); - - if (tot) - strcpy(str, "Copy Property %t|Replace All|Merge All|%l"); - else - strcpy(str, "Copy Property %t|Clear All (no properties on active)"); - - tot = 0; - prop = ob->prop.first; - while (prop) { - tot++; - strcat(str, "|"); - strcat(str, prop->name); - prop = prop->next; - } - - nr = pupmenu(str); - - if (nr == 1 || nr == 2) { - for (base = FIRSTBASE; base; base = base->next) { - if ((base != BASACT) && (TESTBASELIB(v3d, base))) { - if (nr == 1) { /* replace */ - BKE_bproperty_copy_list(&base->object->prop, &ob->prop); - } - else { - for (prop = ob->prop.first; prop; prop = prop->next) { - BKE_bproperty_object_set(base->object, prop); - } - } - } - } - } - else if (nr > 0) { - prop = BLI_findlink(&ob->prop, nr - 4); /* account for first 3 menu items & menu index starting at 1*/ - - if (prop) { - for (base = FIRSTBASE; base; base = base->next) { - if ((base != BASACT) && (TESTBASELIB(v3d, base))) { - BKE_bproperty_object_set(base->object, prop); - } - } - } - } - MEM_freeN(str); - -} - -static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob) -{ -//XXX no longer used - to be removed - replaced by logicbricks_copy_exec - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->object != ob) { - if (TESTBASELIB(v3d, base)) { - - /* first: free all logic */ - free_sensors(&base->object->sensors); - unlink_controllers(&base->object->controllers); - free_controllers(&base->object->controllers); - unlink_actuators(&base->object->actuators); - free_actuators(&base->object->actuators); - - /* now copy it, this also works without logicbricks! */ - clear_sca_new_poins_ob(ob); - copy_sensors(&base->object->sensors, &ob->sensors, 0); - copy_controllers(&base->object->controllers, &ob->controllers, 0); - copy_actuators(&base->object->actuators, &ob->actuators, 0); - set_sca_new_poins_ob(base->object); - - /* some menu settings */ - base->object->scavisflag = ob->scavisflag; - base->object->scaflag = ob->scaflag; - - /* set the initial state */ - base->object->state = ob->state; - base->object->init_state = ob->init_state; - } - } - } -} - /* both pointers should exist */ static void copy_texture_space(Object *to, Object *ob) { @@ -881,40 +896,32 @@ static void copy_texture_space(Object *to, Object *ob) } /* UNUSED, keep in case we want to copy functionality for use elsewhere */ -static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) +static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, short event) { Object *ob; Base *base; Curve *cu, *cu1; Nurb *nu; - bool do_depgraph_update = false; if (ID_IS_LINKED(scene)) return; - if (!(ob = OBACT)) return; + if (!(ob = OBACT(view_layer))) return; - if (scene->obedit) { // XXX get from context + if (BKE_object_is_in_editmode(ob)) { /* obedit_copymenu(); */ return; } - if (event == 9) { - copymenu_properties(scene, v3d, ob); - return; - } - else if (event == 10) { - copymenu_logicbricks(scene, v3d, ob); - return; - } - else if (event == 24) { + + if (event == 24) { /* moved to BKE_object_link_modifiers */ /* copymenu_modifiers(bmain, scene, v3d, ob); */ return; } - for (base = FIRSTBASE; base; base = base->next) { - if (base != BASACT) { + for (base = FIRSTBASE(view_layer); base; base = base->next) { + if (base != BASACT(view_layer)) { if (TESTBASELIB(v3d, base)) { - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); if (event == 1) { /* loc */ copy_v3_v3(base->object->loc, ob->loc); @@ -953,30 +960,6 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) if (ob->dup_group) id_us_plus(&ob->dup_group->id); } - else if (event == 7) { /* mass */ - base->object->mass = ob->mass; - } - else if (event == 8) { /* damping */ - base->object->damping = ob->damping; - base->object->rdamping = ob->rdamping; - } - else if (event == 11) { /* all physical attributes */ - base->object->gameflag = ob->gameflag; - base->object->inertia = ob->inertia; - base->object->formfactor = ob->formfactor; - base->object->damping = ob->damping; - base->object->rdamping = ob->rdamping; - base->object->min_vel = ob->min_vel; - base->object->max_vel = ob->max_vel; - base->object->min_angvel = ob->min_angvel; - base->object->max_angvel = ob->max_angvel; - if (ob->gameflag & OB_BOUNDS) { - base->object->collision_boundtype = ob->collision_boundtype; - } - base->object->margin = ob->margin; - base->object->bsoft = copy_bulletsoftbody(ob->bsoft, 0); - - } else if (event == 17) { /* tex space */ copy_texture_space(base->object, ob); } @@ -1017,7 +1000,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) BLI_strncpy(cu1->family, cu->family, sizeof(cu1->family)); - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } } else if (event == 19) { /* bevel settings */ @@ -1033,7 +1016,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) cu1->ext1 = cu->ext1; cu1->ext2 = cu->ext2; - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } } else if (event == 25) { /* curve resolution */ @@ -1052,7 +1035,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) nu = nu->next; } - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } } else if (event == 21) { @@ -1068,25 +1051,26 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) } modifier_copyData(md, tmd); - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); + DEG_id_tag_update(&base->object->id, OB_RECALC_DATA); } } } else if (event == 22) { /* Copy the constraint channels over */ BKE_constraints_copy(&base->object->constraints, &ob->constraints, true); - - do_depgraph_update = true; + DEG_id_tag_update(&base->object->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } else if (event == 23) { - base->object->softflag = ob->softflag; - if (base->object->soft) sbFree(base->object->soft); - - base->object->soft = copy_softbody(ob->soft, 0); + sbFree(base->object); + BKE_object_copy_softbody(base->object, ob, 0); if (!modifiers_findByType(base->object, eModifierType_Softbody)) { BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody)); } + + DEG_id_tag_update(&base->object->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } else if (event == 26) { #if 0 // XXX old animation system @@ -1127,20 +1111,17 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) } } } - - if (do_depgraph_update) - DAG_relations_tag_update(bmain); } -static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D *v3d) +static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, Object *obedit) { Object *ob; short event; char str[512]; - if (!(ob = OBACT)) return; + if (!(ob = OBACT(view_layer))) return; - if (scene->obedit) { /* XXX get from context */ + if (obedit) { /* if (ob->type == OB_MESH) */ /* XXX mesh_copy_menu(); */ return; @@ -1186,7 +1167,7 @@ static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D * event = pupmenu(str); if (event <= 0) return; - copy_attr(bmain, scene, v3d, event); + copy_attr(bmain, scene, view_layer, v3d, event); } /* ******************* force field toggle operator ***************** */ @@ -1253,9 +1234,15 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot) * * To be called from various tools that do incremental updates */ -void ED_objects_recalculate_paths(bContext *C, Scene *scene) +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 */ @@ -1268,8 +1255,20 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene) CTX_DATA_END; /* recalculate paths, then free */ - animviz_calc_motionpaths(bmain, scene, &targets); + 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, DEG_TAG_COPY_ON_WRITE); + } + } + CTX_DATA_END; + } } @@ -1291,7 +1290,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv /* show popup dialog to allow editing of range... */ /* FIXME: hardcoded dimensions here are just arbitrary */ - return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y); + return WM_operator_props_dialog_popup(C, op, 200, 200); } /* Calculate/recalculate whole paths (avs.path_sf to avs.path_ef) */ @@ -1316,7 +1315,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene); + ED_objects_recalculate_paths(C, scene, false); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1366,7 +1365,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene); + ED_objects_recalculate_paths(C, scene, false); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1398,6 +1397,9 @@ static void object_clear_mpath(Object *ob) 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, DEG_TAG_COPY_ON_WRITE); } } @@ -1466,6 +1468,43 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot) 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, DEG_TAG_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"; + + /* callbacks */ + ot->exec = object_update_paths_range_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /********************** Smooth/Flat *********************/ @@ -1489,7 +1528,8 @@ static int shade_smooth_exec(bContext *C, wmOperator *op) if (ob->type == OB_MESH) { BKE_mesh_smooth_flag_set(ob, !clear); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); done = true; @@ -1502,7 +1542,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op) else nu->flag &= ~ME_SMOOTH; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); done = true; @@ -1553,75 +1593,12 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) /* ********************** */ -static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) -{ - /* all selected objects with an image map: scale in image aspect */ - Base *base; - Object *ob; - Material *ma; - Tex *tex; - float x, y, space; - int a, b, done; - - if (scene->obedit) return; // XXX get from context - if (ID_IS_LINKED(scene)) return; - - for (base = FIRSTBASE; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { - ob = base->object; - done = false; - - for (a = 1; a <= ob->totcol; a++) { - ma = give_current_material(ob, a); - if (ma) { - for (b = 0; b < MAX_MTEX; b++) { - if (ma->mtex[b] && ma->mtex[b]->tex) { - tex = ma->mtex[b]->tex; - if (tex->type == TEX_IMAGE && tex->ima) { - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, NULL, NULL); - - /* texturespace */ - space = 1.0; - if (ob->type == OB_MESH) { - float size[3]; - BKE_mesh_texspace_get(ob->data, NULL, NULL, size); - space = size[0] / size[1]; - } - else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { - float size[3]; - BKE_curve_texspace_get(ob->data, NULL, NULL, size); - space = size[0] / size[1]; - } - - x = ibuf->x / space; - y = ibuf->y; - - if (x > y) ob->size[0] = ob->size[1] * x / y; - else ob->size[1] = ob->size[0] * y / x; - - done = true; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); - - BKE_image_release_ibuf(tex->ima, ibuf, NULL); - } - } - if (done) break; - } - } - if (done) break; - } - } - } - -} - 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; - bGPdata *gpd; int totitem = 0; if (!C) /* needed for docs */ @@ -1637,7 +1614,9 @@ static const EnumPropertyItem *object_mode_set_itemsf( (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)) || + OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || + (ELEM(input->value, OB_MODE_GPENCIL_EDIT, OB_MODE_GPENCIL_PAINT, + OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT) && (ob->type == OB_GPENCIL)) || (input->value == OB_MODE_OBJECT)) { RNA_enum_item_add(&item, &totitem, input); @@ -1650,14 +1629,6 @@ static const EnumPropertyItem *object_mode_set_itemsf( RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT); } - /* On top of all the rest, GPencil Stroke Edit Mode - * is available if there's a valid gp datablock... - */ - gpd = CTX_data_gpencil_data(C); - if (gpd) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_object_mode_items, OB_MODE_GPENCIL); - } - RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1680,30 +1651,32 @@ static bool object_mode_set_poll(bContext *C) 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); - bGPdata *gpd = CTX_data_gpencil_data(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 (gpd) { - /* GP Mode is not bound to a specific object. Therefore, - * we don't want it to be actually saved on any objects, - * as weirdness can happen if you select other objects, - * or load old files. - * - * Instead, we use the following 2 rules to ensure that - * the mode selector works as expected: - * 1) If there's no object, we want to enter editmode. - * (i.e. with no object, we're in object mode) - * 2) Otherwise, exit stroke editmode, so that we can - * enter another mode... - */ - if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); + 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_GPENCIL_EDIT; + } + if (!ob || !ED_object_mode_compat_test(ob, mode)) return OPERATOR_PASS_THROUGH; @@ -1732,6 +1705,14 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) } } + /* 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; } @@ -1760,453 +1741,408 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/************************ Game Properties ***********************/ - -static int game_property_new_exec(bContext *C, wmOperator *op) +void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot) { - Object *ob = CTX_data_active_object(C); - bProperty *prop; - char name[MAX_NAME]; - int type = RNA_enum_get(op->ptr, "type"); - - prop = BKE_bproperty_new(type); - BLI_addtail(&ob->prop, prop); - - RNA_string_get(op->ptr, "name", name); - if (name[0] != '\0') { - BLI_strncpy(prop->name, name, sizeof(prop->name)); - } - - BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name)); - - WM_event_add_notifier(C, NC_LOGIC, NULL); - return OPERATOR_FINISHED; -} - + PropertyRNA *prop; -void OBJECT_OT_game_property_new(wmOperatorType *ot) -{ /* identifiers */ - ot->name = "New Game Property"; - ot->description = "Create a new property available to the game engine"; - ot->idname = "OBJECT_OT_game_property_new"; + 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 = game_property_new_exec; - ot->poll = ED_operator_object_active_editable; + ot->exec = object_mode_set_exec; + + ot->poll = object_mode_set_poll; //ED_operator_object_active_editable; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = 0; /* no register/undo here, leave it to operators being called */ - RNA_def_enum(ot->srna, "type", rna_enum_gameproperty_type_items, GPROP_FLOAT, "Type", "Type of game property to add"); - RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the game property to add"); + 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); } -static int game_property_remove_exec(bContext *C, wmOperator *op) +bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3]) { - Object *ob = CTX_data_active_object(C); - bProperty *prop; - int index = RNA_int_get(op->ptr, "index"); + switch (obedit->type) { + case OB_MESH: + { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMEditSelection ese; - if (!ob) - return OPERATOR_CANCELLED; + 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; + } - prop = BLI_findlink(&ob->prop, index); + break; + } + case OB_CURVE: + case OB_SURF: + { + Curve *cu = obedit->data; - if (prop) { - BLI_remlink(&ob->prop, prop); - BKE_bproperty_free(prop); + if (ED_curve_active_center(cu, r_center)) { + return true; + } + break; + } + case OB_MBALL: + { + MetaBall *mb = obedit->data; + MetaElem *ml_act = mb->lastelem; - WM_event_add_notifier(C, NC_LOGIC, NULL); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + 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; } -void OBJECT_OT_game_property_remove(wmOperatorType *ot) +static bool move_to_collection_poll(bContext *C) { - /* identifiers */ - ot->name = "Remove Game Property"; - ot->description = "Remove game property"; - ot->idname = "OBJECT_OT_game_property_remove"; - - /* api callbacks */ - ot->exec = game_property_remove_exec; - ot->poll = ED_operator_object_active_editable; + if (CTX_wm_space_outliner(C) != NULL) { + return ED_outliner_collections_editor_poll(C); + } + else { + View3D *v3d = CTX_wm_view3d(C); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + if (v3d && v3d->localvd) { + return false; + } - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX); + return ED_operator_object_active_editable(C); + } } -#define GAME_PROPERTY_MOVE_UP 1 -#define GAME_PROPERTY_MOVE_DOWN -1 - -static int game_property_move(bContext *C, wmOperator *op) +static int move_to_collection_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - bProperty *prop; - bProperty *otherprop = NULL; - const int index = RNA_int_get(op->ptr, "index"); - const int dir = RNA_enum_get(op->ptr, "direction"); - - if (ob == NULL) + 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; + } - prop = BLI_findlink(&ob->prop, index); - /* invalid index */ - if (prop == NULL) + 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 (dir == GAME_PROPERTY_MOVE_UP) { - otherprop = prop->prev; } - else if (dir == GAME_PROPERTY_MOVE_DOWN) { - otherprop = prop->next; + + if (CTX_wm_space_outliner(C) != NULL) { + ED_outliner_selected_objects_get(C, &objects); } else { - BLI_assert(0); + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + BLI_addtail(&objects, BLI_genericNodeN(ob)); + } + CTX_DATA_END; } - if (prop && otherprop) { - BLI_listbase_swaplinks(&ob->prop, prop, otherprop); - - WM_event_add_notifier(C, NC_LOGIC, NULL); - return OPERATOR_FINISHED; + 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); } - else { + + 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; } -} - -void OBJECT_OT_game_property_move(wmOperatorType *ot) -{ - static const EnumPropertyItem direction_property_move[] = { - {GAME_PROPERTY_MOVE_UP, "UP", 0, "Up", ""}, - {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL} - }; - PropertyRNA *prop; - /* identifiers */ - ot->name = "Move Game Property"; - ot->description = "Move game property"; - ot->idname = "OBJECT_OT_game_property_move"; + for (LinkData *link = objects.first; link; link = link->next) { + Object *ob = link->data; - /* api callbacks */ - ot->exec = game_property_move; - ot->poll = ED_operator_object_active_editable; + if (!is_link) { + BKE_collection_object_move(bmain, scene, collection, NULL, ob); + } + else { + BKE_collection_object_add(bmain, collection, ob); + } + } + BLI_freelistN(&objects); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + 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); - /* properties */ - prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction", - "Direction for moving the property"); -} + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); -#undef GAME_PROPERTY_MOVE_UP -#undef GAME_PROPERTY_MOVE_DOWN + 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); -#define COPY_PROPERTIES_REPLACE 1 -#define COPY_PROPERTIES_MERGE 2 -#define COPY_PROPERTIES_COPY 3 + return OPERATOR_FINISHED; +} -static const EnumPropertyItem game_properties_copy_operations[] = { - {COPY_PROPERTIES_REPLACE, "REPLACE", 0, "Replace Properties", ""}, - {COPY_PROPERTIES_MERGE, "MERGE", 0, "Merge Properties", ""}, - {COPY_PROPERTIES_COPY, "COPY", 0, "Copy a Property", ""}, - {0, NULL, 0, NULL, NULL} +struct MoveToCollectionData { + struct MoveToCollectionData *next, *prev; + int index; + struct Collection *collection; + struct ListBase submenus; + PointerRNA ptr; + struct wmOperatorType *ot; }; -static const EnumPropertyItem *gameprops_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu) { - Object *ob = ED_object_active_context(C); - EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; - bProperty *prop; - int a, totitem = 0; - - if (!ob) - return DummyRNA_NULL_items; - - for (a = 1, prop = ob->prop.first; prop; prop = prop->next, a++) { - tmp.value = a; - tmp.identifier = prop->name; - tmp.name = prop->name; - RNA_enum_item_add(&item, &totitem, &tmp); + 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; } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + return index; } -static int game_property_copy_exec(bContext *C, wmOperator *op) +static void move_to_collection_menus_free_recursive(MoveToCollectionData *menu) { - Object *ob = ED_object_active_context(C); - bProperty *prop; - int type = RNA_enum_get(op->ptr, "operation"); - int propid = RNA_enum_get(op->ptr, "property"); - - if (propid > 0) { /* copy */ - prop = BLI_findlink(&ob->prop, propid - 1); - - if (prop) { - CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects) - { - if (ob != ob_iter) - BKE_bproperty_object_set(ob_iter, prop); - } CTX_DATA_END; - } + for (MoveToCollectionData *submenu = menu->submenus.first; + submenu != NULL; + submenu = submenu->next) + { + move_to_collection_menus_free_recursive(submenu); } + BLI_freelistN(&menu->submenus); +} - else { - CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects) - { - if (ob != ob_iter) { - if (type == COPY_PROPERTIES_REPLACE) { - BKE_bproperty_copy_list(&ob_iter->prop, &ob->prop); - } - else { - /* merge - the default when calling with no argument */ - for (prop = ob->prop.first; prop; prop = prop->next) { - BKE_bproperty_object_set(ob_iter, prop); - } - } - } - } - CTX_DATA_END; +static void move_to_collection_menus_free(MoveToCollectionData **menu) +{ + if (*menu == NULL) { + return; } - return OPERATOR_FINISHED; + move_to_collection_menus_free_recursive(*menu); + MEM_freeN(*menu); + *menu = NULL; } -void OBJECT_OT_game_property_copy(wmOperatorType *ot) +static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "Copy Game Property"; - ot->idname = "OBJECT_OT_game_property_copy"; - ot->description = "Copy/merge/replace a game property from active object to all selected objects"; + MoveToCollectionData *menu = menu_v; + const char *name = BKE_collection_ui_name_get(menu->collection); - /* api callbacks */ - ot->exec = game_property_copy_exec; - ot->poll = ED_operator_object_active_editable; + uiItemIntO(layout, + name, + ICON_NONE, + menu->ot->idname, + "collection_index", + menu->index); + uiItemS(layout); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + for (MoveToCollectionData *submenu = menu->submenus.first; + submenu != NULL; + submenu = submenu->next) + { + move_to_collection_menus_items(layout, submenu); + } + + uiItemS(layout); - RNA_def_enum(ot->srna, "operation", game_properties_copy_operations, 3, "Operation", ""); - prop = RNA_def_enum(ot->srna, "property", DummyRNA_NULL_items, 0, "Property", "Properties to copy"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_ENUM_NO_TRANSLATE); - RNA_def_enum_funcs(prop, gameprops_itemf); - ot->prop = prop; + 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 int game_property_clear_exec(bContext *C, wmOperator *UNUSED(op)) +static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu) { - CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects) - { - BKE_bproperty_free_list(&ob_iter->prop); + 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); } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_LOGIC, NULL); - return OPERATOR_FINISHED; } -void OBJECT_OT_game_property_clear(wmOperatorType *ot) + +/* This is allocated statically because we need this available for the menus creation callback. */ +static MoveToCollectionData *master_collection_menu = NULL; + +static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - /* identifiers */ - ot->name = "Clear Game Properties"; - ot->idname = "OBJECT_OT_game_property_clear"; - ot->description = "Remove all game properties from all selected objects"; + Scene *scene = CTX_data_scene(C); - /* api callbacks */ - ot->exec = game_property_clear_exec; - ot->poll = ED_operator_object_active_editable; + /* Reset the menus data for the current master collection, and free previously allocated data. */ + move_to_collection_menus_free(&master_collection_menu); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} + 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); -/************************ Copy Logic Bricks ***********************/ + 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; -static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = ED_object_active_context(C); + collection = BKE_collection_from_index(scene, collection_index); + BKE_collection_new_name_get(collection, name); - CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects) - { - if (ob != ob_iter) { - /* first: free all logic */ - free_sensors(&ob_iter->sensors); - unlink_controllers(&ob_iter->controllers); - free_controllers(&ob_iter->controllers); - unlink_actuators(&ob_iter->actuators); - free_actuators(&ob_iter->actuators); - - /* now copy it, this also works without logicbricks! */ - clear_sca_new_poins_ob(ob); - copy_sensors(&ob_iter->sensors, &ob->sensors, 0); - copy_controllers(&ob_iter->controllers, &ob->controllers, 0); - copy_actuators(&ob_iter->actuators, &ob->actuators, 0); - set_sca_new_poins_ob(ob_iter); - - /* some menu settings */ - ob_iter->scavisflag = ob->scavisflag; - ob_iter->scaflag = ob->scaflag; - - /* set the initial state */ - ob_iter->state = ob->state; - ob_iter->init_state = ob->init_state; - - if (ob_iter->totcol == ob->totcol) { - ob_iter->actcol = ob->actcol; - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); + 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); } - CTX_DATA_END; - WM_event_add_notifier(C, NC_LOGIC, NULL); + Collection *master_collection = BKE_collection_master(scene); - return OPERATOR_FINISHED; -} + /* 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"); + } -void OBJECT_OT_logic_bricks_copy(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Copy Logic Bricks to Selected"; - ot->description = "Copy logic bricks to other selected objects"; - ot->idname = "OBJECT_OT_logic_bricks_copy"; + master_collection_menu->collection = master_collection; + master_collection_menu->ot = op->type; + move_to_collection_menus_create(op, master_collection_menu); - /* api callbacks */ - ot->exec = logicbricks_copy_exec; - ot->poll = ED_operator_object_active_editable; + uiPopupMenu *pup; + uiLayout *layout; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} + /* 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); -static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = ED_object_active_context(C); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); - CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects) - { - if (ob != ob_iter) { - ob_iter->gameflag = ob->gameflag; - ob_iter->gameflag2 = ob->gameflag2; - ob_iter->inertia = ob->inertia; - ob_iter->formfactor = ob->formfactor; - ob_iter->damping = ob->damping; - ob_iter->rdamping = ob->rdamping; - ob_iter->min_vel = ob->min_vel; - ob_iter->max_vel = ob->max_vel; - ob_iter->min_angvel = ob->min_angvel; - ob_iter->max_angvel = ob->max_angvel; - ob_iter->obstacleRad = ob->obstacleRad; - ob_iter->mass = ob->mass; - copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction); - ob_iter->collision_boundtype = ob->collision_boundtype; - ob_iter->margin = ob->margin; - ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0); - if (ob->restrictflag & OB_RESTRICT_RENDER) - ob_iter->restrictflag |= OB_RESTRICT_RENDER; - else - ob_iter->restrictflag &= ~OB_RESTRICT_RENDER; - - ob_iter->col_group = ob->col_group; - ob_iter->col_mask = ob->col_mask; - } - } - CTX_DATA_END; + move_to_collection_menu_create(C, layout, master_collection_menu); - return OPERATOR_FINISHED; + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; } -void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot) +void OBJECT_OT_move_to_collection(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ - ot->name = "Copy Game Physics Properties to Selected"; - ot->description = "Copy game physics properties to other selected objects"; - ot->idname = "OBJECT_OT_game_physics_copy"; + ot->name = "Move to Collection"; + ot->description = "Move objects to a scene collection"; + ot->idname = "OBJECT_OT_move_to_collection"; /* api callbacks */ - ot->exec = game_physics_copy_exec; - ot->poll = ED_operator_object_active_editable; + 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; -} -/* generic utility function */ + 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); +} -bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3]) +void OBJECT_OT_link_to_collection(wmOperatorType *ot) { - 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; + PropertyRNA *prop; - if (ED_curve_active_center(cu, r_center)) { - return true; - } - break; - } - case OB_MBALL: - { - MetaBall *mb = obedit->data; - MetaElem *ml_act = mb->lastelem; + /* identifiers */ + ot->name = "Link to Collection"; + ot->description = "Link objects to a collection"; + ot->idname = "OBJECT_OT_link_to_collection"; - 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); + /* api callbacks */ + ot->exec = move_to_collection_exec; + ot->invoke = move_to_collection_invoke; + ot->poll = move_to_collection_poll; - if (actbp) { - copy_v3_v3(r_center, actbp->vec); - return true; - } - break; - } - } + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - return false; + 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 new file mode 100644 index 00000000000..ab710b21817 --- /dev/null +++ b/source/blender/editors/object/object_facemap_ops.c @@ -0,0 +1,501 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_facemap_ops.c + * \ingroup edobj + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_listbase.h" + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_workspace_types.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" +#include "BKE_object_facemap.h" +#include "BKE_object_deform.h" + +#include "DEG_depsgraph.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "WM_types.h" +#include "WM_api.h" + +#include "ED_mesh.h" +#include "ED_object.h" + +#include "object_intern.h" + +/* 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; + + /* 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 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; + } +} + +/* 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; + + /* 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 ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) + return; + + 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_btmesh) { + BMEditMesh *em = me->edit_btmesh; + 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; + } + } + } + } + } +} + +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); +} + +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); +} + +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; +} + +static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = ED_object_context(C); + + BKE_object_facemap_add(ob); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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_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"; + + /* api callbacks */ + ot->poll = face_map_supported_poll; + ot->exec = face_map_add_exec; + + /* 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, OB_RECALC_DATA); + 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"; + + /* api callbacks */ + ot->poll = face_map_supported_poll; + ot->exec = face_map_remove_exec; + + /* 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_btmesh; + 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, OB_RECALC_DATA); + 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"; + + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_assign_exec; + + /* 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_btmesh; + 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, OB_RECALC_DATA); + 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"; + + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_remove_from_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static void fmap_select(Object *ob, bool select) +{ + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + 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); + + if (fmap) { + fmap_select(ob, true); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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"; + + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_select_exec; + + /* 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); + + if (fmap) { + fmap_select(ob, false); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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"; + + /* api callbacks */ + ot->poll = face_map_supported_edit_mode_poll; + ot->exec = face_map_deselect_exec; + + /* 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, OB_RECALC_DATA); + 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"); +} diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c new file mode 100644 index 00000000000..d67b79375e2 --- /dev/null +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -0,0 +1,647 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2018 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_gpencil_modifier.c + * \ingroup edobj + */ + + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_report.h" +#include "BKE_object.h" +#include "BKE_gpencil.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "object_intern.h" + +/******************************** API ****************************/ + +GpencilModifierData *ED_object_gpencil_modifier_add( + 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; + } + + 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; + } + } + + /* get new modifier data to add */ + new_md = BKE_gpencil_modifier_new(type); + + BLI_addtail(&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, OB_RECALC_OB | OB_RECALC_DATA); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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 UNUSED_FUNCTION(gpencil_object_has_modifier)( + const Object *ob, const GpencilModifierData *exclude, + GpencilModifierType type) +{ + GpencilModifierData *md; + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if ((md != exclude) && (md->type == type)) + return true; + } + + return false; +} + +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; + } + + DEG_relations_tag_update(bmain); + + BLI_remlink(&ob->greasepencil_modifiers, md); + BKE_gpencil_modifier_free(md); + BKE_object_free_derived_caches(ob); + + return 1; +} + +bool ED_object_gpencil_modifier_remove(ReportList *reports, Main *bmain, Object *ob, GpencilModifierData *md) +{ + bool sort_depsgraph = false; + bool ok; + + 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; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return 1; +} + +void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + bool sort_depsgraph = false; + + if (!md) + return; + + while (md) { + GpencilModifierData *next_md; + + next_md = md->next; + + gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); + + md = next_md; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); +} + +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); + } + + return 1; +} + +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); + } + + 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, OB_RECALC_DATA); + } + 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; + + 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); + + 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"); + + 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); + + return OPERATOR_FINISHED; +} + +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; + + 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); + + if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) + continue; + } + else { + group_item = md_item; + md_item = NULL; + + continue; + } + + 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_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot) +{ + 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"; + + /* 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; + + /* 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); + + if (!ptr.data) { + CTX_wm_operator_poll_msg_set(C, "Context missing 'modifier'"); + 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; + } + + return 1; +} + +static bool gpencil_edit_modifier_poll(bContext *C) +{ + 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); +} + +static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op) +{ + 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; + } + } + + return false; +} + +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); + + md = BKE_gpencil_modifiers_findByName(ob, modifier_name); + + if (md && type != 0 && md->type != type) + md = NULL; + + 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); + + 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); + + return OPERATOR_FINISHED; +} + +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; +} + +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->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); +} + +/************************ 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); + + if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +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; +} + +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->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); +} + +/************************ 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); + + if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +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; +} + +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->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); +} + +/************************ 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"); + + if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + 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; +} + +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} +}; + +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->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; + + 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); + + if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + 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; +} + +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->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); +} diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c deleted file mode 100644 index c764ee22162..00000000000 --- a/source/blender/editors/object/object_group.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/object/object_group.c - * \ingroup edobj - */ - - -#include <string.h> - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - -#include "DNA_group_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_group.h" -#include "BKE_library.h" -#include "BKE_library_remap.h" -#include "BKE_main.h" -#include "BKE_report.h" -#include "BKE_object.h" - -#include "ED_screen.h" -#include "ED_object.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "object_intern.h" - -/********************* 3d view operators ***********************/ - -/* can be called with C == NULL */ -static const EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - Main *bmain = CTX_data_main(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) { - Group *group; - int i = 0, count = 0; - - /* if 2 or more groups, add option to add to all groups */ - group = NULL; - while ((group = BKE_group_object_find(bmain, group, ob))) - count++; - - if (count >= 2) { - item_tmp.identifier = item_tmp.name = "All Groups"; - 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 groups */ - group = NULL; - while ((group = BKE_group_object_find(bmain, group, ob))) { - item_tmp.identifier = item_tmp.name = group->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 group back from the enum index, quite awkward and UI specific */ -static Group *group_object_active_find_index(Main *bmain, Object *ob, const int group_object_index) -{ - Group *group = NULL; - int i = 0; - while ((group = BKE_group_object_find(bmain, group, ob))) { - if (i == group_object_index) { - break; - } - i++; - } - - return group; -} - -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_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(bmain, ob, single_group_index); - Group *group; - bool is_cycle = false; - bool updated = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - /* now add all selected objects to the group(s) */ - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) - continue; - if (!BKE_group_object_exists(group, ob)) - continue; - - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - if (BKE_group_object_exists(group, base->object)) - continue; - - if (!BKE_group_object_cyclic_check(bmain, base->object, group)) { - BKE_group_object_add(group, base->object, scene, base); - updated = true; - } - else { - is_cycle = true; - } - } - CTX_DATA_END; - } - - if (is_cycle) - BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); - - if (!updated) - return OPERATOR_CANCELLED; - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GROUP_OT_objects_add_active(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Add Selected To Active Group"; - ot->description = "Add the object to an object group that contains the active object"; - ot->idname = "GROUP_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, "group", DummyRNA_NULL_items, 0, "Group", "The group to add other selected objects to"); - RNA_def_enum_funcs(prop, group_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); - Object *ob = OBACT; - int single_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(bmain, ob, single_group_index); - Group *group; - bool ok = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - /* linking to same group requires its own loop so we can avoid - * looking up the active objects groups each time */ - - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) - continue; - - if (BKE_group_object_exists(group, ob)) { - /* Remove groups from selected objects */ - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - BKE_group_object_unlink(bmain, group, base->object, scene, base); - ok = 1; - } - CTX_DATA_END; - } - } - - if (!ok) - BKE_report(op->reports, RPT_ERROR, "Active object contains no groups"); - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GROUP_OT_objects_remove_active(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Remove Selected From Active Group"; - ot->description = "Remove the object from an object group that contains the active object"; - ot->idname = "GROUP_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, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove other selected objects from"); - RNA_def_enum_funcs(prop, group_object_active_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - -static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) -{ - 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, base->object); - } - CTX_DATA_END; - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GROUP_OT_objects_remove_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove From All Groups"; - ot->description = "Remove selected objects from all groups"; - ot->idname = "GROUP_OT_objects_remove_all"; - - /* api callbacks */ - ot->exec = group_objects_remove_all_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int group_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_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(bmain, ob, single_group_index); - Group *group; - bool updated = false; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) - continue; - if (!BKE_group_object_exists(group, ob)) - continue; - - /* now remove all selected objects from the group */ - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) - { - BKE_group_object_unlink(bmain, group, base->object, scene, base); - updated = true; - } - CTX_DATA_END; - } - - if (!updated) - return OPERATOR_CANCELLED; - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GROUP_OT_objects_remove(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Remove From Group"; - ot->description = "Remove selected objects from a group"; - ot->idname = "GROUP_OT_objects_remove"; - - /* api callbacks */ - ot->exec = group_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, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from"); - RNA_def_enum_funcs(prop, group_object_active_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - -static int group_create_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Group *group = NULL; - char name[MAX_ID_NAME - 2]; /* id name */ - - RNA_string_get(op->ptr, "name", name); - - group = BKE_group_add(bmain, name); - - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - BKE_group_object_add(group, base->object, scene, base); - } - CTX_DATA_END; - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GROUP_OT_create(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Create New Group"; - ot->description = "Create an object group from selected objects"; - ot->idname = "GROUP_OT_create"; - - /* api callbacks */ - ot->exec = group_create_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Name of the new group"); -} - -/****************** properties window operators *********************/ - -static int group_add_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - Main *bmain = CTX_data_main(C); - Group *group; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - group = BKE_group_add(bmain, "Group"); - BKE_group_object_add(group, ob, scene, NULL); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_group_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add to Group"; - ot->idname = "OBJECT_OT_group_add"; - ot->description = "Add an object to a new group"; - - /* api callbacks */ - ot->exec = group_add_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int group_link_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - Group *group = BLI_findlink(&bmain->group, RNA_enum_get(op->ptr, "group")); - - if (ELEM(NULL, ob, group)) - return OPERATOR_CANCELLED; - - /* Early return check, if the object is already in group - * we could skip all the dependency check and just consider - * operator is finished. - */ - if (BKE_group_object_exists(group, ob)) { - return OPERATOR_FINISHED; - } - - /* Adding object to group which is used as dupligroup for self is bad idea. - * - * It is also bad idea to add object to group which is in group which - * contains our current object. - */ - if (BKE_group_object_cyclic_check(bmain, ob, group)) { - BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); - return OPERATOR_CANCELLED; - } - - BKE_group_object_add(group, ob, scene, NULL); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_group_link(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Link to Group"; - ot->idname = "OBJECT_OT_group_link"; - ot->description = "Add an object to an existing group"; - - /* api callbacks */ - ot->exec = group_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, "group", DummyRNA_NULL_items, 0, "Group", ""); - RNA_def_enum_funcs(prop, RNA_group_local_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - -static int group_remove_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; - - if (!ob || !group) - return OPERATOR_CANCELLED; - - BKE_group_object_unlink(bmain, group, ob, scene, NULL); /* base will be used if found */ - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_group_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Group"; - ot->idname = "OBJECT_OT_group_remove"; - ot->description = "Remove the active object from this group"; - - /* api callbacks */ - ot->exec = group_remove_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Main *bmain = CTX_data_main(C); - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; - - if (!group) - return OPERATOR_CANCELLED; - - BKE_libblock_delete(bmain, group); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_group_unlink(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Unlink Group"; - ot->idname = "OBJECT_OT_group_unlink"; - ot->description = "Unlink the group from all objects"; - - /* api callbacks */ - ot->exec = group_unlink_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */ -{ - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; - - if (!group) - return OPERATOR_CANCELLED; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { - ED_base_object_select(base, BA_SELECT); - } - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_grouped_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Grouped"; - ot->idname = "OBJECT_OT_grouped_select"; - ot->description = "Select all objects in group"; - - /* api callbacks */ - ot->exec = select_grouped_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index bfc24d4f325..ff9cc65180b 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -48,7 +48,7 @@ #include "BKE_action.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -57,6 +57,9 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "RNA_define.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -318,7 +321,7 @@ static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit, EDBM_mesh_load(bmain, obedit); EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); em = me->edit_btmesh; @@ -445,26 +448,24 @@ static bool hook_op_edit_poll(bContext *C) return 0; } -static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit) +static Object *add_hook_object_new(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit) { - Base *base, *basedit; + Base *basedit; Object *ob; - ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL); + ob = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL); - basedit = BKE_scene_base_find(scene, obedit); - base = scene->basact; - base->lay = ob->lay = obedit->lay; - BLI_assert(scene->basact->object == ob); + basedit = BKE_view_layer_base_find(view_layer, obedit); + BLI_assert(view_layer->basact->object == ob); /* icky, BKE_object_add sets new base as active. * so set it back to the original edit object */ - scene->basact = basedit; + view_layer->basact = basedit; return ob; } -static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode, ReportList *reports) +static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *ob, int mode, ReportList *reports) { ModifierData *md = NULL; HookModifierData *hmd = NULL; @@ -482,7 +483,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob if (mode == OBJECT_ADDHOOK_NEWOB && !ob) { - ob = add_hook_object_new(bmain, scene, obedit); + ob = add_hook_object_new(bmain, scene, view_layer, obedit); /* transform cent to global coords for loc */ mul_v3_m4v3(ob->loc, obedit->obmat, cent); @@ -541,13 +542,13 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob /* matrix calculus */ /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ /* (parentinv ) */ - BKE_object_where_is_calc(scene, ob); + 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); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); return true; } @@ -556,6 +557,7 @@ 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"); @@ -580,7 +582,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) { + if (add_hook_object(C, bmain, scene, view_layer, obedit, obsel, mode, op->reports)) { WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); return OPERATOR_FINISHED; } @@ -611,9 +613,11 @@ 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); Object *obedit = CTX_data_edit_object(C); - if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { + if (add_hook_object(C, bmain, scene, view_layer, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) { + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit); return OPERATOR_FINISHED; @@ -655,7 +659,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op) BLI_remlink(&ob->modifiers, (ModifierData *)hmd); modifier_free((ModifierData *)hmd); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -729,7 +733,7 @@ static int object_hook_reset_exec(bContext *C, wmOperator *op) BKE_object_modifier_hook_reset(ob, hmd); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -776,10 +780,10 @@ static int object_hook_recenter_exec(bContext *C, wmOperator *op) copy_m3_m4(bmat, ob->obmat); invert_m3_m3(imat, bmat); - sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]); + sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]); mul_m3_v3(imat, hmd->cent); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -838,7 +842,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op) hmd->indexar = indexar; hmd->totindex = tot; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -884,6 +888,7 @@ static int object_hook_select_exec(bContext *C, wmOperator *op) /* select functionality */ object_hook_select(ob, hmd); + DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index f962f83844b..c750a3fb2bd 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -55,6 +55,7 @@ void OBJECT_OT_scale_clear(struct wmOperatorType *ot); void OBJECT_OT_origin_clear(struct wmOperatorType *ot); void OBJECT_OT_visual_transform_apply(struct wmOperatorType *ot); void OBJECT_OT_transform_apply(struct wmOperatorType *ot); +void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot); void OBJECT_OT_origin_set(struct wmOperatorType *ot); /* object_relations.c */ @@ -67,36 +68,32 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); +void OBJECT_OT_make_override_static(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); -void OBJECT_OT_move_to_layer(struct wmOperatorType *ot); void OBJECT_OT_drop_named_material(struct wmOperatorType *ot); void OBJECT_OT_unlink_data(struct wmOperatorType *ot); /* object_edit.c */ +void OBJECT_OT_hide_view_set(struct wmOperatorType *ot); +void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot); +void OBJECT_OT_hide_collection(struct wmOperatorType *ot); void OBJECT_OT_mode_set(struct wmOperatorType *ot); +void OBJECT_OT_mode_set_or_submode(struct wmOperatorType *ot); void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot); void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot); -void OBJECT_OT_hide_view_set(struct wmOperatorType *ot); -void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot); -void OBJECT_OT_hide_render_set(struct wmOperatorType *ot); -void OBJECT_OT_hide_render_clear(struct wmOperatorType *ot); void OBJECT_OT_proxy_make(struct wmOperatorType *ot); void OBJECT_OT_shade_smooth(struct wmOperatorType *ot); void OBJECT_OT_shade_flat(struct wmOperatorType *ot); void OBJECT_OT_paths_calculate(struct wmOperatorType *ot); void OBJECT_OT_paths_update(struct wmOperatorType *ot); void OBJECT_OT_paths_clear(struct wmOperatorType *ot); +void OBJECT_OT_paths_range_update(struct wmOperatorType *ot); void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot); -void OBJECT_OT_game_property_new(struct wmOperatorType *ot); -void OBJECT_OT_game_property_remove(struct wmOperatorType *ot); -void OBJECT_OT_game_property_copy(struct wmOperatorType *ot); -void OBJECT_OT_game_property_clear(struct wmOperatorType *ot); -void OBJECT_OT_game_property_move(struct wmOperatorType *ot); -void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot); -void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot); +void OBJECT_OT_move_to_collection(struct wmOperatorType *ot); +void OBJECT_OT_link_to_collection(struct wmOperatorType *ot); /* object_select.c */ void OBJECT_OT_select_all(struct wmOperatorType *ot); @@ -108,7 +105,7 @@ void OBJECT_OT_select_grouped(struct wmOperatorType *ot); void OBJECT_OT_select_mirror(struct wmOperatorType *ot); void OBJECT_OT_select_more(struct wmOperatorType *ot); void OBJECT_OT_select_less(struct wmOperatorType *ot); -void OBJECT_OT_select_same_group(struct wmOperatorType *ot); +void OBJECT_OT_select_same_collection(struct wmOperatorType *ot); /* object_add.c */ void OBJECT_OT_add(struct wmOperatorType *ot); @@ -117,12 +114,14 @@ void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); void OBJECT_OT_empty_add(struct wmOperatorType *ot); +void OBJECT_OT_lightprobe_add(struct wmOperatorType *ot); void OBJECT_OT_drop_named_image(struct wmOperatorType *ot); -void OBJECT_OT_lamp_add(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_add(struct wmOperatorType *ot); +void OBJECT_OT_light_add(struct wmOperatorType *ot); void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_camera_add(struct wmOperatorType *ot); void OBJECT_OT_speaker_add(struct wmOperatorType *ot); -void OBJECT_OT_group_instance_add(struct wmOperatorType *ot); +void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot); void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); void OBJECT_OT_duplicate(struct wmOperatorType *ot); @@ -141,11 +140,11 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot); void OBJECT_OT_hook_recenter(struct wmOperatorType *ot); /* object_group.c */ -void GROUP_OT_create(struct wmOperatorType *ot); -void GROUP_OT_objects_remove_all(struct wmOperatorType *ot); -void GROUP_OT_objects_remove(struct wmOperatorType *ot); -void GROUP_OT_objects_add_active(struct wmOperatorType *ot); -void GROUP_OT_objects_remove_active(struct wmOperatorType *ot); +void COLLECTION_OT_create(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove(struct wmOperatorType *ot); +void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot); /* object_modifier.c */ bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag); @@ -178,6 +177,20 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot); void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot); void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot); +/* grease pencil modifiers */ +void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot); + +/* shader fx */ +void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot); + /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); void OBJECT_OT_constraint_add_with_targets(struct wmOperatorType *ot); @@ -237,6 +250,15 @@ void OBJECT_OT_vertex_weight_set_active(struct wmOperatorType *ot); void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot); void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot); +/* object_facemap_ops.c */ +void OBJECT_OT_face_map_add(struct wmOperatorType *ot); +void OBJECT_OT_face_map_remove(struct wmOperatorType *ot); +void OBJECT_OT_face_map_assign(struct wmOperatorType *ot); +void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot); +void OBJECT_OT_face_map_select(struct wmOperatorType *ot); +void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot); +void OBJECT_OT_face_map_move(struct wmOperatorType *ot); + /* object_warp.c */ void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot); @@ -249,20 +271,16 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot); void OBJECT_OT_shape_key_move(struct wmOperatorType *ot); /* object_group.c */ -void OBJECT_OT_group_add(struct wmOperatorType *ot); -void OBJECT_OT_group_link(struct wmOperatorType *ot); -void OBJECT_OT_group_remove(struct wmOperatorType *ot); -void OBJECT_OT_group_unlink(struct wmOperatorType *ot); -void OBJECT_OT_grouped_select(struct wmOperatorType *ot); +void OBJECT_OT_collection_add(struct wmOperatorType *ot); +void OBJECT_OT_collection_link(struct wmOperatorType *ot); +void OBJECT_OT_collection_remove(struct wmOperatorType *ot); +void OBJECT_OT_collection_unlink(struct wmOperatorType *ot); +void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot); /* object_bake.c */ void OBJECT_OT_bake_image(wmOperatorType *ot); void OBJECT_OT_bake(wmOperatorType *ot); -/* object_lod.c */ -void OBJECT_OT_lod_add(struct wmOperatorType *ot); -void OBJECT_OT_lod_remove(struct wmOperatorType *ot); - /* object_random.c */ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c deleted file mode 100644 index ced306178b8..00000000000 --- a/source/blender/editors/object/object_lod.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/object/object_lod.c - * \ingroup edobj - */ - -#include "DNA_object_types.h" - -#include "BKE_context.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "ED_screen.h" -#include "ED_object.h" - -#ifdef WITH_GAMEENGINE -# include "BKE_object.h" - -# include "RNA_enum_types.h" -#endif - -#include "object_intern.h" - -static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = ED_object_context(C); - -#ifdef WITH_GAMEENGINE - BKE_object_lod_add(ob); -#else - (void)ob; -#endif - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_lod_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Level of Detail"; - ot->description = "Add a level of detail to this object"; - ot->idname = "OBJECT_OT_lod_add"; - - /* api callbacks */ - ot->exec = object_lod_add_exec; - ot->poll = ED_operator_object_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int object_lod_remove_exec(bContext *C, wmOperator *op) -{ - Object *ob = ED_object_context(C); - int index = RNA_int_get(op->ptr, "index"); - -#ifdef WITH_GAMEENGINE - if (!BKE_object_lod_remove(ob, index)) - return OPERATOR_CANCELLED; -#else - (void)ob; - (void)index; -#endif - - WM_event_add_notifier(C, NC_OBJECT | ND_LOD, CTX_wm_view3d(C)); - return OPERATOR_FINISHED; -} - -void OBJECT_OT_lod_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Level of Detail"; - ot->description = "Remove a level of detail from this object"; - ot->idname = "OBJECT_OT_lod_remove"; - - /* api callbacks */ - ot->exec = object_lod_remove_exec; - ot->poll = ED_operator_object_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_int(ot->srna, "index", 1, 1, INT_MAX, "Index", "", 1, INT_MAX); -} diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index d70a69e30f8..10c7fcfeba1 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -27,18 +27,36 @@ * actual mode switching logic is per-object type. */ +#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_workspace_types.h" #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" +#include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "WM_api.h" #include "WM_types.h" -#include "ED_object.h" +#include "RNA_access.h" + +#include "DEG_depsgraph.h" + +#include "ED_armature.h" +#include "ED_screen.h" + +#include "ED_object.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name High Level Mode Operations + * + * \{ */ static const char *object_mode_op_string(eObjectMode mode) { @@ -56,8 +74,14 @@ static const char *object_mode_op_string(eObjectMode mode) return "PARTICLE_OT_particle_edit_toggle"; if (mode == OB_MODE_POSE) return "OBJECT_OT_posemode_toggle"; - if (mode == OB_MODE_GPENCIL) + if (mode == OB_MODE_GPENCIL_EDIT) return "GPENCIL_OT_editmode_toggle"; + if (mode == OB_MODE_GPENCIL_PAINT) + return "GPENCIL_OT_paintmode_toggle"; + if (mode == OB_MODE_GPENCIL_SCULPT) + return "GPENCIL_OT_sculptmode_toggle"; + if (mode == OB_MODE_GPENCIL_WEIGHT) + return "GPENCIL_OT_weightmode_toggle"; return NULL; } @@ -70,8 +94,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) if (ob) { if (mode == OB_MODE_OBJECT) return true; - else if (mode == OB_MODE_GPENCIL) - return true; /* XXX: assume this is the case for now... */ switch (ob->type) { case OB_MESH: @@ -96,13 +118,19 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) return true; break; + case OB_GPENCIL: + if (mode & (OB_MODE_EDIT | OB_MODE_GPENCIL_EDIT | OB_MODE_GPENCIL_PAINT | + OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT)) + { + return true; + } + break; } } return false; } - /** * Sets the mode to a compatible state (use before entering the mode). * @@ -113,6 +141,7 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, Report 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) { @@ -131,48 +160,151 @@ void ED_object_mode_toggle(bContext *C, eObjectMode mode) { if (mode != OB_MODE_OBJECT) { const char *opstring = object_mode_op_string(mode); + if (opstring) { - WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + 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) { -#if 0 + 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; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic Mode Enter/Exit + * + * Supports exiting a mode without it being in the current context. + * This could be done for entering modes too if it's needed. + * + * \{ */ + +bool ED_object_mode_generic_enter( + struct bContext *C, eObjectMode object_mode) +{ + Object *ob = CTX_data_active_object(C); + 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", mode); - RNA_boolean_set(&ptr, "toggle", false); - WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr); + RNA_enum_set(&ptr, "mode", object_mode); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); -#else - Object *ob = CTX_data_active_object(C); - if (ob == NULL) { - return; + 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) +{ + 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); + } } - if (ob->mode == mode) { - /* pass */ + 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 (mode != OB_MODE_OBJECT) { - if (ob && (ob->mode & mode) == 0) { - /* needed so we don't do undo pushes. */ - wmWindowManager *wm = CTX_wm_manager(C); - wm->op_undo_depth++; - ED_object_mode_toggle(C, mode); - wm->op_undo_depth--; + 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 { - /* needed so we don't do undo pushes. */ - wmWindowManager *wm = CTX_wm_manager(C); - wm->op_undo_depth++; - ED_object_mode_toggle(C, ob->mode); - wm->op_undo_depth--; - + if (only_test) { + return false; + } + BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0); } -#endif + + return false; } + +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); +} + +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); +} + +/** \} */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 5f3a6d0ac94..7923e300377 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -54,26 +54,32 @@ #include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_displist.h" #include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_editmesh.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_lattice.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" -#include "BKE_report.h" #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_ocean.h" #include "BKE_paint.h" #include "BKE_particle.h" +#include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_softbody.h" -#include "BKE_editmesh.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "RNA_access.h" #include "RNA_define.h" @@ -93,6 +99,23 @@ static void modifier_skin_customdata_delete(struct Object *ob); /******************************** API ****************************/ +static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + if (ob->type == OB_MESH) { + Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene, ob, 0); + BKE_id_free(NULL, me_eval); + } + else if (ob->type == OB_LATTICE) { + BKE_lattice_modifiers_calc(depsgraph, scene, ob); + } + else if (ob->type == OB_MBALL) { + BKE_displist_make_mball(depsgraph, scene, ob); + } + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false); + } +} + ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type) { ModifierData *md = NULL, *new_md = NULL; @@ -171,8 +194,8 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc } } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - DAG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); return new_md; } @@ -180,7 +203,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc /* 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) + ModifierType type) { ModifierData *md; @@ -200,9 +223,10 @@ 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) +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; @@ -243,8 +267,8 @@ static bool object_has_modifier_cb(Object *ob, void *data) } /* Use with ED_object_iter_other(). Sets the total number of levels - * for any multires modifiers on the object to the int pointed to by - * callback_data. */ +* for any multires modifiers on the object to the int pointed to by +* callback_data. */ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) { ModifierData *md; @@ -253,7 +277,7 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Multires) { multires_set_tot_level(ob, (MultiresModifierData *)md, totlevel); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } return false; @@ -261,16 +285,16 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) /* 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) + ModifierData *exclude, + ModifierType type) { return (!object_has_modifier(ob, exclude, type) && - !ED_object_iter_other(bmain, ob, false, - object_has_modifier_cb, &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) + bool *r_sort_depsgraph) { /* It seems on rapid delete it is possible to * get called twice on same modifier, so make @@ -289,9 +313,8 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, } else if (md->type == eModifierType_Softbody) { if (ob->soft) { - sbFree(ob->soft); - ob->soft = NULL; - ob->softflag = 0; + sbFree(ob); + ob->softflag = 0; /* TODO(Sybren): this should probably be moved into sbFree() */ } } else if (md->type == eModifierType_Collision) { @@ -320,8 +343,6 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, ob->mode &= ~OB_MODE_PARTICLE_EDIT; } - DAG_relations_tag_update(bmain); - BLI_remlink(&ob->modifiers, md); modifier_free(md); BKE_object_free_derived_caches(ob); @@ -341,8 +362,8 @@ bool ED_object_modifier_remove(ReportList *reports, Main *bmain, Object *ob, Mod return 0; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - DAG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); return 1; } @@ -365,8 +386,8 @@ void ED_object_modifier_clear(Main *bmain, Object *ob) md = next_md; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - DAG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); } int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md) @@ -411,7 +432,7 @@ int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData * return 1; } -int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, Object *ob, ModifierData *md) +int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, ModifierData *md) { Object *obn; ParticleSystem *psys; @@ -463,7 +484,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * if (totvert == 0) return 0; /* add new mesh */ - obn = BKE_object_add(bmain, scene, OB_MESH, NULL); + obn = BKE_object_add(bmain, scene, view_layer, OB_MESH, NULL); me = obn->data; me->totvert = totvert; @@ -515,18 +536,17 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * } } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); return 1; } -static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, Object *ob, ModifierData *md) +static int modifier_apply_shape( + Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - - if (mti->isDisabled && mti->isDisabled(md, 0)) { + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); return 0; } @@ -543,7 +563,7 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, */ if (ob->type == OB_MESH) { - DerivedMesh *dm; + Mesh *mesh_applied; Mesh *me = ob->data; Key *key = me->key; KeyBlock *kb; @@ -553,8 +573,8 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, return 0; } - dm = mesh_create_derived_for_modifier(scene, ob, md, 0); - if (!dm) { + mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 0); + if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); return 0; } @@ -565,13 +585,13 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, /* 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, kb); + BKE_keyblock_convert_from_mesh(me, key, kb); } kb = BKE_keyblock_add(key, md->name); - DM_to_meshkey(dm, me, kb); + BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb); - dm->release(dm); + BKE_id_free(NULL, mesh_applied); } else { BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); @@ -580,19 +600,17 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, return 1; } -static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md) +static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - - if (mti->isDisabled && mti->isDisabled(md, 0)) { + 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) { - DerivedMesh *dm; + Mesh *mesh_applied; Mesh *me = ob->data; MultiresModifierData *mmd = find_multires_modifier_before(scene, md); @@ -606,19 +624,19 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, multires_force_update(ob); if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { - if (!multiresModifier_reshapeFromDeformMod(scene, mmd, ob, md)) { + if (!multiresModifier_reshapeFromDeformModifier(depsgraph, mmd, ob, md)) { BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply"); return 0; } } else { - dm = mesh_create_derived_for_modifier(scene, ob, md, 1); - if (!dm) { + mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 1); + if (!mesh_applied) { BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); return 0; } - DM_to_mesh(dm, me, ob, CD_MASK_MESH, true); + BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true); if (md->type == eModifierType_Multires) multires_customdata_delete(me); @@ -628,9 +646,10 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, Curve *cu; int numVerts; float (*vertexCos)[3]; + ModifierEvalContext mectx = {depsgraph, ob, 0}; if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) { - BKE_report(reports, RPT_ERROR, "Cannot apply constructive modifiers on curve"); + BKE_report(reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers"); return 0; } @@ -638,12 +657,12 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices"); vertexCos = BKE_curve_nurbs_vertexCos_get(&cu->nurb, &numVerts); - mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0); + mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts); BK_curve_nurbs_vertexCos_apply(&cu->nurb, vertexCos); MEM_freeN(vertexCos); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); @@ -660,18 +679,20 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, if (psys->part->type != PART_HAIR) continue; - psys_apply_hair_lattice(scene, ob, psys); + psys_apply_hair_lattice(depsgraph, scene, ob, psys); } } return 1; } -int ED_object_modifier_apply(Main *bmain, ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode) +int ED_object_modifier_apply( + Main *bmain, ReportList *reports, Depsgraph *depsgraph, + Scene *scene, Object *ob, ModifierData *md, int mode) { int prev_mode; - if (scene->obedit) { + if (BKE_object_is_in_editmode(ob)) { BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode"); return 0; } @@ -690,23 +711,29 @@ int ED_object_modifier_apply(Main *bmain, ReportList *reports, Scene *scene, Obj 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->mode; - md->mode |= eModifierMode_Realtime; + prev_mode = md_eval->mode; + md_eval->mode |= eModifierMode_Realtime; if (mode == MODIFIER_APPLY_SHAPE) { - if (!modifier_apply_shape(bmain, reports, scene, ob, md)) { - md->mode = prev_mode; + if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) { + md_eval->mode = prev_mode; return 0; } } else { - if (!modifier_apply_obdata(reports, scene, ob, md)) { - md->mode = prev_mode; + 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); @@ -745,7 +772,7 @@ static int modifier_add_exec(bContext *C, wmOperator *op) } static const EnumPropertyItem *modifier_add_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { Object *ob = ED_object_active_context(C); EnumPropertyItem *item = NULL; @@ -823,6 +850,11 @@ bool edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_fla 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; + } + return 1; } @@ -833,7 +865,8 @@ bool edit_modifier_poll(bContext *C) void edit_modifier_properties(wmOperatorType *ot) { - RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); + 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) @@ -874,7 +907,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) static int modifier_remove_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 = ED_object_active_context(C); ModifierData *md = edit_modifier_property_get(op, ob, 0); int mode_orig = ob->mode; @@ -885,11 +918,13 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) 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 (scene->basact && scene->basact->object == ob) + 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; } @@ -926,7 +961,7 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op) if (!md || !ED_object_modifier_move_up(op->reports, ob, md)) return OPERATOR_CANCELLED; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -965,7 +1000,7 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op) if (!md || !ED_object_modifier_move_down(op->reports, ob, md)) return OPERATOR_CANCELLED; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -999,16 +1034,17 @@ void OBJECT_OT_modifier_move_down(wmOperatorType *ot) 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"); - if (!md || !ED_object_modifier_apply(bmain, op->reports, scene, ob, md, apply_as)) { + if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) { return OPERATOR_CANCELLED; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1051,13 +1087,14 @@ static int modifier_convert_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 = ED_object_active_context(C); ModifierData *md = edit_modifier_property_get(op, ob, 0); - if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, ob, md)) + if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, view_layer, ob, md)) return OPERATOR_CANCELLED; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1096,7 +1133,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) if (!md || !ED_object_modifier_copy(op->reports, ob, md)) return OPERATOR_CANCELLED; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1134,17 +1171,18 @@ static bool multires_poll(bContext *C) 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); if (!mmd) return OPERATOR_CANCELLED; - multiresModifier_del_levels(mmd, 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_multires_update_totlevels_cb, + &mmd->totlvl); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1178,19 +1216,20 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot) 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); if (!mmd) return OPERATOR_CANCELLED; - multiresModifier_subdivide(mmd, 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_multires_update_totlevels_cb, + &mmd->totlvl); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); if (ob->mode & OB_MODE_SCULPT) { @@ -1228,8 +1267,8 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot) static int multires_reshape_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *ob = ED_object_active_context(C), *secondob = NULL; - Scene *scene = CTX_data_scene(C); MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires); if (!mmd) @@ -1254,12 +1293,12 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (!multiresModifier_reshape(scene, mmd, ob, secondob)) { + 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; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1363,8 +1402,8 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot) 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); + 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); } @@ -1400,15 +1439,16 @@ void OBJECT_OT_multires_external_pack(wmOperatorType *ot) /********************* 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); if (!mmd) return OPERATOR_CANCELLED; - multiresModifier_base_apply(mmd, ob); + multiresModifier_base_apply(mmd, scene, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1455,13 +1495,13 @@ static void modifier_skin_customdata_delete(Object *ob) static bool skin_poll(bContext *C) { return (!CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); + 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))); + 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) @@ -1514,7 +1554,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) BLI_gset_free(visited, NULL); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1554,8 +1594,8 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op) 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); + bm_vert->head.data, + CD_MVERT_SKIN); switch (action) { @@ -1569,7 +1609,7 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op) } } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1611,15 +1651,15 @@ static int skin_radii_equalize_exec(bContext *C, wmOperator *UNUSED(op)) 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); + bm_vert->head.data, + CD_MVERT_SKIN); float avg = (vs->radius[0] + vs->radius[1]) * 0.5f; vs->radius[0] = vs->radius[1] = avg; } } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1639,12 +1679,12 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot) } 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) + MVert *mvert, MEdge *medge, + bArmature *arm, + BLI_bitmap *edges_visited, + const MeshElemMap *emap, + EditBone *parent_bone, + int parent_v) { int i; @@ -1679,19 +1719,19 @@ static void skin_armature_bone_create(Object *skin_ob, } skin_armature_bone_create(skin_ob, - mvert, medge, - arm, - edges_visited, - emap, - bone, - v); + mvert, medge, + arm, + edges_visited, + emap, + bone, + v); } } -static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *skin_ob) +static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *skin_ob) { BLI_bitmap *edges_visited; - DerivedMesh *deform_dm; + Mesh *me_eval_deform; MVert *mvert; Mesh *me = skin_ob->data; Object *arm_ob; @@ -1701,17 +1741,18 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object * int *emap_mem; int v; - deform_dm = mesh_get_derived_deform(scene, skin_ob, CD_MASK_BAREMESH); - mvert = deform_dm->getVertArray(deform_dm); + me_eval_deform = mesh_get_eval_deform(depsgraph, scene, skin_ob, 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); + CD_MDEFORMVERT, + CD_CALLOC, + NULL, + me->totvert); - arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL); + 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; @@ -1721,7 +1762,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object * 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); + me->medge, me->totvert, me->totedge); edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); @@ -1746,12 +1787,12 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object * if (emap[v].count >= 1) { skin_armature_bone_create(skin_ob, - mvert, me->medge, - arm, - edges_visited, - emap, - bone, - v); + mvert, me->medge, + arm, + edges_visited, + emap, + bone, + v); } } } @@ -1769,6 +1810,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object * 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; @@ -1781,7 +1823,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) } /* create new armature */ - arm_ob = modifier_skin_armature_create(bmain, scene, ob); + 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); @@ -1791,8 +1833,8 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) arm_md->object = arm_ob; arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION; - DAG_relations_tag_update(bmain); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1859,7 +1901,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) csmd->bind_coords_num = (unsigned int)-1; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -1900,7 +1942,7 @@ static bool meshdeform_poll(bContext *C) static int meshdeform_bind_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *ob = ED_object_active_context(C); MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_MeshDeform); @@ -1928,36 +1970,23 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) mmd->totvert = 0; mmd->totcagevert = 0; mmd->totinfluence = 0; - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); } else { - DerivedMesh *dm; int mode = mmd->modifier.mode; - - /* force modifier to run, it will call binding routine */ mmd->bindfunc = ED_mesh_deform_bind_callback; mmd->modifier.mode |= eModifierMode_Realtime; - if (ob->type == OB_MESH) { - dm = mesh_create_derived_view(scene, ob, 0); - dm->release(dm); - } - else if (ob->type == OB_LATTICE) { - BKE_lattice_modifiers_calc(scene, ob); - } - else if (ob->type == OB_MBALL) { - BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, ob); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - BKE_displist_make_curveTypes(scene, ob, 0); - } + /* Force depsgraph update, this will do binding. */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + BKE_scene_graph_update_tagged(depsgraph, bmain); mmd->bindfunc = NULL; mmd->modifier.mode = mode; } + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + return OPERATOR_FINISHED; } @@ -2003,7 +2032,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op) emd->flag |= eExplodeFlag_CalcFaces; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; @@ -2041,28 +2070,9 @@ static bool ocean_bake_poll(bContext *C) return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0); } -/* copied from init_ocean_modifier, MOD_ocean.c */ -static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData *omd) -{ - int do_heightfield, do_chop, do_normals, do_jacobian; - - if (!omd || !oc) return; - - do_heightfield = true; - do_chop = (omd->chop_amount > 0); - do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); - do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM); - - BKE_ocean_init(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size, - omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment, - omd->depth, omd->time, - do_heightfield, do_chop, do_normals, do_jacobian, - omd->seed); -} - typedef struct OceanBakeJob { /* from wmJob */ - void *owner; + struct Object *owner; short *stop, *do_update; float *progress; int current_frame; @@ -2128,6 +2138,9 @@ static void oceanbake_endjob(void *customdata) oj->omd->oceancache = oj->och; oj->omd->cached = true; + + Object *ob = oj->owner; + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } static int ocean_bake_exec(bContext *C, wmOperator *op) @@ -2148,15 +2161,15 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; if (free) { - omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + BKE_ocean_free_modifier_cache(omd); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE); 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); + 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"); @@ -2177,11 +2190,11 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) * this part of the process before a threaded job is created */ //scene->r.cfra = f; - //ED_update_for_newframe(bmain, scene, 1); + //ED_update_for_newframe(bmain, scene); /* ok, this doesn't work with drivers, but is way faster. * let's use this for now and hope nobody wants to drive the time value... */ - BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); och->time[i] = omd->time; i++; @@ -2189,7 +2202,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) /* make a copy of ocean to use for baking - threadsafety */ ocean = BKE_ocean_add(); - init_ocean_modifier_bake(ocean, omd); + BKE_ocean_init_from_modifier(ocean, omd); #if 0 BKE_ocean_bake(ocean, och); @@ -2199,7 +2212,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) scene->r.cfra = cfra; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); #endif @@ -2209,8 +2222,9 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) /* 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); + 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; @@ -2261,18 +2275,30 @@ static bool laplaciandeform_poll(bContext *C) static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); 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) return OPERATOR_CANCELLED; if (lmd->flag & MOD_LAPLACIANDEFORM_BIND) { + /* Un-binding happens inside the modifier when it's evaluated. */ lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; } else { + int mode = lmd->modifier.mode; + + /* Force modifier to run, it will call binding routine. */ + lmd->modifier.mode |= eModifierMode_Realtime; lmd->flag |= MOD_LAPLACIANDEFORM_BIND; + + object_force_modifier_update_for_bind(depsgraph, scene, ob); + + lmd->modifier.mode = mode; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); return OPERATOR_FINISHED; } @@ -2311,22 +2337,31 @@ static bool surfacedeform_bind_poll(bContext *C) static int surfacedeform_bind_exec(bContext *C, wmOperator *op) { + Scene *scene = CTX_data_scene(C); 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) return OPERATOR_CANCELLED; - if (smd->flags & MOD_SDEF_BIND) { + /* Un-binding happens inside the modifier when it's evaluated. */ smd->flags &= ~MOD_SDEF_BIND; } else if (smd->target) { + int mode = smd->modifier.mode; + + /* Force modifier to run, it will call binding routine. */ + smd->modifier.mode |= eModifierMode_Realtime; smd->flags |= MOD_SDEF_BIND; + + object_force_modifier_update_for_bind(depsgraph, scene, ob); + + smd->modifier.mode = mode; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index f6db6d1f5fc..eb9dd0bbe28 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -40,13 +40,17 @@ #include "BKE_context.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_object.h" +#include "DEG_depsgraph.h" + #include "object_intern.h" @@ -61,21 +65,20 @@ void ED_operatortypes_object(void) 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_hide_view_clear); - WM_operatortype_append(OBJECT_OT_hide_view_set); - WM_operatortype_append(OBJECT_OT_hide_render_clear); - WM_operatortype_append(OBJECT_OT_hide_render_set); 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); @@ -87,40 +90,41 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_slow_parent_set); WM_operatortype_append(OBJECT_OT_slow_parent_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_move_to_layer); WM_operatortype_append(OBJECT_OT_select_random); WM_operatortype_append(OBJECT_OT_select_all); - WM_operatortype_append(OBJECT_OT_select_same_group); + WM_operatortype_append(OBJECT_OT_select_same_collection); WM_operatortype_append(OBJECT_OT_select_by_type); - WM_operatortype_append(OBJECT_OT_select_by_layer); 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(GROUP_OT_create); - WM_operatortype_append(GROUP_OT_objects_remove_all); - WM_operatortype_append(GROUP_OT_objects_remove); - WM_operatortype_append(GROUP_OT_objects_add_active); - WM_operatortype_append(GROUP_OT_objects_remove_active); + 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_lamp_add); + 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_group_instance_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); @@ -146,6 +150,20 @@ void ED_operatortypes_object(void) 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); @@ -202,15 +220,18 @@ void ED_operatortypes_object(void) 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_game_property_new); - WM_operatortype_append(OBJECT_OT_game_property_remove); - WM_operatortype_append(OBJECT_OT_game_property_copy); - WM_operatortype_append(OBJECT_OT_game_property_clear); - WM_operatortype_append(OBJECT_OT_game_property_move); - WM_operatortype_append(OBJECT_OT_logic_bricks_copy); - WM_operatortype_append(OBJECT_OT_game_physics_copy); + 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); @@ -219,11 +240,11 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shape_key_mirror); WM_operatortype_append(OBJECT_OT_shape_key_move); - WM_operatortype_append(OBJECT_OT_group_add); - WM_operatortype_append(OBJECT_OT_group_link); - WM_operatortype_append(OBJECT_OT_group_remove); - WM_operatortype_append(OBJECT_OT_group_unlink); - WM_operatortype_append(OBJECT_OT_grouped_select); + 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); @@ -239,14 +260,15 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_unlink_data); WM_operatortype_append(OBJECT_OT_laplaciandeform_bind); - WM_operatortype_append(OBJECT_OT_lod_add); - WM_operatortype_append(OBJECT_OT_lod_remove); - 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) @@ -283,199 +305,12 @@ static bool object_mode_poll(bContext *C) void ED_keymap_object(wmKeyConfig *keyconf) { wmKeyMap *keymap; - wmKeyMapItem *kmi; - int i; /* Objects, Regardless of Mode -------------------------------------------------- */ keymap = WM_keymap_ensure(keyconf, "Object Non-modal", 0, 0); - /* Note: this keymap works disregarding mode */ - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "mode", OB_MODE_EDIT); - RNA_boolean_set(kmi->ptr, "toggle", true); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "mode", OB_MODE_POSE); - RNA_boolean_set(kmi->ptr, "toggle", true); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", VKEY, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "mode", OB_MODE_VERTEX_PAINT); - RNA_boolean_set(kmi->ptr, "toggle", true); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "mode", OB_MODE_WEIGHT_PAINT); - RNA_boolean_set(kmi->ptr, "toggle", true); - - WM_keymap_add_item(keymap, "OBJECT_OT_origin_set", CKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_CTRL, 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 supports PET now */ - ED_keymap_proportional_cycle(keyconf, keymap); - ED_keymap_proportional_obmode(keyconf, keymap); - - /* game-engine only, leave free for users to define */ - WM_keymap_add_item(keymap, "VIEW3D_OT_game_start", PKEY, KM_PRESS, 0, 0); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", AKEY, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "action", SEL_INVERT); - - WM_keymap_add_item(keymap, "OBJECT_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_select_mirror", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0); - RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT"); - RNA_boolean_set(kmi->ptr, "extend", false); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT"); - RNA_boolean_set(kmi->ptr, "extend", true); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0); - RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD"); - RNA_boolean_set(kmi->ptr, "extend", false); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD"); - RNA_boolean_set(kmi->ptr, "extend", true); - - WM_keymap_verify_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_parent_no_inverse_set", PKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_track_set", TKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_track_clear", TKEY, KM_PRESS, KM_ALT, 0); - - WM_keymap_verify_item(keymap, "OBJECT_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "clear_delta", false); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "clear_delta", false); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "clear_delta", false); - - WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "unselected", false); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "unselected", true); - - /* same as above but for rendering */ - WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_clear", HKEY, KM_PRESS, KM_ALT | KM_CTRL, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_CTRL, 0); - - /* conflicts, removing */ -#if 0 - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0) - RNA_boolean_set(kmi->ptr, "unselected", true); -#endif - - WM_keymap_add_item(keymap, "OBJECT_OT_move_to_layer", MKEY, KM_PRESS, 0, 0); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "use_global", false); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "use_global", true); - - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "use_global", false); - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "use_global", true); - - WM_keymap_add_menu(keymap, "INFO_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_duplicates_make_real", AKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - - WM_keymap_add_menu(keymap, "VIEW3D_MT_object_apply", AKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_menu(keymap, "VIEW3D_MT_make_single_user", UKEY, KM_PRESS, 0, 0); - WM_keymap_add_menu(keymap, "VIEW3D_MT_make_links", LKEY, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move_linked", DKEY, KM_PRESS, KM_ALT, 0); - - WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_convert", CKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_proxy_make", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - WM_keymap_add_item(keymap, "OBJECT_OT_make_local", LKEY, KM_PRESS, 0, 0); - - /* XXX this should probably be in screen instead... here for testing purposes in the meantime... - Aligorith */ - WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert_menu", IKEY, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete_v3d", IKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_verify_item(keymap, "ANIM_OT_keying_set_active_set", IKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0); - - WM_keymap_verify_item(keymap, "GROUP_OT_create", GKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_all", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0); - - WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0); - - WM_keymap_verify_item(keymap, "OBJECT_OT_data_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - /* XXX No more available 'T' shortcuts... :/ */ - /* WM_keymap_verify_item(keymap, "OBJECT_OT_datalayout_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); */ - - for (i = 0; i <= 5; i++) { - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0); - RNA_int_set(kmi->ptr, "level", i); - } -} - -void ED_keymap_proportional_cycle(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap) -{ - wmKeyMapItem *kmi; - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_enum", OKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit_falloff"); - RNA_boolean_set(kmi->ptr, "wrap", true); -} - -void ED_keymap_proportional_obmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap) -{ - wmKeyMapItem *kmi; - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_edit_objects"); -} - -void ED_keymap_proportional_maskmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap) -{ - wmKeyMapItem *kmi; - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_edit_mask"); -} - -void ED_keymap_proportional_editmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap, - const bool do_connected) -{ - wmKeyMapItem *kmi; - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", OKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit"); - RNA_string_set(kmi->ptr, "value_1", "DISABLED"); - RNA_string_set(kmi->ptr, "value_2", "ENABLED"); - - /* for modes/object types that allow 'connected' mode, add the Alt O key */ - if (do_connected) { - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", OKEY, KM_PRESS, KM_ALT, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit"); - RNA_string_set(kmi->ptr, "value_1", "DISABLED"); - RNA_string_set(kmi->ptr, "value_2", "CONNECTED"); - } } diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c index 05726e5be2d..8291b68f15f 100644 --- a/source/blender/editors/object/object_random.c +++ b/source/blender/editors/object/object_random.c @@ -25,6 +25,9 @@ * \ingroup edobj */ +#include "MEM_guardedalloc.h" + +#include "DNA_layer_types.h" #include "DNA_object_types.h" #include "BLI_math.h" @@ -32,6 +35,7 @@ #include "BKE_context.h" +#include "BKE_layer.h" #include "RNA_access.h" #include "RNA_define.h" @@ -94,34 +98,53 @@ static bool object_rand_transverts( 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"); - TransVertStore tvs = {NULL}; - Object *obedit = CTX_data_edit_object(C); + 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]; - if (obedit) { - int mode = TM_ALL_JOINTS; + TransVertStore tvs = { NULL }; - if (normal_factor != 0.0f) { - mode |= TX_VERT_USE_NORMAL; - } + if (ob_iter) { + int mode = TM_ALL_JOINTS; - ED_transverts_create_from_obedit(&tvs, obedit, mode); - if (tvs.transverts_tot == 0) - return OPERATOR_CANCELLED; + if (normal_factor != 0.0f) { + mode |= TX_VERT_USE_NORMAL; + } - object_rand_transverts(&tvs, offset, uniform, normal_factor, seed); + ED_transverts_create_from_obedit(&tvs, ob_iter, mode); + if (tvs.transverts_tot == 0) { + continue; + } - ED_transverts_update_obedit(&tvs, obedit); - ED_transverts_free(&tvs); - } + 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, obedit); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter); + changed_multi = true; + } + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot) @@ -139,10 +162,12 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ - RNA_def_float(ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f); + ot->prop = RNA_def_float( + ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, + "Amount", "Distance to offset", -10.0f, 10.0f); RNA_def_float(ot->srna, "uniform", 0.0f, 0.0f, 1.0f, "Uniform", "Increase for uniform offset distance", 0.0f, 1.0f); - RNA_def_float(ot->srna, "normal", 0.0f, 0.0f, 1.0f, "normal", + RNA_def_float(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 d27edb5a9e4..5121f1534bd 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -37,8 +37,8 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_mesh_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" -#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" @@ -63,21 +63,25 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_displist.h" +#include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_group.h" +#include "BKE_gpencil.h" #include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" +#include "BKE_lightprobe.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -86,11 +90,12 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_report.h" -#include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_speaker.h" #include "BKE_texture.h" -#include "BKE_editmesh.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "WM_api.h" #include "WM_types.h" @@ -104,6 +109,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_gpencil.h" #include "ED_keyframing.h" #include "ED_object.h" #include "ED_mesh.h" @@ -123,10 +129,12 @@ 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; - Curve *cu; Nurb *nu; BezTriple *bezt; BPoint *bp; @@ -142,7 +150,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) EDBM_mesh_load(bmain, obedit); EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); em = me->edit_btmesh; @@ -151,7 +159,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* derivedMesh might be needed for solving parenting, * so re-create it here */ - makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false); + makeDerivedMesh(depsgraph, scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { @@ -167,15 +175,13 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) { ListBase *editnurb = object_editcurve_get(obedit); - cu = obedit->data; - nu = editnurb->first; while (nu) { if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; while (a--) { - if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) { + if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) { if (v1 == 0) v1 = nr; else if (v2 == 0) v2 = nr; else if (v3 == 0) v3 = nr; @@ -230,7 +236,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obedit) { - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); par = obedit->parent; if (BKE_object_parent_loop_check(par, ob)) { @@ -239,7 +245,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) else { Object workob; - ob->parent = BASACT->object; + ob->parent = BASACT(view_layer)->object; if (v3) { ob->partype = PARVERT3; ob->par1 = v1 - 1; @@ -247,7 +253,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) ob->par3 = v3 - 1; /* inverse parent matrix */ - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } else { @@ -255,7 +261,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) ob->par1 = v1 - 1; /* inverse parent matrix */ - BKE_object_workob_calc_parent(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } } @@ -263,7 +269,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT, NULL); @@ -322,7 +328,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* error.. cannot continue */ - BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group"); + BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); return OPERATOR_CANCELLED; } @@ -332,44 +338,42 @@ static int make_proxy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob, *gob = ED_object_active_context(C); - GroupObject *go; Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); if (gob->dup_group != NULL) { - go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object")); - ob = go->ob; + const ListBase dup_group_objects = BKE_collection_object_cache_get(gob->dup_group); + Base *base = BLI_findlink(&dup_group_objects, RNA_enum_get(op->ptr, "object")); + ob = base->object; } else { ob = gob; - gob = NULL; } if (ob) { Object *newob; - Base *newbase, *oldbase = BASACT; 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(bmain, scene, OB_EMPTY, name); + newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob); /* set layers OK */ - newbase = BASACT; /* BKE_object_add sets active... */ - newbase->lay = oldbase->lay; - newob->lay = newbase->lay; - - /* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */ - if (gob == NULL) { - BKE_scene_base_unlink(scene, oldbase); - MEM_freeN(oldbase); - } - - BKE_object_make_proxy(newob, ob, gob); + 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 */ - DAG_relations_tag_update(bmain); - DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob); } else { @@ -381,24 +385,25 @@ static int make_proxy_exec(bContext *C, wmOperator *op) } /* Generic itemf's for operators that take library args */ -static const EnumPropertyItem *proxy_group_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); - GroupObject *go; if (!ob || !ob->dup_group) return DummyRNA_DEFAULT_items; /* find the object to affect */ - for (go = ob->dup_group->gobject.first; go; go = go->next) { - item_tmp.identifier = item_tmp.name = go->ob->id.name + 2; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, 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; @@ -426,8 +431,8 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot) /* 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/grouped object to make a proxy for"); - RNA_def_enum_funcs(prop, proxy_group_object_itemf); + "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; } @@ -524,7 +529,7 @@ void ED_object_parent_clear(Object *ob, const int type) /* Always clear parentinv matrix for sake of consistency, see T41950. */ unit_m4(ob->parentinv); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } /* note, poll should check for editable scene */ @@ -539,7 +544,7 @@ static int parent_clear_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + 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; @@ -607,13 +612,15 @@ EnumPropertyItem prop_make_parent_types[] = { {0, NULL, 0, NULL, NULL} }; -bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par, +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; const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); - DAG_id_tag_update(&par->id, OB_RECALC_OB); + DEG_id_tag_update(&par->id, OB_RECALC_OB); /* preconditions */ if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) { @@ -624,7 +631,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if ((cu->flag & CU_PATH) == 0) { cu->flag |= CU_PATH | CU_FOLLOW; - BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */ + BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); /* force creation of path data */ } else { cu->flag |= CU_FOLLOW; @@ -634,7 +641,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if (partype == PAR_FOLLOW) { /* get or create F-Curve */ bAction *act = verify_adt_action(bmain, &cu->id, 1); - FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 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) @@ -709,8 +716,8 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if (md) { ((CurveModifierData *)md)->object = par; } - if (par->curve_cache && par->curve_cache->path == NULL) { - DAG_id_tag_update(&par->id, OB_RECALC_DATA); + if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { + DEG_id_tag_update(&par->id, OB_RECALC_DATA); } } break; @@ -766,34 +773,53 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object data = con->data; data->tar = par; - BKE_constraint_target_matrix_get(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + 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, scene, ob, par, ARM_GROUPS_NAME, false); - else if (partype == PAR_ARMATURE_ENVELOPE) - ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); + 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, scene, ob, par, ARM_GROUPS_AUTO, xmirror); + 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(scene, ob, &workob); + 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(scene, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); } - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); } } @@ -864,7 +890,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) parent_set_vert_find(tree, ob, vert_par, is_tri); } - if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { + if (!ED_object_parent_set(op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { ok = false; break; } @@ -879,7 +905,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) if (!ok) return OPERATOR_CANCELLED; - DAG_relations_tag_update(bmain); + 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); @@ -984,7 +1010,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Object *par = ED_object_active_context(C); - DAG_id_tag_update(&par->id, OB_RECALC_OB); + DEG_id_tag_update(&par->id, OB_RECALC_OB); /* context iterator */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) @@ -999,7 +1025,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) memset(ob->loc, 0, 3 * sizeof(float)); /* set recalc flags */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); /* set parenting type for object - object only... */ ob->parent = par; @@ -1009,7 +1035,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1035,6 +1061,7 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot) static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) @@ -1042,9 +1069,9 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->parent) { if (ob->partype & PARSLOW) { ob->partype -= PARSLOW; - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); ob->partype |= PARSLOW; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } } } @@ -1082,7 +1109,7 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->parent) ob->partype |= PARSLOW; - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; @@ -1136,7 +1163,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) /* remove track-object for old track */ ob->track = NULL; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* also remove all tracking constraints */ for (con = ob->constraints.last; con; con = pcon) { @@ -1150,7 +1177,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1210,7 +1237,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1233,7 +1260,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1257,7 +1284,7 @@ static int track_set_exec(bContext *C, wmOperator *op) data = con->data; data->tar = obact; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { @@ -1271,7 +1298,7 @@ static int track_set_exec(bContext *C, wmOperator *op) } } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -1297,120 +1324,6 @@ void OBJECT_OT_track_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", ""); } -/************************** Move to Layer Operator *****************************/ - -static unsigned int move_to_layer_init(bContext *C, wmOperator *op) -{ - int a; - bool values[20]; - unsigned int lay = 0; - - if (!RNA_struct_property_is_set(op->ptr, "layers")) { - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay |= base->lay; - } - CTX_DATA_END; - - for (a = 0; a < 20; a++) - values[a] = (lay & (1 << a)) != 0; - - RNA_boolean_set_array(op->ptr, "layers", values); - } - else { - RNA_boolean_get_array(op->ptr, "layers", values); - - for (a = 0; a < 20; a++) - if (values[a]) - lay |= (1 << a); - } - - return lay; -} - -static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - if (v3d && v3d->localvd) { - return WM_operator_confirm_message(C, op, "Move out of Local View"); - } - else { - move_to_layer_init(C, op); - return WM_operator_props_popup(C, op, event); - } -} - -static int move_to_layer_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - unsigned int lay, local; - /* bool is_lamp = false; */ /* UNUSED */ - - lay = move_to_layer_init(C, op); - lay &= 0xFFFFFF; - - if (lay == 0) return OPERATOR_CANCELLED; - - if (v3d && v3d->localvd) { - /* now we can move out of localview. */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - lay = base->lay & ~v3d->lay; - base->lay = lay; - base->object->lay = lay; - base->object->flag &= ~SELECT; - base->flag &= ~SELECT; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - else { - /* normal non localview operation */ - /* note: layers are set in bases, library objects work for this */ - CTX_DATA_BEGIN (C, Base *, base, selected_bases) - { - /* upper byte is used for local view */ - local = base->lay & 0xFF000000; - base->lay = lay + local; - base->object->lay = base->lay; - /* if (base->object->type == OB_LAMP) is_lamp = true; */ - } - CTX_DATA_END; - } - - /* warning, active object may be hidden now */ - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - - DAG_relations_tag_update(bmain); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_move_to_layer(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Move to Layer"; - ot->description = "Move the object to different layers"; - ot->idname = "OBJECT_OT_move_to_layer"; - - /* api callbacks */ - ot->invoke = move_to_layer_invoke; - ot->exec = move_to_layer_exec; - ot->poll = ED_operator_objectmode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", ""); -} - /************************** Link to Scene Operator *****************************/ #if 0 @@ -1433,23 +1346,10 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr)) } #endif -Base *ED_object_scene_link(Scene *scene, Object *ob) -{ - Base *base; - - if (BKE_scene_base_find(scene, ob)) { - return NULL; - } - - base = BKE_scene_base_add(scene, ob); - id_us_plus(&ob->id); - - return base; -} - static int make_links_scene_exec(bContext *C, wmOperator *op) { - Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene")); + Main *bmain = CTX_data_main(C); + Scene *scene_to = BLI_findlink(&bmain->scene, RNA_enum_get(op->ptr, "scene")); if (scene_to == NULL) { BKE_report(op->reports, RPT_ERROR, "Could not find scene"); @@ -1466,9 +1366,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Collection *collection_to = BKE_collection_master(scene_to); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - ED_object_scene_link(scene_to, base->object); + BKE_collection_object_add(bmain, collection_to, base->object); } CTX_DATA_END; @@ -1484,7 +1385,7 @@ enum { MAKE_LINKS_MATERIALS = 2, MAKE_LINKS_ANIMDATA = 3, MAKE_LINKS_GROUP = 4, - MAKE_LINKS_DUPLIGROUP = 5, + MAKE_LINKS_DUPLICOLLECTION = 5, MAKE_LINKS_MODIFIERS = 6, MAKE_LINKS_FONTS = 7, }; @@ -1505,7 +1406,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst break; case MAKE_LINKS_ANIMDATA: case MAKE_LINKS_GROUP: - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: return true; case MAKE_LINKS_MODIFIERS: if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) { @@ -1523,23 +1424,23 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst static int make_links_data_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); 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; - /* group */ - LinkNode *ob_groups = NULL; + /* collection */ + LinkNode *ob_collections = NULL; bool is_cycle = false; bool is_lib = false; ob_src = ED_object_active_context(C); - /* avoid searching all groups in source object each time */ + /* avoid searching all collections in source object each time */ if (type == MAKE_LINKS_GROUP) { - ob_groups = BKE_object_groups(bmain, ob_src); + ob_collections = BKE_object_groups(bmain, ob_src); } CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases) @@ -1561,7 +1462,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) /* if amount of material indices changed: */ test_object_materials(bmain, ob_dst, ob_dst->data); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_MATERIALS: /* new approach, using functions from kernel */ @@ -1569,30 +1470,30 @@ static int make_links_data_exec(bContext *C, wmOperator *op) Material *ma = give_current_material(ob_src, a + 1); assign_material(bmain, ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */ } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_ANIMDATA: - BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false); + 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, false); + BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, 0); } - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; case MAKE_LINKS_GROUP: { - LinkNode *group_node; + LinkNode *collection_node; - /* first clear groups */ - BKE_object_groups_clear(bmain, scene, base_dst, ob_dst); + /* first clear collections */ + BKE_object_groups_clear(bmain, ob_dst); - /* now add in the groups from the link nodes */ - for (group_node = ob_groups; group_node; group_node = group_node->next) { - if (ob_dst->dup_group != group_node->link) { - BKE_group_object_add(group_node->link, ob_dst, scene, base_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->dup_group != collection_node->link) { + BKE_collection_object_add(bmain, collection_node->link, ob_dst); } else { is_cycle = true; @@ -1600,16 +1501,16 @@ static int make_links_data_exec(bContext *C, wmOperator *op) } break; } - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: ob_dst->dup_group = ob_src->dup_group; if (ob_dst->dup_group) { id_us_plus(&ob_dst->dup_group->id); - ob_dst->transflag |= OB_DUPLIGROUP; + ob_dst->transflag |= OB_DUPLICOLLECTION; } break; case MAKE_LINKS_MODIFIERS: - BKE_object_link_modifiers(ob_dst, ob_src); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + BKE_object_link_modifiers(scene, ob_dst, ob_src); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; case MAKE_LINKS_FONTS: { @@ -1638,7 +1539,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) cu_dst->vfontbi = cu_src->vfontbi; id_us_plus((ID *)cu_dst->vfontbi); - DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); break; } } @@ -1648,12 +1549,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op) CTX_DATA_END; if (type == MAKE_LINKS_GROUP) { - if (ob_groups) { - BLI_linklist_free(ob_groups, NULL); + if (ob_collections) { + BLI_linklist_free(ob_collections, NULL); } if (is_cycle) { - BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); } } @@ -1661,7 +1562,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_WARNING, "Skipped editing library object data"); } - DAG_relations_tag_update(bmain); + 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); @@ -1701,7 +1602,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""}, {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""}, {MAKE_LINKS_GROUP, "GROUPS", 0, "Group", ""}, - {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""}, + {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "DupliGroup", ""}, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, {0, NULL, 0, NULL, NULL}}; @@ -1725,101 +1626,110 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ -/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ -static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) +static void libblock_relink_collection(Collection *collection) { - Base *base; - Object *ob, *obn; - Group *group, *groupn; - GroupObject *go; - - clear_sca_new_poins(); /* BGE logic */ - - /* duplicate (must set newid) */ - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; + BKE_libblock_relink_to_newid(&collection->id); - if ((base->flag & flag) == flag) { - if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - /* base gets copy of object */ - base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ - } - /* remap gpencil parenting */ + for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { + BKE_libblock_relink_to_newid(&cob->ob->id); + } - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } - } - } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + libblock_relink_collection(child->collection); + } +} - base->flag = obn->flag; +static void 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)); + } - id_us_min(&ob->id); + /* 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) && ob->id.us > 1) { + ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); } } } - /* duplicate groups that consist entirely of duplicated objects */ - for (group = bmain->group.first; group; group = group->id.next) { - if (copy_groups && group->gobject.first) { + for (CollectionChild *child = collection->children.first; child; child = child->next) { + single_object_users_collection(bmain, scene, child->collection, flag, copy_collections, false); + } +} + +/* 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) +{ + /* 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->collection.first; collection; collection = collection->id.next) { bool all_duplicated = true; + bool any_duplicated = false; - for (go = group->gobject.first; go; go = go->next) { - if (!(go->ob && (go->ob->id.newid))) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + any_duplicated = true; + if (cob->ob->id.newid == NULL) { all_duplicated = false; break; } } - if (all_duplicated) { - groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); + 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 (go = groupn->gobject.first; go; go = go->next) { - go->ob = (Object *)go->ob->id.newid; + 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); - /* group pointers in scene */ + /* collection pointers in scene */ BKE_scene_groups_relink(scene); + /* active camera */ ID_NEW_REMAP(scene->camera); if (v3d) ID_NEW_REMAP(v3d->camera); - /* object and group pointers */ - for (base = FIRSTBASE; base; base = base->next) { - BKE_libblock_relink_to_newid(&base->object->id); - } - - set_sca_new_poins(); + BKE_scene_collection_sync(scene); } /* 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) { - Base *base; - const bool copy_groups = false; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->object == ob) base->flag |= OB_DONE; - else base->flag &= ~OB_DONE; + FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter) + { + ob_iter->flag &= ~OB_DONE; } + FOREACH_SCENE_OBJECT_END; - single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); + /* tag only the one object */ + ob->flag |= OB_DONE; + single_object_users(bmain, scene, NULL, OB_DONE, false); BKE_main_id_clear_newpoins(bmain); } @@ -1844,34 +1754,26 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol) } } -static void single_obdata_users(Main *bmain, Scene *scene, const int flag) +static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; Lamp *la; Curve *cu; /* Camera *cam; */ - Base *base; Mesh *me; Lattice *lat; ID *id; - int a; - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (base->flag & flag) == flag) { + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { id = ob->data; if (id && id->us > 1 && !ID_IS_LINKED(id)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); switch (ob->type) { case OB_LAMP: ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data)); - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a]) { - ID_NEW_REMAP(la->mtex[a]->object); - } - } break; case OB_CAMERA: ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); @@ -1900,16 +1802,25 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false); break; case OB_ARMATURE: - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); - BKE_pose_rebuild(ob, 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: - if (G.debug & G_DEBUG) - printf("ERROR %s: can't copy %s\n", __func__, id->name); + 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; } @@ -1924,6 +1835,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } } } + FOREACH_OBJECT_FLAG_END; me = bmain->mesh.first; while (me) { @@ -1932,31 +1844,26 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } } -static void single_object_action_users(Main *bmain, Scene *scene, const int flag) +static void single_object_action_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); BKE_animdata_copy_id_action(bmain, &ob->id, false); } } + FOREACH_OBJECT_FLAG_END; } -static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures) +static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag) { - Object *ob; - Base *base; Material *ma, *man; - Tex *tex; - int a, b; + int a; - for (base = FIRSTBASE; base; base = base->next) { - ob = base->object; - if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) { + FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob) + { + if (!ID_IS_LINKED(ob)) { for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { @@ -1968,84 +1875,12 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo man->id.us = 0; assign_material(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF); - - if (do_textures) { - for (b = 0; b < MAX_MTEX; b++) { - if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) { - if (tex->id.us > 1) { - id_us_min(&tex->id); - tex = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(bmain, &tex->id, false); - man->mtex[b]->tex = tex; - } - } - } - } } } } } } -} - -static void do_single_tex_user(Main *bmain, Tex **from) -{ - Tex *tex, *texn; - - tex = *from; - if (tex == NULL) return; - - if (tex->id.newid) { - *from = (Tex *)tex->id.newid; - id_us_plus(tex->id.newid); - id_us_min(&tex->id); - } - else if (tex->id.us > 1) { - texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex)); - BKE_animdata_copy_id_action(bmain, &texn->id, false); - tex->id.newid = (ID *)texn; - id_us_min(&tex->id); - *from = texn; - } -} - -static void single_tex_users_expand(Main *bmain) -{ - /* only when 'parent' blocks are LIB_TAG_NEW */ - Material *ma; - Lamp *la; - World *wo; - int b; - - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (ma->mtex[b] && ma->mtex[b]->tex) { - do_single_tex_user(bmain, &(ma->mtex[b]->tex)); - } - } - } - } - - for (la = bmain->lamp.first; la; la = la->id.next) { - if (la->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (la->mtex[b] && la->mtex[b]->tex) { - do_single_tex_user(bmain, &(la->mtex[b]->tex)); - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - if (wo->id.tag & LIB_TAG_NEW) { - for (b = 0; b < MAX_MTEX; b++) { - if (wo->mtex[b] && wo->mtex[b]->tex) { - do_single_tex_user(bmain, &(wo->mtex[b]->tex)); - } - } - } - } + FOREACH_OBJECT_FLAG_END; } static void single_mat_users_expand(Main *bmain) @@ -2055,8 +1890,7 @@ static void single_mat_users_expand(Main *bmain) Mesh *me; Curve *cu; MetaBall *mb; - Material *ma; - int a; + bGPdata *gpd; for (ob = bmain->object.first; ob; ob = ob->id.next) if (ob->id.tag & LIB_TAG_NEW) @@ -2074,24 +1908,20 @@ static void single_mat_users_expand(Main *bmain) if (mb->id.tag & LIB_TAG_NEW) new_id_matar(bmain, mb->mat, mb->totcol); - /* material imats */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) - if (ma->id.tag & LIB_TAG_NEW) - for (a = 0; a < MAX_MTEX; a++) - if (ma->mtex[a]) - ID_NEW_REMAP(ma->mtex[a]->object); + for (gpd = bmain->gpencil.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_groups) +void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_collections) { - single_object_users(bmain, scene, NULL, 0, copy_groups); + single_object_users(bmain, scene, NULL, 0, copy_collections); if (full) { - single_obdata_users(bmain, scene, 0); - single_object_action_users(bmain, scene, 0); + single_obdata_users(bmain, scene, NULL, 0); + single_object_action_users(bmain, scene, NULL, 0); single_mat_users_expand(bmain); - single_tex_users_expand(bmain); } /* Relink nodetrees' pointers that have been duplicated. */ @@ -2110,12 +1940,13 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo { IDP_RelinkProperty(scene->id.properties); - for (Base *base = scene->base.first; base; base = base->next) { - Object *ob = base->object; + 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); @@ -2124,10 +1955,6 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo } } - if (scene->gpd) { - IDP_RelinkProperty(scene->gpd->id.properties); - } - if (scene->world) { IDP_RelinkProperty(scene->world->id.properties); } @@ -2137,7 +1964,7 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo } } BKE_main_id_clear_newpoins(bmain); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } /******************************* Make Local ***********************************/ @@ -2204,7 +2031,7 @@ static void tag_localizable_objects(bContext *C, const int mode) * Instance indirectly referenced zero user objects, * otherwise they're lost on reload, see T40595. */ -static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) +static bool make_local_all__instance_indirect_unused(Main *bmain, ViewLayer *view_layer, Collection *collection) { Object *ob; bool changed = false; @@ -2215,10 +2042,11 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) id_us_plus(&ob->id); - base = BKE_scene_base_add(scene, ob); - base->flag |= SELECT; - base->object->flag = base->flag; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + 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, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); changed = true; } @@ -2235,9 +2063,6 @@ static void make_local_animdata_tag_strips(ListBase *strips) if (strip->act) { strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING; } - if (strip->remap && strip->remap->target) { - strip->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING; - } make_local_animdata_tag_strips(&strip->strips); } @@ -2254,10 +2079,6 @@ static void make_local_animdata_tag(AnimData *adt) if (adt->tmpact) { adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING; } - /* Remaps */ - if (adt->remap && adt->remap->target) { - adt->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING; - } /* Drivers */ /* TODO: need to handle the ID-targets too? */ @@ -2276,33 +2097,28 @@ static void make_local_material_tag(Material *ma) 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... */ - - for (int a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex) { - ma->mtex[a]->tex->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - } } } static int make_local_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ParticleSystem *psys; Material *ma, ***matarar; - Lamp *la; 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_scene_base_deselect_all(scene); + /* 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, scene)) { + 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"); } } @@ -2339,16 +2155,6 @@ static int make_local_exec(bContext *C, wmOperator *op) } } } - - if (ob->type == OB_LAMP) { - BLI_assert(ob->data != NULL); - la = ob->data; - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex) { - la->id.tag &= ~LIB_TAG_PRE_EXISTING; - } - } - } } if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) { @@ -2393,6 +2199,234 @@ void OBJECT_OT_make_local(wmOperatorType *ot) 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); + } +} + +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); + } +} + +/* 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->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + /* 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->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + Object *obcollection = obact; + Collection *collection = obcollection->dup_group; + + 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, DEG_TAG_TRANSFORM | DEG_TAG_BASE_FLAGS_UPDATE); + } + /* 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->dup_group = 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->object, 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->object.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->object, 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 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->dup_group != NULL && ID_IS_LINKED(obact->dup_group)))); +} + +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; +} + enum { MAKE_SINGLE_USER_ALL = 1, MAKE_SINGLE_USER_SELECTED = 2, @@ -2402,32 +2436,35 @@ 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_groups = false; + const bool copy_collections = false; bool update_deps = false; if (RNA_boolean_get(op->ptr, "object")) { - single_object_users(bmain, scene, v3d, flag, copy_groups); + 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, flag); + single_obdata_users(bmain, scene, view_layer, flag); } if (RNA_boolean_get(op->ptr, "material")) { - single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture")); + single_mat_users(bmain, scene, view_layer, flag); } -#if 0 /* can't do this separate from materials */ - if (RNA_boolean_get(op->ptr, "texture")) - single_mat_users(scene, flag, true); -#endif if (RNA_boolean_get(op->ptr, "animation")) { - single_object_action_users(bmain, scene, flag); + single_object_action_users(bmain, scene, view_layer, flag); } BKE_main_id_clear_newpoins(bmain); @@ -2435,7 +2472,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); if (update_deps) { - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } return OPERATOR_FINISHED; @@ -2467,8 +2504,6 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) 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, "texture", 0, "Textures", - "Make textures local to each material (needs 'Materials' to be set too)"); RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); } @@ -2486,7 +2521,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent assign_material(CTX_data_main(C), base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF); - DAG_id_tag_update(&base->object->id, OB_RECALC_OB); + DEG_id_tag_update(&base->object->id, OB_RECALC_OB); 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)); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 2fc6207d6c1..7c03e93f4b2 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -34,15 +34,17 @@ #include <string.h> #include "DNA_anim_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_material_types.h" #include "DNA_modifier_types.h" -#include "DNA_property_types.h" #include "DNA_scene_types.h" #include "DNA_armature_types.h" #include "DNA_lamp_types.h" +#include "DNA_workspace_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_listbase.h" #include "BLI_rand.h" #include "BLI_string_utils.h" @@ -50,22 +52,31 @@ #include "BLT_translation.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" +#include "BKE_deform.h" +#include "BKE_layer.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_particle.h" -#include "BKE_property.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_library.h" -#include "BKE_deform.h" +#include "BKE_workspace.h" + +#include "DEG_depsgraph.h" #include "WM_api.h" #include "WM_types.h" +#include "ED_armature.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_keyframing.h" #include "UI_interface.h" @@ -83,40 +94,280 @@ * this takes into account the 'restrict selection in 3d view' flag. * deselect works always, the restriction just prevents selection */ -/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or - * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */ + /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or + * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */ -void ED_base_object_select(Base *base, short mode) +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) { - if (mode == BA_SELECT) { - if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) - base->flag |= SELECT; - } - else if (mode == BA_DESELECT) { - base->flag &= ~SELECT; + 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; } - base->object->flag = base->flag; + BKE_scene_object_base_flag_sync_from_base(base); } } -/* also to set active NULL */ -void ED_base_object_activate(bContext *C, Base *base) +/** + * Change active base, it includes the notifier + */ +void ED_object_base_activate(bContext *C, Base *base) { Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + view_layer->basact = base; - /* sets scene->basact */ - BASACT = base; + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_SELECT_UPDATE); +} - if (base) { +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; +} - /* XXX old signals, remember to handle notifiers now! */ - // select_actionchannel_by_name(base->object->action, "Object", 1); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); +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); +} + +/********************** Jump To Object Utilities **********************/ + +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; } - else - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL); +} + +/** + * If id is not already an Object, try to find an object that uses it as data. + * Prefers active, then selected, then visible/selectable. + */ +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; +} + +/** + * Select and make the target object active in the view layer. + * If already selected, selection isn't changed. + * + * \returns false if not found in current view layer + */ +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); + + if (base == NULL) { + return false; + } + + /* 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 (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)); + } + + /* Make active if not active. */ + ED_object_base_activate(C, base); + } + + return true; +} + +/** + * Select and make the target object and bone active. + * Switches to Pose mode if in Object mode so the selection is visible. + * Unhides the target bone and bone layer if necessary. + * + * \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) +{ + /* 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; } /********************** Selection Operators **********************/ @@ -139,28 +390,28 @@ 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) { - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - ED_base_object_select(base, BA_DESELECT); - } - CTX_DATA_END; + ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); } CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (base->object->type == obtype) { - ED_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); } } CTX_DATA_END; - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } @@ -191,7 +442,6 @@ enum { OBJECT_SELECT_LINKED_IPO = 1, OBJECT_SELECT_LINKED_OBDATA, OBJECT_SELECT_LINKED_MATERIAL, - OBJECT_SELECT_LINKED_TEXTURE, OBJECT_SELECT_LINKED_DUPGROUP, OBJECT_SELECT_LINKED_PARTICLE, OBJECT_SELECT_LINKED_LIBRARY, @@ -202,7 +452,6 @@ 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_TEXTURE, "TEXTURE", 0, "Texture", ""}, {OBJECT_SELECT_LINKED_DUPGROUP, "DUPGROUP", 0, "Dupligroup", ""}, {OBJECT_SELECT_LINKED_PARTICLE, "PARTICLE", 0, "Particle System", ""}, {OBJECT_SELECT_LINKED_LIBRARY, "LIBRARY", 0, "Library", ""}, @@ -210,38 +459,15 @@ static const EnumPropertyItem prop_select_linked_types[] = { {0, NULL, 0, NULL, NULL} }; -// XXX old animation system -#if 0 -static int object_select_all_by_ipo(bContext *C, Ipo *ipo) -{ - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (base->object->ipo == ipo) { - base->flag |= SELECT; - base->object->flag = base->flag; - - changed = true; - } - } - CTX_DATA_END; - - return changed; -} -#endif - 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 & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { if (base->object->data == obdata) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -251,40 +477,25 @@ static bool object_select_all_by_obdata(bContext *C, void *obdata) return changed; } -static bool object_select_all_by_material_texture(bContext *C, int use_texture, Material *mat, Tex *tex) +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 & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { Object *ob = base->object; Material *mat1; - int a, b; + int a; for (a = 1; a <= ob->totcol; a++) { mat1 = give_current_material(ob, a); - if (!use_texture) { - if (mat1 == mat) { - base->flag |= SELECT; - changed = true; - } - } - else if (mat1 && use_texture) { - for (b = 0; b < MAX_MTEX; b++) { - if (mat1->mtex[b]) { - if (tex == mat1->mtex[b]->tex) { - base->flag |= SELECT; - changed = true; - break; - } - } - } + if (mat1 == mat) { + ED_object_base_select(base, BA_SELECT); + changed = true; } } - - base->object->flag = base->flag; } } CTX_DATA_END; @@ -295,16 +506,14 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture, static bool object_select_all_by_dup_group(bContext *C, Object *ob) { bool changed = false; - Group *dup_group = (ob->transflag & OB_DUPLIGROUP) ? ob->dup_group : NULL; + Collection *dup_group = (ob->transflag & OB_DUPLICOLLECTION) ? ob->dup_group : NULL; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { - Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL; + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { + Collection *dup_group_other = (base->object->transflag & OB_DUPLICOLLECTION) ? base->object->dup_group : NULL; if (dup_group == dup_group_other) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -321,23 +530,21 @@ static bool object_select_all_by_particle(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + 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) { - base->flag |= SELECT; + ED_object_base_select(base, BA_SELECT); changed = true; break; } - if (base->flag & SELECT) { + if (base->flag & BASE_SELECTED) { break; } } - - base->object->flag = base->flag; } } CTX_DATA_END; @@ -351,11 +558,9 @@ static bool object_select_all_by_library(bContext *C, Library *lib) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { if (lib == base->object->id.lib) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -371,11 +576,9 @@ static bool object_select_all_by_library_obdata(bContext *C, Library *lib) CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if ((base->flag & SELECT) == 0) { + if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) { if (base->object->data && lib == ((ID *)base->object->data)->lib) { - base->flag |= SELECT; - base->object->flag = base->flag; - + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -394,20 +597,24 @@ void ED_object_select_linked_by_id(bContext *C, ID *id) changed = object_select_all_by_obdata(C, id); } else if (idtype == ID_MA) { - changed = object_select_all_by_material_texture(C, false, (Material *)id, NULL); + 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) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + 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; @@ -415,14 +622,10 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) extend = RNA_boolean_get(op->ptr, "extend"); if (extend == 0) { - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - ED_base_object_select(base, BA_DESELECT); - } - CTX_DATA_END; + ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); } - ob = OBACT; + ob = OBACT(view_layer); if (ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; @@ -440,21 +643,13 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) changed = object_select_all_by_obdata(C, ob->data); } - else if (nr == OBJECT_SELECT_LINKED_MATERIAL || nr == OBJECT_SELECT_LINKED_TEXTURE) { + else if (nr == OBJECT_SELECT_LINKED_MATERIAL) { Material *mat = NULL; - Tex *tex = NULL; - bool use_texture = false; mat = give_current_material(ob, ob->actcol); if (mat == NULL) return OPERATOR_CANCELLED; - if (nr == OBJECT_SELECT_LINKED_TEXTURE) { - use_texture = true; - if (mat->mtex[(int)mat->texact]) tex = mat->mtex[(int)mat->texact]->tex; - if (tex == NULL) return OPERATOR_CANCELLED; - } - - changed = object_select_all_by_material_texture(C, use_texture, mat, tex); + changed = object_select_all_by_material(C, mat); } else if (nr == OBJECT_SELECT_LINKED_DUPGROUP) { if (ob->dup_group == NULL) @@ -482,6 +677,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; if (changed) { + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } @@ -517,14 +713,12 @@ enum { OBJECT_GRPSEL_PARENT = 2, OBJECT_GRPSEL_SIBLINGS = 3, OBJECT_GRPSEL_TYPE = 4, - OBJECT_GRPSEL_LAYER = 5, - OBJECT_GRPSEL_GROUP = 6, + OBJECT_GRPSEL_COLLECTION = 5, OBJECT_GRPSEL_HOOK = 7, OBJECT_GRPSEL_PASS = 8, OBJECT_GRPSEL_COLOR = 9, - OBJECT_GRPSEL_PROPERTIES = 10, - OBJECT_GRPSEL_KEYINGSET = 11, - OBJECT_GRPSEL_LAMP_TYPE = 12, + OBJECT_GRPSEL_KEYINGSET = 10, + OBJECT_GRPSEL_LIGHT_TYPE = 11, }; static const EnumPropertyItem prop_select_grouped_types[] = { @@ -533,14 +727,12 @@ static const EnumPropertyItem prop_select_grouped_types[] = { {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_LAYER, "LAYER", 0, "Layer", "Shared layers"}, - {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"}, + {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_PROPERTIES, "PROPERTIES", 0, "Properties", "Game Properties"}, {OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, - {OBJECT_GRPSEL_LAMP_TYPE, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"}, + {OBJECT_GRPSEL_LIGHT_TYPE, "LIGHT_TYPE", 0, "Light Type", "Matching light types"}, {0, NULL, 0, NULL, NULL} }; @@ -551,13 +743,14 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { if (ob == base->object->parent) { - if (!(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); changed = true; } - if (recursive) + if (recursive) { changed |= select_grouped_children(C, base->object, 1); + } } } CTX_DATA_END; @@ -566,51 +759,54 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv static bool select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */ { - Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); - - bool changed = false; Base *baspar, *basact = CTX_data_active_base(C); + bool changed = false; - if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */ + if (!basact || !(basact->object->parent)) { + return 0; /* we know OBACT is valid */ + } - baspar = BKE_scene_base_find(scene, basact->object->parent); + 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_base_object_select(baspar, BA_SELECT); - ED_base_object_activate(C, baspar); + ED_object_base_select(baspar, BA_SELECT); + ED_object_base_activate(C, baspar); changed = true; } return changed; } -#define GROUP_MENU_MAX 24 -static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in the same group as the active */ +#define COLLECTION_MENU_MAX 24 +static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same group as the active */ { bool changed = false; - Group *group, *ob_groups[GROUP_MENU_MAX]; - int group_count = 0, i; + Collection *collection, *ob_collections[COLLECTION_MENU_MAX]; + int collection_count = 0, i; uiPopupMenu *pup; uiLayout *layout; - for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) { - if (BKE_group_object_exists(group, ob)) { - ob_groups[group_count] = group; - group_count++; + for (collection = CTX_data_main(C)->collection.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 (!group_count) + if (!collection_count) return 0; - else if (group_count == 1) { - group = ob_groups[0]; + else if (collection_count == 1) { + collection = ob_collections[0]; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { - ED_base_object_select(base, BA_SELECT); - changed = true; + 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; @@ -618,12 +814,12 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in } /* build the menu. */ - pup = UI_popup_menu_begin(C, IFACE_("Select Group"), ICON_NONE); + pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); layout = UI_popup_menu_layout(pup); - for (i = 0; i < group_count; i++) { - group = ob_groups[i]; - uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name + 2); + 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); @@ -632,7 +828,7 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in static bool select_grouped_object_hooks(bContext *C, Object *ob) { - Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); bool changed = false; @@ -643,10 +839,10 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob) for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Hook) { hmd = (HookModifierData *) md; - if (hmd->object && !(hmd->object->flag & SELECT)) { - base = BKE_scene_base_find(scene, hmd->object); - if (base && (BASE_SELECTABLE(v3d, base))) { - ED_base_object_select(base, BA_SELECT); + 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; } } @@ -663,8 +859,8 @@ static bool select_grouped_siblings(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->parent == ob->parent) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->parent == ob->parent) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -681,8 +877,8 @@ static bool select_grouped_lamptype(bContext *C, Object *ob) { if (base->object->type == OB_LAMP) { Lamp *la_test = base->object->data; - if ((la->type == la_test->type) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((la->type == la_test->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -696,23 +892,8 @@ static bool select_grouped_type(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->type == ob->type) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; -} - -static bool select_grouped_layer(bContext *C, Object *ob) -{ - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if ((base->lay & ob->lay) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -726,8 +907,8 @@ static bool select_grouped_index_object(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->object->index == ob->index) && !(base->flag & SELECT)) { - ED_base_object_select(base, BA_SELECT); + if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -741,35 +922,8 @@ static bool select_grouped_color(bContext *C, Object *ob) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) { - ED_base_object_select(base, BA_SELECT); - changed = true; - } - } - CTX_DATA_END; - return changed; -} - -static bool objects_share_gameprop(Object *a, Object *b) -{ - bProperty *prop; - - for (prop = a->prop.first; prop; prop = prop->next) { - if (BKE_bproperty_object_get(b, prop->name)) { - return 1; - } - } - return 0; -} - -static bool select_grouped_gameprops(bContext *C, Object *ob) -{ - bool changed = false; - - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) - { - if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) { - ED_base_object_select(base, BA_SELECT); + if (((base->flag & BASE_SELECTED) == 0) && (compare_v3v3(base->object->col, ob->col, 0.005f))) { + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -807,7 +961,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList 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 & SELECT) == 0) { + if ((base->flag & BASE_SELECTED) == 0) { KS_Path *ksp; /* this is the slow way... we could end up with > 500 items here, @@ -816,7 +970,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList 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_base_object_select(base, BA_SELECT); + ED_object_base_select(base, BA_SELECT); changed = true; break; } @@ -831,6 +985,8 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList 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; @@ -838,15 +994,10 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) extend = RNA_boolean_get(op->ptr, "extend"); if (extend == 0) { - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - ED_base_object_select(base, BA_DESELECT); - changed = true; - } - CTX_DATA_END; + changed = ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); } - ob = OBACT; + ob = OBACT(view_layer); if (ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; @@ -868,11 +1019,8 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) case OBJECT_GRPSEL_TYPE: changed |= select_grouped_type(C, ob); break; - case OBJECT_GRPSEL_LAYER: - changed |= select_grouped_layer(C, ob); - break; - case OBJECT_GRPSEL_GROUP: - changed |= select_grouped_group(C, ob); + case OBJECT_GRPSEL_COLLECTION: + changed |= select_grouped_collection(C, ob); break; case OBJECT_GRPSEL_HOOK: changed |= select_grouped_object_hooks(C, ob); @@ -883,15 +1031,12 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) case OBJECT_GRPSEL_COLOR: changed |= select_grouped_color(C, ob); break; - case OBJECT_GRPSEL_PROPERTIES: - changed |= select_grouped_gameprops(C, ob); - break; case OBJECT_GRPSEL_KEYINGSET: changed |= select_grouped_keyingset(C, ob, op->reports); break; - case OBJECT_GRPSEL_LAMP_TYPE: + case OBJECT_GRPSEL_LIGHT_TYPE: if (ob->type != OB_LAMP) { - BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp"); + BKE_report(op->reports, RPT_ERROR, "Active object must be a light"); break; } changed |= select_grouped_lamptype(C, ob); @@ -901,6 +1046,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) } if (changed) { + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } @@ -928,130 +1074,32 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); } -/************************* Select by Layer **********************/ -enum { - OB_SEL_LAYERMATCH_EXACT = 1, - OB_SEL_LAYERMATCH_SHARED = 2, -}; - -static int object_select_by_layer_exec(bContext *C, wmOperator *op) -{ - unsigned int layernum; - bool extend; - int match; - - extend = RNA_boolean_get(op->ptr, "extend"); - layernum = RNA_int_get(op->ptr, "layers"); - match = RNA_enum_get(op->ptr, "match"); - - if (extend == false) { - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - ED_base_object_select(base, BA_DESELECT); - } - CTX_DATA_END; - } - - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - bool ok = false; - - switch (match) { - case OB_SEL_LAYERMATCH_EXACT: - /* Mask out bits used for local view, only work on real layer ones, see T45783. */ - ok = ((base->lay & ((1 << 20) - 1)) == (1 << (layernum - 1))); - break; - case OB_SEL_LAYERMATCH_SHARED: - ok = (base->lay & (1 << (layernum - 1))) != 0; - break; - default: - break; - } - - if (ok) { - ED_base_object_select(base, BA_SELECT); - } - } - CTX_DATA_END; - - /* undo? */ - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_select_by_layer(wmOperatorType *ot) -{ - static const EnumPropertyItem match_items[] = { - {OB_SEL_LAYERMATCH_EXACT, "EXACT", 0, "Exact Match", ""}, - {OB_SEL_LAYERMATCH_SHARED, "SHARED", 0, "Shared Layers", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Select by Layer"; - ot->description = "Select all visible objects on a layer"; - ot->idname = "OBJECT_OT_select_by_layer"; - - /* api callbacks */ - /*ot->invoke = XXX - need a int grid popup*/ - ot->exec = object_select_by_layer_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "match", match_items, OB_SEL_LAYERMATCH_EXACT, "Match", ""); - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20); -} - /**************************** (De)select All ****************************/ 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; - /* passthrough if no objects are visible */ - if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; + bool changed = ED_object_base_deselect_all_ex(view_layer, v3d, action, &any_visible); - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - if (base->flag & SELECT) { - action = SEL_DESELECT; - break; - } - } - CTX_DATA_END; - } + if (changed) { + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - CTX_DATA_BEGIN (C, Base *, base, visible_bases) - { - switch (action) { - case SEL_SELECT: - ED_base_object_select(base, BA_SELECT); - break; - case SEL_DESELECT: - ED_base_object_select(base, BA_DESELECT); - break; - case SEL_INVERT: - if (base->flag & SELECT) { - ED_base_object_select(base, BA_DESELECT); - } - else { - ED_base_object_select(base, BA_SELECT); - } - break; - } + 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; } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); - - return OPERATOR_FINISHED; } void OBJECT_OT_select_all(wmOperatorType *ot) @@ -1072,53 +1120,58 @@ void OBJECT_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/**************************** Select In The Same Group ****************************/ +/**************************** Select In The Same Collection ****************************/ -static int object_select_same_group_exec(bContext *C, wmOperator *op) +static int object_select_same_collection_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Group *group; - char group_name[MAX_ID_NAME]; + 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; - RNA_string_get(op->ptr, "group", group_name); + RNA_string_get(op->ptr, "collection", collection_name); - group = (Group *)BKE_libblock_find_name(bmain, ID_GR, group_name); + collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, collection_name); - if (!group) { + if (!collection) { return OPERATOR_PASS_THROUGH; } CTX_DATA_BEGIN (C, Base *, base, visible_bases) { - if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) - ED_base_object_select(base, BA_SELECT); + 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; - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } -void OBJECT_OT_select_same_group(wmOperatorType *ot) +void OBJECT_OT_select_same_collection(wmOperatorType *ot) { /* identifiers */ - ot->name = "Select Same Group"; - ot->description = "Select object in the same group"; - ot->idname = "OBJECT_OT_select_same_group"; + 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_group_exec; + ot->exec = object_select_same_collection_exec; ot->poll = objects_selectable_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_string(ot->srna, "group", NULL, MAX_ID_NAME, "Group", "Name of the group to select"); + RNA_def_string(ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select"); } /**************************** Select Mirror ****************************/ @@ -1126,6 +1179,7 @@ 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"); @@ -1139,20 +1193,21 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op) 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_scene_base_find(scene, ob); + Base *secbase = BKE_view_layer_base_find(view_layer, ob); if (secbase) { - ED_base_object_select(secbase, BA_SELECT); + ED_object_base_select(secbase, BA_SELECT); } } } - if (extend == false) ED_base_object_select(primbase, BA_DESELECT); + if (extend == false) ED_object_base_select(primbase, BA_DESELECT); } CTX_DATA_END; /* undo? */ + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; @@ -1182,9 +1237,9 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) static bool object_select_more_less(bContext *C, const bool select) { - Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); - for (Base *base = scene->base.first; base; base = base->next) { + 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; @@ -1219,13 +1274,13 @@ static bool object_select_more_less(bContext *C, const bool select) bool changed = false; const short select_mode = select ? BA_SELECT : BA_DESELECT; - const short select_flag = select ? SELECT : 0; + 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) && ((ob->flag & SELECT) != select_flag)) { - ED_base_object_select(base, select_mode); + if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) { + ED_object_base_select(base, select_mode); changed = true; } } @@ -1240,7 +1295,9 @@ static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op)) bool changed = object_select_more_less(C, true); if (changed) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } else { @@ -1268,7 +1325,9 @@ static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op)) bool changed = object_select_more_less(C, false); if (changed) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } else { @@ -1307,14 +1366,16 @@ static int object_select_random_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { if (BLI_rng_get_float(rng) < randfac) { - ED_base_object_select(base, select); + ED_object_base_select(base, select); } } CTX_DATA_END; BLI_rng_free(rng); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c new file mode 100644 index 00000000000..47cf9f6c20b --- /dev/null +++ b/source/blender/editors/object/object_shader_fx.c @@ -0,0 +1,470 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2018 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_shader_fx.c + * \ingroup edobj + */ + + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_shader_fx.h" +#include "BKE_report.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "object_intern.h" + +/******************************** API ****************************/ + +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); + + 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; + } + } + + /* get new effect data to add */ + new_fx = BKE_shaderfx_new(type); + + BLI_addtail(&ob->shader_fx, new_fx); + + 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); + + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + 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) +{ + ShaderFxData *fx; + + for (fx = ob->shader_fx.first; fx; fx = fx->next) { + if ((fx != exclude) && (fx->type == type)) + return true; + } + + return false; +} + +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; + } + + DEG_relations_tag_update(bmain); + + BLI_remlink(&ob->shader_fx, fx); + BKE_shaderfx_free(fx); + BKE_object_free_derived_caches(ob); + + return 1; +} + +bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx) +{ + bool sort_depsgraph = false; + bool ok; + + 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; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return 1; +} + +void ED_object_shaderfx_clear(Main *bmain, Object *ob) +{ + ShaderFxData *fx = ob->shader_fx.first; + bool sort_depsgraph = false; + + if (!fx) + return; + + while (fx) { + ShaderFxData *next_fx; + + next_fx = fx->next; + + object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); + + fx = next_fx; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + 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); + } + + 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); + } + + 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"); + + 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); + + return OPERATOR_FINISHED; +} + +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; +} + +void OBJECT_OT_shaderfx_add(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* 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 */ + prop = RNA_def_enum(ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", ""); + RNA_def_enum_funcs(prop, shaderfx_add_itemf); + ot->prop = prop; +} + +/************************ 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; +} + +static bool edit_shaderfx_poll(bContext *C) +{ + 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); +} + +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; +} + +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); + + fx = BKE_shaderfx_findByName(ob, shaderfx_name); + + if (fx && type != 0 && fx->type != type) + fx = NULL; + + 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); + + if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + 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; +} + +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->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); +} + +/************************ 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); + + if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + 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; +} + +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->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); +} + +/************************ 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); + + if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + 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; +} + +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->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); +} diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index e67b62ea624..7d16898c2a2 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -51,13 +51,14 @@ #include "DNA_object_types.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_curve.h" #include "BKE_key.h" -#include "BKE_library.h" +#include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" -#include "BKE_lattice.h" -#include "BKE_curve.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "BLI_sys_types.h" // for intptr_t support @@ -214,7 +215,7 @@ static bool object_shape_key_mirror(bContext *C, Object *ob, *r_totmirr = totmirr; *r_totfail = totfail; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return 1; @@ -265,8 +266,8 @@ static int shape_key_add_exec(bContext *C, wmOperator *op) ED_object_shape_key_add(C, ob, from_mix); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - DAG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(CTX_data_main(C)); return OPERATOR_FINISHED; } @@ -303,8 +304,8 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op) } if (changed) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - DAG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -344,7 +345,7 @@ static int shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op)) for (kb = key->block.first; kb; kb = kb->next) kb->curval = 0.0f; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -381,7 +382,7 @@ static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op)) cfra += 0.1f; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -472,7 +473,7 @@ static int shape_key_move_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index fab2396b05a..e2574cf3813 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -38,16 +38,17 @@ #include "DNA_lamp_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_group_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_collection_types.h" #include "DNA_lattice_types.h" #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLI_array.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_idcode.h" #include "BKE_mball.h" @@ -59,6 +60,9 @@ #include "BKE_armature.h" #include "BKE_lattice.h" #include "BKE_tracking.h" +#include "BKE_gpencil.h" + +#include "DEG_depsgraph.h" #include "RNA_define.h" #include "RNA_access.h" @@ -71,6 +75,9 @@ #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "ED_gpencil.h" + +#include "MEM_guardedalloc.h" #include "object_intern.h" @@ -266,7 +273,7 @@ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, ED_autokeyframe_object(C, scene, ob, ks); /* tag for updates */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } } CTX_DATA_END; @@ -372,7 +379,7 @@ static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op)) mul_m3_v3(mat, v3); } - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; @@ -400,16 +407,17 @@ void OBJECT_OT_origin_clear(wmOperatorType *ot) /* use this when the loc/size/rot of the parent has changed but the children * should stay in the same place, e.g. for apply-size-rot or object center */ -static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob) +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->object.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(scene, ob_child, &workob); + BKE_object_workob_calc_parent(depsgraph, scene, ob_child, &workob); invert_m4_m4(ob_child->parentinv, workob.obmat); } } @@ -422,13 +430,14 @@ static int apply_objects_internal( { 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)) { + 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, @@ -474,12 +483,43 @@ static int apply_objects_internal( } } + 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) { Lamp *la = ob->data; if (la->type == LA_AREA) { if (apply_rot || apply_loc) { BKE_reportf(reports, RPT_ERROR, - "Area Lamps can only have scale applied: \"%s\"", + "Area Lights can only have scale applied: \"%s\"", ob->id.name + 2); changed = false; } @@ -538,7 +578,7 @@ static int apply_objects_internal( Mesh *me = ob->data; if (apply_scale) - multiresModifier_scale_disp(scene, ob); + multiresModifier_scale_disp(depsgraph, scene, ob); /* adjust data */ BKE_mesh_transform(me, mat, true); @@ -581,6 +621,10 @@ static int apply_objects_internal( 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); @@ -625,6 +669,10 @@ static int apply_objects_internal( 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]; @@ -644,14 +692,14 @@ static int apply_objects_internal( unit_axis_angle(ob->rotAxis, &ob->rotAngle); } - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(scene, ob); /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ } - ignore_parent_tx(bmain, scene, ob); + ignore_parent_tx(C, bmain, scene, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } @@ -669,16 +717,17 @@ static int apply_objects_internal( 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; CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); BKE_object_apply_mat4(ob, ob->obmat, true, true); - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); /* update for any children that may get moved */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); changed = true; } @@ -759,6 +808,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) 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 cursor[3], cent[3], cent_neg[3], centn[3]; int centermode = RNA_enum_get(op->ptr, "type"); @@ -778,9 +828,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else { /* get the view settings if 'around' isn't set and the view is available */ View3D *v3d = CTX_wm_view3d(C); - copy_v3_v3(cursor, ED_view3d_cursor3d_get(scene, v3d)); + copy_v3_v3(cursor, scene->cursor.location); if (v3d && !RNA_struct_property_is_set(op->ptr, "center")) - around = v3d->around; + around = scene->toolsettings->transform_pivot_point; } zero_v3(cent); @@ -822,7 +872,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) EDBM_mesh_normals_update(em); tot_change++; - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); } } @@ -871,7 +921,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (ob->data == NULL) { /* special support for dupligroups */ - if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) { + if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) { if (ID_IS_LINKED(ob->dup_group)) { tot_lib_error++; } @@ -883,7 +933,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) float min[3], max[3]; /* only bounds support */ INIT_MINMAX(min, max); - BKE_object_minmax_dupli(bmain, scene, ob, min, max, true); + 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); @@ -947,7 +997,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (obedit) { if (centermode == GEOMETRY_TO_ORIGIN) { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); } break; } @@ -994,16 +1044,16 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* Function to recenter armatures in editarmature.c * Bone + object locations are handled there. */ - ED_armature_origin_set(bmain, scene, ob, cursor, centermode, around); + 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(scene, ob); - BKE_pose_where_is(scene, ob); /* needed for bone parents */ + BKE_object_where_is_calc(depsgraph, scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ - ignore_parent_tx(bmain, scene, ob); + ignore_parent_tx(C, bmain, scene, ob); if (obedit) break; @@ -1025,7 +1075,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (obedit) { if (centermode == GEOMETRY_TO_ORIGIN) { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); } break; } @@ -1044,6 +1094,69 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) 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 attributtes) */ + 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, OB_RECALC_OB | OB_RECALC_DATA); + + 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)) { @@ -1059,12 +1172,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) add_v3_v3(ob->loc, centn); - BKE_object_where_is_calc(scene, ob); + BKE_object_where_is_calc(depsgraph, scene, ob); if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(scene, ob); /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ } - ignore_parent_tx(bmain, scene, ob); + ignore_parent_tx(C, bmain, scene, ob); /* other users? */ //CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects) @@ -1080,19 +1193,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if ((ob_other->flag & OB_DONE) == 0 && ((ob->data && (ob->data == ob_other->data)) || (ob->dup_group == ob_other->dup_group && - (ob->transflag | ob_other->transflag) & OB_DUPLIGROUP))) + (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) { ob_other->flag |= OB_DONE; - DAG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA); mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ add_v3_v3(ob_other->loc, centn); - BKE_object_where_is_calc(scene, ob_other); + BKE_object_where_is_calc(depsgraph, scene, ob_other); if (ob_other->type == OB_ARMATURE) { - BKE_pose_where_is(scene, ob_other); /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob_other); /* needed for bone parents */ } - ignore_parent_tx(bmain, scene, ob_other); + ignore_parent_tx(C, bmain, scene, ob_other); } } //CTX_DATA_END; @@ -1101,9 +1214,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } BLI_freelistN(&ctx_data_list); - for (tob = bmain->object.first; tob; tob = tob->id.next) - if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT)) - DAG_id_tag_update(&tob->id, OB_RECALC_OB | OB_RECALC_DATA); + for (tob = bmain->object.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, OB_RECALC_OB | OB_RECALC_DATA); + } + } if (tot_change) { WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1160,3 +1276,385 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) 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_MEAN, "Center", ""); } + +/* -------------------------------------------------------------------- */ + +/** \name Transform Axis Target + * + * Note this is an experemental operator to point lamps/cameras at objects. + * We may re-work how this behaves based on user feedback. + * - campbell. + * \{ */ + +/* When using multiple objects, apply their relative rotational offset to the active object. */ +#define USE_RELATIVE_ROTATION + +struct XFormAxisItem { + 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]; +#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; +}; + +static bool object_is_target_compat(const Object *ob) +{ + if (ob->type == OB_LAMP) { + const Lamp *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 lamps */ +#if 0 + else if (ob->type == OB_CAMERA) { + return true; + } +#endif + return false; +} + +static void object_transform_axis_target_free_data(wmOperator *op) +{ + struct XFormAxisData *xfd = op->customdata; + struct XFormAxisItem *item = xfd->object_data; + 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->size); + copy_v3_v3(loc, ob->loc); + BKE_object_apply_mat4(ob, rmat4, true, true); + copy_v3_v3(ob->size, 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]); +} + +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); + + mul_m3_m3m3(final_rot, delta_rot, rot_orig); + + object_apply_rotation(ob, final_rot); + + DEG_id_tag_update(&ob->id, OB_RECALC_OB); + } + } +} + +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, OB_RECALC_OB); + 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 (!object_is_target_compat(vc.obact)) { + /* Falls back to texture space transform. */ + return OPERATOR_PASS_THROUGH; + } + + 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) { + BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane"); + return OPERATOR_CANCELLED; + } + + ED_region_tag_redraw(vc.ar); + + 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]; + + 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); + + { + struct XFormAxisItem *object_data = NULL; + BLI_array_declare(object_data); + + 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; + + 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)); + } + } + + { + 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); + + 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; + } + } + 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); + } + } + } + +#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; + } + + 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); + } +#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); + copy_v3_v3(item->ob->obmat[3], loc); /* so orient behaves as expected */ + } + + 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; +} + +#undef USE_RELATIVE_ROTATION + +/** \} */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index e11782cd4b3..1a0c129e23a 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -43,6 +43,7 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_workspace_types.h" #include "BLI_alloca.h" #include "BLI_array.h" @@ -56,16 +57,18 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_report.h" -#include "BKE_DerivedMesh.h" #include "BKE_object_deform.h" #include "BKE_object.h" #include "BKE_lattice.h" +#include "DEG_depsgraph.h" + #include "DNA_armature_types.h" #include "RNA_access.h" #include "RNA_define.h" @@ -1254,27 +1257,6 @@ static void getVerticalAndHorizontalChange( changes[index][1] = len_v3v3(projA, projB); } -/* I need the derived mesh to be forgotten so the positions are recalculated - * with weight changes (see dm_deform_recalc) */ -static void dm_deform_clear(DerivedMesh *dm, Object *ob) -{ - if (ob->derivedDeform && (ob->derivedDeform) == dm) { - ob->derivedDeform->needsFree = 1; - ob->derivedDeform->release(ob->derivedDeform); - ob->derivedDeform = NULL; - } - else if (dm) { - dm->needsFree = 1; - dm->release(dm); - } -} - -/* recalculate the deformation */ -static DerivedMesh *dm_deform_recalc(Scene *scene, Object *ob) -{ - return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); -} - /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to * distToBe distance away from the provided plane strength can change distToBe so that it moves * towards distToBe by that percentage cp changes how much the weights are adjusted @@ -1285,10 +1267,10 @@ static DerivedMesh *dm_deform_recalc(Scene *scene, Object *ob) * coord is a point on the plane */ static void moveCloserToDistanceFromPlane( - Scene *scene, Object *ob, Mesh *me, int index, float norm[3], + Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, int index, float norm[3], float coord[3], float d, float distToBe, float strength, float cp) { - DerivedMesh *dm; + Mesh *me_deform; MDeformWeight *dw; MVert m; MDeformVert *dvert = me->dvert + index; @@ -1312,8 +1294,8 @@ static void moveCloserToDistanceFromPlane( float originalDistToBe = distToBe; do { wasChange = false; - dm = dm_deform_recalc(scene, ob); - dm->getVert(dm, index, &m); + 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; @@ -1331,8 +1313,10 @@ static void moveCloserToDistanceFromPlane( continue; } for (k = 0; k < 2; k++) { - if (dm) { - dm_deform_clear(dm, ob); dm = NULL; + 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) { @@ -1350,8 +1334,8 @@ static void moveCloserToDistanceFromPlane( if (dw->weight > 1) { dw->weight = 1; } - dm = dm_deform_recalc(scene, ob); - dm->getVert(dm, index, &m); + 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) { @@ -1445,8 +1429,10 @@ static void moveCloserToDistanceFromPlane( if (oldw == dw->weight) { wasChange = false; } - if (dm) { - dm_deform_clear(dm, ob); dm = NULL; + 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) == @@ -1460,8 +1446,9 @@ static void moveCloserToDistanceFromPlane( /* 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(Scene *scene, Object *ob, float distToBe, float strength, float cp) +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; @@ -1477,11 +1464,10 @@ static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints"); int k; - DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + Mesh *me_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH); k = count; while (k--) { - dm->getVert(dm, verts[k], &m); - p[k] = m; + p[k] = me_deform->mvert[verts[k]]; } if (count >= 3) { @@ -1489,13 +1475,13 @@ static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float coord[3]; float norm[3]; getSingleCoordinate(p, count, coord); - dm->getVert(dm, i, &m); + 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(scene, ob, me, i, norm, coord, d, distToBe, strength, cp); + moveCloserToDistanceFromPlane(depsgraph, scene, ob, me, i, norm, coord, d, distToBe, strength, cp); } } @@ -2635,7 +2621,7 @@ static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_context(C); BKE_object_defgroup_add(ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -2668,7 +2654,7 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op) else vgroup_delete_active(ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -2703,7 +2689,7 @@ static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_context(C); vgroup_assign_verts(ob, ts->vgroup_weight); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); return OPERATOR_FINISHED; @@ -2776,7 +2762,7 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) } } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); return OPERATOR_FINISHED; @@ -2815,6 +2801,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; vgroup_select_verts(ob, 1); + DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); return OPERATOR_FINISHED; @@ -2840,6 +2827,7 @@ static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_context(C); vgroup_select_verts(ob, 0); + DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); return OPERATOR_FINISHED; @@ -2865,7 +2853,7 @@ static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_context(C); vgroup_duplicate(ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data); @@ -2901,7 +2889,7 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op) vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain); MEM_freeN((void *)vgroup_validmap); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -2935,7 +2923,7 @@ static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op)) changed = vgroup_normalize(ob); if (changed) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -2974,7 +2962,7 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) MEM_freeN((void *)vgroup_validmap); if (changed) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3027,9 +3015,9 @@ static int vertex_group_fix_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier"); return OPERATOR_CANCELLED; } - vgroup_fix(scene, ob, distToBe, strength, cp); + vgroup_fix(C, scene, ob, distToBe, strength, cp); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3101,7 +3089,7 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op) vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove); MEM_freeN((void *)vgroup_validmap); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3131,21 +3119,32 @@ void OBJECT_OT_vertex_group_invert(wmOperatorType *ot) static int vertex_group_smooth_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_context(C); 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); - int subset_count, vgroup_tot; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; - 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); + int subset_count, vgroup_tot; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + 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, OB_RECALC_DATA); + 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; } @@ -3185,7 +3184,7 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op) vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single); MEM_freeN((void *)vgroup_validmap); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3226,7 +3225,7 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op) vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps); MEM_freeN((void *)vgroup_validmap); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3267,7 +3266,7 @@ static int vertex_group_limit_total_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, remove_tot ? RPT_INFO : RPT_WARNING, "%d vertex weights limited", remove_tot); if (remove_tot) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3313,7 +3312,7 @@ static int vertex_group_mirror_exec(bContext *C, wmOperator *op) ED_mesh_report_mirror(op, totmirr, totfail); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3346,25 +3345,26 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - Base *base; + Object *ob_active = ED_object_context(C); int retval = OPERATOR_CANCELLED; - for (base = scene->base.first; base; base = base->next) { - if (base->object->type == ob->type) { - if (base->object != ob && base->object->data == ob->data) { - BLI_freelistN(&base->object->defbase); - BLI_duplicatelist(&base->object->defbase, &ob->defbase); - base->object->actdef = ob->actdef; + 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; - DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, base->object); - WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, base->object->data); + DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA); + 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; } @@ -3394,7 +3394,7 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) { if (obact != ob) { if (ED_vgroup_array_copy(ob, obact)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); changed_tot++; } @@ -3437,7 +3437,7 @@ static int set_active_group_exec(bContext *C, wmOperator *op) BLI_assert(nr + 1 >= 0); ob->actdef = nr + 1; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); return OPERATOR_FINISHED; @@ -3651,7 +3651,7 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op) ret = vgroup_do_remap(ob, name_array, op); if (ret != OPERATOR_CANCELLED) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); } @@ -3701,7 +3701,7 @@ static int vgroup_move_exec(bContext *C, wmOperator *op) ret = vgroup_do_remap(ob, name_array, op); if (ret != OPERATOR_CANCELLED) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob); } } @@ -3830,7 +3830,7 @@ static int vertex_weight_paste_exec(bContext *C, wmOperator *op) vgroup_copy_active_to_sel_single(ob, def_nr); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -3867,7 +3867,7 @@ static int vertex_weight_delete_exec(bContext *C, wmOperator *op) vgroup_remove_weight(ob, def_nr); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -3900,7 +3900,7 @@ static int vertex_weight_set_active_exec(bContext *C, wmOperator *op) if (wg_index != -1) { ob->actdef = wg_index + 1; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } @@ -3937,7 +3937,7 @@ static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *U changed = vgroup_normalize_active_vertex(ob, subset_type); if (changed) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -3970,7 +3970,7 @@ static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op)) vgroup_copy_active_to_sel(ob, subset_type); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index 92b82e2a31b..d28ed71c382 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -223,12 +223,8 @@ static int object_warp_verts_exec(bContext *C, wmOperator *op) RNA_property_float_get_array(op->ptr, prop_center, center); } else { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - const float *cursor; - - cursor = ED_view3d_cursor3d_get(scene, v3d); - copy_v3_v3(center, cursor); + const Scene *scene = CTX_data_scene(C); + copy_v3_v3(center, scene->cursor.location); RNA_property_float_set_array(op->ptr, prop_center, center); } |