From fb9546746efe63a2e6c2806ad12978a4401002d1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 22 Mar 2010 00:22:52 +0000 Subject: [PATCH] Screw Modifier (old patch was called Lathe) didnt commit this patch because curves are generally better to create a shape to lathe however now that curves can have modifiers applied to them I think its good to have this. Added options to offset the lathe so it can work like the screw tool as well. - optional object for axis which also controls the center point. - screw offset so rather then just lathing this can work more like the screw tool. - screw optionally using the object distance along the axis. - iterations so the screw can be applied multiple times. tested to work well with curves. --- .../scripts/ui/properties_data_modifier.py | 22 + source/blender/blenkernel/intern/modifier.c | 813 ++++++++++++++++++ source/blender/editors/include/UI_icons.h | 2 +- .../blender/editors/space_outliner/outliner.c | 2 + source/blender/makesdna/DNA_modifier_types.h | 19 + source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 82 ++ 7 files changed, 940 insertions(+), 1 deletion(-) diff --git a/release/scripts/ui/properties_data_modifier.py b/release/scripts/ui/properties_data_modifier.py index 8364d070d1a..b91c7d4372c 100644 --- a/release/scripts/ui/properties_data_modifier.py +++ b/release/scripts/ui/properties_data_modifier.py @@ -497,6 +497,28 @@ class DATA_PT_modifiers(DataButtonsPanel): def PARTICLE_SYSTEM(self, layout, ob, md, wide_ui): layout.label(text="See Particle panel.") + def SCREW(self, layout, ob, md, wide_ui): + split = layout.split() + + col = split.column() + col.prop(md, "axis") + col.prop(md, "object", text="AxisOb") + col.prop(md, "angle") + col.prop(md, "steps") + col.prop(md, "render_steps") + + col = split.column() + row = col.row() + row.active = (md.object is None or md.use_object_screw_offset == False) + row.prop(md, "screw_offset") + row = col.row() + row.active = (md.object is not None) + row.prop(md, "use_object_screw_offset") + col.prop(md, "use_normal_calculate") + col.prop(md, "use_normal_flip") + col.prop(md, "iterations") + + def SHRINKWRAP(self, layout, ob, md, wide_ui): split = layout.split() col = split.column() diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 4c4abf80db4..811836024f1 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -5991,6 +5991,803 @@ static DerivedMesh *solidifyModifier_applyModifierEM(ModifierData *md, return solidifyModifier_applyModifier(md, ob, derivedData, 0, 1); } +/* Screw */ + +/* Screw */ +/* Screw modifier: revolves the edges about an axis +*/ + +/* used for gathering edge connectivity */ +typedef struct ScrewVertConnect { + float dist; /* distance from the center axis */ + float co[3]; /* loaction relative to the transformed axis */ + float no[3]; /* calc normal of the vertex */ + int v[2]; /* 2 verts on either side of this one */ + MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */ + char flag; +} ScrewVertConnect; + +typedef struct ScrewVertIter { + ScrewVertConnect * v_array; + ScrewVertConnect * v_poin; + int v; + int v_other; + MEdge *e; +} ScrewVertIter; + +#define ScrewVertIter_INIT(iter, array, v_init, dir)\ + iter.v_array = array;\ + iter.v = v_init;\ + if (v_init>=0) {\ + iter.v_poin = &array[v_init];\ + iter.v_other = iter.v_poin->v[dir];\ + if (dir)\ + iter.e = iter.v_poin->e[0];\ + else\ + iter.e = iter.v_poin->e[1];\ + } else {\ + iter.v_poin= NULL;\ + iter.e= NULL;\ + } + + +#define ScrewVertIter_NEXT(iter)\ + if (iter.v_poin->v[0] == iter.v_other) {\ + iter.v_other= iter.v;\ + iter.v= iter.v_poin->v[1];\ + } else if (iter.v_poin->v[1] == iter.v_other) {\ + iter.v_other= iter.v;\ + iter.v= iter.v_poin->v[0];\ + }\ + if (iter.v >=0) {\ + iter.v_poin= &iter.v_array[iter.v];\ + if ( iter.v_poin->e[0] != iter.e ) iter.e= iter.v_poin->e[0];\ + else iter.e= iter.v_poin->e[1];\ + } else {\ + iter.e= NULL;\ + iter.v_poin= NULL;\ + } + +static void screwModifier_initData(ModifierData *md) +{ + ScrewModifierData *ltmd= (ScrewModifierData*) md; + ltmd->ob_axis= NULL; + ltmd->angle= M_PI * 2.0; + ltmd->axis= 2; + ltmd->flag= 0; + ltmd->steps= 16; + ltmd->render_steps= 16; + ltmd->iter= 1; +} + +static void screwModifier_copyData(ModifierData *md, ModifierData *target) +{ + ScrewModifierData *sltmd= (ScrewModifierData*) md; + ScrewModifierData *tltmd= (ScrewModifierData*) target; + + tltmd->ob_axis= sltmd->ob_axis; + tltmd->angle= sltmd->angle; + tltmd->axis= sltmd->axis; + tltmd->flag= sltmd->flag; + tltmd->steps= sltmd->steps; + tltmd->render_steps= sltmd->render_steps; + tltmd->iter= sltmd->iter; +} + +static DerivedMesh *screwModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *dm= derivedData; + DerivedMesh *result; + ScrewModifierData *ltmd= (ScrewModifierData*) md; + + int *origindex; + int mface_index=0; + int i, j; + int i1,i2; + int steps= ltmd->steps; + int maxVerts=0, maxEdges=0, maxFaces=0; + int totvert= dm->getNumVerts(dm); + int totedge= dm->getNumEdges(dm); + + char axis_char, close; + float angle= ltmd->angle; + float screw_ofs= ltmd->screw_ofs; + float axis_vec[3]= {0.0f, 0.0f, 0.0f}; + float tmp_vec1[3], tmp_vec2[3]; + float mat3[3][3]; + float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ + float mtx_tx_inv[4][4]; /* inverted */ + float mtx_tmp_a[4][4]; + + int vc_tot_linked= 0; + short other_axis_1, other_axis_2; + float *tmpf1, *tmpf2; + + MFace *mface_new, *mf_new; + MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; + MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; + + ScrewVertConnect *vc, *vc_tmp, *vert_connect= NULL; + + + float mat[4][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}}; + + /* dont do anything? */ + if (!totvert) + return CDDM_from_template(dm, 0, 0, 0); + + if (useRenderParams) + steps= ltmd->render_steps; + else + steps= ltmd->steps; + + if (ltmd->axis==0) { + other_axis_1=1; + other_axis_2=2; + } else if (ltmd->axis==1) { + other_axis_1=0; + other_axis_2=2; + } else { + other_axis_1=0; + other_axis_2=1; + } + + axis_vec[ltmd->axis]= 1.0; + if (ltmd->ob_axis) { + float mtx3_tx[3][3]; + /* calc the matrix relative to the axis object */ + invert_m4_m4(mtx_tmp_a, ob->obmat); + copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); + mul_m4_m4m4(mtx_tx, mtx_tx_inv, mtx_tmp_a); + + copy_m3_m4(mtx3_tx, mtx_tx); + + /* calc the axis vec */ + mul_m3_v3(mtx3_tx, axis_vec); + normalize_v3(axis_vec); + + /* screw */ + if(ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { + /* find the offset along this axis relative to this objects matrix */ + float totlen = len_v3(mtx_tx[3]); + + if(totlen != 0.0f) { + float zero[3]={0,0,0}; + float cp[3]; + screw_ofs= closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); + } + else { + screw_ofs= 0.0f; + } + } + + /* angle */ + +#if 0 // cant incluide this, not pradictable enough, though quite fun,. + if(ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { + + + float vec[3] = {0,1,0}; + float cross1[3]; + float cross2[3]; + cross_v3_v3v3(cross1, vec, axis_vec); + + mul_v3_m3v3(cross2, mtx3_tx, cross1); + { + float c1[3]; + float c2[3]; + float axis_tmp[3]; + + cross_v3_v3v3(c1, cross2, axis_vec); + cross_v3_v3v3(c2, axis_vec, c1); + + + angle= angle_v3v3(cross1, c2); + + cross_v3_v3v3(axis_tmp, cross1, c2); + normalize_v3(axis_tmp); + + if(len_v3v3(axis_tmp, axis_vec) > 1.0) + angle= -angle; + + } + } +#endif + + } else { + /* exis char is used by i_rotate*/ + axis_char= 'X' + ltmd->axis; + + /* useful to be able to use the axis vec in some cases still */ + zero_v3(axis_vec); + axis_vec[ltmd->axis]= 1.0; + } + + /* apply the multiplier */ + angle *= ltmd->iter; + screw_ofs *= ltmd->iter; + + /* multiplying the steps is a bit tricky, this works best */ + steps += 1; + steps = (steps * ltmd->iter) - (ltmd->iter - 1); + if(steps < 2) steps= 2; + + /* will the screw be closed? */ + if (fabs(screw_ofs) <= (FLT_EPSILON*100) && fabs(fabs(angle) - M_PI * 2.0) <= (FLT_EPSILON*100)) { + close= 1; + + maxVerts = totvert * steps; /* -1 because we're joining back up */ + maxEdges = (totvert * steps) + /* these are the edges between new verts */ + (totedge * steps); /* -1 because vert edges join */ + maxFaces = totedge * steps; + + screw_ofs= 0.0f; + } else { + close= 0; + + maxVerts = totvert * steps; /* -1 because we're joining back up */ + maxEdges = (totvert * (steps-1)) + /* these are the edges between new verts */ + (totedge * steps); /* -1 because vert edges join */ + maxFaces = totedge * (steps-1); + } + + result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces); + + /* copy verts from mesh */ + mvert_orig = dm->getVertArray(dm); + medge_orig = dm->getEdgeArray(dm); + + mvert_new = result->getVertArray(result); + mface_new = result->getFaceArray(result); + medge_new = result->getEdgeArray(result); + + origindex= result->getFaceDataArray(result, CD_ORIGINDEX); + + /* Set the locations of the first set of verts */ + + mv_new= mvert_new; + mv_orig= mvert_orig; + + /* Copy the first set of edges */ + med_orig= medge_orig; + med_new= medge_new; + for (i=0; i < totedge; i++, med_orig++, med_new++) { + med_new->v1= med_orig->v1; + med_new->v2= med_orig->v2; + med_new->crease= med_orig->crease; + med_new->flag= med_orig->flag & ~ME_LOOSEEDGE; + } + + if(ltmd->flag & MOD_SCREW_NORMAL_CALC) { + /* + * Normal Calculation (for face flipping) + * Sort edge verts for correct face flipping + * NOT REALLY NEEDED but face flipping is nice. + * + * */ + + + /* Notice! + * + * Since we are only ordering the edges here it can avoid mallocing the + * extra space by abusing the vert array berfore its filled with new verts. + * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert + * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3 + * so its safe to use the second 2 thrids of MVert the array for vert_connect, + * just make sure ScrewVertConnect struct is no more then twice as big as MVert, + * at the moment there is no chance of that being a problem, + * unless MVert becomes half its current size. + * + * once the edges are ordered, vert_connect is not needed and it can be used for verts + * + * This makes the modifier faster with one less alloc. + */ + + vert_connect= MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect"); + //vert_connect= (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */ + vc= vert_connect; + + /* Copy Vert Locations */ + /* - We can do this in a later loop - only do here if no normal calc */ + if (!totedge) { + for (i=0; i < totvert; i++, mv_orig++, mv_new++) { + copy_v3_v3(mv_new->co, mv_orig->co); + normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is realy a dummy normal */ + } + } else { + /*printf("\n\n\n\n\nStarting Modifier\n");*/ + /* set edge users */ + med_new= medge_new; + mv_new= mvert_new; + + if (ltmd->ob_axis) { + /*mtx_tx is initialized early on */ + for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) { + vc->co[0]= mv_new->co[0]= mv_orig->co[0]; + vc->co[1]= mv_new->co[1]= mv_orig->co[1]; + vc->co[2]= mv_new->co[2]= mv_orig->co[2]; + + vc->flag= 0; + vc->e[0]= vc->e[1]= NULL; + vc->v[0]= vc->v[1]= -1; + + mul_m4_v3(mtx_tx, vc->co); + /* length in 2d, dont sqrt because this is only for comparison */ + vc->dist = vc->co[other_axis_1]*vc->co[other_axis_1] + + vc->co[other_axis_2]*vc->co[other_axis_2]; + + /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ + } + } else { + for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) { + vc->co[0]= mv_new->co[0]= mv_orig->co[0]; + vc->co[1]= mv_new->co[1]= mv_orig->co[1]; + vc->co[2]= mv_new->co[2]= mv_orig->co[2]; + + vc->flag= 0; + vc->e[0]= vc->e[1]= NULL; + vc->v[0]= vc->v[1]= -1; + + /* length in 2d, dont sqrt because this is only for comparison */ + vc->dist = vc->co[other_axis_1]*vc->co[other_axis_1] + + vc->co[other_axis_2]*vc->co[other_axis_2]; + + /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ + } + } + + /* this loop builds connectivity info for verts */ + for (i=0; iv1]; + + if (vc->v[0]==-1) { /* unused */ + vc->v[0]= med_new->v2; + vc->e[0]= med_new; + } else if (vc->v[1]==-1) { + vc->v[1]= med_new->v2; + vc->e[1]= med_new; + } else { + vc->v[0]= vc->v[1]= -2; /* erro value - dont use, 3 edges on vert */ + } + + vc= &vert_connect[med_new->v2]; + + /* same as above but swap v1/2 */ + if (vc->v[0]==-1) { /* unused */ + vc->v[0]= med_new->v1; + vc->e[0]= med_new; + } else if (vc->v[1]==-1) { + vc->v[1]= med_new->v1; + vc->e[1]= med_new; + } else { + vc->v[0]= vc->v[1]= -2; /* erro value - dont use, 3 edges on vert */ + } + } + + /* find the first vert */ + vc= vert_connect; + for (i=0; i < totvert; i++, vc++) { + int VBEST=-1, ed_loop_closed=0; /* vert and vert new */ + int ed_loop_flip; + float fl= -1.0f; + ScrewVertIter lt_iter; + + /* Now do search for connected verts, order all edges and flip them + * so resulting faces are flipped the right way */ + vc_tot_linked= 0; /* count the number of linked verts for this loop */ + if (vc->flag==0) { + /*printf("Loop on connected vert: %i\n", i);*/ + + for(j=0; j<2; j++) { + /*printf("\tSide: %i\n", j);*/ + ScrewVertIter_INIT(lt_iter, vert_connect, i, j); + if (j==1) { + ScrewVertIter_NEXT(lt_iter); + } + while (lt_iter.v_poin) { + /*printf("\t\tVERT: %i\n", lt_iter.v);*/ + if (lt_iter.v_poin->flag) { + /*printf("\t\t\tBreaking Found end\n");*/ + //endpoints[0]= endpoints[1]= -1; + ed_loop_closed= 1; /* circle */ + break; + } + lt_iter.v_poin->flag= 1; + vc_tot_linked++; + /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/ + if (fl <= lt_iter.v_poin->dist) { + fl= lt_iter.v_poin->dist; + VBEST= lt_iter.v; + /*printf("\t\t\tVERT BEST: %i\n", VBEST);*/ + } + ScrewVertIter_NEXT(lt_iter); + if (!lt_iter.v_poin) { + /*printf("\t\t\tFound End Also Num %i\n", j);*/ + /*endpoints[j]= lt_iter.v_other;*/ /* other is still valid */ + break; + } + } + } + + /* now we have a collection of used edges. flip their edges the right way*/ + /*if (VBEST !=-1) - */ + + /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/ + + if (vc_tot_linked>1) { + float vf_1, vf_2, vf_best; + + vc_tmp= &vert_connect[VBEST]; + + tmpf1= vert_connect[vc_tmp->v[0]].co; + tmpf2= vert_connect[vc_tmp->v[1]].co; + + + /* edge connects on each side! */ + if ((vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) { + /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ + /* find out which is higher */ + + vf_1= tmpf1[ltmd->axis]; + vf_2= tmpf2[ltmd->axis]; + vf_best= vc_tmp->co[ltmd->axis]; + + if (vf_1 < vf_best && vf_best < vf_2) { + ed_loop_flip= 0; + } else if (vf_1 > vf_best && vf_best > vf_2) { + ed_loop_flip= 1; + } else { + /* not so simple to work out wich edge is higher */ + sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co); + sub_v3_v3v3(tmp_vec1, tmpf2, vc_tmp->co); + normalize_v3(tmp_vec1); + normalize_v3(tmp_vec2); + + if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) { + ed_loop_flip= 1; + } else { + ed_loop_flip= 0; + } + } + } else if (vc_tmp->v[0] >= 0) { /*vertex only connected on 1 side */ + /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ + if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */ + ed_loop_flip= 1; + } else { /* best is below or even... in even case we cant know whet to do. */ + ed_loop_flip= 0; + } + + }/* else { + printf("No Connected ___\n"); + }*/ + + /*printf("flip direction %i\n", ed_loop_flip);*/ + + + /* switch the flip option if set */ + if (ltmd->flag & MOD_SCREW_NORMAL_FLIP) { + if (ed_loop_flip) ed_loop_flip= 0; + else ed_loop_flip= 1; + } + if (angle < 0.0f) { + if (ed_loop_flip) ed_loop_flip= 0; + else ed_loop_flip= 1; + } + + /* if its closed, we only need 1 loop */ + for(j=ed_loop_closed; j<2; j++) { + /*printf("Ordering Side J %i\n", j);*/ + + ScrewVertIter_INIT(lt_iter, vert_connect, VBEST, j); + /*printf("\n\nStarting - Loop\n");*/ + lt_iter.v_poin->flag= 1; /* so a non loop will traverse the other side */ + + + /* If this is the vert off the best vert and + * the best vert has 2 edges connected too it + * then swap the flip direction */ + if (j==1 && (vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) { + if (ed_loop_flip) ed_loop_flip= 0; + else ed_loop_flip= 1; + } + + while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) { + /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/ + + lt_iter.v_poin->flag= 2; + if (lt_iter.e) { + if (lt_iter.v == lt_iter.e->v1) { + if (ed_loop_flip==0) { + /*printf("\t\t\tFlipping 0\n");*/ + SWAP( int, lt_iter.e->v1, lt_iter.e->v2 ); + }/* else { + printf("\t\t\tFlipping Not 0\n"); + }*/ + } else if (lt_iter.v == lt_iter.e->v2) { + if (ed_loop_flip==1) { + /*printf("\t\t\tFlipping 1\n");*/ + SWAP( int, lt_iter.e->v1, lt_iter.e->v2 ); + }/* else { + printf("\t\t\tFlipping Not 1\n"); + }*/ + }/* else { + printf("\t\tIncorrect edge topology"); + }*/ + }/* else { + printf("\t\tNo Edge at this point\n"); + }*/ + ScrewVertIter_NEXT(lt_iter); + } + } + } + } + + /* *VERTEX NORMALS* + * we know the surrounding edges are ordered correctly now + * so its safe to create vertex normals. + * + * calculate vertex normals that can be propodated on lathing + * use edge connectivity work this out */ + if (vc->v[0]>=0) { + if (vc->v[1]>=0) { + /* 2 edges connedted */ + /* make 2 connecting vert locations relative to the middle vert */ + sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); + sub_v3_v3v3(tmp_vec2, mvert_new[vc->v[1]].co, mvert_new[i].co); + /* normalize so both edges have the same influence, no matter their length */ + normalize_v3(tmp_vec1); + normalize_v3(tmp_vec2); + + /* vc_no_tmp1 - this line is the average direction of both connecting edges + * + * Use the edge order to make the subtraction, flip the normal the right way + * edge should be there but check just in case... */ + if (vc->e && vc->e[0]->v1 == i) { + sub_v3_v3v3(tmp_vec1, tmp_vec1, tmp_vec2); + } else { + sub_v3_v3v3(tmp_vec1, tmp_vec2, tmp_vec1); + } + + } else { + /* only 1 edge connected - same as above except + * dont need to average edge direction */ + if (vc->e && vc->e[0]->v2 == i) { + sub_v3_v3v3(tmp_vec1, mvert_new[i].co, mvert_new[vc->v[0]].co); + } else { + sub_v3_v3v3(tmp_vec1, mvert_new[vc->v[0]].co, mvert_new[i].co); + } + } + + /* vc_no_tmp2 - is a line 90d from the pivot to the vec + * This is used so the resulting normal points directly away from the middle */ + cross_v3_v3v3(tmp_vec2, axis_vec, vc->co); + + /* edge average vector and right angle to the pivot make the normal */ + cross_v3_v3v3(vc->no, tmp_vec1, tmp_vec2); + + } else { + copy_v3_v3(vc->no, vc->co); + } + + /* we wont be looping on this data again so copy normals here */ + if (angle < 0.0) + negate_v3(vc->no); + + normalize_v3(vc->no); + normal_float_to_short_v3(mvert_new[i].no, vc->no); + + /* Done with normals */ + } + } + } + else { + + if (ltmd->flag & MOD_SCREW_NORMAL_FLIP) { + mv_orig= mvert_orig; + mv_new= mvert_new + (totvert-1); + + for (i=0; i < totvert; i++, mv_new--, mv_orig++) { + copy_v3_v3(mv_new->co, mv_orig->co); + } + } + else { + mv_orig= mvert_orig; + mv_new= mvert_new; + + for (i=0; i < totvert; i++, mv_new++, mv_orig++) { + copy_v3_v3(mv_new->co, mv_orig->co); + } + } + } + /* done with edge connectivity based normal flipping */ + + + /* Add Faces */ + for (i=1; i < steps; i++) { + float step_angle; + float no_tx[3]; + /* Rotation Matrix */ + if (close) step_angle= (angle / steps) * i; + else step_angle= (angle / (steps-1)) * i; + + if (ltmd->ob_axis) { + axis_angle_to_mat3(mat3, axis_vec, step_angle); + copy_m4_m3(mat, mat3); + } else { + unit_m4(mat); + rotate_m4(mat, axis_char, step_angle); + copy_m3_m4(mat3, mat); + } + + if(screw_ofs) + madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)i / (float)(steps-1))); + + mv_new_base= mvert_new; + mv_new= &mvert_new[totvert*i]; /* advance to the next slice */ + + for (j=0; jno, no_tx); + } + + /* set location */ + copy_v3_v3(mv_new->co, mv_new_base->co); + + /* only need to set these if using non cleared memory */ + /*mv_new->mat_nr= mv_new->flag= 0;*/ + + if (ltmd->ob_axis) { + sub_v3_v3(mv_new->co, mtx_tx[3]); + + mul_m4_v3(mat, mv_new->co); + + add_v3_v3(mv_new->co, mtx_tx[3]); + } else { + mul_m4_v3(mat, mv_new->co); + } + + /* add the new edge */ + med_new->v1= j+(i*totvert); + med_new->v2= med_new->v1 - totvert; + med_new->flag= ME_EDGEDRAW|ME_EDGERENDER; + med_new++; + } + } + + /* we can avoid if using vert alloc trick */ + if(vert_connect) { + MEM_freeN(vert_connect); + vert_connect= NULL; + } + + if (close) { + /* last loop of edges, previous loop dosnt account for the last set of edges */ + for (i=0; iv1= i+((steps-1)*totvert); + med_new->v2= i; + med_new->flag= ME_EDGEDRAW|ME_EDGERENDER; + med_new++; + } + } + + mf_new= mface_new; + med_new_firstloop= medge_new; + + for (i=0; i < totedge; i++, med_new_firstloop++) { + /* for each edge, make a cylinder of quads */ + i1= med_new_firstloop->v1; + i2= med_new_firstloop->v2; + + for (j=0; j < steps-1; j++) { + + /* new face */ + mf_new->v1= i1; + mf_new->v2= i2; + mf_new->v3= i2 + totvert; + mf_new->v4= i1 + totvert; + + if( !mf_new->v3 || !mf_new->v4 ) { + SWAP( int, mf_new->v1, mf_new->v3 ); + SWAP( int, mf_new->v2, mf_new->v4 ); + } + mf_new->flag= ME_SMOOTH; + origindex[mface_index]= ORIGINDEX_NONE; + mf_new++; + mface_index++; + + /* new vertical edge */ + if (j) { /* The first set is alredy dome */ + med_new->v1= i1; + med_new->v2= i2; + med_new->flag= med_new_firstloop->flag; + med_new->crease= med_new_firstloop->crease; + med_new++; + } + i1 += totvert; + i2 += totvert; + } + + /* close the loop*/ + if (close) { + mf_new->v1= i1; + mf_new->v2= i2; + mf_new->v3= med_new_firstloop->v2; + mf_new->v4= med_new_firstloop->v1; + + if( !mf_new->v3 || !mf_new->v4 ) { + SWAP( int, mf_new->v1, mf_new->v3 ); + SWAP( int, mf_new->v2, mf_new->v4 ); + } + mf_new->flag= ME_SMOOTH; + origindex[mface_index]= ORIGINDEX_NONE; + mf_new++; + mface_index++; + } + + /* new vertical edge */ + med_new->v1= i1; + med_new->v2= i2; + med_new->flag= med_new_firstloop->flag & ~ME_LOOSEEDGE; + med_new->crease= med_new_firstloop->crease; + med_new++; + } + + if((ltmd->flag & MOD_SCREW_NORMAL_CALC)==0) { + CDDM_calc_normals(result); + } + + return result; +} + + +static void screwModifier_updateDepgraph( + ModifierData *md, DagForest *forest, + Scene *scene, Object *ob, DagNode *obNode) +{ + ScrewModifierData *ltmd= (ScrewModifierData*) md; + + if(ltmd->ob_axis) { + DagNode *curNode= dag_get_node(forest, ltmd->ob_axis); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, + "Screw Modifier"); + } +} + +static void screwModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) +{ + ScrewModifierData *ltmd= (ScrewModifierData*) md; + + walk(userData, ob, <md->ob_axis); +} + +/* This dosnt work with material*/ +static DerivedMesh *screwModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return screwModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +static int screwModifier_dependsOnTime(ModifierData *md) +{ + return 0; +} + + /* Smoke */ static void smokeModifier_initData(ModifierData *md) @@ -8921,6 +9718,22 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->applyModifier = solidifyModifier_applyModifier; mti->applyModifierEM = solidifyModifier_applyModifierEM; typeArrInit = 0; + + mti = INIT_TYPE(Screw); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode + | eModifierTypeFlag_AcceptsCVs; + + mti->initData = screwModifier_initData; + mti->copyData = screwModifier_copyData; + mti->foreachObjectLink = screwModifier_foreachObjectLink; + mti->dependsOnTime = screwModifier_dependsOnTime; + mti->updateDepgraph = screwModifier_updateDepgraph; + mti->applyModifier = screwModifier_applyModifier; + mti->applyModifierEM = screwModifier_applyModifierEM; + #undef INIT_TYPE } diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 745073fd235..30560687702 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -540,7 +540,7 @@ DEF_ICON(ICON_MOD_FLUIDSIM) DEF_ICON(ICON_MOD_MULTIRES) DEF_ICON(ICON_MOD_SMOKE) DEF_ICON(ICON_MOD_SOLIDIFY) -DEF_ICON(ICON_BLANK159) +DEF_ICON(ICON_MOD_SCREW) // XXX, needs drawing DEF_ICON(ICON_BLANK160) DEF_ICON(ICON_BLANK161) DEF_ICON(ICON_BLANK162) diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index 38691a62d35..f5ef9a6ba75 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -4219,6 +4219,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_MOD_SMOKE); break; case eModifierType_Solidify: UI_icon_draw(x, y, ICON_MOD_SOLIDIFY); break; + case eModifierType_Screw: + UI_icon_draw(x, y, ICON_MOD_SCREW); break; default: UI_icon_draw(x, y, ICON_DOT); break; } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 5d321fe49c2..dbcf5849616 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -65,6 +65,7 @@ typedef enum ModifierType { eModifierType_Smoke, eModifierType_ShapeKey, eModifierType_Solidify, + eModifierType_Screw, NUM_MODIFIER_TYPES } ModifierType; @@ -692,4 +693,22 @@ typedef struct SolidifyModifierData { #define MOD_SOLIDIFY_EVEN (1<<1) #define MOD_SOLIDIFY_NORMAL_CALC (1<<2) +typedef struct ScrewModifierData { + ModifierData modifier; + struct Object *ob_axis; + int steps; + int render_steps; + int iter; + float screw_ofs; + float angle; + short axis; + short flag; +} ScrewModifierData; + +#define MOD_SCREW_NORMAL_FLIP (1<<0) +#define MOD_SCREW_NORMAL_CALC (1<<1) +#define MOD_SCREW_OBJECT_OFFSET (1<<2) +// #define MOD_SCREW_OBJECT_ANGLE (1<<4) + + #endif diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 2671f480d3b..5f9565c874d 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -383,6 +383,7 @@ extern StructRNA RNA_SceneGameData; extern StructRNA RNA_SceneRenderLayer; extern StructRNA RNA_SceneSequence; extern StructRNA RNA_Screen; +extern StructRNA RNA_ScrewModifier; extern StructRNA RNA_Sculpt; extern StructRNA RNA_Sensor; extern StructRNA RNA_Sequence; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 69370b63362..3e3377dcd38 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -54,6 +54,7 @@ EnumPropertyItem modifier_type_items[] ={ {eModifierType_EdgeSplit, "EDGE_SPLIT", ICON_MOD_EDGESPLIT, "Edge Split", ""}, {eModifierType_Mask, "MASK", ICON_MOD_MASK, "Mask", ""}, {eModifierType_Mirror, "MIRROR", ICON_MOD_MIRROR, "Mirror", ""}, + {eModifierType_Screw, "SCREW", ICON_MOD_SCREW, "Screw", ""}, {eModifierType_Multires, "MULTIRES", ICON_MOD_MULTIRES, "Multiresolution", ""}, {eModifierType_Solidify, "SOLIDIFY", ICON_MOD_SOLIDIFY, "Solidify", ""}, {eModifierType_Subsurf, "SUBSURF", ICON_MOD_SUBSURF, "Subdivision Surface", ""}, @@ -164,6 +165,8 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_SmokeModifier; case eModifierType_Solidify: return &RNA_SolidifyModifier; + case eModifierType_Screw: + return &RNA_ScrewModifier; default: return &RNA_Modifier; } @@ -1191,6 +1194,7 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna) RNA_def_struct_sdna(srna, "EdgeSplitModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_EDGESPLIT); + // XXX, convert to radians. prop= RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0, 180); RNA_def_property_ui_range(prop, 0, 180, 100, 2); @@ -2069,6 +2073,83 @@ static void rna_def_modifier_solidify(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_NORMAL_CALC); RNA_def_property_ui_text(prop, "High Quality Normals", "Calculate normals which result in more even thickness (slow, disable when not needed)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + +} + +static void rna_def_modifier_screw(BlenderRNA *brna) +{ + static EnumPropertyItem axis_items[]= { + {0, "X", 0, "X Axis", ""}, + {1, "Y", 0, "Y Axis", ""}, + {2, "Z", 0, "Z Axis", ""}, + {0, NULL, 0, NULL, NULL}}; + + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "ScrewModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Screw Modifier", "Revolve edges"); + RNA_def_struct_sdna(srna, "ScrewModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_SCREW); + + prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ob_axis"); + RNA_def_property_ui_text(prop, "Object", "Object to define the screw axis"); + RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + prop= RNA_def_property(srna, "steps", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_range(prop, 1, 1024, 1, 0); + RNA_def_property_ui_text(prop, "Steps", "Number of steps in the revolution"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "render_steps", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_range(prop, 1, 1024, 1, 0); + RNA_def_property_ui_text(prop, "Render Steps", "Number of steps in the revolution"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "iterations", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "iter"); + RNA_def_property_ui_range(prop, 1, 1024, 1, 0); + RNA_def_property_ui_text(prop, "Iterations", "Number of times to apply the screw operation"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, axis_items); + RNA_def_property_ui_text(prop, "Axis", "Screw axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + // XXX, convert to radians. + prop= RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); + //RNA_def_property_range(prop, 0, 180); + //RNA_def_property_ui_range(prop, 0, 180, 100, 2); + RNA_def_property_ui_text(prop, "Angle", "Angle of revolution"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "screw_offset", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "screw_ofs"); + RNA_def_property_ui_text(prop, "Screw", "Offset the revolution along its axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "use_normal_flip", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_NORMAL_FLIP); + RNA_def_property_ui_text(prop, "Flip", "Flip normals of lathed faces"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "use_normal_calculate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_NORMAL_CALC); + RNA_def_property_ui_text(prop, "Calc Order", "Calculate the order of edges (needed for meshes, but not curves)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "use_object_screw_offset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_OBJECT_OFFSET); + RNA_def_property_ui_text(prop, "Object Screw", "Use the distance between the objects to make a screw"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /*prop= RNA_def_property(srna, "use_angle_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_OBJECT_ANGLE); + RNA_def_property_ui_text(prop, "Object Angle", "Use the angle between the objects rather then the fixed angle"); + RNA_def_property_update(prop, 0, "rna_Modifier_update");*/ } void RNA_def_modifier(BlenderRNA *brna) @@ -2160,6 +2241,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_surface(brna); rna_def_modifier_smoke(brna); rna_def_modifier_solidify(brna); + rna_def_modifier_screw(brna); } #endif