code cleanup: favor braces when blocks have mixed brace use.
[blender.git] / source / blender / windowmanager / intern / wm_playanim.c
index 3c7ae3e..cc364c2 100644 (file)
 
 #include "PIL_time.h"
 
+#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
 #include "BLI_listbase.h"
-#include "BLI_string.h"
 #include "BLI_path_util.h"
-#include "BLI_fileops.h"
 #include "BLI_rect.h"
+#include "BLI_string.h"
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
 #include "BKE_blender.h"
 #include "BKE_global.h"
-#include "BKE_utildefines.h"
+#include "BKE_image.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
-#ifdef WITH_QUICKTIME
-#  ifdef _WIN32
-#    include <QTML.h>
-#    include <Movies.h>
-#  elif defined(__APPLE__)
-#    include <QuickTime/Movies.h>
-#  endif /* __APPLE__ */
-#endif /* WITH_QUICKTIME */
-
 #include "DNA_scene_types.h"
-#include "BLI_utildefines.h"
 #include "ED_datafiles.h" /* for fonts */
-#include "wm_event_types.h"
 #include "GHOST_C-api.h"
 #include "BLF_api.h"
 
+#include "wm_event_types.h"
+
+#include "WM_api.h"  /* only for WM_main_playanim */
+
+struct PlayState;
+static void playanim_window_zoom(const struct PlayState *ps, const float zoom_offset);
 
 typedef struct PlayState {
 
        /* playback state */
        short direction;
-       short next;
+       short next_frame;
        short once;
        short turbo;
        short pingpong;
        short noskip;
        short sstep;
-       short pause;
        short wait2;
        short stopped;
        short go;
+       
+       int fstep;
 
        /* current picture */
        struct PlayAnimPict *picture;
@@ -106,6 +103,9 @@ typedef struct PlayState {
 
        /* saves passing args */
        struct ImBuf *curframe_ibuf;
+       
+       /* restarts player for file drop */
+       char dropped_file[FILE_MAX];
 } PlayState;
 
 /* for debugging */
@@ -138,6 +138,7 @@ typedef enum eWS_Qual {
        WS_QUAL_ALT     = (WS_QUAL_LALT | WS_QUAL_RALT),
        WS_QUAL_LCTRL   = (1 << 4),
        WS_QUAL_RCTRL   = (1 << 5),
+       WS_QUAL_CTRL    = (WS_QUAL_LCTRL | WS_QUAL_RCTRL),
        WS_QUAL_LMOUSE  = (1 << 16),
        WS_QUAL_MMOUSE  = (1 << 17),
        WS_QUAL_RMOUSE  = (1 << 18),
@@ -152,7 +153,7 @@ static struct WindowStateGlobal {
        eWS_Qual qual;
 } g_WS = {NULL};
 
-void playanim_window_get_size(int *width_r, int *height_r)
+static void playanim_window_get_size(int *width_r, int *height_r)
 {
        GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_WS.ghost_window);
        *width_r = GHOST_GetWidthRectangle(bounds);
@@ -185,27 +186,12 @@ static void playanim_event_qual_update(void)
 
        /* Alt */
        GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftAlt, &val);
-       if (val) g_WS.qual |=  WS_QUAL_LCTRL;
-       else     g_WS.qual &= ~WS_QUAL_LCTRL;
+       if (val) g_WS.qual |=  WS_QUAL_LALT;
+       else     g_WS.qual &= ~WS_QUAL_LALT;
 
        GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightAlt, &val);
-       if (val) g_WS.qual |=  WS_QUAL_RCTRL;
-       else     g_WS.qual &= ~WS_QUAL_RCTRL;
-
-       /* LMB */
-       GHOST_GetButtonState(g_WS.ghost_system, GHOST_kButtonMaskLeft, &val);
-       if (val) g_WS.qual |=  WS_QUAL_LMOUSE;
-       else     g_WS.qual &= ~WS_QUAL_LMOUSE;
-
-       /* MMB */
-       GHOST_GetButtonState(g_WS.ghost_system, GHOST_kButtonMaskMiddle, &val);
-       if (val) g_WS.qual |=  WS_QUAL_MMOUSE;
-       else     g_WS.qual &= ~WS_QUAL_MMOUSE;
-
-       /* RMB */
-       GHOST_GetButtonState(g_WS.ghost_system, GHOST_kButtonMaskRight, &val);
-       if (val) g_WS.qual |=  WS_QUAL_RMOUSE;
-       else     g_WS.qual &= ~WS_QUAL_RMOUSE;
+       if (val) g_WS.qual |=  WS_QUAL_RALT;
+       else     g_WS.qual &= ~WS_QUAL_RALT;
 }
 
 typedef struct PlayAnimPict {
@@ -221,10 +207,24 @@ typedef struct PlayAnimPict {
 
 static struct ListBase picsbase = {NULL, NULL};
 static int fromdisk = FALSE;
-static int fstep = 1;
 static float zoomx = 1.0, zoomy = 1.0;
 static double ptottime = 0.0, swaptime = 0.04;
 
+static PlayAnimPict *playanim_step(PlayAnimPict *playanim, int step)
+{
+       if (step > 0) {
+               while (step-- && playanim) {
+                       playanim = playanim->next;
+               }
+       }
+       else if (step < 0) {
+               while (step++ && playanim) {
+                       playanim = playanim->prev;
+               }
+       }
+       return playanim;
+}
+
 static int pupdate_time(void)
 {
        static double ltime;
@@ -237,11 +237,11 @@ static int pupdate_time(void)
        return (ptottime < 0);
 }
 
-static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fontid)
+static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fontid, int fstep)
 {
 
        if (ibuf == NULL) {
-               printf("no ibuf !\n");
+               printf("%s: no ibuf for picture '%s'\n", __func__, picture ? picture->name : "<NIL>");
                return;
        }
        if (ibuf->rect == NULL && ibuf->rect_float) {
@@ -255,8 +255,15 @@ static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fon
 
        glRasterPos2f(0.0f, 0.0f);
 
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+       fdrawcheckerboard(0.0f, 0.0f, ibuf->x, ibuf->y);
+
        glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
 
+       glDisable(GL_BLEND);
+
        pupdate_time();
 
        if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {
@@ -289,12 +296,13 @@ static void build_pict_list(char *first, int totframes, int fstep, int fontid)
        struct anim *anim;
 
        if (IMB_isanim(first)) {
-               anim = IMB_open_anim(first, IB_rect, 0);
+               /* OCIO_TODO: support different input color space */
+               anim = IMB_open_anim(first, IB_rect, 0, NULL);
                if (anim) {
                        int pic;
                        ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
                        if (ibuf) {
-                               playanim_toscreen(NULL, ibuf, fontid);
+                               playanim_toscreen(NULL, ibuf, fontid, fstep);
                                IMB_freeImBuf(ibuf);
                        }
 
@@ -336,7 +344,11 @@ static void build_pict_list(char *first, int totframes, int fstep, int fontid)
                        int file;
 
                        file = open(filepath, O_BINARY | O_RDONLY, 0);
-                       if (file < 0) return;
+                       if (file < 0) {
+                               /* print errno? */
+                               return;
+                       }
+
                        picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture");
                        if (picture == NULL) {
                                printf("Not enough memory for pict struct '%s'\n", filepath);
@@ -384,15 +396,16 @@ static void build_pict_list(char *first, int totframes, int fstep, int fontid)
                        pupdate_time();
 
                        if (ptottime > 1.0) {
+                               /* OCIO_TODO: support different input color space */
                                if (picture->mem) {
                                        ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size,
-                                                                    picture->IB_flags, picture->name);
+                                                                    picture->IB_flags, NULL, picture->name);
                                }
                                else {
-                                       ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
+                                       ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL);
                                }
                                if (ibuf) {
-                                       playanim_toscreen(picture, ibuf, fontid);
+                                       playanim_toscreen(picture, ibuf, fontid, fstep);
                                        IMB_freeImBuf(ibuf);
                                }
                                pupdate_time();
@@ -433,6 +446,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                ps->stopped = FALSE;
        }
 
+       if (ps->wait2) {
+               pupdate_time();
+               ptottime = 0;
+       }
+
        switch (type) {
                case GHOST_kEventKeyDown:
                case GHOST_kEventKeyUp:
@@ -447,35 +465,44 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                case GHOST_kKeyP:
                                        if (val) ps->pingpong = !ps->pingpong;
                                        break;
+                               case GHOST_kKey1:
                                case GHOST_kKeyNumpad1:
-                                       if (val) swaptime = fstep / 60.0;
+                                       if (val) swaptime = ps->fstep / 60.0;
                                        break;
+                               case GHOST_kKey2:
                                case GHOST_kKeyNumpad2:
-                                       if (val) swaptime = fstep / 50.0;
+                                       if (val) swaptime = ps->fstep / 50.0;
                                        break;
+                               case GHOST_kKey3:
                                case GHOST_kKeyNumpad3:
-                                       if (val) swaptime = fstep / 30.0;
+                                       if (val) swaptime = ps->fstep / 30.0;
                                        break;
+                               case GHOST_kKey4:
                                case GHOST_kKeyNumpad4:
                                        if (g_WS.qual & WS_QUAL_SHIFT)
-                                               swaptime = fstep / 24.0;
+                                               swaptime = ps->fstep / 24.0;
                                        else
-                                               swaptime = fstep / 25.0;
+                                               swaptime = ps->fstep / 25.0;
                                        break;
+                               case GHOST_kKey5:
                                case GHOST_kKeyNumpad5:
-                                       if (val) swaptime = fstep / 20.0;
+                                       if (val) swaptime = ps->fstep / 20.0;
                                        break;
+                               case GHOST_kKey6:
                                case GHOST_kKeyNumpad6:
-                                       if (val) swaptime = fstep / 15.0;
+                                       if (val) swaptime = ps->fstep / 15.0;
                                        break;
+                               case GHOST_kKey7:
                                case GHOST_kKeyNumpad7:
-                                       if (val) swaptime = fstep / 12.0;
+                                       if (val) swaptime = ps->fstep / 12.0;
                                        break;
+                               case GHOST_kKey8:
                                case GHOST_kKeyNumpad8:
-                                       if (val) swaptime = fstep / 10.0;
+                                       if (val) swaptime = ps->fstep / 10.0;
                                        break;
+                               case GHOST_kKey9:
                                case GHOST_kKeyNumpad9:
-                                       if (val) swaptime = fstep / 6.0;
+                                       if (val) swaptime = ps->fstep / 6.0;
                                        break;
                                case GHOST_kKeyLeftArrow:
                                        if (val) {
@@ -483,10 +510,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                                ps->wait2 = FALSE;
                                                if (g_WS.qual & WS_QUAL_SHIFT) {
                                                        ps->picture = picsbase.first;
-                                                       ps->next = 0;
+                                                       ps->next_frame = 0;
                                                }
                                                else {
-                                                       ps->next = -1;
+                                                       ps->next_frame = -1;
                                                }
                                        }
                                        break;
@@ -494,10 +521,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                        if (val) {
                                                ps->wait2 = FALSE;
                                                if (g_WS.qual & WS_QUAL_SHIFT) {
-                                                       ps->next = ps->direction = -1;
+                                                       ps->next_frame = ps->direction = -1;
                                                }
                                                else {
-                                                       ps->next = -10;
+                                                       ps->next_frame = -10;
                                                        ps->sstep = TRUE;
                                                }
                                        }
@@ -508,10 +535,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                                ps->wait2 = FALSE;
                                                if (g_WS.qual & WS_QUAL_SHIFT) {
                                                        ps->picture = picsbase.last;
-                                                       ps->next = 0;
+                                                       ps->next_frame = 0;
                                                }
                                                else {
-                                                       ps->next = 1;
+                                                       ps->next_frame = 1;
                                                }
                                        }
                                        break;
@@ -519,10 +546,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                        if (val) {
                                                ps->wait2 = FALSE;
                                                if (g_WS.qual & WS_QUAL_SHIFT) {
-                                                       ps->next = ps->direction = 1;
+                                                       ps->next_frame = ps->direction = 1;
                                                }
                                                else {
-                                                       ps->next = 10;
+                                                       ps->next_frame = 10;
                                                        ps->sstep = TRUE;
                                                }
                                        }
@@ -533,35 +560,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                        if (val) {
                                                if (g_WS.qual & WS_QUAL_SHIFT) {
                                                        if (ps->curframe_ibuf)
-                                                               printf(" Name: %s | Speed: %.2f frames/s\n", ps->curframe_ibuf->name, fstep / swaptime);
+                                                               printf(" Name: %s | Speed: %.2f frames/s\n",
+                                                                      ps->curframe_ibuf->name, ps->fstep / swaptime);
                                                }
                                                else {
-                                                       swaptime = fstep / 5.0;
-                                               }
-                                       }
-                                       break;
-                               case GHOST_kKeyEqual:
-                                       if (val) {
-                                               if (g_WS.qual & WS_QUAL_SHIFT) {
-                                                       ps->pause++;
-                                                       printf("pause:%d\n", ps->pause);
-                                               }
-                                               else {
-                                                       swaptime /= 1.1;
-                                               }
-                                       }
-                                       break;
-                               case GHOST_kKeyMinus:
-                                       if (val) {
-                                               if (g_WS.qual & WS_QUAL_SHIFT) {
-                                                       ps->pause--;
-                                                       printf("pause:%d\n", ps->pause);
-                                               }
-                                               else {
-                                                       swaptime *= 1.1;
+                                                       swaptime = ps->fstep / 5.0;
                                                }
                                        }
                                        break;
+                               case GHOST_kKey0:
                                case GHOST_kKeyNumpad0:
                                        if (val) {
                                                if (ps->once) {
@@ -580,38 +587,40 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                                ps->wait2 = ps->sstep = FALSE;
                                        }
                                        break;
+                               case GHOST_kKeyPeriod:
                                case GHOST_kKeyNumpadPeriod:
                                        if (val) {
-                                               if (ps->sstep) ps->wait2 = FALSE;
+                                               if (ps->sstep) {
+                                                       ps->wait2 = FALSE;
+                                               }
                                                else {
                                                        ps->sstep = TRUE;
                                                        ps->wait2 = !ps->wait2;
                                                }
                                        }
                                        break;
+                               case GHOST_kKeyEqual:
                                case GHOST_kKeyNumpadPlus:
+                               {
                                        if (val == 0) break;
-                                       zoomx += 2.0;
-                                       zoomy += 2.0;
-                                       /* no break??? - is this intentional? - campbell XXX25 */
+                                       if (g_WS.qual & WS_QUAL_CTRL) {
+                                               playanim_window_zoom(ps, 1.0f);
+                                       }
+                                       else {
+                                               swaptime /= 1.1;
+                                       }
+                                       break;
+                               }
+                               case GHOST_kKeyMinus:
                                case GHOST_kKeyNumpadMinus:
                                {
-                                       int sizex, sizey;
-                                       /* int ofsx, ofsy; */ /* UNUSED */
-
                                        if (val == 0) break;
-                                       if (zoomx > 1.0) zoomx -= 1.0;
-                                       if (zoomy > 1.0) zoomy -= 1.0;
-                                       // playanim_window_get_position(&ofsx, &ofsy);
-                                       playanim_window_get_size(&sizex, &sizey);
-                                       /* ofsx += sizex / 2; */ /* UNUSED */
-                                       /* ofsy += sizey / 2; */ /* UNUSED */
-                                       sizex = zoomx * ps->ibufx;
-                                       sizey = zoomy * ps->ibufy;
-                                       /* ofsx -= sizex / 2; */ /* UNUSED */
-                                       /* ofsy -= sizey / 2; */ /* UNUSED */
-                                       // window_set_position(g_WS.ghost_window,sizex,sizey);
-                                       GHOST_SetClientSize(g_WS.ghost_window, sizex, sizey);
+                                       if (g_WS.qual & WS_QUAL_CTRL) {
+                                               playanim_window_zoom(ps, -1.0f);
+                                       }
+                                       else {
+                                               swaptime *= 1.1;
+                                       }
                                        break;
                                }
                                case GHOST_kKeyEsc:
@@ -622,6 +631,44 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                        }
                        break;
                }
+               case GHOST_kEventButtonDown:
+               case GHOST_kEventButtonUp:
+               {
+                       GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
+                       int cx, cy, sizex, sizey, inside_window;
+                       
+                       GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy);
+                       GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy);
+                       playanim_window_get_size(&sizex, &sizey);
+
+                       inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
+                       
+                       if (bd->button == GHOST_kButtonMaskLeft) {
+                               if (type == GHOST_kEventButtonDown) {
+                                       if (inside_window)
+                                               g_WS.qual |= WS_QUAL_LMOUSE;
+                               }
+                               else
+                                       g_WS.qual &= ~WS_QUAL_LMOUSE;
+                       }
+                       else if (bd->button == GHOST_kButtonMaskMiddle) {
+                               if (type == GHOST_kEventButtonDown) {
+                                       if (inside_window)
+                                               g_WS.qual |= WS_QUAL_MMOUSE;
+                               }
+                               else
+                                       g_WS.qual &= ~WS_QUAL_MMOUSE;
+                       }
+                       else if (bd->button == GHOST_kButtonMaskRight) {
+                               if (type == GHOST_kEventButtonDown) {
+                                       if (inside_window)
+                                               g_WS.qual |= WS_QUAL_RMOUSE;
+                               }
+                               else
+                                       g_WS.qual &= ~WS_QUAL_RMOUSE;
+                       }
+                       break;
+               }
                case GHOST_kEventCursorMove:
                {
                        if (g_WS.qual & WS_QUAL_LMOUSE) {
@@ -649,10 +696,16 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                                }
                                ps->sstep = TRUE;
                                ps->wait2 = FALSE;
-                               ps->next = 0;
+                               ps->next_frame = 0;
                        }
                        break;
                }
+               case GHOST_kEventWindowActivate:
+               case GHOST_kEventWindowDeactivate:
+               {
+                       g_WS.qual &= ~WS_QUAL_MOUSE;
+                       break;
+               }
                case GHOST_kEventWindowSize:
                case GHOST_kEventWindowMove:
                {
@@ -666,10 +719,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
 
                        zoomx = (float) sizex / ps->ibufx;
                        zoomy = (float) sizey / ps->ibufy;
-                       zoomx = floor(zoomx + 0.5);
-                       zoomy = floor(zoomy + 0.5);
-                       if (zoomx < 1.0) zoomx = 1.0;
-                       if (zoomy < 1.0) zoomy = 1.0;
+                       zoomx = floor(zoomx + 0.5f);
+                       zoomy = floor(zoomy + 0.5f);
+                       if (zoomx < 1.0f) zoomx = 1.0f;
+                       if (zoomy < 1.0f) zoomy = 1.0f;
 
                        sizex = zoomx * ps->ibufx;
                        sizey = zoomy * ps->ibufy;
@@ -677,7 +730,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                        glPixelZoom(zoomx, zoomy);
                        glEnable(GL_DITHER);
                        ptottime = 0.0;
-                       playanim_toscreen(ps->picture, ps->curframe_ibuf, ps->fontid);
+                       playanim_toscreen(ps->picture, ps->curframe_ibuf, ps->fontid, ps->fstep);
 
                        break;
                }
@@ -687,6 +740,23 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
                        ps->go = FALSE;
                        break;
                }
+               case GHOST_kEventDraggingDropDone:
+               {
+                       GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
+                       
+                       if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
+                               GHOST_TStringArray *stra = ddd->data;
+                               int a;
+                               
+                               for (a = 0; a < stra->count; a++) {
+                                       BLI_strncpy(ps->dropped_file, (char *)stra->strings[a], sizeof(ps->dropped_file));
+                                       ps->go = FALSE;
+                                       printf("drop file %s\n", stra->strings[a]);
+                                       break; /* only one drop element supported now */
+                               }
+                       }
+                       break;
+               }
                default:
                        /* quiet warnings */
                        break;
@@ -695,7 +765,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
        return 1;
 }
 
-void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
+static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
 {
        GHOST_TWindowState inital_state;
        GHOST_TUns32 scr_w, scr_h;
@@ -708,36 +778,41 @@ void playanim_window_open(const char *title, int posx, int posy, int sizex, int
                inital_state = start_maximized ? GHOST_kWindowStateFullScreen : GHOST_kWindowStateNormal;
        else
                inital_state = start_maximized ? GHOST_kWindowStateMaximized : GHOST_kWindowStateNormal;
-#if defined(__APPLE__) && !defined(GHOST_COCOA)
-       {
-               extern int macPrefState; /* creator.c */
-               initial_state += macPrefState;
-       }
-#endif
 
        g_WS.ghost_window = GHOST_CreateWindow(g_WS.ghost_system,
-                                     title,
-                                     posx, posy, sizex, sizey,
-                                     inital_state,
-                                     GHOST_kDrawingContextTypeOpenGL,
-                                     FALSE /* no stereo */, FALSE);
-
-       //if (ghostwin) {
-       //if (win) {
-       // GHOST_SetWindowUserData(ghostwin, win);
-       //} else {
-       //      GHOST_DisposeWindow(g_WS.ghost_system, ghostwin);
-       //}
-       //}
+                                              title,
+                                              posx, posy, sizex, sizey,
+                                              inital_state,
+                                              GHOST_kDrawingContextTypeOpenGL,
+                                              FALSE /* no stereo */, FALSE);
 }
 
+static void playanim_window_zoom(const PlayState *ps, const float zoom_offset)
+{
+       int sizex, sizey;
+       /* int ofsx, ofsy; */ /* UNUSED */
+
+       if (zoomx + zoom_offset > 0.0f) zoomx += zoom_offset;
+       if (zoomy + zoom_offset > 0.0f) zoomy += zoom_offset;
+
+       // playanim_window_get_position(&ofsx, &ofsy);
+       playanim_window_get_size(&sizex, &sizey);
+       /* ofsx += sizex / 2; */ /* UNUSED */
+       /* ofsy += sizey / 2; */ /* UNUSED */
+       sizex = zoomx * ps->ibufx;
+       sizey = zoomy * ps->ibufy;
+       /* ofsx -= sizex / 2; */ /* UNUSED */
+       /* ofsy -= sizey / 2; */ /* UNUSED */
+       // window_set_position(g_WS.ghost_window,sizex,sizey);
+       GHOST_SetClientSize(g_WS.ghost_window, sizex, sizey);
+}
 
-void playanim(int argc, const char **argv)
+/* return path for restart */
+static char *wm_main_playanim_intern(int argc, const char **argv)
 {
        struct ImBuf *ibuf = NULL;
-       char filepath[FILE_MAX];
+       static char filepath[FILE_MAX]; /* abused to return dropped file path */
        GHOST_TUns32 maxwinx, maxwiny;
-       /* short c233 = FALSE, yuvx = FALSE; */ /* UNUSED */
        int i;
        /* This was done to disambiguate the name for use under c++. */
        struct anim *anim = NULL;
@@ -745,24 +820,26 @@ void playanim(int argc, const char **argv)
        int sfra = -1;
        int efra = -1;
        int totblock;
-
+       
        PlayState ps = {0};
 
        /* ps.doubleb   = TRUE;*/ /* UNUSED */
        ps.go        = TRUE;
        ps.direction = TRUE;
-       ps.next      = TRUE;
+       ps.next_frame = 1;
        ps.once      = FALSE;
        ps.turbo     = FALSE;
        ps.pingpong  = FALSE;
        ps.noskip    = FALSE;
        ps.sstep     = FALSE;
-       ps.pause     = FALSE;
        ps.wait2     = FALSE;
        ps.stopped   = FALSE;
        ps.picture   = NULL;
+       ps.dropped_file[0] = 0;
        /* resetmap = FALSE */
 
+       ps.fstep     = 1;
+
        ps.fontid = -1;
 
        while (argc > 1) {
@@ -810,8 +887,8 @@ void playanim(int argc, const char **argv)
                                        argv++;
                                        break;
                                case 'j':
-                                       fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
-                                       swaptime *= fstep;
+                                       ps.fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
+                                       swaptime *= ps.fstep;
                                        argc--;
                                        argv++;
                                        break;
@@ -827,26 +904,6 @@ void playanim(int argc, const char **argv)
                }
        }
 
-#ifdef WITH_QUICKTIME
-#if defined(_WIN32) || defined(__APPLE__) && !defined(GHOST_COCOA)
-       /* Initialize QuickTime */
-#ifndef noErr
-#define noErr 0
-#endif
-
-#ifdef _WIN32
-       if (InitializeQTML(0) != noErr)
-               G.have_quicktime = FALSE;
-       else
-               G.have_quicktime = TRUE;
-#endif /* _WIN32 */
-       if (EnterMovies() != noErr)
-               G.have_quicktime = FALSE;
-       else
-#endif /* _WIN32 || __APPLE__  && !defined(GHOST_COCOA)*/
-       G.have_quicktime = TRUE;
-#endif /* WITH_QUICKTIME */
-
        if (argc > 1) {
                BLI_strncpy(filepath, argv[1], sizeof(filepath));
        }
@@ -856,7 +913,8 @@ void playanim(int argc, const char **argv)
        }
 
        if (IMB_isanim(filepath)) {
-               anim = IMB_open_anim(filepath, IB_rect, 0);
+               /* OCIO_TODO: support different input color spaces */
+               anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
                if (anim) {
                        ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
                        IMB_close_anim(anim);
@@ -868,7 +926,8 @@ void playanim(int argc, const char **argv)
        }
 
        if (ibuf == NULL) {
-               ibuf = IMB_loadiffname(filepath, IB_rect);
+               /* OCIO_TODO: support different input color space */
+               ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
        }
 
        if (ibuf == NULL) {
@@ -928,11 +987,11 @@ void playanim(int argc, const char **argv)
                efra = MAXFRAME;
        }
 
-       build_pict_list(filepath, (efra - sfra) + 1, fstep, ps.fontid);
+       build_pict_list(filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
 
        for (i = 2; i < argc; i++) {
                BLI_strncpy(filepath, argv[i], sizeof(filepath));
-               build_pict_list(filepath, (efra - sfra) + 1, fstep, ps.fontid);
+               build_pict_list(filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
        }
 
        IMB_freeImBuf(ibuf);
@@ -941,6 +1000,9 @@ void playanim(int argc, const char **argv)
        pupdate_time();
        ptottime = 0;
 
+       /* newly added in 2.6x, without this images never get freed */
+#define USE_IMB_CACHE
+
        while (ps.go) {
                if (ps.pingpong)
                        ps.direction = -ps.direction;
@@ -967,8 +1029,10 @@ void playanim(int argc, const char **argv)
                if (ptottime > 0.0) ptottime = 0.0;
 
                while (ps.picture) {
+                       int hasevent;
+#ifndef USE_IMB_CACHE
                        if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
-
+#endif
                        if (ps.picture->ibuf) {
                                ibuf = ps.picture->ibuf;
                        }
@@ -976,14 +1040,21 @@ void playanim(int argc, const char **argv)
                                ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
                        }
                        else if (ps.picture->mem) {
+                               /* use correct colorspace here */
                                ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
-                                                            ps.picture->IB_flags, ps.picture->name);
+                                                            ps.picture->IB_flags, NULL, ps.picture->name);
                        }
                        else {
-                               ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags);
+                               /* use correct colorspace here */
+                               ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags, NULL);
                        }
 
                        if (ibuf) {
+
+#ifdef USE_IMB_CACHE
+                               ps.picture->ibuf = ibuf;
+#endif
+
                                BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));
 
                                /* why only windows? (from 2.4x) - campbell */
@@ -993,7 +1064,7 @@ void playanim(int argc, const char **argv)
 
                                while (pupdate_time()) PIL_sleep_ms(1);
                                ptottime -= swaptime;
-                               playanim_toscreen(ps.picture, ibuf, ps.fontid);
+                               playanim_toscreen(ps.picture, ibuf, ps.fontid, ps.fstep);
                        } /* else deleten */
                        else {
                                printf("error: can't play this image type\n");
@@ -1009,22 +1080,25 @@ void playanim(int argc, const char **argv)
                                }
                        }
 
-                       ps.next = ps.direction;
+                       ps.next_frame = ps.direction;
 
 
-                       {
-                               int hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0);
+                       while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0) || ps.wait2 != 0)) {
                                if (hasevent) {
                                        GHOST_DispatchEvents(g_WS.ghost_system);
                                }
-                       }
-
-                       /* XXX25 - we should not have to do this, but it makes scrubbing functional! */
-                       if (g_WS.qual & WS_QUAL_LMOUSE) {
-                               ps.next = 0;
-                       }
-                       else {
-                               ps.sstep = 0;
+                               if (ps.wait2) {
+                                       if (hasevent) {
+                                               if (ibuf) {
+                                                       while (pupdate_time()) PIL_sleep_ms(1);
+                                                       ptottime -= swaptime;
+                                                       playanim_toscreen(ps.picture, ibuf, ps.fontid, ps.fstep);
+                                               }
+                                       }
+                               }
+                               if (!ps.go) {
+                                       break;
+                               }
                        }
 
                        ps.wait2 = ps.sstep;
@@ -1035,15 +1109,10 @@ void playanim(int argc, const char **argv)
 
                        pupdate_time();
 
-                       if (ps.picture && ps.next) {
+                       if (ps.picture && ps.next_frame) {
                                /* always at least set one step */
                                while (ps.picture) {
-                                       if (ps.next < 0) {
-                                               ps.picture = ps.picture->prev;
-                                       }
-                                       else {
-                                               ps.picture = ps.picture->next;
-                                       }
+                                       ps.picture = playanim_step(ps.picture, ps.next_frame);
 
                                        if (ps.once && ps.picture != NULL) {
                                                if (ps.picture->next == NULL) {
@@ -1058,12 +1127,7 @@ void playanim(int argc, const char **argv)
                                        ptottime -= swaptime;
                                }
                                if (ps.picture == NULL && ps.sstep) {
-                                       if (ps.next < 0) {
-                                               ps.picture = picsbase.last;
-                                       }
-                                       else if (ps.next > 0) {
-                                               ps.picture = picsbase.first;
-                                       }
+                                       ps.picture = playanim_step(ps.picture, ps.next_frame);
                                }
                        }
                        if (ps.go == FALSE) {
@@ -1089,33 +1153,59 @@ void playanim(int argc, const char **argv)
 
                ps.picture = ps.picture->next;
        }
-#ifdef WITH_QUICKTIME
-#if defined(_WIN32) || defined(__APPLE__) && !defined(GHOST_COCOA)
-       if (G.have_quicktime) {
-               ExitMovies();
-#ifdef _WIN32
-               TerminateQTML();
-#endif /* _WIN32 */
-       }
-#endif /* _WIN32 || __APPLE__ && !defined(GHOST_COCOA) */
-#endif /* WITH_QUICKTIME */
 
        /* cleanup */
+#ifndef USE_IMB_CACHE
        if (ibuf) IMB_freeImBuf(ibuf);
+#endif
+
        BLI_freelistN(&picsbase);
 #if 0 // XXX25
        free_blender();
 #else
        /* we still miss freeing a lot!,
         * but many areas could skip initialization too for anim play */
-       IMB_exit();
+       
        BLF_exit();
 #endif
        GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
 
+       /* early exit, IMB and BKE should be exited only in end */
+       if (ps.dropped_file) {
+               BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
+               return filepath;
+       }
+       
+       IMB_exit();
+       BKE_images_exit();
+
        totblock = MEM_get_memory_blocks_in_use();
        if (totblock != 0) {
+               /* prints many bAKey, bArgument's which are tricky to fix */
+#if 0
                printf("Error Totblock: %d\n", totblock);
                MEM_printmemlist();
+#endif
+       }
+       
+       return NULL;
+}
+
+
+void WM_main_playanim(int argc, const char **argv)
+{
+       bool looping = true;
+
+       while (looping) {
+               char *filepath = wm_main_playanim_intern(argc, argv);
+
+               if (filepath) { /* use simple args */
+                       argv[1] = "-a";
+                       argv[2] = filepath;
+                       argc = 3;
+               }
+               else {
+                       looping = false;
+               }
        }
 }