diff options
-rw-r--r-- | source/blender/blenkernel/intern/modifier.c | 366 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_modifier_types.h | 19 | ||||
-rw-r--r-- | source/blender/src/buttons_editing.c | 27 | ||||
-rw-r--r-- | source/blender/src/drawaction.c | 4 | ||||
-rw-r--r-- | source/blender/src/editobject.c | 4 |
5 files changed, 416 insertions, 4 deletions
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 56b4aa574c7..be18c0a873a 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -54,6 +54,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_camera_types.h" #include "DNA_cloth_types.h" @@ -587,6 +588,361 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, return result; } +/* Mask */ + +static void maskModifier_copyData(ModifierData *md, ModifierData *target) +{ + MaskModifierData *mmd = (MaskModifierData*) md; + MaskModifierData *tmmd = (MaskModifierData*) target; + + strcpy(tmmd->vgroup, mmd->vgroup); +} + +static CustomDataMask maskModifier_requiredDataMask(ModifierData *md) +{ + return (1 << CD_MDEFORMVERT); +} + +static void maskModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + walk(userData, ob, &mmd->ob_arm); +} + +static void maskModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + MaskModifierData *mmd = (MaskModifierData *)md; + + if (mmd->ob_arm) + { + DagNode *armNode = dag_get_node(forest, mmd->ob_arm); + + dag_add_relation(forest, armNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mask Modifier"); + } +} + +static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + MaskModifierData *mmd= (MaskModifierData *)md; + DerivedMesh *dm= derivedData, *result= NULL; + GHash *vertHash=NULL, *edgeHash, *faceHash; + GHashIterator *hashIter; + MDeformVert *dvert= NULL; + int numFaces=0, numEdges=0, numVerts=0; + int maxVerts, maxEdges, maxFaces; + int i; + + /* Overview of Method: + * 1. Get the vertices that are in the vertexgroup of interest + * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices + * 3. Make a new mesh containing only the mapping data + */ + + /* get original number of verts, edges, and faces */ + maxVerts= dm->getNumVerts(dm); + maxEdges= dm->getNumEdges(dm); + maxFaces= dm->getNumFaces(dm); + + /* check if we can just return the original mesh + * - must have verts and therefore verts assigned to vgroups to do anything useful + */ + if ( !(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || + (maxVerts == 0) || (ob->defbase.first == NULL) ) + { + return derivedData; + } + + /* if mode is to use selected armature bones, aggregate the bone groups */ + if (mmd->mode == MOD_MASK_MODE_ARM) /* --- using selected bones --- */ + { + GHash *vgroupHash, *boneHash; + Object *oba= mmd->ob_arm; + bPoseChannel *pchan; + bDeformGroup *def; + + /* check that there is armature object with bones to use, otherwise return original mesh */ + if (ELEM(NULL, mmd->ob_arm, mmd->ob_arm->pose)) + return derivedData; + + /* hashes for finding mapping of: + * - vgroups to indicies -> vgroupHash (string, int) + * - bones to vgroup indices -> boneHash (index of vgroup, dummy) + */ + vgroupHash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp); + boneHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + /* build mapping of names of vertex groups to indices */ + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) + BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i)); + + /* get selected-posechannel <-> vertexgroup index mapping */ + for (pchan= oba->pose->chanbase.first; pchan; pchan= pchan->next) + { + /* check if bone is selected */ + // TODO: include checks for visibility too? + // FIXME: the depsgraph needs extensions to make this work in realtime... + if ( (pchan->bone) && (pchan->bone->flag & BONE_SELECTED) ) + { + /* check if hash has group for this bone */ + if (BLI_ghash_haskey(vgroupHash, pchan->name)) + { + int defgrp_index= GET_INT_FROM_POINTER(BLI_ghash_lookup(vgroupHash, pchan->name)); + + /* add index to hash (store under key only) */ + BLI_ghash_insert(boneHash, SET_INT_IN_POINTER(defgrp_index), pchan); + } + } + } + + /* if no bones selected, free hashes and return original mesh */ + if (BLI_ghash_size(boneHash) == 0) + { + BLI_ghash_free(vgroupHash, NULL, NULL); + BLI_ghash_free(boneHash, NULL, NULL); + + return derivedData; + } + + /* repeat the previous check, but for dverts */ + dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT); + if (dvert == NULL) + { + BLI_ghash_free(vgroupHash, NULL, NULL); + BLI_ghash_free(boneHash, NULL, NULL); + + return derivedData; + } + + /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ + vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + /* add vertices which exist in vertexgroups into vertHash for filtering */ + for (i = 0; i < maxVerts; i++) + { + MDeformWeight *def_weight = NULL; + int j; + + for (j= 0; j < dvert[i].totweight; j++) + { + if (BLI_ghash_haskey(boneHash, SET_INT_IN_POINTER(dvert[i].dw[j].def_nr))) + { + def_weight = &dvert[i].dw[j]; + break; + } + } + + /* check if include vert in vertHash */ + if (mmd->flag & MOD_MASK_INV) { + /* if this vert is in the vgroup, don't include it in vertHash */ + if (def_weight) continue; + } + else { + /* if this vert isn't in the vgroup, don't include it in vertHash */ + if (!def_weight) continue; + } + + /* add to ghash for verts (numVerts acts as counter for mapping) */ + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); + numVerts++; + } + + /* free temp hashes */ + BLI_ghash_free(vgroupHash, NULL, NULL); + BLI_ghash_free(boneHash, NULL, NULL); + } + else /* --- Using Nominated VertexGroup only --- */ + { + int defgrp_index = -1; + + /* get index of vertex group */ + if (mmd->vgroup[0]) + { + bDeformGroup *def; + + /* find index by comparing names - SLOW... */ + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) + { + if (!strcmp(def->name, mmd->vgroup)) + { + defgrp_index = i; + break; + } + } + } + + /* get dverts */ + if (defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + /* if no vgroup (i.e. dverts) found, return the initial mesh */ + if ((defgrp_index < 0) || (dvert == NULL)) + return dm; + + /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ + vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + /* add vertices which exist in vertexgroup into ghash for filtering */ + for (i = 0; i < maxVerts; i++) + { + MDeformWeight *def_weight = NULL; + int j; + + for (j= 0; j < dvert[i].totweight; j++) + { + if (dvert[i].dw[j].def_nr == defgrp_index) + { + def_weight = &dvert[i].dw[j]; + break; + } + } + + /* check if include vert in vertHash */ + if (mmd->flag & MOD_MASK_INV) { + /* if this vert is in the vgroup, don't include it in vertHash */ + if (def_weight) continue; + } + else { + /* if this vert isn't in the vgroup, don't include it in vertHash */ + if (!def_weight) continue; + } + + /* add to ghash for verts (numVerts acts as counter for mapping) */ + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); + numVerts++; + } + } + + /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ + edgeHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + /* loop over edges and faces, and do the same thing to + * ensure that they only reference existing verts + */ + for (i = 0; i < maxEdges; i++) + { + MEdge me; + dm->getEdge(dm, i, &me); + + /* only add if both verts will be in new mesh */ + if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && + BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)) ) + { + BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); + numEdges++; + } + } + for (i = 0; i < maxFaces; i++) + { + MFace mf; + dm->getFace(dm, i, &mf); + + /* all verts must be available */ + if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) && + BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) && + BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) && + (mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) ) + { + BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces)); + numFaces++; + } + } + + + /* now we know the number of verts, edges and faces, + * we can create the new (reduced) mesh + */ + result = CDDM_from_template(dm, numVerts, numEdges, numFaces); + + + /* using ghash-iterators, map data into new mesh */ + /* vertices */ + for ( hashIter = BLI_ghashIterator_new(vertHash); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter) ) + { + MVert source; + MVert *dest; + int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); + int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); + + dm->getVert(dm, oldIndex, &source); + dest = CDDM_get_vert(result, newIndex); + + DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + } + BLI_ghashIterator_free(hashIter); + + /* edges */ + for ( hashIter = BLI_ghashIterator_new(edgeHash); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter) ) + { + MEdge source; + MEdge *dest; + int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); + int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); + + dm->getEdge(dm, oldIndex, &source); + dest = CDDM_get_edge(result, newIndex); + + source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); + source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); + + DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + } + BLI_ghashIterator_free(hashIter); + + /* faces */ + for ( hashIter = BLI_ghashIterator_new(faceHash); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter) ) + { + MFace source; + MFace *dest; + int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); + int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); + int orig_v4; + + dm->getFace(dm, oldIndex, &source); + dest = CDDM_get_face(result, newIndex); + + orig_v4 = source.v4; + + source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); + source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); + source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3))); + if (source.v4) + source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); + + DM_copy_face_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + + test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3)); + } + BLI_ghashIterator_free(hashIter); + + /* recalculate normals */ + CDDM_calc_normals(result); + + /* free hashes */ + BLI_ghash_free(vertHash, NULL, NULL); + BLI_ghash_free(edgeHash, NULL, NULL); + BLI_ghash_free(faceHash, NULL, NULL); + + /* return the new mesh */ + return result; +} + /* Array */ /* Array modifier: duplicates the object multiple times along an axis */ @@ -7519,6 +7875,15 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->copyData = buildModifier_copyData; mti->dependsOnTime = buildModifier_dependsOnTime; mti->applyModifier = buildModifier_applyModifier; + + mti = INIT_TYPE(Mask); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->copyData = maskModifier_copyData; + mti->requiredDataMask= maskModifier_requiredDataMask; + mti->foreachObjectLink = maskModifier_foreachObjectLink; + mti->updateDepgraph = maskModifier_updateDepgraph; + mti->applyModifier = maskModifier_applyModifier; mti = INIT_TYPE(Array); mti->type = eModifierTypeType_Constructive; @@ -8211,3 +8576,4 @@ void modifier_freeTemporaryData(ModifierData *md) } + diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 114dfe10bae..3e8f8702003 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -37,6 +37,7 @@ typedef enum ModifierType { eModifierType_Bevel, eModifierType_Shrinkwrap, eModifierType_Fluidsim, + eModifierType_Mask, NUM_MODIFIER_TYPES } ModifierType; @@ -105,6 +106,24 @@ typedef struct BuildModifierData { int randomize, seed; } BuildModifierData; +/* Mask Modifier */ +typedef struct MaskModifierData { + ModifierData modifier; + + struct Object *ob_arm; /* armature to use to in place of hardcoded vgroup */ + char vgroup[32]; /* name of vertex group to use to mask */ + + int mode; /* using armature or hardcoded vgroup */ + int flag; /* flags for various things */ +} MaskModifierData; + +/* Mask Modifier -> mode */ +#define MOD_MASK_MODE_VGROUP 0 +#define MOD_MASK_MODE_ARM 1 + +/* Mask Modifier -> flag */ +#define MOD_MASK_INV (1<<0) + typedef struct ArrayModifierData { ModifierData modifier; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index cb2feebfe89..44e0008576a 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1850,6 +1850,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco } else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) height += 19; + } else if (md->type == eModifierType_Mask) { + height = 66; } /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */ uiDefBut(block, ROUNDBOX, 0, "", x-10, y-height-2, width, height-2, NULL, 5.0, 0.0, 12, 40, ""); @@ -2128,6 +2130,30 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefButF(block, NUM, B_MODIFIER_RECALC, "Ratio:", lx,(cy-=19),buttonWidth,19, &dmd->percent, 0.0, 1.0, 10, 0, "Defines the percentage of triangles to reduce to"); sprintf(str, "Face Count: %d", dmd->faceCount); uiDefBut(block, LABEL, 1, str, lx, (cy-=19), 160,19, NULL, 0.0, 0.0, 0, 0, "Displays the current number of faces in the decimated mesh"); + } else if (md->type==eModifierType_Mask) { + MaskModifierData *mmd = (MaskModifierData *)md; + + sprintf(str, "Mask Mode%%t|Vertex Group%%x%d|Selected Bones%%x%d|", + MOD_MASK_MODE_VGROUP,MOD_MASK_MODE_ARM); + uiDefButI(block, MENU, B_MODIFIER_RECALC, str, + lx, (cy -= 19), buttonWidth, 19, &mmd->mode, + 0.0, 1.0, 0, 0, "How masking region is defined"); + + if (mmd->mode == MOD_MASK_MODE_ARM) { + uiDefIDPoinBut(block, modifier_testArmatureObj, ID_OB, B_CHANGEDEP, + "Ob: ", lx, (cy -= 19), buttonWidth, 19, &mmd->ob_arm, + "Armature to use as source of bones to mask"); + } + else { + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", + lx, (cy-=19), buttonWidth, 19, &mmd->vgroup, + 0.0, 31.0, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); + } + + uiDefButBitI(block, TOG, MOD_MASK_INV, B_MODIFIER_RECALC, "Inverse", + lx, (cy-=19), buttonWidth, 19, &mmd->flag, + 0, 0, 0, 0, "Use vertices that are not part of region defined"); } else if (md->type==eModifierType_Smooth) { SmoothModifierData *smd = (SmoothModifierData*) md; @@ -2266,6 +2292,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefBut(block, LABEL, 1, "See Soft Body panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); } else if (md->type==eModifierType_Cloth) { uiDefBut(block, LABEL, 1, "See Cloth panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); + } else if (md->type==eModifierType_Collision) { uiDefBut(block, LABEL, 1, "See Collision panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); } else if (md->type==eModifierType_Fluidsim) { diff --git a/source/blender/src/drawaction.c b/source/blender/src/drawaction.c index dfbe17179a4..64e85bfcd4e 100644 --- a/source/blender/src/drawaction.c +++ b/source/blender/src/drawaction.c @@ -1459,6 +1459,10 @@ static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index * Note: we can't search from end to try to optimise this as it causes errors there's * an A ___ B |---| B situation */ + // FIXME: here there is a bug where we are trying to get the summary for the following channels + // A|--------------|A ______________ B|--------------|B + // A|------------------------------------------------|A + // A|----|A|---|A|-----------------------------------|A for (ab= blocks->first; ab; ab= ab->next) { /* check if alter existing block or add new block */ if (ab->start == prev->vec[1][0]) { diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index a52882e6003..6c830c7febf 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -3624,10 +3624,6 @@ void copy_attr(short event) } } else if(event==22) { - /* Clear the constraints on the target */ - free_constraints(&base->object->constraints); - free_constraint_channels(&base->object->constraintChannels); - /* Copy the constraint channels over */ copy_constraints(&base->object->constraints, &ob->constraints); if (U.dupflag& USER_DUP_IPO) |