Cloth: fixed completely useless/wrong friction force; changed some initial settings
[blender.git] / source / blender / src / buttons_object.c
index 8451a4c8afd8a636b6a5e150c906993caef02aec..da06351404ec9203050f29ad1eaf1cfa8f6b6fb4 100644 (file)
@@ -47,6 +47,7 @@
 #include "DNA_scene_types.h"
 
 #include "BKE_action.h"
+#include "BKE_cloth.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_library.h"
@@ -89,6 +90,7 @@
 #include "DNA_action_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_camera_types.h"
+#include "DNA_cloth_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_effect_types.h"
@@ -190,15 +192,18 @@ static void constraint_active_func(void *ob_v, void *con_v)
 
 static void add_constraint_to_active(Object *ob, bConstraint *con)
 {
-       ListBase *list;
+       ListBase *list= get_active_constraints(ob);
+       bPoseChannel *pchan= get_active_posechannel(ob);
        
-       list = get_active_constraints(ob);
        if (list) {
                unique_constraint_name(con, list);
                BLI_addtail(list, con);
                
+               if (proxylocked_constraints_owner(ob, pchan))
+                       con->flag |= CONSTRAINT_PROXY_LOCAL;
+               
                con->flag |= CONSTRAINT_ACTIVE;
-               for(con= con->prev; con; con= con->prev)
+               for (con= con->prev; con; con= con->prev)
                        con->flag &= ~CONSTRAINT_ACTIVE;
        }
 }
@@ -209,8 +214,7 @@ static void get_constraint_ipo_context(void *ob_v, char *actname)
 {
        Object *ob= ob_v;
        
-       /* todo; check object if it has ob-level action ipo */
-       
+       /* todo: check object if it has ob-level action ipo */
        if (ob->flag & OB_POSEMODE) {
                bPoseChannel *pchan;
                
@@ -503,12 +507,15 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short
 static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco)
 {
        Object *ob= OBACT;
+       bPoseChannel *pchan= get_active_posechannel(ob);
        bConstraintTypeInfo *cti;
        uiBut *but;
        char typestr[32];
        short height, width = 265;
+       short proxy_protected;
        int rb_col;
 
+       /* get constraint typeinfo */
        cti= constraint_get_typeinfo(con);
        if (cti == NULL) {
                /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
@@ -520,6 +527,13 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
        else
                strcpy(typestr, cti->name);
                
+       /* determine whether constraint is proxy protected or not */
+       if (proxylocked_constraints_owner(ob, pchan)) {
+               proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
+       }
+       else
+               proxy_protected= 0;
+               
        /* unless button has own callback, it adds this callback to button */
        uiBlockSetFunc(block, constraint_active_func, ob, con);
 
@@ -534,17 +548,8 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
        /* open/close */
        uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_DISCLOSURE_TRI_RIGHT, *xco-10, *yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
        
-       /* up/down */
-       uiBlockBeginAlign(block);
-       uiBlockSetEmboss(block, UI_EMBOSS);
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
-       uiButSetFunc(but, constraint_moveUp, ob, con);
-       
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
-       uiButSetFunc(but, constraint_moveDown, ob, con);
-       uiBlockEndAlign(block);
-       
-       if (con->flag & CONSTRAINT_EXPAND) {
+       /* name */      
+       if ((con->flag & CONSTRAINT_EXPAND) && (proxy_protected==0)) {
                if (con->flag & CONSTRAINT_DISABLE)
                        uiBlockSetCol(block, TH_REDALERT);
                
@@ -568,14 +573,69 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
 
        uiBlockSetCol(block, TH_AUTO);  
        
-       uiBlockSetEmboss(block, UI_EMBOSSN);
+       /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
+       if (proxy_protected) {
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               
+               /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
+               uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, *xco+244, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
+               uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, *xco+262, *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
+               
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+       else {
+               short prev_proxylock, show_upbut, show_downbut;
+               
+               /* Up/Down buttons: 
+                *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
+                *      as that poses problems when restoring them, so disable the "up" button where
+                *      it may cause this situation. 
+                *
+                *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
+                */
+               if (proxylocked_constraints_owner(ob, pchan)) {
+                       if (con->prev) {
+                               prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
+                       }
+                       else
+                               prev_proxylock= 0;
+               }
+               else
+                       prev_proxylock= 0;
+                       
+               show_upbut= ((prev_proxylock == 0) && (con->prev));
+               show_downbut= (con->next) ? 1 : 0;
+               
+               if (show_upbut || show_downbut) {
+                       uiBlockBeginAlign(block);
+                               uiBlockSetEmboss(block, UI_EMBOSS);
+                               
+                               if (show_upbut) {
+                                       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
+                                       uiButSetFunc(but, constraint_moveUp, ob, con);
+                               }
+                               
+                               if (show_downbut) {
+                                       but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
+                                       uiButSetFunc(but, constraint_moveDown, ob, con);
+                               }
+                       uiBlockEndAlign(block);
+               }
+               
+               
+               /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+               
+                       but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
+                       uiButSetFunc(but, del_constraint_func, ob, con);
+               
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+       
+       /* Set but-locks for protected settings (magic numbers are used here!) */
+       if (proxy_protected)
+               uiSetButLock(1, "Cannot edit Proxy-Protected Constraint");
        
-       but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
-       uiButSetFunc(but, del_constraint_func, ob, con);
-
-       uiBlockSetEmboss(block, UI_EMBOSS);
-
-
        /* Draw constraint data */
        if ((con->flag & CONSTRAINT_EXPAND) == 0) {
                (*yco) -= 21;
@@ -601,7 +661,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                menustr = buildmenu_pyconstraints(data->text, &pyconindex);
                                but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
                                      *xco+120, *yco-24, 150, 20, &pyconindex,
-                                     0.0, 1.0, 0, 0, "Set the Script Constraint to use");
+                                     00, 0, 0, "Set the Script Constraint to use");
                                uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
                                MEM_freeN(menustr);     
                                
@@ -613,8 +673,8 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                                short yoffset= ((tarnum-1) * 38);
                                                
                                                /* target label */
-                                               sprintf(tarstr, "Target %02d:", tarnum);
-                                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+45, *yco-(48+yoffset), 60, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+                                               sprintf(tarstr, "Target %d:", tarnum);
+                                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+45, *yco-(48+yoffset), 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
                                                
                                                /* target space-selector - per target */
                                                if (is_armature_target(ct->tar)) {
@@ -772,10 +832,10 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                /* Inverse options */
                                uiBlockBeginAlign(block);
                                        but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", *xco, *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)");
-                                       uiButSetFunc(but, childof_const_setinv, data, NULL);
+                                       uiButSetFunc(but, childof_const_setinv, con, NULL);
                                        
                                        but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", *xco+((width/2)+10), *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)");
-                                       uiButSetFunc(but, childof_const_clearinv, data, NULL);
+                                       uiButSetFunc(but, childof_const_clearinv, con, NULL);
                                uiBlockEndAlign(block);
                        }
                        break;
@@ -1215,12 +1275,12 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                
                                uiBlockBeginAlign(block);
                                        if (is_armature_target(data->tar)) {
-                                               uiDefButF(block, BUTM, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength");
+                                               uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength");
                                                uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Rest Length:", *xco+18, *yco-60,139,18, &data->orglength, 0.0, 100, 0.5, 0.5, "Length at Rest Position");
-                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,97,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1");
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,98,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1");
                                        }
                                        else {
-                                               uiDefButF(block, BUTM, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength");
+                                               uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->orglength, 0.0, 0, 0, 0, "Recalculate RLength");
                                                uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Rest Length:", *xco+18, *yco-60, 237, 18, &data->orglength, 0.0, 100, 0.5, 0.5, "Length at Rest Position");
                                        }
                                uiBlockEndAlign(block);
@@ -1295,7 +1355,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                bRotLimitConstraint *data = con->data;
                                int normButWidth = (width/3);
                                
-                               height = 106; 
+                               height = 136; 
                                
                                uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
                                
@@ -1318,8 +1378,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                        uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-72, normButWidth, 18, &(data->zmax), -360, 360, 0.1,0.5,"Highest z value to allow"); 
                                uiBlockEndAlign(block); 
                                
+                               /* special option(s) */
+                               uiDefButBitS(block, TOG, LIMIT_TRANSFORM, B_CONSTRAINT_TEST, "For Transform", *xco+(width/4), *yco-100, (width/2), 18, &data->flag2, 0, 24, 0, 0, "Transforms are affected by this constraint as well"); 
+                               
                                /* constraint space settings */
-                               draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1);
+                               draw_constraint_spaceselect(block, con, *xco, *yco-130, is_armature_owner(ob), -1);
                        }
                        break;
                case CONSTRAINT_TYPE_SIZELIMIT:
@@ -1329,7 +1392,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                int togButWidth = 50;
                                int textButWidth = ((width/2)-togButWidth);
                                
-                               height = 106; 
+                               height = 136; 
                                        
                                uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
                                
@@ -1366,8 +1429,59 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                        uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), 0.0001, 1000, 0.1,0.5,"Highest z value to allow"); 
                                uiBlockEndAlign(block);
                                
+                               /* special option(s) */
+                               uiDefButBitS(block, TOG, LIMIT_TRANSFORM, B_CONSTRAINT_TEST, "For Transform", *xco+(width/4), *yco-100, (width/2), 18, &data->flag2, 0, 24, 0, 0, "Transforms are affected by this constraint as well"); 
+                               
                                /* constraint space settings */
-                               draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1);
+                               draw_constraint_spaceselect(block, con, *xco, *yco-130, is_armature_owner(ob), -1);
+                       }
+                       break;
+               case CONSTRAINT_TYPE_DISTLIMIT:
+                       {
+                               bDistLimitConstraint *data = con->data;
+                               
+                               height = 105;
+                               uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
+                               
+                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+                               
+                               /* Draw target parameters */
+                               uiBlockBeginAlign(block);
+                                       uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); 
+                                       
+                                       if (is_armature_target(data->tar)) {
+                                               but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+                                               uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+                                       }
+                                       else if (is_geom_target(data->tar)) {
+                                               but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+                                               uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+                                       }
+                                       else {
+                                               strcpy(data->subtarget, "");
+                                       }
+                               uiBlockEndAlign(block);
+                               
+                               uiBlockBeginAlign(block);
+                                       if (is_armature_target(data->tar)) {
+                                               uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); 
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60,139,18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere");
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,100,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1");
+                                       }
+                                       else {
+                                               uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); 
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60, 237, 18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere");
+                                       }
+                                       
+                                       /* disabled soft-distance controls... currently it doesn't work yet. It was intended to be used for soft-ik (see xsi-blog for details) */
+#if 0
+                                       uiDefButBitS(block, TOG, LIMITDIST_USESOFT, B_CONSTRAINT_TEST, "Soft", *xco, *yco-82, 50, 18, &data->flag, 0, 24, 0, 0, "Enables soft-distance");
+                                       if (data->flag & LIMITDIST_USESOFT)
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Soft-Distance:", *xco+50, *yco-82, 187, 18, &data->soft, 0.0, 100, 0.5, 0.5, "Distance surrounding radius when transforms should get 'delayed'");
+#endif
+                               uiBlockEndAlign(block);
+                               
+                               uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Limit Mode%t|Inside %x0|Outside %x1|Surface %x2", *xco+((width/2)-50), *yco-104, 100, 18, &data->mode, 0, 24, 0, 0, "Distances in relation to sphere of influence to allow");
                        }
                        break;
                case CONSTRAINT_TYPE_RIGIDBODYJOINT:
@@ -1520,7 +1634,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                                uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
                                        }
                                        else if (is_geom_target(data->tar)) {
-                                               but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+                                               but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
                                                uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
                                        }
                                        else {
@@ -1649,6 +1763,9 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
        else {
                (*yco)-=3;
        }
+       
+       /* clear any locks set up for proxies/lib-linking */
+       uiClearButLock();
 }
 
 static uiBlock *add_constraintmenu(void *arg_unused)
@@ -1676,6 +1793,7 @@ static uiBlock *add_constraintmenu(void *arg_unused)
        uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCLIMIT, "Limit Location", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
        uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ROTLIMIT, "Limit Rotation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
        uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SIZELIMIT, "Limit Scale", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+       uiDefBut(block, BUTM, B_CONSTRAINT_ADD_DISTLIMIT, "Limit Distance", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
        
        uiDefBut(block, SEPR, 0, "",                                    0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
        
@@ -1908,6 +2026,14 @@ void do_constraintbuts(unsigned short event)
                        BIF_undo_push("Add constraint");
                }
                break;
+       case B_CONSTRAINT_ADD_DISTLIMIT:
+               {
+                       con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT);
+                       add_constraint_to_active(ob, con);
+                       
+                       BIF_undo_push("Add constraint");
+               }
+               break;
 
        default:
                break;
@@ -2096,7 +2222,7 @@ void do_object_panels(unsigned short event)
        case B_DUPLI_VERTS:
                ob->transflag &= ~(OB_DUPLIFRAMES|OB_DUPLIFACES|OB_DUPLIGROUP);
                DAG_scene_sort(G.scene);
-               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA|OB_RECALC_OB);
                allqueue(REDRAWVIEW3D, 0);
                allqueue(REDRAWBUTSOBJECT, 0);
                break;
@@ -2227,6 +2353,78 @@ void do_object_panels(unsigned short event)
                if(ob->ipo) ob->ipo->showkey= (ob->ipoflag & OB_DRAWKEY)?1:0;
                allqueue(REDRAWVIEW3D, 0);
                break;
+       case B_CLOTH_CLEARCACHEALL:
+       {
+               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+               if(clmd)
+               {
+                       // do nothing in editmode
+                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
+                               break;
+                       
+                       /* force freeing because user wants */
+                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
+                       
+                       /*user wants to free all, so free whole cloth, this helps to start sim at later frame */
+                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
+                       
+                       CFRA= 1;
+                       update_for_newframe_muted();
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
+                       cloth_clear_cache(ob, clmd, 0); 
+                       allqueue(REDRAWBUTSOBJECT, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+               }       
+       }
+       break;  
+       case B_CLOTH_CLEARCACHEFRAME:
+       {
+               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+               if(clmd)
+               {
+                       // do nothing in editmode
+                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
+                               break;
+                       
+                       /* force freeing because user wants */
+                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE;
+                       
+                       cloth_clear_cache(ob, clmd, MAX2(0.0,G.scene->r.cfra)); 
+                       // MAX2(1.0,G.scene->r.cfra + 1.0)
+                       allqueue(REDRAWBUTSOBJECT, 0);
+               }
+       }
+       break;  
+       case B_CLOTH_CHANGEPREROLL:
+       {
+               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+               if(clmd)
+               {
+                       // do nothing in editmode
+                       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE)
+                               break;
+                       
+                       CFRA= 1;
+                       update_for_newframe_muted();
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
+                       allqueue(REDRAWBUTSOBJECT, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       break;  
+       case B_CLOTH_RENEW:
+       {
+               ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       
+               if(clmd)
+               {
+                       clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET;
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); 
+                       allqueue(REDRAWBUTSOBJECT, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       break;
                
        default:
                if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
@@ -2294,8 +2492,7 @@ static void group_ob_rem(void *gr_v, void *ob_v)
 {
        Object *ob= OBACT;
        
-       rem_from_group(gr_v, ob);
-       if(find_group(ob)==NULL) {
+       if(rem_from_group(gr_v, ob) && find_group(ob, NULL)==NULL) {
                ob->flag &= ~OB_FROMGROUP;
                BASACT->flag &= ~OB_FROMGROUP;
        }
@@ -2388,9 +2585,16 @@ static void object_panel_object(Object *ob)
                uiNewPanelHeight(block, 204 - (120-yco));
 }
 
+static void object_panel_anim_timeoffset_callback( void *data, void *timeoffset_ui) {
+       Object *ob = (Object *)data;
+       ob->sf = (*(float *)timeoffset_ui) - (give_timeoffset(ob) - ob->sf);
+}
+
 static void object_panel_anim(Object *ob)
 {
        uiBlock *block;
+       uiBut *but;
+       static float timeoffset_ui;
        char str[32];
        
        block= uiNewBlock(&curarea->uiblocks, "object_panel_anim", UI_EMBOSS, UI_HELV, curarea->win);
@@ -2439,19 +2643,29 @@ static void object_panel_anim(Object *ob)
        uiDefButI(block, NUM, REDRAWVIEW3D, "DupOn:",           170,85,146,19, &ob->dupon, 1.0, 1500.0, 0, 0, "Specify the number of frames to use between DupOff frames");
        uiDefButI(block, NUM, REDRAWVIEW3D, "DupEnd",           24,65,140,19, &ob->dupend, 1.0, 32767, 0, 0, "Specify endframe for Dupliframes");
        uiDefButI(block, NUM, REDRAWVIEW3D, "DupOff",           171,65,145,19, &ob->dupoff, 0.0, 1500.0, 0, 0, "Specify recurring frames to exclude from the Dupliframes");
+       uiBlockEndAlign(block);
+       
        uiBlockBeginAlign(block);
-       uiDefButBitS(block, TOG, OB_OFFS_OB, REDRAWALL, "Offs Ob",                      24,35,56,20, &ob->ipoflag, 0, 0, 0, 0, "Not functional at the moment!");
-       uiDefButBitS(block, TOG, OB_OFFS_PARENT, REDRAWALL, "Offs Par",                 82,35,56,20 , &ob->ipoflag, 0, 0, 0, 0, "Let the timeoffset work on the parent");
-       uiDefButBitS(block, TOG, OB_OFFS_PARTICLE, REDRAWALL, "Offs Particle",          140,35,103,20, &ob->ipoflag, 0, 0, 0, 0, "Let the timeoffset work on the particle effect");
+       
+       timeoffset_ui = give_timeoffset(ob);
+       but = uiDefButF(block, NUM, REDRAWALL, "TimeOffset:",                   24,35,115,20, &timeoffset_ui, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Animation offset in frames for ipo's and dupligroup instances");
+       uiButSetFunc(but, object_panel_anim_timeoffset_callback, ob, &timeoffset_ui);
+       
+       uiDefBut(block, BUT, B_AUTOTIMEOFS, "Auto",     139,35,34,20, 0, 0, 0, 0, 0, "Assign selected objects a timeoffset within a range, starting from the active object");
+       uiDefBut(block, BUT, B_OFSTIMEOFS, "Ofs",       173,35,34,20, 0, 0, 0, 0, 0, "Offset selected objects timeoffset");
+       uiDefBut(block, BUT, B_RANDTIMEOFS, "Rand",     207,35,34,20, 0, 0, 0, 0, 0, "Randomize selected objects timeoffset");
+       uiDefBut(block, BUT, B_PRINTSPEED,      "PrSpeed",                      250,35,65,20, 0, 0, 0, 0, 0, "Print objectspeed");
+       uiBlockEndAlign(block);
        
        uiBlockBeginAlign(block);
-       uiDefButF(block, NUM, REDRAWALL, "TimeOffset:",                 24,10,115,20, &ob->sf, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify an offset in frames");
-       uiDefBut(block, BUT, B_AUTOTIMEOFS, "Automatic Time",   139,10,104,20, 0, 0, 0, 0, 0, "Generate automatic timeoffset values for all selected frames");
-       uiDefBut(block, BUT, B_PRINTSPEED,      "PrSpeed",                      248,10,67,20, 0, 0, 0, 0, 0, "Print objectspeed");
+       uiDefButBitS(block, TOG, OB_OFFS_OB, REDRAWALL, "OfsEdit",                      24,10,56,20, &ob->ipoflag, 0, 0, 0, 0, "Use timeoffset when inserting keys and display timeoffset for ipo and action views");
+       uiDefButBitS(block, TOG, OB_OFFS_PARENT, REDRAWALL, "OfsParent",                        82,10,56,20 , &ob->ipoflag, 0, 0, 0, 0, "Apply the timeoffset to this objects parent relationship");
+       uiDefButBitS(block, TOG, OB_OFFS_PARTICLE, REDRAWALL, "OfsParticle",            140,10,56,20, &ob->ipoflag, 0, 0, 0, 0, "Let the timeoffset work on the particle effect");
+       uiDefButBitS(block, TOG, OB_OFFS_PARENTADD, REDRAWALL, "AddParent",             196,10,56,20, &ob->ipoflag, 0, 0, 0, 0, "Add the parents timeoffset value");
        uiBlockEndAlign(block);
        
        sprintf(str, "%.4f", prspeed);
-       uiDefBut(block, LABEL, 0, str,                                                  247,35,63,31, NULL, 1.0, 0, 0, 0, "");
+       uiDefBut(block, LABEL, 0, str,                                                  260,10,63,31, NULL, 1.0, 0, 0, 0, "");
        
 }
 
@@ -2592,6 +2806,12 @@ void do_effects_panels(unsigned short event)
     case B_AUTOTIMEOFS:
                auto_timeoffs();
                break;
+    case B_OFSTIMEOFS:
+               ofs_timeoffs();
+               break;
+    case B_RANDTIMEOFS:
+               rand_timeoffs();
+               break;
        case B_FRAMEMAP:
                G.scene->r.framelen= G.scene->r.framapto;
                G.scene->r.framelen/= G.scene->r.images;
@@ -2871,6 +3091,10 @@ void do_effects_panels(unsigned short event)
                        allqueue(REDRAWOOPS, 0);
                }
                /* no break! */
+       case B_PART_REDRAW_DEPS:
+               if(event == B_PART_REDRAW_DEPS)
+                       DAG_scene_sort(G.scene);
+               /* no break! */
        case B_PART_REDRAW:
                nr=0;
                for(psys=ob->particlesystem.first; psys; psys=psys->next){
@@ -3021,10 +3245,38 @@ static void field_testTexture(char *name, ID **idpp)
        }
        *idpp = 0;
 }
+
+/* Panel for collision */
+static void object_collision__enabletoggle ( void *ob_v, void *arg2 )
+{
+       Object *ob = ob_v;
+       PartDeflect *pd= ob->pd;
+       ModifierData *md = modifiers_findByType ( ob, eModifierType_Collision );
+       
+       if ( !md )
+       {
+               if(pd && (pd->deflect))
+               {
+                       md = modifier_new ( eModifierType_Collision );
+                       BLI_addhead ( &ob->modifiers, md );
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+                       allqueue(REDRAWBUTSEDIT, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       else
+       {
+               BLI_remlink ( &ob->modifiers, md );
+               modifier_free ( md );
+               allqueue(REDRAWBUTSEDIT, 0);
+       }
+}
+
 /* Panels for particle interaction settings */
 static void object_panel_deflection(Object *ob)
 {
        uiBlock *block;
+       uiBut *but;
 
        block= uiNewBlock(&curarea->uiblocks, "object_panel_deflection", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Deflection", "Physics", 0, 0, 318, 204)==0) return;
@@ -3044,7 +3296,9 @@ static void object_panel_deflection(Object *ob)
        if(ob->pd && ob->type==OB_MESH) {
                PartDeflect *pd= ob->pd;
                
-               uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
+               but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
+               uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
+               
                if(pd->deflect) {
                        uiDefBut(block, LABEL, 0, "Particles",                  160,140,75,20, NULL, 0.0, 0, 0, 0, "");
                        uiDefButBitS(block, TOG, PDEFLE_KILL_PART, B_DIFF, "Kill",235,140,75,20, &pd->flag, 0, 0, 0, 0, "Kill collided particles");
@@ -3057,7 +3311,7 @@ static void object_panel_deflection(Object *ob)
                        uiDefButF(block, NUM, B_DIFF, "Permeability: ", 160,80,150,20, &pd->pdef_perm, 0.0, 1.0, 10, 0, "Chance that the particle will pass through the mesh");
                        uiBlockEndAlign(block);
                        
-                       uiDefBut(block, LABEL, 0, "Soft Body",                  160,60,150,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, "Soft Body / Cloth",                  160,60,150,20, NULL, 0.0, 0, 0, 0, "");
 
                        uiBlockBeginAlign(block);
                        uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:",       160,40,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
@@ -3121,9 +3375,9 @@ static void object_panel_fields(Object *ob)
                        sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d", 
                                        PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC);
 
-                       if(pd->forcefield==PFIELD_FORCE) tipstr= "Particle attracts or repels particles";
-                       else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of particle Z axis";
-                       else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the particle";
+                       if(pd->forcefield==PFIELD_FORCE) tipstr= "Particle attracts or repels particles (On shared object layers)";
+                       else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of particle Z axis (On shared object layers)";
+                       else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the particle (On shared object layers)";
                }
                else{
                        if(ob->type==OB_CURVE)
@@ -3133,10 +3387,10 @@ static void object_panel_fields(Object *ob)
                                sprintf(menustr, "Field Type%%t|None%%x0|Spherical%%x%d|Wind%%x%d|Vortex%%x%d|Magnetic%%x%d|Harmonic%%x%d|Texture%%x%d", 
                                                PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_MAGNET, PFIELD_HARMONIC, PFIELD_TEXTURE);
 
-                       if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles";
-                       else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis";
-                       else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the Object";
-                       else if(pd->forcefield==PFIELD_GUIDE) tipstr= "Use a Curve Path to guide particles";
+                       if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles (On shared object layers)";
+                       else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis (On shared object layers)";
+                       else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the Object (On shared object layers)";
+                       else if(pd->forcefield==PFIELD_GUIDE) tipstr= "Use a Curve Path to guide particles (On shared object layers)";
                }
                
                if(ob->particlesystem.first)
@@ -3158,12 +3412,13 @@ static void object_panel_fields(Object *ob)
                                uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ",      50,80,100,20, &pd->maxdist, 0, 1000.0, 10, 0, "Maximum distance for the field to work");
                        }
                        else {
-                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ",     10,140,140,20, &pd->f_strength, -1000, 1000, 10, 0, "Strength of force field");
+                               uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ",     10,140,140,20, &pd->f_strength, -1000, 1000, 10, 3, "Strength of force field");
                                
                                if(pd->forcefield == PFIELD_TEXTURE){
                                        uiDefIDPoinBut(block, field_testTexture, ID_TE, B_FIELD_CHANGE, "Texture: ", 10, 120, 140, 20, &pd->tex, "Texture to use as force");
                                        uiDefButBitS(block, TOG, PFIELD_TEX_OBJECT, B_FIELD_CHANGE, "Use Object Co",    10,100,140,20, &pd->flag, 0.0, 0, 0, 0, "Use object/global coordinates for texture");
-                                       uiDefButBitS(block, TOG, PFIELD_TEX_2D, B_FIELD_CHANGE, "2D",   10,80,140,20, &pd->flag, 0.0, 0, 0, 0, "Apply force only in 2d");
+                                       uiDefButBitS(block, TOG, PFIELD_TEX_ROOTCO, B_FIELD_CHANGE, "Root TexCo",       10,80,120,20, &pd->flag, 0.0, 0, 0, 0, "Texture coords from root particle locations");
+                                       uiDefButBitS(block, TOG, PFIELD_TEX_2D, B_FIELD_CHANGE, "2D",   130,80,20,20, &pd->flag, 0.0, 0, 0, 0, "Apply force only in 2d");
                                }
                                else if(pd->forcefield == PFIELD_HARMONIC) 
                                        uiDefButF(block, NUM, B_FIELD_CHANGE, "Damp: ", 10,120,140,20, &pd->f_damp, 0, 10, 10, 0, "Damping of the harmonic force");     
@@ -3175,7 +3430,7 @@ static void object_panel_fields(Object *ob)
                                uiDefButBitS(block, TOG, PFIELD_GUIDE_PATH_ADD, B_FIELD_CHANGE, "Additive",     10,40,140,20, &pd->flag, 0.0, 0, 0, 0, "Based on distance/falloff it adds a portion of the entire path");
                        }
                        else if(pd->forcefield==PFIELD_TEXTURE){
-                               uiDefButS(block, MENU, B_FIELD_CHANGE, "Texture mode%t|RGB%x0|Gradient%x1|Curl%x2",     10,40,140,20, &pd->tex_mode, 0.0, 0.0, 0, 0, "How the texture effect is calculated (RGB & Curl need a RGB texture)");
+                               uiDefButS(block, MENU, B_FIELD_CHANGE, "Texture mode%t|RGB%x0|Gradient%x1|Curl%x2",     10,40,140,20, &pd->tex_mode, 0.0, 0.0, 0, 0, "How the texture effect is calculated (RGB & Curl need a RGB texture else Gradient will be used instead)");
        
                                uiDefButF(block, NUM, B_FIELD_CHANGE, "Nabla:", 10,20,140,20, &pd->tex_nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient and curl calculation");
                        }
@@ -3307,10 +3562,20 @@ static void object_softbodies__enable_psys(void *ob_v, void *psys_v)
        allqueue(REDRAWBUTSEDIT, 0);
 }
 
-static void object_softbodies_II(Object *ob)
+
+#ifdef _work_on_sb_solver
+static char sbsolvers[] = "Solver %t|RKP almost SOFT not usable but for some german teachers %x1|STU ip semi implicit euler%x3|SI1  (half step)adaptive semi implict euler %x2|SI2  (use dv)adaptive semi implict euler %x4|SOFT  step size controlled midpoint(1rst choice for real softbodies)%x0";
+/* SIF would have been candidate  .. well lack of time .. brecht is busy .. better make a stable version for peach now :) */
+static char sbsolvers[] = "SIF  semi implicit euler with fixed step size (worth a try with real stiff egdes)%x3|SOFT  step size controlled midpoint(1rst choice for real softbodies)%x0";
+#else
+static char sbsolvers[] = "RKCP correct physics (harder to get stable but usefull for education :)%x1|SOFT  step size controlled midpoint(1rst choice for real softbodies)%x0";
+#endif
+
+static void object_softbodies_collision(Object *ob)
 {
        SoftBody *sb=ob->soft;
        uiBlock *block;
+       uiBut *but = NULL;
        static int val;
        short *softflag=&ob->softflag, psys_cur=0;
        int ob_has_hair=psys_ob_has_hair(ob);
@@ -3322,8 +3587,8 @@ static void object_softbodies_II(Object *ob)
                ob->pd->pdef_sbift  = 0.2f;
                ob->pd->pdef_sboft  = 0.02f;
        }
-       block= uiNewBlock(&curarea->uiblocks, "object_softbodies_II", UI_EMBOSS, UI_HELV, curarea->win);
-       uiNewPanelTabbed("Soft Body", "Physics");
+       block= uiNewBlock(&curarea->uiblocks, "object_softbodies_collision", UI_EMBOSS, UI_HELV, curarea->win);
+       // uiNewPanelTabbed("Soft Body", "Physics"); /*don't really want it tabbed first */
        if(uiNewPanel(curarea, block, "Soft Body Collision", "Physics", 651, 0, 318, 204)==0) return;
 
        uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
@@ -3362,7 +3627,8 @@ static void object_softbodies_II(Object *ob)
                /* OTHER OBJECTS COLLISION STUFF */
                if (ob->type==OB_MESH){
                        uiBlockBeginAlign(block);
-                       uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to softbody objects");
+                       but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to softbody objects");
+                       uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
                        if(ob->pd->deflect) {
                                uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:",       160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
                                uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
@@ -3396,17 +3662,12 @@ static void object_softbodies_II(Object *ob)
 
                        uiBlockEndAlign(block);
                        /*SOLVER SETTINGS*/
-                       uiDefButF(block, NUM, B_DIFF, "Error Lim:",     10,100,130,20, &sb->rklimit , 0.001, 10.0, 10, 0, "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed");
-                       uiDefButBitS(block, TOG, SBSO_OLDERR, B_DIFF,"O", 140,100,20,20, &sb->solverflags,  0,  0, 0, 0, "Old Error Calculation");
-                       uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 160,100,130,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
-                       uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"M", 290,100,20,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");
-                       uiDefButS(block, NUM, B_DIFF, "MinS:", 10,80,100,20, &sb->minloops,  0.00,  30000.0, 10, 0, "Minimal # solver steps/frame ");
-                       uiDefButS(block, NUM, B_DIFF, "MaxS:", 110,80,100,20, &sb->maxloops,  0.00,  30000.0, 10, 0, "Maximal # solver steps/frame ");
-                       uiDefButS(block, NUM, B_DIFF, "Choke:", 210,80,100,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
+                       /* done in another panel now*/
                }
                /* OTHER OBJECTS COLLISION STUFF */
                if (ob->type==OB_MESH){
-                       uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to other softbody objects");
+                       but = uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to other softbody objects");
+                       uiButSetFunc(but, object_collision__enabletoggle, ob, NULL);
                        if(ob->pd->deflect) {
                                uiDefButF(block, NUM, B_DIFF, "Damping:",       160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
                            uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
@@ -3418,6 +3679,101 @@ static void object_softbodies_II(Object *ob)
        }
        uiBlockEndAlign(block);
 }
+static void object_softbodies_solver(Object *ob)
+{
+       SoftBody *sb=ob->soft;
+       uiBlock *block;
+       static int val;
+       short *softflag=&ob->softflag, psys_cur=0, adaptive_mode=0;
+       int ob_has_hair=psys_ob_has_hair(ob);
+       if(!_can_softbodies_at_all(ob)) return;
+       block= uiNewBlock(&curarea->uiblocks, "object_softbodies_solver", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Soft Body Solver", "Physics", 651, 0, 318, 204)==0) return;
+
+       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       /* doubt that is really needed here but for now */ 
+       if(ob_has_hair) {
+               if(PE_get_current_num(ob) >= 0) {
+                       ParticleSystem *psys = PE_get_current(ob);
+                       if(psys) {
+                               sb = psys->soft;
+                               softflag = &psys->softflag;
+                               psys_cur = 1;
+                       }
+               }
+       }
+
+       if(psys_cur) {
+               if(*softflag & OB_SB_ENABLE)
+                       val = 1;
+               else
+                       val = 0;
+       }
+       else
+               val = modifiers_isSoftbodyEnabled(ob);
+
+       if(!val) { 
+               uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+               if(psys_cur){
+                       uiDefBut(block, LABEL, 0, "Hair is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
+               }
+               else {
+                       uiDefBut(block, LABEL, 0, "Object is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, ""); 
+               }
+       }
+       else{ 
+               if ((ob->type==OB_MESH)||(ob->type==OB_CURVE) ) {
+                       /*SOLVER SETTINGS*/
+                       uiBlockBeginAlign(block);
+                       uiDefBut(block, LABEL, 0, "Solver select",10,200,300,20, NULL, 0.0, 0, 0, 0, ""); 
+                       uiDefButS(block, MENU, B_SOFTBODY_CHANGE, sbsolvers,10,180,300,20, &sb->solver_ID, 14.0, 0.0, 0, 0, "Select Solver");
+                       uiBlockEndAlign(block);
+
+                       /*some have adapive step size - some not*/
+                       switch (sb->solver_ID) {
+                       case 0:
+                       case 1:
+                               {adaptive_mode = 1; break;}
+                       case 3:
+                               {adaptive_mode = 0; break;}
+                       default: printf("SB_solver?\n"); // should never happen
+                       }
+                       if(adaptive_mode){
+                               uiBlockBeginAlign(block);
+                               uiDefBut(block, LABEL, 0, "Step size controls",10,160,300,20, NULL, 0.0, 0, 0, 0, "");
+                               uiDefButF(block, NUM, B_DIFF, "Error Lim:",     10,140,280,20, &sb->rklimit , 0.001, 10.0, 10, 0, "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed");
+                               uiDefButBitS(block, TOG, SBSO_OLDERR, B_DIFF,"V", 290,140,20,20, &sb->solverflags,  0,  0, 0, 0, "Use velocities for automagic step sizes");
+                               uiDefButS(block, NUM, B_DIFF, "MinS:", 10,120,150,20, &sb->minloops,  0.00,  30000.0, 10, 0, "Minimal # solver steps/frame ");
+                               uiDefButS(block, NUM, B_DIFF, "MaxS:", 160,120,150,20, &sb->maxloops,  0.00,  30000.0, 10, 0, "Maximal # solver steps/frame ");
+                               uiBlockEndAlign(block);
+
+                               uiBlockBeginAlign(block);
+                               uiDefBut(block, LABEL, 0, "Collision helpers",10,100,300,20, NULL, 0.0, 0, 0, 0, "");
+                               uiDefButS(block, NUM, B_DIFF, "Choke:", 10,80,150,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
+                               uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 160,80,150,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
+                               uiBlockEndAlign(block);
+
+                               uiBlockBeginAlign(block);
+                               uiDefBut(block, LABEL, 0, "Diagnosis",10,60,300,20, NULL, 0.0, 0, 0, 0, "");
+                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"Print Performance to Console", 10,40,300,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");                              
+                               uiBlockEndAlign(block);
+                       } 
+                       else{
+                               uiBlockEndAlign(block);
+                               uiBlockBeginAlign(block);
+                               uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 210,100,90,20, &sb->fuzzyness,  1.00,  100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
+                               uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"M", 290,100,20,20, &sb->solverflags,  0,  0, 0, 0, "Turn on SB diagnose console prints");
+                               uiBlockEndAlign(block);
+                               uiDefButS(block, NUM, B_DIFF, "Steps:", 10,80,100,20, &sb->minloops,  1.00,  30000.0, 10, 0, "Solver steps/frame ");
+                               uiDefButS(block, NUM, B_DIFF, "Choke:", 210,80,100,20, &sb->choke, 0.00,  100.0, 10, 0, "'Viscosity' inside collision target ");
+                       }
+
+                       uiBlockEndAlign(block);
+
+               }
+       }
+       uiBlockEndAlign(block);
+}
 
 static void sb_clear_cache(void *ob_v, void *actsoft_v)
 {
@@ -3481,6 +3837,7 @@ static void object_softbodies(Object *ob)
                else
                        but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body",      10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become soft body");
 
+
                uiButSetFunc(but, object_softbodies__enable, ob, NULL);
        }
        
@@ -3537,7 +3894,7 @@ static void object_softbodies(Object *ob)
                        uiBlockBeginAlign(block);
                        uiDefButF(block, NUM, B_DIFF, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 50.0, 10, 0, "General media friction for point movements");
                        uiDefButF(block, NUM, B_DIFF, "Mass:",     160, 170,150,20, &sb->nodemass , 0.001, 50000.0, 10, 0, str);
-                       uiDefButF(block, NUM, B_DIFF, "Grav:",     10,150,150,20, &sb->grav , 0.0, 10.0, 10, 0, "Apply gravitation to point movement");
+                       uiDefButF(block, NUM, B_DIFF, "Grav:",     10,150,150,20, &sb->grav , -10.0, 10.0, 10, 0, "Apply gravitation to point movement");
                        uiDefButF(block, NUM, B_DIFF, "Speed:",    160,150,150,20, &sb->physics_speed , 0.01, 100.0, 10, 0, "Tweak timing for physics to control frequency and speed");
                        uiBlockEndAlign(block);
 
@@ -3583,11 +3940,18 @@ static void object_softbodies(Object *ob)
                                uiDefButBitS(block, TOG, OB_SB_QUADS, B_SOFTBODY_CHANGE, "Stiff Quads",         110,50,90,20, softflag, 0, 0, 0, 0, "Adds diagonal springs on 4-gons");
                                uiDefButBitS(block, TOG, OB_SB_EDGECOLL, B_DIFF, "CEdge",               220,50,45,20, softflag, 0, 0, 0, 0, "Edge collide too"); 
                                uiDefButBitS(block, TOG, OB_SB_FACECOLL, B_DIFF, "CFace",               265,50,45,20, softflag, 0, 0, 0, 0, "Faces collide too SLOOOOOW warning "); 
-                               uiDefButF(block, NUM, B_DIFF, "E Stiff:",       10,30,150,20, &sb->inspring, 0.0,  0.999, 10, 0, "Edge spring stiffness");
-                               uiDefButF(block, NUM, B_DIFF, "E Damp:",        160,30,150,20, &sb->infrict, 0.0,  50.0, 10, 0, "Edge spring friction");
-                               uiDefButS(block, NUM, B_DIFF, "Aero:",     10,10,150,20, &sb->aeroedge,  0.00,  30000.0, 10, 0, "Make edges 'sail'");
+                               uiDefButF(block, NUM, B_DIFF, "E Pull:",        10,30,100,20, &sb->inspring, 0.0,  0.999, 10, 0, "Edge spring stiffness when longer than rest length");
+                               uiDefButF(block, NUM, B_DIFF, "E Push:",        110,30,100,20, &sb->inpush, 0.0,  0.999, 10, 0, "Edge spring stiffness when shorter than rest length");
+                               uiDefButF(block, NUM, B_DIFF, "E Damp:",        210,30,100,20, &sb->infrict, 0.0,  50.0, 10, 0, "Edge spring friction");
+                               
+                               uiDefButBitS(block, TOG,OB_SB_AERO_ANGLE,B_SOFTBODY_CHANGE, "N",10,10,20,20, softflag, 0, 0, 0, 0, "New aero(uses angle and length)");
+                               uiDefButS(block, NUM, B_DIFF, "Aero:",     30,10,60,20, &sb->aeroedge,  0.00,  30000.0, 10, 0, "Make edges 'sail'");
+                           uiDefButS(block, NUM, B_SOFTBODY_CHANGE, "Plas:", 90,10,60,20, &sb->plastic, 0.0,  100.0, 10, 0, "Permanent deform");
                                if(ob->type==OB_MESH) {
-                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Rigidity:", 160,10,150,20, &sb->secondspring, 0.0,  10.0, 10, 0, "Strenght of Springs over 2 Edges");
+                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Be:", 150,10,80,20, &sb->secondspring, 0.0,  10.0, 10, 0, "Bendig Stiffness");
+                                       if (*softflag & OB_SB_QUADS){ 
+                                       uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Sh:", 230,10,80,20, &sb->shearstiff, 0.0,  1.0, 10, 0, "Shear Stiffness");
+                                       }
                                }
                                else sb->secondspring = 0;
                                uiDefBut(block, LABEL, 0, "",10,10,1,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
@@ -3620,7 +3984,7 @@ static void object_panel_particle_children(Object *ob)
 
        if(part->childtype==0) return;
 
-       if((psys->flag&(PSYS_HAIR_DONE|PSYS_KEYED))==0) {
+       if(part->childtype==PART_CHILD_FACES && (psys->flag&(PSYS_HAIR_DONE|PSYS_KEYED))==0) {
                uiDefBut(block, LABEL, 0, "Hair or keyed",      butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                uiDefBut(block, LABEL, 0, "particles needed!",  butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                return;
@@ -3631,7 +3995,9 @@ static void object_panel_particle_children(Object *ob)
        buty -= buth/2;
        
        uiDefButI(block, NUM, B_PART_ALLOC_CHILD, "Amount:", butx,(buty-=buth),butw,buth, &part->child_nbr, 0.0, MAX_PART_CHILDREN, 0, 0, "Amount of children/parent");
-       uiDefButI(block, NUM, B_DIFF, "Render Amount:", butx,(buty-=buth),butw,buth, &part->ren_child_nbr, 0.0, MAX_PART_CHILDREN, 0, 0, "Amount of children/parent for rendering");
+       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED))
+               uiDefButI(block, NUM, B_DIFF, "Render Amount:", butx,(buty-=buth),butw,buth, &part->ren_child_nbr, 0.0, MAX_PART_CHILDREN, 0, 0, "Amount of children/parent for rendering");
+
        if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES) {
                uiDefButF(block, NUMSLI, B_PART_DISTR_CHILD, "VParents:",               butx,(buty-=buth),butw,buth, &part->parents, 0.0, 1.0, 1, 3, "Relative amount of virtual parents");
                }
@@ -3652,9 +4018,11 @@ static void object_panel_particle_children(Object *ob)
        buty -= buth/2;
 
        uiBlockBeginAlign(block);
-       uiDefButF(block, NUM, B_PART_REDRAW, "Size:",           butx,(buty-=buth),butw/2,buth, &part->childsize, 0.01, 100, 10, 1, "A multiplier for the child particle size");
-       uiDefButF(block, NUM, B_PART_REDRAW, "Rand:",           butx+butw/2,buty,butw/2,buth, &part->childrandsize, 0.0, 1.0, 10, 1, "Random variation to the size of the child particles");
-       if(part->childtype==PART_CHILD_FACES) {
+       if(part->draw_as != PART_DRAW_PATH) {
+               uiDefButF(block, NUM, B_PART_REDRAW, "Size:",           butx,(buty-=buth),butw/2,buth, &part->childsize, 0.01, 100, 10, 1, "A multiplier for the child particle size");
+               uiDefButF(block, NUM, B_PART_REDRAW, "Rand:",           butx+butw/2,buty,butw/2,buth, &part->childrandsize, 0.0, 1.0, 10, 1, "Random variation to the size of the child particles");
+       }
+       if(part->childtype == PART_CHILD_FACES) {
                uiDefButF(block, NUM, B_PART_REDRAW, "Spread:",butx,(buty-=buth),butw/2,buth, &part->childspread, -1.0, 1.0, 10, 1, "Spread children from the faces");
                uiDefButBitI(block, TOG, PART_CHILD_SEAMS, B_PART_DISTR_CHILD, "Use Seams",      butx+butw/2,buty,butw/2,buth, &part->flag, 0, 0, 0, 0, "Use seams to determine parents");
        }
@@ -3663,27 +4031,30 @@ static void object_panel_particle_children(Object *ob)
        butx=160;
        buty=180;
 
-       uiDefButBitS(block, TOG, 1, B_PART_REDRAW, "Kink/Branch",        butx,(buty-=buth),butw,buth, &kink_ui, 0, 0, 0, 0, "Show kink and branch options");
+       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED))
+               uiDefButBitS(block, TOG, 1, B_PART_REDRAW, "Kink/Branch",        butx,(buty-=buth),butw,buth, &kink_ui, 0, 0, 0, 0, "Show kink and branch options");
+       else
+               buty-=buth;
 
-       if(kink_ui) {
+       if(kink_ui || (psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)) == 0) {
                buty -= buth/2;
 
                /* kink */
                uiBlockBeginAlign(block);
                if(part->kink) {
-                       uiDefButS(block, MENU, B_PART_RECALC_CHILD, "Kink:%t|Roll%x6|Rotation%x5|Braid%x4|Wave%x3|Radial%x2|Curl%x1|Nothing%x0", butx,(buty-=buth),butw/2,buth, &part->kink, 14.0, 0.0, 0, 0, "Type of periodic offset on the path");
+                       uiDefButS(block, MENU, B_PART_RECALC_CHILD, "Kink:%t|Braid%x4|Wave%x3|Radial%x2|Curl%x1|Nothing%x0", butx,(buty-=buth),butw/2,buth, &part->kink, 14.0, 0.0, 0, 0, "Type of periodic offset on the path");
                        uiDefButS(block, MENU, B_PART_RECALC_CHILD, "Axis %t|Z %x2|Y %x1|X %x0", butx+butw/2,buty,butw/2,buth, &part->kink_axis, 14.0, 0.0, 0, 0, "Which axis to use for offset");
                        uiDefButF(block, NUM, B_PART_RECALC_CHILD, "Freq:",                     butx,(buty-=buth),butw,buth, &part->kink_freq, 0.0, 10.0, 1, 3, "The frequency of the offset (1/total length)");
                        uiDefButF(block, NUMSLI, B_PART_RECALC_CHILD, "Shape:",         butx,(buty-=buth),butw,buth, &part->kink_shape, -0.999, 0.999, 1, 3, "Adjust the offset to the beginning/end");
                        uiDefButF(block, NUM, B_PART_RECALC_CHILD, "Amplitude:",        butx,(buty-=buth),butw,buth, &part->kink_amp, 0.0, 10.0, 1, 3, "The amplitude of the offset");
                }
                else {
-                       uiDefButS(block, MENU, B_PART_RECALC_CHILD, "Kink:%t|Roll%x6|Rotation%x5|Braid%x4|Wave%x3|Radial%x2|Curl%x1|Nothing%x0", butx,(buty-=buth),butw,buth, &part->kink, 14.0, 0.0, 0, 0, "Type of periodic offset on the path");
+                       uiDefButS(block, MENU, B_PART_RECALC_CHILD, "Kink:%t|Braid%x4|Wave%x3|Radial%x2|Curl%x1|Nothing%x0", butx,(buty-=buth),butw,buth, &part->kink, 14.0, 0.0, 0, 0, "Type of periodic offset on the path");
                        buty-=3*buth;
                }
                uiBlockEndAlign(block);
 
-               if(part->childtype==PART_CHILD_PARTICLES) {
+               if(part->childtype==PART_CHILD_PARTICLES && psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)) {
                        if(part->flag & PART_BRANCHING) {
                                uiDefButBitI(block, TOG, PART_BRANCHING, B_PART_RECALC_CHILD, "Branching",      butx,(buty-=2*buth),butw,buth, &part->flag, 0, 0, 0, 0, "Branch child paths from eachother");
                                uiDefButBitI(block, TOG, PART_ANIM_BRANCHING, B_PART_RECALC_CHILD, "Animated",  butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Animate branching");
@@ -3773,11 +4144,11 @@ static void object_panel_particle_extra(Object *ob)
        uiDefButBitI(block, TOG, PART_GLOB_TIME, B_PART_RECALC, "Global",        butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Set all ipos that work on particles to be calculated in global/object time");
        uiDefButBitI(block, TOG, PART_ABS_TIME, B_PART_RECALC, "Absolute",       butx+butw/2,buty,butw/2,buth, &part->flag, 0, 0, 0, 0, "Set all ipos that work on particles to be calculated in absolute/relative time");
 
-       if(part->flag & PART_LOOP){
-               uiDefButBitI(block, TOG, PART_LOOP, B_PART_RECALC, "Loop",       butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Loop particle lives");
-               uiDefButBitI(block, TOG, PART_LOOP_INSTANT, B_PART_RECALC, "Instantly",  butx+butw/2,buty,butw/2,buth, &part->flag, 0, 0, 0, 0, "Loop particle life at time of death");
-       }
-       else
+       //if(part->flag & PART_LOOP){
+       //      uiDefButBitI(block, TOG, PART_LOOP, B_PART_RECALC, "Loop",       butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Loop particle lives");
+       //      uiDefButBitI(block, TOG, PART_LOOP_INSTANT, B_PART_RECALC, "Instantly",  butx+butw/2,buty,butw/2,buth, &part->flag, 0, 0, 0, 0, "Loop particle life at time of death");
+       //}
+       //else
                uiDefButBitI(block, TOG, PART_LOOP, B_PART_RECALC, "Loop",       butx,(buty-=buth),butw,buth, &part->flag, 0, 0, 0, 0, "Loop particle lives");
 
        uiDefButF(block, NUM, B_PART_RECALC, "Tweak:",  butx,(buty-=buth),butw,buth, &part->timetweak, 0.0, 10.0, 1, 0, "A multiplier for physics timestep (1.0 means one frame = 1/25 seconds)");
@@ -3792,13 +4163,13 @@ static void object_panel_particle_extra(Object *ob)
 
                uiBlockBeginAlign(block);
                
-               uiDefButS(block, MENU, B_PART_REDRAW, "Attribute%t|TanRot%x10|TanVel%x9|Size%x8|RoughE%x7|Rough2%x6|Rough1%x5|Kink%x4|Clump%x3|Length%x2|Velocity%x1|Density%x0", butx,(buty-=buth),butw-40,buth, &vgnum, 14.0, 0.0, 0, 0, "Attribute effected by vertex group");
-               but=uiDefButBitS(block, TOG, (1<<vgnum), B_PART_REDRAW, "Neg",  butx+butw-40,buty,40,buth, &psys->vg_neg, 0, 0, 0, 0, "Negate the effect of the vertex group");
+               uiDefButS(block, MENU, B_PART_REDRAW, "Attribute%t|Effector%x11|TanRot%x10|TanVel%x9|Size%x8|RoughE%x7|Rough2%x6|Rough1%x5|Kink%x4|Clump%x3|Length%x2|Velocity%x1|Density%x0", butx,(buty-=buth),butw-40,buth, &vgnum, 14.0, 0.0, 0, 0, "Attribute effected by vertex group");
+               but=uiDefButBitS(block, TOG, (1<<vgnum), B_PART_RECALC, "Neg",  butx+butw-40,buty,40,buth, &psys->vg_neg, 0, 0, 0, 0, "Negate the effect of the vertex group");
                uiButSetFunc(but, particle_set_vg, (void *)ob, (void *)(&vgnum));
                
                butx+=butw;
 
-               but= uiDefButS(block, MENU, B_PART_REDRAW, menustr,     butx,buty,buth,buth, psys->vgroup+vgnum, 0, defCount, 0, 0, "Browses available vertex groups");
+               but= uiDefButS(block, MENU, B_PART_RECALC, menustr,     butx,buty,buth,buth, psys->vgroup+vgnum, 0, defCount, 0, 0, "Browses available vertex groups");
                uiButSetFunc(but, particle_set_vg, (void *)ob, (void *)(&vgnum));
                MEM_freeN (menustr);
 
@@ -3809,7 +4180,7 @@ static void object_panel_particle_extra(Object *ob)
                        else{
                                uiDefBut(block, BUT, B_PART_REDRAW, "(no group)",       butx+buth,buty,butw-2*buth,buth, NULL, 0.0, 0.0, 0, 0, "Vertex Group doesn't exist anymore");
                        }
-                       but=uiDefIconBut(block, BUT, B_PART_REDRAW, ICON_X, butx+butw-buth,buty,buth,buth, 0, 0, 0, 0, 0, "Disable use of vertex group");
+                       but=uiDefIconBut(block, BUT, B_PART_RECALC, ICON_X, butx+butw-buth,buty,buth,buth, 0, 0, 0, 0, 0, "Disable use of vertex group");
                        uiButSetFunc(but, particle_del_vg, (void *)ob, (void *)(&vgnum));
                }
 
@@ -3819,9 +4190,17 @@ static void object_panel_particle_extra(Object *ob)
        buty=butx=160;
 
        uiDefButI(block, NUM, B_PART_DISTR, "Seed:",                            butx,(buty-=buth),butw,buth, &psys->seed, 0.0, 255.0, 1, 0, "Set an offset in the random table");
+       if(part->type == PART_HAIR) {
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUM, B_PART_RECALC, "Stiff:",  butx,(buty-=buth),(butw*3)/5,buth, &part->eff_hair, 0.0, 1.0, 0, 0, "Hair stiffness for effectors");
+               uiDefButBitI(block, TOG, PART_CHILD_EFFECT, B_PART_RECALC, "Children", butx+(butw*3)/5,buty,(butw*2)/5,buth, &part->flag, 0, 0, 0, 0, "Apply effectors to children");
+               uiBlockEndAlign(block);
+       }
+       else
+               buty-=buth;
 
        /* size changes must create a recalc event always so that sizes are updated properly */
-       uiDefButF(block, NUM, B_PART_RECALC, "Size:",   butx,(buty-=2*buth),butw,buth, &part->size, 0.01, 100, 10, 1, "The size of the particles");
+       uiDefButF(block, NUM, B_PART_RECALC, "Size:",   butx,(buty-=buth),butw,buth, &part->size, 0.01, 100, 10, 1, "The size of the particles");
        uiDefButF(block, NUM, B_PART_RECALC, "Rand:",   butx,(buty-=buth),butw,buth, &part->randsize, 0.0, 2.0, 10, 1, "Give the particle size a random variation");
 
        uiDefButBitI(block, TOG, PART_SIZEMASS, B_PART_RECALC, "Mass from size",         butx,(buty-=buth),butw,buth, &part->flag, 0, 0, 0, 0, "Multiply mass with particle size");
@@ -3877,7 +4256,7 @@ static void object_panel_particle_visual(Object *ob)
        uiDefButBitS(block, TOG, PART_DRAW_SIZE, B_PART_REDRAW, "Size", butx+butw/3,buty,butw/3,buth, &part->draw, 0, 0, 0, 0, "Show particle size");
        uiDefButBitS(block, TOG, PART_DRAW_NUM, B_PART_REDRAW, "Num",   butx+2*butw/3,buty,butw/3,buth, &part->draw, 0, 0, 0, 0, "Show particle number");
        uiDefButS(block, NUM, B_PART_REDRAW, "Draw Size:", butx,(buty-=buth),butw,buth, &part->draw_size, 0.0, 10.0, 0, 0, "Size of particles on viewport in pixels (0=default)");
-       uiDefButS(block, NUM, B_PART_RECALC, "Disp:",           butx,(buty-=buth),butw,buth, &part->disp, 0.0, 100.0, 10, 0, "Percentage of particles to calculate for 3d view");
+       uiDefButS(block, NUM, B_PART_RECALC_CHILD, "Disp:",             butx,(buty-=buth),butw,buth, &part->disp, 0.0, 100.0, 10, 0, "Percentage of particles to display in 3d view");
        uiBlockEndAlign(block);
 
        uiDefBut(block, LABEL, 0, "Render:",    butx,(buty-=buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
@@ -3898,10 +4277,10 @@ static void object_panel_particle_visual(Object *ob)
 
        switch(part->draw_as) {
                case PART_DRAW_OB:
-                       uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_PART_REDRAW, "OB:",     butx,(buty-=buth),butw,buth, &part->dup_ob, "Show this Object in place of particles"); 
+                       uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_PART_REDRAW_DEPS, "OB:",        butx,(buty-=buth),butw,buth, &part->dup_ob, "Show this Object in place of particles"); 
                        break;
                case PART_DRAW_GR:
-                       uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_PART_REDRAW, "GR:",  butx,(buty-=buth),butw,buth, &part->dup_group, "Show Objects in this Group in place of particles"); 
+                       uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_PART_REDRAW_DEPS, "GR:",     butx,(buty-=buth),butw,buth, &part->dup_group, "Show Objects in this Group in place of particles"); 
                        uiDefButBitS(block, TOG, PART_DRAW_WHOLE_GR, B_PART_REDRAW, "Dupli Group",      butx,(buty-=buth),butw,buth, &part->draw, 0, 0, 0, 0, "Use whole group at once");
                        if((part->draw & PART_DRAW_WHOLE_GR)==0)
                                uiDefButBitS(block, TOG, PART_DRAW_RAND_GR, B_PART_REDRAW, "Pick Random",       butx,(buty-=buth),butw,buth, &part->draw, 0, 0, 0, 0, "Pick objects from group randomly");
@@ -3952,7 +4331,7 @@ static void object_panel_particle_visual(Object *ob)
                                }
                        }
                        else {
-                               uiDefBut(block, LABEL, 0, "Baked or keyed",     butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
+                               uiDefBut(block, LABEL, 0, "Hair or keyed",      butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                                uiDefBut(block, LABEL, 0, "particles needed!",  butx,(buty-=2*buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                        }
                        break;
@@ -4139,15 +4518,17 @@ static void object_panel_particle_physics(Object *ob)
                uiDefBut(block, LABEL, 0, "Rotation:",  butx, (buty-=buth),butw,buth, NULL, 0.0, 0, 0, 0, "");
                uiBlockBeginAlign(block);
                uiDefButBitI(block, TOG, PART_ROT_DYN, B_PART_RECALC, "Dynamic",         butx,(buty-=buth*4/5),butw/2,buth*4/5, &part->flag, 0, 0, 0, 0, "Sets rotation to dynamic/constant");
-               uiDefButS(block, MENU, B_PART_RECALC, "Rotation %t|Random %x3|Velocity %x2|Normal %x1|None %x0", butx+butw/2,buty,butw/2,buth*4/5, &part->rotmode, 14.0, 0.0, 0, 0, "Select particle rotation mode");
+               uiDefButS(block, MENU, B_PART_RECALC, "Rotation%t|Object Z%x8|Object Y%x7|Object X%x6|Global Z%x5|Global Y%x4|Global X%x3|Velocity%x2|Normal%x1|None%x0", butx+butw/2,buty,butw/2,buth*4/5, &part->rotmode, 14.0, 0.0, 0, 0, "Particles initial rotation");
                uiBlockSetCol(block, TH_BUT_SETTING2);
-               uiDefButF(block, NUM, B_PART_RECALC, "Amount:",         butx,(buty-=buth*4/5),butw,buth*4/5, &part->rotfac, -1.0, 1.0, 1, 3, "Rotation amount");
-               uiDefButF(block, NUM, B_PART_RECALC, "Phase:",                  butx,(buty-=buth*4/5),butw,buth*4/5, &part->phasefac, -1.0, 1.0, 1, 3, "Initial rotation phase");
+               uiDefButF(block, NUM, B_PART_RECALC, "Random:",         butx,(buty-=buth*4/5),butw,buth*4/5, &part->randrotfac, 0.0, 1.0, 1, 3, "Randomize rotation");
+               uiDefButF(block, NUM, B_PART_RECALC, "Phase:",                  butx,(buty-=buth*4/5),butw/2,buth*4/5, &part->phasefac, -1.0, 1.0, 1, 3, "Initial rotation phase");
+               uiDefButF(block, NUM, B_PART_RECALC, "Rand:",                   butx+butw/2,buty,butw/2,buth*4/5, &part->randphasefac, 0.0, 1.0, 1, 3, "Randomize rotation phase");
                uiBlockSetCol(block, TH_AUTO);
 
-               uiDefButS(block, MENU, B_PART_RECALC, "Angular v %t|Velocity%x3|Random%x2|Spin%x1|None%x0", butx,(buty-=buth*4/5),butw,buth*4/5, &part->avemode, 14.0, 0.0, 0, 0, "Select particle angular velocity mode");
+               uiDefButS(block, MENU, B_PART_RECALC, "Angular v %t|Random%x2|Spin%x1|None%x0", butx,(buty-=buth*4/5),butw,buth*4/5, &part->avemode, 14.0, 0.0, 0, 0, "Select particle angular velocity mode");
                uiBlockSetCol(block, TH_BUT_SETTING2);
-               uiDefButF(block, NUM, B_PART_RECALC, "Angular v:",              butx,(buty-=buth*4/5),butw,buth*4/5, &part->avefac, -200.0, 200.0, 1, 3, "Angular velocity amount");
+               if(ELEM(part->avemode,PART_AVE_RAND,PART_AVE_SPIN))
+                       uiDefButF(block, NUM, B_PART_RECALC, "Angular v:",              butx,(buty-=buth*4/5),butw,buth*4/5, &part->avefac, -200.0, 200.0, 1, 3, "Angular velocity amount");
                uiBlockSetCol(block, TH_AUTO);
                uiBlockEndAlign(block);
                
@@ -4212,7 +4593,7 @@ static void object_panel_particle_system(Object *ob)
        short butx=0, buty=160, butw=150, buth=20;
        char str[30];
        static short partact;
-       short totpart;
+       short totpart, lock;
 
        block= uiNewBlock(&curarea->uiblocks, "object_panel_particle_system", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Particle System", "Particle", 0, 0, 318, 204)==0) return;
@@ -4272,9 +4653,9 @@ static void object_panel_particle_system(Object *ob)
                uiBlockEndAlign(block);
        }
 
-       if(psys->flag & PSYS_EDITED || psys->flag & PSYS_PROTECT_CACHE) {
+       lock= (psys->flag & PSYS_EDITED || psys->flag & PSYS_PROTECT_CACHE);
+       if(lock)
                uiSetButLock(1, "Hair is edited or cache is protected!");
-       }
 
        uiDefButS(block, MENU, B_PARTTYPE, "Type%t|Hair%x2|Reactor%x1|Emitter%x0", 210,buty,100,buth, &part->type, 14.0, 0.0, 0, 0, "Type of particle system");
 
@@ -4320,15 +4701,20 @@ static void object_panel_particle_system(Object *ob)
 
        uiDefBut(block, LABEL, 0, "Emit From:",                                                 butx,buty,butw,buth, NULL, 0.0, 0, 0, 0, "");
        uiBlockBeginAlign(block);
+
+       if(lock) uiClearButLock();
        uiDefButBitI(block, TOG, PART_TRAND, B_PART_DISTR, "Random",    butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Emit in random order of elements");
-       
+       if(lock) uiSetButLock(1, "Hair is edited or cache is protected!");
+
        if(part->type==PART_REACTOR)
                uiDefButS(block, MENU, B_PART_DISTR, "Particle %x3|Volume %x2|Faces %x1|Verts %x0", butx+butw/2,buty,butw/2,buth, &part->from, 14.0, 0.0, 0, 0, "Where to emit particles from");
        else
                uiDefButS(block, MENU, B_PART_DISTR, "Volume %x2|Faces %x1|Verts%x0", butx+butw/2,buty,butw/2,buth, &part->from, 14.0, 0.0, 0, 0, "Where to emit particles from");
 
        if(ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)) {
+               if(lock) uiClearButLock();
                uiDefButBitI(block, TOG, PART_EDISTR, B_PART_DISTR, "Even",butx,(buty-=buth),butw/2,buth, &part->flag, 0, 0, 0, 0, "Use even distribution from faces based on face areas or edge lengths");
+               if(lock) uiSetButLock(1, "Hair is edited or cache is protected!");
                uiDefButS(block, MENU, B_PART_DISTR, "Distribution %t|Grid%x2|Random%x1|Jittered%x0", butx+butw/2,buty,butw/2,buth, &part->distr, 14.0, 0.0, 0, 0, "How to distribute particles on selected element");
                if(part->distr==PART_DISTR_JIT) {
                        uiDefButF(block, NUM, B_PART_DISTR, "Amount:",          butx,(buty-=buth),butw,buth, &part->jitfac, 0, 2.0, 1, 1, "Amount of jitter applied to the sampling");
@@ -4699,6 +5085,379 @@ errMessage:
 #endif // DISABLE_ELBEEM
 }
 
+/* Panel for cloth */
+static void object_cloth__enabletoggle(void *ob_v, void *arg2)
+{
+       Object *ob = ob_v;
+       ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+
+       if (!md) {
+               md = modifier_new(eModifierType_Cloth);
+               BLI_addhead(&ob->modifiers, md);
+               
+               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               allqueue(REDRAWBUTSEDIT, 0);
+               allqueue(REDRAWVIEW3D, 0);
+       }
+       else {
+               Object *ob = ob_v;
+               ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+       
+               if (!md)
+                       return;
+
+               BLI_remlink(&ob->modifiers, md);
+
+               modifier_free(md);
+
+               BIF_undo_push("Del modifier");
+               
+               ob->softflag |= OB_SB_RESET;
+               allqueue(REDRAWBUTSEDIT, 0);
+               allqueue(REDRAWVIEW3D, 0);
+               allqueue(REDRAWIMAGE, 0);
+               allqueue(REDRAWOOPS, 0);
+               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               object_handle_update(ob);
+               countall();
+       }
+}
+
+static int _can_cloth_at_all(Object *ob)
+{
+       // list of Yes
+       if ((ob->type==OB_MESH)) return 1;
+       // else deny
+       return 0;
+}
+
+static void object_panel_cloth(Object *ob)
+{
+       uiBlock *block=NULL;
+       uiBut *but=NULL;
+       static int val, val2;
+       ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       
+       block= uiNewBlock(&curarea->uiblocks, "object_cloth", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Cloth ", "Physics", 640, 0, 318, 204)==0) return;
+       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       
+       val = (clmd ? 1:0);
+       
+       if(!_can_cloth_at_all(ob))
+       {
+               uiDefBut(block, LABEL, 0, "Cloth can be activated on mesh only.",  10,200,300,20, NULL, 0.0, 0, 0, 0, "");
+       }
+       else    
+       {
+               but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Cloth",  10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become cloth");
+               uiButSetFunc(but, object_cloth__enabletoggle, ob, NULL);
+       }
+
+       uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+       
+       if(clmd)
+       {
+               int defCount;
+               char *clvg1, *clvg2;
+               char clmvg [] = "Vertex Groups%t|";
+
+               val2=0;
+               
+               /* GENERAL STUFF */
+               uiClearButLock();
+               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
+               
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "StructStiff:", 10,170,150,20, &clmd->sim_parms->structural, 1.0, 10000.0, 100, 0, "Overall stiffness of structure");
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "BendStiff:", 160,170,150,20, &clmd->sim_parms->bending, 0.0, 10000.0, 1000, 0, "Wrinkle coefficient (higher = less smaller but more big wrinkles)");
+               uiDefButI(block, NUM, B_CLOTH_RENEW, "Quality:", 10,150,150,20, &clmd->sim_parms->stepsPerFrame, 4.0, 80.0, 5, 0, "Quality of the simulation (higher=better=slower)");
+
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "Spring Damp:", 160,150,150,20, &clmd->sim_parms->Cdis, 0.0, 1.0, 10, 0, "Spring damping");
+               uiDefButF(block, NUM, B_DIFF, "Air Damp:", 10,130,150,20, &clmd->sim_parms->Cvi, 0.0, 10.0, 10, 0, "Air has normaly some thickness which slows falling things down");
+               
+               uiDefBut(block, LABEL, 0, "Gravity:",  10,100,60,20, NULL, 0.0, 0, 0, 0, "");
+               
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "X:", 70,100,80,20, &clmd->sim_parms->gravity[0], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "Y:", 150,100,80,20, &clmd->sim_parms->gravity[1], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiDefButF(block, NUM, B_CLOTH_RENEW, "Z:", 230,100,80,20, &clmd->sim_parms->gravity[2], -100.0, 100.0, 10, 0, "Apply gravitation to point movement");
+               uiBlockEndAlign(block);
+               
+               /* GOAL STUFF */
+               uiBlockBeginAlign(block);
+               
+               
+               uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_GOAL, B_CLOTH_RENEW, "Pinning of cloth",        10,70,150,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
+               
+               if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (BLI_countlist (&ob->defbase) > 0))
+               {
+                       if(ob->type==OB_MESH) 
+                       {
+                               
+                               defCount = sizeof (clmvg);
+                               clvg1 = get_vertexgroup_menustr (ob);
+                               clvg2 = MEM_callocN (strlen (clvg1) + 1 + defCount, "clothVgMS");
+                               if (! clvg2) {
+                                       printf ("draw_modifier: error allocating memory for cloth vertex group menu string.\n");
+                                       return;
+                               }
+                               defCount = BLI_countlist (&ob->defbase);
+                               if (defCount == 0) 
+                               {
+                                       clmd->sim_parms->vgroup_mass = 0;
+                               }
+                               else
+                               {
+                                       if(!clmd->sim_parms->vgroup_mass)
+                                               clmd->sim_parms->vgroup_mass = 1;
+                                       else if(clmd->sim_parms->vgroup_mass > defCount)
+                                               clmd->sim_parms->vgroup_mass = defCount;
+                               }
+                                                       
+                               sprintf (clvg2, "%s%s", clmvg, clvg1);
+                               
+                               uiDefButS(block, MENU, B_CLOTH_RENEW, clvg2, 160,70,150,20, &clmd->sim_parms->vgroup_mass, 0, defCount, 0, 0, "Browses available vertex groups");
+                               MEM_freeN (clvg1);
+                               MEM_freeN (clvg2);
+                       }
+                       
+                       uiDefButF(block, NUM, B_CLOTH_RENEW, "Pin Stiff:", 10,50,150,20, &clmd->sim_parms->goalspring, 0.0, 50.0, 50, 0, "Pin (vertex target position) spring stiffness");
+                       uiDefBut(block, LABEL, 0, "",160,50,150,20, NULL, 0.0, 0, 0, 0, "");    
+                       // uiDefButI(block, NUM, B_CLOTH_RENEW, "Pin Damp:", 160,50,150,20, &clmd->sim_parms->goalfrict, 1.0, 100.0, 10, 0, "Pined damping (higher = doesn't oszilate so much)");
+                       /*
+                       // nobody is changing these ones anyway
+                       uiDefButF(block, NUM, B_CLOTH_RENEW, "G Min:",          10,30,150,20, &clmd->sim_parms->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
+                       uiDefButF(block, NUM, B_CLOTH_RENEW, "G Max:",          160,30,150,20, &clmd->sim_parms->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
+                       */
+               }
+               else if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL)
+               {
+                       uiDefBut(block, LABEL, 0, " ",  160,70,150,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, "No vertex group for pinning available.",  10,50,300,20, NULL, 0.0, 0, 0, 0, "");
+               }
+               
+               uiBlockEndAlign(block); 
+               
+               /*
+               // no tearing supported anymore since modifier stack restrictions 
+               uiBlockBeginAlign(block);
+               uiDefButBitI(block, TOG, CSIMSETT_FLAG_TEARING_ENABLED, B_EFFECT_DEP, "Tearing",        10,0,150,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Sets object to become a cloth collision object");
+               
+               if (clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED)
+               {
+               uiDefButI(block, NUM, B_DIFF, "Max extent:",       160,0,150,20, &clmd->sim_parms->maxspringlen, 1.0, 1000.0, 10, 0, "Maximum extension before spring gets cut");
+       }
+               
+               uiBlockEndAlign(block); 
+               */
+       }
+       
+       uiBlockEndAlign(block);
+       
+       uiBlockEndAlign(block);
+}
+
+static void object_cloth__protecttoggle(void *ob_v, void *arg2)
+{
+       Object *ob = ob_v;
+       int cageIndex, stack_index;
+       ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       
+       // automatically enable modifier in editmode when we havee a protected cache
+       if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)
+       {
+               cageIndex = modifiers_getCageIndex(ob_v, NULL );
+               stack_index = modifiers_indexInObject(ob_v, (ModifierData *)clmd);
+               if( stack_index >= cageIndex )
+                       ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
+       }
+       else
+       {
+               ((ModifierData *)clmd)->mode ^= eModifierMode_OnCage;
+       }
+       
+}
+
+
+static void object_panel_cloth_II(Object *ob)
+{
+       uiBlock *block;
+       uiBut *but = NULL;
+       ClothModifierData *clmd = NULL;
+
+       block= uiNewBlock(&curarea->uiblocks, "object_cloth_II", UI_EMBOSS, UI_HELV, curarea->win);
+       uiNewPanelTabbed("Cloth ", "Physics");
+       if(uiNewPanel(curarea, block, "Cloth Cache/Collisions", "Physics", 651, 0, 318, 204)==0) return;
+
+       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       
+       clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       
+       if(clmd)
+       {       
+               uiClearButLock();
+               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
+               
+               uiDefButI(block, NUM, B_CLOTH_RENEW, "First Frame:",10,160,150,20, &clmd->sim_parms->firstframe, 0, MAXFRAME, 1, 0, "Frame on which the simulation starts");
+               uiDefButI(block, NUM, B_CLOTH_RENEW, "Last Frame:",160,160,150,20, &clmd->sim_parms->lastframe, 0, MAXFRAME, 1, 0, "Frame on which the simulation stops");
+               
+               uiDefBut(block, LABEL, 0, "",10,140,300,20, NULL, 0.0, 0, 0, 0, "");
+               uiClearButLock();
+               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE) uiSetButLock(1, "Please leave editmode.");
+               if (!G.relbase_valid)
+               {
+                       uiDefBut(block, LABEL, 0, "Cache deactivated until file is saved.",  10,120,300,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, " ",  10,100,300,40, NULL, 0.0, 0, 0, 0, "");
+               }
+               else
+               {
+                       but = uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT, REDRAWVIEW3D, "Protect Cache & Enable Cache Editing",     10,120,300,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "Protect cache from automatic freeing when scene changed. This also enabled the cache beeing edited in editmode.");
+                       uiButSetFunc(but, object_cloth__protecttoggle, ob, NULL);
+                       uiDefBut(block, LABEL, 0, "Clear cache:",  10,100,90,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, BUT, B_CLOTH_CLEARCACHEALL, "All", 100, 100,100,20, NULL, 0.0, 0.0, 10, 0, "Free ALL cloth cache without preroll");
+                       uiDefBut(block, BUT, B_CLOTH_CLEARCACHEFRAME, "From next frame", 200, 100,110,20, NULL, 0.0, 0.0, 10, 0, "Free cloth cache starting from next frame");  
+                       uiDefBut(block, LABEL, 0, " ",  10,80,300,20, NULL, 0.0, 0, 0, 0, "");
+               }
+               
+               uiClearButLock();
+               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
+               
+               /*
+               TODO: implement this again in cloth!
+               if(length>1) // B_CLOTH_CHANGEPREROLL
+               uiDefButI(block, NUM, B_CLOTH_CHANGEPREROLL, "Preroll:", 10,80,145,20, &clmd->sim_parms->preroll, 0, length-1, 1, 0, "Simulation starts on this frame");        
+               else
+               uiDefBut(block, LABEL, 0, " ",  10,80,145,20, NULL, 0.0, 0, 0, 0, "");
+               */
+#if WITH_BULLET == 1
+               uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_ENABLED, B_CLOTH_RENEW, "Enable collisions",   10,60,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable collisions with this object");
+               if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)
+               {
+                       uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Min Distance:",           160,60,150,20, &clmd->coll_parms->epsilon, 0.001f, 1.0, 0.01f, 0, "Minimum distance between collision objects before collision response takes in, can be changed for each frame");
+                       uiDefButS(block, NUM, REDRAWBUTSOBJECT, "Collision Quality:",      10,40,150,20, &clmd->coll_parms->loop_count, 1.0, 20.0, 1.0, 0, "How many collision iterations should be done. (higher = better = slower), can be changed for each frame");
+                       uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Friction:",       160,40,150,20, &clmd->coll_parms->friction, 0.0, 80.0, 1.0, 0, "Friction force if a collision happened (0=movement not changed, 100=no movement left)");
+                       
+                       uiDefButBitI(block, TOG, CLOTH_COLLSETTINGS_FLAG_SELF, B_CLOTH_RENEW, "Enable selfcollisions",  10,20,150,20, &clmd->coll_parms->flags, 0, 0, 0, 0, "Enable selfcollisions with this object");
+                       if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)     
+                       {
+                               uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Min Distance:",           160,20,150,20, &clmd->coll_parms->selfepsilon, 0.5f, 1.0, 0.01f, 0, "0.5 means no distance at all, 1.0 is maximum distance");
+                               // self_loop_count
+                               uiDefButS(block, NUM, REDRAWBUTSOBJECT, "Selfcoll Quality:",       10,0,150,20, &clmd->coll_parms->self_loop_count, 1.0, 10.0, 1.0, 0, "How many selfcollision iterations should be done. (higher = better = slower), can be changed for each frame");
+                       }
+                       else
+                               uiDefBut(block, LABEL, 0, "",160,20,150,20, NULL, 0.0, 0, 0, 0, "");    
+               }
+               else
+                       uiDefBut(block, LABEL, 0, "",160,60,150,20, NULL, 0.0, 0, 0, 0, "");    
+#else
+               uiDefBut(block, LABEL, 0, "No collisions available (compile with bullet).",10,60,300,20, NULL, 0.0, 0, 0, 0, "");
+#endif
+       }
+       
+       uiBlockEndAlign(block);
+       
+}
+
+static void object_panel_cloth_III(Object *ob)
+{
+       uiBlock *block;
+       ClothModifierData *clmd = NULL;
+
+       block= uiNewBlock(&curarea->uiblocks, "object_cloth_III", UI_EMBOSS, UI_HELV, curarea->win);
+       uiNewPanelTabbed("Cloth ", "Physics");
+       if(uiNewPanel(curarea, block, "Cloth Advanced", "Physics", 651, 0, 318, 204)==0) return;
+
+       uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+       
+       clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+       
+       if(clmd)
+       {
+               int defCount;
+               char *clvg1, *clvg2;
+               char clmvg [] = "Vertex Groups%t|None%x0|";
+               char clmvg2 [] = "Vertex Groups%t|None%x0|";
+               
+               uiClearButLock();
+               if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT) uiSetButLock(1, "Cache is protected");
+               
+               
+               uiDefButI(block, NUM, B_DIFF, "Autoprotect Cache From:",10,160,300,20, &clmd->sim_parms->autoprotect, 0.0, MAXFRAME + 1, 1, 0, "Frame on which the simulation gets cache protection enabled automatically (To prevent accidently cleaning it).");
+                               
+               uiDefButBitI(block, TOG, CLOTH_SIMSETTINGS_FLAG_SCALING, B_CLOTH_RENEW, "Enable stiffness scaling",10,130,300,20, &clmd->sim_parms->flags, 0, 0, 0, 0, "If enabled, stiffness can be scaled along a weight painted vertex group.");
+               
+               if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING)&& (BLI_countlist (&ob->defbase) > 0))
+               {       
+                       uiDefBut(block, LABEL, 0, "StructStiff VGroup:",10,110,150,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, "BendStiff VGroup:",160,110,150,20, NULL, 0.0, 0, 0, 0, "");
+                       
+                       defCount = sizeof (clmvg);
+                       clvg1 = get_vertexgroup_menustr (ob);
+                       clvg2 = MEM_callocN (strlen (clvg1) + 1 + defCount, "clothVgST");
+                       if (! clvg2) {
+                               printf ("draw_modifier: error allocating memory for cloth vertex group menu string.\n");
+                               return;
+                       }
+                       defCount = BLI_countlist (&ob->defbase);
+                       if (defCount == 0) 
+                       {
+                               clmd->sim_parms->vgroup_struct = 0;
+                       }
+                       else
+                       {
+                               if(clmd->sim_parms->vgroup_struct > defCount)
+                                       clmd->sim_parms->vgroup_struct = 0;
+                       }
+                                               
+                       sprintf (clvg2, "%s%s", clmvg, clvg1);
+                       
+                       uiDefButS(block, MENU, B_CLOTH_RENEW, clvg2,    10,90,150,20, &clmd->sim_parms->vgroup_struct, 0, defCount, 0, 0, "Browses available vertex groups");
+                       MEM_freeN (clvg1);
+                       MEM_freeN (clvg2);
+                       
+                       defCount = sizeof (clmvg);
+                       clvg1 = get_vertexgroup_menustr (ob);
+                       clvg2 = MEM_callocN (strlen (clvg1) + 1 + defCount, "clothVgBD");
+                       if (! clvg2) {
+                               printf ("draw_modifier: error allocating memory for cloth vertex group menu string.\n");
+                               return;
+                       }
+                       defCount = BLI_countlist (&ob->defbase);
+                       if (defCount == 0) 
+                       {
+                               clmd->sim_parms->vgroup_bend = 0;
+                       }
+                       else
+                       {
+                               if(clmd->sim_parms->vgroup_bend > defCount)
+                                       clmd->sim_parms->vgroup_bend = 0;
+                       }
+                                               
+                       sprintf (clvg2, "%s%s", clmvg2, clvg1);
+                       
+                       uiDefButS(block, MENU, B_CLOTH_RENEW, clvg2, 160,90,150,20, &clmd->sim_parms->vgroup_bend, 0, defCount, 0, 0, "Browses available vertex groups");
+                       MEM_freeN (clvg1);
+                       MEM_freeN (clvg2);
+                       
+                       uiDefButF(block, NUM, B_CLOTH_RENEW, "StructStiff Max:",10,70,150,20, &clmd->sim_parms->max_struct, clmd->sim_parms->structural, 10000.0, 0.01f, 0, "Maximum structural stiffness value");
+                       
+                       uiDefButF(block, NUM, B_CLOTH_RENEW, "BendStiff Max:",160,70,150,20, &clmd->sim_parms->max_bend, clmd->sim_parms->bending, 10000.0, 0.01f, 0, "Maximum bending stiffness value");
+
+               }
+               else if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING)
+               {
+                       uiDefBut(block, LABEL, 0, " ",  10,110,300,20, NULL, 0.0, 0, 0, 0, "");
+                       uiDefBut(block, LABEL, 0, "No vertex group for pinning available.",  10,90,300,20, NULL, 0.0, 0, 0, 0, "");
+               }
+       
+               
+               
+       }
+       
+       uiBlockEndAlign(block);
+       
+}
+
 void object_panels()
 {
        Object *ob;
@@ -4726,7 +5485,11 @@ void physics_panels()
                        object_panel_deflection(ob);
                object_panel_fields(ob);
                object_softbodies(ob);
-               object_softbodies_II(ob);
+               object_softbodies_collision(ob);
+               object_softbodies_solver(ob);
+               object_panel_cloth(ob);
+               object_panel_cloth_II(ob);
+               object_panel_cloth_III(ob);
                object_panel_fluidsim(ob);
        }
 }