1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup bke
22  */
23 
24 #include <limits.h>
25 #include <math.h>
26 #include <memory.h>
27 #include <stddef.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "DNA_anim_types.h"
32 #include "DNA_camera_types.h"
33 #include "DNA_gpencil_types.h"
34 #include "DNA_movieclip_types.h"
35 #include "DNA_object_types.h" /* SELECT */
36 #include "DNA_scene_types.h"
37 
38 #include "BLI_bitmap_draw_2d.h"
39 #include "BLI_ghash.h"
40 #include "BLI_listbase.h"
41 #include "BLI_math.h"
42 #include "BLI_math_base.h"
43 #include "BLI_string.h"
44 #include "BLI_string_utils.h"
45 #include "BLI_threads.h"
46 #include "BLI_utildefines.h"
47 
48 #include "BLT_translation.h"
49 
50 #include "BKE_fcurve.h"
51 #include "BKE_layer.h"
52 #include "BKE_lib_id.h"
53 #include "BKE_movieclip.h"
54 #include "BKE_object.h"
55 #include "BKE_scene.h"
56 #include "BKE_tracking.h"
57 
58 #include "IMB_imbuf.h"
59 #include "IMB_imbuf_types.h"
60 
61 #include "RNA_access.h"
62 
63 #include "libmv-capi.h"
64 #include "tracking_private.h"
65 
66 typedef struct MovieDistortion {
67   struct libmv_CameraIntrinsics *intrinsics;
68   /* Parameters needed for coordinates normalization. */
69   float principal[2];
70   float pixel_aspect;
71   float focal;
72 } MovieDistortion;
73 
74 static struct {
75   ListBase tracks;
76 } tracking_clipboard;
77 
78 /*********************** Common functions *************************/
79 
80 /* Free the whole list of tracks, list's head and tail are set to NULL. */
tracking_tracks_free(ListBase * tracks)81 static void tracking_tracks_free(ListBase *tracks)
82 {
83   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks) {
84     BKE_tracking_track_free(track);
85   }
86 
87   BLI_freelistN(tracks);
88 }
89 
90 /* Free the whole list of plane tracks, list's head and tail are set to NULL. */
tracking_plane_tracks_free(ListBase * plane_tracks)91 static void tracking_plane_tracks_free(ListBase *plane_tracks)
92 {
93   LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks) {
94     BKE_tracking_plane_track_free(plane_track);
95   }
96 
97   BLI_freelistN(plane_tracks);
98 }
99 
100 /* Free reconstruction structures, only frees contents of a structure,
101  * (if structure is allocated in heap, it shall be handled outside).
102  *
103  * All the pointers inside structure becomes invalid after this call.
104  */
tracking_reconstruction_free(MovieTrackingReconstruction * reconstruction)105 static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruction)
106 {
107   if (reconstruction->cameras) {
108     MEM_freeN(reconstruction->cameras);
109   }
110 }
111 
112 /* Free memory used by tracking object, only frees contents of the structure,
113  * (if structure is allocated in heap, it shall be handled outside).
114  *
115  * All the pointers inside structure becomes invalid after this call.
116  */
tracking_object_free(MovieTrackingObject * object)117 static void tracking_object_free(MovieTrackingObject *object)
118 {
119   tracking_tracks_free(&object->tracks);
120   tracking_plane_tracks_free(&object->plane_tracks);
121   tracking_reconstruction_free(&object->reconstruction);
122 }
123 
124 /* Free list of tracking objects, list's head and tail is set to NULL. */
tracking_objects_free(ListBase * objects)125 static void tracking_objects_free(ListBase *objects)
126 {
127   /* Free objects contents. */
128   LISTBASE_FOREACH (MovieTrackingObject *, object, objects) {
129     tracking_object_free(object);
130   }
131 
132   /* Free objects themselves. */
133   BLI_freelistN(objects);
134 }
135 
136 /* Free memory used by a dopesheet, only frees dopesheet contents.
137  * leaving dopesheet crystal clean for further usage.
138  */
tracking_dopesheet_free(MovieTrackingDopesheet * dopesheet)139 static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
140 {
141   MovieTrackingDopesheetChannel *channel;
142 
143   /* Free channel's segments. */
144   channel = dopesheet->channels.first;
145   while (channel) {
146     if (channel->segments) {
147       MEM_freeN(channel->segments);
148     }
149 
150     channel = channel->next;
151   }
152 
153   /* Free lists themselves. */
154   BLI_freelistN(&dopesheet->channels);
155   BLI_freelistN(&dopesheet->coverage_segments);
156 
157   /* Ensure lists are clean. */
158   BLI_listbase_clear(&dopesheet->channels);
159   BLI_listbase_clear(&dopesheet->coverage_segments);
160   dopesheet->tot_channel = 0;
161 }
162 
163 /* Free tracking structure, only frees structure contents
164  * (if structure is allocated in heap, it shall be handled outside).
165  *
166  * All the pointers inside structure becomes invalid after this call.
167  */
BKE_tracking_free(MovieTracking * tracking)168 void BKE_tracking_free(MovieTracking *tracking)
169 {
170   tracking_tracks_free(&tracking->tracks);
171   tracking_plane_tracks_free(&tracking->plane_tracks);
172   tracking_reconstruction_free(&tracking->reconstruction);
173   tracking_objects_free(&tracking->objects);
174 
175   if (tracking->camera.intrinsics) {
176     BKE_tracking_distortion_free(tracking->camera.intrinsics);
177   }
178 
179   tracking_dopesheet_free(&tracking->dopesheet);
180 }
181 
182 /* Copy the whole list of tracks. */
tracking_tracks_copy(ListBase * tracks_dst,const ListBase * tracks_src,GHash * tracks_mapping,const int flag)183 static void tracking_tracks_copy(ListBase *tracks_dst,
184                                  const ListBase *tracks_src,
185                                  GHash *tracks_mapping,
186                                  const int flag)
187 {
188   BLI_listbase_clear(tracks_dst);
189   BLI_ghash_clear(tracks_mapping, NULL, NULL);
190 
191   LISTBASE_FOREACH (MovieTrackingTrack *, track_src, tracks_src) {
192     MovieTrackingTrack *track_dst = MEM_dupallocN(track_src);
193     if (track_src->markers) {
194       track_dst->markers = MEM_dupallocN(track_src->markers);
195     }
196     if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
197       id_us_plus(&track_dst->gpd->id);
198     }
199     BLI_addtail(tracks_dst, track_dst);
200     BLI_ghash_insert(tracks_mapping, track_src, track_dst);
201   }
202 }
203 
204 /* Copy the whole list of plane tracks
205  * (need whole MovieTracking structures due to embedded pointers to tracks).
206  * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
tracking_plane_tracks_copy(ListBase * plane_tracks_list_dst,const ListBase * plane_tracks_list_src,GHash * tracks_mapping,const int flag)207 static void tracking_plane_tracks_copy(ListBase *plane_tracks_list_dst,
208                                        const ListBase *plane_tracks_list_src,
209                                        GHash *tracks_mapping,
210                                        const int flag)
211 {
212   BLI_listbase_clear(plane_tracks_list_dst);
213 
214   LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track_src, plane_tracks_list_src) {
215     MovieTrackingPlaneTrack *plane_track_dst = MEM_dupallocN(plane_track_src);
216     if (plane_track_src->markers) {
217       plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers);
218     }
219     plane_track_dst->point_tracks = MEM_mallocN(
220         sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__);
221     for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
222       plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping,
223                                                           plane_track_src->point_tracks[i]);
224     }
225     if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
226       id_us_plus(&plane_track_dst->image->id);
227     }
228     BLI_addtail(plane_tracks_list_dst, plane_track_dst);
229   }
230 }
231 
232 /* Copy reconstruction structure. */
tracking_reconstruction_copy(MovieTrackingReconstruction * reconstruction_dst,const MovieTrackingReconstruction * reconstruction_src,const int UNUSED (flag))233 static void tracking_reconstruction_copy(MovieTrackingReconstruction *reconstruction_dst,
234                                          const MovieTrackingReconstruction *reconstruction_src,
235                                          const int UNUSED(flag))
236 {
237   *reconstruction_dst = *reconstruction_src;
238   if (reconstruction_src->cameras) {
239     reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras);
240   }
241 }
242 
243 /* Copy stabilization structure. */
tracking_stabilization_copy(MovieTrackingStabilization * stabilization_dst,const MovieTrackingStabilization * stabilization_src,const int UNUSED (flag))244 static void tracking_stabilization_copy(MovieTrackingStabilization *stabilization_dst,
245                                         const MovieTrackingStabilization *stabilization_src,
246                                         const int UNUSED(flag))
247 {
248   *stabilization_dst = *stabilization_src;
249 }
250 
251 /* Copy tracking object. */
tracking_object_copy(MovieTrackingObject * object_dst,const MovieTrackingObject * object_src,GHash * tracks_mapping,const int flag)252 static void tracking_object_copy(MovieTrackingObject *object_dst,
253                                  const MovieTrackingObject *object_src,
254                                  GHash *tracks_mapping,
255                                  const int flag)
256 {
257   *object_dst = *object_src;
258   tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag);
259   tracking_plane_tracks_copy(
260       &object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag);
261   tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag);
262 }
263 
264 /* Copy list of tracking objects. */
tracking_objects_copy(ListBase * objects_dst,const ListBase * objects_src,GHash * tracks_mapping,const int flag)265 static void tracking_objects_copy(ListBase *objects_dst,
266                                   const ListBase *objects_src,
267                                   GHash *tracks_mapping,
268                                   const int flag)
269 {
270   BLI_listbase_clear(objects_dst);
271 
272   LISTBASE_FOREACH (MovieTrackingObject *, object_src, objects_src) {
273     MovieTrackingObject *object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
274     tracking_object_copy(object_dst, object_src, tracks_mapping, flag);
275     BLI_addtail(objects_dst, object_dst);
276   }
277 }
278 
279 /* Copy tracking structure content. */
BKE_tracking_copy(MovieTracking * tracking_dst,const MovieTracking * tracking_src,const int flag)280 void BKE_tracking_copy(MovieTracking *tracking_dst,
281                        const MovieTracking *tracking_src,
282                        const int flag)
283 {
284   GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
285 
286   *tracking_dst = *tracking_src;
287 
288   tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag);
289   tracking_plane_tracks_copy(
290       &tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag);
291   tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag);
292   tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag);
293   if (tracking_src->act_track) {
294     tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
295   }
296   if (tracking_src->act_plane_track) {
297     MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst;
298     for (plane_track_src = tracking_src->plane_tracks.first,
299         plane_track_dst = tracking_dst->plane_tracks.first;
300          !ELEM(NULL, plane_track_src, plane_track_dst);
301          plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next) {
302       if (plane_track_src == tracking_src->act_plane_track) {
303         tracking_dst->act_plane_track = plane_track_dst;
304         break;
305       }
306     }
307   }
308 
309   /* Warning! Will override tracks_mapping. */
310   tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag);
311 
312   /* Those remaining are runtime data, they will be reconstructed as needed,
313    * do not bother copying them. */
314   tracking_dst->dopesheet.ok = false;
315   BLI_listbase_clear(&tracking_dst->dopesheet.channels);
316   BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments);
317 
318   tracking_dst->camera.intrinsics = NULL;
319   tracking_dst->stats = NULL;
320 
321   BLI_ghash_free(tracks_mapping, NULL, NULL);
322 }
323 
324 /* Initialize motion tracking settings to default values,
325  * used when new movie clip datablock is created.
326  */
BKE_tracking_settings_init(MovieTracking * tracking)327 void BKE_tracking_settings_init(MovieTracking *tracking)
328 {
329   tracking->camera.sensor_width = 35.0f;
330   tracking->camera.pixel_aspect = 1.0f;
331   tracking->camera.units = CAMERA_UNITS_MM;
332 
333   tracking->settings.default_motion_model = TRACK_MOTION_MODEL_TRANSLATION;
334   tracking->settings.default_minimum_correlation = 0.75;
335   tracking->settings.default_pattern_size = 21;
336   tracking->settings.default_search_size = 71;
337   tracking->settings.default_algorithm_flag |= TRACK_ALGORITHM_FLAG_USE_BRUTE;
338   tracking->settings.default_weight = 1.0f;
339   tracking->settings.dist = 1;
340   tracking->settings.object_distance = 1;
341 
342   tracking->stabilization.scaleinf = 1.0f;
343   tracking->stabilization.anchor_frame = 1;
344   zero_v2(tracking->stabilization.target_pos);
345   tracking->stabilization.target_rot = 0.0f;
346   tracking->stabilization.scale = 1.0f;
347 
348   tracking->stabilization.act_track = 0;
349   tracking->stabilization.act_rot_track = 0;
350   tracking->stabilization.tot_track = 0;
351   tracking->stabilization.tot_rot_track = 0;
352 
353   tracking->stabilization.scaleinf = 1.0f;
354   tracking->stabilization.locinf = 1.0f;
355   tracking->stabilization.rotinf = 1.0f;
356   tracking->stabilization.maxscale = 2.0f;
357   tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
358   tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
359 
360   BKE_tracking_object_add(tracking, "Camera");
361 }
362 
363 /* Get list base of active object's tracks. */
BKE_tracking_get_active_tracks(MovieTracking * tracking)364 ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
365 {
366   MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
367 
368   if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
369     return &object->tracks;
370   }
371 
372   return &tracking->tracks;
373 }
374 
375 /* Get list base of active object's plane tracks. */
BKE_tracking_get_active_plane_tracks(MovieTracking * tracking)376 ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
377 {
378   MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
379 
380   if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
381     return &object->plane_tracks;
382   }
383 
384   return &tracking->plane_tracks;
385 }
386 
387 /* Get reconstruction data of active object. */
BKE_tracking_get_active_reconstruction(MovieTracking * tracking)388 MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
389 {
390   MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
391 
392   return BKE_tracking_object_get_reconstruction(tracking, object);
393 }
394 
395 /* Get transformation matrix for a given object which is used
396  * for parenting motion tracker reconstruction to 3D world.
397  */
BKE_tracking_get_camera_object_matrix(Object * camera_object,float mat[4][4])398 void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4])
399 {
400   BLI_assert(camera_object != NULL);
401   /* NOTE: Construct matrix from scratch rather than using obmat because the camera object here
402    * will have camera solver constraint taken into account. But here we do not want or need it:
403    * object is solved in camera space (as in, camera is stationary and object is moving).
404    *
405    * This will include animation applied on the camera, but not possible camera rig. This isn't
406    * an issue in practice due to the way how VFX is constructed.
407    *
408    * If we ever need to support crazy setups like that one possible solution would be to use
409    * final camera matrix and multiple it by an inverse of solved camera matrix at the current
410    * frame. */
411   BKE_object_where_is_calc_mat4(camera_object, mat);
412 }
413 
414 /* Get projection matrix for camera specified by given tracking object
415  * and frame number.
416  *
417  * NOTE: frame number should be in clip space, not scene space
418  */
BKE_tracking_get_projection_matrix(MovieTracking * tracking,MovieTrackingObject * object,int framenr,int winx,int winy,float mat[4][4])419 void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
420                                         MovieTrackingObject *object,
421                                         int framenr,
422                                         int winx,
423                                         int winy,
424                                         float mat[4][4])
425 {
426   MovieReconstructedCamera *camera;
427   float lens = tracking->camera.focal * tracking->camera.sensor_width / (float)winx;
428   float viewfac, pixsize, left, right, bottom, top, clipsta, clipend;
429   float winmat[4][4];
430   float ycor = 1.0f / tracking->camera.pixel_aspect;
431   float shiftx, shifty, winside = (float)min_ii(winx, winy);
432 
433   BKE_tracking_camera_shift_get(tracking, winx, winy, &shiftx, &shifty);
434 
435   clipsta = 0.1f;
436   clipend = 1000.0f;
437 
438   if (winx >= winy) {
439     viewfac = (lens * winx) / tracking->camera.sensor_width;
440   }
441   else {
442     viewfac = (ycor * lens * winy) / tracking->camera.sensor_width;
443   }
444 
445   pixsize = clipsta / viewfac;
446 
447   left = -0.5f * (float)winx + shiftx * winside;
448   bottom = -0.5f * (ycor) * (float)winy + shifty * winside;
449   right = 0.5f * (float)winx + shiftx * winside;
450   top = 0.5f * (ycor) * (float)winy + shifty * winside;
451 
452   left *= pixsize;
453   right *= pixsize;
454   bottom *= pixsize;
455   top *= pixsize;
456 
457   perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
458 
459   camera = BKE_tracking_camera_get_reconstructed(tracking, object, framenr);
460 
461   if (camera) {
462     float imat[4][4];
463 
464     invert_m4_m4(imat, camera->mat);
465     mul_m4_m4m4(mat, winmat, imat);
466   }
467   else {
468     copy_m4_m4(mat, winmat);
469   }
470 }
471 
472 /*********************** clipboard *************************/
473 
474 /* Free clipboard by freeing memory used by all tracks in it. */
BKE_tracking_clipboard_free(void)475 void BKE_tracking_clipboard_free(void)
476 {
477   MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
478 
479   while (track) {
480     next_track = track->next;
481 
482     BKE_tracking_track_free(track);
483     MEM_freeN(track);
484 
485     track = next_track;
486   }
487 
488   BLI_listbase_clear(&tracking_clipboard.tracks);
489 }
490 
491 /* Copy selected tracks from specified object to the clipboard. */
BKE_tracking_clipboard_copy_tracks(MovieTracking * tracking,MovieTrackingObject * object)492 void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingObject *object)
493 {
494   ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
495   MovieTrackingTrack *track = tracksbase->first;
496 
497   /* First drop all tracks from current clipboard. */
498   BKE_tracking_clipboard_free();
499 
500   /* Then copy all selected visible tracks to it. */
501   while (track) {
502     if (TRACK_SELECTED(track) && (track->flag & TRACK_HIDDEN) == 0) {
503       MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
504 
505       BLI_addtail(&tracking_clipboard.tracks, new_track);
506     }
507 
508     track = track->next;
509   }
510 }
511 
512 /* Check whether there are any tracks in the clipboard. */
BKE_tracking_clipboard_has_tracks(void)513 bool BKE_tracking_clipboard_has_tracks(void)
514 {
515   return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
516 }
517 
518 /* Paste tracks from clipboard to specified object.
519  *
520  * Names of new tracks in object are guaranteed to
521  * be unique here.
522  */
BKE_tracking_clipboard_paste_tracks(MovieTracking * tracking,MovieTrackingObject * object)523 void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingObject *object)
524 {
525   ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
526   MovieTrackingTrack *track = tracking_clipboard.tracks.first;
527 
528   while (track) {
529     MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
530     if (track->prev == NULL) {
531       tracking->act_track = new_track;
532     }
533 
534     BLI_addtail(tracksbase, new_track);
535     BKE_tracking_track_unique_name(tracksbase, new_track);
536 
537     track = track->next;
538   }
539 }
540 
541 /*********************** Tracks *************************/
542 
543 /* Add new track to a specified tracks base.
544  *
545  * Coordinates are expected to be in normalized 0..1 space,
546  * frame number is expected to be in clip space.
547  *
548  * Width and height are clip's dimension used to scale track's
549  * pattern and search regions.
550  */
BKE_tracking_track_add(MovieTracking * tracking,ListBase * tracksbase,float x,float y,int framenr,int width,int height)551 MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
552                                            ListBase *tracksbase,
553                                            float x,
554                                            float y,
555                                            int framenr,
556                                            int width,
557                                            int height)
558 {
559   MovieTrackingTrack *track;
560   MovieTrackingMarker marker;
561   MovieTrackingSettings *settings = &tracking->settings;
562 
563   float half_pattern = (float)settings->default_pattern_size / 2.0f;
564   float half_search = (float)settings->default_search_size / 2.0f;
565   float pat[2], search[2];
566 
567   pat[0] = half_pattern / (float)width;
568   pat[1] = half_pattern / (float)height;
569 
570   search[0] = half_search / (float)width;
571   search[1] = half_search / (float)height;
572 
573   track = MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track");
574   strcpy(track->name, "Track");
575 
576   /* fill track's settings from default settings */
577   track->motion_model = settings->default_motion_model;
578   track->minimum_correlation = settings->default_minimum_correlation;
579   track->margin = settings->default_margin;
580   track->pattern_match = settings->default_pattern_match;
581   track->frames_limit = settings->default_frames_limit;
582   track->flag = settings->default_flag;
583   track->algorithm_flag = settings->default_algorithm_flag;
584   track->weight = settings->default_weight;
585   track->weight_stab = settings->default_weight;
586 
587   memset(&marker, 0, sizeof(marker));
588   marker.pos[0] = x;
589   marker.pos[1] = y;
590   marker.framenr = framenr;
591 
592   marker.pattern_corners[0][0] = -pat[0];
593   marker.pattern_corners[0][1] = -pat[1];
594 
595   marker.pattern_corners[1][0] = pat[0];
596   marker.pattern_corners[1][1] = -pat[1];
597 
598   negate_v2_v2(marker.pattern_corners[2], marker.pattern_corners[0]);
599   negate_v2_v2(marker.pattern_corners[3], marker.pattern_corners[1]);
600 
601   copy_v2_v2(marker.search_max, search);
602   negate_v2_v2(marker.search_min, search);
603 
604   BKE_tracking_marker_insert(track, &marker);
605 
606   BLI_addtail(tracksbase, track);
607   BKE_tracking_track_unique_name(tracksbase, track);
608 
609   return track;
610 }
611 
612 /* Duplicate the specified track, result will no belong to any list. */
BKE_tracking_track_duplicate(MovieTrackingTrack * track)613 MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
614 {
615   MovieTrackingTrack *new_track;
616 
617   new_track = MEM_callocN(sizeof(MovieTrackingTrack), "tracking_track_duplicate new_track");
618 
619   *new_track = *track;
620   new_track->next = new_track->prev = NULL;
621 
622   new_track->markers = MEM_dupallocN(new_track->markers);
623 
624   /* Prevent duplicate from being used for 2D stabilization.
625    * If necessary, it shall be added explicitly.
626    */
627   new_track->flag &= ~TRACK_USE_2D_STAB;
628   new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
629 
630   return new_track;
631 }
632 
633 /* Ensure specified track has got unique name,
634  * if it's not name of specified track will be changed
635  * keeping names of all other tracks unchanged.
636  */
BKE_tracking_track_unique_name(ListBase * tracksbase,MovieTrackingTrack * track)637 void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
638 {
639   BLI_uniquename(tracksbase,
640                  track,
641                  CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"),
642                  '.',
643                  offsetof(MovieTrackingTrack, name),
644                  sizeof(track->name));
645 }
646 
647 /* Free specified track, only frees contents of a structure
648  * (if track is allocated in heap, it shall be handled outside).
649  *
650  * All the pointers inside track becomes invalid after this call.
651  */
BKE_tracking_track_free(MovieTrackingTrack * track)652 void BKE_tracking_track_free(MovieTrackingTrack *track)
653 {
654   if (track->markers) {
655     MEM_freeN(track->markers);
656   }
657 }
658 
659 /* Set flag for all specified track's areas.
660  *
661  * area - which part of marker should be selected. see TRACK_AREA_* constants.
662  * flag - flag to be set for areas.
663  */
BKE_tracking_track_flag_set(MovieTrackingTrack * track,int area,int flag)664 void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
665 {
666   if (area == TRACK_AREA_NONE) {
667     return;
668   }
669 
670   if (area & TRACK_AREA_POINT) {
671     track->flag |= flag;
672   }
673   if (area & TRACK_AREA_PAT) {
674     track->pat_flag |= flag;
675   }
676   if (area & TRACK_AREA_SEARCH) {
677     track->search_flag |= flag;
678   }
679 }
680 
681 /* Clear flag from all specified track's areas.
682  *
683  * area - which part of marker should be selected. see TRACK_AREA_* constants.
684  * flag - flag to be cleared for areas.
685  */
BKE_tracking_track_flag_clear(MovieTrackingTrack * track,int area,int flag)686 void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag)
687 {
688   if (area == TRACK_AREA_NONE) {
689     return;
690   }
691 
692   if (area & TRACK_AREA_POINT) {
693     track->flag &= ~flag;
694   }
695   if (area & TRACK_AREA_PAT) {
696     track->pat_flag &= ~flag;
697   }
698   if (area & TRACK_AREA_SEARCH) {
699     track->search_flag &= ~flag;
700   }
701 }
702 
703 /* Check whether track has got marker at specified frame.
704  *
705  * NOTE: frame number should be in clip space, not scene space.
706  */
BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack * track,int framenr)707 bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr)
708 {
709   return BKE_tracking_marker_get_exact(track, framenr) != NULL;
710 }
711 
712 /* Check whether track has got enabled marker at specified frame.
713  *
714  * NOTE: frame number should be in clip space, not scene space.
715  */
BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack * track,int framenr)716 bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr)
717 {
718   MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
719 
720   return marker && (marker->flag & MARKER_DISABLED) == 0;
721 }
722 
723 /* Clear track's path:
724  *
725  * - If action is TRACK_CLEAR_REMAINED path from ref_frame+1 up to
726  *   end will be clear.
727  *
728  * - If action is TRACK_CLEAR_UPTO path from the beginning up to
729  *   ref_frame-1 will be clear.
730  *
731  * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
732  *
733  * NOTE: frame number should be in clip space, not scene space
734  */
BKE_tracking_track_path_clear(MovieTrackingTrack * track,int ref_frame,int action)735 void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
736 {
737   int a;
738 
739   if (action == TRACK_CLEAR_REMAINED) {
740     a = 1;
741 
742     while (a < track->markersnr) {
743       if (track->markers[a].framenr > ref_frame) {
744         track->markersnr = a;
745         track->markers = MEM_reallocN(track->markers,
746                                       sizeof(MovieTrackingMarker) * track->markersnr);
747 
748         break;
749       }
750 
751       a++;
752     }
753 
754     if (track->markersnr) {
755       tracking_marker_insert_disabled(track, &track->markers[track->markersnr - 1], false, true);
756     }
757   }
758   else if (action == TRACK_CLEAR_UPTO) {
759     a = track->markersnr - 1;
760 
761     while (a >= 0) {
762       if (track->markers[a].framenr <= ref_frame) {
763         memmove(track->markers,
764                 track->markers + a,
765                 (track->markersnr - a) * sizeof(MovieTrackingMarker));
766 
767         track->markersnr = track->markersnr - a;
768         track->markers = MEM_reallocN(track->markers,
769                                       sizeof(MovieTrackingMarker) * track->markersnr);
770 
771         break;
772       }
773 
774       a--;
775     }
776 
777     if (track->markersnr) {
778       tracking_marker_insert_disabled(track, &track->markers[0], true, true);
779     }
780   }
781   else if (action == TRACK_CLEAR_ALL) {
782     MovieTrackingMarker *marker, marker_new;
783 
784     marker = BKE_tracking_marker_get(track, ref_frame);
785     marker_new = *marker;
786 
787     MEM_freeN(track->markers);
788     track->markers = NULL;
789     track->markersnr = 0;
790 
791     BKE_tracking_marker_insert(track, &marker_new);
792 
793     tracking_marker_insert_disabled(track, &marker_new, true, true);
794     tracking_marker_insert_disabled(track, &marker_new, false, true);
795   }
796 }
797 
BKE_tracking_tracks_join(MovieTracking * tracking,MovieTrackingTrack * dst_track,MovieTrackingTrack * src_track)798 void BKE_tracking_tracks_join(MovieTracking *tracking,
799                               MovieTrackingTrack *dst_track,
800                               MovieTrackingTrack *src_track)
801 {
802   int i = 0, a = 0, b = 0, tot;
803   MovieTrackingMarker *markers;
804 
805   tot = dst_track->markersnr + src_track->markersnr;
806   markers = MEM_callocN(tot * sizeof(MovieTrackingMarker), "tmp tracking joined tracks");
807 
808   while (a < src_track->markersnr || b < dst_track->markersnr) {
809     if (b >= dst_track->markersnr) {
810       markers[i] = src_track->markers[a++];
811     }
812     else if (a >= src_track->markersnr) {
813       markers[i] = dst_track->markers[b++];
814     }
815     else if (src_track->markers[a].framenr < dst_track->markers[b].framenr) {
816       markers[i] = src_track->markers[a++];
817     }
818     else if (src_track->markers[a].framenr > dst_track->markers[b].framenr) {
819       markers[i] = dst_track->markers[b++];
820     }
821     else {
822       if ((src_track->markers[a].flag & MARKER_DISABLED) == 0) {
823         if ((dst_track->markers[b].flag & MARKER_DISABLED) == 0) {
824           /* both tracks are enabled on this frame, so find the whole segment
825            * on which tracks are intersecting and blend tracks using linear
826            * interpolation to prevent jumps
827            */
828 
829           MovieTrackingMarker *marker_a, *marker_b;
830           int start_a = a, start_b = b, len = 0, frame = src_track->markers[a].framenr;
831           int inverse = 0;
832 
833           inverse = (b == 0) || (dst_track->markers[b - 1].flag & MARKER_DISABLED) ||
834                     (dst_track->markers[b - 1].framenr != frame - 1);
835 
836           /* find length of intersection */
837           while (a < src_track->markersnr && b < dst_track->markersnr) {
838             marker_a = &src_track->markers[a];
839             marker_b = &dst_track->markers[b];
840 
841             if (marker_a->flag & MARKER_DISABLED || marker_b->flag & MARKER_DISABLED) {
842               break;
843             }
844 
845             if (marker_a->framenr != frame || marker_b->framenr != frame) {
846               break;
847             }
848 
849             frame++;
850             len++;
851             a++;
852             b++;
853           }
854 
855           a = start_a;
856           b = start_b;
857 
858           /* linear interpolation for intersecting frames */
859           for (int j = 0; j < len; j++) {
860             float fac = 0.5f;
861 
862             if (len > 1) {
863               fac = 1.0f / (len - 1) * j;
864             }
865 
866             if (inverse) {
867               fac = 1.0f - fac;
868             }
869 
870             marker_a = &src_track->markers[a];
871             marker_b = &dst_track->markers[b];
872 
873             markers[i] = dst_track->markers[b];
874             interp_v2_v2v2(markers[i].pos, marker_b->pos, marker_a->pos, fac);
875             a++;
876             b++;
877             i++;
878           }
879 
880           /* this values will be incremented at the end of the loop cycle */
881           a--;
882           b--;
883           i--;
884         }
885         else {
886           markers[i] = src_track->markers[a];
887         }
888       }
889       else {
890         markers[i] = dst_track->markers[b];
891       }
892 
893       a++;
894       b++;
895     }
896 
897     i++;
898   }
899 
900   MEM_freeN(dst_track->markers);
901 
902   dst_track->markers = MEM_mallocN(i * sizeof(MovieTrackingMarker), "tracking joined tracks");
903   memcpy(dst_track->markers, markers, i * sizeof(MovieTrackingMarker));
904 
905   dst_track->markersnr = i;
906 
907   MEM_freeN(markers);
908 
909   BKE_tracking_dopesheet_tag_update(tracking);
910 }
911 
BKE_tracking_track_get_named(MovieTracking * tracking,MovieTrackingObject * object,const char * name)912 MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking,
913                                                  MovieTrackingObject *object,
914                                                  const char *name)
915 {
916   ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
917   MovieTrackingTrack *track = tracksbase->first;
918 
919   while (track) {
920     if (STREQ(track->name, name)) {
921       return track;
922     }
923 
924     track = track->next;
925   }
926 
927   return NULL;
928 }
929 
BKE_tracking_track_get_indexed(MovieTracking * tracking,int tracknr,ListBase ** r_tracksbase)930 MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking,
931                                                    int tracknr,
932                                                    ListBase **r_tracksbase)
933 {
934   MovieTrackingObject *object;
935   int cur = 1;
936 
937   object = tracking->objects.first;
938   while (object) {
939     ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
940     MovieTrackingTrack *track = tracksbase->first;
941 
942     while (track) {
943       if (track->flag & TRACK_HAS_BUNDLE) {
944         if (cur == tracknr) {
945           *r_tracksbase = tracksbase;
946           return track;
947         }
948 
949         cur++;
950       }
951 
952       track = track->next;
953     }
954 
955     object = object->next;
956   }
957 
958   *r_tracksbase = NULL;
959 
960   return NULL;
961 }
962 
BKE_tracking_track_get_active(MovieTracking * tracking)963 MovieTrackingTrack *BKE_tracking_track_get_active(MovieTracking *tracking)
964 {
965   ListBase *tracksbase;
966 
967   if (!tracking->act_track) {
968     return NULL;
969   }
970 
971   tracksbase = BKE_tracking_get_active_tracks(tracking);
972 
973   /* check that active track is in current tracks list */
974   if (BLI_findindex(tracksbase, tracking->act_track) != -1) {
975     return tracking->act_track;
976   }
977 
978   return NULL;
979 }
980 
track_mask_gpencil_layer_get(MovieTrackingTrack * track)981 static bGPDlayer *track_mask_gpencil_layer_get(MovieTrackingTrack *track)
982 {
983   bGPDlayer *layer;
984 
985   if (!track->gpd) {
986     return NULL;
987   }
988 
989   layer = track->gpd->layers.first;
990 
991   while (layer) {
992     if (layer->flag & GP_LAYER_ACTIVE) {
993       bGPDframe *frame = layer->frames.first;
994       bool ok = false;
995 
996       while (frame) {
997         if (frame->strokes.first) {
998           ok = true;
999           break;
1000         }
1001 
1002         frame = frame->next;
1003       }
1004 
1005       if (ok) {
1006         return layer;
1007       }
1008     }
1009 
1010     layer = layer->next;
1011   }
1012 
1013   return NULL;
1014 }
1015 
1016 typedef struct TrackMaskSetPixelData {
1017   float *mask;
1018   int mask_width;
1019   int mask_height;
1020 } TrackMaskSetPixelData;
1021 
track_mask_set_pixel_cb(int x,int x_end,int y,void * user_data)1022 static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
1023 {
1024   TrackMaskSetPixelData *data = (TrackMaskSetPixelData *)user_data;
1025   size_t index = (size_t)y * data->mask_width + x;
1026   size_t index_end = (size_t)y * data->mask_width + x_end;
1027   do {
1028     data->mask[index] = 1.0f;
1029   } while (++index != index_end);
1030 }
1031 
track_mask_gpencil_layer_rasterize(int frame_width,int frame_height,const float region_min[2],bGPDlayer * layer,float * mask,int mask_width,int mask_height)1032 static void track_mask_gpencil_layer_rasterize(int frame_width,
1033                                                int frame_height,
1034                                                const float region_min[2],
1035                                                bGPDlayer *layer,
1036                                                float *mask,
1037                                                int mask_width,
1038                                                int mask_height)
1039 {
1040   bGPDframe *frame = layer->frames.first;
1041   TrackMaskSetPixelData data;
1042 
1043   data.mask = mask;
1044   data.mask_width = mask_width;
1045   data.mask_height = mask_height;
1046 
1047   while (frame) {
1048     bGPDstroke *stroke = frame->strokes.first;
1049 
1050     while (stroke) {
1051       bGPDspoint *stroke_points = stroke->points;
1052       if (stroke->flag & GP_STROKE_2DSPACE) {
1053         int *mask_points, *point;
1054         point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
1055                                           "track mask rasterization points");
1056         for (int i = 0; i < stroke->totpoints; i++, point += 2) {
1057           point[0] = stroke_points[i].x * frame_width - region_min[0];
1058           point[1] = stroke_points[i].y * frame_height - region_min[1];
1059         }
1060         /* TODO: add an option to control whether AA is enabled or not */
1061         BLI_bitmap_draw_2d_poly_v2i_n(0,
1062                                       0,
1063                                       mask_width,
1064                                       mask_height,
1065                                       (const int(*)[2])mask_points,
1066                                       stroke->totpoints,
1067                                       track_mask_set_pixel_cb,
1068                                       &data);
1069         MEM_freeN(mask_points);
1070       }
1071       stroke = stroke->next;
1072     }
1073     frame = frame->next;
1074   }
1075 }
1076 
1077 /* Region is in pixel space, relative to marker's center. */
tracking_track_get_mask_for_region(int frame_width,int frame_height,const float region_min[2],const float region_max[2],MovieTrackingTrack * track)1078 float *tracking_track_get_mask_for_region(int frame_width,
1079                                           int frame_height,
1080                                           const float region_min[2],
1081                                           const float region_max[2],
1082                                           MovieTrackingTrack *track)
1083 {
1084   float *mask = NULL;
1085   bGPDlayer *layer = track_mask_gpencil_layer_get(track);
1086   if (layer != NULL) {
1087     const int mask_width = region_max[0] - region_min[0];
1088     const int mask_height = region_max[1] - region_min[1];
1089     mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
1090     track_mask_gpencil_layer_rasterize(
1091         frame_width, frame_height, region_min, layer, mask, mask_width, mask_height);
1092   }
1093   return mask;
1094 }
1095 
BKE_tracking_track_get_mask(int frame_width,int frame_height,MovieTrackingTrack * track,MovieTrackingMarker * marker)1096 float *BKE_tracking_track_get_mask(int frame_width,
1097                                    int frame_height,
1098                                    MovieTrackingTrack *track,
1099                                    MovieTrackingMarker *marker)
1100 {
1101   /* Convert normalized space marker's search area to pixel-space region. */
1102   const float region_min[2] = {
1103       marker->search_min[0] * frame_width,
1104       marker->search_min[1] * frame_height,
1105   };
1106   const float region_max[2] = {
1107       marker->search_max[0] * frame_width,
1108       marker->search_max[1] * frame_height,
1109   };
1110   return tracking_track_get_mask_for_region(
1111       frame_width, frame_height, region_min, region_max, track);
1112 }
1113 
BKE_tracking_track_get_weight_for_marker(MovieClip * clip,MovieTrackingTrack * track,MovieTrackingMarker * marker)1114 float BKE_tracking_track_get_weight_for_marker(MovieClip *clip,
1115                                                MovieTrackingTrack *track,
1116                                                MovieTrackingMarker *marker)
1117 {
1118   FCurve *weight_fcurve;
1119   float weight = track->weight;
1120 
1121   weight_fcurve = id_data_find_fcurve(
1122       &clip->id, track, &RNA_MovieTrackingTrack, "weight", 0, NULL);
1123 
1124   if (weight_fcurve) {
1125     int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
1126     weight = evaluate_fcurve(weight_fcurve, scene_framenr);
1127   }
1128 
1129   return weight;
1130 }
1131 
1132 /* area - which part of marker should be selected. see TRACK_AREA_* constants */
BKE_tracking_track_select(ListBase * tracksbase,MovieTrackingTrack * track,int area,bool extend)1133 void BKE_tracking_track_select(ListBase *tracksbase,
1134                                MovieTrackingTrack *track,
1135                                int area,
1136                                bool extend)
1137 {
1138   if (extend) {
1139     BKE_tracking_track_flag_set(track, area, SELECT);
1140   }
1141   else {
1142     MovieTrackingTrack *cur = tracksbase->first;
1143 
1144     while (cur) {
1145       if ((cur->flag & TRACK_HIDDEN) == 0) {
1146         if (cur == track) {
1147           BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
1148           BKE_tracking_track_flag_set(cur, area, SELECT);
1149         }
1150         else {
1151           BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
1152         }
1153       }
1154 
1155       cur = cur->next;
1156     }
1157   }
1158 }
1159 
BKE_tracking_track_deselect(MovieTrackingTrack * track,int area)1160 void BKE_tracking_track_deselect(MovieTrackingTrack *track, int area)
1161 {
1162   BKE_tracking_track_flag_clear(track, area, SELECT);
1163 }
1164 
BKE_tracking_tracks_deselect_all(ListBase * tracksbase)1165 void BKE_tracking_tracks_deselect_all(ListBase *tracksbase)
1166 {
1167   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
1168     if ((track->flag & TRACK_HIDDEN) == 0) {
1169       BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
1170     }
1171   }
1172 }
1173 
1174 /*********************** Marker *************************/
1175 
BKE_tracking_marker_insert(MovieTrackingTrack * track,MovieTrackingMarker * marker)1176 MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track,
1177                                                 MovieTrackingMarker *marker)
1178 {
1179   MovieTrackingMarker *old_marker = NULL;
1180 
1181   if (track->markersnr) {
1182     old_marker = BKE_tracking_marker_get_exact(track, marker->framenr);
1183   }
1184 
1185   if (old_marker) {
1186     /* simply replace settings for already allocated marker */
1187     *old_marker = *marker;
1188 
1189     return old_marker;
1190   }
1191 
1192   int a = track->markersnr;
1193 
1194   /* find position in array where to add new marker */
1195   while (a--) {
1196     if (track->markers[a].framenr < marker->framenr) {
1197       break;
1198     }
1199   }
1200 
1201   track->markersnr++;
1202 
1203   if (track->markers) {
1204     track->markers = MEM_reallocN(track->markers, sizeof(MovieTrackingMarker) * track->markersnr);
1205   }
1206   else {
1207     track->markers = MEM_callocN(sizeof(MovieTrackingMarker), "MovieTracking markers");
1208   }
1209 
1210   /* shift array to "free" space for new marker */
1211   memmove(track->markers + a + 2,
1212           track->markers + a + 1,
1213           (track->markersnr - a - 2) * sizeof(MovieTrackingMarker));
1214 
1215   /* put new marker */
1216   track->markers[a + 1] = *marker;
1217 
1218   track->last_marker = a + 1;
1219 
1220   return &track->markers[a + 1];
1221 }
1222 
BKE_tracking_marker_delete(MovieTrackingTrack * track,int framenr)1223 void BKE_tracking_marker_delete(MovieTrackingTrack *track, int framenr)
1224 {
1225   int a = 0;
1226 
1227   while (a < track->markersnr) {
1228     if (track->markers[a].framenr == framenr) {
1229       if (track->markersnr > 1) {
1230         memmove(track->markers + a,
1231                 track->markers + a + 1,
1232                 (track->markersnr - a - 1) * sizeof(MovieTrackingMarker));
1233         track->markersnr--;
1234         track->markers = MEM_reallocN(track->markers,
1235                                       sizeof(MovieTrackingMarker) * track->markersnr);
1236       }
1237       else {
1238         MEM_freeN(track->markers);
1239         track->markers = NULL;
1240         track->markersnr = 0;
1241       }
1242 
1243       break;
1244     }
1245 
1246     a++;
1247   }
1248 }
1249 
BKE_tracking_marker_clamp(MovieTrackingMarker * marker,int event)1250 void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
1251 {
1252   float pat_min[2], pat_max[2];
1253 
1254   BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
1255 
1256   if (event == CLAMP_PAT_DIM) {
1257     for (int a = 0; a < 2; a++) {
1258       /* search shouldn't be resized smaller than pattern */
1259       marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
1260       marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
1261     }
1262   }
1263   else if (event == CLAMP_PAT_POS) {
1264     float dim[2];
1265 
1266     sub_v2_v2v2(dim, pat_max, pat_min);
1267 
1268     for (int a = 0; a < 2; a++) {
1269       /* pattern shouldn't be moved outside of search */
1270       if (pat_min[a] < marker->search_min[a]) {
1271         for (int b = 0; b < 4; b++) {
1272           marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a];
1273         }
1274       }
1275       if (pat_max[a] > marker->search_max[a]) {
1276         for (int b = 0; b < 4; b++) {
1277           marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a];
1278         }
1279       }
1280     }
1281   }
1282   else if (event == CLAMP_SEARCH_DIM) {
1283     for (int a = 0; a < 2; a++) {
1284       /* search shouldn't be resized smaller than pattern */
1285       marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
1286       marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
1287     }
1288   }
1289   else if (event == CLAMP_SEARCH_POS) {
1290     float dim[2];
1291 
1292     sub_v2_v2v2(dim, marker->search_max, marker->search_min);
1293 
1294     for (int a = 0; a < 2; a++) {
1295       /* search shouldn't be moved inside pattern */
1296       if (marker->search_min[a] > pat_min[a]) {
1297         marker->search_min[a] = pat_min[a];
1298         marker->search_max[a] = marker->search_min[a] + dim[a];
1299       }
1300       if (marker->search_max[a] < pat_max[a]) {
1301         marker->search_max[a] = pat_max[a];
1302         marker->search_min[a] = marker->search_max[a] - dim[a];
1303       }
1304     }
1305   }
1306 }
1307 
BKE_tracking_marker_get(MovieTrackingTrack * track,int framenr)1308 MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
1309 {
1310   int a = track->markersnr - 1;
1311 
1312   if (!track->markersnr) {
1313     return NULL;
1314   }
1315 
1316   /* approximate pre-first framenr marker with first marker */
1317   if (framenr < track->markers[0].framenr) {
1318     return &track->markers[0];
1319   }
1320 
1321   if (track->last_marker < track->markersnr) {
1322     a = track->last_marker;
1323   }
1324 
1325   if (track->markers[a].framenr <= framenr) {
1326     while (a < track->markersnr && track->markers[a].framenr <= framenr) {
1327       if (track->markers[a].framenr == framenr) {
1328         track->last_marker = a;
1329 
1330         return &track->markers[a];
1331       }
1332       a++;
1333     }
1334 
1335     /* if there's no marker for exact position, use nearest marker from left side */
1336     return &track->markers[a - 1];
1337   }
1338 
1339   while (a >= 0 && track->markers[a].framenr >= framenr) {
1340     if (track->markers[a].framenr == framenr) {
1341       track->last_marker = a;
1342 
1343       return &track->markers[a];
1344     }
1345 
1346     a--;
1347   }
1348 
1349   /* if there's no marker for exact position, use nearest marker from left side */
1350   return &track->markers[a];
1351 
1352   return NULL;
1353 }
1354 
BKE_tracking_marker_get_exact(MovieTrackingTrack * track,int framenr)1355 MovieTrackingMarker *BKE_tracking_marker_get_exact(MovieTrackingTrack *track, int framenr)
1356 {
1357   MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1358 
1359   if (marker->framenr != framenr) {
1360     return NULL;
1361   }
1362 
1363   return marker;
1364 }
1365 
BKE_tracking_marker_ensure(MovieTrackingTrack * track,int framenr)1366 MovieTrackingMarker *BKE_tracking_marker_ensure(MovieTrackingTrack *track, int framenr)
1367 {
1368   MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1369 
1370   if (marker->framenr != framenr) {
1371     MovieTrackingMarker marker_new;
1372 
1373     marker_new = *marker;
1374     marker_new.framenr = framenr;
1375 
1376     BKE_tracking_marker_insert(track, &marker_new);
1377     marker = BKE_tracking_marker_get(track, framenr);
1378   }
1379 
1380   return marker;
1381 }
1382 
BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker * marker,float min[2],float max[2])1383 void BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker *marker,
1384                                         float min[2],
1385                                         float max[2])
1386 {
1387   INIT_MINMAX2(min, max);
1388 
1389   minmax_v2v2_v2(min, max, marker->pattern_corners[0]);
1390   minmax_v2v2_v2(min, max, marker->pattern_corners[1]);
1391   minmax_v2v2_v2(min, max, marker->pattern_corners[2]);
1392   minmax_v2v2_v2(min, max, marker->pattern_corners[3]);
1393 }
1394 
BKE_tracking_marker_get_subframe_position(MovieTrackingTrack * track,float framenr,float pos[2])1395 void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
1396                                                float framenr,
1397                                                float pos[2])
1398 {
1399   MovieTrackingMarker *marker = BKE_tracking_marker_get(track, (int)framenr);
1400   MovieTrackingMarker *marker_last = track->markers + (track->markersnr - 1);
1401 
1402   if (marker != marker_last) {
1403     MovieTrackingMarker *marker_next = marker + 1;
1404 
1405     if (marker_next->framenr == marker->framenr + 1) {
1406       /* currently only do subframing inside tracked ranges, do not extrapolate tracked segments
1407        * could be changed when / if mask parent would be interpolating position in-between
1408        * tracked segments
1409        */
1410 
1411       float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
1412 
1413       interp_v2_v2v2(pos, marker->pos, marker_next->pos, fac);
1414     }
1415     else {
1416       copy_v2_v2(pos, marker->pos);
1417     }
1418   }
1419   else {
1420     copy_v2_v2(pos, marker->pos);
1421   }
1422 
1423   /* currently track offset is always wanted to be applied here, could be made an option later */
1424   add_v2_v2(pos, track->offset);
1425 }
1426 
1427 /*********************** Plane Track *************************/
1428 
1429 /* Creates new plane track out of selected point tracks */
BKE_tracking_plane_track_add(MovieTracking * tracking,ListBase * plane_tracks_base,ListBase * tracks,int framenr)1430 MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
1431                                                       ListBase *plane_tracks_base,
1432                                                       ListBase *tracks,
1433                                                       int framenr)
1434 {
1435   MovieTrackingPlaneTrack *plane_track;
1436   MovieTrackingPlaneMarker plane_marker;
1437   float tracks_min[2], tracks_max[2];
1438   int num_selected_tracks = 0;
1439 
1440   (void)tracking; /* Ignored. */
1441 
1442   /* Use bounding box of selected markers as an initial size of plane. */
1443   INIT_MINMAX2(tracks_min, tracks_max);
1444   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks) {
1445     if (TRACK_SELECTED(track)) {
1446       MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1447       float pattern_min[2], pattern_max[2];
1448       BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max);
1449       add_v2_v2(pattern_min, marker->pos);
1450       add_v2_v2(pattern_max, marker->pos);
1451       minmax_v2v2_v2(tracks_min, tracks_max, pattern_min);
1452       minmax_v2v2_v2(tracks_min, tracks_max, pattern_max);
1453       num_selected_tracks++;
1454     }
1455   }
1456 
1457   if (num_selected_tracks < 4) {
1458     return NULL;
1459   }
1460 
1461   /* Allocate new plane track. */
1462   plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track");
1463 
1464   /* Use some default name. */
1465   strcpy(plane_track->name, "Plane Track");
1466 
1467   plane_track->image_opacity = 1.0f;
1468 
1469   /* Use selected tracks from given list as a plane. */
1470   plane_track->point_tracks = MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks,
1471                                           "new plane tracks array");
1472   int track_index = 0;
1473   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks) {
1474     if (TRACK_SELECTED(track)) {
1475       plane_track->point_tracks[track_index] = track;
1476       track_index++;
1477     }
1478   }
1479   plane_track->point_tracksnr = num_selected_tracks;
1480 
1481   /* Setup new plane marker and add it to the track. */
1482   plane_marker.framenr = framenr;
1483   plane_marker.flag = 0;
1484 
1485   copy_v2_v2(plane_marker.corners[0], tracks_min);
1486   copy_v2_v2(plane_marker.corners[2], tracks_max);
1487 
1488   plane_marker.corners[1][0] = tracks_max[0];
1489   plane_marker.corners[1][1] = tracks_min[1];
1490   plane_marker.corners[3][0] = tracks_min[0];
1491   plane_marker.corners[3][1] = tracks_max[1];
1492 
1493   BKE_tracking_plane_marker_insert(plane_track, &plane_marker);
1494 
1495   /* Put new plane track to the list, ensure its name is unique. */
1496   BLI_addtail(plane_tracks_base, plane_track);
1497   BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
1498 
1499   return plane_track;
1500 }
1501 
BKE_tracking_plane_track_unique_name(ListBase * plane_tracks_base,MovieTrackingPlaneTrack * plane_track)1502 void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base,
1503                                           MovieTrackingPlaneTrack *plane_track)
1504 {
1505   BLI_uniquename(plane_tracks_base,
1506                  plane_track,
1507                  CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"),
1508                  '.',
1509                  offsetof(MovieTrackingPlaneTrack, name),
1510                  sizeof(plane_track->name));
1511 }
1512 
1513 /* Free specified plane track, only frees contents of a structure
1514  * (if track is allocated in heap, it shall be handled outside).
1515  *
1516  * All the pointers inside track becomes invalid after this call.
1517  */
BKE_tracking_plane_track_free(MovieTrackingPlaneTrack * plane_track)1518 void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
1519 {
1520   if (plane_track->markers) {
1521     MEM_freeN(plane_track->markers);
1522   }
1523 
1524   MEM_freeN(plane_track->point_tracks);
1525 }
1526 
BKE_tracking_plane_track_get_named(MovieTracking * tracking,MovieTrackingObject * object,const char * name)1527 MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *tracking,
1528                                                             MovieTrackingObject *object,
1529                                                             const char *name)
1530 {
1531   ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object);
1532 
1533   LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
1534     if (STREQ(plane_track->name, name)) {
1535       return plane_track;
1536     }
1537   }
1538 
1539   return NULL;
1540 }
1541 
BKE_tracking_plane_track_get_active(struct MovieTracking * tracking)1542 MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking)
1543 {
1544   if (tracking->act_plane_track == NULL) {
1545     return NULL;
1546   }
1547 
1548   ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
1549 
1550   /* Check that active track is in current plane tracks list */
1551   if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) != -1) {
1552     return tracking->act_plane_track;
1553   }
1554 
1555   return NULL;
1556 }
1557 
BKE_tracking_plane_tracks_deselect_all(ListBase * plane_tracks_base)1558 void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
1559 {
1560   LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
1561     plane_track->flag &= ~SELECT;
1562   }
1563 }
1564 
BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack * plane_track,MovieTrackingTrack * track)1565 bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track,
1566                                               MovieTrackingTrack *track)
1567 {
1568   for (int i = 0; i < plane_track->point_tracksnr; i++) {
1569     if (plane_track->point_tracks[i] == track) {
1570       return true;
1571     }
1572   }
1573   return false;
1574 }
1575 
BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack * plane_track,MovieTrackingTrack * track)1576 bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track,
1577                                                  MovieTrackingTrack *track)
1578 {
1579   if (plane_track->point_tracksnr <= 4) {
1580     return false;
1581   }
1582 
1583   MovieTrackingTrack **new_point_tracks = MEM_mallocN(
1584       sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1), "new point tracks array");
1585 
1586   for (int i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
1587     if (plane_track->point_tracks[i] != track) {
1588       new_point_tracks[track_index++] = plane_track->point_tracks[i];
1589     }
1590   }
1591 
1592   MEM_freeN(plane_track->point_tracks);
1593   plane_track->point_tracks = new_point_tracks;
1594   plane_track->point_tracksnr--;
1595 
1596   return true;
1597 }
1598 
BKE_tracking_plane_tracks_remove_point_track(MovieTracking * tracking,MovieTrackingTrack * track)1599 void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking,
1600                                                   MovieTrackingTrack *track)
1601 {
1602   ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
1603   LISTBASE_FOREACH_MUTABLE (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
1604     if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
1605       if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
1606         /* Delete planes with less than 3 point tracks in it. */
1607         BKE_tracking_plane_track_free(plane_track);
1608         BLI_freelinkN(plane_tracks_base, plane_track);
1609       }
1610     }
1611   }
1612 }
1613 
BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack * plane_track,MovieTrackingTrack * old_track,MovieTrackingTrack * new_track)1614 void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track,
1615                                                   MovieTrackingTrack *old_track,
1616                                                   MovieTrackingTrack *new_track)
1617 {
1618   for (int i = 0; i < plane_track->point_tracksnr; i++) {
1619     if (plane_track->point_tracks[i] == old_track) {
1620       plane_track->point_tracks[i] = new_track;
1621       break;
1622     }
1623   }
1624 }
1625 
BKE_tracking_plane_tracks_replace_point_track(MovieTracking * tracking,MovieTrackingTrack * old_track,MovieTrackingTrack * new_track)1626 void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
1627                                                    MovieTrackingTrack *old_track,
1628                                                    MovieTrackingTrack *new_track)
1629 {
1630   ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
1631   LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
1632     if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
1633       BKE_tracking_plane_track_replace_point_track(plane_track, old_track, new_track);
1634     }
1635   }
1636 }
1637 
1638 /*********************** Plane Marker *************************/
1639 
BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack * plane_track,MovieTrackingPlaneMarker * plane_marker)1640 MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
1641                                                            MovieTrackingPlaneMarker *plane_marker)
1642 {
1643   MovieTrackingPlaneMarker *old_plane_marker = NULL;
1644 
1645   if (plane_track->markersnr) {
1646     old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr);
1647   }
1648 
1649   if (old_plane_marker) {
1650     /* Simply replace settings in existing marker. */
1651     *old_plane_marker = *plane_marker;
1652 
1653     return old_plane_marker;
1654   }
1655 
1656   int a = plane_track->markersnr;
1657 
1658   /* Find position in array where to add new marker. */
1659   /* TODO(sergey): we could use bisect to speed things up. */
1660   while (a--) {
1661     if (plane_track->markers[a].framenr < plane_marker->framenr) {
1662       break;
1663     }
1664   }
1665 
1666   plane_track->markersnr++;
1667   plane_track->markers = MEM_reallocN(plane_track->markers,
1668                                       sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr);
1669 
1670   /* Shift array to "free" space for new marker. */
1671   memmove(plane_track->markers + a + 2,
1672           plane_track->markers + a + 1,
1673           (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker));
1674 
1675   /* Put new marker to an array. */
1676   plane_track->markers[a + 1] = *plane_marker;
1677   plane_track->last_marker = a + 1;
1678 
1679   return &plane_track->markers[a + 1];
1680 }
1681 
BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack * plane_track,int framenr)1682 void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int framenr)
1683 {
1684   int a = 0;
1685 
1686   while (a < plane_track->markersnr) {
1687     if (plane_track->markers[a].framenr == framenr) {
1688       if (plane_track->markersnr > 1) {
1689         memmove(plane_track->markers + a,
1690                 plane_track->markers + a + 1,
1691                 (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker));
1692         plane_track->markersnr--;
1693         plane_track->markers = MEM_reallocN(plane_track->markers,
1694                                             sizeof(MovieTrackingMarker) * plane_track->markersnr);
1695       }
1696       else {
1697         MEM_freeN(plane_track->markers);
1698         plane_track->markers = NULL;
1699         plane_track->markersnr = 0;
1700       }
1701 
1702       break;
1703     }
1704 
1705     a++;
1706   }
1707 }
1708 
1709 /* TODO(sergey): The next couple of functions are really quite the same as point marker version,
1710  *               would be nice to de-duplicate them somehow..
1711  */
1712 
1713 /* Get a plane marker at given frame,
1714  * If there's no such marker, closest one from the left side will be returned.
1715  */
BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack * plane_track,int framenr)1716 MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track,
1717                                                         int framenr)
1718 {
1719   int a = plane_track->markersnr - 1;
1720 
1721   if (!plane_track->markersnr) {
1722     return NULL;
1723   }
1724 
1725   /* Approximate pre-first framenr marker with first marker. */
1726   if (framenr < plane_track->markers[0].framenr) {
1727     return &plane_track->markers[0];
1728   }
1729 
1730   if (plane_track->last_marker < plane_track->markersnr) {
1731     a = plane_track->last_marker;
1732   }
1733 
1734   if (plane_track->markers[a].framenr <= framenr) {
1735     while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) {
1736       if (plane_track->markers[a].framenr == framenr) {
1737         plane_track->last_marker = a;
1738 
1739         return &plane_track->markers[a];
1740       }
1741       a++;
1742     }
1743 
1744     /* If there's no marker for exact position, use nearest marker from left side. */
1745     return &plane_track->markers[a - 1];
1746   }
1747 
1748   while (a >= 0 && plane_track->markers[a].framenr >= framenr) {
1749     if (plane_track->markers[a].framenr == framenr) {
1750       plane_track->last_marker = a;
1751 
1752       return &plane_track->markers[a];
1753     }
1754 
1755     a--;
1756   }
1757 
1758   /* If there's no marker for exact position, use nearest marker from left side. */
1759   return &plane_track->markers[a];
1760 
1761   return NULL;
1762 }
1763 
1764 /* Get a plane marker at exact given frame, if there's no marker at the frame,
1765  * NULL will be returned.
1766  */
BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack * plane_track,int framenr)1767 MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track,
1768                                                               int framenr)
1769 {
1770   MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
1771 
1772   if (plane_marker->framenr != framenr) {
1773     return NULL;
1774   }
1775 
1776   return plane_marker;
1777 }
1778 
1779 /* Ensure there's a marker for the given frame. */
BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack * plane_track,int framenr)1780 MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track,
1781                                                            int framenr)
1782 {
1783   MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
1784 
1785   if (plane_marker->framenr != framenr) {
1786     MovieTrackingPlaneMarker plane_marker_new;
1787 
1788     plane_marker_new = *plane_marker;
1789     plane_marker_new.framenr = framenr;
1790 
1791     plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new);
1792   }
1793 
1794   return plane_marker;
1795 }
1796 
BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack * plane_track,float framenr,float corners[4][2])1797 void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *plane_track,
1798                                                     float framenr,
1799                                                     float corners[4][2])
1800 {
1801   MovieTrackingPlaneMarker *marker = BKE_tracking_plane_marker_get(plane_track, (int)framenr);
1802   MovieTrackingPlaneMarker *marker_last = plane_track->markers + (plane_track->markersnr - 1);
1803   if (marker != marker_last) {
1804     MovieTrackingPlaneMarker *marker_next = marker + 1;
1805     if (marker_next->framenr == marker->framenr + 1) {
1806       float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
1807       for (int i = 0; i < 4; i++) {
1808         interp_v2_v2v2(corners[i], marker->corners[i], marker_next->corners[i], fac);
1809       }
1810     }
1811     else {
1812       for (int i = 0; i < 4; i++) {
1813         copy_v2_v2(corners[i], marker->corners[i]);
1814       }
1815     }
1816   }
1817   else {
1818     for (int i = 0; i < 4; i++) {
1819       copy_v2_v2(corners[i], marker->corners[i]);
1820     }
1821   }
1822 }
1823 
1824 /*********************** Object *************************/
1825 
BKE_tracking_object_add(MovieTracking * tracking,const char * name)1826 MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name)
1827 {
1828   MovieTrackingObject *object = MEM_callocN(sizeof(MovieTrackingObject), "tracking object");
1829 
1830   if (tracking->tot_object == 0) {
1831     /* first object is always camera */
1832     BLI_strncpy(object->name, "Camera", sizeof(object->name));
1833 
1834     object->flag |= TRACKING_OBJECT_CAMERA;
1835   }
1836   else {
1837     BLI_strncpy(object->name, name, sizeof(object->name));
1838   }
1839 
1840   BLI_addtail(&tracking->objects, object);
1841 
1842   tracking->tot_object++;
1843   tracking->objectnr = BLI_listbase_count(&tracking->objects) - 1;
1844 
1845   object->scale = 1.0f;
1846   object->keyframe1 = 1;
1847   object->keyframe2 = 30;
1848 
1849   BKE_tracking_object_unique_name(tracking, object);
1850   BKE_tracking_dopesheet_tag_update(tracking);
1851 
1852   return object;
1853 }
1854 
BKE_tracking_object_delete(MovieTracking * tracking,MovieTrackingObject * object)1855 bool BKE_tracking_object_delete(MovieTracking *tracking, MovieTrackingObject *object)
1856 {
1857   MovieTrackingTrack *track;
1858   int index = BLI_findindex(&tracking->objects, object);
1859 
1860   if (index == -1) {
1861     return false;
1862   }
1863 
1864   if (object->flag & TRACKING_OBJECT_CAMERA) {
1865     /* object used for camera solving can't be deleted */
1866     return false;
1867   }
1868 
1869   track = object->tracks.first;
1870   while (track) {
1871     if (track == tracking->act_track) {
1872       tracking->act_track = NULL;
1873     }
1874 
1875     track = track->next;
1876   }
1877 
1878   tracking_object_free(object);
1879   BLI_freelinkN(&tracking->objects, object);
1880 
1881   tracking->tot_object--;
1882 
1883   if (index != 0) {
1884     tracking->objectnr = index - 1;
1885   }
1886   else {
1887     tracking->objectnr = 0;
1888   }
1889 
1890   BKE_tracking_dopesheet_tag_update(tracking);
1891 
1892   return true;
1893 }
1894 
BKE_tracking_object_unique_name(MovieTracking * tracking,MovieTrackingObject * object)1895 void BKE_tracking_object_unique_name(MovieTracking *tracking, MovieTrackingObject *object)
1896 {
1897   BLI_uniquename(&tracking->objects,
1898                  object,
1899                  DATA_("Object"),
1900                  '.',
1901                  offsetof(MovieTrackingObject, name),
1902                  sizeof(object->name));
1903 }
1904 
BKE_tracking_object_get_named(MovieTracking * tracking,const char * name)1905 MovieTrackingObject *BKE_tracking_object_get_named(MovieTracking *tracking, const char *name)
1906 {
1907   MovieTrackingObject *object = tracking->objects.first;
1908 
1909   while (object) {
1910     if (STREQ(object->name, name)) {
1911       return object;
1912     }
1913 
1914     object = object->next;
1915   }
1916 
1917   return NULL;
1918 }
1919 
BKE_tracking_object_get_active(MovieTracking * tracking)1920 MovieTrackingObject *BKE_tracking_object_get_active(MovieTracking *tracking)
1921 {
1922   return BLI_findlink(&tracking->objects, tracking->objectnr);
1923 }
1924 
BKE_tracking_object_get_camera(MovieTracking * tracking)1925 MovieTrackingObject *BKE_tracking_object_get_camera(MovieTracking *tracking)
1926 {
1927   MovieTrackingObject *object = tracking->objects.first;
1928 
1929   while (object) {
1930     if (object->flag & TRACKING_OBJECT_CAMERA) {
1931       return object;
1932     }
1933 
1934     object = object->next;
1935   }
1936 
1937   return NULL;
1938 }
1939 
BKE_tracking_object_get_tracks(MovieTracking * tracking,MovieTrackingObject * object)1940 ListBase *BKE_tracking_object_get_tracks(MovieTracking *tracking, MovieTrackingObject *object)
1941 {
1942   if (object->flag & TRACKING_OBJECT_CAMERA) {
1943     return &tracking->tracks;
1944   }
1945 
1946   return &object->tracks;
1947 }
1948 
BKE_tracking_object_get_plane_tracks(MovieTracking * tracking,MovieTrackingObject * object)1949 ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking,
1950                                                MovieTrackingObject *object)
1951 {
1952   if (object->flag & TRACKING_OBJECT_CAMERA) {
1953     return &tracking->plane_tracks;
1954   }
1955 
1956   return &object->plane_tracks;
1957 }
1958 
BKE_tracking_object_get_reconstruction(MovieTracking * tracking,MovieTrackingObject * object)1959 MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTracking *tracking,
1960                                                                     MovieTrackingObject *object)
1961 {
1962   if (object->flag & TRACKING_OBJECT_CAMERA) {
1963     return &tracking->reconstruction;
1964   }
1965 
1966   return &object->reconstruction;
1967 }
1968 
1969 /*********************** Camera *************************/
1970 
reconstructed_camera_index_get(MovieTrackingReconstruction * reconstruction,int framenr,bool nearest)1971 static int reconstructed_camera_index_get(MovieTrackingReconstruction *reconstruction,
1972                                           int framenr,
1973                                           bool nearest)
1974 {
1975   MovieReconstructedCamera *cameras = reconstruction->cameras;
1976   int a = 0, d = 1;
1977 
1978   if (!reconstruction->camnr) {
1979     return -1;
1980   }
1981 
1982   if (framenr < cameras[0].framenr) {
1983     if (nearest) {
1984       return 0;
1985     }
1986 
1987     return -1;
1988   }
1989 
1990   if (framenr > cameras[reconstruction->camnr - 1].framenr) {
1991     if (nearest) {
1992       return reconstruction->camnr - 1;
1993     }
1994 
1995     return -1;
1996   }
1997 
1998   if (reconstruction->last_camera < reconstruction->camnr) {
1999     a = reconstruction->last_camera;
2000   }
2001 
2002   if (cameras[a].framenr >= framenr) {
2003     d = -1;
2004   }
2005 
2006   while (a >= 0 && a < reconstruction->camnr) {
2007     int cfra = cameras[a].framenr;
2008 
2009     /* check if needed framenr was "skipped" -- no data for requested frame */
2010 
2011     if (d > 0 && cfra > framenr) {
2012       /* interpolate with previous position */
2013       if (nearest) {
2014         return a - 1;
2015       }
2016 
2017       break;
2018     }
2019 
2020     if (d < 0 && cfra < framenr) {
2021       /* interpolate with next position */
2022       if (nearest) {
2023         return a;
2024       }
2025 
2026       break;
2027     }
2028 
2029     if (cfra == framenr) {
2030       reconstruction->last_camera = a;
2031 
2032       return a;
2033     }
2034 
2035     a += d;
2036   }
2037 
2038   return -1;
2039 }
2040 
reconstructed_camera_scale_set(MovieTrackingObject * object,float mat[4][4])2041 static void reconstructed_camera_scale_set(MovieTrackingObject *object, float mat[4][4])
2042 {
2043   if ((object->flag & TRACKING_OBJECT_CAMERA) == 0) {
2044     float smat[4][4];
2045 
2046     scale_m4_fl(smat, 1.0f / object->scale);
2047     mul_m4_m4m4(mat, mat, smat);
2048   }
2049 }
2050 
2051 /* converts principal offset from center to offset of blender's camera */
BKE_tracking_camera_shift_get(MovieTracking * tracking,int winx,int winy,float * shiftx,float * shifty)2052 void BKE_tracking_camera_shift_get(
2053     MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
2054 {
2055   /* Indeed in both of cases it should be winx -
2056    * it's just how camera shift works for blender's camera. */
2057   *shiftx = (0.5f * winx - tracking->camera.principal[0]) / winx;
2058   *shifty = (0.5f * winy - tracking->camera.principal[1]) / winx;
2059 }
2060 
BKE_tracking_camera_to_blender(MovieTracking * tracking,Scene * scene,Camera * camera,int width,int height)2061 void BKE_tracking_camera_to_blender(
2062     MovieTracking *tracking, Scene *scene, Camera *camera, int width, int height)
2063 {
2064   float focal = tracking->camera.focal;
2065 
2066   camera->sensor_x = tracking->camera.sensor_width;
2067   camera->sensor_fit = CAMERA_SENSOR_FIT_AUTO;
2068   camera->lens = focal * camera->sensor_x / width;
2069 
2070   scene->r.xsch = width;
2071   scene->r.ysch = height;
2072 
2073   scene->r.xasp = tracking->camera.pixel_aspect;
2074   scene->r.yasp = 1.0f;
2075 
2076   BKE_tracking_camera_shift_get(tracking, width, height, &camera->shiftx, &camera->shifty);
2077 }
2078 
BKE_tracking_camera_get_reconstructed(MovieTracking * tracking,MovieTrackingObject * object,int framenr)2079 MovieReconstructedCamera *BKE_tracking_camera_get_reconstructed(MovieTracking *tracking,
2080                                                                 MovieTrackingObject *object,
2081                                                                 int framenr)
2082 {
2083   MovieTrackingReconstruction *reconstruction;
2084   int a;
2085 
2086   reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
2087   a = reconstructed_camera_index_get(reconstruction, framenr, false);
2088 
2089   if (a == -1) {
2090     return NULL;
2091   }
2092 
2093   return &reconstruction->cameras[a];
2094 }
2095 
BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking * tracking,MovieTrackingObject * object,float framenr,float mat[4][4])2096 void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking,
2097                                                        MovieTrackingObject *object,
2098                                                        float framenr,
2099                                                        float mat[4][4])
2100 {
2101   MovieTrackingReconstruction *reconstruction;
2102   MovieReconstructedCamera *cameras;
2103   int a;
2104 
2105   reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
2106   cameras = reconstruction->cameras;
2107   a = reconstructed_camera_index_get(reconstruction, (int)framenr, true);
2108 
2109   if (a == -1) {
2110     unit_m4(mat);
2111     return;
2112   }
2113 
2114   if (cameras[a].framenr != framenr && a < reconstruction->camnr - 1) {
2115     float t = ((float)framenr - cameras[a].framenr) /
2116               (cameras[a + 1].framenr - cameras[a].framenr);
2117     blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t);
2118   }
2119   else {
2120     copy_m4_m4(mat, cameras[a].mat);
2121   }
2122 
2123   reconstructed_camera_scale_set(object, mat);
2124 }
2125 
2126 /*********************** Distortion/Undistortion *************************/
2127 
BKE_tracking_distortion_new(MovieTracking * tracking,int calibration_width,int calibration_height)2128 MovieDistortion *BKE_tracking_distortion_new(MovieTracking *tracking,
2129                                              int calibration_width,
2130                                              int calibration_height)
2131 {
2132   MovieDistortion *distortion;
2133   libmv_CameraIntrinsicsOptions camera_intrinsics_options;
2134 
2135   tracking_cameraIntrinscisOptionsFromTracking(
2136       tracking, calibration_width, calibration_height, &camera_intrinsics_options);
2137 
2138   distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
2139   distortion->intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
2140 
2141   const MovieTrackingCamera *camera = &tracking->camera;
2142   copy_v2_v2(distortion->principal, camera->principal);
2143   distortion->pixel_aspect = camera->pixel_aspect;
2144   distortion->focal = camera->focal;
2145 
2146   return distortion;
2147 }
2148 
BKE_tracking_distortion_update(MovieDistortion * distortion,MovieTracking * tracking,int calibration_width,int calibration_height)2149 void BKE_tracking_distortion_update(MovieDistortion *distortion,
2150                                     MovieTracking *tracking,
2151                                     int calibration_width,
2152                                     int calibration_height)
2153 {
2154   libmv_CameraIntrinsicsOptions camera_intrinsics_options;
2155 
2156   tracking_cameraIntrinscisOptionsFromTracking(
2157       tracking, calibration_width, calibration_height, &camera_intrinsics_options);
2158 
2159   const MovieTrackingCamera *camera = &tracking->camera;
2160   copy_v2_v2(distortion->principal, camera->principal);
2161   distortion->pixel_aspect = camera->pixel_aspect;
2162   distortion->focal = camera->focal;
2163 
2164   libmv_cameraIntrinsicsUpdate(&camera_intrinsics_options, distortion->intrinsics);
2165 }
2166 
BKE_tracking_distortion_set_threads(MovieDistortion * distortion,int threads)2167 void BKE_tracking_distortion_set_threads(MovieDistortion *distortion, int threads)
2168 {
2169   libmv_cameraIntrinsicsSetThreads(distortion->intrinsics, threads);
2170 }
2171 
BKE_tracking_distortion_copy(MovieDistortion * distortion)2172 MovieDistortion *BKE_tracking_distortion_copy(MovieDistortion *distortion)
2173 {
2174   MovieDistortion *new_distortion;
2175 
2176   new_distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
2177   *new_distortion = *distortion;
2178   new_distortion->intrinsics = libmv_cameraIntrinsicsCopy(distortion->intrinsics);
2179 
2180   return new_distortion;
2181 }
2182 
BKE_tracking_distortion_exec(MovieDistortion * distortion,MovieTracking * tracking,ImBuf * ibuf,int calibration_width,int calibration_height,float overscan,bool undistort)2183 ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion,
2184                                     MovieTracking *tracking,
2185                                     ImBuf *ibuf,
2186                                     int calibration_width,
2187                                     int calibration_height,
2188                                     float overscan,
2189                                     bool undistort)
2190 {
2191   ImBuf *resibuf;
2192 
2193   BKE_tracking_distortion_update(distortion, tracking, calibration_width, calibration_height);
2194 
2195   resibuf = IMB_dupImBuf(ibuf);
2196 
2197   if (ibuf->rect_float) {
2198     if (undistort) {
2199       libmv_cameraIntrinsicsUndistortFloat(distortion->intrinsics,
2200                                            ibuf->rect_float,
2201                                            ibuf->x,
2202                                            ibuf->y,
2203                                            overscan,
2204                                            ibuf->channels,
2205                                            resibuf->rect_float);
2206     }
2207     else {
2208       libmv_cameraIntrinsicsDistortFloat(distortion->intrinsics,
2209                                          ibuf->rect_float,
2210                                          ibuf->x,
2211                                          ibuf->y,
2212                                          overscan,
2213                                          ibuf->channels,
2214                                          resibuf->rect_float);
2215     }
2216 
2217     if (ibuf->rect) {
2218       imb_freerectImBuf(ibuf);
2219     }
2220   }
2221   else {
2222     if (undistort) {
2223       libmv_cameraIntrinsicsUndistortByte(distortion->intrinsics,
2224                                           (unsigned char *)ibuf->rect,
2225                                           ibuf->x,
2226                                           ibuf->y,
2227                                           overscan,
2228                                           ibuf->channels,
2229                                           (unsigned char *)resibuf->rect);
2230     }
2231     else {
2232       libmv_cameraIntrinsicsDistortByte(distortion->intrinsics,
2233                                         (unsigned char *)ibuf->rect,
2234                                         ibuf->x,
2235                                         ibuf->y,
2236                                         overscan,
2237                                         ibuf->channels,
2238                                         (unsigned char *)resibuf->rect);
2239     }
2240   }
2241 
2242   return resibuf;
2243 }
2244 
BKE_tracking_distortion_distort_v2(MovieDistortion * distortion,const float co[2],float r_co[2])2245 void BKE_tracking_distortion_distort_v2(MovieDistortion *distortion,
2246                                         const float co[2],
2247                                         float r_co[2])
2248 {
2249   const float aspy = 1.0f / distortion->pixel_aspect;
2250 
2251   /* Normalize coords. */
2252   float inv_focal = 1.0f / distortion->focal;
2253   double x = (co[0] - distortion->principal[0]) * inv_focal,
2254          y = (co[1] - distortion->principal[1] * aspy) * inv_focal;
2255 
2256   libmv_cameraIntrinsicsApply(distortion->intrinsics, x, y, &x, &y);
2257 
2258   /* Result is in image coords already. */
2259   r_co[0] = x;
2260   r_co[1] = y;
2261 }
2262 
BKE_tracking_distortion_undistort_v2(MovieDistortion * distortion,const float co[2],float r_co[2])2263 void BKE_tracking_distortion_undistort_v2(MovieDistortion *distortion,
2264                                           const float co[2],
2265                                           float r_co[2])
2266 {
2267   double x = co[0], y = co[1];
2268   libmv_cameraIntrinsicsInvert(distortion->intrinsics, x, y, &x, &y);
2269 
2270   const float aspy = 1.0f / distortion->pixel_aspect;
2271   r_co[0] = (float)x * distortion->focal + distortion->principal[0];
2272   r_co[1] = (float)y * distortion->focal + distortion->principal[1] * aspy;
2273 }
2274 
BKE_tracking_distortion_free(MovieDistortion * distortion)2275 void BKE_tracking_distortion_free(MovieDistortion *distortion)
2276 {
2277   libmv_cameraIntrinsicsDestroy(distortion->intrinsics);
2278 
2279   MEM_freeN(distortion);
2280 }
2281 
BKE_tracking_distort_v2(MovieTracking * tracking,int image_width,int image_height,const float co[2],float r_co[2])2282 void BKE_tracking_distort_v2(
2283     MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
2284 {
2285   const MovieTrackingCamera *camera = &tracking->camera;
2286   const float aspy = 1.0f / tracking->camera.pixel_aspect;
2287 
2288   libmv_CameraIntrinsicsOptions camera_intrinsics_options;
2289   tracking_cameraIntrinscisOptionsFromTracking(
2290       tracking, image_width, image_height, &camera_intrinsics_options);
2291   libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
2292 
2293   /* Normalize coordinates. */
2294   double x = (co[0] - camera->principal[0]) / camera->focal,
2295          y = (co[1] - camera->principal[1] * aspy) / camera->focal;
2296 
2297   libmv_cameraIntrinsicsApply(intrinsics, x, y, &x, &y);
2298   libmv_cameraIntrinsicsDestroy(intrinsics);
2299 
2300   /* Result is in image coords already. */
2301   r_co[0] = x;
2302   r_co[1] = y;
2303 }
2304 
BKE_tracking_undistort_v2(MovieTracking * tracking,int image_width,int image_height,const float co[2],float r_co[2])2305 void BKE_tracking_undistort_v2(
2306     MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
2307 {
2308   const MovieTrackingCamera *camera = &tracking->camera;
2309   const float aspy = 1.0f / tracking->camera.pixel_aspect;
2310 
2311   libmv_CameraIntrinsicsOptions camera_intrinsics_options;
2312   tracking_cameraIntrinscisOptionsFromTracking(
2313       tracking, image_width, image_height, &camera_intrinsics_options);
2314   libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
2315 
2316   double x = co[0], y = co[1];
2317   libmv_cameraIntrinsicsInvert(intrinsics, x, y, &x, &y);
2318   libmv_cameraIntrinsicsDestroy(intrinsics);
2319 
2320   r_co[0] = (float)x * camera->focal + camera->principal[0];
2321   r_co[1] = (float)y * camera->focal + camera->principal[1] * aspy;
2322 }
2323 
BKE_tracking_undistort_frame(MovieTracking * tracking,ImBuf * ibuf,int calibration_width,int calibration_height,float overscan)2324 ImBuf *BKE_tracking_undistort_frame(MovieTracking *tracking,
2325                                     ImBuf *ibuf,
2326                                     int calibration_width,
2327                                     int calibration_height,
2328                                     float overscan)
2329 {
2330   MovieTrackingCamera *camera = &tracking->camera;
2331 
2332   if (camera->intrinsics == NULL) {
2333     camera->intrinsics = BKE_tracking_distortion_new(
2334         tracking, calibration_width, calibration_height);
2335   }
2336 
2337   return BKE_tracking_distortion_exec(
2338       camera->intrinsics, tracking, ibuf, calibration_width, calibration_height, overscan, true);
2339 }
2340 
BKE_tracking_distort_frame(MovieTracking * tracking,ImBuf * ibuf,int calibration_width,int calibration_height,float overscan)2341 ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking,
2342                                   ImBuf *ibuf,
2343                                   int calibration_width,
2344                                   int calibration_height,
2345                                   float overscan)
2346 {
2347   MovieTrackingCamera *camera = &tracking->camera;
2348 
2349   if (camera->intrinsics == NULL) {
2350     camera->intrinsics = BKE_tracking_distortion_new(
2351         tracking, calibration_width, calibration_height);
2352   }
2353 
2354   return BKE_tracking_distortion_exec(
2355       camera->intrinsics, tracking, ibuf, calibration_width, calibration_height, overscan, false);
2356 }
2357 
BKE_tracking_max_distortion_delta_across_bound(MovieTracking * tracking,int image_width,int image_height,rcti * rect,bool undistort,float delta[2])2358 void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
2359                                                     int image_width,
2360                                                     int image_height,
2361                                                     rcti *rect,
2362                                                     bool undistort,
2363                                                     float delta[2])
2364 {
2365   float pos[2], warped_pos[2];
2366   const int coord_delta = 5;
2367   void (*apply_distortion)(MovieTracking * tracking,
2368                            int image_width,
2369                            int image_height,
2370                            const float pos[2],
2371                            float out[2]);
2372 
2373   if (undistort) {
2374     apply_distortion = BKE_tracking_undistort_v2;
2375   }
2376   else {
2377     apply_distortion = BKE_tracking_distort_v2;
2378   }
2379 
2380   delta[0] = delta[1] = -FLT_MAX;
2381 
2382   for (int a = rect->xmin; a <= rect->xmax + coord_delta; a += coord_delta) {
2383     if (a > rect->xmax) {
2384       a = rect->xmax;
2385     }
2386 
2387     /* bottom edge */
2388     pos[0] = a;
2389     pos[1] = rect->ymin;
2390 
2391     apply_distortion(tracking, image_width, image_height, pos, warped_pos);
2392 
2393     delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
2394     delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
2395 
2396     /* top edge */
2397     pos[0] = a;
2398     pos[1] = rect->ymax;
2399 
2400     apply_distortion(tracking, image_width, image_height, pos, warped_pos);
2401 
2402     delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
2403     delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
2404 
2405     if (a >= rect->xmax) {
2406       break;
2407     }
2408   }
2409 
2410   for (int a = rect->ymin; a <= rect->ymax + coord_delta; a += coord_delta) {
2411     if (a > rect->ymax) {
2412       a = rect->ymax;
2413     }
2414 
2415     /* left edge */
2416     pos[0] = rect->xmin;
2417     pos[1] = a;
2418 
2419     apply_distortion(tracking, image_width, image_height, pos, warped_pos);
2420 
2421     delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
2422     delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
2423 
2424     /* right edge */
2425     pos[0] = rect->xmax;
2426     pos[1] = a;
2427 
2428     apply_distortion(tracking, image_width, image_height, pos, warped_pos);
2429 
2430     delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
2431     delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
2432 
2433     if (a >= rect->ymax) {
2434       break;
2435     }
2436   }
2437 }
2438 
2439 /*********************** Image sampling *************************/
2440 
disable_imbuf_channels(ImBuf * ibuf,MovieTrackingTrack * track,bool grayscale)2441 static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, bool grayscale)
2442 {
2443   BKE_tracking_disable_channels(ibuf,
2444                                 track->flag & TRACK_DISABLE_RED,
2445                                 track->flag & TRACK_DISABLE_GREEN,
2446                                 track->flag & TRACK_DISABLE_BLUE,
2447                                 grayscale);
2448 }
2449 
BKE_tracking_sample_pattern(int frame_width,int frame_height,ImBuf * search_ibuf,MovieTrackingTrack * track,MovieTrackingMarker * marker,bool from_anchor,bool use_mask,int num_samples_x,int num_samples_y,float pos[2])2450 ImBuf *BKE_tracking_sample_pattern(int frame_width,
2451                                    int frame_height,
2452                                    ImBuf *search_ibuf,
2453                                    MovieTrackingTrack *track,
2454                                    MovieTrackingMarker *marker,
2455                                    bool from_anchor,
2456                                    bool use_mask,
2457                                    int num_samples_x,
2458                                    int num_samples_y,
2459                                    float pos[2])
2460 {
2461   ImBuf *pattern_ibuf;
2462   double src_pixel_x[5], src_pixel_y[5];
2463   double warped_position_x, warped_position_y;
2464   float *mask = NULL;
2465 
2466   if (num_samples_x <= 0 || num_samples_y <= 0) {
2467     return NULL;
2468   }
2469 
2470   pattern_ibuf = IMB_allocImBuf(
2471       num_samples_x, num_samples_y, 32, search_ibuf->rect_float ? IB_rectfloat : IB_rect);
2472 
2473   tracking_get_marker_coords_for_tracking(
2474       frame_width, frame_height, marker, src_pixel_x, src_pixel_y);
2475 
2476   /* from_anchor means search buffer was obtained for an anchored position,
2477    * which means applying track offset rounded to pixel space (we could not
2478    * store search buffer with sub-pixel precision)
2479    *
2480    * in this case we need to alter coordinates a bit, to compensate rounded
2481    * fractional part of offset
2482    */
2483   if (from_anchor) {
2484     for (int a = 0; a < 5; a++) {
2485       src_pixel_x[a] += (double)((track->offset[0] * frame_width) -
2486                                  ((int)(track->offset[0] * frame_width)));
2487       src_pixel_y[a] += (double)((track->offset[1] * frame_height) -
2488                                  ((int)(track->offset[1] * frame_height)));
2489 
2490       /* when offset is negative, rounding happens in opposite direction */
2491       if (track->offset[0] < 0.0f) {
2492         src_pixel_x[a] += 1.0;
2493       }
2494       if (track->offset[1] < 0.0f) {
2495         src_pixel_y[a] += 1.0;
2496       }
2497     }
2498   }
2499 
2500   if (use_mask) {
2501     mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
2502   }
2503 
2504   if (search_ibuf->rect_float) {
2505     libmv_samplePlanarPatchFloat(search_ibuf->rect_float,
2506                                  search_ibuf->x,
2507                                  search_ibuf->y,
2508                                  4,
2509                                  src_pixel_x,
2510                                  src_pixel_y,
2511                                  num_samples_x,
2512                                  num_samples_y,
2513                                  mask,
2514                                  pattern_ibuf->rect_float,
2515                                  &warped_position_x,
2516                                  &warped_position_y);
2517   }
2518   else {
2519     libmv_samplePlanarPatchByte((unsigned char *)search_ibuf->rect,
2520                                 search_ibuf->x,
2521                                 search_ibuf->y,
2522                                 4,
2523                                 src_pixel_x,
2524                                 src_pixel_y,
2525                                 num_samples_x,
2526                                 num_samples_y,
2527                                 mask,
2528                                 (unsigned char *)pattern_ibuf->rect,
2529                                 &warped_position_x,
2530                                 &warped_position_y);
2531   }
2532 
2533   if (pos) {
2534     pos[0] = warped_position_x;
2535     pos[1] = warped_position_y;
2536   }
2537 
2538   if (mask) {
2539     MEM_freeN(mask);
2540   }
2541 
2542   return pattern_ibuf;
2543 }
2544 
BKE_tracking_get_pattern_imbuf(ImBuf * ibuf,MovieTrackingTrack * track,MovieTrackingMarker * marker,bool anchored,bool disable_channels)2545 ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf,
2546                                       MovieTrackingTrack *track,
2547                                       MovieTrackingMarker *marker,
2548                                       bool anchored,
2549                                       bool disable_channels)
2550 {
2551   ImBuf *pattern_ibuf, *search_ibuf;
2552   float pat_min[2], pat_max[2];
2553   int num_samples_x, num_samples_y;
2554 
2555   BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
2556 
2557   num_samples_x = (pat_max[0] - pat_min[0]) * ibuf->x;
2558   num_samples_y = (pat_max[1] - pat_min[1]) * ibuf->y;
2559 
2560   search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, anchored, disable_channels);
2561 
2562   if (search_ibuf) {
2563     pattern_ibuf = BKE_tracking_sample_pattern(ibuf->x,
2564                                                ibuf->y,
2565                                                search_ibuf,
2566                                                track,
2567                                                marker,
2568                                                anchored,
2569                                                false,
2570                                                num_samples_x,
2571                                                num_samples_y,
2572                                                NULL);
2573 
2574     IMB_freeImBuf(search_ibuf);
2575   }
2576   else {
2577     pattern_ibuf = NULL;
2578   }
2579 
2580   return pattern_ibuf;
2581 }
2582 
BKE_tracking_get_search_imbuf(ImBuf * ibuf,MovieTrackingTrack * track,MovieTrackingMarker * marker,bool anchored,bool disable_channels)2583 ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
2584                                      MovieTrackingTrack *track,
2585                                      MovieTrackingMarker *marker,
2586                                      bool anchored,
2587                                      bool disable_channels)
2588 {
2589   ImBuf *searchibuf;
2590   int x, y, w, h;
2591   float search_origin[2];
2592 
2593   tracking_get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin);
2594 
2595   x = search_origin[0];
2596   y = search_origin[1];
2597 
2598   if (anchored) {
2599     x += track->offset[0] * ibuf->x;
2600     y += track->offset[1] * ibuf->y;
2601   }
2602 
2603   w = (marker->search_max[0] - marker->search_min[0]) * ibuf->x;
2604   h = (marker->search_max[1] - marker->search_min[1]) * ibuf->y;
2605 
2606   if (w <= 0 || h <= 0) {
2607     return NULL;
2608   }
2609 
2610   searchibuf = IMB_allocImBuf(w, h, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
2611 
2612   IMB_rectcpy(searchibuf, ibuf, 0, 0, x, y, w, h);
2613 
2614   if (disable_channels) {
2615     if ((track->flag & TRACK_PREVIEW_GRAYSCALE) || (track->flag & TRACK_DISABLE_RED) ||
2616         (track->flag & TRACK_DISABLE_GREEN) || (track->flag & TRACK_DISABLE_BLUE)) {
2617       disable_imbuf_channels(searchibuf, track, true);
2618     }
2619   }
2620 
2621   return searchibuf;
2622 }
2623 
2624 /* zap channels from the imbuf that are disabled by the user. this can lead to
2625  * better tracks sometimes. however, instead of simply zeroing the channels
2626  * out, do a partial grayscale conversion so the display is better.
2627  */
BKE_tracking_disable_channels(ImBuf * ibuf,bool disable_red,bool disable_green,bool disable_blue,bool grayscale)2628 void BKE_tracking_disable_channels(
2629     ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
2630 {
2631   if (!disable_red && !disable_green && !disable_blue && !grayscale) {
2632     return;
2633   }
2634 
2635   /* if only some components are selected, it's important to rescale the result
2636    * appropriately so that e.g. if only blue is selected, it's not zeroed out.
2637    */
2638   float scale = (disable_red ? 0.0f : 0.2126f) + (disable_green ? 0.0f : 0.7152f) +
2639                 (disable_blue ? 0.0f : 0.0722f);
2640 
2641   for (int y = 0; y < ibuf->y; y++) {
2642     for (int x = 0; x < ibuf->x; x++) {
2643       int pixel = ibuf->x * y + x;
2644 
2645       if (ibuf->rect_float) {
2646         float *rrgbf = ibuf->rect_float + pixel * 4;
2647         float r = disable_red ? 0.0f : rrgbf[0];
2648         float g = disable_green ? 0.0f : rrgbf[1];
2649         float b = disable_blue ? 0.0f : rrgbf[2];
2650 
2651         if (grayscale) {
2652           float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
2653 
2654           rrgbf[0] = rrgbf[1] = rrgbf[2] = gray;
2655         }
2656         else {
2657           rrgbf[0] = r;
2658           rrgbf[1] = g;
2659           rrgbf[2] = b;
2660         }
2661       }
2662       else {
2663         char *rrgb = (char *)ibuf->rect + pixel * 4;
2664         char r = disable_red ? 0 : rrgb[0];
2665         char g = disable_green ? 0 : rrgb[1];
2666         char b = disable_blue ? 0 : rrgb[2];
2667 
2668         if (grayscale) {
2669           float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
2670 
2671           rrgb[0] = rrgb[1] = rrgb[2] = gray;
2672         }
2673         else {
2674           rrgb[0] = r;
2675           rrgb[1] = g;
2676           rrgb[2] = b;
2677         }
2678       }
2679     }
2680   }
2681 
2682   if (ibuf->rect_float) {
2683     ibuf->userflags |= IB_RECT_INVALID;
2684   }
2685 }
2686 
2687 /*********************** Dopesheet functions *************************/
2688 
2689 /* ** Channels sort comparators ** */
2690 
channels_alpha_sort(const void * a,const void * b)2691 static int channels_alpha_sort(const void *a, const void *b)
2692 {
2693   const MovieTrackingDopesheetChannel *channel_a = a;
2694   const MovieTrackingDopesheetChannel *channel_b = b;
2695 
2696   if (BLI_strcasecmp(channel_a->track->name, channel_b->track->name) > 0) {
2697     return 1;
2698   }
2699 
2700   return 0;
2701 }
2702 
channels_total_track_sort(const void * a,const void * b)2703 static int channels_total_track_sort(const void *a, const void *b)
2704 {
2705   const MovieTrackingDopesheetChannel *channel_a = a;
2706   const MovieTrackingDopesheetChannel *channel_b = b;
2707 
2708   if (channel_a->total_frames > channel_b->total_frames) {
2709     return 1;
2710   }
2711 
2712   return 0;
2713 }
2714 
channels_longest_segment_sort(const void * a,const void * b)2715 static int channels_longest_segment_sort(const void *a, const void *b)
2716 {
2717   const MovieTrackingDopesheetChannel *channel_a = a;
2718   const MovieTrackingDopesheetChannel *channel_b = b;
2719 
2720   if (channel_a->max_segment > channel_b->max_segment) {
2721     return 1;
2722   }
2723 
2724   return 0;
2725 }
2726 
channels_average_error_sort(const void * a,const void * b)2727 static int channels_average_error_sort(const void *a, const void *b)
2728 {
2729   const MovieTrackingDopesheetChannel *channel_a = a;
2730   const MovieTrackingDopesheetChannel *channel_b = b;
2731 
2732   if (channel_a->track->error > channel_b->track->error) {
2733     return 1;
2734   }
2735 
2736   return 0;
2737 }
2738 
channels_alpha_inverse_sort(const void * a,const void * b)2739 static int channels_alpha_inverse_sort(const void *a, const void *b)
2740 {
2741   if (channels_alpha_sort(a, b)) {
2742     return 0;
2743   }
2744 
2745   return 1;
2746 }
2747 
channels_total_track_inverse_sort(const void * a,const void * b)2748 static int channels_total_track_inverse_sort(const void *a, const void *b)
2749 {
2750   if (channels_total_track_sort(a, b)) {
2751     return 0;
2752   }
2753 
2754   return 1;
2755 }
2756 
channels_longest_segment_inverse_sort(const void * a,const void * b)2757 static int channels_longest_segment_inverse_sort(const void *a, const void *b)
2758 {
2759   if (channels_longest_segment_sort(a, b)) {
2760     return 0;
2761   }
2762 
2763   return 1;
2764 }
2765 
channels_average_error_inverse_sort(const void * a,const void * b)2766 static int channels_average_error_inverse_sort(const void *a, const void *b)
2767 {
2768   const MovieTrackingDopesheetChannel *channel_a = a;
2769   const MovieTrackingDopesheetChannel *channel_b = b;
2770 
2771   if (channel_a->track->error < channel_b->track->error) {
2772     return 1;
2773   }
2774 
2775   return 0;
2776 }
2777 
2778 /* Calculate frames segments at which track is tracked continuously. */
tracking_dopesheet_channels_segments_calc(MovieTrackingDopesheetChannel * channel)2779 static void tracking_dopesheet_channels_segments_calc(MovieTrackingDopesheetChannel *channel)
2780 {
2781   MovieTrackingTrack *track = channel->track;
2782   int i, segment;
2783 
2784   channel->tot_segment = 0;
2785   channel->max_segment = 0;
2786   channel->total_frames = 0;
2787 
2788   /* TODO(sergey): looks a bit code-duplicated, need to look into
2789    *               logic de-duplication here.
2790    */
2791 
2792   /* count */
2793   i = 0;
2794   while (i < track->markersnr) {
2795     MovieTrackingMarker *marker = &track->markers[i];
2796 
2797     if ((marker->flag & MARKER_DISABLED) == 0) {
2798       int prev_fra = marker->framenr, len = 0;
2799 
2800       i++;
2801       while (i < track->markersnr) {
2802         marker = &track->markers[i];
2803 
2804         if (marker->framenr != prev_fra + 1) {
2805           break;
2806         }
2807         if (marker->flag & MARKER_DISABLED) {
2808           break;
2809         }
2810 
2811         prev_fra = marker->framenr;
2812         len++;
2813         i++;
2814       }
2815 
2816       channel->tot_segment++;
2817     }
2818 
2819     i++;
2820   }
2821 
2822   if (!channel->tot_segment) {
2823     return;
2824   }
2825 
2826   channel->segments = MEM_callocN(sizeof(int[2]) * channel->tot_segment,
2827                                   "tracking channel segments");
2828 
2829   /* create segments */
2830   i = 0;
2831   segment = 0;
2832   while (i < track->markersnr) {
2833     MovieTrackingMarker *marker = &track->markers[i];
2834 
2835     if ((marker->flag & MARKER_DISABLED) == 0) {
2836       MovieTrackingMarker *start_marker = marker;
2837       int prev_fra = marker->framenr, len = 0;
2838 
2839       i++;
2840       while (i < track->markersnr) {
2841         marker = &track->markers[i];
2842 
2843         if (marker->framenr != prev_fra + 1) {
2844           break;
2845         }
2846         if (marker->flag & MARKER_DISABLED) {
2847           break;
2848         }
2849 
2850         prev_fra = marker->framenr;
2851         channel->total_frames++;
2852         len++;
2853         i++;
2854       }
2855 
2856       channel->segments[2 * segment] = start_marker->framenr;
2857       channel->segments[2 * segment + 1] = start_marker->framenr + len;
2858 
2859       channel->max_segment = max_ii(channel->max_segment, len);
2860       segment++;
2861     }
2862 
2863     i++;
2864   }
2865 }
2866 
2867 /* Create channels for tracks and calculate tracked segments for them. */
tracking_dopesheet_channels_calc(MovieTracking * tracking)2868 static void tracking_dopesheet_channels_calc(MovieTracking *tracking)
2869 {
2870   MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
2871   MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
2872   MovieTrackingReconstruction *reconstruction = BKE_tracking_object_get_reconstruction(tracking,
2873                                                                                        object);
2874   ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
2875 
2876   bool sel_only = (dopesheet->flag & TRACKING_DOPE_SELECTED_ONLY) != 0;
2877   bool show_hidden = (dopesheet->flag & TRACKING_DOPE_SHOW_HIDDEN) != 0;
2878 
2879   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
2880     if (!show_hidden && (track->flag & TRACK_HIDDEN) != 0) {
2881       continue;
2882     }
2883 
2884     if (sel_only && !TRACK_SELECTED(track)) {
2885       continue;
2886     }
2887 
2888     MovieTrackingDopesheetChannel *channel = MEM_callocN(sizeof(MovieTrackingDopesheetChannel),
2889                                                          "tracking dopesheet channel");
2890     channel->track = track;
2891 
2892     if (reconstruction->flag & TRACKING_RECONSTRUCTED) {
2893       BLI_snprintf(channel->name, sizeof(channel->name), "%s (%.4f)", track->name, track->error);
2894     }
2895     else {
2896       BLI_strncpy(channel->name, track->name, sizeof(channel->name));
2897     }
2898 
2899     tracking_dopesheet_channels_segments_calc(channel);
2900 
2901     BLI_addtail(&dopesheet->channels, channel);
2902     dopesheet->tot_channel++;
2903   }
2904 }
2905 
2906 /* Sot dopesheet channels using given method (name, average error, total coverage,
2907  * longest tracked segment) and could also inverse the list if it's enabled.
2908  */
tracking_dopesheet_channels_sort(MovieTracking * tracking,int sort_method,bool inverse)2909 static void tracking_dopesheet_channels_sort(MovieTracking *tracking,
2910                                              int sort_method,
2911                                              bool inverse)
2912 {
2913   MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
2914 
2915   if (inverse) {
2916     if (sort_method == TRACKING_DOPE_SORT_NAME) {
2917       BLI_listbase_sort(&dopesheet->channels, channels_alpha_inverse_sort);
2918     }
2919     else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
2920       BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_inverse_sort);
2921     }
2922     else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
2923       BLI_listbase_sort(&dopesheet->channels, channels_total_track_inverse_sort);
2924     }
2925     else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
2926       BLI_listbase_sort(&dopesheet->channels, channels_average_error_inverse_sort);
2927     }
2928   }
2929   else {
2930     if (sort_method == TRACKING_DOPE_SORT_NAME) {
2931       BLI_listbase_sort(&dopesheet->channels, channels_alpha_sort);
2932     }
2933     else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
2934       BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_sort);
2935     }
2936     else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
2937       BLI_listbase_sort(&dopesheet->channels, channels_total_track_sort);
2938     }
2939     else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
2940       BLI_listbase_sort(&dopesheet->channels, channels_average_error_sort);
2941     }
2942   }
2943 }
2944 
coverage_from_count(int count)2945 static int coverage_from_count(int count)
2946 {
2947   /* Values are actually arbitrary here, probably need to be tweaked. */
2948   if (count < 8) {
2949     return TRACKING_COVERAGE_BAD;
2950   }
2951   if (count < 16) {
2952     return TRACKING_COVERAGE_ACCEPTABLE;
2953   }
2954   return TRACKING_COVERAGE_OK;
2955 }
2956 
2957 /* Calculate coverage of frames with tracks, this information
2958  * is used to highlight dopesheet background depending on how
2959  * many tracks exists on the frame.
2960  */
tracking_dopesheet_calc_coverage(MovieTracking * tracking)2961 static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
2962 {
2963   MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
2964   MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
2965   ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
2966   int frames, start_frame = INT_MAX, end_frame = -INT_MAX;
2967   int *per_frame_counter;
2968   int prev_coverage, last_segment_frame;
2969 
2970   /* find frame boundaries */
2971   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
2972     start_frame = min_ii(start_frame, track->markers[0].framenr);
2973     end_frame = max_ii(end_frame, track->markers[track->markersnr - 1].framenr);
2974   }
2975 
2976   frames = end_frame - start_frame + 1;
2977 
2978   /* this is a per-frame counter of markers (how many markers belongs to the same frame) */
2979   per_frame_counter = MEM_callocN(sizeof(int) * frames, "per frame track counter");
2980 
2981   /* find per-frame markers count */
2982   LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
2983     for (int i = 0; i < track->markersnr; i++) {
2984       MovieTrackingMarker *marker = &track->markers[i];
2985 
2986       /* TODO: perhaps we need to add check for non-single-frame track here */
2987       if ((marker->flag & MARKER_DISABLED) == 0) {
2988         per_frame_counter[marker->framenr - start_frame]++;
2989       }
2990     }
2991   }
2992 
2993   /* convert markers count to coverage and detect segments with the same coverage */
2994   prev_coverage = coverage_from_count(per_frame_counter[0]);
2995   last_segment_frame = start_frame;
2996 
2997   /* means only disabled tracks in the beginning, could be ignored */
2998   if (!per_frame_counter[0]) {
2999     prev_coverage = TRACKING_COVERAGE_OK;
3000   }
3001 
3002   for (int i = 1; i < frames; i++) {
3003     int coverage = coverage_from_count(per_frame_counter[i]);
3004 
3005     /* means only disabled tracks in the end, could be ignored */
3006     if (i == frames - 1 && !per_frame_counter[i]) {
3007       coverage = TRACKING_COVERAGE_OK;
3008     }
3009 
3010     if (coverage != prev_coverage || i == frames - 1) {
3011       MovieTrackingDopesheetCoverageSegment *coverage_segment;
3012       int end_segment_frame = i - 1 + start_frame;
3013 
3014       if (end_segment_frame == last_segment_frame) {
3015         end_segment_frame++;
3016       }
3017 
3018       coverage_segment = MEM_callocN(sizeof(MovieTrackingDopesheetCoverageSegment),
3019                                      "tracking coverage segment");
3020       coverage_segment->coverage = prev_coverage;
3021       coverage_segment->start_frame = last_segment_frame;
3022       coverage_segment->end_frame = end_segment_frame;
3023 
3024       BLI_addtail(&dopesheet->coverage_segments, coverage_segment);
3025 
3026       last_segment_frame = end_segment_frame;
3027     }
3028 
3029     prev_coverage = coverage;
3030   }
3031 
3032   MEM_freeN(per_frame_counter);
3033 }
3034 
3035 /* Tag dopesheet for update, actual update will happen later
3036  * when it'll be actually needed.
3037  */
BKE_tracking_dopesheet_tag_update(MovieTracking * tracking)3038 void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
3039 {
3040   MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
3041 
3042   dopesheet->ok = false;
3043 }
3044 
3045 /* Do dopesheet update, if update is not needed nothing will happen. */
BKE_tracking_dopesheet_update(MovieTracking * tracking)3046 void BKE_tracking_dopesheet_update(MovieTracking *tracking)
3047 {
3048   MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
3049 
3050   short sort_method = dopesheet->sort_method;
3051   bool inverse = (dopesheet->flag & TRACKING_DOPE_SORT_INVERSE) != 0;
3052 
3053   if (dopesheet->ok) {
3054     return;
3055   }
3056 
3057   tracking_dopesheet_free(dopesheet);
3058 
3059   /* channels */
3060   tracking_dopesheet_channels_calc(tracking);
3061   tracking_dopesheet_channels_sort(tracking, sort_method, inverse);
3062 
3063   /* frame coverage */
3064   tracking_dopesheet_calc_coverage(tracking);
3065 
3066   dopesheet->ok = true;
3067 }
3068 
3069 /* NOTE: Returns NULL if the track comes from camera object, */
BKE_tracking_find_object_for_track(const MovieTracking * tracking,const MovieTrackingTrack * track)3070 MovieTrackingObject *BKE_tracking_find_object_for_track(const MovieTracking *tracking,
3071                                                         const MovieTrackingTrack *track)
3072 {
3073   const ListBase *tracksbase = &tracking->tracks;
3074   if (BLI_findindex(tracksbase, track) != -1) {
3075     return NULL;
3076   }
3077   MovieTrackingObject *object = tracking->objects.first;
3078   while (object != NULL) {
3079     if (BLI_findindex(&object->tracks, track) != -1) {
3080       return object;
3081     }
3082     object = object->next;
3083   }
3084   return NULL;
3085 }
3086 
BKE_tracking_find_tracks_list_for_track(MovieTracking * tracking,const MovieTrackingTrack * track)3087 ListBase *BKE_tracking_find_tracks_list_for_track(MovieTracking *tracking,
3088                                                   const MovieTrackingTrack *track)
3089 {
3090   MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
3091   if (object != NULL) {
3092     return &object->tracks;
3093   }
3094   return &tracking->tracks;
3095 }
3096 
3097 /* NOTE: Returns NULL if the track comes from camera object, */
BKE_tracking_find_object_for_plane_track(const MovieTracking * tracking,const MovieTrackingPlaneTrack * plane_track)3098 MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
3099     const MovieTracking *tracking, const MovieTrackingPlaneTrack *plane_track)
3100 {
3101   const ListBase *plane_tracks_base = &tracking->plane_tracks;
3102   if (BLI_findindex(plane_tracks_base, plane_track) != -1) {
3103     return NULL;
3104   }
3105   MovieTrackingObject *object = tracking->objects.first;
3106   while (object != NULL) {
3107     if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
3108       return object;
3109     }
3110     object = object->next;
3111   }
3112   return NULL;
3113 }
3114 
BKE_tracking_find_tracks_list_for_plane_track(MovieTracking * tracking,const MovieTrackingPlaneTrack * plane_track)3115 ListBase *BKE_tracking_find_tracks_list_for_plane_track(MovieTracking *tracking,
3116                                                         const MovieTrackingPlaneTrack *plane_track)
3117 {
3118   MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
3119   if (object != NULL) {
3120     return &object->plane_tracks;
3121   }
3122   return &tracking->plane_tracks;
3123 }
3124 
BKE_tracking_get_rna_path_for_track(const struct MovieTracking * tracking,const struct MovieTrackingTrack * track,char * rna_path,size_t rna_path_len)3125 void BKE_tracking_get_rna_path_for_track(const struct MovieTracking *tracking,
3126                                          const struct MovieTrackingTrack *track,
3127                                          char *rna_path,
3128                                          size_t rna_path_len)
3129 {
3130   MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
3131   char track_name_esc[MAX_NAME * 2];
3132   BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
3133   if (object == NULL) {
3134     BLI_snprintf(rna_path, rna_path_len, "tracking.tracks[\"%s\"]", track_name_esc);
3135   }
3136   else {
3137     char object_name_esc[MAX_NAME * 2];
3138     BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
3139     BLI_snprintf(rna_path,
3140                  rna_path_len,
3141                  "tracking.objects[\"%s\"].tracks[\"%s\"]",
3142                  object_name_esc,
3143                  track_name_esc);
3144   }
3145 }
3146 
BKE_tracking_get_rna_path_prefix_for_track(const struct MovieTracking * tracking,const struct MovieTrackingTrack * track,char * rna_path,size_t rna_path_len)3147 void BKE_tracking_get_rna_path_prefix_for_track(const struct MovieTracking *tracking,
3148                                                 const struct MovieTrackingTrack *track,
3149                                                 char *rna_path,
3150                                                 size_t rna_path_len)
3151 {
3152   MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
3153   if (object == NULL) {
3154     BLI_strncpy(rna_path, "tracking.tracks", rna_path_len);
3155   }
3156   else {
3157     char object_name_esc[MAX_NAME * 2];
3158     BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
3159     BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"]", object_name_esc);
3160   }
3161 }
3162 
BKE_tracking_get_rna_path_for_plane_track(const struct MovieTracking * tracking,const struct MovieTrackingPlaneTrack * plane_track,char * rna_path,size_t rna_path_len)3163 void BKE_tracking_get_rna_path_for_plane_track(const struct MovieTracking *tracking,
3164                                                const struct MovieTrackingPlaneTrack *plane_track,
3165                                                char *rna_path,
3166                                                size_t rna_path_len)
3167 {
3168   MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
3169   char track_name_esc[MAX_NAME * 2];
3170   BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
3171   if (object == NULL) {
3172     BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks[\"%s\"]", track_name_esc);
3173   }
3174   else {
3175     char object_name_esc[MAX_NAME * 2];
3176     BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
3177     BLI_snprintf(rna_path,
3178                  rna_path_len,
3179                  "tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
3180                  object_name_esc,
3181                  track_name_esc);
3182   }
3183 }
3184 
BKE_tracking_get_rna_path_prefix_for_plane_track(const struct MovieTracking * tracking,const struct MovieTrackingPlaneTrack * plane_track,char * rna_path,size_t rna_path_len)3185 void BKE_tracking_get_rna_path_prefix_for_plane_track(
3186     const struct MovieTracking *tracking,
3187     const struct MovieTrackingPlaneTrack *plane_track,
3188     char *rna_path,
3189     size_t rna_path_len)
3190 {
3191   MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
3192   if (object == NULL) {
3193     BLI_strncpy(rna_path, "tracking.plane_tracks", rna_path_len);
3194   }
3195   else {
3196     char object_name_esc[MAX_NAME * 2];
3197     BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
3198     BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"].plane_tracks", object_name_esc);
3199   }
3200 }
3201