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:
Diffstat (limited to 'source/blender/blenkernel/intern/object.c')
-rw-r--r--source/blender/blenkernel/intern/object.c258
1 files changed, 196 insertions, 62 deletions
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index ea0ce6a0f33..155508e9caa 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -218,26 +218,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
ob_dst->runtime.bb = MEM_dupallocN(ob_src->runtime.bb);
}
- BLI_listbase_clear(&ob_dst->modifiers);
-
- LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
- ModifierData *nmd = BKE_modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- BKE_modifier_copydata_ex(md, nmd, flag_subdata);
- BLI_addtail(&ob_dst->modifiers, nmd);
- }
-
- BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
-
- LISTBASE_FOREACH (GpencilModifierData *, gmd, &ob_src->greasepencil_modifiers) {
- GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
- BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
- BKE_gpencil_modifier_copydata_ex(gmd, nmd, flag_subdata);
- BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
- }
-
BLI_listbase_clear(&ob_dst->shader_fx);
-
LISTBASE_FOREACH (ShaderFxData *, fx, &ob_src->shader_fx) {
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
@@ -266,10 +247,12 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
}
}
- BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
BKE_rigidbody_object_copy(bmain, ob_dst, ob_src, flag_subdata);
- BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
+ BLI_listbase_clear(&ob_dst->modifiers);
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+ /* Note: Also takes care of softbody and particle systems copying. */
+ BKE_object_modifier_stack_copy(ob_dst, ob_src, true, flag_subdata);
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
@@ -1354,17 +1337,76 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return false;
}
-bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src, ModifierData *md)
+static bool object_modifier_type_copy_check(ModifierType md_type)
{
- if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
- return false;
+ return !ELEM(md_type, eModifierType_Hook, eModifierType_Collision);
+}
+
+/** Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings
+ * ID), or add one, and return valid `psys` from `ob_dst`.
+ *
+ * \note Order handling is fairly weak here. This code assumes that it is called **before** the
+ * modifier using the psys is actually copied, and that this copied modifier will be added at the
+ * end of the stack. That way we can be sure that the particle modifier will be before the one
+ * using its particle system in the stack.
+ */
+static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
+ Scene *scene,
+ Object *ob_dst,
+ ParticleSystem *psys_src)
+{
+ ParticleSystem *psys_dst = NULL;
+
+ /* Check if a particle system with the same particle settings
+ * already exists on the destination object. */
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob_dst->particlesystem) {
+ if (psys->part == psys_src->part) {
+ psys_dst = psys;
+ break;
+ }
}
- if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
+ /* If it does not exist, copy the particle system to the destination object. */
+ if (psys_dst == NULL) {
+ ModifierData *md = object_copy_particle_system(bmain, scene, ob_dst, psys_src);
+ psys_dst = ((ParticleSystemModifierData *)md)->psys;
+ }
+
+ return psys_dst;
+}
+
+/** Copy a single modifier.
+ *
+ * \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
+ * `BKE_object_modifier_stack_copy` instead.
+ *
+ * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
+ * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
+ * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
+ * more than once, this function should preferably be called in stack order. */
+bool BKE_object_copy_modifier(
+ Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
+{
+ BLI_assert(ob_dst->type != OB_GPENCIL);
+
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type);
+ if (!object_modifier_type_copy_check(md_src->type)) {
+ /* We never allow copying those modifiers here. */
+ return false;
+ }
+ if (!BKE_object_support_modifier_type_check(ob_dst, md_src->type)) {
return false;
}
+ if (mti->flags & eModifierTypeFlag_Single) {
+ if (BKE_modifiers_findby_type(ob_dst, md_src->type) != NULL) {
+ return false;
+ }
+ }
+
+ ParticleSystem *psys_src = NULL;
+ ParticleSystem *psys_dst = NULL;
- switch (md->type) {
+ switch (md_src->type) {
case eModifierType_Softbody:
BKE_object_copy_softbody(ob_dst, ob_src, 0);
break;
@@ -1372,66 +1414,158 @@ bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src
/* ensure skin-node customdata exists */
BKE_mesh_ensure_skin_customdata(ob_dst->data);
break;
+ case eModifierType_Fluid: {
+ FluidModifierData *fmd = (FluidModifierData *)md_src;
+ if (fmd->type == MOD_FLUID_TYPE_FLOW) {
+ if (fmd->flow != NULL && fmd->flow->psys != NULL) {
+ psys_src = fmd->flow->psys;
+ psys_dst = object_copy_modifier_particle_system_ensure(bmain, scene, ob_dst, psys_src);
+ }
+ }
+ break;
+ }
+ case eModifierType_DynamicPaint: {
+ DynamicPaintModifierData *dpmd = (DynamicPaintModifierData *)md_src;
+ if (dpmd->brush != NULL && dpmd->brush->psys != NULL) {
+ psys_src = dpmd->brush->psys;
+ psys_dst = object_copy_modifier_particle_system_ensure(bmain, scene, ob_dst, psys_src);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ ModifierData *md_dst;
+ if (md_src->type == eModifierType_ParticleSystem) {
+ md_dst = object_copy_particle_system(
+ bmain, scene, ob_dst, ((ParticleSystemModifierData *)md_src)->psys);
}
+ else {
+ md_dst = BKE_modifier_new(md_src->type);
+
+ BLI_strncpy(md_dst->name, md_src->name, sizeof(md_dst->name));
- ModifierData *nmd = BKE_modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ if (md_src->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(
+ ob_dst, (MultiresModifierData *)md_src, (MultiresModifierData *)md_dst);
+ }
+
+ BKE_modifier_copydata(md_src, md_dst);
+
+ switch (md_dst->type) {
+ case eModifierType_Fluid:
+ if (psys_dst != NULL) {
+ FluidModifierData *fmd_dst = (FluidModifierData *)md_dst;
+ BLI_assert(fmd_dst->type == MOD_FLUID_TYPE_FLOW && fmd_dst->flow != NULL &&
+ fmd_dst->flow->psys != NULL);
+ fmd_dst->flow->psys = psys_dst;
+ }
+ break;
+ case eModifierType_DynamicPaint:
+ if (psys_dst != NULL) {
+ DynamicPaintModifierData *dpmd_dst = (DynamicPaintModifierData *)md_dst;
+ BLI_assert(dpmd_dst->brush != NULL && dpmd_dst->brush->psys != NULL);
+ dpmd_dst->brush->psys = psys_dst;
+ }
+ break;
+ default:
+ break;
+ }
- if (md->type == eModifierType_Multires) {
- /* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(
- ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ BLI_addtail(&ob_dst->modifiers, md_dst);
+ BKE_modifier_unique_name(&ob_dst->modifiers, md_dst);
}
- 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);
+ BKE_object_modifier_set_active(ob_dst, md_dst);
return true;
}
-bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *md)
+/** Copy a single GPencil modifier.
+ *
+ * \note **Do not** use this function to copy a whole modifier stack. Use
+ * `BKE_object_modifier_stack_copy` instead. */
+bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
{
- GpencilModifierData *nmd = BKE_gpencil_modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ BLI_assert(ob_dst->type == OB_GPENCIL);
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
- mti->copyData(md, nmd);
+ GpencilModifierData *gmd_dst = BKE_gpencil_modifier_new(gmd_src->type);
+ BLI_strncpy(gmd_dst->name, gmd_src->name, sizeof(gmd_dst->name));
- BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
- BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(gmd_src->type);
+ mti->copyData(gmd_src, gmd_dst);
+
+ BLI_addtail(&ob_dst->greasepencil_modifiers, gmd_dst);
+ BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, gmd_dst);
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
+/**
+ * Copy the whole stack of modifiers from one object into another.
+ *
+ * \warning **Does not** clear modifier stack and related data (particle systems, softbody,
+ * etc.) in `ob_dst`, if needed calling code must do it.
+ *
+ * @param do_copy_all If true, even modifiers that should not suport copying (like Hook one) will
+ * be duplicated.
+ */
+bool BKE_object_modifier_stack_copy(Object *ob_dst,
+ const Object *ob_src,
+ const bool do_copy_all,
+ const int flag_subdata)
{
- BKE_object_free_modifiers(ob_dst, 0);
+ if ((ob_dst->type == OB_GPENCIL) != (ob_src->type == OB_GPENCIL)) {
+ BLI_assert(!"Trying to copy a modifier stack between a GPencil object and another type.");
+ return false;
+ }
- if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE, OB_GPENCIL)) {
- /* only objects listed above can have modifiers and linking them to objects
- * which doesn't have modifiers stack is quite silly */
- return;
+ if (!BLI_listbase_is_empty(&ob_dst->modifiers) ||
+ !BLI_listbase_is_empty(&ob_dst->greasepencil_modifiers)) {
+ BLI_assert(
+ !"Trying to copy a modifier stack into an object having a non-empty modifier stack.");
+ return false;
}
- /* No grease pencil modifiers. */
- if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) {
- LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
- BKE_object_copy_modifier(ob_dst, ob_src, md);
+ LISTBASE_FOREACH (ModifierData *, md_src, &ob_src->modifiers) {
+ if (!do_copy_all && !object_modifier_type_copy_check(md_src->type)) {
+ continue;
+ }
+ if (!BKE_object_support_modifier_type_check(ob_dst, md_src->type)) {
+ continue;
}
+
+ ModifierData *md_dst = BKE_modifier_new(md_src->type);
+ BLI_strncpy(md_dst->name, md_src->name, sizeof(md_dst->name));
+ BKE_modifier_copydata_ex(md_src, md_dst, flag_subdata);
+ BLI_addtail(&ob_dst->modifiers, md_dst);
}
- /* Copy grease pencil modifiers. */
- if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) {
- LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) {
- BKE_object_copy_gpencil_modifier(ob_dst, md);
- }
+ LISTBASE_FOREACH (GpencilModifierData *, gmd_src, &ob_src->greasepencil_modifiers) {
+ GpencilModifierData *gmd_dst = BKE_gpencil_modifier_new(gmd_src->type);
+ BLI_strncpy(gmd_dst->name, gmd_src->name, sizeof(gmd_dst->name));
+ BKE_gpencil_modifier_copydata_ex(gmd_src, gmd_dst, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, gmd_dst);
}
- BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
+ /* This could be copied from anywhere, since no other modifier actually use this data. But for
+ * consistency do it together with particle systems. */
+ BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
+
+ /* It is mandatory that this happens after copying modifiers, as it will update their `psys`
+ * pointers accordingly. */
+ BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
+
+ return true;
+}
+
+void BKE_object_link_modifiers(Object *ob_dst, const Object *ob_src)
+{
+ BKE_object_free_modifiers(ob_dst, 0);
- /* TODO: smoke?, cloth? */
+ BKE_object_modifier_stack_copy(ob_dst, ob_src, false, 0);
}
/**
@@ -2109,7 +2243,7 @@ Object *BKE_object_add_for_data(
return ob;
}
-void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
+void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src, const int flag)
{
SoftBody *sb = ob_src->soft;
bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
@@ -2153,7 +2287,7 @@ void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src
sbn->scratch = NULL;
- if (tagged_no_main == 0) {
+ if (!tagged_no_main) {
sbn->shared = MEM_dupallocN(sb->shared);
sbn->shared->pointcache = BKE_ptcache_copy_list(
&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);