Merging r44227 through r45619 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_movieclip.h"
38 #include "BKE_context.h"
39 #include "BKE_tracking.h"
40 #include "DNA_object_types.h"   /* SELECT */
41
42 #include "BLI_utildefines.h"
43 #include "BLI_math.h"
44
45 #include "GPU_extensions.h"
46
47 #include "IMB_imbuf_types.h"
48 #include "IMB_imbuf.h"
49
50 #include "ED_screen.h"
51 #include "ED_clip.h"
52
53 #include "BIF_gl.h"
54 #include "BIF_glutil.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "UI_view2d.h"
60
61 #include "clip_intern.h"        // own include
62
63 int ED_space_clip_poll(bContext *C)
64 {
65         SpaceClip *sc = CTX_wm_space_clip(C);
66
67         if (sc && sc->clip)
68                 return TRUE;
69
70         return FALSE;
71 }
72
73 void ED_space_clip_set(bContext *C, SpaceClip *sc, MovieClip *clip)
74 {
75         sc->clip = clip;
76
77         if (sc->clip && sc->clip->id.us==0)
78                 sc->clip->id.us = 1;
79
80         if (C)
81                 WM_event_add_notifier(C, NC_MOVIECLIP|NA_SELECTED, sc->clip);
82 }
83
84 MovieClip *ED_space_clip(SpaceClip *sc)
85 {
86         return sc->clip;
87 }
88
89 ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
90 {
91         if (sc->clip) {
92                 ImBuf *ibuf;
93
94                 ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
95
96                 if (ibuf && (ibuf->rect || ibuf->rect_float))
97                         return ibuf;
98
99                 if (ibuf)
100                         IMB_freeImBuf(ibuf);
101         }
102
103         return NULL;
104 }
105
106 ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
107 {
108         if (sc->clip) {
109                 ImBuf *ibuf;
110
111                 ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
112
113                 if (ibuf && (ibuf->rect || ibuf->rect_float))
114                         return ibuf;
115
116                 if (ibuf)
117                         IMB_freeImBuf(ibuf);
118         }
119
120         return NULL;
121 }
122
123 void ED_space_clip_size(SpaceClip *sc, int *width, int *height)
124 {
125         if (!sc->clip) {
126                 *width = *height = 0;
127         }
128         else {
129                 BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
130         }
131 }
132
133 void ED_space_clip_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
134 {
135         int width, height;
136
137         ED_space_clip_size(sc, &width, &height);
138
139         *zoomx = (float)(ar->winrct.xmax - ar->winrct.xmin + 1)/(float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin)*width);
140         *zoomy = (float)(ar->winrct.ymax - ar->winrct.ymin + 1)/(float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin)*height);
141 }
142
143 void ED_space_clip_aspect(SpaceClip *sc, float *aspx, float *aspy)
144 {
145         MovieClip *clip = ED_space_clip(sc);
146
147         if (clip)
148                 BKE_movieclip_aspect(clip, aspx, aspy);
149         else
150                 *aspx = *aspy = 1.0f;
151 }
152
153 void ED_clip_update_frame(const Main *mainp, int cfra)
154 {
155         wmWindowManager *wm;
156         wmWindow *win;
157
158         /* image window, compo node users */
159         for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
160                 for (win = wm->windows.first; win; win = win->next) {
161                         ScrArea *sa;
162
163                         for (sa = win->screen->areabase.first; sa; sa = sa->next) {
164                                 if (sa->spacetype == SPACE_CLIP) {
165                                         SpaceClip *sc = sa->spacedata.first;
166
167                                         sc->scopes.ok = FALSE;
168
169                                         BKE_movieclip_user_set_frame(&sc->user, cfra);
170                                 }
171                         }
172                 }
173         }
174 }
175
176 static int selected_boundbox(SpaceClip *sc, float min[2], float max[2])
177 {
178         MovieClip *clip = ED_space_clip(sc);
179         MovieTrackingTrack *track;
180         int width, height, ok = FALSE;
181         ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
182
183         INIT_MINMAX2(min, max);
184
185         ED_space_clip_size(sc, &width, &height);
186
187         track = tracksbase->first;
188         while (track) {
189                 if (TRACK_VIEW_SELECTED(sc, track)) {
190                         MovieTrackingMarker *marker = BKE_tracking_get_marker(track, sc->user.framenr);
191
192                         if (marker) {
193                                 float pos[3];
194
195                                 pos[0] = marker->pos[0] + track->offset[0];
196                                 pos[1] = marker->pos[1] + track->offset[1];
197                                 pos[2] = 0.0f;
198
199                                 /* undistortion happens for normalized coords */
200                                 if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
201                                         /* undistortion happens for normalized coords */
202                                         ED_clip_point_undistorted_pos(sc, pos, pos);
203                                 }
204
205                                 pos[0] *= width;
206                                 pos[1] *= height;
207
208                                 mul_v3_m4v3(pos, sc->stabmat, pos);
209
210                                 DO_MINMAX2(pos, min, max);
211
212                                 ok = TRUE;
213                         }
214                 }
215
216                 track = track->next;
217         }
218
219         return ok;
220 }
221
222 int ED_clip_view_selection(SpaceClip *sc, ARegion *ar, int fit)
223 {
224         int w, h, frame_width, frame_height;
225         float min[2], max[2];
226
227         ED_space_clip_size(sc, &frame_width, &frame_height);
228
229         if (frame_width == 0 || frame_height == 0)
230                 return FALSE;
231
232         if (!selected_boundbox(sc, min, max))
233                 return FALSE;
234
235         /* center view */
236         clip_view_center_to_point(sc, (max[0]+min[0])/(2*frame_width), (max[1]+min[1])/(2*frame_height));
237
238         w = max[0] - min[0];
239         h = max[1] - min[1];
240
241         /* set zoom to see all selection */
242         if (w > 0 && h > 0) {
243                 int width, height;
244                 float zoomx, zoomy, newzoom, aspx, aspy;
245
246                 ED_space_clip_aspect(sc, &aspx, &aspy);
247
248                 width = ar->winrct.xmax - ar->winrct.xmin + 1;
249                 height = ar->winrct.ymax - ar->winrct.ymin + 1;
250
251                 zoomx = (float)width / w / aspx;
252                 zoomy = (float)height / h / aspy;
253
254                 newzoom = 1.0f / power_of_2(1.0f / MIN2(zoomx, zoomy));
255
256                 if (fit || sc->zoom>newzoom)
257                         sc->zoom = newzoom;
258         }
259
260         return TRUE;
261 }
262
263 void ED_clip_point_undistorted_pos(SpaceClip *sc, float co[2], float nco[2])
264 {
265         copy_v2_v2(nco, co);
266
267         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
268                 MovieClip *clip = ED_space_clip(sc);
269                 float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
270                 int width, height;
271
272                 ED_space_clip_size(sc, &width, &height);
273
274                 nco[0] *= width;
275                 nco[1] *= height * aspy;
276
277                 BKE_tracking_invert_intrinsics(&clip->tracking, nco, nco);
278
279                 nco[0] /= width;
280                 nco[1] /= height * aspy;
281         }
282 }
283
284 void ED_clip_point_stable_pos(bContext *C, float x, float y, float *xr, float *yr)
285 {
286         ARegion *ar = CTX_wm_region(C);
287         SpaceClip *sc = CTX_wm_space_clip(C);
288         int sx, sy, width, height;
289         float zoomx, zoomy, pos[3] = {0.0f, 0.0f, 0.0f}, imat[4][4];
290
291         ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
292         ED_space_clip_size(sc, &width, &height);
293
294         UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
295
296         pos[0] = (x - sx) / zoomx;
297         pos[1] = (y - sy) / zoomy;
298
299         invert_m4_m4(imat, sc->stabmat);
300         mul_v3_m4v3(pos, imat, pos);
301
302         *xr = pos[0] / width;
303         *yr = pos[1] / height;
304
305         if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
306                 MovieClip *clip = ED_space_clip(sc);
307                 MovieTracking *tracking = &clip->tracking;
308                 float aspy = 1.0f / tracking->camera.pixel_aspect;
309                 float tmp[2] = {*xr * width, *yr * height * aspy};
310
311                 BKE_tracking_apply_intrinsics(tracking, tmp, tmp);
312
313                 *xr = tmp[0] / width;
314                 *yr = tmp[1] / (height * aspy);
315         }
316 }
317
318 void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
319 {
320         ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
321 }
322
323 /* OpenGL draw context */
324
325 typedef struct SpaceClipDrawContext {
326         GLuint texture;                         /* OGL texture ID */
327         short texture_allocated;        /* flag if texture was allocated by glGenTextures */
328         struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
329         int image_width, image_height;  /* image width and height for which texture was created */
330         unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
331         int framenr;
332 } SpaceClipDrawContext;
333
334 void ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
335 {
336         SpaceClipDrawContext *context = sc->draw_context;
337         MovieClip *clip = ED_space_clip(sc);
338         int need_rebind = 0;
339
340         if (!context) {
341                 context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
342                 sc->draw_context = context;
343         }
344
345         context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
346
347         /* image texture need to be rebinded if displaying another image buffer
348          * assuming displaying happens of footage frames only on which painting doesn't heppen.
349          * so not changed image buffer pointer means unchanged image content */
350         need_rebind |= context->texture_ibuf != ibuf;
351         need_rebind |= context->framenr != sc->user.framenr;
352
353         if (need_rebind) {
354                 int width = ibuf->x, height = ibuf->y;
355                 float *frect = NULL, *fscalerect = NULL;
356                 unsigned int *rect = NULL, *scalerect = NULL;
357                 int need_recreate = 0;
358
359                 rect = ibuf->rect;
360                 frect = ibuf->rect_float;
361
362                 /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
363                 need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
364
365                 if (context->texture_ibuf && need_recreate) {
366                         glDeleteTextures(1, &context->texture);
367                         context->texture_allocated = 0;
368                 }
369
370 #if 0
371                 /* disabled for now because current tracking users have got NPOT textures
372                  * working smoothly on their computers and forcing re-scaling during playback
373                  * slows down playback a lot */
374
375                 /* if videocard doesn't support NPOT textures, need to do rescaling */
376                 if (!GPU_non_power_of_two_support()) {
377                         if (!is_power_of_2_i(width) || !is_power_of_2_i(height)) {
378                                 width = power_of_2_max_i(width);
379                                 height = power_of_2_max_i(height);
380
381                                 if (ibuf->x != width || ibuf->y != height) {
382                                         if (frect) {
383                                                 fscalerect= MEM_mallocN(width*width*sizeof(*fscalerect)*4, "fscalerect");
384                                                 gluScaleImage(GL_RGBA, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float, width, height, GL_FLOAT, fscalerect);
385
386                                                 frect = fscalerect;
387                                         }
388                                         else {
389                                                 scalerect= MEM_mallocN(width*height*sizeof(*scalerect), "scalerect");
390                                                 gluScaleImage(GL_RGBA, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect, width, height, GL_UNSIGNED_BYTE, scalerect);
391
392                                                 rect = scalerect;
393                                         }
394                                 }
395                         }
396                 }
397 #endif
398
399                 if (need_recreate || !context->texture_allocated) {
400                         /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
401                         int filter = GL_LINEAR;
402
403                         /* non-scaled proxy shouldn;t use diltering */
404                         if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
405                             ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
406                         {
407                                 filter = GL_NEAREST;
408                         }
409
410                         glGenTextures(1, &context->texture);
411                         glBindTexture(GL_TEXTURE_2D, context->texture);
412                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
413                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
414                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
415                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
416                 }
417                 else {
418                         /* if texture doesn't need to be reallocated itself, just bind it so
419                          * loading of image will happen to a proper texture */
420                         glBindTexture(GL_TEXTURE_2D, context->texture);
421                 }
422
423                 if (frect)
424                         glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  width, height, 0, GL_RGBA, GL_FLOAT, frect);
425                 else
426                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
427
428                 /* store settings */
429                 context->texture_allocated = 1;
430                 context->texture_ibuf = ibuf;
431                 context->image_width = ibuf->x;
432                 context->image_height = ibuf->y;
433                 context->framenr = sc->user.framenr;
434
435                 if (fscalerect)
436                         MEM_freeN(fscalerect);
437                 if (scalerect)
438                         MEM_freeN(scalerect);
439         }
440         else {
441                 /* displaying exactly the same image which was loaded t oa texture,
442                  * just bint texture in this case */
443                 glBindTexture(GL_TEXTURE_2D, context->texture);
444         }
445
446         glEnable(GL_TEXTURE_2D);
447 }
448
449 void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
450 {
451         SpaceClipDrawContext *context = sc->draw_context;
452
453         glBindTexture(GL_TEXTURE_2D, context->last_texture);
454         glDisable(GL_TEXTURE_2D);
455 }
456
457 void ED_space_clip_free_texture_buffer(SpaceClip *sc)
458 {
459         SpaceClipDrawContext *context = sc->draw_context;
460
461         if (context) {
462                 glDeleteTextures(1, &context->texture);
463
464                 MEM_freeN(context);
465         }
466 }