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