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