Merging r47793 through r47805 from trunk into soc-2011-tomato
[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_mask.h"
38 #include "BKE_movieclip.h"
39 #include "BKE_context.h"
40 #include "BKE_tracking.h"
41
42 #include "DNA_mask_types.h"
43 #include "DNA_object_types.h"   /* SELECT */
44
45 #include "BLI_utildefines.h"
46 #include "BLI_math.h"
47
48 #include "GPU_extensions.h"
49
50 #include "IMB_imbuf_types.h"
51 #include "IMB_imbuf.h"
52
53 #include "ED_screen.h"
54 #include "ED_clip.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 #include "UI_view2d.h"
63
64 #include "clip_intern.h"        // own include
65
66 /* ******** operactor poll functions ******** */
67
68 int ED_space_clip_poll(bContext *C)
69 {
70         SpaceClip *sc = CTX_wm_space_clip(C);
71
72         if (sc && sc->clip)
73                 return TRUE;
74
75         return FALSE;
76 }
77
78 int ED_space_clip_view_clip_poll(bContext *C)
79 {
80         SpaceClip *sc = CTX_wm_space_clip(C);
81
82         if (sc && sc->clip) {
83                 return sc->view == SC_VIEW_CLIP;
84         }
85
86         return FALSE;
87 }
88
89 int ED_space_clip_tracking_poll(bContext *C)
90 {
91         SpaceClip *sc = CTX_wm_space_clip(C);
92
93         if (sc && sc->clip)
94                 return ED_space_clip_show_trackedit(sc);
95
96         return FALSE;
97 }
98
99 int ED_space_clip_maskedit_poll(bContext *C)
100 {
101         SpaceClip *sc = CTX_wm_space_clip(C);
102
103         if (sc && sc->clip) {
104                 return ED_space_clip_show_maskedit(sc);
105         }
106
107         return FALSE;
108 }
109
110 int ED_space_clip_maskedit_mask_poll(bContext *C)
111 {
112         if (ED_space_clip_maskedit_poll(C)) {
113                 MovieClip *clip = CTX_data_edit_movieclip(C);
114
115                 if (clip) {
116                         SpaceClip *sc= CTX_wm_space_clip(C);
117
118                         return sc->mask != NULL;
119                 }
120         }
121
122         return FALSE;
123 }
124
125 /* ******** editing functions ******** */
126
127 void ED_space_clip_set(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
128 {
129         MovieClip *old_clip;
130
131         if (!screen && C)
132                 screen = CTX_wm_screen(C);
133
134         old_clip = sc->clip;
135         sc->clip = clip;
136
137         if (sc->clip && sc->clip->id.us == 0)
138                 sc->clip->id.us = 1;
139
140         if (screen && sc->view == SC_VIEW_CLIP) {
141                 ScrArea *area;
142                 SpaceLink *sl;
143
144                 for (area = screen->areabase.first; area; area = area->next) {
145                         for (sl = area->spacedata.first; sl; sl = sl->next) {
146                                 if (sl->spacetype == SPACE_CLIP) {
147                                         SpaceClip *cur_sc = (SpaceClip *) sl;
148
149                                         if (cur_sc != sc && cur_sc->view != SC_VIEW_CLIP) {
150                                                 if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
151                                                         cur_sc->clip = clip;
152                                                 }
153                                         }
154                                 }
155                         }
156                 }
157         }
158
159         if (C)
160                 WM_event_add_notifier(C, NC_MOVIECLIP | NA_SELECTED, sc->clip);
161 }
162
163 MovieClip *ED_space_clip(SpaceClip *sc)
164 {
165         return sc->clip;
166 }
167
168 Mask *ED_space_clip_mask(SpaceClip *sc)
169 {
170         return sc->mask;
171 }
172
173 ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
174 {
175         if (sc->clip) {
176                 ImBuf *ibuf;
177
178                 ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
179
180                 if (ibuf && (ibuf->rect || ibuf->rect_float))
181                         return ibuf;
182
183                 if (ibuf)
184                         IMB_freeImBuf(ibuf);
185         }
186
187         return NULL;
188 }
189
190 ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
191 {
192         if (sc->clip) {
193                 ImBuf *ibuf;
194
195                 ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
196
197                 if (ibuf && (ibuf->rect || ibuf->rect_float))
198                         return ibuf;
199
200                 if (ibuf)
201                         IMB_freeImBuf(ibuf);
202         }
203
204         return NULL;
205 }
206
207 void ED_space_clip_size(SpaceClip *sc, int *width, int *height)
208 {
209         if (!sc->clip) {
210                 *width = *height = 0;
211         }
212         else {
213                 BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
214         }
215 }
216
217 void ED_space_clip_mask_size(SpaceClip *sc, int *width, int *height)
218 {
219         /* quite the same as ED_space_clip_size, but it also runs aspect correction on output resolution
220          * this is needed because mask should be rasterized with exactly the same resolution as
221          * currently displaying frame and it doesn't have access to aspect correction currently
222          * used for display. (sergey)
223          */
224
225         if (!sc->mask) {
226                 *width = 0;
227                 *height = 0;
228         } else {
229                 float aspx, aspy;
230
231                 ED_space_clip_size(sc, width, height);
232                 ED_space_clip_aspect(sc, &aspx, &aspy);
233
234                 *width *= aspx;
235                 *height *= aspy;
236         }
237 }
238
239 void ED_space_clip_mask_aspect(SpaceClip *sc, float *aspx, float *aspy)
240 {
241         int w, h;
242
243         ED_space_clip_aspect(sc, aspx, aspy);
244         ED_space_clip_size(sc, &w, &h);
245
246         /* now this is not accounted for! */
247 #if 0
248         *aspx *= (float)w;
249         *aspy *= (float)h;
250 #endif
251
252         if (*aspx < *aspy) {
253                 *aspy= *aspy / *aspx;
254                 *aspx= 1.0f;
255         }
256         else {
257                 *aspx= *aspx / *aspy;
258                 *aspy= 1.0f;
259         }
260 }
261
262 void ED_space_clip_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
263 {
264         int width, height;
265
266         ED_space_clip_size(sc, &width, &height);
267
268         *zoomx = (float)(ar->winrct.xmax - ar->winrct.xmin + 1) / (float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin) * width);
269         *zoomy = (float)(ar->winrct.ymax - ar->winrct.ymin + 1) / (float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin) * height);
270 }
271
272 void ED_space_clip_aspect(SpaceClip *sc, float *aspx, float *aspy)
273 {
274         MovieClip *clip = ED_space_clip(sc);
275
276         if (clip)
277                 BKE_movieclip_aspect(clip, aspx, aspy);
278         else
279                 *aspx = *aspy = 1.0f;
280 }
281
282 void ED_space_clip_aspect_dimension_aware(SpaceClip *sc, float *aspx, float *aspy)
283 {
284         int w, h;
285
286         /* most of tools does not require aspect to be returned with dimensions correction
287          * due to they're invariant to this stuff, but some transformation tools like rotation
288          * should be aware of aspect correction caused by different resolution in different
289          * directions.
290          * mainly this is sued for transformation stuff
291          */
292
293         ED_space_clip_aspect(sc, aspx, aspy);
294         ED_space_clip_size(sc, &w, &h);
295
296         *aspx *= (float)w;
297         *aspy *= (float)h;
298
299         if (*aspx < *aspy) {
300                 *aspy= *aspy / *aspx;
301                 *aspx= 1.0f;
302         }
303         else {
304                 *aspx= *aspx / *aspy;
305                 *aspy= 1.0f;
306         }
307 }
308
309 void ED_clip_update_frame(const Main *mainp, int cfra)
310 {
311         wmWindowManager *wm;
312         wmWindow *win;
313
314         /* image window, compo node users */
315         for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
316                 for (win = wm->windows.first; win; win = win->next) {
317                         ScrArea *sa;
318
319                         for (sa = win->screen->areabase.first; sa; sa = sa->next) {
320                                 if (sa->spacetype == SPACE_CLIP) {
321                                         SpaceClip *sc = sa->spacedata.first;
322
323                                         sc->scopes.ok = FALSE;
324
325                                         BKE_movieclip_user_set_frame(&sc->user, cfra);
326                                 }
327                         }
328                 }
329         }
330 }
331
332 /* return current frame number in clip space */
333 int ED_space_clip_clip_framenr(SpaceClip *sc)
334 {
335         MovieClip *clip = ED_space_clip(sc);
336
337         return BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
338 }
339
340 static int selected_boundbox(SpaceClip *sc, float min[2], float max[2])
341 {
342         MovieClip *clip = ED_space_clip(sc);
343         MovieTrackingTrack *track;
344         int width, height, ok = FALSE;
345         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
346
347         INIT_MINMAX2(min, max);
348
349         ED_space_clip_size(sc, &width, &height);
350
351         track = tracksbase->first;
352         while (track) {
353                 if (TRACK_VIEW_SELECTED(sc, track)) {
354                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
355
356                         if (marker) {
357                                 float pos[3];
358
359                                 pos[0] = marker->pos[0] + track->offset[0];
360                                 pos[1] = marker->pos[1] + track->offset[1];
361                                 pos[2] = 0.0f;
362
363                                 /* undistortion happens for normalized coords */
364                                 if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
365                                         /* undistortion happens for normalized coords */
366                                         ED_clip_point_undistorted_pos(sc, pos, pos);
367                                 }
368
369                                 pos[0] *= width;
370                                 pos[1] *= height;
371
372                                 mul_v3_m4v3(pos, sc->stabmat, pos);
373
374                                 DO_MINMAX2(pos, min, max);
375
376                                 ok = TRUE;
377                         }
378                 }
379
380                 track = track->next;
381         }
382
383         return ok;
384 }
385
386 int ED_clip_view_selection(SpaceClip *sc, ARegion *ar, int fit)
387 {
388         int w, h, frame_width, frame_height;
389         float min[2], max[2];
390
391         ED_space_clip_size(sc, &frame_width, &frame_height);
392
393         if (frame_width == 0 || frame_height == 0)
394                 return FALSE;
395
396         if (!selected_boundbox(sc, min, max))
397                 return FALSE;
398
399         /* center view */
400         clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width),
401                                   (max[1] + min[1]) / (2 * frame_height));
402
403         w = max[0] - min[0];
404         h = max[1] - min[1];
405
406         /* set zoom to see all selection */
407         if (w > 0 && h > 0) {
408                 int width, height;
409                 float zoomx, zoomy, newzoom, aspx, aspy;
410
411                 ED_space_clip_aspect(sc, &aspx, &aspy);
412
413                 width = ar->winrct.xmax - ar->winrct.xmin + 1;
414                 height = ar->winrct.ymax - ar->winrct.ymin + 1;
415
416                 zoomx = (float)width / w / aspx;
417                 zoomy = (float)height / h / aspy;
418
419                 newzoom = 1.0f / power_of_2(1.0f / MIN2(zoomx, zoomy));
420
421                 if (fit || sc->zoom > newzoom)
422                         sc->zoom = newzoom;
423         }
424
425         return TRUE;
426 }
427
428 void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[2])
429 {
430         copy_v2_v2(r_co, co);
431
432         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
433                 MovieClip *clip = ED_space_clip(sc);
434                 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
435                 int width, height;
436
437                 ED_space_clip_size(sc, &width, &height);
438
439                 r_co[0] *= width;
440                 r_co[1] *= height * aspy;
441
442                 BKE_tracking_invert_intrinsics(&clip->tracking, r_co, r_co);
443
444                 r_co[0] /= width;
445                 r_co[1] /= height * aspy;
446         }
447 }
448
449 void ED_clip_point_stable_pos(bContext *C, float x, float y, float *xr, float *yr)
450 {
451         ARegion *ar = CTX_wm_region(C);
452         SpaceClip *sc = CTX_wm_space_clip(C);
453         int sx, sy, width, height;
454         float zoomx, zoomy, pos[3], imat[4][4];
455
456         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
457         ED_space_clip_size(sc, &width, &height);
458
459         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
460
461         pos[0] = (x - sx) / zoomx;
462         pos[1] = (y - sy) / zoomy;
463         pos[2] = 0.0f;
464
465         invert_m4_m4(imat, sc->stabmat);
466         mul_v3_m4v3(pos, imat, pos);
467
468         *xr = pos[0] / width;
469         *yr = pos[1] / height;
470
471         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
472                 MovieClip *clip = ED_space_clip(sc);
473                 MovieTracking *tracking = &clip->tracking;
474                 float aspy = 1.0f / tracking->camera.pixel_aspect;
475                 float tmp[2] = {*xr * width, *yr * height * aspy};
476
477                 BKE_tracking_apply_intrinsics(tracking, tmp, tmp);
478
479                 *xr = tmp[0] / width;
480                 *yr = tmp[1] / (height * aspy);
481         }
482 }
483
484 /**
485  * \brief the reverse of ED_clip_point_stable_pos(), gets the marker region coords.
486  * better name here? view_to_track / track_to_view or so?
487  */
488 void ED_clip_point_stable_pos__reverse(SpaceClip *sc, ARegion *ar, const float co[2], float r_co[2])
489 {
490         float zoomx, zoomy;
491         float pos[3];
492         int width, height;
493         int sx, sy;
494
495         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
496         ED_space_clip_size(sc, &width, &height);
497         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
498
499         ED_clip_point_undistorted_pos(sc, co, pos);
500         pos[2] = 0.0f;
501
502         /* untested */
503         mul_v3_m4v3(pos, sc->stabmat, pos);
504
505         r_co[0] = (pos[0] * width  * zoomx) + (float)sx;
506         r_co[1] = (pos[1] * height * zoomy) + (float)sy;
507 }
508
509 void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
510 {
511         ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
512 }
513
514 /* OpenGL draw context */
515
516 typedef struct SpaceClipDrawContext {
517         int support_checked, buffers_supported;
518
519         GLuint texture;                 /* OGL texture ID */
520         short texture_allocated;        /* flag if texture was allocated by glGenTextures */
521         struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
522         int image_width, image_height;  /* image width and height for which texture was created */
523         unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
524
525         /* fields to check if cache is still valid */
526         int framenr, start_frame, frame_offset;
527         short render_size, render_flag;
528 } SpaceClipDrawContext;
529
530 int ED_space_clip_texture_buffer_supported(SpaceClip *sc)
531 {
532         SpaceClipDrawContext *context = sc->draw_context;
533
534         if (!context) {
535                 context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
536                 sc->draw_context = context;
537         }
538
539         if (!context->support_checked) {
540                 context->support_checked = TRUE;
541                 if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
542                         context->buffers_supported = FALSE;
543                 }
544                 else {
545                         context->buffers_supported = GPU_non_power_of_two_support();
546                 }
547         }
548
549         return context->buffers_supported;
550 }
551
552 int ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
553 {
554         SpaceClipDrawContext *context = sc->draw_context;
555         MovieClip *clip = ED_space_clip(sc);
556         int need_rebind = 0;
557
558         context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
559
560         /* image texture need to be rebinded if displaying another image buffer
561          * assuming displaying happens of footage frames only on which painting doesn't heppen.
562          * so not changed image buffer pointer means unchanged image content */
563         need_rebind |= context->texture_ibuf != ibuf;
564         need_rebind |= context->framenr != sc->user.framenr;
565         need_rebind |= context->render_size != sc->user.render_size;
566         need_rebind |= context->render_flag != sc->user.render_flag;
567         need_rebind |= context->start_frame != clip->start_frame;
568         need_rebind |= context->frame_offset != clip->frame_offset;
569
570         if (need_rebind) {
571                 int width = ibuf->x, height = ibuf->y;
572                 int need_recreate = 0;
573
574                 if (width > GL_MAX_TEXTURE_SIZE || height > GL_MAX_TEXTURE_SIZE)
575                         return 0;
576
577                 /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
578                 need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
579
580                 if (context->texture_ibuf && need_recreate) {
581                         glDeleteTextures(1, &context->texture);
582                         context->texture_allocated = 0;
583                 }
584
585                 if (need_recreate || !context->texture_allocated) {
586                         /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
587                         int filter = GL_LINEAR;
588
589                         /* non-scaled proxy shouldn;t use diltering */
590                         if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
591                             ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
592                         {
593                                 filter = GL_NEAREST;
594                         }
595
596                         glGenTextures(1, &context->texture);
597                         glBindTexture(GL_TEXTURE_2D, context->texture);
598                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
599                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
600                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
601                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
602                 }
603                 else {
604                         /* if texture doesn't need to be reallocated itself, just bind it so
605                          * loading of image will happen to a proper texture */
606                         glBindTexture(GL_TEXTURE_2D, context->texture);
607                 }
608
609                 if (ibuf->rect_float) {
610                         if (ibuf->rect == NULL)
611                                 IMB_rect_from_float(ibuf);
612                 }
613
614                 if (ibuf->rect)
615                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
616
617                 /* store settings */
618                 context->texture_allocated = 1;
619                 context->texture_ibuf = ibuf;
620                 context->image_width = ibuf->x;
621                 context->image_height = ibuf->y;
622                 context->framenr = sc->user.framenr;
623                 context->render_size = sc->user.render_size;
624                 context->render_flag = sc->user.render_flag;
625                 context->start_frame = clip->start_frame;
626                 context->frame_offset = clip->frame_offset;
627         }
628         else {
629                 /* displaying exactly the same image which was loaded t oa texture,
630                  * just bint texture in this case */
631                 glBindTexture(GL_TEXTURE_2D, context->texture);
632         }
633
634         glEnable(GL_TEXTURE_2D);
635
636         return TRUE;
637 }
638
639 void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
640 {
641         SpaceClipDrawContext *context = sc->draw_context;
642
643         glBindTexture(GL_TEXTURE_2D, context->last_texture);
644         glDisable(GL_TEXTURE_2D);
645 }
646
647 void ED_space_clip_free_texture_buffer(SpaceClip *sc)
648 {
649         SpaceClipDrawContext *context = sc->draw_context;
650
651         if (context) {
652                 glDeleteTextures(1, &context->texture);
653
654                 MEM_freeN(context);
655         }
656 }
657
658 /* ******** masking editing related functions ******** */
659
660 int ED_space_clip_show_trackedit(SpaceClip *sc)
661 {
662         if (sc) {
663                 return ELEM3(sc->mode, SC_MODE_TRACKING, SC_MODE_RECONSTRUCTION, SC_MODE_DISTORTION);
664         }
665
666         return FALSE;
667 }
668
669 int ED_space_clip_show_maskedit(SpaceClip *sc)
670 {
671         if (sc) {
672                 return sc->mode == SC_MODE_MASKEDIT;
673         }
674
675         return FALSE;
676 }
677
678 void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
679 {
680         sc->mask = mask;
681
682         if (sc->mask && sc->mask->id.us==0) {
683                 sc->clip->id.us = 1;
684         }
685
686         if (C) {
687                 WM_event_add_notifier(C, NC_MASK|NA_SELECTED, mask);
688         }
689 }