use static functions where possible for some local functions.
[blender.git] / source / blender / blenkernel / intern / ipo.c
index b9417ccb46713d927f9457f691fc62e3f7ec8784..62f44d92d25c10f83fc7db18d7375527ec0546d7 100644 (file)
@@ -58,6 +58,7 @@
 #include "DNA_key_types.h"
 #include "DNA_material_types.h"
 #include "DNA_mesh_types.h"
+#include "DNA_nla_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
 #include "DNA_particle_types.h"
@@ -85,6 +86,7 @@
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_mesh.h"
+#include "BKE_nla.h"
 #include "BKE_object.h"
 
 
@@ -158,9 +160,9 @@ static AdrBit2Path ma_mode_bits[]= {
 //     {MA_SHADOW, "shadow", 0},
 //     {MA_SHLESS, "shadeless", 0},
 //     ...
-       {MA_RAYTRANSP, "raytrace_transparency.enabled", 0},
+       {MA_RAYTRANSP, "transparency", 0},
        {MA_RAYMIRROR, "raytrace_mirror.enabled", 0},
-       {MA_HALO, "halo.enabled", 0}
+//     {MA_HALO, "type", MA_TYPE_HALO}
 };
 
 /* ----------------- */
@@ -235,17 +237,15 @@ static char *ob_adrcodes_to_paths (int adrcode, int *array_index)
                        *array_index= 1; return "delta_scale";
                case OB_DSIZE_Z:
                        *array_index= 2; return "delta_scale";
-       
-#if 0  
-               case OB_COL_R:  
-                       poin= &(ob->col[0]); break;
+               case OB_COL_R:
+                       *array_index= 0; return "color";
                case OB_COL_G:
-                       poin= &(ob->col[1]); break;
+                       *array_index= 1; return "color";
                case OB_COL_B:
-                       poin= &(ob->col[2]); break;
+                       *array_index= 2; return "color";
                case OB_COL_A:
-                       poin= &(ob->col[3]); break;
-                       
+                       *array_index= 3; return "color";
+#if 0
                case OB_PD_FSTR:
                        if (ob->pd) poin= &(ob->pd->f_strength);
                        break;
@@ -296,8 +296,8 @@ static char *pchan_adrcodes_to_paths (int adrcode, int *array_index)
                case AC_EUL_Z:
                        *array_index= 2; return "euler_rotation";
                        
-               case -1: // XXX special case for rotation drivers... until eulers are added...
-                       *array_index= 0; return "rotation";
+               case -1: /* special case for euler-rotations used by old drivers */
+                       *array_index= 0; return "euler_rotation";
                        
                case AC_LOC_X:
                        *array_index= 0; return "location";
@@ -545,7 +545,7 @@ static char *material_adrcodes_to_paths (int adrcode, int *array_index)
                        return "ambient";
                
                case MA_SPEC:
-                       return "specularity";
+                       return "specular_reflection";
                
                case MA_HARD:
                        return "specular_hardness";
@@ -820,13 +820,17 @@ static char *particle_adrcodes_to_paths (int adrcode, int *array_index)
  *             - array_index                   - index in property's array (if applicable) to use
  *             - return                                - the allocated path...
  */
-char *get_rna_access (int blocktype, int adrcode, char actname[], char constname[], int *array_index)
+static char *get_rna_access (int blocktype, int adrcode, char actname[], char constname[], int *array_index)
 {
        DynStr *path= BLI_dynstr_new();
        char *propname=NULL, *rpath=NULL;
        char buf[512];
        int dummy_index= 0;
        
+       /* hack: if constname is set, we can only be dealing with an Constraint curve */
+       if (constname)
+               blocktype= ID_CO;
+       
        /* get property name based on blocktype */
        switch (blocktype) {
                case ID_OB: /* object */
@@ -842,7 +846,7 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
                        break;
                        
                case ID_CO: /* constraint */
-                       propname= constraint_adrcodes_to_paths(adrcode, &dummy_index);
+                       propname= constraint_adrcodes_to_paths(adrcode, &dummy_index);  
                        break;
                        
                case ID_TE: /* texture */
@@ -872,7 +876,10 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
                        
                /* XXX problematic blocktypes */
                case ID_CU: /* curve */
-                       propname= "speed"; // XXX this was a 'dummy curve' that didn't really correspond to any real var...
+                       /* this used to be a 'dummy' curve which got evaluated on the fly... 
+                        * now we've got real var for this!
+                        */
+                       propname= "eval_time";
                        break;
                        
                case ID_SEQ: /* sequencer strip */
@@ -950,6 +957,7 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
 static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
 {
        ChannelDriver *cdriver;
+       DriverTarget *dtar=NULL, *dtar2=NULL;
        
        /* allocate memory for new driver */
        cdriver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
@@ -957,6 +965,7 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
        /* if 'pydriver', just copy data across */
        if (idriver->type == IPO_DRIVER_TYPE_PYTHON) {
                /* PyDriver only requires the expression to be copied */
+               // TODO: but the expression will be useless...
                cdriver->type = DRIVER_TYPE_PYTHON;
                strcpy(cdriver->expression, idriver->name); // XXX is this safe? 
        }
@@ -965,12 +974,15 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
                if (idriver->blocktype == ID_AR) {
                        /* ID_PO */
                        if (idriver->adrcode == OB_ROT_DIFF) {
-                               if (G.f & G_DEBUG) printf("idriver_to_cdriver - rotdiff %p \n", idriver->ob);
                                /* Rotational Difference is a special type of driver now... */
                                cdriver->type= DRIVER_TYPE_ROTDIFF;
                                
+                               /* make 2 driver targets */
+                               dtar= driver_add_new_target(cdriver);
+                               dtar2= driver_add_new_target(cdriver);
+                               
                                /* driver must use bones from same armature... */
-                               cdriver->id= cdriver->id2= (ID *)idriver->ob;
+                               dtar->id= dtar2->id= (ID *)idriver->ob;
                                
                                /* paths for the two targets get the pointers to the relevant Pose-Channels 
                                 *      - return pointers to Pose-Channels not rotation channels, as calculation code is picky
@@ -979,44 +991,45 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
                                 *      - we use several hacks here - blocktype == -1 specifies that no property needs to be found, and
                                 *        providing a name for 'actname' will automatically imply Pose-Channel with name 'actname'
                                 */
-                               cdriver->rna_path= get_rna_access(-1, -1, idriver->name, NULL, NULL);
-                               cdriver->rna_path2= get_rna_access(-1, -1, idriver->name+DRIVER_NAME_OFFS, NULL, NULL);
+                               dtar->rna_path= get_rna_access(-1, -1, idriver->name, NULL, NULL);
+                               dtar2->rna_path= get_rna_access(-1, -1, idriver->name+DRIVER_NAME_OFFS, NULL, NULL);
                        }
                        else {
-                               if (G.f & G_DEBUG) printf("idriver_to_cdriver - arm  %p \n", idriver->ob);
                                /* 'standard' driver */
-                               cdriver->type= DRIVER_TYPE_CHANNEL;
-                               cdriver->id= (ID *)idriver->ob;
+                               cdriver->type= DRIVER_TYPE_AVERAGE;
+                               
+                               /* make 1 driver target */
+                               dtar= driver_add_new_target(cdriver);
+                               dtar->id= (ID *)idriver->ob;
                                
                                switch (idriver->adrcode) {
                                        case OB_LOC_X:  /* x,y,z location are quite straightforward */
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_LOC_X, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_LOC_X, idriver->name, NULL, &dtar->array_index);
                                                break;
                                        case OB_LOC_Y:
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_LOC_Y, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_LOC_Y, idriver->name, NULL, &dtar->array_index);
                                                break;
                                        case OB_LOC_Z:
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_LOC_Z, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_LOC_Z, idriver->name, NULL, &dtar->array_index);
                                                break;
                                                
                                        case OB_SIZE_X: /* x,y,z scaling are also quite straightforward */
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_SIZE_X, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_X, idriver->name, NULL, &dtar->array_index);
                                                break;
                                        case OB_SIZE_Y:
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_SIZE_Y, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_Y, idriver->name, NULL, &dtar->array_index);
                                                break;
                                        case OB_SIZE_Z:
-                                               cdriver->rna_path= get_rna_access(ID_PO, AC_SIZE_Z, idriver->name, NULL, &cdriver->array_index);
+                                               dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_Z, idriver->name, NULL, &dtar->array_index);
                                                break;  
                                                
-                                       case OB_ROT_X:  /* rotation - we need to be careful with this... XXX (another reason why we need eulers) */     
+                                       case OB_ROT_X:  /* rotation - we need to be careful with this... */     
                                        case OB_ROT_Y:
                                        case OB_ROT_Z:
                                        {
-                                               // XXX this is not yet a 1:1 map, since we'd need euler rotations to make this work nicely (unless we make some hacks)
-                                               // XXX -1 here is a special hack...
-                                               cdriver->rna_path= get_rna_access(ID_PO, -1, idriver->name, NULL, NULL);
-                                               cdriver->array_index= idriver->adrcode - OB_ROT_X;
+                                               /* -1 here, not rotation code, since old system didn't have eulers */
+                                               dtar->rna_path= get_rna_access(ID_PO, -1, idriver->name, NULL, NULL);
+                                               dtar->array_index= idriver->adrcode - OB_ROT_X;
                                        }
                                                break;
                                }
@@ -1024,14 +1037,16 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
                }
                else {
                        /* ID_OB */
-                       if (G.f & G_DEBUG) printf("idriver_to_cdriver  - ob %p \n", idriver->ob);
-                       cdriver->type= DRIVER_TYPE_CHANNEL;
-                       cdriver->id= (ID *)idriver->ob;
-                       cdriver->rna_path= get_rna_access(ID_OB, idriver->adrcode, NULL, NULL, &cdriver->array_index);
+                       cdriver->type= DRIVER_TYPE_AVERAGE;
+                       
+                       /* make 1 driver target */
+                       dtar= driver_add_new_target(cdriver);
+                       
+                       dtar->id= (ID *)idriver->ob;
+                       dtar->rna_path= get_rna_access(ID_OB, idriver->adrcode, NULL, NULL, &dtar->array_index);
                }
        }
        
-       if (G.f & G_DEBUG) printf("\tcdriver -> id = %p \n", cdriver->id);
        
        /* free old driver */
        MEM_freeN(idriver);
@@ -1073,7 +1088,7 @@ static void fcurve_add_to_list (ListBase *groups, ListBase *list, FCurve *fcu, c
                                BLI_snprintf(agrp->name, 64, grpname);
                                
                                BLI_addtail(&tmp_act.groups, agrp);
-                               BLI_uniquename(&tmp_act.groups, agrp, "Group", offsetof(bActionGroup, name), 64);
+                               BLI_uniquename(&tmp_act.groups, agrp, "Group", '.', offsetof(bActionGroup, name), 64);
                        }
                }
                
@@ -1137,7 +1152,7 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
                        /* Add a new FModifier (Cyclic) instead of setting extend value 
                         * as that's the new equivilant of that option. 
                         */
-                       FModifier *fcm= fcurve_add_modifier(fcu, FMODIFIER_TYPE_CYCLES);
+                       FModifier *fcm= add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
                        FMod_Cycles *data= (FMod_Cycles *)fcm->data;
                        
                        /* if 'offset' one is in use, set appropriate settings */
@@ -1160,7 +1175,7 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
                if (G.f & G_DEBUG) printf("\tconvert bitflag ipocurve, totbits = %d \n", totbits);
                
                /* add the 'only int values' flag */
-               fcu->flag |= FCURVE_INT_VALUES;         
+               fcu->flag |= (FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);                
                
                /* for each bit we have to remap + check for:
                 * 1) we need to make copy the existing F-Curve data (fcu -> fcurve),
@@ -1260,6 +1275,26 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
                                        dst->vec[1][1] *= fac;
                                        dst->vec[2][1] *= fac;
                                }
+                               
+                               /* correct times for rotation drivers 
+                                *      - need to go from degrees to radians...
+                                *      - there's only really 1 target to worry about 
+                                */
+                               if (fcu->driver && fcu->driver->targets.first) {
+                                       DriverTarget *dtar= fcu->driver->targets.first;
+                                       
+                                       /* since drivers could only be for objects, we should just check for 'rotation' being 
+                                        * in the name of the path given
+                                        *      - WARNING: this will break if we encounter a bone or object explictly named in that way...
+                                        */
+                                       if ((dtar && dtar->rna_path) && strstr(dtar->rna_path, "rotation")) {
+                                               const float fac= (float)M_PI / 180.0f;
+                                               
+                                               dst->vec[0][0] *= fac;
+                                               dst->vec[1][0] *= fac;
+                                               dst->vec[2][0] *= fac;
+                                       }
+                               }
                        }
                        
                        /* free this data now */
@@ -1456,6 +1491,87 @@ static void action_to_animdata (ID *id, bAction *act)
        action_to_animato(act, &adt->action->groups, &adt->action->curves, &adt->drivers);
 }
 
+/* ------------------------- */
+
+// TODO:
+//     - NLA group duplicators info
+//     - NLA curve/stride modifiers...
+
+/* Convert NLA-Strip to new system */
+static void nlastrips_to_animdata (ID *id, ListBase *strips)
+{
+       AnimData *adt= BKE_animdata_from_id(id);
+       NlaTrack *nlt = NULL;
+       NlaStrip *strip;
+       bActionStrip *as, *asn;
+       
+       /* for each one of the original strips, convert to a new strip and free the old... */
+       for (as= strips->first; as; as= asn) {
+               asn= as->next;
+               
+               /* this old strip is only worth something if it had an action... */
+               if (as->act) {
+                       /* convert Action data (if not yet converted), storing the results in the same Action */
+                       action_to_animato(as->act, &as->act->groups, &as->act->curves, &adt->drivers);
+                       
+                       /* create a new-style NLA-strip which references this Action, then copy over relevant settings */
+                       {
+                               /* init a new strip, and assign the action to it 
+                                *      - no need to muck around with the user-counts, since this is just 
+                                *        passing over the ref to the new owner, not creating an additional ref
+                                */
+                               strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+                               strip->act= as->act;
+                               
+                                       /* endpoints */
+                               strip->start= as->start;
+                               strip->end= as->end;
+                               strip->actstart= as->actstart;
+                               strip->actend= as->actend;
+                               
+                                       /* action reuse */
+                               strip->repeat= as->repeat;
+                               strip->scale= as->scale;
+                               if (as->flag & ACTSTRIP_LOCK_ACTION)    strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+                               
+                                       /* blending */
+                               strip->blendin= as->blendin;
+                               strip->blendout= as->blendout;
+                               strip->blendmode= (as->mode==ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD : NLASTRIP_MODE_REPLACE;
+                               if (as->flag & ACTSTRIP_AUTO_BLENDS)    strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
+                                       
+                                       /* assorted setting flags */
+                               if (as->flag & ACTSTRIP_SELECT)                 strip->flag |= NLASTRIP_FLAG_SELECT;
+                               if (as->flag & ACTSTRIP_ACTIVE)                 strip->flag |= NLASTRIP_FLAG_ACTIVE;
+                               
+                               if (as->flag & ACTSTRIP_MUTE)                   strip->flag |= NLASTRIP_FLAG_MUTED;
+                               if (as->flag & ACTSTRIP_REVERSE)                strip->flag |= NLASTRIP_FLAG_REVERSE;
+                               
+                                       /* by default, we now always extrapolate, while in the past this was optional */
+                               if ((as->flag & ACTSTRIP_HOLDLASTFRAME)==0) 
+                                       strip->extendmode= NLASTRIP_EXTEND_NOTHING;
+                       }       
+                       
+                       /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
+                       if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
+                               /* trying to add to the current failed (no space), 
+                                * so add a new track to the stack, and add to that...
+                                */
+                               nlt= add_nlatrack(adt, NULL);
+                               BKE_nlatrack_add_strip(nlt, strip);
+                       }
+               }
+               
+               /* modifiers */
+               // FIXME: for now, we just free them...
+               if (as->modifiers.first)
+                       BLI_freelistN(&as->modifiers);
+               
+               /* free the old strip */
+               BLI_freelinkN(strips, as);
+       }
+}
+
 /* *************************************************** */
 /* External API - Only Called from do_versions() */
 
@@ -1502,18 +1618,34 @@ void do_versions_ipos_to_animato(Main *main)
                if (G.f & G_DEBUG) printf("\tconverting ob %s \n", id->name+2);
                
                /* check if object has any animation data */
-               if ((ob->ipo) || (ob->action) || (ob->nlastrips.first)) {
+               if (ob->nlastrips.first) {
                        /* Add AnimData block */
                        adt= BKE_id_add_animdata(id);
                        
-                       /* IPO first */
+                       /* IPO first to take into any non-NLA'd Object Animation */
                        if (ob->ipo) {
                                ipo_to_animdata(id, ob->ipo, NULL, NULL);
+                               
                                ob->ipo->id.us--;
                                ob->ipo= NULL;
                        }
                        
-                       /* now Action */
+                       /* Action is skipped since it'll be used by some strip in the NLA anyway, 
+                        * causing errors with evaluation in the new evaluation pipeline
+                        */
+                       if (ob->action) {
+                               ob->action->id.us--;
+                               ob->action= NULL;
+                       }
+                       
+                       /* finally NLA */
+                       nlastrips_to_animdata(id, &ob->nlastrips);
+               }
+               else if ((ob->ipo) || (ob->action)) {
+                       /* Add AnimData block */
+                       adt= BKE_id_add_animdata(id);
+                       
+                       /* Action first - so that Action name get conserved */
                        if (ob->action) {
                                action_to_animdata(id, ob->action);
                                
@@ -1524,8 +1656,12 @@ void do_versions_ipos_to_animato(Main *main)
                                }
                        }
                        
-                       /* finally NLA */
-                       // XXX todo... for now, new NLA code not hooked up yet, so keep old stuff (but not for too long!)
+                       /* IPO second... */
+                       if (ob->ipo) {
+                               ipo_to_animdata(id, ob->ipo, NULL, NULL);
+                               ob->ipo->id.us--;
+                               ob->ipo= NULL;
+                       }
                }
                
                /* check PoseChannels for constraints with local data */
@@ -1732,3 +1868,4 @@ void do_versions_ipos_to_animato(Main *main)
        
        printf("INFO: Animato convert done \n"); // xxx debug
 }
+