Merging r42896 through r42944 from trunk into soc-2911-tomato
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 28 Dec 2011 18:31:32 +0000 (18:31 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 28 Dec 2011 18:31:32 +0000 (18:31 +0000)
1  2 
source/blender/blenkernel/intern/movieclip.c
source/blender/blenkernel/intern/tracking.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_clip/tracking_ops.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_constraint_types.h

index 224ce003ea34c5828375511213c996e566eb3eca,10c060e0aabbb4f880ed9cfa22092f87bdcb16b3..ab963f1e78c158221bc8a9837821a0dec16818b8
@@@ -816,8 -816,7 +816,8 @@@ void BKE_movieclip_reload(MovieClip *cl
  
  void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
  {
 -      if(scopes->ok) return;
 +      if(scopes->ok)
 +              return;
  
        if(scopes->track_preview) {
                IMB_freeImBuf(scopes->track_preview);
        scopes->track= NULL;
  
        if(clip) {
 -              if(clip->tracking.act_track) {
 -                      MovieTrackingTrack *track= clip->tracking.act_track;
 +              MovieTrackingTrack *act_track= BKE_tracking_active_track(&clip->tracking);
 +
 +              if(act_track) {
 +                      MovieTrackingTrack *track= act_track;
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
  
                        if(marker->flag&MARKER_DISABLED) {
@@@ -921,15 -918,17 +921,17 @@@ static void movieclip_build_proxy_ibuf(
        IMB_freeImBuf(scaleibuf);
  }
  
- void BKE_movieclip_build_proxy_frame(MovieClip *clip, struct MovieDistortion *distortion,
+ void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
                        int cfra, int *build_sizes, int build_count, int undistorted)
  {
        ImBuf *ibuf;
        MovieClipUser user;
  
        user.framenr= cfra;
+       user.render_flag= 0;
+       user.render_size= MCLIP_PROXY_RENDER_SIZE_FULL;
  
-       ibuf= BKE_movieclip_get_ibuf_flag(clip, &user, 0);
+       ibuf= BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag);
  
        if(ibuf) {
                ImBuf *tmpibuf= ibuf;
index 0b58d1562fa88db7979a0a7e0b3759d3a37d0a6d,1a0007c5bfe3b94668c3593da8e5e2c09f6f1c2f..b75a9ff0037f0beae0b76d31256606273fcb4b4a
@@@ -55,7 -55,6 +55,7 @@@
  #include "BKE_movieclip.h"
  #include "BKE_object.h"
  #include "BKE_scene.h"
 +#include "BKE_main.h" // XXX: ...
  
  #include "IMB_imbuf_types.h"
  #include "IMB_imbuf.h"
@@@ -86,14 -85,11 +86,14 @@@ void BKE_tracking_init_settings(MovieTr
        tracking->settings.keyframe1= 1;
        tracking->settings.keyframe2= 30;
        tracking->settings.dist= 1;
 +      tracking->settings.object_distance= 1;
  
        tracking->stabilization.scaleinf= 1.0f;
        tracking->stabilization.locinf= 1.0f;
        tracking->stabilization.rotinf= 1.0f;
        tracking->stabilization.maxscale= 2.0f;
 +
 +      BKE_tracking_new_object(tracking, "Camera");
  }
  
  void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event)
@@@ -212,7 -208,7 +212,7 @@@ void BKE_tracking_track_flag(MovieTrack
        }
  }
  
 -MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, float x, float y,
 +MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, ListBase *tracksbase, float x, float y,
                        int framenr, int width, int height)
  {
        MovieTrackingTrack *track;
        if(track->tracker == TRACKER_KLT)
                BKE_tracking_clamp_track(track, CLAMP_PYRAMID_LEVELS);
  
 -      BLI_addtail(&tracking->tracks, track);
 -      BKE_track_unique_name(tracking, track);
 +      BLI_addtail(tracksbase, track);
 +      BKE_track_unique_name(tracksbase, track);
  
        return track;
  }
@@@ -528,44 -524,18 +528,44 @@@ void BKE_tracking_join_tracks(MovieTrac
        dst_track->markersnr= tot;
  }
  
 -void BKE_tracking_free(MovieTracking *tracking)
 +static void tracking_tracks_free(ListBase *tracks)
  {
        MovieTrackingTrack *track;
  
 -      for(track= tracking->tracks.first; track; track= track->next) {
 +      for(track= tracks->first; track; track= track->next) {
                BKE_tracking_free_track(track);
        }
  
 -      BLI_freelistN(&tracking->tracks);
 +      BLI_freelistN(tracks);
 +}
 +
 +static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruction)
 +{
 +      if(reconstruction->cameras)
 +              MEM_freeN(reconstruction->cameras);
 +}
 +
 +static void tracking_object_free(MovieTrackingObject *object)
 +{
 +      tracking_tracks_free(&object->tracks);
 +      tracking_reconstruction_free(&object->reconstruction);
 +}
 +
 +static void tracking_objects_free(ListBase *objects)
 +{
 +      MovieTrackingObject *object;
 +
 +      for(object= objects->first; object; object= object->next)
 +              tracking_object_free(object);
  
 -      if(tracking->reconstruction.cameras)
 -              MEM_freeN(tracking->reconstruction.cameras);
 +      BLI_freelistN(objects);
 +}
 +
 +void BKE_tracking_free(MovieTracking *tracking)
 +{
 +      tracking_tracks_free(&tracking->tracks);
 +      tracking_reconstruction_free(&tracking->reconstruction);
 +      tracking_objects_free(&tracking->objects);
  
        if(tracking->stabilization.scaleibuf)
                IMB_freeImBuf(tracking->stabilization.scaleibuf);
  /*********************** tracks map *************************/
  
  typedef struct TracksMap {
 +      char object_name[32];
 +      int is_camera;
 +
        int num_tracks;
        int customdata_size;
  
        int ptr;
  } TracksMap;
  
 -static TracksMap *tracks_map_new(int num_tracks, int customdata_size)
 +static TracksMap *tracks_map_new(const char *object_name, int is_camera, int num_tracks, int customdata_size)
  {
        TracksMap *map= MEM_callocN(sizeof(TracksMap), "TrackingsMap");
  
 +      strcpy(map->object_name, object_name);
 +      map->is_camera= is_camera;
 +
        map->num_tracks= num_tracks;
        map->customdata_size= customdata_size;
  
@@@ -643,24 -607,10 +643,24 @@@ static void tracks_map_insert(TracksMa
  static void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
  {
        MovieTrackingTrack *track;
 +      MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        ListBase tracks= {NULL, NULL}, new_tracks= {NULL, NULL};
 -      ListBase *old_tracks= &tracking->tracks;
 +      ListBase *old_tracks;
        int a;
  
 +      if(map->is_camera) {
 +              old_tracks= &tracking->tracks;
 +      } else {
 +              MovieTrackingObject *object= BKE_tracking_named_object(tracking, map->object_name);
 +
 +              if(!object) {
 +                      /* object was deleted by user, create new one */
 +                      object= BKE_tracking_new_object(tracking, map->object_name);
 +              }
 +
 +              old_tracks= &object->tracks;
 +      }
 +
        /* duplicate currently operating tracks to temporary list.
           this is needed to keep names in unique state and it's faster to change names
           of currently operating tracks (if needed) */
  
                        /* original track was found, re-use flags and remove this track */
                        if(cur) {
 -                              if(cur==tracking->act_track)
 +                              if(act_track)
                                        replace_sel= 1;
  
                                track->flag= cur->flag;
                track= next;
        }
  
 -      tracking->tracks= new_tracks;
 +      *old_tracks= new_tracks;
  }
  
  static void tracks_map_free(TracksMap *map, void (*customdata_free) (void *customdata))
@@@ -780,34 -730,34 +780,35 @@@ typedef struct TrackContext 
  typedef struct MovieTrackingContext {
        MovieClipUser user;
        MovieClip *clip;
+       int clip_flag;
  
        int first_time, frames;
  
        MovieTrackingSettings settings;
        TracksMap *tracks_map;
  
 -      short backwards, disable_failed, sequence;
 +      short backwards, sequence;
        int sync_frame;
  } MovieTrackingContext;
  
 -MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, short backwards, short disable_failed, short sequence)
 +MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *user, short backwards, short sequence)
  {
        MovieTrackingContext *context= MEM_callocN(sizeof(MovieTrackingContext), "trackingContext");
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingSettings *settings= &tracking->settings;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
 +      MovieTrackingObject *object= BKE_tracking_active_object(tracking);
        int num_tracks= 0;
  
        context->settings= *settings;
        context->backwards= backwards;
 -      context->disable_failed= disable_failed;
        context->sync_frame= user->framenr;
        context->first_time= 1;
        context->sequence= sequence;
  
        /* count */
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
        if(num_tracks) {
                int width, height;
  
 -              context->tracks_map= tracks_map_new(num_tracks, sizeof(TrackContext));
 +              context->tracks_map= tracks_map_new(object->name, object->flag & TRACKING_OBJECT_CAMERA,
 +                                      num_tracks, sizeof(TrackContext));
  
                BKE_movieclip_get_size(clip, user, &width, &height);
  
                /* create tracking data */
 -              track= tracking->tracks.first;
 +              track= tracksbase->first;
                while(track) {
                        if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
                                MovieTrackingMarker *marker= BKE_tracking_get_marker(track, user->framenr);
        }
  
        context->clip= clip;
+       /* store needed clip flags passing to get_buffer functions
+        * - MCLIP_USE_PROXY is needed to because timecode affects on movie clip
+        *   only in case Proxy/Timecode flag is set, so store this flag to use
+        *   timecodes properly but reset render size to SIZE_FULL so correct resolution
+        *   would be used for images
+        * - MCLIP_USE_PROXY_CUSTOM_DIR is needed because proxy/timecode files might
+        *   be stored in a different location
+        * ignore all the rest pssible flags for now */
+       context->clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
        context->user= *user;
+       context->user.render_size= 0;
+       context->user.render_flag= MCLIP_PROXY_RENDER_SIZE_FULL;
  
        if(!sequence)
                BLI_begin_threaded_malloc();
@@@ -921,53 -883,29 +935,53 @@@ void BKE_tracking_context_free(MovieTra
        MEM_freeN(context);
  }
  
 -static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track)
 +/* zap channels from the imbuf that are disabled by the user. this can lead to
 + * better tracks sometimes. however, instead of simply zeroing the channels
 + * out, do a partial grayscale conversion so the display is better. */
 +static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, int grayscale)
  {
        int x, y;
 +      float scale;
  
 -      if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0)
 +      if((track->flag&(TRACK_DISABLE_RED|TRACK_DISABLE_GREEN|TRACK_DISABLE_BLUE))==0 && !grayscale)
                return;
  
 +      /* If only some components are selected, it's important to rescale the result
 +       * appropriately so that e.g. if only blue is selected, it's not zeroed out. */
 +      scale = ((track->flag&TRACK_DISABLE_RED  ) ? 0.0f : 0.2126f) +
 +              ((track->flag&TRACK_DISABLE_GREEN) ? 0.0f : 0.7152f) +
 +              ((track->flag&TRACK_DISABLE_BLUE)  ? 0.0f : 0.0722f);
 +
        for(y= 0; y<ibuf->y; y++) {
                for (x= 0; x<ibuf->x; x++) {
                        int pixel= ibuf->x*y + x;
  
                        if(ibuf->rect_float) {
                                float *rrgbf= ibuf->rect_float + pixel*4;
 -
 -                              if(track->flag&TRACK_DISABLE_RED)       rrgbf[0]= 0;
 -                              if(track->flag&TRACK_DISABLE_GREEN)     rrgbf[1]= 0;
 -                              if(track->flag&TRACK_DISABLE_BLUE)      rrgbf[2]= 0;
 +                              float r = (track->flag&TRACK_DISABLE_RED)   ? 0.0f : rrgbf[0];
 +                              float g = (track->flag&TRACK_DISABLE_GREEN) ? 0.0f : rrgbf[1];
 +                              float b = (track->flag&TRACK_DISABLE_BLUE)  ? 0.0f : rrgbf[2];
 +                              if (grayscale) {
 +                                      float gray = (0.2126f*r + 0.7152f*g + 0.0722f*b) / scale;
 +                                      rrgbf[0] = rrgbf[1] = rrgbf[2] = gray;
 +                              } else {
 +                                      rrgbf[0] = r;
 +                                      rrgbf[1] = g;
 +                                      rrgbf[2] = b;
 +                              }
                        } else {
                                char *rrgb= (char*)ibuf->rect + pixel*4;
 -
 -                              if(track->flag&TRACK_DISABLE_RED)       rrgb[0]= 0;
 -                              if(track->flag&TRACK_DISABLE_GREEN)     rrgb[1]= 0;
 -                              if(track->flag&TRACK_DISABLE_BLUE)      rrgb[2]= 0;
 +                              char r = (track->flag&TRACK_DISABLE_RED)   ? 0 : rrgb[0];
 +                              char g = (track->flag&TRACK_DISABLE_GREEN) ? 0 : rrgb[1];
 +                              char b = (track->flag&TRACK_DISABLE_BLUE)  ? 0 : rrgb[2];
 +                              if (grayscale) {
 +                                      float gray = (0.2126f*r + 0.7152f*g + 0.0722f*b) / scale;
 +                                      rrgb[0] = rrgb[1] = rrgb[2] = gray;
 +                              } else {
 +                                      rrgb[0] = r;
 +                                      rrgb[1] = g;
 +                                      rrgb[2] = b;
 +                              }
                        }
                }
        }
@@@ -1009,12 -947,7 +1023,12 @@@ static ImBuf *get_area_imbuf(ImBuf *ibu
                origin[1]= y1-margin;
        }
  
 -      disable_imbuf_channels(tmpibuf, track);
 +      if ((track->flag & TRACK_PREVIEW_GRAYSCALE) ||
 +                      (track->flag & TRACK_DISABLE_RED)       ||
 +                      (track->flag & TRACK_DISABLE_GREEN)     ||
 +                      (track->flag & TRACK_DISABLE_BLUE) ) {
 +              disable_imbuf_channels(tmpibuf, track, 1 /* grayscale */);
 +      }
  
        return tmpibuf;
  }
@@@ -1043,7 -976,7 +1057,7 @@@ static float *get_search_floatbuf(ImBu
        height= (track->search_max[1]-track->search_min[1])*ibuf->y;
  
        tmpibuf= BKE_tracking_get_search_imbuf(ibuf, track, marker, 0, 0, pos, origin);
 -      disable_imbuf_channels(tmpibuf, track);
 +      disable_imbuf_channels(tmpibuf, track, 0 /* don't grayscale */);
  
        *width_r= width;
        *height_r= height;
  
                        if(tmpibuf->rect_float) {
                                float *rrgbf= tmpibuf->rect_float + pixel*4;
 -
                                *fp= 0.2126*rrgbf[0] + 0.7152*rrgbf[1] + 0.0722*rrgbf[2];
                        } else {
                                unsigned char *rrgb= (unsigned char*)tmpibuf->rect + pixel*4;
 -
                                *fp= (0.2126*rrgb[0] + 0.7152*rrgb[1] + 0.0722*rrgb[2])/255.0f;
                        }
 -
                        fp++;
                }
        }
@@@ -1081,11 -1017,14 +1095,11 @@@ static unsigned char *get_ucharbuf(ImBu
  
                        if(ibuf->rect_float) {
                                float *rrgbf= ibuf->rect_float + pixel*4;
 -
                                *cp= FTOCHAR(0.2126f*rrgbf[0] + 0.7152f*rrgbf[1] + 0.0722f*rrgbf[2]);
                        } else {
                                unsigned char *rrgb= (unsigned char*)ibuf->rect + pixel*4;
 -
                                *cp= 0.2126f*rrgb[0] + 0.7152f*rrgb[1] + 0.0722f*rrgb[2];
                        }
 -
                        cp++;
                }
        }
@@@ -1100,7 -1039,7 +1114,7 @@@ static unsigned char *get_search_bytebu
        unsigned char *pixels;
  
        tmpibuf= BKE_tracking_get_search_imbuf(ibuf, track, marker, 0, 0, pos, origin);
 -      disable_imbuf_channels(tmpibuf, track);
 +      disable_imbuf_channels(tmpibuf, track, 0 /* don't grayscale */);
  
        *width_r= tmpibuf->x;
        *height_r= tmpibuf->y;
@@@ -1119,7 -1058,7 +1133,7 @@@ static ImBuf *get_frame_ibuf(MovieTrack
  
        user.framenr= framenr;
  
-       ibuf= BKE_movieclip_get_ibuf_flag(context->clip, &user, 0);
+       ibuf= BKE_movieclip_get_ibuf_flag(context->clip, &user, context->clip_flag);
  
        return ibuf;
  }
@@@ -1223,7 -1162,7 +1237,7 @@@ int BKE_tracking_next(MovieTrackingCont
        if(context->backwards) context->user.framenr--;
        else context->user.framenr++;
  
-       ibuf_new= BKE_movieclip_get_ibuf_flag(context->clip, &context->user, 0);
+       ibuf_new= BKE_movieclip_get_ibuf_flag(context->clip, &context->user, context->clip_flag);
        if(!ibuf_new)
                return 0;
  
                                MEM_freeN(image_new);
                        }
  
 -                      coords_correct= !onbound && !isnan(x2) && !isnan(y2) && finite(x2) && finite(y2);
 -                      if(coords_correct && (tracked || !context->disable_failed)) {
 +                      coords_correct= !isnan(x2) && !isnan(y2) && finite(x2) && finite(y2);
 +                      if(coords_correct && !onbound && tracked) {
                                if(context->first_time) {
                                        #pragma omp critical
                                        {
@@@ -1431,8 -1370,6 +1445,8 @@@ typedef struct MovieReconstructContext 
  
        struct libmv_Reconstruction *reconstruction;
  #endif
 +      char object_name[32];
 +      int is_camera;
  
        float focal_length;
        float principal_point[2];
@@@ -1454,13 -1391,13 +1468,13 @@@ typedef struct ReconstructProgressData 
  } ReconstructProgressData;
  
  #if WITH_LIBMV
 -static struct libmv_Tracks *create_libmv_tracks(MovieTracking *tracking, int width, int height)
 +static struct libmv_Tracks *create_libmv_tracks(ListBase *tracksbase, int width, int height)
  {
        int tracknr= 0;
        MovieTrackingTrack *track;
        struct libmv_Tracks *tracks= libmv_tracksNew();
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                int a= 0;
  
@@@ -1504,28 -1441,16 +1518,28 @@@ static void retrieve_libmv_reconstruct_
  static int retrieve_libmv_reconstruct_tracks(MovieReconstructContext *context, MovieTracking *tracking)
  {
        struct libmv_Reconstruction *libmv_reconstruction= context->reconstruction;
 -      MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
 +      MovieTrackingReconstruction *reconstruction= NULL;
        MovieReconstructedCamera *reconstructed;
        MovieTrackingTrack *track;
 +      ListBase *tracksbase=  NULL;
        int ok= 1, tracknr= 0, a, origin_set= 0;
        int sfra= context->sfra, efra= context->efra;
        float imat[4][4];
  
 +      if(context->is_camera) {
 +              tracksbase= &tracking->tracks;
 +              reconstruction= &tracking->reconstruction;
 +      }
 +      else {
 +              MovieTrackingObject *object= BKE_tracking_named_object(tracking, context->object_name);
 +
 +              tracksbase= &object->tracks;
 +              reconstruction= &object->reconstruction;
 +      }
 +
        unit_m4(imat);
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                double pos[3];
  
        }
  
        if(origin_set) {
 -              track= tracking->tracks.first;
 +              track= tracksbase->first;
                while(track) {
                        if(track->flag&TRACK_HAS_BUNDLE)
                                mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
  
  static int retrieve_libmv_reconstruct(MovieReconstructContext *context, MovieTracking *tracking)
  {
 -      tracks_map_merge(context->tracks_map, tracking);
 -
        /* take the intrinscis back from libmv */
        retrieve_libmv_reconstruct_intrinscis(context, tracking);
  
        return retrieve_libmv_reconstruct_tracks(context, tracking);
  }
  
 -static int get_refine_intrinsics_flags(MovieTracking *tracking)
 +static int get_refine_intrinsics_flags(MovieTracking *tracking, MovieTrackingObject *object)
  {
        int refine= tracking->settings.refine_camera_intrinsics;
        int flags= 0;
  
 +      if((object->flag&TRACKING_OBJECT_CAMERA)==0)
 +              return 0;
 +
        if(refine&REFINE_FOCAL_LENGTH)
                flags|= LIBMV_REFINE_FOCAL_LENGTH;
  
        return flags;
  }
  
 -static int count_tracks_on_both_keyframes(MovieTracking *tracking)
 +static int count_tracks_on_both_keyframes(MovieTracking *tracking, ListBase *tracksbase)
  {
        int tot= 0;
        int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
        MovieTrackingTrack *track;
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(BKE_tracking_has_marker(track, frame1))
                        if(BKE_tracking_has_marker(track, frame2))
  }
  #endif
  
 -int BKE_tracking_can_reconstruct(MovieTracking *tracking, char *error_msg, int error_size)
 +int BKE_tracking_can_reconstruct(MovieTracking *tracking, MovieTrackingObject *object, char *error_msg, int error_size)
  {
  #if WITH_LIBMV
 -      if(count_tracks_on_both_keyframes(tracking)<8) {
 +      ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
 +
 +      if(count_tracks_on_both_keyframes(tracking, tracksbase)<8) {
                BLI_strncpy(error_msg, "At least 8 tracks on both of keyframes are needed for reconstruction", error_size);
                return 0;
        }
  }
  
  MovieReconstructContext* BKE_tracking_reconstruction_context_new(MovieTracking *tracking,
 -                      int keyframe1, int keyframe2, int width, int height)
 +                      MovieTrackingObject *object, int keyframe1, int keyframe2, int width, int height)
  {
        MovieReconstructContext *context= MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
        MovieTrackingCamera *camera= &tracking->camera;
 +      ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
        float aspy= 1.0f/tracking->camera.pixel_aspect;
 -      int num_tracks= BLI_countlist(&tracking->tracks);
 +      int num_tracks= BLI_countlist(tracksbase);
        int sfra= INT_MAX, efra= INT_MIN;
        MovieTrackingTrack *track;
  
 -      context->tracks_map= tracks_map_new(num_tracks, 0);
 -      track= tracking->tracks.first;
 +      strcpy(context->object_name, object->name);
 +      context->is_camera = object->flag&TRACKING_OBJECT_CAMERA;
 +
 +      context->tracks_map= tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);
 +
 +      track= tracksbase->first;
        while(track) {
                int first= 0, last= track->markersnr;
                MovieTrackingMarker *first_marker= &track->markers[0];
        context->efra= efra;
  
  #ifdef WITH_LIBMV
 -      context->tracks= create_libmv_tracks(tracking, width, height*aspy);
 +      context->tracks= create_libmv_tracks(tracksbase, width, height*aspy);
        context->keyframe1= keyframe1;
        context->keyframe2= keyframe2;
 -      context->refine_flags= get_refine_intrinsics_flags(tracking);
 +      context->refine_flags= get_refine_intrinsics_flags(tracking, object);
  #else
        (void) width;
        (void) height;
@@@ -1823,22 -1740,8 +1837,22 @@@ void BKE_tracking_solve_reconstruction(
  
  int BKE_tracking_finish_reconstruction(MovieReconstructContext *context, MovieTracking *tracking)
  {
 -      tracking->reconstruction.error= context->reprojection_error;
 -      tracking->reconstruction.flag|= TRACKING_RECONSTRUCTED;
 +      MovieTrackingReconstruction *reconstruction;
 +
 +      tracks_map_merge(context->tracks_map, tracking);
 +
 +      if(context->is_camera) {
 +              reconstruction= &tracking->reconstruction;
 +      }
 +      else {
 +              MovieTrackingObject *object;
 +
 +              object= BKE_tracking_named_object(tracking, context->object_name);
 +              reconstruction= &object->reconstruction;
 +      }
 +
 +      reconstruction->error= context->reprojection_error;
 +      reconstruction->flag|= TRACKING_RECONSTRUCTED;
  
  #ifdef WITH_LIBMV
        if(!retrieve_libmv_reconstruct(context, tracking))
        return 1;
  }
  
 -void BKE_track_unique_name(MovieTracking *tracking, MovieTrackingTrack *track)
 +void BKE_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
  {
 -      BLI_uniquename(&tracking->tracks, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
 +      BLI_uniquename(tracksbase, track, "Track", '.', offsetof(MovieTrackingTrack, name), sizeof(track->name));
  }
  
 -MovieTrackingTrack *BKE_tracking_named_track(MovieTracking *tracking, const char *name)
 +MovieTrackingTrack *BKE_tracking_named_track(MovieTracking *tracking, MovieTrackingObject *object, const char *name)
  {
 -      MovieTrackingTrack *track= tracking->tracks.first;
 +      ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
 +      MovieTrackingTrack *track= tracksbase->first;
  
        while(track) {
                if(!strcmp(track->name, name))
        return NULL;
  }
  
 -static int reconstruction_camera_index(MovieTracking *tracking, int framenr, int nearest)
 +static int reconstruction_camera_index(MovieTrackingReconstruction *reconstruction, int framenr, int nearest)
  {
 -      MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
        MovieReconstructedCamera *cameras= reconstruction->cameras;
        int a= 0, d= 1;
  
        return -1;
  }
  
 -MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking, int framenr)
 +static void scale_reconstructed_camera(MovieTrackingObject *object, float mat[4][4])
  {
 -      int a= reconstruction_camera_index(tracking, framenr, 0);
 +      if((object->flag&TRACKING_OBJECT_CAMERA)==0) {
 +              float smat[4][4];
 +
 +              scale_m4_fl(smat, 1.0f/object->scale);
 +              mult_m4_m4m4(mat, mat, smat);
 +      }
 +}
 +
 +MovieReconstructedCamera *BKE_tracking_get_reconstructed_camera(MovieTracking *tracking,
 +                      MovieTrackingObject *object, int framenr)
 +{
 +      MovieTrackingReconstruction *reconstruction;
 +      int a;
 +
 +      reconstruction= BKE_tracking_object_reconstruction(tracking, object);
 +      a= reconstruction_camera_index(reconstruction, framenr, 0);
  
        if(a==-1)
                return NULL;
  
 -      return &tracking->reconstruction.cameras[a];
 +      return &reconstruction->cameras[a];
  }
  
 -void BKE_tracking_get_interpolated_camera(MovieTracking *tracking, int framenr, float mat[4][4])
 +void BKE_tracking_get_interpolated_camera(MovieTracking *tracking, MovieTrackingObject *object,
 +                      int framenr, float mat[4][4])
  {
 -      MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
 -      MovieReconstructedCamera *cameras= reconstruction->cameras;
 -      int a= reconstruction_camera_index(tracking, framenr, 1);
 +      MovieTrackingReconstruction *reconstruction;
 +      MovieReconstructedCamera *cameras;
 +      int a;
 +
 +      reconstruction= BKE_tracking_object_reconstruction(tracking, object);
 +      cameras= reconstruction->cameras;
 +      a= reconstruction_camera_index(reconstruction, framenr, 1);
  
        if(a==-1) {
                unit_m4(mat);
        } else {
                copy_m4_m4(mat, cameras[a].mat);
        }
 +
 +      scale_reconstructed_camera(object, mat);
  }
  
  void BKE_get_tracking_mat(Scene *scene, Object *ob, float mat[4][4])
@@@ -2009,8 -1890,7 +2023,8 @@@ void BKE_tracking_camera_to_blender(Mov
        BKE_tracking_camera_shift(tracking, width, height, &camera->shiftx, &camera->shifty);
  }
  
 -void BKE_tracking_projection_matrix(MovieTracking *tracking, int framenr, int winx, int winy, float mat[4][4])
 +void BKE_tracking_projection_matrix(MovieTracking *tracking, MovieTrackingObject *object,
 +                      int framenr, int winx, int winy, float mat[4][4])
  {
        MovieReconstructedCamera *camera;
        float lens= tracking->camera.focal*tracking->camera.sensor_width/(float)winx;
  
        perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
  
 -      camera= BKE_tracking_get_reconstructed_camera(tracking, framenr);
 +      camera= BKE_tracking_get_reconstructed_camera(tracking, object, framenr);
 +
        if(camera) {
                float imat[4][4];
  
        } else copy_m4_m4(mat, winmat);
  }
  
 +ListBase *BKE_tracking_get_tracks(MovieTracking *tracking)
 +{
 +      MovieTrackingObject *object= BKE_tracking_active_object(tracking);
 +
 +      if(object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
 +              return &object->tracks;
 +      }
 +
 +      return &tracking->tracks;
 +}
 +
 +MovieTrackingTrack *BKE_tracking_active_track(MovieTracking *tracking)
 +{
 +      ListBase *tracksbase;
 +
 +      if(!tracking->act_track)
 +              return NULL;
 +
 +      tracksbase= BKE_tracking_get_tracks(tracking);
 +
 +      /* check that active track is in current tracks list */
 +      if(BLI_findindex(tracksbase, tracking->act_track) >= 0)
 +              return tracking->act_track;
 +
 +      return NULL;
 +}
 +
 +MovieTrackingObject *BKE_tracking_active_object(MovieTracking *tracking)
 +{
 +      return BLI_findlink(&tracking->objects, tracking->objectnr);
 +}
 +
 +MovieTrackingObject *BKE_tracking_get_camera_object(MovieTracking *tracking)
 +{
 +      MovieTrackingObject *object= tracking->objects.first;
 +
 +      while(object) {
 +              if(object->flag & TRACKING_OBJECT_CAMERA)
 +                      return object;
 +
 +              object= object->next;
 +      }
 +
 +      return NULL;
 +}
 +
 +ListBase *BKE_tracking_object_tracks(MovieTracking *tracking, MovieTrackingObject *object)
 +{
 +      if(object->flag & TRACKING_OBJECT_CAMERA) {
 +              return &tracking->tracks;
 +      }
 +
 +      return &object->tracks;
 +}
 +
 +MovieTrackingReconstruction *BKE_tracking_object_reconstruction(MovieTracking *tracking, MovieTrackingObject *object)
 +{
 +      if(object->flag & TRACKING_OBJECT_CAMERA) {
 +              return &tracking->reconstruction;
 +      }
 +
 +      return &object->reconstruction;
 +}
 +
 +MovieTrackingReconstruction *BKE_tracking_get_reconstruction(MovieTracking *tracking)
 +{
 +      MovieTrackingObject *object= BKE_tracking_active_object(tracking);
 +
 +      return BKE_tracking_object_reconstruction(tracking, object);
 +}
 +
  void BKE_tracking_apply_intrinsics(MovieTracking *tracking, float co[2], float nco[2])
  {
        MovieTrackingCamera *camera= &tracking->camera;
@@@ -2210,9 -2018,8 +2224,9 @@@ static int point_in_layer(bGPDlayer *la
        return 0;
  }
  
 -static void retrieve_libmv_features(MovieTracking *tracking, struct libmv_Features *features,
 -                      int framenr, int width, int height, bGPDlayer *layer, int place_outside_layer)
 +static void retrieve_libmv_features(MovieTracking *tracking, ListBase *tracksbase,
 +                      struct libmv_Features *features, int framenr, int width, int height,
 +                      bGPDlayer *layer, int place_outside_layer)
  {
        int a;
  
                        ok= point_in_layer(layer, xu, yu)!=place_outside_layer;
  
                if(ok) {
 -                      track= BKE_tracking_add_track(tracking, xu, yu, framenr, width, height);
 +                      track= BKE_tracking_add_track(tracking, tracksbase, xu, yu, framenr, width, height);
                        track->flag|= SELECT;
                        track->pat_flag|= SELECT;
                        track->search_flag|= SELECT;
  }
  #endif
  
 -void BKE_tracking_detect_fast(MovieTracking *tracking, ImBuf *ibuf,
 +void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
                        int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer,
                        int place_outside_layer)
  {
        struct libmv_Features *features;
        unsigned char *pixels= get_ucharbuf(ibuf);
  
 -      features= libmv_detectFeaturesFAST(pixels, ibuf->x, ibuf->y, ibuf->x, margin, min_trackness, min_distance);
 +      features= libmv_detectFeaturesFAST(pixels, ibuf->x, ibuf->y, ibuf->x,
 +                      margin, min_trackness, min_distance);
  
        MEM_freeN(pixels);
  
 -      retrieve_libmv_features(tracking, features, framenr, ibuf->x, ibuf->y, layer, place_outside_layer);
 +      retrieve_libmv_features(tracking, tracksbase, features, framenr,
 +                      ibuf->x, ibuf->y, layer, place_outside_layer);
  
        libmv_destroyFeatures(features);
  #else
  #endif
  }
  
 -MovieTrackingTrack *BKE_tracking_indexed_track(MovieTracking *tracking, int tracknr)
 +MovieTrackingTrack *BKE_tracking_indexed_track(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r)
  {
 -      MovieTrackingTrack *track= tracking->tracks.first;
 +      MovieTrackingObject *object;
        int cur= 1;
  
 -      while(track) {
 -              if(track->flag&TRACK_HAS_BUNDLE) {
 -                      if(cur==tracknr)
 -                              return track;
 +      object= tracking->objects.first;
 +      while(object) {
 +              ListBase *tracksbase= BKE_tracking_object_tracks(tracking, object);
 +              MovieTrackingTrack *track= tracksbase->first;
 +
 +              while(track) {
 +                      if(track->flag&TRACK_HAS_BUNDLE) {
 +                              if(cur==tracknr) {
 +                                      *tracksbase_r= tracksbase;
 +                                      return track;
 +                              }
 +
 +                              cur++;
 +                      }
  
 -                      cur++;
 +                      track= track->next;
                }
  
 -              track= track->next;
 +              object= object->next;
        }
  
 +      *tracksbase_r= NULL;
 +
        return NULL;
  }
  
@@@ -2309,8 -2102,6 +2323,8 @@@ static int stabilization_median_point(M
  
        INIT_MINMAX2(min, max);
  
 +      (void) tracking;
 +
        track= tracking->tracks.first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
@@@ -2748,12 -2539,12 +2762,12 @@@ ImBuf *BKE_tracking_distort(MovieTracki
  }
  
  /* area - which part of marker should be selected. see TRACK_AREA_* constants */
 -void BKE_tracking_select_track(MovieTracking *tracking, MovieTrackingTrack *track, int area, int extend)
 +void BKE_tracking_select_track(ListBase *tracksbase, MovieTrackingTrack *track, int area, int extend)
  {
        if(extend) {
                BKE_tracking_track_flag(track, area, SELECT, 0);
        } else {
 -              MovieTrackingTrack *cur= tracking->tracks.first;
 +              MovieTrackingTrack *cur= tracksbase->first;
  
                while(cur) {
                        if(cur==track) {
@@@ -2773,78 -2564,3 +2787,78 @@@ void BKE_tracking_deselect_track(MovieT
  {
        BKE_tracking_track_flag(track, area, SELECT, 1);
  }
 +
 +MovieTrackingObject *BKE_tracking_new_object(MovieTracking *tracking, const char *name)
 +{
 +      MovieTrackingObject *object= MEM_callocN(sizeof(MovieTrackingObject), "tracking object");
 +
 +      if(tracking->tot_object==0) {
 +              /* first object is always camera */
 +              BLI_strncpy(object->name, "Camera", sizeof(object->name));
 +
 +              object->flag|= TRACKING_OBJECT_CAMERA;
 +      }
 +      else {
 +              BLI_strncpy(object->name, name, sizeof(object->name));
 +      }
 +
 +      BLI_addtail(&tracking->objects, object);
 +
 +      tracking->tot_object++;
 +      tracking->objectnr= BLI_countlist(&tracking->objects) - 1;
 +
 +      BKE_tracking_object_unique_name(tracking, object);
 +
 +      return object;
 +}
 +
 +void BKE_tracking_remove_object(MovieTracking *tracking, MovieTrackingObject *object)
 +{
 +      MovieTrackingTrack *track;
 +      int index= BLI_findindex(&tracking->objects, object);
 +
 +      if(index<0)
 +              return;
 +
 +      if(object->flag & TRACKING_OBJECT_CAMERA) {
 +              /* object used for camera solving can't be deleted */
 +              return;
 +      }
 +
 +      track= object->tracks.first;
 +      while(track) {
 +              if(track==tracking->act_track)
 +                      tracking->act_track= NULL;
 +
 +              track= track->next;
 +      }
 +
 +      tracking_object_free(object);
 +      BLI_freelinkN(&tracking->objects, object);
 +
 +      tracking->tot_object--;
 +
 +      if(index>0)
 +              tracking->objectnr= index-1;
 +      else
 +              tracking->objectnr= 0;
 +}
 +
 +void BKE_tracking_object_unique_name(MovieTracking *tracking, MovieTrackingObject *object)
 +{
 +      BLI_uniquename(&tracking->objects, object, "Object", '.', offsetof(MovieTrackingObject, name), sizeof(object->name));
 +}
 +
 +MovieTrackingObject *BKE_tracking_named_object(MovieTracking *tracking, const char *name)
 +{
 +      MovieTrackingObject *object= tracking->objects.first;
 +
 +      while(object) {
 +              if(!strcmp(object->name, name))
 +                      return object;
 +
 +              object= object->next;
 +      }
 +
 +      return NULL;
 +}
index eb4b10361d80a34783f0150d53a17a48184729cc,8a14e9416df8a45a3ceb1cec67a3e12ec7f218f3..59a34a706eef327dee0d954721a12544996d81cb
@@@ -3680,6 -3680,7 +3680,7 @@@ static void direct_link_mdisps(FileDat
        }
  }
  
+ /*this isn't really a public api function, so prototyped here*/
  static void direct_link_customdata(FileData *fd, CustomData *data, int count)
  {
        int i = 0;
                        i++;
                }
        }
+       CustomData_update_typemap(data);
  }
  
  static void direct_link_mesh(FileData *fd, Mesh *mesh)
        direct_link_customdata(fd, &mesh->edata, mesh->totedge);
        direct_link_customdata(fd, &mesh->fdata, mesh->totface);
  
+ #ifdef USE_BMESH_FORWARD_COMPAT
+       /* NEVER ENABLE THIS CODE INTO BMESH!
+        * THIS IS FOR LOADING BMESH INTO OLDER FILES ONLY */
+       mesh->mpoly= newdataadr(fd, mesh->mpoly);
+       mesh->mloop= newdataadr(fd, mesh->mloop);
+       direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
+       direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
+       if (mesh->mpoly) {
+               /* be clever and load polygons as mfaces */
+               mesh->totface= mesh_mpoly_to_mface(&mesh->fdata, &mesh->ldata, &mesh->pdata,
+                                                  mesh->totface, mesh->totloop, mesh->totpoly);
+               CustomData_free(&mesh->pdata, mesh->totpoly);
+               memset(&mesh->pdata, 0, sizeof(CustomData));
+               mesh->totpoly = 0;
+               CustomData_free(&mesh->ldata, mesh->totloop);
+               memset(&mesh->ldata, 0, sizeof(CustomData));
+               mesh->totloop = 0;
+               mesh_update_customdata_pointers(mesh);
+       }
+ #endif
        mesh->bb= NULL;
        mesh->mselect = NULL;
        mesh->edit_mesh= NULL;
@@@ -5936,29 -5969,10 +5969,29 @@@ static void lib_link_group(FileData *fd
  
  /* ***************** READ MOVIECLIP *************** */
  
 +static void direct_link_movieReconstruction(FileData *fd, MovieTrackingReconstruction *reconstruction)
 +{
 +      reconstruction->cameras= newdataadr(fd, reconstruction->cameras);
 +}
 +
 +static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase)
 +{
 +      MovieTrackingTrack *track;
 +
 +      link_list(fd, tracksbase);
 +
 +      track= tracksbase->first;
 +      while(track) {
 +              track->markers= newdataadr(fd, track->markers);
 +
 +              track= track->next;
 +      }
 +}
 +
  static void direct_link_movieclip(FileData *fd, MovieClip *clip)
  {
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track;
 +      MovieTrackingObject *object;
  
        if(fd->movieclipmap) clip->cache= newmclipadr(fd, clip->cache);
        else clip->cache= NULL;
        if(fd->movieclipmap) clip->tracking.camera.intrinsics= newmclipadr(fd, clip->tracking.camera.intrinsics);
        else clip->tracking.camera.intrinsics= NULL;
  
 -      tracking->reconstruction.cameras= newdataadr(fd, tracking->reconstruction.cameras);
 -
 -      link_list(fd, &tracking->tracks);
 -
 -      track= tracking->tracks.first;
 -      while(track) {
 -              track->markers= newdataadr(fd, track->markers);
 -
 -              track= track->next;
 -      }
 +      direct_link_movieTracks(fd, &tracking->tracks);
 +      direct_link_movieReconstruction(fd, &tracking->reconstruction);
  
        clip->tracking.act_track= newdataadr(fd, clip->tracking.act_track);
  
        clip->tracking.stabilization.ok= 0;
        clip->tracking.stabilization.scaleibuf= NULL;
        clip->tracking.stabilization.rot_track= newdataadr(fd, clip->tracking.stabilization.rot_track);
 +
 +      link_list(fd, &tracking->objects);
 +
 +      object= tracking->objects.first;
 +      while(object) {
 +              direct_link_movieTracks(fd, &object->tracks);
 +              direct_link_movieReconstruction(fd, &object->reconstruction);
 +
 +              object= object->next;
 +      }
  }
  
  static void lib_link_movieclip(FileData *fd, Main *main)
@@@ -12761,43 -12773,8 +12794,43 @@@ static void do_versions(FileData *fd, L
                }
                {
                        MovieClip *clip;
 -                      for(clip= main->movieclip.first; clip; clip= clip->id.next) {
 +                      Object *ob;
 +
 +                      for (clip= main->movieclip.first; clip; clip= clip->id.next) {
 +                              MovieTracking *tracking= &clip->tracking;
 +                              MovieTrackingObject *tracking_object= tracking->objects.first;
 +
                                clip->proxy.build_tc_flag|= IMB_TC_RECORD_RUN_NO_GAPS;
 +
 +                              if(!tracking->settings.object_distance)
 +                                      tracking->settings.object_distance= 1.0f;
 +
 +                              if(tracking->objects.first == NULL)
 +                                      BKE_tracking_new_object(tracking, "Camera");
 +
 +                              while(tracking_object) {
 +                                      if(!tracking_object->scale)
 +                                              tracking_object->scale= 1.0f;
 +
 +                                      tracking_object= tracking_object->next;
 +                              }
 +                      }
 +
 +                      for (ob= main->object.first; ob; ob= ob->id.next) {
 +                              bConstraint *con;
 +                              for (con= ob->constraints.first; con; con=con->next) {
 +                                      bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
 +
 +                                      if(!cti)
 +                                              continue;
 +
 +                                      if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
 +                                              bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
 +
 +                                              if(data->invmat[3][3]==0.0f)
 +                                                      unit_m4(data->invmat);
 +                                      }
 +                              }
                        }
                }
        }
index 4828e9703fb80b0a844ecc547650234f9c3a756f,e9c14404057dcc361e17ab3f78133deb9dc460ff..7cde4c8a1e21231baf02a7f7bcdbcdbb59521054
@@@ -174,6 -174,10 +174,10 @@@ typedef struct 
        MemFile *compare, *current;
        
        int tot, count, error, memsize;
+ #ifdef USE_BMESH_SAVE_AS_COMPAT
+       char use_mesh_compat; /* option to save with older mesh format */
+ #endif
  } WriteData;
  
  static WriteData *writedata_new(int file)
@@@ -2522,27 -2526,6 +2526,27 @@@ static void write_scripts(WriteData *wd
        }
  }
  
 +static void write_movieTracks(WriteData *wd, ListBase *tracks)
 +{
 +      MovieTrackingTrack *track;
 +
 +      track= tracks->first;
 +      while(track) {
 +              writestruct(wd, DATA, "MovieTrackingTrack", 1, track);
 +
 +              if(track->markers)
 +                      writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers);
 +
 +              track= track->next;
 +      }
 +}
 +
 +static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction)
 +{
 +      if(reconstruction->camnr)
 +              writestruct(wd, DATA, "MovieReconstructedCamera", reconstruction->camnr, reconstruction->cameras);
 +}
 +
  static void write_movieclips(WriteData *wd, ListBase *idbase)
  {
        MovieClip *clip;
        while(clip) {
                if(clip->id.us>0 || wd->current) {
                        MovieTracking *tracking= &clip->tracking;
 -                      MovieTrackingTrack *track;
 +                      MovieTrackingObject *object;
                        writestruct(wd, ID_MC, "MovieClip", 1, clip);
  
 -                      if(tracking->reconstruction.camnr)
 -                              writestruct(wd, DATA, "MovieReconstructedCamera", tracking->reconstruction.camnr, tracking->reconstruction.cameras);
 +                      write_movieTracks(wd, &tracking->tracks);
 +                      write_movieReconstruction(wd, &tracking->reconstruction);
  
 -                      track= tracking->tracks.first;
 -                      while(track) {
 -                              writestruct(wd, DATA, "MovieTrackingTrack", 1, track);
 +                      object= tracking->objects.first;
 +                      while(object) {
 +                              writestruct(wd, DATA, "MovieTrackingObject", 1, object);
  
 -                              if(track->markers)
 -                                      writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers);
 +                              write_movieTracks(wd, &object->tracks);
 +                              write_movieReconstruction(wd, &object->reconstruction);
  
 -                              track= track->next;
 +                              object= object->next;
                        }
                }
  
@@@ -2595,7 -2578,10 +2599,10 @@@ static void write_global(WriteData *wd
        fg.curscene= screen->scene;
        fg.displaymode= G.displaymode;
        fg.winpos= G.winpos;
-       fg.fileflags= (fileflags & ~(G_FILE_NO_UI|G_FILE_RELATIVE_REMAP));      // prevent to save this, is not good convention, and feature with concerns...
+       /* prevent to save this, is not good convention, and feature with concerns... */
+       fg.fileflags= (fileflags & ~(G_FILE_NO_UI|G_FILE_RELATIVE_REMAP|G_FILE_MESH_COMPAT));
        fg.globalf= G.f;
        BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
  
@@@ -2638,7 -2624,11 +2645,11 @@@ static int write_file_handle(Main *main
        blo_split_main(&mainlist, mainvar);
  
        wd= bgnwrite(handle, compare, current);
-       
+ #ifdef USE_BMESH_SAVE_AS_COMPAT
+       wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0;
+ #endif
        sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (ENDIAN_ORDER==B_ENDIAN)?'V':'v', BLENDER_VERSION);
        mywrite(wd, buf, 12);
  
index dd5b78c5b8ddf20e1487f435eac352c129128bed,d911e68236b09b4bd9b99de06db2ccb476554c0c..918fc5f347dde2a4db5fac026bc07f00bdf8b9a3
@@@ -32,7 -32,6 +32,7 @@@
  #include "MEM_guardedalloc.h"
  
  #include "DNA_camera_types.h"
 +#include "DNA_constraint_types.h"
  #include "DNA_gpencil_types.h"
  #include "DNA_movieclip_types.h"
  #include "DNA_object_types.h" /* SELECT */
@@@ -46,7 -45,6 +46,7 @@@
  
  #include "BKE_main.h"
  #include "BKE_context.h"
 +#include "BKE_constraint.h"
  #include "BKE_movieclip.h"
  #include "BKE_tracking.h"
  #include "BKE_global.h"
@@@ -92,21 -90,41 +92,21 @@@ static int space_clip_frame_poll(bConte
        return 0;
  }
  
 -static int space_clip_frame_camera_poll(bContext *C)
 -{
 -      Scene *scene= CTX_data_scene(C);
 -
 -      if(space_clip_frame_poll(C)) {
 -              return scene->camera != NULL;
 -      }
 -
 -      return 0;
 -}
 -
 -static int space_clip_camera_poll(bContext *C)
 -{
 -      SpaceClip *sc= CTX_wm_space_clip(C);
 -      Scene *scene= CTX_data_scene(C);
 -
 -      if(sc && sc->clip && scene->camera)
 -              return 1;
 -
 -      return 0;
 -}
 -
  /********************** add marker operator *********************/
  
  static void add_marker(SpaceClip *sc, float x, float y)
  {
        MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int width, height;
        
        ED_space_clip_size(sc, &width, &height);
  
 -      track= BKE_tracking_add_track(&clip->tracking, x, y, sc->user.framenr, width, height);
 +      track= BKE_tracking_add_track(tracking, tracksbase, x, y, sc->user.framenr, width, height);
  
 -      BKE_tracking_select_track(&clip->tracking, track, TRACK_AREA_ALL, 0);
 +      BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
  
        clip->tracking.act_track= track;
  }
@@@ -173,14 -191,13 +173,14 @@@ static int delete_track_exec(bContext *
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track= tracking->tracks.first, *next;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track= tracksbase->first, *next;
  
        while(track) {
                next= track->next;
  
                if(TRACK_VIEW_SELECTED(sc, track))
 -                      clip_delete_track(C, clip, track);
 +                      clip_delete_track(C, clip, tracksbase, track);
  
                track= next;
        }
@@@ -213,8 -230,7 +213,8 @@@ static int delete_marker_exec(bContext 
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 -      MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
 +      MovieTrackingTrack *track= tracksbase->first, *next;
        int framenr= sc->user.framenr;
        int has_selection= 0;
  
                        if(marker) {
                                has_selection|= track->markersnr>1;
  
 -                              clip_delete_marker(C, clip, track, marker);
 +                              clip_delete_marker(C, clip, tracksbase, track, marker);
                        }
                }
  
@@@ -413,7 -429,6 +413,7 @@@ static void *slide_marker_customdata(bC
        int width, height;
        float co[2];
        void *customdata= NULL;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
  
        ED_space_clip_size(sc, &width, &height);
  
  
        ED_clip_mouse_pos(C, event, co);
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@@ -706,12 -721,12 +706,12 @@@ static float dist_to_rect(float co[2], 
        return MIN4(d1, d2, d3, d4);
  }
  
 -static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
 +static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
  {
        MovieTrackingTrack *track= NULL, *cur;
        float mindist= 0.0f;
  
 -      cur= clip->tracking.tracks.first;
 +      cur= tracksbase->first;
        while(cur) {
                MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
  
@@@ -749,11 -764,10 +749,11 @@@ static int mouse_select(bContext *C, fl
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *act_track= tracking->act_track;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        MovieTrackingTrack *track= NULL;        /* selected marker */
  
 -      track= find_nearest_track(sc, clip, co);
 +      track= find_nearest_track(sc, tracksbase, co);
  
        if(track) {
                int area= track_mouse_area(sc, co, track);
                        if(area==TRACK_AREA_POINT)
                                area= TRACK_AREA_ALL;
  
 -                      BKE_tracking_select_track(tracking, track, area, extend);
 +                      BKE_tracking_select_track(tracksbase, track, area, extend);
                        clip->tracking.act_track= track;
                }
        }
@@@ -853,7 -867,6 +853,7 @@@ static int border_select_exec(bContext 
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        rcti rect;
        rctf rectf;
        int change= 0, mode, extend;
        extend= RNA_boolean_get(op->ptr, "extend");
  
        /* do actual selection */
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@@ -939,7 -952,6 +939,7 @@@ static int circle_select_exec(bContext 
        MovieClip *clip= ED_space_clip(sc);
        ARegion *ar= CTX_wm_region(C);
        MovieTrackingTrack *track;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int x, y, radius, width, height, mode, change= 0;
        float zoomx, zoomy, offset[2], ellipse[2];
  
        ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
  
        /* do selection */
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@@ -1014,14 -1026,13 +1014,14 @@@ static int select_all_exec(bContext *C
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track= NULL;        /* selected track */
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int action= RNA_enum_get(op->ptr, "action");
        int framenr= sc->user.framenr;
        int has_selection= 0;
  
        if(action == SEL_TOGGLE){
                action= SEL_SELECT;
 -              track= clip->tracking.tracks.first;
 +              track= tracksbase->first;
                while(track) {
                        if(TRACK_VIEW_SELECTED(sc, track)) {
                                action= SEL_DESELECT;
                }
        }
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
@@@ -1097,11 -1108,9 +1097,11 @@@ static int select_groped_exec(bContext 
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
        MovieTrackingMarker *marker;
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        int group= RNA_enum_get(op->ptr, "group");
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                int ok= 0;
  
                        ok= marker->flag&MARKER_DISABLED;
                }
                else if(group==5) { /* color */
 -                      if(clip->tracking.act_track) {
 -                              ok= (track->flag&TRACK_CUSTOMCOLOR) == (clip->tracking.act_track->flag&TRACK_CUSTOMCOLOR);
 +                      MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
 +
 +                      if(act_track) {
 +                              ok= (track->flag&TRACK_CUSTOMCOLOR) == (act_track->flag&TRACK_CUSTOMCOLOR);
  
                                if(ok && track->flag&TRACK_CUSTOMCOLOR)
 -                                      ok= equals_v3v3(track->color, clip->tracking.act_track->color);
 +                                      ok= equals_v3v3(track->color, act_track->color);
                        }
                }
                else if(group==6) { /* failed */
@@@ -1201,11 -1208,10 +1201,11 @@@ static int track_markers_testbreak(void
  static int track_count_markers(SpaceClip *sc, MovieClip *clip)
  {
        int tot= 0;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
        int framenr= sc->user.framenr;
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
  
  static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
  {
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
        int framenr= sc->user.framenr, hidden= 0;
        int frames_limit= 0;
        if((sc->flag&SC_SHOW_MARKER_PATTERN)==0) hidden|= TRACK_AREA_PAT;
        if((sc->flag&SC_SHOW_MARKER_SEARCH)==0) hidden|= TRACK_AREA_SEARCH;
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(hidden)
                        BKE_tracking_track_flag(track, hidden, SELECT, 1);
@@@ -1297,7 -1302,7 +1297,7 @@@ static int track_markers_initjob(bConte
                else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
        }
  
 -      tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1, 1);
 +      tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
  
        clip->tracking_context= tmj->context;
  
@@@ -1408,7 -1413,7 +1408,7 @@@ static int track_markers_exec(bContext 
                return OPERATOR_CANCELLED;
  
        /* do not disable tracks due to threshold when tracking frame-by-frame */
 -      context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence, sequence);
 +      context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
  
        while(framenr != efra) {
                if(!BKE_tracking_next(context))
@@@ -1443,11 -1448,6 +1443,11 @@@ static int track_markers_invoke(bContex
        int backwards= RNA_boolean_get(op->ptr, "backwards");
        int sequence= RNA_boolean_get(op->ptr, "sequence");
  
 +      if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
 +              /* only one tracking is allowed at a time */
 +              return OPERATOR_CANCELLED;
 +      }
 +
        if(clip->tracking_context)
                return OPERATOR_CANCELLED;
  
@@@ -1546,10 -1546,9 +1546,10 @@@ static int solve_camera_initjob(bContex
        Scene *scene= CTX_data_scene(C);
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingSettings *settings= &clip->tracking.settings;
 +      MovieTrackingObject *object= BKE_tracking_active_object(tracking);
        int width, height;
  
 -      if(!BKE_tracking_can_reconstruct(tracking, error_msg, max_error))
 +      if(!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
                return 0;
  
        /* could fail if footage uses images with different sizes */
        scj->reports= op->reports;
        scj->user= sc->user;
  
 -      scj->context= BKE_tracking_reconstruction_context_new(tracking,
 +      scj->context= BKE_tracking_reconstruction_context_new(tracking, object,
                        settings->keyframe1, settings->keyframe2, width, height);
  
        tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
@@@ -1671,15 -1670,9 +1671,15 @@@ static int solve_camera_invoke(bContex
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
        wmJob *steve;
        char error_msg[256]= "\0";
  
 +      if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
 +              /* only one solve is allowed at a time */
 +              return OPERATOR_CANCELLED;
 +      }
 +
        scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
        if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
                if(error_msg[0])
        BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
  
        /* hide reconstruction statistics from previous solve */
 -      clip->tracking.reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
 +      reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
        WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
  
        /* setup job */
@@@ -1753,9 -1746,7 +1753,9 @@@ static int clear_solution_exec(bContex
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track= tracking->tracks.first;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
 +      MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
 +      MovieTrackingTrack *track= tracksbase->first;
  
        while(track) {
                track->flag&= ~TRACK_HAS_BUNDLE;
                track= track->next;
        }
  
 -      if(tracking->reconstruction.cameras)
 -              MEM_freeN(tracking->reconstruction.cameras);
 +      if(reconstruction->cameras)
 +              MEM_freeN(reconstruction->cameras);
  
 -      tracking->reconstruction.cameras= NULL;
 -      tracking->reconstruction.camnr= 0;
 +      reconstruction->cameras= NULL;
 +      reconstruction->camnr= 0;
  
 -      tracking->reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
 +      reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
  
        DAG_id_tag_update(&clip->id, 0);
  
@@@ -1801,10 -1792,9 +1801,10 @@@ static int clear_track_path_exec(bConte
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int action= RNA_enum_get(op->ptr, "action");
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track))
                        BKE_tracking_clear_path(track, sc->user.framenr, action);
@@@ -1849,8 -1839,7 +1849,8 @@@ static int disable_markers_exec(bContex
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track= tracking->tracks.first;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track= tracksbase->first;
        int action= RNA_enum_get(op->ptr, "action");
  
        while(track) {
@@@ -1899,80 -1888,14 +1899,80 @@@ void CLIP_OT_disable_markers(wmOperator
  
  /********************** set origin operator *********************/
  
 +static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
 +{
 +      Object *camera= scene->camera;
 +      Base *base;
 +
 +      if(camera && object_get_movieclip(scene, camera, 0)==clip)
 +              return camera;
 +
 +      base= scene->base.first;
 +      while(base) {
 +              if(base->object->type == OB_CAMERA) {
 +                      if(object_get_movieclip(scene, base->object, 0)==clip) {
 +                              camera= base->object;
 +                              break;
 +                      }
 +              }
 +
 +              base= base->next;
 +      }
 +
 +      return camera;
 +}
 +
 +static Object *get_orientation_object(bContext *C)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      SpaceClip *sc= CTX_wm_space_clip(C);
 +      MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
 +      Object *object= NULL;
 +
 +      if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
 +              object= get_camera_with_movieclip(scene, clip);
 +      }
 +      else {
 +              object= OBACT;
 +      }
 +
 +      if(object && object->parent)
 +              object= object->parent;
 +
 +      return object;
 +}
 +
 +static int set_orientation_poll(bContext *C)
 +{
 +      if(space_clip_frame_poll(C)) {
 +              Scene *scene= CTX_data_scene(C);
 +              SpaceClip *sc= CTX_wm_space_clip(C);
 +              MovieClip *clip= ED_space_clip(sc);
 +              MovieTracking *tracking= &clip->tracking;
 +              MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
 +
 +              if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
 +                      return 1;
 +              }
 +              else {
 +                      return OBACT != NULL;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
  static int count_selected_bundles(bContext *C)
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
        int tot= 0;
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
                        tot++;
        return tot;
  }
  
 +static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
 +{
 +      bConstraint *con;
 +      int found= 0;
 +
 +      for (con= ob->constraints.first; con; con=con->next) {
 +              bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
 +
 +              if(!cti)
 +                      continue;
 +
 +              if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
 +                      bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
 +
 +                      if(!found) {
 +                              Object *cam= data->camera ? data->camera : scene->camera;
 +
 +                              where_is_object_mat(scene, cam, invmat);
 +                      }
 +
 +                      mult_m4_m4m4(invmat, invmat, data->invmat);
 +
 +                      found= 1;
 +              }
 +      }
 +
 +      if(found)
 +              invert_m4(invmat);
 +      else
 +              unit_m4(invmat);
 +}
 +
 +static Object *object_solver_camera(Scene *scene, Object *ob)
 +{
 +      bConstraint *con;
 +
 +      for (con= ob->constraints.first; con; con=con->next) {
 +              bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
 +
 +              if(!cti)
 +                      continue;
 +
 +              if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
 +                      bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
 +
 +                      return data->camera ? data->camera : scene->camera;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
  static int set_origin_exec(bContext *C, wmOperator *op)
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
        MovieTrackingTrack *track;
 +      MovieTrackingObject *tracking_object;
        Scene *scene= CTX_data_scene(C);
 -      Object *parent= scene->camera;
 -      float mat[4][4], vec[3];
 +      Object *object;
 +      Object *camera= get_camera_with_movieclip(scene, clip);
 +      ListBase *tracksbase;
 +      float mat[4][4], vec[3], median[3];
 +      int selected_count= count_selected_bundles(C);
 +
 +      if(selected_count==0) {
 +              BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
 +
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      object= get_orientation_object(C);
 +      if(!object) {
 +              BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
  
 -      if(count_selected_bundles(C)!=1) {
 -              BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
                return OPERATOR_CANCELLED;
        }
  
 -      if(scene->camera->parent)
 -              parent= scene->camera->parent;
 +      tracking_object= BKE_tracking_active_object(tracking);
 +
 +      tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
 +      zero_v3(median);
        while(track) {
 -              if(TRACK_VIEW_SELECTED(sc, track))
 -                      break;
 +              if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
 +                      add_v3_v3(median, track->bundle_pos);
 +              }
  
                track= track->next;
        }
 +      mul_v3_fl(median, 1.0f/selected_count);
  
 -      BKE_get_tracking_mat(scene, NULL, mat);
 -      mul_v3_m4v3(vec, mat, track->bundle_pos);
 +      BKE_get_tracking_mat(scene, camera, mat);
  
 -      sub_v3_v3(parent->loc, vec);
 +      mul_v3_m4v3(vec, mat, median);
 +
 +      if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
 +              sub_v3_v3(object->loc, vec);
 +      }
 +      else {
 +              object_solver_inverted_matrix(scene, object, mat);
 +              mul_v3_m4v3(vec, mat, vec);
 +              copy_v3_v3(object->loc, vec);
 +      }
  
        DAG_id_tag_update(&clip->id, 0);
 -      DAG_id_tag_update(&parent->id, OB_RECALC_OB);
 +      DAG_id_tag_update(&object->id, OB_RECALC_OB);
  
        WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
        WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
@@@ -2108,42 -1954,20 +2108,42 @@@ void CLIP_OT_set_origin(wmOperatorType 
  
        /* api callbacks */
        ot->exec= set_origin_exec;
 -      ot->poll= space_clip_frame_camera_poll;
 +      ot->poll= set_orientation_poll;
  
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
  }
  
  /********************** set floor operator *********************/
  
 -static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char axis)
 +static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
 +                      MovieTrackingTrack *track, char axis)
  {
 -      float mat[4][4], vec[3], obmat[4][4];
 +      Object *camera= get_camera_with_movieclip(scene, clip);
 +      int is_camera= tracking_object->flag&TRACKING_OBJECT_CAMERA;
 +      int  flip= 0;
 +      float mat[4][4], vec[3], obmat[4][4], dvec[3];
 +
 +      object_to_mat4(ob, obmat);
  
 -      BKE_get_tracking_mat(scene, NULL, mat);
 +      BKE_get_tracking_mat(scene, camera, mat);
        mul_v3_m4v3(vec, mat, track->bundle_pos);
 +      copy_v3_v3(dvec, vec);
 +
 +      if(!is_camera) {
 +              float imat[4][4];
 +
 +              object_solver_inverted_matrix(scene, ob, imat);
 +              mul_v3_m4v3(vec, imat, vec);
 +
 +              invert_m4_m4(imat, obmat);
 +              mul_v3_m4v3(dvec, imat, vec);
 +
 +              sub_v3_v3(vec, obmat[3]);
 +      }
  
        if(len_v2(vec) < 1e-3f)
                return;
        unit_m4(mat);
  
        if(axis=='X') {
 -              if(fabsf(vec[1])<1e-3f) {
 +              if(fabsf(dvec[1])<1e-3f) {
 +                      flip= 1;
 +
                        mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
                        mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
                        mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
                } else {
                        copy_v3_v3(mat[0], vec);
 -                      mat[0][2]= 0.0f;
 -                      mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
 -                      cross_v3_v3v3(mat[1], mat[2], mat[0]);
 +
 +                      if(is_camera || fabsf(vec[2])<1e-3f) {
 +                              mat[0][2]= 0.0f;
 +                              mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
 +                              cross_v3_v3v3(mat[1], mat[2], mat[0]);
 +                      }
 +                      else {
 +                              vec[2]= 0.0f;
 +
 +                              cross_v3_v3v3(mat[1], mat[0], vec);
 +                              cross_v3_v3v3(mat[2], mat[0], mat[1]);
 +                      }
                }
        } else {
 -              if(fabsf(vec[0])<1e-3f) {
 +              if(fabsf(dvec[0])<1e-3f) {
 +                      flip= 1;
 +
                        mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
                        mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
                        mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
                } else {
                        copy_v3_v3(mat[1], vec);
 -                      mat[1][2]= 0.0f;
 -                      mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
 -                      cross_v3_v3v3(mat[0], mat[1], mat[2]);
 +
 +                      if(is_camera || fabsf(vec[2])<1e-3f) {
 +                              mat[1][2]= 0.0f;
 +                              mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
 +                              cross_v3_v3v3(mat[0], mat[1], mat[2]);
 +                      }
 +                      else {
 +                              vec[2]= 0.0f;
 +
 +                              cross_v3_v3v3(mat[0], vec, mat[1]);
 +                              cross_v3_v3v3(mat[2], mat[0], mat[1]);
 +                      }
                }
        }
  
        normalize_v3(mat[1]);
        normalize_v3(mat[2]);
  
 -      invert_m4(mat);
 +      if(is_camera) {
 +              invert_m4(mat);
 +
 +              mult_m4_m4m4(mat, mat, obmat);
 +      }
 +      else {
 +              if(!flip) {
 +                      float lmat[4][4], ilmat[4][4], rmat[3][3];
 +
 +                      object_rot_to_mat3(ob, rmat);
 +                      invert_m3(rmat);
 +                      mul_m4_m4m3(mat, mat, rmat);
 +
 +                      unit_m4(lmat);
 +                      copy_v3_v3(lmat[3], obmat[3]);
 +                      invert_m4_m4(ilmat, lmat);
 +
 +                      mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
 +              }
 +              else {
 +                      mult_m4_m4m4(mat, obmat, mat);
 +              }
 +      }
  
 -      object_to_mat4(ob, obmat);
 -      mult_m4_m4m4(mat, mat, obmat);
        object_apply_mat4(ob, mat, 0, 0);
  }
  
@@@ -2232,12 -2014,9 +2232,12 @@@ static int set_floor_exec(bContext *C, 
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        Scene *scene= CTX_data_scene(C);
 -      MovieTrackingTrack *track, *axis_track= NULL;
 -      Object *camera= scene->camera;
 -      Object *parent= camera;
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *tracking_object;
 +      MovieTrackingTrack *track, *axis_track= NULL, *act_track;
 +      ListBase *tracksbase;
 +      Object *object;
 +      Object *camera= get_camera_with_movieclip(scene, clip);
        int tot= 0;
        float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
        float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
  
        if(count_selected_bundles(C)!=3) {
                BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
 +
                return OPERATOR_CANCELLED;
        }
  
 -      if(scene->camera->parent)
 -              parent= scene->camera->parent;
 +      tracking_object= BKE_tracking_active_object(tracking);
 +      tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
 +      act_track= BKE_tracking_active_track(tracking);
 +
 +      object= get_orientation_object(C);
 +      if(!object) {
 +              BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 +
 +              return OPERATOR_CANCELLED;
 +      }
  
 -      BKE_get_tracking_mat(scene, NULL, mat);
 +      BKE_get_tracking_mat(scene, camera, mat);
  
        /* get 3 bundles to use as reference */
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track && tot<3) {
                if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
                        mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
  
 -                      if(tot==0 || track==clip->tracking.act_track)
 +                      if(tot==0 || track==act_track)
                                copy_v3_v3(orig, vec[tot]);
                        else
                                axis_track= track;
        mat[3][1]= orig[1];
        mat[3][2]= orig[2];
  
 -      invert_m4(mat);
 +      if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
 +              invert_m4(mat);
  
 -      object_to_mat4(parent, obmat);
 -      mult_m4_m4m4(mat, mat, obmat);
 -      mult_m4_m4m4(newmat, rot, mat);
 -      object_apply_mat4(parent, newmat, 0, 0);
 -
 -      /* make camera have positive z-coordinate */
 -      if(parent->loc[2]<0) {
 -              invert_m4(rot);
 +              object_to_mat4(object, obmat);
 +              mult_m4_m4m4(mat, mat, obmat);
                mult_m4_m4m4(newmat, rot, mat);
 -              object_apply_mat4(parent, newmat, 0, 0);
 +              object_apply_mat4(object, newmat, 0, 0);
 +
 +              /* make camera have positive z-coordinate */
 +              if(object->loc[2]<0) {
 +                invert_m4(rot);
 +                mult_m4_m4m4(newmat, rot, mat);
 +                object_apply_mat4(object, newmat, 0, 0);
 +              }
 +      }
 +      else {
 +              object_apply_mat4(object, mat, 0, 0);
        }
  
 -      where_is_object(scene, parent);
 -      set_axis(scene, parent, axis_track, 'X');
 +      where_is_object(scene, object);
 +      set_axis(scene, object, clip, tracking_object, axis_track, 'X');
  
        DAG_id_tag_update(&clip->id, 0);
 -      DAG_id_tag_update(&parent->id, OB_RECALC_OB);
 +      DAG_id_tag_update(&object->id, OB_RECALC_OB);
  
        WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
        WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
@@@ -2340,7 -2105,7 +2340,7 @@@ void CLIP_OT_set_floor(wmOperatorType *
  
        /* api callbacks */
        ot->exec= set_floor_exec;
 -      ot->poll= space_clip_camera_poll;
 +      ot->poll= set_orientation_poll;
  
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@@ -2352,12 -2117,9 +2352,12 @@@ static int set_axis_exec(bContext *C, w
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
        MovieTrackingTrack *track;
        Scene *scene= CTX_data_scene(C);
 -      Object *parent= scene->camera;
 +      Object *object;
 +      ListBase *tracksbase;
        int axis= RNA_enum_get(op->ptr, "axis");
  
        if(count_selected_bundles(C)!=1) {
                return OPERATOR_CANCELLED;
        }
  
 -      if(scene->camera->parent)
 -              parent= scene->camera->parent;
 +      object= get_orientation_object(C);
 +      if(!object) {
 +              BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 +
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
  
 -      track= clip->tracking.tracks.first;
 +      track=tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track))
                        break;
                track= track->next;
        }
  
 -      set_axis(scene, parent, track, axis==0?'X':'Y');
 +      set_axis(scene, object, clip, tracking_object, track, axis==0?'X':'Y');
  
        DAG_id_tag_update(&clip->id, 0);
 -      DAG_id_tag_update(&parent->id, OB_RECALC_OB);
 +      DAG_id_tag_update(&object->id, OB_RECALC_OB);
  
        WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
        WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
@@@ -2409,7 -2165,7 +2409,7 @@@ void CLIP_OT_set_axis(wmOperatorType *o
  
        /* api callbacks */
        ot->exec= set_axis_exec;
 -      ot->poll= space_clip_frame_camera_poll;
 +      ot->poll= set_orientation_poll;
  
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
  
  /********************** set scale operator *********************/
  
 -static int set_scale_exec(bContext *C, wmOperator *op)
 +static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
        MovieTrackingTrack *track;
        Scene *scene= CTX_data_scene(C);
 -      Object *parent= scene->camera;
 +      Object *object= NULL;
 +      Object *camera= get_camera_with_movieclip(scene, clip);
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        int tot= 0;
        float vec[2][3], mat[4][4], scale;
        float dist= RNA_float_get(op->ptr, "distance");
  
        if(count_selected_bundles(C)!=2) {
 -              BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
 +              BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
  
                return OPERATOR_CANCELLED;
        }
  
 -      if(scene->camera->parent)
 -              parent= scene->camera->parent;
 +      object= get_orientation_object(C);
 +      if(!object) {
 +              BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 +
 +              return OPERATOR_CANCELLED;
 +      }
  
 -      BKE_get_tracking_mat(scene, NULL, mat);
 +      BKE_get_tracking_mat(scene, camera, mat);
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track)) {
                        mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
        if(len_v3(vec[0])>1e-5f) {
                scale= dist / len_v3(vec[0]);
  
 -              mul_v3_fl(parent->size, scale);
 -              mul_v3_fl(parent->loc, scale);
 +              if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
 +                      mul_v3_fl(object->size, scale);
 +                      mul_v3_fl(object->loc, scale);
 +              } else
 +              if(!scale_solution){
 +                      Object *camera= object_solver_camera(scene, object);
 +
 +                      object->size[0]= object->size[1]= object->size[2]= 1.0f/scale;
 +
 +                      if(camera) {
 +                              object->size[0]/= camera->size[0];
 +                              object->size[1]/= camera->size[1];
 +                              object->size[2]/= camera->size[2];
 +                      }
 +              }
 +              else {
 +                      tracking_object->scale= scale;
 +              }
  
                DAG_id_tag_update(&clip->id, 0);
 -              DAG_id_tag_update(&parent->id, OB_RECALC_OB);
 +
 +              if(object)
 +                      DAG_id_tag_update(&object->id, OB_RECALC_OB);
  
                WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
                WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
        return OPERATOR_FINISHED;
  }
  
 +static int set_scale_exec(bContext *C, wmOperator *op)
 +{
 +      return do_set_scale(C, op, 0);
 +}
 +
  static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
@@@ -2523,60 -2248,7 +2523,60 @@@ void CLIP_OT_set_scale(wmOperatorType *
        /* api callbacks */
        ot->exec= set_scale_exec;
        ot->invoke= set_scale_invoke;
 -      ot->poll= space_clip_frame_camera_poll;
 +      ot->poll= set_orientation_poll;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
 +              "Distance", "Distance between selected tracks", -100.0f, 100.0f);
 +}
 +
 +/********************** set solution scale operator *********************/
 +
 +static int set_solution_scale_poll(bContext *C)
 +{
 +      if(space_clip_frame_poll(C)) {
 +              SpaceClip *sc= CTX_wm_space_clip(C);
 +              MovieClip *clip= ED_space_clip(sc);
 +              MovieTracking *tracking= &clip->tracking;
 +              MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
 +
 +              return (tracking_object->flag&TRACKING_OBJECT_CAMERA) == 0;
 +      }
 +
 +      return 0;
 +}
 +
 +static int set_solution_scale_exec(bContext *C, wmOperator *op)
 +{
 +      return do_set_scale(C, op, 1);
 +}
 +
 +static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 +{
 +      SpaceClip *sc= CTX_wm_space_clip(C);
 +      MovieClip *clip= ED_space_clip(sc);
 +      float dist= RNA_float_get(op->ptr, "distance");
 +
 +      if(dist==0.0f)
 +              RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
 +
 +      return set_solution_scale_exec(C, op);
 +}
 +
 +void CLIP_OT_set_solution_scale(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Set Solution Scale";
 +      ot->description= "Set object solution scale using distance between two selected tracks";
 +      ot->idname= "CLIP_OT_set_solution_scale";
 +
 +      /* api callbacks */
 +      ot->exec= set_solution_scale_exec;
 +      ot->invoke= set_solution_scale_invoke;
 +      ot->poll= set_solution_scale_poll;
  
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@@ -2629,14 -2301,11 +2629,14 @@@ static int hide_tracks_exec(bContext *C
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        int unselected;
  
        unselected= RNA_boolean_get(op->ptr, "unselected");
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
                        track->flag|= TRACK_HIDDEN;
                track= track->next;
        }
  
 -      if(clip->tracking.act_track && clip->tracking.act_track->flag&TRACK_HIDDEN)
 +      if(act_track && act_track->flag&TRACK_HIDDEN)
                clip->tracking.act_track= NULL;
  
        if(unselected==0) {
@@@ -2684,10 -2353,9 +2684,10 @@@ static int hide_tracks_clear_exec(bCont
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                track->flag&= ~TRACK_HIDDEN;
  
@@@ -2738,10 -2406,9 +2738,11 @@@ static int detect_features_exec(bContex
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, 0);
+       int clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
+       ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag);
 -      MovieTrackingTrack *track= clip->tracking.tracks.first;
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track= tracksbase->first;
        int placement= RNA_enum_get(op->ptr, "placement");
        int margin= RNA_int_get(op->ptr, "margin");
        int min_trackability= RNA_int_get(op->ptr, "min_trackability");
                track= track->next;
        }
  
 -      BKE_tracking_detect_fast(&clip->tracking, ibuf, sc->user.framenr, margin, min_trackability, min_distance, layer, place_outside_layer);
 +      BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
 +                              min_trackability, min_distance, layer, place_outside_layer);
  
        IMB_freeImBuf(ibuf);
  
@@@ -2813,7 -2479,7 +2814,7 @@@ static int frame_jump_exec(bContext *C
        int delta;
  
        if(pos<=1) {    /* jump to path */
 -              track= clip->tracking.act_track;
 +              track= BKE_tracking_active_track(&clip->tracking);
  
                if(!track)
                        return OPERATOR_CANCELLED;
                if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
                        int a= sc->user.framenr;
                        MovieTracking *tracking= &clip->tracking;
 +                      MovieTrackingObject *object= BKE_tracking_active_object(tracking);
  
                        delta= pos == 3 ? 1 : -1;
  
                        a+= delta;
  
                        while(a+delta >= SFRA && a+delta <= EFRA) {
 -                              MovieReconstructedCamera *cam= BKE_tracking_get_reconstructed_camera(tracking, a);
 +                              MovieReconstructedCamera *cam;
 +
 +                              cam= BKE_tracking_get_reconstructed_camera(tracking, object, a);
  
                                if(!cam) {
                                        sc->user.framenr= a;
@@@ -2899,18 -2562,16 +2900,18 @@@ static int join_tracks_exec(bContext *C
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *act_track, *track, *next;
  
 -      act_track= clip->tracking.act_track;
 +      act_track= BKE_tracking_active_track(tracking);
  
        if(!act_track) {
                BKE_report(op->reports, RPT_ERROR, "No active track to join to");
                return OPERATOR_CANCELLED;
        }
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
                        if(!BKE_tracking_test_join_tracks(act_track, track)) {
                track= track->next;
        }
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                next= track->next;
  
                        BKE_tracking_join_tracks(act_track, track);
  
                        BKE_tracking_free_track(track);
 -                      BLI_freelinkN(&clip->tracking.tracks, track);
 +                      BLI_freelinkN(tracksbase, track);
                }
  
                track= next;
@@@ -2963,8 -2624,7 +2964,8 @@@ static int lock_tracks_exec(bContext *C
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track= tracking->tracks.first;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track= tracksbase->first;
        int action= RNA_enum_get(op->ptr, "action");
  
        while(track) {
@@@ -3013,14 -2673,12 +3014,14 @@@ static int track_copy_color_exec(bConte
  {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
 -      MovieTrackingTrack *track, *act_track= clip->tracking.act_track;
 +      MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track, *act_track= BKE_tracking_active_track(tracking);
  
        if(!act_track)
                return OPERATOR_CANCELLED;
  
 -      track= clip->tracking.tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
                        track->flag&= ~TRACK_CUSTOMCOLOR;
@@@ -3061,12 -2719,11 +3062,12 @@@ static int stabilize_2d_add_exec(bConte
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        MovieTrackingStabilization *stab= &tracking->stabilization;
        int update= 0;
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
                        track->flag|= TRACK_USE_2D_STAB;
@@@ -3111,11 -2768,10 +3112,11 @@@ static int stabilize_2d_remove_exec(bCo
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingStabilization *stab= &tracking->stabilization;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int a= 0, update= 0;
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
                        if(a==stab->act_track) {
@@@ -3170,11 -2826,10 +3171,11 @@@ static int stabilize_2d_select_exec(bCo
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int update= 0;
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
                        BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
@@@ -3213,12 -2868,11 +3214,12 @@@ static int stabilize_2d_set_rotation_ex
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
  
 -      if(tracking->act_track) {
 +      if(act_track) {
                MovieTrackingStabilization *stab= &tracking->stabilization;
  
 -              stab->rot_track= tracking->act_track;
 +              stab->rot_track= act_track;
                stab->ok= 0;
  
                DAG_id_tag_update(&clip->id, 0);
@@@ -3343,8 -2997,7 +3344,8 @@@ static int clean_tracks_exec(bContext *
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
 -      MovieTrackingTrack *track, *next, *act_track= clip->tracking.act_track;
 +      ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
 +      MovieTrackingTrack *track, *next, *act_track= BKE_tracking_active_track(tracking);
        int frames= RNA_int_get(op->ptr, "frames");
        int action= RNA_enum_get(op->ptr, "action");
        float error= RNA_float_get(op->ptr, "error");
        if(error && action==TRACKING_CLEAN_DELETE_SEGMENT)
                action= TRACKING_CLEAN_DELETE_TRACK;
  
 -      track= tracking->tracks.first;
 +      track= tracksbase->first;
        while(track) {
                next= track->next;
  
                                                clip->tracking.act_track= NULL;
  
                                        BKE_tracking_free_track(track);
 -                                      BLI_freelinkN(&clip->tracking.tracks, track);
 +                                      BLI_freelinkN(tracksbase, track);
                                        track= NULL;
                                }
  
                                                clip->tracking.act_track= NULL;
  
                                        BKE_tracking_free_track(track);
 -                                      BLI_freelinkN(&clip->tracking.tracks, track);
 +                                      BLI_freelinkN(tracksbase, track);
                                }
                        }
                }
@@@ -3438,71 -3091,3 +3439,71 @@@ void CLIP_OT_clean_tracks(wmOperatorTyp
        RNA_def_float(ot->srna, "error", 0.0f, 0.0f, FLT_MAX, "Reprojection Error", "Effect on tracks with have got larger reprojection error", 0.0f, 100.0f);
        RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
  }
 +
 +/********************** add tracking object *********************/
 +
 +static int tracking_object_new_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      SpaceClip *sc= CTX_wm_space_clip(C);
 +      MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +
 +      BKE_tracking_new_object(tracking, "Object");
 +
 +      WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void CLIP_OT_tracking_object_new(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Add Tracking Object";
 +      ot->description= "Add new object for tracking";
 +      ot->idname= "CLIP_OT_tracking_object_new";
 +
 +      /* api callbacks */
 +      ot->exec= tracking_object_new_exec;
 +      ot->poll= ED_space_clip_poll;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +/********************** remove tracking object *********************/
 +
 +static int tracking_object_remove_exec(bContext *C, wmOperator *op)
 +{
 +      SpaceClip *sc= CTX_wm_space_clip(C);
 +      MovieClip *clip= ED_space_clip(sc);
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *object;
 +
 +      object= BKE_tracking_active_object(tracking);
 +
 +      if(object->flag&TRACKING_OBJECT_CAMERA) {
 +              BKE_report(op->reports, RPT_WARNING, "Object used for camera tracking can't be deleted");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      BKE_tracking_remove_object(tracking, object);
 +
 +      WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Movie Tracking Object";
 +      ot->description= "Remove object for tracking";
 +      ot->idname= "CLIP_OT_tracking_object_remove";
 +
 +      /* api callbacks */
 +      ot->exec= tracking_object_remove_exec;
 +      ot->poll= ED_space_clip_poll;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
index 79c08c8dea9a1f8cee5932aef8f59ce13f3aa21c,c6775873fabfc6309063fbd0e04a55ec3348329e..7f54821c98d34d4227c419f94410ced7d0bb532f
@@@ -1500,49 -1500,48 +1500,49 @@@ static void draw_bundle_sphere(void
        glCallList(displist);
  }
  
 -static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip, int flag)
 +static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
 +                      MovieClip *clip, MovieTrackingObject *tracking_object, int flag, int *global_track_index)
  {
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingTrack *track;
 -      float mat[4][4], imat[4][4], curcol[4];
 +      float mat[4][4], imat[4][4];
        unsigned char col[4], scol[4];
 -      int bundlenr= 1;
 -
 -      if((v3d->flag2&V3D_SHOW_RECONSTRUCTION)==0)
 -              return;
 -
 -      if(v3d->flag2&V3D_RENDER_OVERRIDE)
 -              return;
 -
 -      glGetFloatv(GL_CURRENT_COLOR, curcol);
 +      int tracknr= *global_track_index;
 +      ListBase *tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
  
        UI_GetThemeColor4ubv(TH_TEXT, col);
        UI_GetThemeColor4ubv(TH_SELECT, scol);
  
        BKE_get_tracking_mat(scene, base->object, mat);
  
 -      glEnable(GL_LIGHTING);
 -      glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
 -      glEnable(GL_COLOR_MATERIAL);
 -      glShadeModel(GL_SMOOTH);
 +      glPushMatrix();
  
 -      /* current ogl matrix is translated in camera space, bundles should
 -         be rendered in world space, so camera matrix should be "removed"
 -         from current ogl matrix */
 -      invert_m4_m4(imat, base->object->obmat);
 +      if(tracking_object->flag & TRACKING_OBJECT_CAMERA) {
 +              /* current ogl matrix is translated in camera space, bundles should
 +                 be rendered in world space, so camera matrix should be "removed"
 +                 from current ogl matrix */
 +              invert_m4_m4(imat, base->object->obmat);
  
 -      glPushMatrix();
 -      glMultMatrixf(imat);
 -      glMultMatrixf(mat);
 +              glMultMatrixf(imat);
 +              glMultMatrixf(mat);
 +      }
 +      else {
 +              float obmat[4][4];
 +
 +              BKE_tracking_get_interpolated_camera(tracking, tracking_object, scene->r.cfra, obmat);
 +
 +              invert_m4_m4(imat, obmat);
 +              glMultMatrixf(imat);
 +      }
 +
 +      for (track= tracksbase->first; track; track= track->next) {
 +              int selected= TRACK_SELECTED(track);
  
 -      for ( track= tracking->tracks.first; track; track= track->next) {
 -              int selected= track->flag&SELECT || track->pat_flag&SELECT || track->search_flag&SELECT;
                if((track->flag&TRACK_HAS_BUNDLE)==0)
                        continue;
  
                if(flag&DRAW_PICKING)
 -                      glLoadName(base->selcol + (bundlenr<<16));
 +                      glLoadName(base->selcol + (tracknr<<16));
  
                glPushMatrix();
                        glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
  
                        if(v3d->drawtype==OB_WIRE) {
                                glDisable(GL_LIGHTING);
 -                              glDepthMask(0);
  
                                if(selected) {
                                        if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
  
                                drawaxes(0.05f, v3d->bundle_drawtype);
  
 -                              glDepthMask(1);
                                glEnable(GL_LIGHTING);
                        } else if(v3d->drawtype>OB_WIRE) {
                                if(v3d->bundle_drawtype==OB_EMPTY_SPHERE) {
                                                if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
                                                else UI_ThemeColor(TH_SELECT);
  
 -                                              glDepthMask(0);
                                                glLineWidth(2.f);
                                                glDisable(GL_LIGHTING);
                                                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                                                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                                                glEnable(GL_LIGHTING);
                                                glLineWidth(1.f);
 -                                              glDepthMask(1);
                                        }
  
                                        if(track->flag&TRACK_CUSTOMCOLOR) glColor3fv(track->color);
                                        draw_bundle_sphere();
                                } else {
                                        glDisable(GL_LIGHTING);
 -                                      glDepthMask(0);
  
                                        if(selected) {
                                                if(base==BASACT) UI_ThemeColor(TH_ACTIVE);
  
                                        drawaxes(0.05f, v3d->bundle_drawtype);
  
 -                                      glDepthMask(1);
                                        glEnable(GL_LIGHTING);
                                }
                        }
                        view3d_cached_text_draw_add(pos, track->name, 10, V3D_CACHE_TEXT_GLOBALSPACE, tcol);
                }
  
 -              bundlenr++;
 +              tracknr++;
        }
  
        if((flag & DRAW_PICKING)==0) {
 -              if(v3d->flag2&V3D_SHOW_CAMERAPATH && clip->tracking.reconstruction.camnr) {
 -                      int a= 0;
 -                      MovieTrackingReconstruction *reconstruction= &tracking->reconstruction;
 -                      MovieReconstructedCamera *camera= tracking->reconstruction.cameras;
 +              if((v3d->flag2&V3D_SHOW_CAMERAPATH) && (tracking_object->flag&TRACKING_OBJECT_CAMERA)) {
 +                      MovieTrackingReconstruction *reconstruction;
 +                      reconstruction= BKE_tracking_object_reconstruction(tracking, tracking_object);
  
 -                      glDisable(GL_LIGHTING);
 -                      UI_ThemeColor(TH_CAMERA_PATH);
 -                      glLineWidth(2.0f);
 +                      if(reconstruction->camnr) {
 +                              MovieReconstructedCamera *camera= reconstruction->cameras;
 +                              int a= 0;
  
 -                      glBegin(GL_LINE_STRIP);
 -                              for(a= 0; a<reconstruction->camnr; a++, camera++) {
 -                                      glVertex3fv(camera->mat[3]);
 -                              }
 -                      glEnd();
 +                              glDisable(GL_LIGHTING);
 +                              UI_ThemeColor(TH_CAMERA_PATH);
 +                              glLineWidth(2.0f);
  
 -                      glLineWidth(1.0f);
 -                      glEnable(GL_LIGHTING);
 +                              glBegin(GL_LINE_STRIP);
 +                                      for(a= 0; a<reconstruction->camnr; a++, camera++) {
 +                                              glVertex3fv(camera->mat[3]);
 +                                      }
 +                                      glEnd();
 +
 +                                      glLineWidth(1.0f);
 +                                      glEnable(GL_LIGHTING);
 +                      }
                }
        }
  
        glPopMatrix();
  
 +      *global_track_index= tracknr;
 +}
 +
 +static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip, int flag)
 +{
 +      MovieTracking *tracking= &clip->tracking;
 +      MovieTrackingObject *tracking_object;
 +      float curcol[4];
 +      int global_track_index= 1;
 +
 +      if((v3d->flag2&V3D_SHOW_RECONSTRUCTION)==0)
 +              return;
 +
 +      if(v3d->flag2&V3D_RENDER_OVERRIDE)
 +              return;
 +
 +      glGetFloatv(GL_CURRENT_COLOR, curcol);
 +
 +      glEnable(GL_LIGHTING);
 +      glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
 +      glEnable(GL_COLOR_MATERIAL);
 +      glShadeModel(GL_SMOOTH);
 +
 +      tracking_object= tracking->objects.first;
 +      while(tracking_object) {
 +              draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
 +                                      flag, &global_track_index);
 +
 +              tracking_object= tracking_object->next;
 +      }
 +
        /* restore */
        glShadeModel(GL_FLAT);
        glDisable(GL_COLOR_MATERIAL);
@@@ -2811,28 -2781,34 +2811,34 @@@ static void draw_em_indices(EditMesh *e
  
        /* For now, reuse appropriate theme colors from stats text colors */
  
-       UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
-       for (v = em->verts.first, i = 0; v; v = v->next, i++) {
-               if (v->f & SELECT) {
-                       sprintf(val, "%d", i);
-                       view3d_cached_text_draw_add(v->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
+       if (em->selectmode & SCE_SELECT_VERTEX) {
+               UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+               for (v = em->verts.first, i = 0; v; v = v->next, i++) {
+                       if (v->f & SELECT) {
+                               sprintf(val, "%d", i);
+                               view3d_cached_text_draw_add(v->co, val, 0, V3D_CACHE_TEXT_ASCII, col);
+                       }
                }
        }
  
-       UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
-       for (e = em->edges.first, i = 0; e; e = e->next, i++) {
-               if (e->f & SELECT) {
-                       sprintf(val, "%d", i);
-                       mid_v3_v3v3(pos, e->v1->co, e->v2->co);
-                       view3d_cached_text_draw_add(pos, val, 0, V3D_CACHE_TEXT_ASCII, col);
+       if (em->selectmode & SCE_SELECT_EDGE) {
+               UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
+               for (e = em->edges.first, i = 0; e; e = e->next, i++) {
+                       if (e->f & SELECT) {
+                               sprintf(val, "%d", i);
+                               mid_v3_v3v3(pos, e->v1->co, e->v2->co);
+                               view3d_cached_text_draw_add(pos, val, 0, V3D_CACHE_TEXT_ASCII, col);
+                       }
                }
        }
  
-       UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
-       for (f = em->faces.first, i = 0; f; f = f->next, i++) {
-               if (f->f & SELECT) {
-                       sprintf(val, "%d", i);
-                       view3d_cached_text_draw_add(f->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
+       if (em->selectmode & SCE_SELECT_FACE) {
+               UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
+               for (f = em->faces.first, i = 0; f; f = f->next, i++) {
+                       if (f->f & SELECT) {
+                               sprintf(val, "%d", i);
+                               view3d_cached_text_draw_add(f->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
+                       }
                }
        }
  }
@@@ -6873,34 -6849,7 +6879,34 @@@ void draw_object(Scene *scene, ARegion 
                                ListBase targets = {NULL, NULL};
                                bConstraintTarget *ct;
                                
 -                              if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) {
 +                              if(ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
 +                                      /* special case for object solver and follow track constraints because they don't fill
 +                                         constraint targets properly (design limitation -- scene is needed for their target
 +                                         but it can't be accessed from get_targets callvack) */
 +
 +                                      Object *camob= NULL;
 +
 +                                      if(cti->type==CONSTRAINT_TYPE_FOLLOWTRACK) {
 +                                              bFollowTrackConstraint *data= (bFollowTrackConstraint *)curcon->data;
 +
 +                                              camob= data->camera ? data->camera : scene->camera;
 +                                      }
 +                                      else if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
 +                                              bObjectSolverConstraint *data= (bObjectSolverConstraint *)curcon->data;
 +
 +                                              camob= data->camera ? data->camera : scene->camera;
 +                                      }
 +
 +                                      if(camob) {
 +                                              setlinestyle(3);
 +                                              glBegin(GL_LINES);
 +                                              glVertex3fv(camob->obmat[3]);
 +                                              glVertex3fv(ob->obmat[3]);
 +                                              glEnd();
 +                                              setlinestyle(0);
 +                                      }
 +                              }
 +                              else if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) {
                                        cti->get_constraint_targets(curcon, &targets);
                                        
                                        for (ct= targets.first; ct; ct= ct->next) {
index 50c1779960dc9c7bba2d130e9fcac49408fe5d0b,87c680a6ee2636b7208cdc91748cce5797d70b2b..f5abf00bd44d0e9a44b041e44e2745e97202ebde
@@@ -126,10 -126,10 +126,10 @@@ typedef struct bPythonConstraint 
  
  
  /* Inverse-Kinematics (IK) constraint
-    This constraint supports a variety of mode determine by the type field 
-    according to B_CONSTRAINT_IK_TYPE.
-    Some fields are used by all types, some are specific to some types
-    This is indicated in the comments for each field
+  * This constraint supports a variety of mode determine by the type field
+  * according to B_CONSTRAINT_IK_TYPE.
+  * Some fields are used by all types, some are specific to some types
+  * This is indicated in the comments for each field
   */
  typedef struct bKinematicConstraint {
        struct Object           *tar;                   /* All: target object in case constraint needs a target */
@@@ -412,8 -412,6 +412,8 @@@ typedef struct bFollowTrackConstraint 
        struct MovieClip        *clip;
        char    track[24];
        int             flag, pad;
 +      char            object[24];
 +      struct Object *camera;
  } bFollowTrackConstraint;
  
  /* Camera Solver constraints */
@@@ -422,15 -420,6 +422,15 @@@ typedef struct bCameraSolverConstraint 
        int             flag, pad;
  } bCameraSolverConstraint;
  
 +/* Camera Solver constraints */
 +typedef struct bObjectSolverConstraint {
 +      struct MovieClip        *clip;
 +      int             flag, pad;
 +      char            object[24];
 +      float           invmat[4][4];   /* parent-inverse matrix to use */
 +      struct Object *camera;
 +} bObjectSolverConstraint;
 +
  /* ------------------------------------------ */
  
  /* bConstraint->type 
@@@ -466,7 -455,6 +466,7 @@@ typedef enum eBConstraint_Types 
        CONSTRAINT_TYPE_PIVOT,                          /* Pivot Constraint */
        CONSTRAINT_TYPE_FOLLOWTRACK,            /* Follow Track Constraint */
        CONSTRAINT_TYPE_CAMERASOLVER,           /* Camera Solver Constraint */
 +      CONSTRAINT_TYPE_OBJECTSOLVER,           /* Object Solver Constraint */
        
        /* NOTE: no constraints are allowed to be added after this */
        NUM_CONSTRAINT_TYPES
@@@ -774,11 -762,6 +774,11 @@@ typedef enum eCameraSolver_Flags 
        CAMERASOLVER_ACTIVECLIP = (1<<0)
  } eCameraSolver_Flags;
  
 +/* ObjectSolver Constraint -> flag */
 +typedef enum eObjectSolver_Flags {
 +      OBJECTSOLVER_ACTIVECLIP = (1<<0)
 +} eObjectSolver_Flags;
 +
  /* Rigid-Body Constraint */
  #define CONSTRAINT_DRAW_PIVOT 0x40
  #define       CONSTRAINT_DISABLE_LINKED_COLLISION 0x80