From 125c77bca330830c5fe6dd32cc3b5d3f4c716bbb Mon Sep 17 00:00:00 2001 From: Ben Batt Date: Sun, 29 Apr 2007 18:13:55 +0000 Subject: Patch #6113 - Cast & Smooth modifiers This patch adds two modifiers: Cast and Smooth. The Cast modifier deforms vertices into a sphere, cylinder or cuboid shape. The location and orientation of the projection shape can be controlled by a specified control object. The Smooth modifier smooths the mesh in a similar way to the Edit mode "Smooth" button. Thanks to Willian Padovani Germano (ianwill) for the patch! --- source/blender/blenkernel/intern/modifier.c | 825 ++++++++++++++++++++++++++ source/blender/makesdna/DNA_modifier_types.h | 38 ++ source/blender/python/api2_2x/Modifier.c | 182 +++++- source/blender/python/api2_2x/doc/Modifier.py | 27 +- source/blender/src/buttons_editing.c | 36 ++ 5 files changed, 1101 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2d7113f7cc0..543c1362023 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -3318,6 +3318,809 @@ exit: return result; } +/* Smooth */ + +static void smoothModifier_initData(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + + smd->fac = 0.5f; + smd->repeat = 1; + smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z; + smd->defgrp_name[0] = '\0'; +} + +static void smoothModifier_copyData(ModifierData *md, ModifierData *target) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + SmoothModifierData *tsmd = (SmoothModifierData*) target; + + tsmd->fac = smd->fac; + tsmd->repeat = smd->repeat; + tsmd->flag = smd->flag; + strncpy(tsmd->defgrp_name, smd->defgrp_name, 32); +} + +int smoothModifier_isDisabled(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData*) md; + short flag; + + flag = smd->flag & (MOD_SMOOTH_X|MOD_SMOOTH_Y|MOD_SMOOTH_Z); + + /* disable if modifier is off for X, Y and Z or if factor is 0 */ + if((smd->fac == 0.0f) || flag == 0) return 1; + + return 0; +} + +CustomDataMask smoothModifier_requiredDataMask(ModifierData *md) +{ + SmoothModifierData *smd = (SmoothModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(smd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void smoothModifier_do( + SmoothModifierData *smd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + MEdge *medges = NULL; + + int i, j, numDMEdges, defgrp_index; + unsigned char *uctmp; + float *ftmp, fac, facm; + + ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts, + "smoothmodifier_f"); + if (!ftmp) return; + uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts, + "smoothmodifier_uc"); + if (!uctmp) { + if (ftmp) MEM_freeN(ftmp); + return; + } + + fac = smd->fac; + facm = 1 - fac; + + medges = CDDM_get_edges(dm); + numDMEdges = dm->getNumEdges(dm); + + defgrp_index = -1; + + if (smd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, smd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if (defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + /* NOTICE: this can be optimized a little bit by moving the + * if (dvert) out of the loop, if needed */ + for (j = 0; j < smd->repeat; j++) { + for (i = 0; i < numDMEdges; i++) { + float fvec[3]; + float *v1, *v2; + unsigned int idx1, idx2; + + idx1 = medges[i].v1; + idx2 = medges[i].v2; + + v1 = vertexCos[idx1]; + v2 = vertexCos[idx2]; + + fvec[0] = (v1[0] + v2[0]) / 2.0; + fvec[1] = (v1[1] + v2[1]) / 2.0; + fvec[2] = (v1[2] + v2[2]) / 2.0; + + v1 = &ftmp[idx1*3]; + v2 = &ftmp[idx2*3]; + + if (uctmp[idx1] < 255) { + uctmp[idx1]++; + VecAddf(v1, v1, fvec); + } + if (uctmp[idx2] < 255) { + uctmp[idx2]++; + VecAddf(v2, v2, fvec); + } + } + + if (dvert) { + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + float f, fm, facw, *fp, *v; + int k; + short flag = smd->flag; + + v = vertexCos[i]; + fp = &ftmp[i*3]; + + for (k = 0; k < dvert[i].totweight; ++k) { + if(dvert[i].dw[k].def_nr == defgrp_index) { + dw = &dvert[i].dw[k]; + break; + } + } + if (!dw) continue; + + f = fac * dw->weight; + fm = 1.0f - f; + + /* fp is the sum of uctmp[i] verts, so must be averaged */ + facw = 0.0f; + if (uctmp[i]) + facw = f / (float)uctmp[i]; + + if (flag & MOD_SMOOTH_X) + v[0] = fm * v[0] + facw * fp[0]; + if (flag & MOD_SMOOTH_Y) + v[1] = fm * v[1] + facw * fp[1]; + if (flag & MOD_SMOOTH_Z) + v[2] = fm * v[2] + facw * fp[2]; + } + } + else { /* no vertex group */ + for (i = 0; i < numVerts; i++) { + float facw, *fp, *v; + short flag = smd->flag; + + v = vertexCos[i]; + fp = &ftmp[i*3]; + + /* fp is the sum of uctmp[i] verts, so must be averaged */ + facw = 0.0f; + if (uctmp[i]) + facw = fac / (float)uctmp[i]; + + if (flag & MOD_SMOOTH_X) + v[0] = facm * v[0] + facw * fp[0]; + if (flag & MOD_SMOOTH_Y) + v[1] = facm * v[1] + facw * fp[1]; + if (flag & MOD_SMOOTH_Z) + v[2] = facm * v[2] + facw * fp[2]; + } + + } + + memset(ftmp, 0, 3*sizeof(float)*numVerts); + memset(uctmp, 0, sizeof(unsigned char)*numVerts); + } + + MEM_freeN(ftmp); + MEM_freeN(uctmp); +} + +static void smoothModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_mesh(ob->data, ob); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smoothModifier_do((SmoothModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +static void smoothModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_editmesh(editData, ob->data); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smoothModifier_do((SmoothModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +/* Cast */ + +static void castModifier_initData(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData*) md; + + cmd->fac = 0.5f; + cmd->radius = 0.0f; + cmd->size = 0.0f; + cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z + | MOD_CAST_SIZE_FROM_RADIUS; + cmd->type = MOD_CAST_TYPE_SPHERE; + cmd->defgrp_name[0] = '\0'; + cmd->object = NULL; +} + + +static void castModifier_copyData(ModifierData *md, ModifierData *target) +{ + CastModifierData *cmd = (CastModifierData*) md; + CastModifierData *tcmd = (CastModifierData*) target; + + tcmd->fac = cmd->fac; + tcmd->radius = cmd->radius; + tcmd->size = cmd->size; + tcmd->flag = cmd->flag; + tcmd->type = cmd->type; + tcmd->object = cmd->object; + strncpy(tcmd->defgrp_name, cmd->defgrp_name, 32); +} + +int castModifier_isDisabled(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData*) md; + short flag; + + flag = cmd->flag & (MOD_CAST_X|MOD_CAST_Y|MOD_CAST_Z); + + if((cmd->fac == 0.0f) || flag == 0) return 1; + + return 0; +} + +CustomDataMask castModifier_requiredDataMask(ModifierData *md) +{ + CastModifierData *cmd = (CastModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(cmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void castModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + CastModifierData *cmd = (CastModifierData*) md; + + walk (userData, ob, &cmd->object); +} + +static void castModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + CastModifierData *cmd = (CastModifierData*) md; + + if (cmd->object) { + DagNode *curNode = dag_get_node(forest, cmd->object); + + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + } +} + +static void castModifier_sphere_do( + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + + Object *ctrl_ob = NULL; + + int i, defgrp_index = -1; + int has_radius = 0; + short flag, type; + float fac, facm, len = 0.0f; + float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + fac = cmd->fac; + facm = 1.0f - fac; + + flag = cmd->flag; + + type = cmd->type; /* projection type: sphere or cylinder */ + + ctrl_ob = cmd->object; + + /* spherify's center is {0, 0, 0} (the ob's own center in its local + * space), by default, but if the user defined a control object, + * we use its location, transformed to ob's local space */ + if (ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat); + Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat); + Mat4Invert(imat, mat); + } + + Mat4Invert(ob->imat, ob->obmat); + VECCOPY(center, ctrl_ob->obmat[3]); + Mat4MulVecfl(ob->imat, center); + } + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + if (cmd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, cmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if ((ob->type == OB_MESH) && dm && defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + if(cmd->flag & MOD_CAST_SIZE_FROM_RADIUS) { + len = cmd->radius; + } + else { + len = cmd->size; + } + + if(len <= 0) { + for (i = 0; i < numVerts; i++) { + len += VecLenf(center, vertexCos[i]); + } + len /= numVerts; + + if (len == 0.0f) len = 10.0f; + } + + /* ready to apply the effect, one vertex at a time; + * tiny optimization: the code is separated (with parts repeated) + * in two possible cases: + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ + if (dvert) { /* with a vgroup */ + float fac_orig = fac; + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + int j; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vec, tmp_co); + + if (type == MOD_CAST_TYPE_CYLINDER) + vec[2] = 0.0f; + + if (has_radius) { + if (VecLength(vec) > cmd->radius) continue; + } + + for (j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + dw = &dvert[i].dw[j]; + break; + } + } + if (!dw) continue; + + fac = fac_orig * dw->weight; + facm = 1.0f - fac; + + Normalize(vec); + + if (flag & MOD_CAST_X) + tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; + if (flag & MOD_CAST_Y) + tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; + if (flag & MOD_CAST_Z && type != MOD_CAST_TYPE_CYLINDER) + tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } + return; + } + + /* no vgroup */ + for (i = 0; i < numVerts; i++) { + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vec, tmp_co); + + if (type == MOD_CAST_TYPE_CYLINDER) + vec[2] = 0.0f; + + if (has_radius) { + if (VecLength(vec) > cmd->radius) continue; + } + + Normalize(vec); + + if (flag & MOD_CAST_X) + tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; + if (flag & MOD_CAST_Y) + tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; + if (flag & MOD_CAST_Z && type != MOD_CAST_TYPE_CYLINDER) + tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } +} + +static void castModifier_cuboid_do( + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) +{ + MDeformVert *dvert = NULL; + Object *ctrl_ob = NULL; + + int i, defgrp_index = -1; + int has_radius = 0; + short flag, type; + float fac, facm; + float min[3], max[3], bb[8][3]; + float center[3] = {0.0f, 0.0f, 0.0f}; + float mat[4][4], imat[4][4]; + + fac = cmd->fac; + facm = 1.0f - fac; + + flag = cmd->flag; + + type = cmd->type; /* projection type: sphere or cylinder */ + + ctrl_ob = cmd->object; + + /* now we check which options the user wants */ + + /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ + /* 2) cmd->radius > 0.0f: only the vertices within this radius from + * the center of the effect should be deformed */ + if (cmd->radius > FLT_EPSILON) has_radius = 1; + + /* 3) if we were given a vertex group name, + * only those vertices should be affected */ + if (cmd->defgrp_name[0]) { + bDeformGroup *def; + + for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if (!strcmp(def->name, cmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + if ((ob->type == OB_MESH) && dm && defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + if (ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat); + Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat); + Mat4Invert(imat, mat); + } + + Mat4Invert(ob->imat, ob->obmat); + VECCOPY(center, ctrl_ob->obmat[3]); + Mat4MulVecfl(ob->imat, center); + } + + if((cmd->flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { + for(i = 0; i < 3; i++) { + min[i] = -cmd->radius; + max[i] = cmd->radius; + } + } else if(!(cmd->flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { + for(i = 0; i < 3; i++) { + min[i] = -cmd->size; + max[i] = cmd->size; + } + } else { + /* get bound box */ + /* We can't use the object's bound box because other modifiers + * may have changed the vertex data. */ + INIT_MINMAX(min, max); + + /* Cast's center is the ob's own center in its local space,by default, + * but if the user defined a control object, we use its location, + * transformed to ob's local space. */ + if (ctrl_ob) { + float vec[3]; + + /* let the center of the ctrl_ob be part of the bound box: */ + DO_MINMAX(center, min, max); + + for (i = 0; i < numVerts; i++) { + VecSubf(vec, vertexCos[i], center); + DO_MINMAX(vec, min, max); + } + } + else { + for (i = 0; i < numVerts; i++) { + DO_MINMAX(vertexCos[i], min, max); + } + } + + /* we want a symmetric bound box around the origin */ + if (fabs(min[0]) > fabs(max[0])) max[0] = fabs(min[0]); + if (fabs(min[1]) > fabs(max[1])) max[1] = fabs(min[1]); + if (fabs(min[2]) > fabs(max[2])) max[2] = fabs(min[2]); + min[0] = -max[0]; + min[1] = -max[1]; + min[2] = -max[2]; + } + + /* building our custom bounding box */ + bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; + bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; + bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; + bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; + bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; + bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; + + /* ready to apply the effect, one vertex at a time; + * tiny optimization: the code is separated (with parts repeated) + * in two possible cases: + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ + if (dvert) { /* with a vgroup */ + float fac_orig = fac; + for (i = 0; i < numVerts; i++) { + MDeformWeight *dw = NULL; + int j, octant, coord; + float d[3], dmax, apex[3], fbb; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + if (has_radius) { + if (fabs(tmp_co[0]) > cmd->radius || + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; + } + + for (j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + dw = &dvert[i].dw[j]; + break; + } + } + if (!dw) continue; + + fac = fac_orig * dw->weight; + facm = 1.0f - fac; + + /* The algo used to project the vertices to their + * bounding box (bb) is pretty simple: + * for each vertex v: + * 1) find in which octant v is in; + * 2) find which outer "wall" of that octant is closer to v; + * 3) calculate factor (var fbb) to project v to that wall; + * 4) project. */ + + /* find in which octant this vertex is in */ + octant = 0; + if (tmp_co[0] > 0.0f) octant += 1; + if (tmp_co[1] > 0.0f) octant += 2; + if (tmp_co[2] > 0.0f) octant += 4; + + /* apex is the bb's vertex at the chosen octant */ + VecCopyf(apex, bb[octant]); + + /* find which bb plane is closest to this vertex ... */ + d[0] = tmp_co[0] / apex[0]; + d[1] = tmp_co[1] / apex[1]; + d[2] = tmp_co[2] / apex[2]; + + /* ... (the closest has the higher (closer to 1) d value) */ + dmax = d[0]; + coord = 0; + if (d[1] > dmax) { + dmax = d[1]; + coord = 1; + } + if (d[2] > dmax) { + /* dmax = d[2]; */ /* commented, we don't need it */ + coord = 2; + } + + /* ok, now we know which coordinate of the vertex to use */ + + if (fabs(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ + continue; + + /* finally, this is the factor we wanted, to project the vertex + * to its bounding box (bb) */ + fbb = apex[coord] / tmp_co[coord]; + + /* calculate the new vertex position */ + if (flag & MOD_CAST_X) + tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; + if (flag & MOD_CAST_Y) + tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; + if (flag & MOD_CAST_Z) + tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } + return; + } + + /* no vgroup (check previous case for comments about the code) */ + for (i = 0; i < numVerts; i++) { + int octant, coord; + float d[3], dmax, fbb, apex[3]; + float tmp_co[3]; + + VECCOPY(tmp_co, vertexCos[i]); + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(mat, tmp_co); + } else { + VecSubf(tmp_co, tmp_co, center); + } + } + + if (has_radius) { + if (fabs(tmp_co[0]) > cmd->radius || + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; + } + + octant = 0; + if (tmp_co[0] > 0.0f) octant += 1; + if (tmp_co[1] > 0.0f) octant += 2; + if (tmp_co[2] > 0.0f) octant += 4; + + VecCopyf(apex, bb[octant]); + + d[0] = tmp_co[0] / apex[0]; + d[1] = tmp_co[1] / apex[1]; + d[2] = tmp_co[2] / apex[2]; + + dmax = d[0]; + coord = 0; + if (d[1] > dmax) { + dmax = d[1]; + coord = 1; + } + if (d[2] > dmax) { + /* dmax = d[2]; */ /* commented, we don't need it */ + coord = 2; + } + + if (fabs(tmp_co[coord]) < FLT_EPSILON) + continue; + + fbb = apex[coord] / tmp_co[coord]; + + if (flag & MOD_CAST_X) + tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; + if (flag & MOD_CAST_Y) + tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; + if (flag & MOD_CAST_Z) + tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; + + if(ctrl_ob) { + if(flag & MOD_CAST_USE_OB_TRANSFORM) { + Mat4MulVecfl(imat, tmp_co); + } else { + VecAddf(tmp_co, tmp_co, center); + } + } + + VECCOPY(vertexCos[i], tmp_co); + } +} + +static void castModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + CastModifierData *cmd = (CastModifierData *)md; + + if (!dm && ob->type == OB_MESH) + dm = CDDM_from_mesh(ob->data, ob); + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts); + } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts); + } + + if (!derivedData && dm) dm->release(dm); +} + +static void castModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm = derivedData; + CastModifierData *cmd = (CastModifierData *)md; + + if (!dm && ob->type == OB_MESH) + dm = CDDM_from_editmesh(editData, ob->data); + + if (cmd->type == MOD_CAST_TYPE_CUBOID) { + castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts); + } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */ + castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts); + } + + if (!derivedData && dm) dm->release(dm); +} + /* Wave */ static void waveModifier_initData(ModifierData *md) @@ -4130,6 +4933,28 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->copyData = decimateModifier_copyData; mti->applyModifier = decimateModifier_applyModifier; + mti = INIT_TYPE(Smooth); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsEditmode; + mti->initData = smoothModifier_initData; + mti->copyData = smoothModifier_copyData; + mti->requiredDataMask = smoothModifier_requiredDataMask; + mti->deformVerts = smoothModifier_deformVerts; + mti->deformVertsEM = smoothModifier_deformVertsEM; + + mti = INIT_TYPE(Cast); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = castModifier_initData; + mti->copyData = castModifier_copyData; + mti->requiredDataMask = castModifier_requiredDataMask; + mti->foreachObjectLink = castModifier_foreachObjectLink; + mti->updateDepgraph = castModifier_updateDepgraph; + mti->deformVerts = castModifier_deformVerts; + mti->deformVertsEM = castModifier_deformVertsEM; + mti = INIT_TYPE(Wave); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index c5c37406c46..52ba7455284 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -26,6 +26,8 @@ typedef enum ModifierType { eModifierType_EdgeSplit, eModifierType_Displace, eModifierType_UVProject, + eModifierType_Smooth, + eModifierType_Cast, NUM_MODIFIER_TYPES } ModifierType; @@ -233,6 +235,42 @@ typedef struct DecimateModifierData { int faceCount; } DecimateModifierData; +/* Smooth modifier flags */ +#define MOD_SMOOTH_X 1<<1 +#define MOD_SMOOTH_Y 1<<2 +#define MOD_SMOOTH_Z 1<<3 + +typedef struct SmoothModifierData { + ModifierData modifier; + float fac; + char defgrp_name[32]; + short flag, repeat; + +} SmoothModifierData; + +/* Cast modifier flags */ +#define MOD_CAST_X 1<<1 +#define MOD_CAST_Y 1<<2 +#define MOD_CAST_Z 1<<3 +#define MOD_CAST_USE_OB_TRANSFORM 1<<4 +#define MOD_CAST_SIZE_FROM_RADIUS 1<<5 + +/* Cast modifier projection types */ +#define MOD_CAST_TYPE_SPHERE 0 +#define MOD_CAST_TYPE_CYLINDER 1 +#define MOD_CAST_TYPE_CUBOID 2 + +typedef struct CastModifierData { + ModifierData modifier; + + struct Object *object; + float fac; + float radius; + float size; + char defgrp_name[32]; + short flag, type; +} CastModifierData; + enum { MOD_WAV_MAP_LOCAL, MOD_WAV_MAP_GLOBAL, diff --git a/source/blender/python/api2_2x/Modifier.c b/source/blender/python/api2_2x/Modifier.c index 06c813e7820..694a0dbfbfe 100644 --- a/source/blender/python/api2_2x/Modifier.c +++ b/source/blender/python/api2_2x/Modifier.c @@ -67,14 +67,18 @@ enum mod_constants { /*GENERIC*/ EXPP_MOD_OBJECT, /*ARMATURE, LATTICE, CURVE, BOOLEAN, ARRAY*/ - EXPP_MOD_VERTGROUP, /*ARMATURE, LATTICE, CURVE*/ + EXPP_MOD_VERTGROUP, /*ARMATURE, LATTICE, CURVE, SMOOTH, CAST*/ EXPP_MOD_LIMIT, /*ARRAY, MIRROR*/ EXPP_MOD_FLAG, /*MIRROR, WAVE*/ EXPP_MOD_COUNT, /*DECIMATOR, ARRAY*/ EXPP_MOD_LENGTH, /*BUILD, ARRAY*/ + EXPP_MOD_FACTOR, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_X, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_Y, /*SMOOTH, CAST*/ + EXPP_MOD_ENABLE_Z, /*SMOOTH, CAST*/ + EXPP_MOD_TYPES, /*SUBSURF, CAST*/ /*SUBSURF SPESIFIC*/ - EXPP_MOD_TYPES, EXPP_MOD_LEVELS, EXPP_MOD_RENDLEVELS, EXPP_MOD_OPTIMAL, @@ -126,7 +130,16 @@ enum mod_constants { EXPP_MOD_STRENGTH, EXPP_MOD_TEXTURE, EXPP_MOD_MAPPING, - EXPP_MOD_DIRECTION + EXPP_MOD_DIRECTION, + + /* SMOOTH */ + EXPP_MOD_REPEAT, + + /* CAST */ + EXPP_MOD_RADIUS, + EXPP_MOD_SIZE, + EXPP_MOD_USE_OB_TRANSFORM, + EXPP_MOD_SIZE_FROM_RADIUS /* yet to be implemented */ /* EXPP_MOD_HOOK_,*/ @@ -548,6 +561,133 @@ static int decimate_setter( BPy_Modifier *self, int type, PyObject *value ) return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); } +static PyObject *smooth_getter( BPy_Modifier * self, int type ) +{ + SmoothModifierData *md = (SmoothModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_FACTOR: + return PyFloat_FromDouble( (double)md->fac ); + case EXPP_MOD_REPEAT: + return PyInt_FromLong( (long)md->repeat ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->defgrp_name ) ; + case EXPP_MOD_ENABLE_X: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Z, 'h' ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int smooth_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + SmoothModifierData *md = (SmoothModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_FACTOR: + return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 ); + case EXPP_MOD_REPEAT: + return EXPP_setIValueRange( value, &md->repeat, 0, 30, 'h' ); + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) ); + return 0; + } + case EXPP_MOD_ENABLE_X: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Z, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + +static PyObject *cast_getter( BPy_Modifier * self, int type ) +{ + CastModifierData *md = (CastModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return PyInt_FromLong( (long)md->type ); + case EXPP_MOD_FACTOR: + return PyFloat_FromDouble( (double)md->fac ); + case EXPP_MOD_RADIUS: + return PyFloat_FromDouble( (double)md->radius ); + case EXPP_MOD_SIZE: + return PyFloat_FromDouble( (double)md->size ); + case EXPP_MOD_OBJECT: + return Object_CreatePyObject( md->object ); + case EXPP_MOD_VERTGROUP: + return PyString_FromString( md->defgrp_name ) ; + case EXPP_MOD_ENABLE_X: + return EXPP_getBitfield( &md->flag, MOD_CAST_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_getBitfield( &md->flag, MOD_CAST_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_getBitfield( &md->flag, MOD_CAST_Z, 'h' ); + case EXPP_MOD_USE_OB_TRANSFORM: + return EXPP_getBitfield( &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' ); + case EXPP_MOD_SIZE_FROM_RADIUS: + return EXPP_getBitfield( &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int cast_setter( BPy_Modifier *self, int type, PyObject *value ) +{ + CastModifierData *md = (CastModifierData *)(self->md); + + switch( type ) { + case EXPP_MOD_TYPES: + return EXPP_setIValueRange( value, &md->type, 0, MOD_CAST_TYPE_CUBOID, 'h' ); + case EXPP_MOD_FACTOR: + return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 ); + case EXPP_MOD_RADIUS: + return EXPP_setFloatClamped( value, &md->radius, 0.0, 100.0 ); + case EXPP_MOD_SIZE: + return EXPP_setFloatClamped( value, &md->size, 0.0, 100.0 ); + case EXPP_MOD_OBJECT: { + Object *ob_new=NULL; + if (value == Py_None) { + md->object = NULL; + } else if (BPy_Object_Check( value )) { + ob_new = ((( BPy_Object * )value)->object); + md->object = ob_new; + } else { + return EXPP_ReturnIntError( PyExc_TypeError, + "Expected an Object or None value" ); + } + return 0; + } + case EXPP_MOD_VERTGROUP: { + char *name = PyString_AsString( value ); + if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); + BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) ); + return 0; + } + case EXPP_MOD_ENABLE_X: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_X, 'h' ); + case EXPP_MOD_ENABLE_Y: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_Y, 'h' ); + case EXPP_MOD_ENABLE_Z: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_Z, 'h' ); + case EXPP_MOD_USE_OB_TRANSFORM: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' ); + case EXPP_MOD_SIZE_FROM_RADIUS: + return EXPP_setBitfield( value, &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + static PyObject *wave_getter( BPy_Modifier * self, int type ) { WaveModifierData *md = (WaveModifierData *)(self->md); @@ -866,6 +1006,10 @@ static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key ) return mirror_getter( self, setting ); case eModifierType_Decimate: return decimate_getter( self, setting ); + case eModifierType_Smooth: + return smooth_getter( self, setting ); + case eModifierType_Cast: + return cast_getter( self, setting ); case eModifierType_Wave: return wave_getter( self, setting ); case eModifierType_Boolean: @@ -934,6 +1078,10 @@ static int Modifier_setData( BPy_Modifier * self, PyObject * key, return array_setter( self, key_int, arg ); case eModifierType_Decimate: return decimate_setter( self, key_int, arg ); + case eModifierType_Smooth: + return smooth_setter( self, key_int, arg ); + case eModifierType_Cast: + return cast_setter( self, key_int, arg ); case eModifierType_Wave: return wave_setter( self, key_int, arg ); case eModifierType_Boolean: @@ -1347,6 +1495,10 @@ static PyObject *M_Modifier_TypeDict( void ) PyInt_FromLong( eModifierType_Array ) ); PyConstant_Insert( d, "EDGESPLIT", PyInt_FromLong( eModifierType_EdgeSplit ) ); + PyConstant_Insert( d, "SMOOTH", + PyInt_FromLong( eModifierType_Smooth ) ); + PyConstant_Insert( d, "CAST", + PyInt_FromLong( eModifierType_Cast ) ); } return S; } @@ -1407,6 +1559,14 @@ for var in st.replace(',','').split('\n'): PyInt_FromLong( EXPP_MOD_COUNT ) ); PyConstant_Insert( d, "LENGTH", PyInt_FromLong( EXPP_MOD_LENGTH ) ); + PyConstant_Insert( d, "FACTOR", + PyInt_FromLong( EXPP_MOD_FACTOR ) ); + PyConstant_Insert( d, "ENABLE_X", + PyInt_FromLong( EXPP_MOD_ENABLE_X ) ); + PyConstant_Insert( d, "ENABLE_Y", + PyInt_FromLong( EXPP_MOD_ENABLE_Y ) ); + PyConstant_Insert( d, "ENABLE_Z", + PyInt_FromLong( EXPP_MOD_ENABLE_Z ) ); PyConstant_Insert( d, "TYPES", PyInt_FromLong( EXPP_MOD_TYPES ) ); PyConstant_Insert( d, "LEVELS", @@ -1471,6 +1631,22 @@ for var in st.replace(',','').split('\n'): PyInt_FromLong( EXPP_MOD_MID_LEVEL ) ); PyConstant_Insert( d, "STRENGTH", PyInt_FromLong( EXPP_MOD_STRENGTH ) ); + PyConstant_Insert( d, "TEXTURE", + PyInt_FromLong( EXPP_MOD_TEXTURE ) ); + PyConstant_Insert( d, "MAPPING", + PyInt_FromLong( EXPP_MOD_MAPPING ) ); + PyConstant_Insert( d, "DIRECTION", + PyInt_FromLong( EXPP_MOD_DIRECTION ) ); + PyConstant_Insert( d, "REPEAT", + PyInt_FromLong( EXPP_MOD_REPEAT ) ); + PyConstant_Insert( d, "RADIUS", + PyInt_FromLong( EXPP_MOD_RADIUS ) ); + PyConstant_Insert( d, "SIZE", + PyInt_FromLong( EXPP_MOD_SIZE ) ); + PyConstant_Insert( d, "USE_OB_TRANSFORM", + PyInt_FromLong( EXPP_MOD_USE_OB_TRANSFORM ) ); + PyConstant_Insert( d, "SIZE_FROM_RADIUS", + PyInt_FromLong( EXPP_MOD_SIZE_FROM_RADIUS ) ); /*End Auto generated code*/ } return S; diff --git a/source/blender/python/api2_2x/doc/Modifier.py b/source/blender/python/api2_2x/doc/Modifier.py index 6d9c9de595a..1b00fce7721 100644 --- a/source/blender/python/api2_2x/doc/Modifier.py +++ b/source/blender/python/api2_2x/doc/Modifier.py @@ -4,7 +4,7 @@ The Blender.Modifier submodule B{New}: - - provides access to Blender's modifier stack + - Supports the new Cast and Smooth modifiers. This module provides access to the Modifier Data in Blender. @@ -57,6 +57,9 @@ Example:: - SUBSURF - type value for Subsurf modifiers - WAVE - type value for Wave modifiers - EDGESPLIT - type value for Edge Split modifiers + - DISPLACE - type value for Displace modifiers + - SMOOTH - type value for Smooth modifiers + - CAST - type value for Cast modifiers @type Settings: readonly dictionary @var Settings: Constant Modifier dict used for changing modifier settings. @@ -66,13 +69,17 @@ Example:: - ONCAGE - Used for all modifiers (bool) If true, the modifier is enabled for the editing cage during edit mode. - OBJECT - Used for Armature, Lattice, Curve, Boolean and Array (Object) - - VERTGROUP - Used for Armature, Lattice and Curve (String) + - VERTGROUP - Used for Armature, Lattice, Curve, Smooth and Cast (String) - LIMIT - Array and Mirror (float [0.0 - 1.0]) - FLAG - Mirror and Wave (int) - COUNT - Decimator Polycount (readonly) and Array (int) - LENGTH - Build [1.0-300000.0] and Array [0.0 - 10000.0] (float) - - - TYPES - Used for Subsurf only. Determines the subdivision algorithm. Integer: 0 = Catmull-Clark; 1 = simple subdivision. + - FACTOR - Smooth [-10.0, 10.0] and Cast [-10.0, 10.0] (float) + - ENABLE_X = Smooth and Cast (bool, default: True) + - ENABLE_Y = Smooth and Cast (bool, default: True) + - ENABLE_Z = Smooth and Cast (bool, default: True) + - TYPES - Subsurf and Cast. For Subsurf it determines the subdivision algorithm - (int): 0 = Catmull-Clark; 1 = simple subdivision. For Cast it determines the shape to deform to = (int): 0 = Sphere; 1 = Cylinder; 2 = Cuboid + - LEVELS - Used for Subsurf only (int [0 - 6]). The number of subdivision levels used for interactive display. - RENDLEVELS - Used for Subsurf only (int [0 - 6]). The number of subdivision levels used for rendering. - OPTIMAL - Used for Subsurf only (bool). Enables Optimal Draw. @@ -109,6 +116,18 @@ Example:: - EDGESPLIT_ANGLE - Used for edge split only (float 0.0 - 180) - EDGESPLIT_FROM_ANGLE - Used for edge split only, should the modifier use the edge angle (bool) - EDGESPLIT_FROM_SHARP - Used for edge split only, should the modifier use the edge sharp flag (bool) + + - UVLAYER - Used for Displace only + - MID_LEVEL - Used for Displace only (float [0.0, 1.0], default: 0.5) + - STRENGTH - Used for Displace only (float [-1000.0, 1000.0, default: 1.0) + - TEXTURE - Used for Displace only (string) + - MAPPING - Used for Displace only + - DIRECTION - Used for Displace only + + - REPEAT - Used for Smooth only (int [0, 30], default: 1) + + - RADIUS - Used for Cast only (float [0.0, 100.0], default: 0.0) + - USE_OB_SCALE - Used for Cast only (bool, default: False) """ class ModSeq: diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index c20b52b35b8..6adcdde2be9 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1601,6 +1601,11 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 114 + ((UVProjectModifierData *)md)->num_projectors * 19; } else if (md->type==eModifierType_Decimate) { height = 48; + } else if (md->type==eModifierType_Smooth) { + height = 86; + } else if (md->type==eModifierType_Cast) { + height = 124; + height += 19; } else if (md->type==eModifierType_Wave) { WaveModifierData *wmd = (WaveModifierData *)md; height = 280; @@ -1825,6 +1830,37 @@ 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_Smooth) { + SmoothModifierData *smd = (SmoothModifierData*) md; + + uiDefButBitS(block, TOG, MOD_SMOOTH_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &smd->flag, 0, 0, 0, 0, "Enable X axis smoothing"); + uiDefButBitS(block, TOG, MOD_SMOOTH_Y, B_MODIFIER_RECALC, "Y", lx+45,cy,45,19, &smd->flag, 0, 0, 0, 0, "Enable Y axis smoothing"); + uiDefButBitS(block, TOG, MOD_SMOOTH_Z, B_MODIFIER_RECALC, "Z", lx+90,cy,45,19, &smd->flag, 0, 0, 0, 0, "Enable Z axis smoothing"); + + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Factor:", lx,(cy-=19),buttonWidth, 19, &smd->fac, -10.0, 10.0, 0.5, 0, "Define the amount of smoothing, from 0.0 to 1.0 (lower / higher values can deform the mesh)"); + uiDefButS(block, NUM, B_MODIFIER_RECALC, "Repeat:", lx,(cy-=19),buttonWidth, 19, &smd->repeat, 0.0, 30.0, 1, 0, "Number of smoothing iterations"); + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &smd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to define which vertices are affected"); + } else if (md->type==eModifierType_Cast) { + CastModifierData *cmd = (CastModifierData*) md; + + char casttypemenu[]="Projection Type%t|Sphere%x0|Cylinder%x1|Cuboid%x2"; + uiDefButS(block, MENU, B_MODIFIER_RECALC, casttypemenu, lx,(cy-=19),buttonWidth - 30,19, &cmd->type, 0, 0, 0, 0, "Projection type to apply"); + uiDefButBitS(block, TOG, MOD_CAST_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) X axis deformation"); + uiDefButBitS(block, TOG, MOD_CAST_Y, B_MODIFIER_RECALC, "Y", lx+45,cy,45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) Y axis deformation"); + if (cmd->type != MOD_CAST_TYPE_CYLINDER) { + uiDefButBitS(block, TOG, MOD_CAST_Z, B_MODIFIER_RECALC, "Z", lx+90,cy,45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) Z axis deformation"); + } + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Factor:", lx,(cy-=19),buttonWidth, 19, &cmd->fac, -10.0, 10.0, 5, 0, "Define the amount of deformation"); + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Radius:", lx,(cy-=19),buttonWidth, 19, &cmd->radius, 0.0, 100.0, 10.0, 0, "Only deform vertices within this distance from the center of the effect (leave as 0 for infinite)"); + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Size:", lx,(cy-=19),buttonWidth, 19, &cmd->size, 0.0, 100.0, 10.0, 0, "Size of projection shape (leave as 0 for auto)"); + uiDefButBitS(block, TOG, MOD_CAST_SIZE_FROM_RADIUS, B_MODIFIER_RECALC, "From radius", lx+buttonWidth,cy,80,19, &cmd->flag, 0, 0, 0, 0, "Use radius as size of projection shape (0 = auto)"); + if (ob->type == OB_MESH) { + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to define which vertices are affected"); + } + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx,(cy-=19), buttonWidth,19, &cmd->object, "Control object: if available, its location determines the center of the effect"); + if(cmd->object) { + uiDefButBitS(block, TOG, MOD_CAST_USE_OB_TRANSFORM, B_MODIFIER_RECALC, "Use transform", lx+buttonWidth,cy,80,19, &cmd->flag, 0, 0, 0, 0, "Use object transform to control projection shape"); + } } else if (md->type==eModifierType_Wave) { WaveModifierData *wmd = (WaveModifierData*) md; uiDefButBitS(block, TOG, WAV_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &wmd->flag, 0, 0, 0, 0, "Enable X axis motion"); -- cgit v1.2.3