Merging r46495 through r46557 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_tracking_size_poll(bContext *C)
100 {
101         if (ED_space_clip_tracking_poll(C)) {
102                 MovieClip *clip = CTX_data_edit_movieclip(C);
103
104                 if (clip) {
105                         SpaceClip *sc = CTX_wm_space_clip(C);
106                         int width, height;
107
108                         BKE_movieclip_get_size(clip, &sc->user, &width, &height);
109
110                         return width > 0 && height > 0;
111                 }
112         }
113
114         return FALSE;
115 }
116
117 int ED_space_clip_tracking_frame_poll(bContext *C)
118 {
119         if (ED_space_clip_tracking_poll(C)) {
120                 MovieClip *clip = CTX_data_edit_movieclip(C);
121
122                 if (clip) {
123                         SpaceClip *sc = CTX_wm_space_clip(C);
124
125                         return BKE_movieclip_has_frame(clip, &sc->user);
126                 }
127         }
128
129         return FALSE;
130 }
131
132 int ED_space_clip_maskediting_poll(bContext *C)
133 {
134         SpaceClip *sc = CTX_wm_space_clip(C);
135
136         if (sc && sc->clip) {
137                 return ED_space_clip_show_maskedit(sc);
138         }
139
140         return FALSE;
141 }
142
143 int ED_space_clip_maskediting_mask_poll(bContext *C)
144 {
145         if (ED_space_clip_maskediting_poll(C)) {
146                 MovieClip *clip = CTX_data_edit_movieclip(C);
147
148                 if (clip) {
149                         SpaceClip *sc= CTX_wm_space_clip(C);
150
151                         return sc->mask != NULL;
152                 }
153         }
154
155         return FALSE;
156 }
157
158 /* ******** editing functions ******** */
159
160 void ED_space_clip_set(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
161 {
162         MovieClip *old_clip;
163
164         if (!screen && C)
165                 screen = CTX_wm_screen(C);
166
167         old_clip = sc->clip;
168         sc->clip = clip;
169
170         if (sc->clip && sc->clip->id.us == 0)
171                 sc->clip->id.us = 1;
172
173         if (screen) {
174                 ScrArea *area;
175                 SpaceLink *sl;
176
177                 for (area = screen->areabase.first; area; area = area->next) {
178                         for (sl = area->spacedata.first; sl; sl = sl->next) {
179                                 if (sl->spacetype == SPACE_CLIP) {
180                                         SpaceClip *cur_sc = (SpaceClip *) sl;
181
182                                         if (cur_sc != sc) {
183                                                 if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
184                                                         cur_sc->clip = clip;
185                                                 }
186                                         }
187                                 }
188                         }
189                 }
190         }
191
192         if (C)
193                 WM_event_add_notifier(C, NC_MOVIECLIP | NA_SELECTED, sc->clip);
194 }
195
196 MovieClip *ED_space_clip(SpaceClip *sc)
197 {
198         return sc->clip;
199 }
200
201 Mask *ED_space_clip_mask(SpaceClip *sc)
202 {
203         return sc->mask;
204 }
205
206 ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
207 {
208         if (sc->clip) {
209                 ImBuf *ibuf;
210
211                 ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
212
213                 if (ibuf && (ibuf->rect || ibuf->rect_float))
214                         return ibuf;
215
216                 if (ibuf)
217                         IMB_freeImBuf(ibuf);
218         }
219
220         return NULL;
221 }
222
223 ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
224 {
225         if (sc->clip) {
226                 ImBuf *ibuf;
227
228                 ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
229
230                 if (ibuf && (ibuf->rect || ibuf->rect_float))
231                         return ibuf;
232
233                 if (ibuf)
234                         IMB_freeImBuf(ibuf);
235         }
236
237         return NULL;
238 }
239
240 void ED_space_clip_size(SpaceClip *sc, int *width, int *height)
241 {
242         if (!sc->clip) {
243                 *width = *height = 0;
244         }
245         else {
246                 BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
247         }
248 }
249
250 void ED_space_clip_mask_size(SpaceClip *sc, int *width, int *height)
251 {
252         if(!sc->mask) {
253                 *width= 0;
254                 *height= 0;
255         } else {
256                 float aspx, aspy;
257
258                 ED_space_clip_size(sc, width, height);
259                 ED_space_clip_aspect(sc, &aspx, &aspy);
260
261                 *width *= aspx;
262                 *height *= aspy;
263         }
264 }
265
266 void ED_space_clip_mask_aspect(SpaceClip *sc, float *aspx, float *aspy)
267 {
268         int w, h;
269
270         ED_space_clip_aspect(sc, aspx, aspy);
271         ED_space_clip_size(sc, &w, &h);
272
273         *aspx *= (float)w;
274         *aspy *= (float)h;
275
276         if(*aspx < *aspy) {
277                 *aspy= *aspy / *aspx;
278                 *aspx= 1.0f;
279         }
280         else {
281                 *aspx= *aspx / *aspy;
282                 *aspy= 1.0f;
283         }
284 }
285
286 void ED_space_clip_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
287 {
288         int width, height;
289
290         ED_space_clip_size(sc, &width, &height);
291
292         *zoomx = (float)(ar->winrct.xmax - ar->winrct.xmin + 1) / (float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin) * width);
293         *zoomy = (float)(ar->winrct.ymax - ar->winrct.ymin + 1) / (float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin) * height);
294 }
295
296 void ED_space_clip_aspect(SpaceClip *sc, float *aspx, float *aspy)
297 {
298         MovieClip *clip = ED_space_clip(sc);
299
300         if (clip)
301                 BKE_movieclip_aspect(clip, aspx, aspy);
302         else
303                 *aspx = *aspy = 1.0f;
304 }
305
306 void ED_clip_update_frame(const Main *mainp, int cfra)
307 {
308         wmWindowManager *wm;
309         wmWindow *win;
310
311         /* image window, compo node users */
312         for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
313                 for (win = wm->windows.first; win; win = win->next) {
314                         ScrArea *sa;
315
316                         for (sa = win->screen->areabase.first; sa; sa = sa->next) {
317                                 if (sa->spacetype == SPACE_CLIP) {
318                                         SpaceClip *sc = sa->spacedata.first;
319
320                                         sc->scopes.ok = FALSE;
321
322                                         BKE_movieclip_user_set_frame(&sc->user, cfra);
323                                 }
324                         }
325                 }
326         }
327 }
328
329 static int selected_boundbox(SpaceClip *sc, float min[2], float max[2])
330 {
331         MovieClip *clip = ED_space_clip(sc);
332         MovieTrackingTrack *track;
333         int width, height, ok = FALSE;
334         ListBase *tracksbase = BKE_tracking_get_tracks(&clip->tracking);
335
336         INIT_MINMAX2(min, max);
337
338         ED_space_clip_size(sc, &width, &height);
339
340         track = tracksbase->first;
341         while (track) {
342                 if (TRACK_VIEW_SELECTED(sc, track)) {
343                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
344
345                         if (marker) {
346                                 float pos[3];
347
348                                 pos[0] = marker->pos[0] + track->offset[0];
349                                 pos[1] = marker->pos[1] + track->offset[1];
350                                 pos[2] = 0.0f;
351
352                                 /* undistortion happens for normalized coords */
353                                 if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
354                                         /* undistortion happens for normalized coords */
355                                         ED_clip_point_undistorted_pos(sc, pos, pos);
356                                 }
357
358                                 pos[0] *= width;
359                                 pos[1] *= height;
360
361                                 mul_v3_m4v3(pos, sc->stabmat, pos);
362
363                                 DO_MINMAX2(pos, min, max);
364
365                                 ok = TRUE;
366                         }
367                 }
368
369                 track = track->next;
370         }
371
372         return ok;
373 }
374
375 int ED_clip_view_selection(SpaceClip *sc, ARegion *ar, int fit)
376 {
377         int w, h, frame_width, frame_height;
378         float min[2], max[2];
379
380         ED_space_clip_size(sc, &frame_width, &frame_height);
381
382         if (frame_width == 0 || frame_height == 0)
383                 return FALSE;
384
385         if (!selected_boundbox(sc, min, max))
386                 return FALSE;
387
388         /* center view */
389         clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width),
390                                   (max[1] + min[1]) / (2 * frame_height));
391
392         w = max[0] - min[0];
393         h = max[1] - min[1];
394
395         /* set zoom to see all selection */
396         if (w > 0 && h > 0) {
397                 int width, height;
398                 float zoomx, zoomy, newzoom, aspx, aspy;
399
400                 ED_space_clip_aspect(sc, &aspx, &aspy);
401
402                 width = ar->winrct.xmax - ar->winrct.xmin + 1;
403                 height = ar->winrct.ymax - ar->winrct.ymin + 1;
404
405                 zoomx = (float)width / w / aspx;
406                 zoomy = (float)height / h / aspy;
407
408                 newzoom = 1.0f / power_of_2(1.0f / MIN2(zoomx, zoomy));
409
410                 if (fit || sc->zoom > newzoom)
411                         sc->zoom = newzoom;
412         }
413
414         return TRUE;
415 }
416
417 void ED_clip_point_undistorted_pos(SpaceClip *sc, float co[2], float nco[2])
418 {
419         copy_v2_v2(nco, co);
420
421         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
422                 MovieClip *clip = ED_space_clip(sc);
423                 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
424                 int width, height;
425
426                 ED_space_clip_size(sc, &width, &height);
427
428                 nco[0] *= width;
429                 nco[1] *= height * aspy;
430
431                 BKE_tracking_invert_intrinsics(&clip->tracking, nco, nco);
432
433                 nco[0] /= width;
434                 nco[1] /= height * aspy;
435         }
436 }
437
438 void ED_clip_point_stable_pos(bContext *C, float x, float y, float *xr, float *yr)
439 {
440         ARegion *ar = CTX_wm_region(C);
441         SpaceClip *sc = CTX_wm_space_clip(C);
442         int sx, sy, width, height;
443         float zoomx, zoomy, pos[3] = {0.0f, 0.0f, 0.0f}, imat[4][4];
444
445         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
446         ED_space_clip_size(sc, &width, &height);
447
448         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
449
450         pos[0] = (x - sx) / zoomx;
451         pos[1] = (y - sy) / zoomy;
452
453         invert_m4_m4(imat, sc->stabmat);
454         mul_v3_m4v3(pos, imat, pos);
455
456         *xr = pos[0] / width;
457         *yr = pos[1] / height;
458
459         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
460                 MovieClip *clip = ED_space_clip(sc);
461                 MovieTracking *tracking = &clip->tracking;
462                 float aspy = 1.0f / tracking->camera.pixel_aspect;
463                 float tmp[2] = {*xr * width, *yr * height * aspy};
464
465                 BKE_tracking_apply_intrinsics(tracking, tmp, tmp);
466
467                 *xr = tmp[0] / width;
468                 *yr = tmp[1] / (height * aspy);
469         }
470 }
471
472 void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
473 {
474         ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
475 }
476
477 /* OpenGL draw context */
478
479 typedef struct SpaceClipDrawContext {
480         int support_checked, buffers_supported;
481
482         GLuint texture;                 /* OGL texture ID */
483         short texture_allocated;        /* flag if texture was allocated by glGenTextures */
484         struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
485         int image_width, image_height;  /* image width and height for which texture was created */
486         unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
487         int framenr;
488 } SpaceClipDrawContext;
489
490 int ED_space_clip_texture_buffer_supported(SpaceClip *sc)
491 {
492         SpaceClipDrawContext *context = sc->draw_context;
493
494         if (!context) {
495                 context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
496                 sc->draw_context = context;
497         }
498
499         if (!context->support_checked) {
500                 context->support_checked = TRUE;
501                 if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
502                         context->buffers_supported = FALSE;
503                 }
504                 else {
505                         context->buffers_supported = GPU_non_power_of_two_support();
506                 }
507         }
508
509         return context->buffers_supported;
510 }
511
512 int ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
513 {
514         SpaceClipDrawContext *context = sc->draw_context;
515         MovieClip *clip = ED_space_clip(sc);
516         int need_rebind = 0;
517
518         context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
519
520         /* image texture need to be rebinded if displaying another image buffer
521          * assuming displaying happens of footage frames only on which painting doesn't heppen.
522          * so not changed image buffer pointer means unchanged image content */
523         need_rebind |= context->texture_ibuf != ibuf;
524         need_rebind |= context->framenr != sc->user.framenr;
525
526         if (need_rebind) {
527                 int width = ibuf->x, height = ibuf->y;
528                 int need_recreate = 0;
529
530                 if (width > GL_MAX_TEXTURE_SIZE || height > GL_MAX_TEXTURE_SIZE)
531                         return 0;
532
533                 /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
534                 need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
535
536                 if (context->texture_ibuf && need_recreate) {
537                         glDeleteTextures(1, &context->texture);
538                         context->texture_allocated = 0;
539                 }
540
541                 if (need_recreate || !context->texture_allocated) {
542                         /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
543                         int filter = GL_LINEAR;
544
545                         /* non-scaled proxy shouldn;t use diltering */
546                         if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
547                             ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
548                         {
549                                 filter = GL_NEAREST;
550                         }
551
552                         glGenTextures(1, &context->texture);
553                         glBindTexture(GL_TEXTURE_2D, context->texture);
554                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
555                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
556                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
557                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
558                 }
559                 else {
560                         /* if texture doesn't need to be reallocated itself, just bind it so
561                          * loading of image will happen to a proper texture */
562                         glBindTexture(GL_TEXTURE_2D, context->texture);
563                 }
564
565                 if (ibuf->rect_float) {
566                         if (ibuf->rect == NULL)
567                                 IMB_rect_from_float(ibuf);
568                 }
569
570                 if (ibuf->rect)
571                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
572
573                 /* store settings */
574                 context->texture_allocated = 1;
575                 context->texture_ibuf = ibuf;
576                 context->image_width = ibuf->x;
577                 context->image_height = ibuf->y;
578                 context->framenr = sc->user.framenr;
579         }
580         else {
581                 /* displaying exactly the same image which was loaded t oa texture,
582                  * just bint texture in this case */
583                 glBindTexture(GL_TEXTURE_2D, context->texture);
584         }
585
586         glEnable(GL_TEXTURE_2D);
587
588         return TRUE;
589 }
590
591 void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
592 {
593         SpaceClipDrawContext *context = sc->draw_context;
594
595         glBindTexture(GL_TEXTURE_2D, context->last_texture);
596         glDisable(GL_TEXTURE_2D);
597 }
598
599 void ED_space_clip_free_texture_buffer(SpaceClip *sc)
600 {
601         SpaceClipDrawContext *context = sc->draw_context;
602
603         if (context) {
604                 glDeleteTextures(1, &context->texture);
605
606                 MEM_freeN(context);
607         }
608 }
609
610 /* ******** masking editing related functions ******** */
611
612 int ED_space_clip_show_trackedit(SpaceClip *sc)
613 {
614         if (sc) {
615                 return ELEM3(sc->mode, SC_MODE_TRACKING, SC_MODE_RECONSTRUCTION, SC_MODE_DISTORTION);
616         }
617
618         return FALSE;
619 }
620
621 int ED_space_clip_show_maskedit(SpaceClip *sc)
622 {
623         if (sc) {
624                 return sc->mode == SC_MODE_MASKEDITING;
625         }
626
627         return FALSE;
628 }
629
630 void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
631 {
632         sc->mask = mask;
633
634         if(sc->mask && sc->mask->id.us==0)
635                 sc->clip->id.us = 1;
636
637         if(C)
638                 WM_event_add_notifier(C, NC_MASK|NA_SELECTED, mask);
639 }