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