1251 lines
35 KiB
C
1251 lines
35 KiB
C
/*
|
|
* ***** 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) 2005 by the Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Contributor(s): Daniel Dunbar
|
|
* Ton Roosendaal,
|
|
* Ben Batt,
|
|
* Brecht Van Lommel,
|
|
* Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*
|
|
* Modifier stack implementation.
|
|
*
|
|
* BKE_modifier.h contains the function prototypes for this file.
|
|
*
|
|
*/
|
|
|
|
/** \file blender/blenkernel/intern/modifier.c
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_linklist.h"
|
|
#include "BLI_path_util.h"
|
|
#include "BLI_string.h"
|
|
#include "BLI_string_utils.h"
|
|
|
|
#include "BLT_translation.h"
|
|
|
|
#include "BKE_appdir.h"
|
|
#include "BKE_cdderivedmesh.h"
|
|
#include "BKE_editmesh.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_idcode.h"
|
|
#include "BKE_key.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_library_query.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_multires.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
/* may move these, only for modifier_path_relbase */
|
|
#include "BKE_main.h"
|
|
/* end */
|
|
|
|
#include "DEG_depsgraph.h"
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
#include "MOD_modifiertypes.h"
|
|
|
|
static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
|
|
static VirtualModifierData virtualModifierCommonData;
|
|
|
|
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;
|
|
}
|
|
|
|
const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
|
|
{
|
|
/* type unsigned, no need to check < 0 */
|
|
if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
|
|
return modifier_types[type];
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/***/
|
|
|
|
ModifierData *modifier_new(int type)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(type);
|
|
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
|
|
|
|
/* note, this name must be made unique later */
|
|
BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
|
|
|
|
md->type = type;
|
|
md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
|
|
md->flag = eModifierFlag_StaticOverride_Local;
|
|
|
|
if (mti->flags & eModifierTypeFlag_EnableInEditmode)
|
|
md->mode |= eModifierMode_Editmode;
|
|
|
|
if (mti->initData) mti->initData(md);
|
|
|
|
return md;
|
|
}
|
|
|
|
static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
|
|
{
|
|
ID *id = *idpoin;
|
|
if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
|
|
id_us_min(id);
|
|
}
|
|
}
|
|
|
|
void modifier_free_ex(ModifierData *md, const int flag)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
|
if (mti->foreachIDLink) {
|
|
mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
|
|
}
|
|
else if (mti->foreachObjectLink) {
|
|
mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
|
|
}
|
|
}
|
|
|
|
if (mti->freeData) mti->freeData(md);
|
|
if (md->error) MEM_freeN(md->error);
|
|
|
|
MEM_freeN(md);
|
|
}
|
|
|
|
void modifier_free(ModifierData *md)
|
|
{
|
|
modifier_free_ex(md, 0);
|
|
}
|
|
|
|
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
|
|
{
|
|
if (modifiers && md) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool modifier_dependsOnTime(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
return mti->dependsOnTime && mti->dependsOnTime(md);
|
|
}
|
|
|
|
bool modifier_supportsMapping(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
return (mti->type == eModifierTypeType_OnlyDeform ||
|
|
(mti->flags & eModifierTypeFlag_SupportsMapping));
|
|
}
|
|
|
|
bool modifier_isPreview(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
/* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
|
|
if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) {
|
|
return false;
|
|
}
|
|
|
|
if (md->mode & eModifierMode_Realtime) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ModifierData *modifiers_findByType(Object *ob, ModifierType type)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
|
|
for (; md; md = md->next)
|
|
if (md->type == type)
|
|
break;
|
|
|
|
return md;
|
|
}
|
|
|
|
ModifierData *modifiers_findByName(Object *ob, const char *name)
|
|
{
|
|
return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
|
|
}
|
|
|
|
void modifiers_clearErrors(Object *ob)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
/* int qRedraw = 0; */
|
|
|
|
for (; md; md = md->next) {
|
|
if (md->error) {
|
|
MEM_freeN(md->error);
|
|
md->error = NULL;
|
|
|
|
/* qRedraw = 1; */
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
|
|
for (; md; md = md->next) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->foreachObjectLink)
|
|
mti->foreachObjectLink(md, ob, walk, userData);
|
|
}
|
|
}
|
|
|
|
void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
|
|
for (; md; md = md->next) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
|
|
else if (mti->foreachObjectLink) {
|
|
/* each Object can masquerade as an ID, so this should be OK */
|
|
ObjectWalkFunc fp = (ObjectWalkFunc)walk;
|
|
mti->foreachObjectLink(md, ob, fp, userData);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
|
|
for (; md; md = md->next) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->foreachTexLink)
|
|
mti->foreachTexLink(md, ob, walk, userData);
|
|
}
|
|
}
|
|
|
|
/* callback's can use this
|
|
* to avoid copying every member.
|
|
*/
|
|
void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
|
|
|
|
/* md_dst may have alredy be fully initialized with some extra allocated data,
|
|
* we need to free it now to avoid memleak. */
|
|
if (mti->freeData) {
|
|
mti->freeData(md_dst);
|
|
}
|
|
|
|
const size_t data_size = sizeof(ModifierData);
|
|
const char *md_src_data = ((const char *)md_src) + data_size;
|
|
char *md_dst_data = ((char *)md_dst) + data_size;
|
|
BLI_assert(data_size <= (size_t)mti->structSize);
|
|
memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size);
|
|
}
|
|
|
|
static void modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
|
|
{
|
|
ID *id = *idpoin;
|
|
if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
|
|
id_us_plus(id);
|
|
}
|
|
}
|
|
|
|
void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
target->mode = md->mode;
|
|
target->flag = md->flag;
|
|
|
|
if (mti->copyData) {
|
|
mti->copyData(md, target);
|
|
}
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
|
if (mti->foreachIDLink) {
|
|
mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL);
|
|
}
|
|
else if (mti->foreachObjectLink) {
|
|
mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_copyData(ModifierData *md, ModifierData *target)
|
|
{
|
|
modifier_copyData_ex(md, target, 0);
|
|
}
|
|
|
|
|
|
bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
md->scene = scene;
|
|
|
|
return ((!mti->isDisabled || !mti->isDisabled(md, 0)) &&
|
|
(mti->flags & eModifierTypeFlag_SupportsEditmode) &&
|
|
modifier_supportsMapping(md));
|
|
}
|
|
|
|
bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
md->scene = scene;
|
|
|
|
return ((md->mode & eModifierMode_Realtime) &&
|
|
(md->mode & eModifierMode_Editmode) &&
|
|
(!mti->isDisabled || !mti->isDisabled(md, 0)) &&
|
|
modifier_supportsMapping(md));
|
|
}
|
|
|
|
bool modifier_isSameTopology(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
|
|
}
|
|
|
|
bool modifier_isNonGeometrical(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
return (mti->type == eModifierTypeType_NonGeometrical);
|
|
}
|
|
|
|
void modifier_setError(ModifierData *md, const char *_format, ...)
|
|
{
|
|
char buffer[512];
|
|
va_list ap;
|
|
const char *format = TIP_(_format);
|
|
|
|
va_start(ap, _format);
|
|
vsnprintf(buffer, sizeof(buffer), format, ap);
|
|
va_end(ap);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
if (md->error)
|
|
MEM_freeN(md->error);
|
|
|
|
md->error = BLI_strdup(buffer);
|
|
|
|
}
|
|
|
|
/* used for buttons, to find out if the 'draw deformed in editmode' option is
|
|
* there
|
|
*
|
|
* also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg
|
|
* then is NULL)
|
|
* also used for some mesh tools to give warnings
|
|
*/
|
|
int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleCageIndex, bool is_virtual)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) : ob->modifiers.first;
|
|
int i, cageIndex = -1;
|
|
|
|
if (r_lastPossibleCageIndex) {
|
|
/* ensure the value is initialized */
|
|
*r_lastPossibleCageIndex = -1;
|
|
}
|
|
|
|
/* Find the last modifier acting on the cage. */
|
|
for (i = 0; md; i++, md = md->next) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
bool supports_mapping;
|
|
|
|
md->scene = scene;
|
|
|
|
if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
|
|
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
|
|
if (md->mode & eModifierMode_DisableTemporary) continue;
|
|
|
|
supports_mapping = modifier_supportsMapping(md);
|
|
if (r_lastPossibleCageIndex && supports_mapping) {
|
|
*r_lastPossibleCageIndex = i;
|
|
}
|
|
|
|
if (!(md->mode & eModifierMode_Realtime)) continue;
|
|
if (!(md->mode & eModifierMode_Editmode)) continue;
|
|
|
|
if (!supports_mapping)
|
|
break;
|
|
|
|
if (md->mode & eModifierMode_OnCage)
|
|
cageIndex = i;
|
|
}
|
|
|
|
return cageIndex;
|
|
}
|
|
|
|
|
|
bool modifiers_isSoftbodyEnabled(Object *ob)
|
|
{
|
|
ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
|
|
|
|
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
|
|
}
|
|
|
|
bool modifiers_isClothEnabled(Object *ob)
|
|
{
|
|
ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
|
|
|
|
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
|
|
}
|
|
|
|
bool modifiers_isModifierEnabled(Object *ob, int modifierType)
|
|
{
|
|
ModifierData *md = modifiers_findByType(ob, modifierType);
|
|
|
|
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
|
|
}
|
|
|
|
bool modifiers_isParticleEnabled(Object *ob)
|
|
{
|
|
ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
|
|
|
|
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
|
|
}
|
|
|
|
/**
|
|
* Check whether is enabled.
|
|
*
|
|
* \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called.
|
|
*/
|
|
bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
md->scene = scene;
|
|
|
|
if ((md->mode & required_mode) != required_mode) return false;
|
|
if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
|
|
if (md->mode & eModifierMode_DisableTemporary) return false;
|
|
if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierData *md,
|
|
CustomDataMask dataMask, int required_mode,
|
|
ModifierData *previewmd, CustomDataMask previewmask)
|
|
{
|
|
CDMaskLink *dataMasks = NULL;
|
|
CDMaskLink *curr, *prev;
|
|
|
|
/* build a list of modifier data requirements in reverse order */
|
|
for (; md; md = md->next) {
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
|
|
|
|
if (modifier_isEnabled(scene, md, required_mode)) {
|
|
if (mti->requiredDataMask)
|
|
curr->mask = mti->requiredDataMask(ob, md);
|
|
|
|
if (previewmd == md) {
|
|
curr->mask |= previewmask;
|
|
}
|
|
}
|
|
|
|
/* prepend new datamask */
|
|
curr->next = dataMasks;
|
|
dataMasks = curr;
|
|
}
|
|
|
|
/* build the list of required data masks - each mask in the list must
|
|
* include all elements of the masks that follow it
|
|
*
|
|
* note the list is currently in reverse order, so "masks that follow it"
|
|
* actually means "masks that precede it" at the moment
|
|
*/
|
|
for (curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) {
|
|
if (prev) {
|
|
CustomDataMask prev_mask = prev->mask;
|
|
CustomDataMask curr_mask = curr->mask;
|
|
|
|
curr->mask = curr_mask | prev_mask;
|
|
}
|
|
else {
|
|
CustomDataMask curr_mask = curr->mask;
|
|
|
|
curr->mask = curr_mask | dataMask;
|
|
}
|
|
}
|
|
|
|
/* reverse the list so it's in the correct order */
|
|
BLI_linklist_reverse((LinkNode **)&dataMasks);
|
|
|
|
return dataMasks;
|
|
}
|
|
|
|
ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, int required_mode)
|
|
{
|
|
ModifierData *tmp_md = NULL;
|
|
|
|
if ((required_mode & ~eModifierMode_Editmode) != eModifierMode_Realtime)
|
|
return tmp_md;
|
|
|
|
/* Find the latest modifier in stack generating preview. */
|
|
for (; md; md = md->next) {
|
|
if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md))
|
|
tmp_md = md;
|
|
}
|
|
return tmp_md;
|
|
}
|
|
|
|
/* NOTE: This is to support old files from before Blender supported modifiers,
|
|
* in some cases versioning code updates these so for new files this will
|
|
* return an empty list. */
|
|
ModifierData *modifiers_getVirtualModifierList(Object *ob, VirtualModifierData *virtualModifierData)
|
|
{
|
|
ModifierData *md;
|
|
|
|
md = ob->modifiers.first;
|
|
|
|
*virtualModifierData = virtualModifierCommonData;
|
|
|
|
if (ob->parent) {
|
|
if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) {
|
|
virtualModifierData->amd.object = ob->parent;
|
|
virtualModifierData->amd.modifier.next = md;
|
|
virtualModifierData->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
|
|
md = &virtualModifierData->amd.modifier;
|
|
}
|
|
else if (ob->parent->type == OB_CURVE && ob->partype == PARSKEL) {
|
|
virtualModifierData->cmd.object = ob->parent;
|
|
virtualModifierData->cmd.defaxis = ob->trackflag + 1;
|
|
virtualModifierData->cmd.modifier.next = md;
|
|
md = &virtualModifierData->cmd.modifier;
|
|
}
|
|
else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
|
|
virtualModifierData->lmd.object = ob->parent;
|
|
virtualModifierData->lmd.modifier.next = md;
|
|
md = &virtualModifierData->lmd.modifier;
|
|
}
|
|
}
|
|
|
|
/* shape key modifier, not yet for curves */
|
|
if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object(ob)) {
|
|
if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE))
|
|
virtualModifierData->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
|
|
else
|
|
virtualModifierData->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
|
|
|
|
virtualModifierData->smd.modifier.next = md;
|
|
md = &virtualModifierData->smd.modifier;
|
|
}
|
|
|
|
return md;
|
|
}
|
|
|
|
/* Takes an object and returns its first selected armature, else just its armature
|
|
* This should work for multiple armatures per object
|
|
*/
|
|
Object *modifiers_isDeformedByArmature(Object *ob)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
ArmatureModifierData *amd = NULL;
|
|
|
|
/* return the first selected armature, this lets us use multiple armatures */
|
|
for (; md; md = md->next) {
|
|
if (md->type == eModifierType_Armature) {
|
|
amd = (ArmatureModifierData *) md;
|
|
if (amd->object && (amd->object->flag & SELECT))
|
|
return amd->object;
|
|
}
|
|
}
|
|
|
|
if (amd) /* if were still here then return the last armature */
|
|
return amd->object;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Object *modifiers_isDeformedByMeshDeform(Object *ob)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
MeshDeformModifierData *mdmd = NULL;
|
|
|
|
/* return the first selected armature, this lets us use multiple armatures */
|
|
for (; md; md = md->next) {
|
|
if (md->type == eModifierType_MeshDeform) {
|
|
mdmd = (MeshDeformModifierData *) md;
|
|
if (mdmd->object && (mdmd->object->flag & SELECT))
|
|
return mdmd->object;
|
|
}
|
|
}
|
|
|
|
if (mdmd) /* if were still here then return the last armature */
|
|
return mdmd->object;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Takes an object and returns its first selected lattice, else just its lattice
|
|
* This should work for multiple lattices per object
|
|
*/
|
|
Object *modifiers_isDeformedByLattice(Object *ob)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
LatticeModifierData *lmd = NULL;
|
|
|
|
/* return the first selected lattice, this lets us use multiple lattices */
|
|
for (; md; md = md->next) {
|
|
if (md->type == eModifierType_Lattice) {
|
|
lmd = (LatticeModifierData *) md;
|
|
if (lmd->object && (lmd->object->flag & SELECT))
|
|
return lmd->object;
|
|
}
|
|
}
|
|
|
|
if (lmd) /* if were still here then return the last lattice */
|
|
return lmd->object;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Takes an object and returns its first selected curve, else just its curve
|
|
* This should work for multiple curves per object
|
|
*/
|
|
Object *modifiers_isDeformedByCurve(Object *ob)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
CurveModifierData *cmd = NULL;
|
|
|
|
/* return the first selected curve, this lets us use multiple curves */
|
|
for (; md; md = md->next) {
|
|
if (md->type == eModifierType_Curve) {
|
|
cmd = (CurveModifierData *) md;
|
|
if (cmd->object && (cmd->object->flag & SELECT))
|
|
return cmd->object;
|
|
}
|
|
}
|
|
|
|
if (cmd) /* if were still here then return the last curve */
|
|
return cmd->object;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool modifiers_usesArmature(Object *ob, bArmature *arm)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
|
|
for (; md; md = md->next) {
|
|
if (md->type == eModifierType_Armature) {
|
|
ArmatureModifierData *amd = (ArmatureModifierData *) md;
|
|
if (amd->object && amd->object->data == arm)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool modifier_isCorrectableDeformed(ModifierData *md)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
return (mti->deformMatricesEM != NULL) || (mti->deformMatricesEM_DM != NULL);
|
|
}
|
|
|
|
bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
|
|
{
|
|
VirtualModifierData virtualModifierData;
|
|
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
|
|
int required_mode = eModifierMode_Realtime;
|
|
|
|
if (ob->mode == OB_MODE_EDIT) {
|
|
required_mode |= eModifierMode_Editmode;
|
|
}
|
|
for (; md; md = md->next) {
|
|
if (!modifier_isEnabled(scene, md, required_mode)) {
|
|
/* pass */
|
|
}
|
|
else if (modifier_isCorrectableDeformed(md)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Check whether the given object has a modifier in its stack that uses WEIGHT_MCOL CD layer
|
|
* to preview something... Used by DynamicPaint and WeightVG currently. */
|
|
bool modifiers_isPreview(Object *ob)
|
|
{
|
|
ModifierData *md = ob->modifiers.first;
|
|
|
|
for (; md; md = md->next) {
|
|
if (modifier_isPreview(md))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void modifier_freeTemporaryData(ModifierData *md)
|
|
{
|
|
if (md->type == eModifierType_Armature) {
|
|
ArmatureModifierData *amd = (ArmatureModifierData *)md;
|
|
|
|
if (amd->prevCos) {
|
|
MEM_freeN(amd->prevCos);
|
|
amd->prevCos = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ensure modifier correctness when changing ob->data */
|
|
void test_object_modifiers(Object *ob)
|
|
{
|
|
ModifierData *md;
|
|
|
|
/* just multires checked for now, since only multires
|
|
* modifies mesh data */
|
|
|
|
if (ob->type != OB_MESH) return;
|
|
|
|
for (md = ob->modifiers.first; md; md = md->next) {
|
|
if (md->type == eModifierType_Multires) {
|
|
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
|
|
|
multiresModifier_set_levels_from_disps(mmd, ob);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* where should this go?, it doesnt fit well anywhere :S - campbell */
|
|
|
|
/* elubie: changed this to default to the same dir as the render output
|
|
* to prevent saving to C:\ on Windows */
|
|
|
|
/* campbell: logic behind this...
|
|
*
|
|
* - if the ID is from a library, return library path
|
|
* - else if the file has been saved return the blend file path.
|
|
* - else if the file isn't saved and the ID isn't from a library, return the temp dir.
|
|
*/
|
|
const char *modifier_path_relbase(Main *bmain, Object *ob)
|
|
{
|
|
if (G.relbase_valid || ID_IS_LINKED(ob)) {
|
|
return ID_BLEND_PATH(bmain, &ob->id);
|
|
}
|
|
else {
|
|
/* last resort, better then using "" which resolves to the current
|
|
* working directory */
|
|
return BKE_tempdir_session();
|
|
}
|
|
}
|
|
|
|
const char *modifier_path_relbase_from_global(Object *ob)
|
|
{
|
|
if (G.relbase_valid || ID_IS_LINKED(ob)) {
|
|
return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
|
|
}
|
|
else {
|
|
/* last resort, better then using "" which resolves to the current
|
|
* working directory */
|
|
return BKE_tempdir_session();
|
|
}
|
|
}
|
|
|
|
/* initializes the path with either */
|
|
void modifier_path_init(char *path, int path_maxlen, const char *name)
|
|
{
|
|
/* elubie: changed this to default to the same dir as the render output
|
|
* to prevent saving to C:\ on Windows */
|
|
BLI_join_dirfile(path, path_maxlen,
|
|
G.relbase_valid ? "//" : BKE_tempdir_session(),
|
|
name);
|
|
}
|
|
|
|
|
|
/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
|
|
|
|
struct DerivedMesh *modwrap_applyModifier(
|
|
ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct DerivedMesh *dm)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
|
|
|
|
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
DM_ensure_normals(dm);
|
|
}
|
|
return modifier_applyModifier_DM_deprecated(md, ctx, dm);
|
|
}
|
|
|
|
struct DerivedMesh *modwrap_applyModifierEM(
|
|
ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *em, DerivedMesh *dm)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
|
|
|
|
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
DM_ensure_normals(dm);
|
|
}
|
|
return modifier_applyModifierEM_DM_deprecated(md, ctx, em, dm);
|
|
}
|
|
|
|
void modwrap_deformVerts(
|
|
ModifierData *md, const ModifierEvalContext *ctx,
|
|
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
|
|
|
|
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
DM_ensure_normals(dm);
|
|
}
|
|
modifier_deformVerts_DM_deprecated(md, ctx, dm, vertexCos, numVerts);
|
|
}
|
|
|
|
void modwrap_deformVertsEM(
|
|
ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *em, DerivedMesh *dm,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
|
|
|
|
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
DM_ensure_normals(dm);
|
|
}
|
|
modifier_deformVertsEM_DM_deprecated(md, ctx, em, dm, vertexCos, numVerts);
|
|
}
|
|
/* end modifier callback wrappers */
|
|
|
|
|
|
/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
|
|
* depending on if the modifier has been ported to Mesh or is still using DerivedMesh
|
|
*/
|
|
|
|
void modifier_deformVerts(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct Mesh *mesh,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformVerts) {
|
|
mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = NULL;
|
|
if (mesh) {
|
|
dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
}
|
|
|
|
mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
|
|
|
|
if (dm) {
|
|
dm->release(dm);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformVerts_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct Mesh *mesh,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(!mesh || CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
|
|
|
|
if (mesh && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
BKE_mesh_calc_normals(mesh);
|
|
}
|
|
modifier_deformVerts(md, ctx, mesh, vertexCos, numVerts);
|
|
}
|
|
|
|
void modifier_deformMatrices(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct Mesh *mesh,
|
|
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformMatrices) {
|
|
mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = NULL;
|
|
if (mesh) {
|
|
dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
}
|
|
|
|
mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
|
|
|
|
if (dm) {
|
|
dm->release(dm);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformVertsEM(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData, struct Mesh *mesh,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformVertsEM) {
|
|
mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = NULL;
|
|
if (mesh) {
|
|
dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
}
|
|
|
|
mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
|
|
|
|
if (dm) {
|
|
dm->release(dm);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformMatricesEM(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData, struct Mesh *mesh,
|
|
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformMatricesEM) {
|
|
mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = NULL;
|
|
if (mesh) {
|
|
dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
}
|
|
|
|
mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
|
|
|
|
if (dm) {
|
|
dm->release(dm);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Mesh *modifier_applyModifier(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct Mesh *mesh)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->applyModifier) {
|
|
return mti->applyModifier(md, ctx, mesh);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
|
|
DerivedMesh *ndm = mti->applyModifier_DM(md, ctx, dm);
|
|
|
|
if (ndm != dm) {
|
|
dm->release(dm);
|
|
}
|
|
|
|
DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
|
|
|
|
return mesh;
|
|
}
|
|
}
|
|
|
|
struct Mesh *modifier_applyModifier_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct Mesh *mesh)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
|
|
|
|
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
|
|
BKE_mesh_calc_normals(mesh);
|
|
}
|
|
return modifier_applyModifier(md, ctx, mesh);
|
|
}
|
|
|
|
struct Mesh *modifier_applyModifierEM(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData,
|
|
struct Mesh *mesh)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->applyModifierEM) {
|
|
return mti->applyModifierEM(md, ctx, editData, mesh);
|
|
}
|
|
else {
|
|
DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
|
|
|
|
DerivedMesh *ndm = mti->applyModifierEM_DM(md, ctx, editData, dm);
|
|
|
|
if (ndm != dm) {
|
|
dm->release(dm);
|
|
}
|
|
|
|
DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
|
|
|
|
return mesh;
|
|
}
|
|
}
|
|
|
|
/* depricated variants of above that accept DerivedMesh */
|
|
|
|
void modifier_deformVerts_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct DerivedMesh *dm,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformVerts_DM) {
|
|
mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
|
|
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformMatrices_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct DerivedMesh *dm,
|
|
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
|
|
{
|
|
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformMatrices_DM) {
|
|
mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
|
|
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformVertsEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData, struct DerivedMesh *dm,
|
|
float (*vertexCos)[3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformVertsEM_DM) {
|
|
mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
|
|
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
void modifier_deformMatricesEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData, struct DerivedMesh *dm,
|
|
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->deformMatricesEM_DM) {
|
|
mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
|
|
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct DerivedMesh *modifier_applyModifier_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct DerivedMesh *dm)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->applyModifier_DM) {
|
|
return mti->applyModifier_DM(md, ctx, dm);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh);
|
|
|
|
/* Make a DM that doesn't reference new_mesh so we can free the latter. */
|
|
DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
|
|
|
|
if (new_mesh != mesh) {
|
|
BKE_id_free(NULL, new_mesh);
|
|
}
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
|
|
return ndm;
|
|
}
|
|
}
|
|
|
|
struct DerivedMesh *modifier_applyModifierEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
|
|
struct BMEditMesh *editData,
|
|
struct DerivedMesh *dm)
|
|
{
|
|
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
|
|
|
if (mti->applyModifierEM_DM) {
|
|
return mti->applyModifierEM_DM(md, ctx, editData, dm);
|
|
}
|
|
else {
|
|
/* TODO(sybren): deduplicate all the copies of this code in this file. */
|
|
Mesh *mesh = NULL;
|
|
if (dm != NULL) {
|
|
mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
|
|
}
|
|
|
|
struct Mesh *new_mesh = mti->applyModifierEM(md, ctx, editData, mesh);
|
|
|
|
/* Make a DM that doesn't reference new_mesh so we can free the latter. */
|
|
DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
|
|
|
|
if (new_mesh != mesh) {
|
|
BKE_id_free(NULL, new_mesh);
|
|
}
|
|
if (mesh != NULL) {
|
|
BKE_id_free(NULL, mesh);
|
|
}
|
|
|
|
return ndm;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
|
|
* e.g. second operand for boolean modifier.
|
|
* Note thqt modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler.
|
|
*/
|
|
Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh)
|
|
{
|
|
Mesh *me;
|
|
|
|
if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
|
|
/* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh...
|
|
* This is TODO in core depsgraph/modifier stack code still. */
|
|
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
|
|
me = BKE_bmesh_to_mesh_nomain(em->bm, &(struct BMeshToMeshParams){0});
|
|
*r_free_mesh = true;
|
|
}
|
|
else {
|
|
me = ob_eval->runtime.mesh_eval;
|
|
*r_free_mesh = false;
|
|
}
|
|
|
|
return me;
|
|
}
|