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