void BKE_modifier_init(void) { ModifierData *md; /* Initialize modifier types */ modifier_type_init(modifier_types); /* MOD_utils.c */ /* Initialize global cmmon storage used for virtual modifier list */ md = modifier_new(eModifierType_Armature); virtualModifierCommonData.amd = *((ArmatureModifierData *) md); modifier_free(md); md = modifier_new(eModifierType_Curve); virtualModifierCommonData.cmd = *((CurveModifierData *) md); modifier_free(md); md = modifier_new(eModifierType_Lattice); virtualModifierCommonData.lmd = *((LatticeModifierData *) md); modifier_free(md); md = modifier_new(eModifierType_ShapeKey); virtualModifierCommonData.smd = *((ShapeKeyModifierData *) md); modifier_free(md); virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual; }
static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr) { Object *ob = (Object*)ptr->id.data; FluidsimModifierData *fluidmd; ParticleSystemModifierData *psmd; ParticleSystem *psys; ParticleSettings *part; fluidmd = (FluidsimModifierData*)modifiers_findByType(ob, eModifierType_Fluidsim); fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */ /* remove fluidsim particle system */ if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) { for (psys = ob->particlesystem.first; psys; psys = psys->next) if (psys->part->type == PART_FLUID) break; if (ob->type == OB_MESH && !psys) { /* add particle system */ part = psys_new_settings("ParticleSettings", bmain); psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); part->type = PART_FLUID; psys->part = part; psys->pointcache = BKE_ptcache_add(&psys->ptcaches); psys->flag |= PSYS_ENABLED; BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name)); BLI_addtail(&ob->particlesystem,psys); /* add modifier */ psmd = (ParticleSystemModifierData*)modifier_new(eModifierType_ParticleSystem); BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name)); psmd->psys = psys; BLI_addtail(&ob->modifiers, psmd); modifier_unique_name(&ob->modifiers, (ModifierData *)psmd); } } else { for (psys = ob->particlesystem.first; psys; psys = psys->next) { if (psys->part->type == PART_FLUID) { /* clear modifier */ psmd = psys_get_modifier(ob, psys); BLI_remlink(&ob->modifiers, psmd); modifier_free((ModifierData *)psmd); /* clear particle system */ BLI_remlink(&ob->particlesystem, psys); psys_free(ob, psys); } } } rna_fluid_update(bmain, scene, ptr); }
static void remove_particle_systems_from_object(Object *ob_to) { ModifierData *md, *md_next; if (ob_to->type != OB_MESH) return; if (!ob_to->data || ((ID *)ob_to->data)->lib) return; for (md = ob_to->modifiers.first; md; md = md_next) { md_next = md->next; /* remove all particle system modifiers as well, * these need to sync to the particle system list */ if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, eModifierType_Smoke)) { BLI_remlink(&ob_to->modifiers, md); modifier_free(md); } } BKE_object_free_particlesystems(ob_to); }
static int object_hook_remove_exec(bContext *C, wmOperator *op) { int num= RNA_enum_get(op->ptr, "modifier"); Object *ob=NULL; HookModifierData *hmd=NULL; ob = CTX_data_edit_object(C); hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); if (!ob || !hmd) { BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier"); return OPERATOR_CANCELLED; } /* remove functionality */ BLI_remlink(&ob->modifiers, (ModifierData *)hmd); modifier_free((ModifierData *)hmd); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); return OPERATOR_FINISHED; }
int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode) { int prev_mode; if (scene->obedit) { BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode"); 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->modifiers.first) BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ prev_mode= md->mode; md->mode |= eModifierMode_Realtime; if (mode == MODIFIER_APPLY_SHAPE) { if (!modifier_apply_shape(reports, scene, ob, md)) { md->mode= prev_mode; return 0; } } else { if (!modifier_apply_obdata(reports, scene, ob, md)) { md->mode= prev_mode; return 0; } } BLI_remlink(&ob->modifiers, md); modifier_free(md); return 1; }
static int bake( Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const ScenePassType pass_type, const int margin, const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[], const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; float *result = NULL; BakePixel *pixel_array_low = NULL; BakePixel *pixel_array_high = NULL; const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); const bool is_noncolor = is_noncolor_pass(pass_type); const int depth = RE_pass_depth(pass_type); BakeImages bake_images = {NULL}; size_t num_pixels; int tot_materials; RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } tot_materials = ob_low->totcol; if (uv_layer && uv_layer[0] != '\0') { Mesh *me = (Mesh *)ob_low->data; if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { BKE_reportf(reports, RPT_ERROR, "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); goto cleanup; } } if (tot_materials == 0) { if (is_save_internal) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); goto cleanup; } else if (is_split_materials) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake without the Split Materials option"); goto cleanup; } else { /* baking externally without splitting materials */ tot_materials = 1; } } /* we overallocate in case there is more materials than images */ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = (size_t)width * (size_t)height * bake_images.size; for (int i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; bake_images.data[i].height = height; bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); bake_images.data[i].image = NULL; } if (!is_split_materials) { /* saving a single image */ for (int i = 0; i < tot_materials; i++) { bake_images.lookup[i] = 0; } } } if (is_selected_to_active) { CollectionPointerLink *link; tot_highpoly = 0; for (link = selected_objects->first; link; link = link->next) { Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; tot_highpoly ++; } if (is_cage && custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; ob_cage->restrictflag |= OB_RESTRICT_RENDER; } } } pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ if (is_selected_to_active) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; int i = 0; /* prepare cage mesh */ if (ob_cage) { me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); BKE_mesh_split_faces(me_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 " "of faces as the active object"); goto cleanup; } } else if (is_cage) { modifiers_original = ob_low->modifiers; BLI_listbase_clear(&modifiers_tmp); for (md = ob_low->modifiers.first; md; md = md->next) { /* Edge Split cannot be applied in the cage, * the cage is supposed to have interpolated normals * between the faces unless the geometry is physically * split. So we create a copy of the low poly mesh without * the eventual edge split.*/ if (md->type == eModifierType_EdgeSplit) continue; nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); modifier_copyData(md, nmd); BLI_addtail(&modifiers_tmp, nmd); } /* temporarily replace the modifiers */ ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* populate highpoly array */ for (link = selected_objects->first; link; link = link->next) { TriangulateModifierData *tmd; Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; /* initialize highpoly_data */ highpoly[i].ob = ob_iter; highpoly[i].restrict_flag = ob_iter->restrictflag; /* triangulating so BVH returns the primitive_id that will be used for rendering */ highpoly[i].tri_mod = ED_object_modifier_add( reports, bmain, scene, highpoly[i].ob, "TmpTriangulate", eModifierType_Triangulate); tmd = (TriangulateModifierData *)highpoly[i].tri_mod; tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; BKE_mesh_split_faces(highpoly[i].me); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); i++; } BLI_assert(i == tot_highpoly); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cage_cleanup; } /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, num_pixels, depth, pass_type, result); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); goto cage_cleanup; } } cage_cleanup: /* reverting data back */ if ((ob_cage == NULL) && is_cage) { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } if (!ok) { goto cleanup; } } else { /* make sure low poly renders */ 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, result); } else { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (ok && pass_type == SCE_PASS_NORMAL) { switch (normal_space) { case R_BAKE_SPACE_WORLD: { /* Cycles internal format */ if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && (normal_swizzle[2] == R_BAKE_POSZ)) { break; } else { RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); } break; } case R_BAKE_SPACE_OBJECT: { RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle); break; } case R_BAKE_SPACE_TANGENT: { if (is_selected_to_active) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat); } else { /* from multiresolution */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; md = modifiers_findByType(ob_low, eModifierType_Multires); if (md) { mode = md->mode; md->mode &= ~eModifierMode_Render; } me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_nores); 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); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (int i = 0; i < bake_images.size; i++) { BakeImage *bk_image = &bake_images.data[i]; if (is_save_internal) { ok = write_internal_bake_pixels( bk_image->image, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, is_clear, is_noncolor); /* might be read by UI to set active image for display */ bake_update_image(sa, bk_image->image); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { BKE_report(reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it"); op_result = OPERATOR_FINISHED; } } /* save externally */ else { BakeData *bake = &scene->r.bake; char name[FILE_MAX]; BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); BLI_path_suffix(name, FILE_MAX, identifier, "_"); } if (is_split_materials) { if (bk_image->image) { BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); } else { if (ob_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_"); } else if (me_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); } else { /* if everything else fails, use the material index */ char tmp[4]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } } /* save it externally */ ok = write_external_bake_pixels( name, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, &bake->im_format, is_noncolor); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); op_result = OPERATOR_CANCELLED; } else { BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); op_result = OPERATOR_FINISHED; } if (!is_split_materials) { break; } } } } if (is_save_internal) refresh_images(&bake_images); cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].tri_mod) ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); if (highpoly[i].me) BKE_libblock_free(bmain, highpoly[i].me); } MEM_freeN(highpoly); } ob_low->restrictflag = restrict_flag_low; if (ob_cage) ob_cage->restrictflag = restrict_flag_cage; if (pixel_array_low) MEM_freeN(pixel_array_low); if (pixel_array_high) MEM_freeN(pixel_array_high); if (bake_images.data) MEM_freeN(bake_images.data); if (bake_images.lookup) MEM_freeN(bake_images.lookup); if (result) MEM_freeN(result); if (me_low) BKE_libblock_free(bmain, me_low); if (me_cage) BKE_libblock_free(bmain, me_cage); return op_result; }
ModifierData *modifiers_getVirtualModifierList(Object *ob) { /* Kinda hacky, but should be fine since we are never * reentrant and avoid free hassles. */ static ArmatureModifierData amd; static CurveModifierData cmd; static LatticeModifierData lmd; static ShapeKeyModifierData smd; static int init = 1; ModifierData *md; if (init) { md = modifier_new(eModifierType_Armature); amd = *((ArmatureModifierData*) md); modifier_free(md); md = modifier_new(eModifierType_Curve); cmd = *((CurveModifierData*) md); modifier_free(md); md = modifier_new(eModifierType_Lattice); lmd = *((LatticeModifierData*) md); modifier_free(md); md = modifier_new(eModifierType_ShapeKey); smd = *((ShapeKeyModifierData*) md); modifier_free(md); amd.modifier.mode |= eModifierMode_Virtual; cmd.modifier.mode |= eModifierMode_Virtual; lmd.modifier.mode |= eModifierMode_Virtual; smd.modifier.mode |= eModifierMode_Virtual; init = 0; } md = ob->modifiers.first; if(ob->parent) { if(ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL) { amd.object = ob->parent; amd.modifier.next = md; amd.deformflag= ((bArmature *)(ob->parent->data))->deformflag; md = &amd.modifier; } else if(ob->parent->type==OB_CURVE && ob->partype==PARSKEL) { cmd.object = ob->parent; cmd.defaxis = ob->trackflag + 1; cmd.modifier.next = md; md = &cmd.modifier; } else if(ob->parent->type==OB_LATTICE && ob->partype==PARSKEL) { lmd.object = ob->parent; lmd.modifier.next = md; md = &lmd.modifier; } } /* shape key modifier, not yet for curves */ if(ELEM(ob->type, OB_MESH, OB_LATTICE) && ob_get_key(ob)) { if(ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE)) smd.modifier.mode |= eModifierMode_Editmode|eModifierMode_OnCage; else smd.modifier.mode &= ~eModifierMode_Editmode|eModifierMode_OnCage; smd.modifier.next = md; md = &smd.modifier; } return md; }
static int object_modifier_remove(Object *ob, ModifierData *md, int *sort_depsgraph) { ModifierData *obmd; /* It seems on rapid delete it is possible to * get called twice on same modifier, so make * sure it is in list. */ for(obmd=ob->modifiers.first; obmd; obmd=obmd->next) if(obmd==md) break; if(!obmd) return 0; /* special cases */ if(md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd=(ParticleSystemModifierData*)md; BLI_remlink(&ob->particlesystem, psmd->psys); psys_free(ob, psmd->psys); psmd->psys= NULL; } else if(md->type == eModifierType_Softbody) { if(ob->soft) { sbFree(ob->soft); ob->soft= NULL; ob->softflag= 0; } } else if(md->type == eModifierType_Collision) { if(ob->pd) ob->pd->deflect= 0; *sort_depsgraph = 1; } else if(md->type == eModifierType_Surface) { if(ob->pd && ob->pd->shape == PFIELD_SHAPE_SURFACE) ob->pd->shape = PFIELD_SHAPE_PLANE; *sort_depsgraph = 1; } else if(md->type == eModifierType_Smoke) { ob->dt = OB_TEXTURE; } else if(md->type == eModifierType_Multires) { int ok= 1; Mesh *me= ob->data; ModifierData *tmpmd; /* ensure MDISPS CustomData layer is't used by another multires modifiers */ for(tmpmd= ob->modifiers.first; tmpmd; tmpmd= tmpmd->next) if(tmpmd!=md && tmpmd->type == eModifierType_Multires) { ok= 0; break; } if(ok) { if(me->edit_mesh) { EditMesh *em= me->edit_mesh; /* CustomData_external_remove is used here only to mark layer as non-external for further free-ing, so zero element count looks safer than em->totface */ CustomData_external_remove(&em->fdata, &me->id, CD_MDISPS, 0); EM_free_data_layer(em, &em->fdata, CD_MDISPS); } else { CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface); } } } if(ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && ob->particlesystem.first == NULL) { ob->mode &= ~OB_MODE_PARTICLE_EDIT; } BLI_remlink(&ob->modifiers, md); modifier_free(md); return 1; }
int ED_object_modifier_remove(ReportList *reports, Main *bmain, Scene *scene, Object *ob, ModifierData *md) { ModifierData *obmd; int sort_depsgraph = 0; /* It seems on rapid delete it is possible to * get called twice on same modifier, so make * sure it is in list. */ for(obmd=ob->modifiers.first; obmd; obmd=obmd->next) if(obmd==md) break; if(!obmd) { BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", ob->id.name, md->name); return 0; } /* special cases */ if(md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd=(ParticleSystemModifierData*)md; BLI_remlink(&ob->particlesystem, psmd->psys); psys_free(ob, psmd->psys); psmd->psys= NULL; } else if(md->type == eModifierType_Softbody) { if(ob->soft) { sbFree(ob->soft); ob->soft= NULL; ob->softflag= 0; } } else if(md->type == eModifierType_Collision) { if(ob->pd) ob->pd->deflect= 0; sort_depsgraph = 1; } else if(md->type == eModifierType_Surface) { if(ob->pd && ob->pd->shape == PFIELD_SHAPE_SURFACE) ob->pd->shape = PFIELD_SHAPE_PLANE; sort_depsgraph = 1; } else if(md->type == eModifierType_Smoke) { ob->dt = OB_TEXTURE; } else if(md->type == eModifierType_Multires) { int ok= 1; Mesh *me= ob->data; ModifierData *tmpmd; /* ensure MDISPS CustomData layer is't used by another multires modifiers */ for(tmpmd= ob->modifiers.first; tmpmd; tmpmd= tmpmd->next) if(tmpmd!=md && tmpmd->type == eModifierType_Multires) { ok= 0; break; } if(ok) { if(me->edit_mesh) { EditMesh *em= me->edit_mesh; /* CustomData_external_remove is used here only to mark layer as non-external for further free-ing, so zero element count looks safer than em->totface */ CustomData_external_remove(&em->fdata, &me->id, CD_MDISPS, 0); EM_free_data_layer(em, &em->fdata, CD_MDISPS); } else { CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface); } } } if(ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && ob->particlesystem.first == NULL) { ob->mode &= ~OB_MODE_PARTICLE_EDIT; } BLI_remlink(&ob->modifiers, md); modifier_free(md); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sorting has to be done after the update so that dynamic systems can react properly */ if(sort_depsgraph) DAG_scene_sort(bmain, scene); return 1; }