From c6de35e55880774812294880f3d908871ff3b7cf Mon Sep 17 00:00:00 2001 From: Andre Susano Pinto Date: Tue, 12 Aug 2008 20:43:10 +0000 Subject: *Added documentation mainly at shrinkwrap.c *removed commented code about the dropped shrinkwrap options *Removed references to "cut plane", "limitMesh".. its now called "auxiliar target" *Added option to shrinkwrap over an selected axis *"Normal projection" mode is now called "projection" since it can now project over "normal, and any combination X, Y, Z" --- source/blender/blenkernel/BKE_shrinkwrap.h | 75 +++- source/blender/blenkernel/intern/constraint.c | 68 +-- source/blender/blenkernel/intern/modifier.c | 34 +- source/blender/blenkernel/intern/shrinkwrap.c | 599 +++++-------------------- source/blender/makesdna/DNA_constraint_types.h | 2 +- source/blender/makesdna/DNA_modifier_types.h | 23 +- source/blender/src/buttons_editing.c | 27 +- source/blender/src/buttons_object.c | 12 +- 8 files changed, 249 insertions(+), 591 deletions(-) diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index dec9635f14c..4fa52f12566 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -30,27 +30,36 @@ #define BKE_SHRINKWRAP_H /* mesh util */ -//TODO move this somewhere else +//TODO: move this somewhere else #include "BKE_customdata.h" struct DerivedMesh; struct Object; struct DerivedMesh *object_get_derived_final(struct Object *ob, CustomDataMask dataMask); -/* bitset stuff */ -//TODO: should move this to other generic lib files? -typedef char* BitSet; -#define bitset_memsize(size) (sizeof(char)*((size+7)>>3)) - -#define bitset_new(size,name) ((BitSet)MEM_callocN( bitset_memsize(size) , name)) -#define bitset_free(set) (MEM_freeN((void*)set)) - -#define bitset_get(set,index) ((set)[(index)>>3] & (1 << ((index)&0x7))) -#define bitset_set(set,index) ((set)[(index)>>3] |= (1 << ((index)&0x7))) -#define bitset_unset(set,index) ((set)[(index)>>3] &= ~(1 << ((index)&0x7))) - /* SpaceTransform stuff */ -//TODO: should move to other generic space? +/* + * TODO: move this somewhere else + * + * this structs encapsulates all needed data to convert between 2 coordinate spaces + * (where conversion can be represented by a matrix multiplication) + * + * This is used to reduce the number of arguments to pass to functions that need to perform + * this kind of operation and make it easier for the coder, as he/she doenst needs to recode + * the matrix calculation. + * + * A SpaceTransform is initialized using: + * space_transform_setup( &data, ob1, ob2 ) + * + * After that the following calls can be used: + * space_transform_apply (&data, co); //converts a coordinate in ob1 coords space to the corresponding ob2 coords + * space_transform_invert(&data, co); //converts a coordinate in ob2 coords space to the corresponding ob1 coords + * + * //Same Concept as space_transform_apply and space_transform_invert, but no is normalized after conversion + * space_transform_apply_normal (&data, &no); + * space_transform_invert_normal(&data, &no); + * + */ struct Object; typedef struct SpaceTransform @@ -66,20 +75,29 @@ void space_transform_from_matrixs(SpaceTransform *data, float local[][4], float void space_transform_apply (const SpaceTransform *data, float *co); void space_transform_invert(const SpaceTransform *data, float *co); -void space_transform_apply_normal (const SpaceTransform *data, float *co); -void space_transform_invert_normal(const SpaceTransform *data, float *co); +void space_transform_apply_normal (const SpaceTransform *data, float *no); +void space_transform_invert_normal(const SpaceTransform *data, float *no); /* Shrinkwrap stuff */ #include "BKE_bvhutils.h" +/* + * Shrinkwrap is composed by a set of functions and options that define the type of shrink. + * + * 3 modes are available: + * - Nearest vertex + * - Nearest surface + * - Normal projection + * + * ShrinkwrapCalcData encapsulates all needed data for shrinkwrap functions. + * (So that you dont have to pass an enormous ammount of arguments to functions) + */ + struct Object; struct DerivedMesh; struct ShrinkwrapModifierData; struct BVHTree; -/* maybe move to bvh util */ -int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); - typedef struct ShrinkwrapCalcData { @@ -95,7 +113,6 @@ typedef struct ShrinkwrapCalcData SpaceTransform local2target; //transform to move bettwem local and target space float keptDist; //Distance to kept from target (units are in local space) - BitSet moved; //BitSet indicating if vertex has moved } ShrinkwrapCalcData; @@ -103,15 +120,27 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *data); void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *data); void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *data); -struct DerivedMesh *shrinkwrapModifier_do(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, int useRenderParams, int isFinalCalc); void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); +/* + * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: + * + * if transf was configured with "space_transform_setup( &transf, ob1, ob2 )" + * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space + * and the BVHTree must be built in ob2 coordinate space. + * + * Thus it provides an easy way to cast the same ray across several trees (where each tree was built on its own coords space) + */ +int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); + +/* + * NULL initializers to local data + */ #define NULL_ShrinkwrapCalcData {NULL, } #define NULL_BVHTreeFromMesh {NULL, } #define NULL_BVHTreeRayHit {NULL, } -#define NULL_BVHTreeNearest {NULL, } +#define NULL_BVHTreeNearest {0, } #endif - diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 2456472d94a..1d7d4d1fda0 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3274,6 +3274,7 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if( VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) { + int fail = FALSE; float co[3] = {0.0f, 0.0f, 0.0f}; float no[3] = {0.0f, 0.0f, 0.0f}; float dist; @@ -3295,58 +3296,72 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr hit.index = -1; hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it - switch(scon->normalAxis) - { - case UP_X: no[0] = 1.0f; break; - case UP_Y: no[1] = 1.0f; break; - case UP_Z: no[2] = 1.0f; break; - } - if(target != NULL) { space_transform_from_matrixs(&transform, cob->startmat, ct->tar->obmat); - //Normal projection applies the transform later - if(scon->shrinkType != MOD_SHRINKWRAP_NORMAL) - { - space_transform_apply(&transform, co); - space_transform_apply_normal(&transform, no); - } - switch(scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: bvhtree_from_mesh_faces(&treeData, target, 0.0, 2, 6); - if(treeData.tree == NULL) return; + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + space_transform_apply(&transform, co); BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); dist = VecLenf(co, nearest.co); VecLerpf(co, co, nearest.co, (dist - scon->dist)/dist); //linear interpolation + space_transform_invert(&transform, co); break; case MOD_SHRINKWRAP_NEAREST_VERTEX: bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); - if(treeData.tree == NULL) return; + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + space_transform_apply_normal(&transform, no); BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); dist = VecLenf(co, nearest.co); VecLerpf(co, co, nearest.co, (dist - scon->dist)/dist); //linear interpolation + space_transform_invert(&transform, co); break; - case MOD_SHRINKWRAP_NORMAL: - bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); - if(treeData.tree == NULL) return; + case MOD_SHRINKWRAP_PROJECT: + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; - if(normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) + if(INPR(no,no) < FLT_EPSILON) { - free_bvhtree_from_mesh(&treeData); + fail = TRUE; + break; + } + + Normalize(no); - target->release(target); - return; + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + if(normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) + { + fail = TRUE; + break; } VECCOPY(co, hit.co); break; @@ -3356,11 +3371,8 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr target->release(target); - if(scon->shrinkType != MOD_SHRINKWRAP_NORMAL) - { - space_transform_invert(&transform, co); - } - VECADD(ct->matrix[3], ct->matrix[3], co); + if(fail == FALSE) + VECADD(ct->matrix[3], ct->matrix[3], co); } } } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 0eb01e823aa..75e6b69a3d9 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -7230,11 +7230,11 @@ static void shrinkwrapModifier_initData(ModifierData *md) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE; - smd->shrinkOpts = MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL; + smd->shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR; smd->keptDist = 0.0f; - smd->target = 0; - smd->cutPlane = 0; + smd->target = NULL; + smd->auxTarget = NULL; } static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target) @@ -7242,12 +7242,14 @@ static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target) ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*)md; ShrinkwrapModifierData *tsmd = (ShrinkwrapModifierData*)target; - tsmd->target = smd->target; - tsmd->cutPlane = smd->cutPlane; + tsmd->target = smd->target; + tsmd->auxTarget = smd->auxTarget; + strcpy(tsmd->vgroup_name, smd->vgroup_name); - tsmd->keptDist = smd->keptDist; - tsmd->shrinkType = smd->shrinkType; - tsmd->shrinkOpts = smd->shrinkOpts; + + tsmd->keptDist = smd->keptDist; + tsmd->shrinkType= smd->shrinkType; + tsmd->shrinkOpts= smd->shrinkOpts; } CustomDataMask shrinkwrapModifier_requiredDataMask(ModifierData *md) @@ -7273,19 +7275,9 @@ static void shrinkwrapModifier_foreachObjectLink(ModifierData *md, Object *ob, O ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; walk(userData, ob, &smd->target); - walk(userData, ob, &smd->cutPlane); -} -/* -static DerivedMesh *shrinkwrapModifier_applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) -{ - return shrinkwrapModifier_do((ShrinkwrapModifierData*)md,ob,derivedData,useRenderParams,isFinalCalc); + walk(userData, ob, &smd->auxTarget); } -static DerivedMesh *shrinkwrapModifier_applyModifierEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData) -{ - return shrinkwrapModifier_do((ShrinkwrapModifierData*)md,ob,derivedData,0,0); -} -*/ static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, derivedData, vertexCos, numVerts); @@ -7313,8 +7305,8 @@ static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *fores if (smd->target) dag_add_relation(forest, dag_get_node(forest, smd->target), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); - if (smd->cutPlane) - dag_add_relation(forest, dag_get_node(forest, smd->cutPlane), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); + if (smd->auxTarget) + dag_add_relation(forest, dag_get_node(forest, smd->auxTarget), obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier"); } /* SimpleDeform */ diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 27442128483..d8ed67855c7 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -62,7 +62,6 @@ /* Benchmark macros */ #if 1 - #include #define BENCH(a) \ @@ -78,20 +77,9 @@ printf("%s: %fs (real) %fs (cpu)\n", #a, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\ } while(0) -#define BENCH_VAR(name) clock_t JOIN(_bench_step,name) = 0, JOIN(_bench_total,name) = 0 -#define BENCH_BEGIN(name) JOIN(_bench_step, name) = clock() -#define BENCH_END(name) JOIN(_bench_total,name) += clock() - JOIN(_bench_step,name) -#define BENCH_RESET(name) JOIN(_bench_total, name) = 0 -#define BENCH_REPORT(name) printf("%s: %fms (cpu) \n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC) - #else #define BENCH(a) (a) -#define BENCH_VAR(name) -#define BENCH_BEGIN(name) -#define BENCH_END(name) -#define BENCH_RESET(name) -#define BENCH_REPORT(name) #endif @@ -115,7 +103,7 @@ DerivedMesh *object_get_derived_final(Object *ob, CustomDataMask dataMask) void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4]) { float itarget[4][4]; - Mat4Invert(itarget, target); //Invserse might be outdated + Mat4Invert(itarget, target); Mat4MulSerie(data->local2target, itarget, local, 0, 0, 0, 0, 0, 0); Mat4Invert(data->target2local, data->local2target); } @@ -152,443 +140,24 @@ static float squared_dist(const float *a, const float *b) return INPR(tmp, tmp); } -/* - * - */ -static void derivedmesh_mergeNearestPoints(DerivedMesh *dm, float mdist, BitSet skipVert) -{ - if(mdist > 0.0f) - { - int i, j, merged; - int numVerts = dm->getNumVerts(dm); - int *translate_vert = MEM_mallocN( sizeof(int)*numVerts, "merge points array"); - - MVert *vert = dm->getVertDataArray(dm, CD_MVERT); - - if(!translate_vert) return; - - merged = 0; - for(i=0; i 0) - { - int numFaces = dm->getNumFaces(dm); - int freeVert; - MFace *face = dm->getFaceDataArray(dm, CD_MFACE); - - - //Adjust vertexs using the translation_table.. only translations to back indexs are allowed - //which means t[i] <= i must always verify - for(i=0, freeVert = 0; iv1 = translate_vert[f->v1]; - f->v2 = translate_vert[f->v2]; - f->v3 = translate_vert[f->v3]; - //TODO be carefull with vertexs v4 being translated to 0 - f->v4 = translate_vert[f->v4]; - } - - //TODO: maybe update edges could be done outside this function - CDDM_calc_edges(dm); - //CDDM_calc_normals(dm); - } - - if(translate_vert) MEM_freeN( translate_vert ); - } -} - - -/* - * This function removes Unused faces, vertexs and edges from calc->target - * - * This function may modify calc->final. As so no data retrieved from - * it before the call to this function can be considered valid - * In case it creates a new DerivedMesh, the old calc->final is freed - */ -//TODO memory checks on allocs -/* -static void shrinkwrap_removeUnused(ShrinkwrapCalcData *calc) -{ - int i, t; - - DerivedMesh *old = calc->final, *new = NULL; - MFace *new_face = NULL; - MVert *new_vert = NULL; - - int numVerts= old->getNumVerts(old); - MVert *vert = old->getVertDataArray(old, CD_MVERT); - - int numFaces= old->getNumFaces(old); - MFace *face = old->getFaceDataArray(old, CD_MFACE); - - BitSet moved_verts = calc->moved; - - //Arrays to translate to new vertexs indexs - int *vert_index = (int*)MEM_callocN(sizeof(int)*(numVerts), "shrinkwrap used verts"); - BitSet used_faces = bitset_new(numFaces, "shrinkwrap used faces"); - int numUsedFaces = 0; - - - //calculate which vertexs need to be used - //even unmoved vertices might need to be used if theres a face that needs it - //calc real number of faces, and vertices - //Count used faces - for(i=0; igetVertDataArray(new, CD_MVERT); - for(i=0, t=0; igetFaceDataArray(new, CD_MFACE); - for(i=0, t=0; iv1 = vert_index[new_face->v1]-1; - new_face->v2 = vert_index[new_face->v2]-1; - new_face->v3 = vert_index[new_face->v3]-1; - if(new_face->v4) - { - new_face->v4 = vert_index[new_face->v4]-1; - - //Ups translated vertex ended on 0 .. TODO fix this - if(new_face->v4 == 0) - { - } - } - new_face++; - } - } - - //Free memory - bitset_free(used_faces); - MEM_freeN(vert_index); - old->release(old); - - //Update edges - CDDM_calc_edges(new); - CDDM_calc_normals(new); - - calc->final = new; -} - - -void shrinkwrap_projectToCutPlane(ShrinkwrapCalcData *calc_data) -{ - if(calc_data->smd->cutPlane && calc_data->moved) - { - int i; - int unmoved = 0; - int numVerts= 0; - MVert *vert = NULL; - MVert *vert_unmoved = NULL; - - ShrinkwrapCalcData calc; - memcpy(&calc, calc_data, sizeof(calc)); - - calc.moved = 0; - - if(calc.smd->cutPlane) - { - //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array - calc.target = CDDM_copy( object_get_derived_final(calc.smd->cutPlane, CD_MASK_BAREMESH) ); - - if(!calc.target) - { - return; - } - - space_transform_setup(&calc.local2target, calc.ob, calc.smd->cutPlane); - calc.keptDist = 0; - } - - - //Make a mesh with the points we want to project - numVerts = calc_data->final->getNumVerts(calc_data->final); - - unmoved = 0; - for(i=0; imoved, i)) - unmoved++; - - calc.final = CDDM_new(unmoved, 0, 0); - if(!calc.final) return; - - - vert = calc_data->final->getVertDataArray(calc_data->final, CD_MVERT); - vert_unmoved = calc.final->getVertDataArray(calc.final, CD_MVERT); - - for(i=0; imoved, i)) - memcpy(vert_unmoved++, vert+i, sizeof(*vert_unmoved)); - - //use shrinkwrap projection - shrinkwrap_calc_normal_projection(&calc); - - //Copy the points back to the mesh - vert = calc_data->final->getVertDataArray(calc_data->final, CD_MVERT); - vert_unmoved = calc.final->getVertDataArray(calc.final, CD_MVERT); - for(i=0; imoved, i)) - memcpy(vert+i, vert_unmoved++, sizeof(*vert_unmoved) ); - - //free memory - calc.final->release(calc.final); - calc.target->release(calc.target); - } - -} -*/ - /* Main shrinkwrap function */ -/* -DerivedMesh *shrinkwrapModifier_do(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - ShrinkwrapCalcData calc; - memset(&calc, 0, sizeof(calc)); - - //Init Shrinkwrap calc data - calc.smd = smd; - - calc.ob = ob; - calc.original = dm; - calc.final = CDDM_copy(calc.original); - - if(!calc.final) - { - OUT_OF_MEMORY(); - return dm; - } - - CDDM_calc_normals(calc.final); //Normals maybe not be calculated yet + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) if(smd->target == ob) smd->target = NULL; - if(smd->cutPlane == ob) smd->cutPlane = NULL; - - - if(smd->target) - { - //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array - calc.target = CDDM_copy( object_get_derived_final(smd->target, CD_MASK_BAREMESH) ); - - if(!calc.target) - { - printf("Target derived mesh is null! :S\n"); - } - - //TODO there might be several "bugs" on non-uniform scales matrixs.. because it will no longer be nearest surface, not sphere projection - //because space has been deformed - space_transform_setup(&calc.local2target, ob, smd->target); - - calc.keptDist = smd->keptDist; //TODO: smd->keptDist is in global units.. must change to local - } - - //Projecting target defined - lets work! - if(calc.target) - { - - printf("Shrinkwrap (%s)%d over (%s)%d\n", - calc.ob->id.name, calc.final->getNumVerts(calc.final), - calc.smd->target->id.name, calc.target->getNumVerts(calc.target) - ); - - - switch(smd->shrinkType) - { - case MOD_SHRINKWRAP_NEAREST_SURFACE: - BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); -// BENCH(shrinkwrap_calc_foreach_vertex(&calc, bruteforce_shrinkwrap_calc_nearest_surface_point)); - break; - - case MOD_SHRINKWRAP_NORMAL: - - if(calc.smd->shrinkOpts & MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES) - calc.moved = bitset_new( calc.final->getNumVerts(calc.final), "shrinkwrap bitset data"); + if(smd->auxTarget == ob) smd->auxTarget = NULL; -// BENCH(shrinkwrap_calc_normal_projection_raytree(&calc)); -// calc.final->release( calc.final ); -// calc.final = CDDM_copy(calc.original); - - BENCH(shrinkwrap_calc_normal_projection(&calc)); -// BENCH(shrinkwrap_calc_foreach_vertex(&calc, bruteforce_shrinkwrap_calc_normal_projection)); - - if(calc.moved) - { - //Adjust vertxs that didn't moved (project to cut plane) - shrinkwrap_projectToCutPlane(&calc); - - //Destroy faces, edges and stuff - shrinkwrap_removeUnused(&calc); - - //Merge points that didn't moved - derivedmesh_mergeNearestPoints(calc.final, calc.smd->mergeDist, calc.moved); - bitset_free(calc.moved); - } - break; - - case MOD_SHRINKWRAP_NEAREST_VERTEX: - - BENCH(shrinkwrap_calc_nearest_vertex(&calc)); -// BENCH(shrinkwrap_calc_foreach_vertex(&calc, bruteforce_shrinkwrap_calc_nearest_vertex)); - break; - } - - //free derived mesh - calc.target->release( calc.target ); - calc.target = NULL; - } - - CDDM_calc_normals(calc.final); - - return calc.final; -} -*/ - -/* Main shrinkwrap function */ -void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) -{ - - ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; - - //Init Shrinkwrap calc data + //Configure Shrinkwrap calc data calc.smd = smd; - calc.ob = ob; calc.original = dm; - calc.numVerts = numVerts; calc.vertexCos = vertexCos; - //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) - if(smd->target == ob) smd->target = NULL; - if(smd->cutPlane == ob) smd->cutPlane = NULL; - - if(smd->target) { //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array @@ -606,6 +175,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM calc.keptDist = smd->keptDist; //TODO: smd->keptDist is in global units.. must change to local } + //Projecting target defined - lets work! if(calc.target) { @@ -615,14 +185,13 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM calc.smd->target->id.name, calc.target->getNumVerts(calc.target) ); - switch(smd->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); break; - case MOD_SHRINKWRAP_NORMAL: + case MOD_SHRINKWRAP_PROJECT: BENCH(shrinkwrap_calc_normal_projection(&calc)); break; @@ -630,18 +199,18 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM BENCH(shrinkwrap_calc_nearest_vertex(&calc)); break; } + } - //free derived mesh + //free memory + if(calc.target) calc.target->release( calc.target ); - calc.target = NULL; - } } /* * Shrinkwrap to the nearest vertex * * it builds a kdtree of vertexs we can attach to and then - * for each vertex on performs a nearest vertex search on the tree + * for each vertex performs a nearest vertex search on the tree */ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { @@ -653,7 +222,6 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; - BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6)); if(treeData.tree == NULL) return OUT_OF_MEMORY(); @@ -665,29 +233,37 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) for(i = 0; inumVerts; ++i) { float *co = calc->vertexCos[i]; - int index; float tmp_co[3]; float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); if(weight == 0.0f) continue; VECCOPY(tmp_co, co); - space_transform_apply(&calc->local2target, tmp_co); + space_transform_apply(&calc->local2target, tmp_co); //Convert the coordinates to the tree coordinates //Use local proximity heuristics (to reduce the nearest search) + // + //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex + //so we can initiate the "nearest.dist" with the expected value to that last hit. + //This will lead in prunning of the search tree. if(nearest.index != -1) nearest.dist = squared_dist(tmp_co, nearest.co); else nearest.dist = FLT_MAX; - index = BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); + BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); - if(index != -1) + + //Found the nearest vertex + if(nearest.index != -1) { - float dist = nearest.dist; - if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; + //Adjusting the vertex weight, so that after interpolating it kepts a certain distance from the nearest position + float dist = sasqrt(nearest.dist); + if(dist > FLT_EPSILON) weight *= (dist - calc->keptDist)/dist; + //Convert the coordinates back to mesh coordinates VECCOPY(tmp_co, nearest.co); space_transform_invert(&calc->local2target, tmp_co); + VecLerpf(co, co, tmp_co, weight); //linear interpolation } } @@ -763,104 +339,132 @@ int normal_projection_project_vertex(char options, const float *vert, const floa void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) { int i; - int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); - char use_normal = calc->smd->shrinkOpts; - - //setup raytracing - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; - BVHTreeRayHit hit = NULL_BVHTreeRayHit; - //cutTree - DerivedMesh * limit_mesh = NULL; - BVHTreeFromMesh limitData= NULL_BVHTreeFromMesh; - SpaceTransform local2cut; + //Options about projection direction + char use_normal = calc->smd->shrinkOpts; + float proj_axis[3] = {0.0f, 0.0f, 0.0f}; + MVert *vert = NULL; //Needed in case of vertex normal - MVert *vert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MVERT) : NULL; //Needed because of vertex normal + //Vertex group data + int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; - if(vert == NULL) + + //Raycast and tree stuff + BVHTreeRayHit hit; + BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; //target + + //auxiliar target + DerivedMesh * aux_mesh = NULL; + BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh; + SpaceTransform local2aux; + + + //Prepare data to retrieve the direction in which we should project each vertex + if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { - printf("Shrinkwrap cant normal project witouth normal information"); + vert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MVERT) : NULL; + if(vert) CDDM_calc_normals(calc->original); //Maybe normals aren't yet calculated + } + else + { + //The code supports any axis that is a combination of X,Y,Z.. altought currently UI only allows to set the 3 diferent axis + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f; + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f; + if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f; + + Normalize(proj_axis); + } + + if(vert == NULL && (INPR(proj_axis, proj_axis) < FLT_EPSILON)) + { + printf("Shrinkwrap can't project witouth normal information"); return; } - if((use_normal & (MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL | MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)) == 0) - return; //Nothing todo - CDDM_calc_normals(calc->original); //Normals maybe arent yet calculated + //If the user doesn't allows to project in any direction of projection axis... then theres nothing todo. + if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) + return; + + //Build target tree BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, calc->keptDist, 4, 6)); if(treeData.tree == NULL) return OUT_OF_MEMORY(); - - if(calc->smd->cutPlane) + //Build auxiliar target + if(calc->smd->auxTarget) { - space_transform_setup( &local2cut, calc->ob, calc->smd->cutPlane); + space_transform_setup( &local2aux, calc->ob, calc->smd->auxTarget); - //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array - limit_mesh = CDDM_copy( object_get_derived_final(calc->smd->cutPlane, CD_MASK_BAREMESH) ); - if(limit_mesh) - BENCH(bvhtree_from_mesh_faces(&limitData, limit_mesh, 0.0, 4, 6)); + aux_mesh = CDDM_copy( object_get_derived_final(calc->smd->auxTarget, CD_MASK_BAREMESH) ); //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array + if(aux_mesh) + BENCH(bvhtree_from_mesh_faces(&auxData, aux_mesh, 0.0, 4, 6)); else - printf("CutPlane finalDerived mesh is null\n"); + printf("Auxiliar target finalDerived mesh is null\n"); } + + //Now, everything is ready to project the vertexs! + //#pragma omp parallel for private(i) private(hit) schedule(static) for(i = 0; inumVerts; ++i) { float *co = calc->vertexCos[i]; float tmp_co[3], tmp_no[3]; - float lim = 1000; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that + float lim = 1000; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); - char moved = FALSE; if(weight == 0.0f) continue; VECCOPY(tmp_co, co); - NormalShortToFloat(tmp_no, vert[i].no); + + if(vert) + NormalShortToFloat(tmp_no, vert[i].no); + else + VECCOPY( tmp_no, proj_axis ); hit.index = -1; hit.dist = lim; - if(use_normal & MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL) + //Project over positive direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { - if(limitData.tree) - normal_projection_project_vertex(0, tmp_co, tmp_no, &local2cut, limitData.tree, &hit, limitData.raycast_callback, &limitData); + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); - if(normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData)) - moved = TRUE; + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); } - - if(use_normal & MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL) + //Project over negative direction of axis + if(use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) { float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; - if(limitData.tree) - normal_projection_project_vertex(0, tmp_co, inv_no, &local2cut, limitData.tree, &hit, limitData.raycast_callback, &limitData); + if(auxData.tree) + normal_projection_project_vertex(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); - if(normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData)) - moved = TRUE; + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); } if(hit.index != -1) { VecLerpf(co, co, hit.co, weight); - - if(moved && calc->moved) - bitset_set(calc->moved, i); } } + + //free data structures + free_bvhtree_from_mesh(&treeData); - free_bvhtree_from_mesh(&limitData); + free_bvhtree_from_mesh(&auxData); - if(limit_mesh) - limit_mesh->release(limit_mesh); + if(aux_mesh) + aux_mesh->release(aux_mesh); } /* @@ -920,7 +524,14 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) else { float dist = sasqrt( nearest.dist ); - VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keptDist)/dist); //linear interpolation + if(dist > FLT_EPSILON) + { + VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keptDist)/dist); //linear interpolation + } + else + { + VECCOPY( tmp_co, nearest.co ); + } } space_transform_invert(&calc->local2target, tmp_co); VecLerpf(co, co, tmp_co, weight); //linear interpolation diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index cc7bdeef0de..48bacdefcf6 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -321,7 +321,7 @@ typedef struct bShrinkwrapConstraint { Object *target; float dist; /* distance to kept from target */ short shrinkType; /* shrink type (look on MOD shrinkwrap for values) */ - char normalAxis; /* axis to project over UP_X, UP_Y, UP_Z */ + char projAxis; /* axis to project over UP_X, UP_Y, UP_Z */ char pad[9]; } bShrinkwrapConstraint; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index b3d80f2e554..c8db1164dc9 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -496,28 +496,35 @@ typedef struct ShrinkwrapModifierData { ModifierData modifier; struct Object *target; /* shrink target */ - struct Object *cutPlane;/* shrink target */ + struct Object *auxTarget; /* additional shrink target */ char vgroup_name[32]; /* optional vertexgroup name */ float keptDist; /* distance offset from mesh/projection point */ short shrinkType; /* shrink type projection */ short shrinkOpts; /* shrink options */ + char projAxis; /* axis to project over */ + char pad[7]; } ShrinkwrapModifierData; /* Shrinkwrap->shrinkType */ #define MOD_SHRINKWRAP_NEAREST_SURFACE 0 -#define MOD_SHRINKWRAP_NORMAL 1 +#define MOD_SHRINKWRAP_PROJECT 1 #define MOD_SHRINKWRAP_NEAREST_VERTEX 2 /* Shrinkwrap->shrinkOpts */ -#define MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL (1<<0) -#define MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL (1<<1) -/* #define MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES (1<<2) / * Currently dropped to make shrinkwrap a deform only modifier */ +#define MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR (1<<0) /* allow shrinkwrap to move the vertex in the positive direction of axis */ +#define MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR (1<<1) /* allow shrinkwrap to move the vertex in the negative direction of axis */ -#define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) -#define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) +#define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) /* ignore vertex moves if a vertex ends projected on a front face of the target */ +#define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) /* ignore vertex moves if a vertex ends projected on a back face of the target */ + +#define MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE (1<<5) /* distance is measure to the front face of the target */ + +#define MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS (1<<0) +#define MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS (1<<1) +#define MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS (1<<2) +#define MOD_SHRINKWRAP_PROJECT_OVER_NORMAL 0 /* projection over normal is used if no axis is selected */ -#define MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE (1<<5) typedef struct SimpleDeformModifierData { ModifierData modifier; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index bfdd4f0c9a0..583532b6ec8 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1902,8 +1902,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco } else if (md->type==eModifierType_Shrinkwrap) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; height = 86 + 3; - if (smd->shrinkType == MOD_SHRINKWRAP_NORMAL) - height += 19*3; + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT) + height += 19*5; else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) height += 19; @@ -2538,7 +2538,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco } else if (md->type==eModifierType_Shrinkwrap) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; - char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|normal projection %x1|nearest vertex %x2"; + char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|projection %x1|nearest vertex %x2"; uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &smd->target, "Target to shrink to"); @@ -2549,18 +2549,25 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco cy -= 3; uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, lx,(cy-=19),buttonWidth,19, &smd->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); - if (smd->shrinkType == MOD_SHRINKWRAP_NORMAL){ - uiDefButBitS(block, TOG, MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL, B_MODIFIER_RECALC, "Default normal", lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows vertices to move in the normal direction"); - uiDefButBitS(block, TOG, MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL, B_MODIFIER_RECALC, "Invert normal", lx + buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows vertices to move in the inverse direction of their normal"); + if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT){ -/* uiDefButBitS(block, TOG, MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES, B_MODIFIER_RECALC, "Remove faces", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Remove faces where all vertices haven't been projected"); */ + + /* UI for projection axis */ + uiBlockBeginAlign(block); + uiDefButC(block, ROW, B_MODIFIER_RECALC, "Normal" , lx,(cy-=19),buttonWidth,19, &smd->projAxis, 18.0, MOD_SHRINKWRAP_PROJECT_OVER_NORMAL, 0, 0, "Projection over X axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_MODIFIER_RECALC, "X", lx+buttonWidth/3*0,(cy-=19),buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over X axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_MODIFIER_RECALC, "Y", lx+buttonWidth/3*1,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Y axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_MODIFIER_RECALC, "Z", lx+buttonWidth/3*2,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Z axis"); + + + /* allowed directions of projection axis */ + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR, B_MODIFIER_RECALC, "Negative", lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the negative direction of axis"); + uiDefButBitS(block, TOG, MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, B_MODIFIER_RECALC, "Positive", lx + buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows to move the vertex in the positive direction of axis"); uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE, B_MODIFIER_RECALC, "Cull frontfaces",lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a front face on target"); uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, B_MODIFIER_RECALC, "Cull backfaces", lx+buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a back face on target"); - -/* uiDefButF(block, NUM, B_MODIFIER_RECALC, "Merge Dist:", lx,(cy-=19),buttonWidth,19, &smd->mergeDist, 0.0f, 0.01f, 0.01f, 0.01f, "Specify merge distance"); */ - uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ", lx, (cy-=19), buttonWidth,19, &smd->cutPlane, "Aditional mesh to project over"); + uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ", lx, (cy-=19), buttonWidth,19, &smd->auxTarget, "Aditional mesh to project over"); } else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE){ uiDefButBitS(block, TOG, MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE, B_MODIFIER_RECALC, "Above surface", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Vertices are kept on the front side of faces"); diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 524a18a9f3d..370f6999dfc 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -1744,10 +1744,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s case CONSTRAINT_TYPE_SHRINKWRAP: { bShrinkwrapConstraint *data = con->data; - char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|normal projection %x1|nearest vertex %x2"; + char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|projection %x1|nearest vertex %x2"; height = 60; - if(data->shrinkType == MOD_SHRINKWRAP_NORMAL) + if(data->shrinkType == MOD_SHRINKWRAP_PROJECT) height += 18; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); @@ -1762,13 +1762,13 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Type:", *xco + 70, *yco-60, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, *xco+120, *yco-60, 135, 18, &data->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); - if(data->shrinkType == MOD_SHRINKWRAP_NORMAL) + if(data->shrinkType == MOD_SHRINKWRAP_PROJECT) { /* Draw XYZ toggles */ uiDefBut(block, LABEL,B_CONSTRAINT_TEST, "Axis:", *xco+ 75, *yco-78, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); - uiDefButC(block, ROW, B_CONSTRAINT_TEST, "X" , *xco+120, *yco-78, 45, 18, &data->normalAxis, 18.0, UP_X, 0, 0, "Direction of normal projection is x-axis"); - uiDefButC(block, ROW, B_CONSTRAINT_TEST, "Y" , *xco+165, *yco-78, 45, 18, &data->normalAxis, 18.0, UP_Y, 0, 0, "Direction of normal projection is y-axis"); - uiDefButC(block, ROW, B_CONSTRAINT_TEST, "Z" , *xco+210, *yco-78, 45, 18, &data->normalAxis, 18.0, UP_Z, 0, 0, "Direction of normal projection is z-axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_CONSTRAINT_TEST, "X",*xco+120, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over X axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_CONSTRAINT_TEST, "Y",*xco+165, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over Y axis"); + uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_CONSTRAINT_TEST, "Z",*xco+210, *yco-78, 45, 18, &data->projAxis, 0, 0, 0, 0, "Projection over Z axis"); } } break; -- cgit v1.2.3