Index: source/blender/blenkernel/intern/modifier.c =================================================================== --- source/blender/blenkernel/intern/modifier.c (revision 14510) +++ source/blender/blenkernel/intern/modifier.c (working copy) @@ -1266,7 +1266,7 @@ { MirrorModifierData *mmd = (MirrorModifierData*) md; - mmd->flag |= MOD_MIR_AXIS_X; + mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP); mmd->tolerance = 0.001; mmd->mirror_ob = NULL; } @@ -1304,7 +1304,116 @@ DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mirror Modifier"); } } +#define IS_SEPARATOR(a) (a=='.' || a==' ' || a=='-' || a=='_') +/* finds the best possible flipped name. For renaming; check for unique names afterwards */ +/* if strip_number: removes number extensions */ +void vertgroup_flip_name (char *name, int strip_number) +{ + int len; + char prefix[128]={""}; /* The part before the facing */ + char suffix[128]={""}; /* The part after the facing */ + char replace[128]={""}; /* The replacement string */ + char number[128]={""}; /* The number extension string */ + char *index=NULL; + + len= strlen(name); + if(len<3) return; // we don't do names like .R or .L + + /* We first check the case with a .### extension, let's find the last period */ + if(isdigit(name[len-1])) { + index= strrchr(name, '.'); // last occurrance + if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever! + if(strip_number==0) + strcpy(number, index); + *index= 0; + len= strlen(name); + } + } + + strcpy (prefix, name); + + /* first case; separator . - _ with extensions r R l L */ + if( IS_SEPARATOR(name[len-2]) ) { + switch(name[len-1]) { + case 'l': + prefix[len-1]= 0; + strcpy(replace, "r"); + break; + case 'r': + prefix[len-1]= 0; + strcpy(replace, "l"); + break; + case 'L': + prefix[len-1]= 0; + strcpy(replace, "R"); + break; + case 'R': + prefix[len-1]= 0; + strcpy(replace, "L"); + break; + } + } + /* case; beginning with r R l L , with separator after it */ + else if( IS_SEPARATOR(name[1]) ) { + switch(name[0]) { + case 'l': + strcpy(replace, "r"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'r': + strcpy(replace, "l"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'L': + strcpy(replace, "R"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'R': + strcpy(replace, "L"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + } + } + else if(len > 5) { + /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ + index = BLI_strcasestr(prefix, "right"); + if (index==prefix || index==prefix+len-5) { + if(index[0]=='r') + strcpy (replace, "left"); + else { + if(index[1]=='I') + strcpy (replace, "LEFT"); + else + strcpy (replace, "Left"); + } + *index= 0; + strcpy (suffix, index+5); + } + else { + index = BLI_strcasestr(prefix, "left"); + if (index==prefix || index==prefix+len-4) { + if(index[0]=='l') + strcpy (replace, "right"); + else { + if(index[1]=='E') + strcpy (replace, "RIGHT"); + else + strcpy (replace, "Right"); + } + *index= 0; + strcpy (suffix, index+4); + } + } + } + + sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); +} + static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, @@ -1318,6 +1427,9 @@ int maxVerts = dm->getNumVerts(dm); int maxEdges = dm->getNumEdges(dm); int maxFaces = dm->getNumFaces(dm); + int vector_size,j,a,b; + bDeformGroup *def,*defb; + bDeformGroup **vector_def = NULL; int (*indexMap)[2]; float mtx[4][4], imtx[4][4]; @@ -1327,6 +1439,17 @@ result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2); + + if (mmd->flag & MOD_MIR_VGROUP){ + /* calculate the number of deformedGroups */ + for(vector_size = 0, def = ob->defbase.first; def; def = def->next, vector_size++); + + /* load the deformedGroups for fast access */ + vector_def = (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*)*vector_size, "group_index"); + for(a = 0, def = ob->defbase.first; def; def = def->next, a++){ + vector_def[a] = def; + } + } if (mmd->mirror_ob) { float obinv[4][4]; @@ -1336,6 +1459,7 @@ } for(i = 0; i < maxVerts; i++) { + MVert inMV; MVert *mv = CDDM_get_vert(result, numVerts); int isShared; @@ -1371,16 +1495,44 @@ mv->flag |= ME_VERT_MERGED; } else { MVert *mv2 = CDDM_get_vert(result, numVerts); - + MDeformVert *dvert = NULL; + DM_copy_vert_data(dm, result, i, numVerts, 1); *mv2 = *mv; - numVerts++; - + co[axis] = -co[axis]; if (mmd->mirror_ob) { VecMat4MulVecfl(co, imtx, co); } VecCopyf(mv2->co, co); + + if (mmd->flag & MOD_MIR_VGROUP){ + dvert = DM_get_vert_data(result, numVerts, CD_MDEFORMVERT); + + if (dvert) + { + for(j = 0; j < dvert[0].totweight; ++j) + { + char tmpname[32]; + + if(dvert->dw[j].def_nr < 0 || dvert->dw[j].def_nr >= vector_size) continue; + + def = vector_def[dvert->dw[j].def_nr]; + strcpy(tmpname, def->name); + vertgroup_flip_name(tmpname,0); + + for(b = 0, defb = ob->defbase.first; defb; defb = defb->next, b++) + { + if(!strcmp(defb->name, tmpname)) + { + dvert->dw[j].def_nr = b; + break; + } + } + } + } + } + numVerts++; } } @@ -1463,7 +1615,8 @@ numFaces++; } } - + if (vector_def)MEM_freeN(vector_def); + MEM_freeN(indexMap); CDDM_lower_num_verts(result, numVerts); Index: source/blender/blenkernel/intern/pointcache.c =================================================================== --- source/blender/blenkernel/intern/pointcache.c (revision 14510) +++ source/blender/blenkernel/intern/pointcache.c (working copy) @@ -39,6 +39,7 @@ #include "DNA_object_force.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_userdef_types.h" #include "BLI_blenlib.h" @@ -167,7 +168,11 @@ static int ptcache_path(PTCacheID *pid, char *filename) { Library *lib; - int i; + int i,ul; + + ul = strlen(U.cachedir); + + if (ul > 1)/*so we don't get / */ BLI_add_slash(U.cachedir); lib= (pid)? pid->ob->id.lib: NULL; @@ -183,17 +188,22 @@ /* remove .blend */ if (i > 6) file[i-6] = '\0'; + + if (ul > 1) sprintf(filename, "%s%s%s", U.cachedir, PTCACHE_PATH,file);/* add blend file name to pointcache dir */ + else sprintf(filename, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ - sprintf(filename, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ BLI_add_slash(filename); BLI_convertstringcode(filename, blendfilename, 0); + /*printf("Pcache_path = %s \n",filename);*/ return strlen(filename); } /* use the temp path. this is weak but better then not using point cache at all */ /* btempdir is assumed to exist and ALWAYS has a trailing slash */ - sprintf(filename, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid())); + if (ul > 1) sprintf(filename, "%s%s%d", U.cachedir, PTCACHE_PATH, abs(getpid())); + else sprintf(filename, "%s%s%d", btempdir, PTCACHE_PATH, abs(getpid())); BLI_add_slash(filename); + /*printf("Pcache_path = %s \n",filename);*/ return strlen(filename); } Index: source/blender/blenkernel/BKE_pointcache.h =================================================================== --- source/blender/blenkernel/BKE_pointcache.h (revision 14510) +++ source/blender/blenkernel/BKE_pointcache.h (working copy) @@ -30,6 +30,7 @@ #define BKE_POINTCACHE_H #include "DNA_ID.h" +#include "DNA_userdef_types.h" /* Point cache clearing option, for BKE_ptcache_id_clear, before * and after are non inclusive (they wont remove the cfra) */ Index: source/blender/makesdna/DNA_userdef_types.h =================================================================== --- source/blender/makesdna/DNA_userdef_types.h (revision 14510) +++ source/blender/makesdna/DNA_userdef_types.h (working copy) @@ -165,6 +165,7 @@ char plugseqdir[160]; char pythondir[160]; char sounddir[160]; + char cachedir[160]; /* yafray: temporary xml export directory */ char yfexportdir[160]; short versions, vrmlflag; // tmp for export, will be replaced by strubi Index: source/blender/makesdna/DNA_modifier_types.h =================================================================== --- source/blender/makesdna/DNA_modifier_types.h (revision 14510) +++ source/blender/makesdna/DNA_modifier_types.h (working copy) @@ -176,6 +176,7 @@ #define MOD_MIR_AXIS_X 1<<3 #define MOD_MIR_AXIS_Y 1<<4 #define MOD_MIR_AXIS_Z 1<<5 +#define MOD_MIR_VGROUP 1<<6 typedef struct EdgeSplitModifierData { ModifierData modifier; Index: source/blender/include/blendef.h =================================================================== --- source/blender/include/blendef.h (revision 14510) +++ source/blender/include/blendef.h (working copy) @@ -306,6 +306,7 @@ /* yafray: for exportdir select */ #define B_YAFRAYDIRFILESEL 338 #define B_PYMENUEVAL 339 /* re-eval scripts registration in menus */ +#define B_POINTCACHEFILESEL 340 /* END Definitions for the fileselect buttons in user prefs */ /* IMAGE: 350 */ Index: source/blender/src/buttons_editing.c =================================================================== --- source/blender/src/buttons_editing.c (revision 14510) +++ source/blender/src/buttons_editing.c (working copy) @@ -1761,7 +1761,7 @@ } else if (md->type==eModifierType_Build) { height = 86; } else if (md->type==eModifierType_Mirror) { - height = 86; + height = 105; } else if (md->type==eModifierType_Bevel) { BevelModifierData *bmd = (BevelModifierData*) md; height = 105; /* height = 124; */ @@ -1893,6 +1893,7 @@ uiDefButBitS(block, TOG, MOD_MIR_AXIS_Y, B_MODIFIER_RECALC, "Y", lx+20,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Y axis mirror"); uiDefButBitS(block, TOG, MOD_MIR_AXIS_Z, B_MODIFIER_RECALC, "Z", lx+40,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Z axis mirror"); uiDefButBitS(block, TOG, MOD_MIR_CLIPPING, B_MODIFIER_RECALC, "Do Clipping", lx+60, cy, buttonWidth-60,19, &mmd->flag, 1, 2, 0, 0, "Prevents during Transform vertices to go through Mirror"); + uiDefButBitS(block, TOG, MOD_MIR_VGROUP, B_MODIFIER_RECALC, "Mirror Vgroups", lx, (cy-=19), buttonWidth,19, &mmd->flag, 1, 2, 0, 0, "Mirror vertgroups eg .R->.L "); uiDefButBitS(block, TOG, MOD_MIR_MIRROR_U, B_MODIFIER_RECALC, "Mirror U", lx, (cy-=19), buttonWidth/2, 19, Index: source/blender/src/space.c =================================================================== --- source/blender/src/space.c (revision 14510) +++ source/blender/src/space.c (working copy) @@ -4288,6 +4288,15 @@ 0, 0, 0, 0, 0, "Select the default yafray export directory"); uiBlockEndAlign(block); + uiDefBut(block, TEX, 0, "PointCache: ", + (xpos+edgsp+lpref+midsp), y2+buth+rspace, lpref-smfileselbut, buth, + U.cachedir, 1.0, 63.0, 0, 0, + "The default directory for Point Cache files"); + uiDefIconBut(block, BUT, B_POINTCACHEFILESEL, ICON_FILESEL, + (xpos+edgsp+(2*lpref)+midsp-smfileselbut), y2+buth+rspace, smfileselbut, buth, + 0, 0, 0, 0, 0, "Select the default Point Cache Directory"); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); uiDefBut(block, TEX, 0, "Fonts: ", (xpos+edgsp),y2,(lpref-smfileselbut),buth, Index: source/blender/src/headerbuttons.c =================================================================== --- source/blender/src/headerbuttons.c (revision 14510) +++ source/blender/src/headerbuttons.c (working copy) @@ -501,6 +501,18 @@ allqueue(REDRAWALL, 0); } +static void filesel_u_pointcachedir(char *name) +{ + char dir[FILE_MAXDIR], file[FILE_MAXFILE]; + + BLI_cleanup_dir(G.sce, name); + BLI_split_dirfile(name, dir, file); + + strcpy(U.cachedir, dir); + allqueue(REDRAWALL, 0); +} + + static void filesel_u_plugtexdir(char *name) { char dir[FILE_MAXDIR], file[FILE_MAXFILE]; @@ -1449,7 +1461,7 @@ case B_PLAINMENUS: /* is button from space.c *info* */ reset_toolbox(); - break; + break; case B_FLIPINFOMENU: /* is button from space.c *info* */ scrarea_queue_headredraw(curarea); @@ -1477,7 +1489,15 @@ activate_fileselect(FILE_SPECIAL, "SELECT YFEXPORT PATH", U.yfexportdir, filesel_u_yfexportdir); break; - + + case B_POINTCACHEFILESEL: /* is button form space.c *info* */ + if(curarea->spacetype==SPACE_INFO) { + sa= closest_bigger_area(); + areawinset(sa->win); + } + activate_fileselect(FILE_SPECIAL, "SELECT POINTCACHE PATH", U.cachedir, filesel_u_pointcachedir); + break; + case B_FONTDIRFILESEL: /* is button from space.c *info* */ if(curarea->spacetype==SPACE_INFO) { sa= closest_bigger_area();