Camera tracking: initial commit of dopesheet view for clip editor
[blender.git] / source / blender / editors / space_clip / clip_editor.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/clip_editor.c
29  *  \ingroup spclip
30  */
31
32 #include <stddef.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BKE_main.h"
37 #include "BKE_movieclip.h"
38 #include "BKE_context.h"
39 #include "BKE_tracking.h"
40
41 #include "DNA_object_types.h"   /* SELECT */
42
43 #include "BLI_utildefines.h"
44 #include "BLI_math.h"
45
46 #include "GPU_extensions.h"
47
48 #include "IMB_imbuf_types.h"
49 #include "IMB_imbuf.h"
50
51 #include "ED_screen.h"
52 #include "ED_clip.h"
53
54 #include "BIF_gl.h"
55 #include "BIF_glutil.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "UI_view2d.h"
61
62 #include "clip_intern.h"        // own include
63
64 /* ******** operactor poll functions ******** */
65
66 int ED_space_clip_poll(bContext *C)
67 {
68         SpaceClip *sc = CTX_wm_space_clip(C);
69
70         if (sc && sc->clip)
71                 return TRUE;
72
73         return FALSE;
74 }
75
76 int ED_space_clip_tracking_poll(bContext *C)
77 {
78         SpaceClip *sc= CTX_wm_space_clip(C);
79
80         if (sc && sc->clip)
81                 return ED_space_clip_show_trackedit(sc);
82
83         return FALSE;
84 }
85
86 int ED_space_clip_tracking_size_poll(bContext *C)
87 {
88         if (ED_space_clip_tracking_poll(C)) {
89                 MovieClip *clip = CTX_data_edit_movieclip(C);
90
91                 if (clip) {
92                         SpaceClip *sc = CTX_wm_space_clip(C);
93                         int width, height;
94
95                         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
96
97                         return width > 0 && height > 0;
98                 }
99         }
100
101         return FALSE;
102 }
103
104 int ED_space_clip_tracking_frame_poll(bContext *C)
105 {
106         if (ED_space_clip_tracking_poll(C)) {
107                 MovieClip *clip = CTX_data_edit_movieclip(C);
108
109                 if (clip) {
110                         SpaceClip *sc = CTX_wm_space_clip(C);
111
112                         return BKE_movieclip_has_frame(clip, &sc->user);
113                 }
114         }
115
116         return FALSE;
117 }
118
119 /* ******** editing functions ******** */
120
121 void ED_space_clip_set(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
122 {
123         MovieClip *old_clip;
124
125         if (!screen && C)
126                 screen = CTX_wm_screen(C);
127
128         old_clip = sc->clip;
129         sc->clip = clip;
130
131         if (sc->clip && sc->clip->id.us==0)
132                 sc->clip->id.us = 1;
133
134         if (screen) {
135                 ScrArea *area;
136                 SpaceLink *sl;
137
138                 for (area = screen->areabase.first; area; area = area->next) {
139                         for (sl = area->spacedata.first; sl; sl = sl->next) {
140                                 if (sl->spacetype == SPACE_CLIP) {
141                                         SpaceClip *cur_sc = (SpaceClip *) sl;
142
143                                         if (cur_sc != sc) {
144                                                 if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
145                                                         cur_sc->clip = clip;
146                                                 }
147                                         }
148                                 }
149                         }
150                 }
151         }
152
153         if (C)
154                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_SELECTED, sc->clip);
155 }
156
157 MovieClip *ED_space_clip(SpaceClip *sc)
158 {
159         return sc->clip;
160 }
161
162 ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
163 {
164         if (sc->clip) {
165                 ImBuf *ibuf;
166
167                 ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
168
169                 if (ibuf && (ibuf->rect || ibuf->rect_float))
170                         return ibuf;
171
172                 if (ibuf)
173                         IMB_freeImBuf(ibuf);
174         }
175
176         return NULL;
177 }
178
179 ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
180 {
181         if (sc->clip) {
182                 ImBuf *ibuf;
183
184                 ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
185
186                 if (ibuf && (ibuf->rect || ibuf->rect_float))
187                         return ibuf;
188
189                 if (ibuf)
190                         IMB_freeImBuf(ibuf);
191         }
192
193         return NULL;
194 }
195
196 void ED_space_clip_size(SpaceClip *sc, int *width, int *height)
197 {
198         if (!sc->clip) {
199                 *width = *height = 0;
200         }
201         else {
202                 BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
203         }
204 }
205
206 void ED_space_clip_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
207 {
208         int width, height;
209
210         ED_space_clip_size(sc, &width, &height);
211
212         *zoomx = (float)(ar->winrct.xmax - ar->winrct.xmin + 1)/(float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin)*width);
213         *zoomy = (float)(ar->winrct.ymax - ar->winrct.ymin + 1)/(float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin)*height);
214 }
215
216 void ED_space_clip_aspect(SpaceClip *sc, float *aspx, float *aspy)
217 {
218         MovieClip *clip = ED_space_clip(sc);
219
220         if (clip)
221                 BKE_movieclip_aspect(clip, aspx, aspy);
222         else
223                 *aspx = *aspy = 1.0f;
224 }
225
226 void ED_clip_update_frame(const Main *mainp, int cfra)
227 {
228         wmWindowManager *wm;
229         wmWindow *win;
230
231         /* image window, compo node users */
232         for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
233                 for (win = wm->windows.first; win; win = win->next) {
234                         ScrArea *sa;
235
236                         for (sa = win->screen->areabase.first; sa; sa = sa->next) {
237                                 if (sa->spacetype == SPACE_CLIP) {
238                                         SpaceClip *sc = sa->spacedata.first;
239
240                                         sc->scopes.ok = FALSE;
241
242                                         BKE_movieclip_user_set_frame(&sc->user, cfra);
243                                 }
244                         }
245                 }
246         }
247 }
248
249 static int selected_boundbox(SpaceClip *sc, float min[2], float max[2])
250 {
251         MovieClip *clip = ED_space_clip(sc);
252         MovieTrackingTrack *track;
253         int width, height, ok = FALSE;
254         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
255
256         INIT_MINMAX2(min, max);
257
258         ED_space_clip_size(sc, &width, &height);
259
260         track = tracksbase->first;
261         while (track) {
262                 if (TRACK_VIEW_SELECTED(sc, track)) {
263                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
264
265                         if (marker) {
266                                 float pos[3];
267
268                                 pos[0] = marker->pos[0] + track->offset[0];
269                                 pos[1] = marker->pos[1] + track->offset[1];
270                                 pos[2] = 0.0f;
271
272                                 /* undistortion happens for normalized coords */
273                                 if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
274                                         /* undistortion happens for normalized coords */
275                                         ED_clip_point_undistorted_pos(sc, pos, pos);
276                                 }
277
278                                 pos[0] *= width;
279                                 pos[1] *= height;
280
281                                 mul_v3_m4v3(pos, sc->stabmat, pos);
282
283                                 DO_MINMAX2(pos, min, max);
284
285                                 ok = TRUE;
286                         }
287                 }
288
289                 track = track->next;
290         }
291
292         return ok;
293 }
294
295 int ED_clip_view_selection(SpaceClip *sc, ARegion *ar, int fit)
296 {
297         int w, h, frame_width, frame_height;
298         float min[2], max[2];
299
300         ED_space_clip_size(sc, &frame_width, &frame_height);
301
302         if (frame_width == 0 || frame_height == 0)
303                 return FALSE;
304
305         if (!selected_boundbox(sc, min, max))
306                 return FALSE;
307
308         /* center view */
309         clip_view_center_to_point(sc, (max[0]+min[0])/(2*frame_width), (max[1]+min[1])/(2*frame_height));
310
311         w = max[0] - min[0];
312         h = max[1] - min[1];
313
314         /* set zoom to see all selection */
315         if (w > 0 && h > 0) {
316                 int width, height;
317                 float zoomx, zoomy, newzoom, aspx, aspy;
318
319                 ED_space_clip_aspect(sc, &aspx, &aspy);
320
321                 width = ar->winrct.xmax - ar->winrct.xmin + 1;
322                 height = ar->winrct.ymax - ar->winrct.ymin + 1;
323
324                 zoomx = (float)width / w / aspx;
325                 zoomy = (float)height / h / aspy;
326
327                 newzoom = 1.0f / power_of_2(1.0f / MIN2(zoomx, zoomy));
328
329                 if (fit || sc->zoom>newzoom)
330                         sc->zoom = newzoom;
331         }
332
333         return TRUE;
334 }
335
336 void ED_clip_point_undistorted_pos(SpaceClip *sc, float co[2], float nco[2])
337 {
338         copy_v2_v2(nco, co);
339
340         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
341                 MovieClip *clip = ED_space_clip(sc);
342                 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
343                 int width, height;
344
345                 ED_space_clip_size(sc, &width, &height);
346
347                 nco[0] *= width;
348                 nco[1] *= height * aspy;
349
350                 BKE_tracking_invert_intrinsics(&clip->tracking, nco, nco);
351
352                 nco[0] /= width;
353                 nco[1] /= height * aspy;
354         }
355 }
356
357 void ED_clip_point_stable_pos(bContext *C, float x, float y, float *xr, float *yr)
358 {
359         ARegion *ar = CTX_wm_region(C);
360         SpaceClip *sc = CTX_wm_space_clip(C);
361         int sx, sy, width, height;
362         float zoomx, zoomy, pos[3] = {0.0f, 0.0f, 0.0f}, imat[4][4];
363
364         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
365         ED_space_clip_size(sc, &width, &height);
366
367         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
368
369         pos[0] = (x - sx) / zoomx;
370         pos[1] = (y - sy) / zoomy;
371
372         invert_m4_m4(imat, sc->stabmat);
373         mul_v3_m4v3(pos, imat, pos);
374
375         *xr = pos[0] / width;
376         *yr = pos[1] / height;
377
378         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
379                 MovieClip *clip = ED_space_clip(sc);
380                 MovieTracking *tracking = &clip->tracking;
381                 float aspy = 1.0f / tracking->camera.pixel_aspect;
382                 float tmp[2] = {*xr * width, *yr * height * aspy};
383
384                 BKE_tracking_apply_intrinsics(tracking, tmp, tmp);
385
386                 *xr = tmp[0] / width;
387                 *yr = tmp[1] / (height * aspy);
388         }
389 }
390
391 void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
392 {
393         ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
394 }
395
396 /* OpenGL draw context */
397
398 typedef struct SpaceClipDrawContext {
399         int support_checked, buffers_supported;
400
401         GLuint texture;                 /* OGL texture ID */
402         short texture_allocated;        /* flag if texture was allocated by glGenTextures */
403         struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
404         int image_width, image_height;  /* image width and height for which texture was created */
405         unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
406         int framenr;
407 } SpaceClipDrawContext;
408
409 int ED_space_clip_texture_buffer_supported(SpaceClip *sc)
410 {
411         SpaceClipDrawContext *context = sc->draw_context;
412
413         if (!context) {
414                 context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
415                 sc->draw_context = context;
416         }
417
418         if (!context->support_checked) {
419                 context->support_checked = TRUE;
420                 if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
421                         context->buffers_supported = FALSE;
422                 }
423                 else {
424                         context->buffers_supported = GPU_non_power_of_two_support();
425                 }
426         }
427
428         return context->buffers_supported;
429 }
430
431 int ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
432 {
433         SpaceClipDrawContext *context = sc->draw_context;
434         MovieClip *clip = ED_space_clip(sc);
435         int need_rebind = 0;
436
437         context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
438
439         /* image texture need to be rebinded if displaying another image buffer
440          * assuming displaying happens of footage frames only on which painting doesn't heppen.
441          * so not changed image buffer pointer means unchanged image content */
442         need_rebind |= context->texture_ibuf != ibuf;
443         need_rebind |= context->framenr != sc->user.framenr;
444
445         if (need_rebind) {
446                 int width = ibuf->x, height = ibuf->y;
447                 float *frect = NULL, *fscalerect = NULL;
448                 unsigned int *rect = NULL, *scalerect = NULL;
449                 int need_recreate = 0;
450
451                 if (width > GL_MAX_TEXTURE_SIZE || height > GL_MAX_TEXTURE_SIZE)
452                         return 0;
453
454                 rect = ibuf->rect;
455                 frect = ibuf->rect_float;
456
457                 /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
458                 need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
459
460                 if (context->texture_ibuf && need_recreate) {
461                         glDeleteTextures(1, &context->texture);
462                         context->texture_allocated = 0;
463                 }
464
465                 if (need_recreate || !context->texture_allocated) {
466                         /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
467                         int filter = GL_LINEAR;
468
469                         /* non-scaled proxy shouldn;t use diltering */
470                         if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
471                             ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
472                         {
473                                 filter = GL_NEAREST;
474                         }
475
476                         glGenTextures(1, &context->texture);
477                         glBindTexture(GL_TEXTURE_2D, context->texture);
478                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
479                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
480                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
481                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
482                 }
483                 else {
484                         /* if texture doesn't need to be reallocated itself, just bind it so
485                          * loading of image will happen to a proper texture */
486                         glBindTexture(GL_TEXTURE_2D, context->texture);
487                 }
488
489                 if (frect)
490                         glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  width, height, 0, GL_RGBA, GL_FLOAT, frect);
491                 else
492                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
493
494                 /* store settings */
495                 context->texture_allocated = 1;
496                 context->texture_ibuf = ibuf;
497                 context->image_width = ibuf->x;
498                 context->image_height = ibuf->y;
499                 context->framenr = sc->user.framenr;
500
501                 if (fscalerect)
502                         MEM_freeN(fscalerect);
503                 if (scalerect)
504                         MEM_freeN(scalerect);
505         }
506         else {
507                 /* displaying exactly the same image which was loaded t oa texture,
508                  * just bint texture in this case */
509                 glBindTexture(GL_TEXTURE_2D, context->texture);
510         }
511
512         glEnable(GL_TEXTURE_2D);
513
514         return TRUE;
515 }
516
517 void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
518 {
519         SpaceClipDrawContext *context = sc->draw_context;
520
521         glBindTexture(GL_TEXTURE_2D, context->last_texture);
522         glDisable(GL_TEXTURE_2D);
523 }
524
525 void ED_space_clip_free_texture_buffer(SpaceClip *sc)
526 {
527         SpaceClipDrawContext *context = sc->draw_context;
528
529         if (context) {
530                 glDeleteTextures(1, &context->texture);
531
532                 MEM_freeN(context);
533         }
534 }
535
536 int ED_space_clip_show_trackedit(SpaceClip *sc)
537 {
538         if (sc) {
539                 return ELEM3(sc->mode, SC_MODE_TRACKING, SC_MODE_RECONSTRUCTION, SC_MODE_DISTORTION);
540         }
541
542         return FALSE;
543 }
544
545 void ED_space_clip_update_dopesheet(SpaceClip *sc)
546 {
547         MovieClip *clip = sc->clip;
548         MovieTracking *tracking = &clip->tracking;
549
550         BKE_tracking_update_dopesheet(tracking);
551 }