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