Movie Clip Editor: implemented option to display frame using OpenGL textures
authorSergey Sharybin <sergey.vfx@gmail.com>
Fri, 3 Feb 2012 19:13:31 +0000 (19:13 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 3 Feb 2012 19:13:31 +0000 (19:13 +0000)
Initial idea was to perform bilinear filtering for displaying proxied frame
to make it looking a bit smoother. It was done but it was also discovered
that using such kind of texture buffers helps on some crappy videocards
when playing $k footage.

Currently check for NPOT support is disabled, so use this option with care.

release/scripts/startup/bl_ui/space_clip.py
source/blender/blenloader/intern/readfile.c
source/blender/editors/include/ED_clip.h
source/blender/editors/space_clip/CMakeLists.txt
source/blender/editors/space_clip/SConscript
source/blender/editors/space_clip/clip_draw.c
source/blender/editors/space_clip/clip_editor.c
source/blender/editors/space_clip/space_clip.c
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_space.c

index 3499249a8f984a15b2c65b9bf8bb7c4d5fd10b14..3799361d3de7c94aa271ba34bb5bbdb525011479 100644 (file)
@@ -559,6 +559,8 @@ class CLIP_PT_display(Panel):
         elif sc.mode == 'RECONSTRUCTION':
             col.prop(sc, "show_stable", text="Stable")
 
+        col.prop(sc, "use_texture_buffer")
+
         clip = sc.clip
         if clip:
             col.label(text="Display Aspect Ratio:")
index 6bd12e8d3f65df461dfd08415dbc3afdff5367ed..b30d04b31cc7d486516bc82ba200ccc09adbe25b 100644 (file)
@@ -5273,6 +5273,7 @@ static void lib_link_screen(FileData *fd, Main *main)
                                                sclip->clip= newlibadr_us(fd, sc->id.lib, sclip->clip);
 
                                                sclip->scopes.track_preview = NULL;
+                                               sclip->draw_context = NULL;
                                                sclip->scopes.ok = 0;
                                        }
                                }
index 7d36159f47e480d442e9ba6391a5166290c0aa25..004fd7ceef7c3fb8f31852e02b437d609ceb0218 100644 (file)
@@ -58,6 +58,10 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, float co[2], float nco[2]);
 void ED_clip_point_stable_pos(struct bContext *C, float x, float y, float *xr, float *yr);
 void ED_clip_mouse_pos(struct bContext *C, struct wmEvent *event, float co[2]);
 
+void ED_space_clip_load_movieclip_buffer(struct SpaceClip *sc, struct ImBuf *ibuf);
+void ED_space_clip_unload_movieclip_buffer(struct SpaceClip *sc);
+void ED_space_clip_free_texture_buffer(struct SpaceClip *sc);
+
 /* clip_ops.c */
 void ED_operatormacros_clip(void);
 
index 4f9819e8e777a4cb1b1cebf90362359a307a910e..30d2fe57c1006e6e7b56e44a91ce9c38e621ab9c 100644 (file)
@@ -31,6 +31,7 @@ set(INC
        ../../makesdna
        ../../makesrna
        ../../windowmanager
+       ../../gpu
        ../../../../intern/guardedalloc
        ${GLEW_INCLUDE_PATH}
 )
index 70331b0ec4aeea8a8b2119b428355dd61ff59ad3..c9c82aea68e571421280846bbd123a918f1b40f4 100644 (file)
@@ -4,6 +4,6 @@ Import ('env')
 sources = env.Glob('*.c')
 defs = []
 incs = '../include ../../blenkernel ../../blenloader ../../blenfont ../../blenlib ../../imbuf ../../makesdna'
-incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../gpu'
 
 env.BlenderLib ( 'bf_editors_space_clip', sources, Split(incs), defs, libtype=['core'], priority=[95] )
index de43b30d4f416a537237ce6f63597716c0aea239..2533629c4fba3f8f80d70eea997dfe032853403c 100644 (file)
@@ -216,9 +216,6 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
        int x, y;
        MovieClip *clip= ED_space_clip(sc);
 
-       /* set zoom */
-       glPixelZoom(zoomx*width/ibuf->x, zoomy*height/ibuf->y);
-
        /* find window pixel coordinates of origin */
        UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
 
@@ -230,8 +227,36 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
                        IMB_rect_from_float(ibuf);
                }
 
-               if(ibuf->rect)
-                       glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+               if(ibuf->rect) {
+                       if(sc->flag & SC_TEXTURE_BUFFER) {
+                               ED_space_clip_load_movieclip_buffer(sc, ibuf);
+
+                               glPushMatrix();
+                               glTranslatef(x, y, 0);
+                               glScalef(zoomx, zoomy, 1.0f);
+                               glMultMatrixf(sc->stabmat);
+
+                               glBegin(GL_QUADS);
+                                       glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f,  0.0f);
+                                       glTexCoord2f(1.0f, 0.0f); glVertex2f(width, 0.0f);
+                                       glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height);
+                                       glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f,  height);
+                               glEnd();
+
+                               glPopMatrix();
+
+                               ED_space_clip_unload_movieclip_buffer(sc);
+                       }
+                       else {
+                               /* set zoom */
+                               glPixelZoom(zoomx*width/ibuf->x, zoomy*height/ibuf->y);
+
+                               glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+                               /* reset zoom */
+                               glPixelZoom(1.0f, 1.0f);
+                       }
+               }
        }
 
        /* draw boundary border for frame if stabilization is enabled */
@@ -260,10 +285,6 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
                glDisable(GL_COLOR_LOGIC_OP);
                glDisable(GL_LINE_STIPPLE);
        }
-
-
-       /* reset zoom */
-       glPixelZoom(1.0f, 1.0f);
 }
 
 static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
index 35d870022a48f10ea54a5febd148b08e4f28a0cc..9835a1cf43bf36f457dd8a3de9fa8f89b2655f8b 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <stddef.h>
 
+#include "MEM_guardedalloc.h"
+
 #include "BKE_main.h"
 #include "BKE_movieclip.h"
 #include "BKE_context.h"
@@ -40,6 +42,8 @@
 #include "BLI_utildefines.h"
 #include "BLI_math.h"
 
+#include "GPU_extensions.h"
+
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
@@ -47,6 +51,7 @@
 #include "ED_clip.h"
 
 #include "BIF_gl.h"
+#include "BIF_glutil.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -309,3 +314,145 @@ void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
 {
        ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
 }
+
+/* OpenGL draw context */
+
+typedef struct SpaceClipDrawContext {
+       GLuint texture;                         /* OGL texture ID */
+       short texture_allocated;        /* flag if texture was allocated by glGenTextures */
+       struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
+       int image_width, image_height;  /* image width and height for which texture was created */
+       unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
+} SpaceClipDrawContext;
+
+void ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+       MovieClip *clip = ED_space_clip(sc);
+       int need_rebind = 0;
+
+       if (!context) {
+               context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
+               sc->draw_context = context;
+       }
+
+       context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
+
+       /* image texture need to be rebinded if displaying another image buffer
+        * assuming displaying happens of footage frames only on which painting doesn't heppen.
+        * so not changed image buffer pointer means unchanged image content */
+       need_rebind |= context->texture_ibuf != ibuf;
+
+       if (need_rebind) {
+               int width = ibuf->x, height = ibuf->y;
+               float *frect = NULL, *fscalerect = NULL;
+               unsigned int *rect = NULL, *scalerect = NULL;
+               int need_recreate = 0;
+
+               rect = ibuf->rect;
+               frect = ibuf->rect_float;
+
+               /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
+               need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
+
+               if (context->texture_ibuf && need_recreate) {
+                       glDeleteTextures(1, &context->texture);
+                       context->texture_allocated = 0;
+               }
+
+#if 0
+               /* disabled for now because current tracking users have got NPOT textures
+                * working smoothly on their computers and forcing re-scaling during playback
+                * slows down playback a lot */
+
+               /* if videocard doesn't support NPOT textures, need to do rescaling */
+               if (!GPU_non_power_of_two_support()) {
+                       if (!is_power_of_2_i(width) || !is_power_of_2_i(height)) {
+                               width = power_of_2_max_i(width);
+                               height = power_of_2_max_i(height);
+
+                               if (ibuf->x != width || ibuf->y != height) {
+                                       if (frect) {
+                                               fscalerect= MEM_mallocN(width*width*sizeof(*fscalerect)*4, "fscalerect");
+                                               gluScaleImage(GL_RGBA, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float, width, height, GL_FLOAT, fscalerect);
+
+                                               frect = fscalerect;
+                                       }
+                                       else {
+                                               scalerect= MEM_mallocN(width*height*sizeof(*scalerect), "scalerect");
+                                               gluScaleImage(GL_RGBA, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect, width, height, GL_UNSIGNED_BYTE, scalerect);
+
+                                               rect = scalerect;
+                                       }
+                               }
+                       }
+               }
+#endif
+
+               if (need_recreate || !context->texture_allocated) {
+                       /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
+                       int filter = GL_LINEAR;
+
+                       /* non-scaled proxy shouldn;t use diltering */
+                       if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
+                           ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
+                       {
+                               filter = GL_NEAREST;
+                       }
+
+                       glGenTextures(1, &context->texture);
+                       glBindTexture(GL_TEXTURE_2D, context->texture);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+               }
+               else {
+                       /* if texture doesn't need to be reallocated itself, just bind it so
+                        * loading of image will happen to a proper texture */
+                       glBindTexture(GL_TEXTURE_2D, context->texture);
+               }
+
+               if (frect)
+                       glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  width, height, 0, GL_RGBA, GL_FLOAT, frect);
+               else
+                       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+               /* store settings */
+               context->texture_allocated = 1;
+               context->texture_ibuf = ibuf;
+               context->image_width = ibuf->x;
+               context->image_height = ibuf->y;
+
+               if (fscalerect)
+                       MEM_freeN(fscalerect);
+               if (scalerect)
+                       MEM_freeN(scalerect);
+       }
+       else {
+               /* displaying exactly the same image which was loaded t oa texture,
+                * just bint texture in this case */
+               glBindTexture(GL_TEXTURE_2D, context->texture);
+       }
+
+       glEnable(GL_TEXTURE_2D);
+}
+
+void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+
+       glBindTexture(GL_TEXTURE_2D, context->last_texture);
+       glDisable(GL_TEXTURE_2D);
+}
+
+void ED_space_clip_free_texture_buffer(SpaceClip *sc)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+
+       if (context) {
+               glDeleteTextures(1, &context->texture);
+
+               MEM_freeN(context);
+       }
+}
index 5abdafbfffc7fd39f4f467124f39aa20f469b76c..7cd7060e1d457ade3e260a51bb1afac4e369fc2d 100644 (file)
@@ -214,6 +214,8 @@ static void clip_free(SpaceLink *sl)
 
        if(sc->scopes.track_preview)
                IMB_freeImBuf(sc->scopes.track_preview);
+
+       ED_space_clip_free_texture_buffer(sc);
 }
 
 /* spacetype; init callback */
@@ -229,6 +231,7 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
        /* clear or remove stuff from old */
        scn->scopes.track_preview= NULL;
        scn->scopes.ok= 0;
+       scn->draw_context= NULL;
 
        return (SpaceLink *)scn;
 }
index 64d858bbcee8d314b444639fa335d79029665864..f5ca88d9391fc4d0ee4ad50a06e05467a0acfdbf 100644 (file)
@@ -521,6 +521,8 @@ typedef struct SpaceClip {
 
        /* movie postprocessing */
        int postproc_flag, pad2;
+
+       void *draw_context;
 } SpaceClip;
 
 /* view3d  Now in DNA_view3d_types.h */
@@ -902,6 +904,7 @@ enum {
 #define SC_SHOW_GRAPH_TRACKS   (1<<15)
 /*#define SC_SHOW_PYRAMID_LEVELS       (1<<16) */      /* UNUSED */
 #define SC_LOCK_TIMECURSOR             (1<<17)
+#define SC_TEXTURE_BUFFER              (1<<18)
 
 /* SpaceClip->mode */
 #define SC_MODE_TRACKING               0
index 8499e2fa111b5fc6ff58e6017fafa7801c746a58..cb4151d8aee8eb1f0d8418ad561f2bb806e9ca09 100644 (file)
@@ -2985,6 +2985,11 @@ static void rna_def_space_clip(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Show Tracks", "Display the speed curves (in \"x\" direction red, in \"y\" direction green) for the selected tracks");
        RNA_def_property_update(prop, NC_SPACE|ND_SPACE_CLIP, NULL);
 
+       prop= RNA_def_property(srna, "use_texture_buffer", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_ui_text(prop, "Use Texture Buffer", "Use texture buffer to display o,age frames frame on screen");
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_TEXTURE_BUFFER);
+       RNA_def_property_update(prop, NC_WINDOW, NULL);
+
        /* ** channels ** */
 
        /* show_red_channel */