Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_object.h1
-rw-r--r--source/blender/blenkernel/intern/object.c10
-rw-r--r--source/blender/blenkernel/intern/particle.c2
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c96
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c225
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c5
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c5
9 files changed, 348 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index a620d9af946..cd253ca4bbc 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -75,6 +75,7 @@ bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModif
bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
+bool BKE_object_supports_modifiers(const struct Object *ob);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
/* Active modifier. */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 7ed906e2cea..163e7d51235 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1315,6 +1315,15 @@ ModifierData *BKE_object_active_modifier(const Object *ob)
return NULL;
}
+/**
+ * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
+ */
+bool BKE_object_supports_modifiers(const Object *ob)
+{
+ return (
+ ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE, OB_POINTCLOUD, OB_VOLUME));
+}
+
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(modifier_type);
@@ -1377,6 +1386,7 @@ bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src
BKE_modifier_copydata(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
+ BKE_object_modifier_set_active(ob_dst, nmd);
return true;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index dce45f44583..335913c9b8e 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -75,6 +75,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
@@ -3948,6 +3949,7 @@ static ModifierData *object_add_or_copy_particle_system(
psmd = (ParticleSystemModifierData *)md;
psmd->psys = psys;
BLI_addtail(&ob->modifiers, md);
+ BKE_object_modifier_set_active(ob, md);
psys->totpart = 0;
psys->flag = PSYS_CURRENT;
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index e5feb74df26..eb3ccf52c6f 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -835,3 +835,99 @@ void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
+
+/************************ Copy Modifier to Selected Operator *********************/
+
+static int gpencil_modifier_copy_to_selected_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, obact, 0);
+
+ if (!md) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (obact->type != OB_GPENCIL) {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Source object '%s' is not a grease pencil object",
+ obact->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob == obact) {
+ continue;
+ }
+
+ if (ob->type != OB_GPENCIL) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Destination object '%s' is not a grease pencil object",
+ ob->id.name + 2);
+ continue;
+ }
+
+ /* This always returns true right now. */
+ BKE_object_copy_gpencil_modifier(ob, md);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ }
+ CTX_DATA_END;
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_copy_to_selected_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ int retval;
+ if (gpencil_edit_modifier_invoke_properties(C, op, event, &retval)) {
+ return gpencil_modifier_copy_to_selected_exec(C, op);
+ }
+ return retval;
+}
+
+static bool gpencil_modifier_copy_to_selected_poll(bContext *C)
+{
+ Object *obact = ED_object_active_context(C);
+
+ /* This could have a performance impact in the worst case, where there are many objects selected
+ * and none of them pass the check. But that should be uncommon, and this operator is only
+ * exposed in a drop-down menu anyway. */
+ bool found_supported_objects = false;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob == obact) {
+ continue;
+ }
+
+ if (ob->type == OB_GPENCIL) {
+ found_supported_objects = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ if (!found_supported_objects) {
+ CTX_wm_operator_poll_msg_set(C, "No supported objects were selected");
+ return false;
+ }
+ return true;
+}
+
+void OBJECT_OT_gpencil_modifier_copy_to_selected(wmOperatorType *ot)
+{
+ ot->name = "Copy Modifier to Selected";
+ ot->description = "Copy the modifier from the active object to all selected objects";
+ ot->idname = "OBJECT_OT_gpencil_modifier_copy_to_selected";
+
+ ot->invoke = gpencil_modifier_copy_to_selected_invoke;
+ ot->exec = gpencil_modifier_copy_to_selected_exec;
+ ot->poll = gpencil_modifier_copy_to_selected_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 89ade5cc49d..00426e96a81 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -175,6 +175,7 @@ void OBJECT_OT_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot);
void OBJECT_OT_modifier_convert(struct wmOperatorType *ot);
void OBJECT_OT_modifier_copy(struct wmOperatorType *ot);
+void OBJECT_OT_modifier_copy_to_selected(struct wmOperatorType *ot);
void OBJECT_OT_modifier_set_active(struct wmOperatorType *ot);
void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
@@ -203,6 +204,7 @@ void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_move_to_index(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_copy_to_selected(struct wmOperatorType *ot);
/* object_shader_fx.c */
void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 3111003703f..e9c84353b80 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -30,6 +30,8 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
+#include "DNA_dynamicpaint_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -1682,6 +1684,229 @@ void OBJECT_OT_modifier_set_active(wmOperatorType *ot)
}
/** \} */
+/** \name Copy Modifier To Selected Operator
+ * \{ */
+
+/* If the modifier uses particles, copy particle system to destination object
+ * or reuse existing if it has the same ParticleSettings */
+static void copy_or_reuse_particle_system(bContext *C, Object *ob, ModifierData *md)
+{
+ ParticleSystem *psys_on_modifier = NULL;
+
+ if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if (pmd->brush && pmd->brush->psys) {
+ psys_on_modifier = pmd->brush->psys;
+ }
+ }
+ else if (md->type == eModifierType_Fluid) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ if (fmd->type == MOD_FLUID_TYPE_FLOW) {
+ if (fmd->flow && fmd->flow->psys) {
+ psys_on_modifier = fmd->flow->psys;
+ }
+ }
+ }
+
+ if (!psys_on_modifier) {
+ return;
+ }
+
+ ParticleSystem *psys_on_new_modifier = NULL;
+
+ /* Check if a particle system with the same particle settings
+ * already exists on the destination object. */
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ if (psys_on_modifier->part == psys->part) {
+ psys_on_new_modifier = psys;
+ break;
+ }
+ }
+
+ /* If it does not exist, copy the particle system to the destination object. */
+ if (!psys_on_new_modifier) {
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ object_copy_particle_system(bmain, scene, ob, psys_on_modifier);
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ if (psys_on_modifier->part == psys->part) {
+ psys_on_new_modifier = psys;
+ }
+ }
+ }
+
+ /* Update the modifier to point to the new/existing particle system. */
+ LISTBASE_FOREACH (ModifierData *, new_md, &ob->modifiers) {
+ if (new_md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *new_pmd = (DynamicPaintModifierData *)new_md;
+
+ if (psys_on_modifier == new_pmd->brush->psys) {
+ new_pmd->brush->psys = psys_on_new_modifier;
+ }
+ }
+ else if (new_md->type == eModifierType_Fluid) {
+ FluidModifierData *new_fmd = (FluidModifierData *)new_md;
+
+ if (psys_on_modifier == new_fmd->flow->psys) {
+ new_fmd->flow->psys = psys_on_new_modifier;
+ }
+ }
+ }
+}
+
+static int modifier_copy_to_selected_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = ED_object_active_context(C);
+ ModifierData *md = edit_modifier_property_get(op, obact, 0);
+
+ if (!md) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int num_copied = 0;
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob == obact) {
+ continue;
+ }
+
+ /* Checked in #BKE_object_copy_modifier, but check here too so we can give a better message. */
+ if (!BKE_object_support_modifier_type_check(ob, md->type)) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Object '%s' does not support %s modifiers",
+ ob->id.name + 2,
+ mti->name);
+ continue;
+ }
+
+ if (mti->flags & eModifierTypeFlag_Single) {
+ if (BKE_modifiers_findby_type(ob, md->type)) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Modifier can only be added once to object '%s'",
+ ob->id.name + 2);
+ continue;
+ }
+ }
+
+ if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+ object_copy_particle_system(bmain, scene, ob, psmd->psys);
+ }
+ else {
+ if (!BKE_object_copy_modifier(ob, obact, md)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Copying modifier '%s' to object '%s' failed",
+ md->name,
+ ob->id.name + 2);
+ }
+ }
+
+ if (ELEM(md->type, eModifierType_DynamicPaint, eModifierType_Fluid)) {
+ copy_or_reuse_particle_system(C, ob, md);
+ }
+
+ num_copied++;
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ }
+ CTX_DATA_END;
+
+ if (num_copied > 0) {
+ DEG_relations_tag_update(bmain);
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Modifier '%s' was not copied to any objects", md->name);
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int modifier_copy_to_selected_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return modifier_copy_to_selected_exec(C, op);
+ }
+ /* Work around multiple operators using the same shortcut. */
+ return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED);
+}
+
+static bool modifier_copy_to_selected_poll(bContext *C)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier);
+ Object *obact = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
+ ModifierData *md = ptr.data;
+
+ /* This just mirrors the check in #BKE_object_copy_modifier,
+ * but there is no reasoning for it there. */
+ if (md && ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
+ CTX_wm_operator_poll_msg_set(C, "Not supported for \"Collision\" or \"Hook\" modifiers");
+ return false;
+ }
+
+ if (!obact) {
+ CTX_wm_operator_poll_msg_set(C, "No selected object is active");
+ return false;
+ }
+
+ if (!BKE_object_supports_modifiers(obact)) {
+ CTX_wm_operator_poll_msg_set(C, "Object type of source object is not supported");
+ return false;
+ }
+
+ /* This could have a performance impact in the worst case, where there are many objects selected
+ * and none of them pass either of the checks. But that should be uncommon, and this operator is
+ * only exposed in a drop-down menu anyway. */
+ bool found_supported_objects = false;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob == obact) {
+ continue;
+ }
+
+ if (!md && BKE_object_supports_modifiers(ob)) {
+ /* Skip type check if modifier could not be found ("modifier" context variable not set). */
+ found_supported_objects = true;
+ break;
+ }
+ else if (BKE_object_support_modifier_type_check(ob, md->type)) {
+ found_supported_objects = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ if (!found_supported_objects) {
+ CTX_wm_operator_poll_msg_set(C, "No supported objects were selected");
+ return false;
+ }
+ return true;
+}
+
+void OBJECT_OT_modifier_copy_to_selected(wmOperatorType *ot)
+{
+ ot->name = "Copy Modifier to Selected";
+ ot->description = "Copy the modifier from the active object to all selected objects";
+ ot->idname = "OBJECT_OT_modifier_copy_to_selected";
+
+ ot->invoke = modifier_copy_to_selected_invoke;
+ ot->exec = modifier_copy_to_selected_exec;
+ ot->poll = modifier_copy_to_selected_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
/* ------------------------------------------------------------------- */
/** \name Multires Delete Higher Levels Operator
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 2e5a75ffa7d..964d9898ac0 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -137,6 +137,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_modifier_apply_as_shapekey);
WM_operatortype_append(OBJECT_OT_modifier_convert);
WM_operatortype_append(OBJECT_OT_modifier_copy);
+ WM_operatortype_append(OBJECT_OT_modifier_copy_to_selected);
WM_operatortype_append(OBJECT_OT_modifier_set_active);
WM_operatortype_append(OBJECT_OT_multires_subdivide);
WM_operatortype_append(OBJECT_OT_multires_reshape);
@@ -159,6 +160,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_to_index);
WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply);
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy_to_selected);
/* shader fx */
WM_operatortype_append(OBJECT_OT_shaderfx_add);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index d3ba5bf8b37..05e7a23bc82 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -270,6 +270,11 @@ static void gpencil_modifier_ops_extra_draw(bContext *C, uiLayout *layout, void
ICON_DUPLICATE,
"OBJECT_OT_gpencil_modifier_copy");
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
+ 0,
+ "OBJECT_OT_gpencil_modifier_copy_to_selected");
+
uiItemS(layout);
/* Move to first. */
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 55dbfdf478f..58eeba35ca9 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -256,6 +256,11 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
"OBJECT_OT_modifier_copy");
}
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
+ 0,
+ "OBJECT_OT_modifier_copy_to_selected");
+
uiItemS(layout);
/* Move to first. */