Color Management, Stage 2: Switch color pipeline to use OpenColorIO
[blender.git] / source / blender / windowmanager / intern / wm_playanim.c
index a8263e8e38df14c7ee0c1cea67efe5a69d051458..bff40faf1d1cbc87de73f98858a37107712cc801 100644 (file)
@@ -1,7 +1,4 @@
-#if 0
-/**
- * $Id: playanim.c 17755 2008-12-09 04:57:42Z bdiego $
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): none yet.
+ * Contributor(s): Campbell Barton
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/windowmanager/intern/wm_playanim.c
+ *  \ingroup wm
+ *
+ * \note This file uses ghost directly and none of the WM definitions.
+ *       this could be made into its own module, alongside creator/
+ */
+
 #include <sys/types.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <math.h>
 
 #ifndef WIN32
-#include <unistd.h>
-#include <sys/times.h>
-#include <sys/wait.h>
+#  include <unistd.h>
+#  include <sys/times.h>
+#  include <sys/wait.h>
 #else
-#include <io.h>
-#endif   
+#  include <io.h>
+#endif
 #include "MEM_guardedalloc.h"
 
 #include "PIL_time.h"
 
-#include <math.h>
-
-#include "BLI_blenlib.h"
-#include "BLI_arithb.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
-#include "BDR_editcurve.h"
-
 #include "BKE_blender.h"
 #include "BKE_global.h"
-#include "BKE_utildefines.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
-#include "BIF_screen.h"
-#include "BIF_mywindow.h"
 
-#include "BMF_Api.h"
+#include "DNA_scene_types.h"
+#include "ED_datafiles.h" /* for fonts */
+#include "GHOST_C-api.h"
+#include "BLF_api.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 "playanim_ext.h"
-#include "mydevice.h"
-#include "blendef.h"
-#include "winlay.h"
-
-/* ***************** gl_util.c ****************** */
-
-static Window *g_window = NULL;
-static int qualN = 0;
-
-#define LSHIFT (1<<0)
-#define RSHIFT (1<<1)
-#define SHIFT  (LSHIFT | RSHIFT)
-#define LALT   (1<<2)
-#define RALT   (1<<3)
-#define ALT    (LALT | RALT)
-#define LCTRL  (1<<4)
-#define RCTRL  (1<<5)
-#define LMOUSE (1<<16)
-#define MMOUSE (1<<17)
-#define RMOUSE (1<<18)
-#define MOUSE  (LMOUSE | MMOUSE | RMOUSE)
-
-unsigned short screen_qread(short *val, char *ascii);
+#include "wm_event_types.h"
 
-/* implementation */
-static int qreadN(short *val)
+#include "WM_api.h"  /* only for WM_main_playanim */
+
+typedef struct PlayState {
+
+       /* playback state */
+       short direction;
+       short next;
+       short once;
+       short turbo;
+       short pingpong;
+       short noskip;
+       short sstep;
+       short pause;
+       short wait2;
+       short stopped;
+       short go;
+
+       /* current picture */
+       struct PlayAnimPict *picture;
+
+       /* set once at the start */
+       int ibufx, ibufy;
+       int fontid;
+
+       /* saves passing args */
+       struct ImBuf *curframe_ibuf;
+} PlayState;
+
+/* for debugging */
+#if 0
+void print_ps(PlayState *ps)
 {
-       char ascii;
-       int event = screen_qread(val, &ascii);
-
-       switch(event){
-       case LEFTMOUSE:
-               if (*val) qualN |= LMOUSE;
-               else qualN &= ~LMOUSE;
-               break;
-       case MIDDLEMOUSE:
-               if (*val) qualN |= MMOUSE;
-               else qualN &= ~MMOUSE;
-               break;
-       case RIGHTMOUSE:
-               if (*val) qualN |= RMOUSE;
-               else qualN &= ~RMOUSE;
-               break;
-       case LEFTSHIFTKEY:
-               if (*val) qualN |= LSHIFT;
-               else qualN &= ~LSHIFT;
-               break;
-       case RIGHTSHIFTKEY:
-               if (*val) qualN |= RSHIFT;
-               else qualN &= ~RSHIFT;
-               break;
-       case LEFTCTRLKEY:
-               if (*val) qualN |= LCTRL;
-               else qualN &= ~LCTRL;
-               break;
-       case RIGHTCTRLKEY:
-               if (*val) qualN |= RCTRL;
-               else qualN &= ~RCTRL;
-               break;
-       case LEFTALTKEY:
-               if (*val) qualN |= LALT;
-               else qualN &= ~LALT;
-               break;
-       case RIGHTALTKEY:
-               if (*val) qualN |= RALT;
-               else qualN &= ~RALT;
-               break;
-       }
+       printf("ps:\n");
+       printf("    direction=%d,\n", (int)ps->direction);
+       printf("    next=%d,\n", ps->next);
+       printf("    once=%d,\n", ps->once);
+       printf("    turbo=%d,\n", ps->turbo);
+       printf("    pingpong=%d,\n", ps->pingpong);
+       printf("    noskip=%d,\n", ps->noskip);
+       printf("    sstep=%d,\n", ps->sstep);
+       printf("    pause=%d,\n", ps->pause);
+       printf("    wait2=%d,\n", ps->wait2);
+       printf("    stopped=%d,\n", ps->stopped);
+       printf("    go=%d,\n\n", ps->go);
+       fflush(stdout);
+}
+#endif
+
+/* global for window and events */
+typedef enum eWS_Qual {
+       WS_QUAL_LSHIFT  = (1 << 0),
+       WS_QUAL_RSHIFT  = (1 << 1),
+       WS_QUAL_SHIFT   = (WS_QUAL_LSHIFT | WS_QUAL_RSHIFT),
+       WS_QUAL_LALT    = (1 << 2),
+       WS_QUAL_RALT    = (1 << 3),
+       WS_QUAL_ALT     = (WS_QUAL_LALT | WS_QUAL_RALT),
+       WS_QUAL_LCTRL   = (1 << 4),
+       WS_QUAL_RCTRL   = (1 << 5),
+       WS_QUAL_LMOUSE  = (1 << 16),
+       WS_QUAL_MMOUSE  = (1 << 17),
+       WS_QUAL_RMOUSE  = (1 << 18),
+       WS_QUAL_MOUSE   = (WS_QUAL_LMOUSE | WS_QUAL_MMOUSE | WS_QUAL_RMOUSE)
+} eWS_Qual;
+
+static struct WindowStateGlobal {
+       GHOST_SystemHandle ghost_system;
+       void *ghost_window;
+
+       /* events */
+       eWS_Qual qual;
+} g_WS = {NULL};
 
-       return(event);
+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);
+       *height_r = GHOST_GetHeightRectangle(bounds);
+       GHOST_DisposeRectangle(bounds);
 }
 
-/* ***************** gl_util.c ****************** */
+/* implementation */
+static void playanim_event_qual_update(void)
+{
+       int val;
+
+       /* Shift */
+       GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val);
+       if (val) g_WS.qual |=  WS_QUAL_LSHIFT;
+       else     g_WS.qual &= ~WS_QUAL_LSHIFT;
+
+       GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightShift, &val);
+       if (val) g_WS.qual |=  WS_QUAL_RSHIFT;
+       else     g_WS.qual &= ~WS_QUAL_RSHIFT;
 
+       /* Control */
+       GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftControl, &val);
+       if (val) g_WS.qual |=  WS_QUAL_LCTRL;
+       else     g_WS.qual &= ~WS_QUAL_LCTRL;
 
+       GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightControl, &val);
+       if (val) g_WS.qual |=  WS_QUAL_RCTRL;
+       else     g_WS.qual &= ~WS_QUAL_RCTRL;
 
+       /* 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;
 
-typedef struct pict{
-       struct pict *next, *prev;
+       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;
+}
+
+typedef struct PlayAnimPict {
+       struct PlayAnimPict *next, *prev;
        char *mem;
        int size;
        char *name;
@@ -165,13 +209,12 @@ typedef struct pict{
        struct anim *anim;
        int frame;
        int IB_flags;
-}Pict;
+} PlayAnimPict;
 
-static struct ListBase _picsbase = {0,0};
-static struct ListBase *picsbase = &_picsbase;
+static struct ListBase picsbase = {NULL, NULL};
 static int fromdisk = FALSE;
-static int fstep = 1; 
-static float zoomx = 1.0 , zoomy = 1.0;
+static int fstep = 1;
+static float zoomx = 1.0, zoomy = 1.0;
 static double ptottime = 0.0, swaptime = 0.04;
 
 static int pupdate_time(void)
@@ -186,97 +229,118 @@ static int pupdate_time(void)
        return (ptottime < 0);
 }
 
-static void toscreen(Pict *picture, struct ImBuf *ibuf)
+static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fontid)
 {
-       
-       if (ibuf == 0){
+
+       if (ibuf == NULL) {
                printf("no ibuf !\n");
                return;
        }
-       if (ibuf->rect==NULL && ibuf->rect_float) {
+       if (ibuf->rect == NULL && ibuf->rect_float) {
                IMB_rect_from_float(ibuf);
                imb_freerectfloatImBuf(ibuf);
        }
-       if (ibuf->rect==NULL)
+       if (ibuf->rect == NULL)
                return;
 
+       GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+
        glRasterPos2f(0.0f, 0.0f);
 
        glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
-       
+
        pupdate_time();
 
-       if(picture && (qualN & (SHIFT|LMOUSE))) {
-               char str[512];
+       if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {
+               int sizex, sizey;
+               float fsizex_inv, fsizey_inv;
+               char str[32 + FILE_MAX];
                cpack(-1);
-               glRasterPos2f(0.02f,  0.03f);
-               sprintf(str, "%s | %.2f frames/s\n", picture->name, fstep / swaptime);
-               BMF_DrawString(G.fonts, str);
+               BLI_snprintf(str, sizeof(str), "%s | %.2f frames/s", picture->name, fstep / swaptime);
+
+               playanim_window_get_size(&sizex, &sizey);
+               fsizex_inv = 1.0f / sizex;
+               fsizey_inv = 1.0f / sizey;
+
+               BLF_enable(fontid, BLF_ASPECT);
+               BLF_aspect(fontid, fsizex_inv, fsizey_inv, 1.0f);
+               BLF_position(fontid, 10.0f * fsizex_inv, 10.0f * fsizey_inv, 0.0f);
+               BLF_draw(fontid, str, sizeof(str));
        }
-       
-       window_swap_buffers(g_window);
+
+       GHOST_SwapWindowBuffers(g_WS.ghost_window);
 }
 
-static void build_pict_list(char * first, int totframes, int fstep)
+static void build_pict_list(char *first, int totframes, int fstep, int fontid)
 {
-       int size,pic,file;
-       char *mem, name[512];
-       short val;
-       struct pict * picture = 0;
-       struct ImBuf *ibuf = 0;
-       int count = 0;
-       char str[512];
-       struct anim * anim;
-       
+       char *mem, filepath[FILE_MAX];
+//     short val;
+       PlayAnimPict *picture = NULL;
+       struct ImBuf *ibuf = NULL;
+       char str[32 + FILE_MAX];
+       struct anim *anim;
+
        if (IMB_isanim(first)) {
-               anim = IMB_open_anim(first, IB_rect);
+               /* OCIO_TODO: support different input color space */
+               anim = IMB_open_anim(first, IB_rect, 0, NULL);
                if (anim) {
-                       ibuf = IMB_anim_absolute(anim, 0);
+                       int pic;
+                       ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
                        if (ibuf) {
-                               toscreen(NULL, ibuf);
+                               playanim_toscreen(NULL, ibuf, fontid);
                                IMB_freeImBuf(ibuf);
                        }
-                       
-                       for (pic = 0; pic < IMB_anim_get_duration(anim); pic ++) {
-                               picture = (Pict*)MEM_callocN(sizeof(Pict),"Pict");
+
+                       for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
+                               picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict");
                                picture->anim = anim;
                                picture->frame = pic;
                                picture->IB_flags = IB_rect;
-                               sprintf(str, "%s : %d", first, pic + 1);
+                               BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
                                picture->name = strdup(str);
-                               BLI_addtail(picsbase, picture);
+                               BLI_addtail(&picsbase, picture);
                        }
-               } 
-               else printf("couldn't open anim %s\n", first);
-       } 
+               }
+               else {
+                       printf("couldn't open anim %s\n", first);
+               }
+       }
        else {
-       
-               strcpy(name,first);
-       
+               int count = 0;
+
+               BLI_strncpy(filepath, first, sizeof(filepath));
+
                pupdate_time();
                ptottime = 1.0;
-               
-/*
-     O_DIRECT
-            If set, all reads and writes on the resulting file descriptor will
-            be performed directly to or from the user program buffer, provided
-            appropriate size and alignment restrictions are met.  Refer to the
-            F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
-            information about how to determine the alignment constraints.
-            O_DIRECT is a Silicon Graphics extension and is only supported on
-            local EFS and XFS file systems.
-*/
-               
-               while(IMB_ispic(name) && totframes){
-                       file = open(name, O_BINARY|O_RDONLY, 0);
-                       if (file < 0) return;
-                       picture = (struct pict*)MEM_callocN(sizeof(struct pict), "picture");
-                       if (picture == 0){
-                               printf("Not enough memory for pict struct \n");
+
+               /* O_DIRECT
+                *
+                * If set, all reads and writes on the resulting file descriptor will
+                * be performed directly to or from the user program buffer, provided
+                * appropriate size and alignment restrictions are met.  Refer to the
+                * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
+                * information about how to determine the alignment constraints.
+                * O_DIRECT is a Silicon Graphics extension and is only supported on
+                * local EFS and XFS file systems.
+                */
+
+               while (IMB_ispic(filepath) && totframes) {
+                       size_t size;
+                       int file;
+
+                       file = open(filepath, O_BINARY | O_RDONLY, 0);
+                       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);
                                close(file);
                                return;
                        }
-                       size = BLI_filesize(file);
+                       size = BLI_file_descriptor_size(file);
 
                        if (size < 1) {
                                close(file);
@@ -286,121 +350,460 @@ static void build_pict_list(char * first, int totframes, int fstep)
 
                        picture->size = size;
                        picture->IB_flags = IB_rect;
-                                               
+
                        if (fromdisk == FALSE) {
-                               mem=(char *)MEM_mallocN(size, "build pic list");
-                               if (mem==0){
+                               mem = (char *)MEM_mallocN(size, "build pic list");
+                               if (mem == NULL) {
                                        printf("Couldn't get memory\n");
                                        close(file);
                                        MEM_freeN(picture);
                                        return;
                                }
-               
-                               if (read(file,mem,size) != size){
-                                       printf("Error while reading %s\n",name);
+
+                               if (read(file, mem, size) != size) {
+                                       printf("Error while reading %s\n", filepath);
                                        close(file);
                                        MEM_freeN(picture);
                                        MEM_freeN(mem);
                                        return;
                                }
-                       } else mem = 0;
-                       
+                       }
+                       else {
+                               mem = NULL;
+                       }
+
                        picture->mem = mem;
-                       picture->name = strdup(name);
+                       picture->name = strdup(filepath);
                        close(file);
-                       BLI_addtail(picsbase,picture);
+                       BLI_addtail(&picsbase, picture);
                        count++;
-                       
+
                        pupdate_time();
-                       
-                       if (ptottime > 1.0) {                           
-                               if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
-                               else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
+
+                       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, NULL, picture->name);
+                               }
+                               else {
+                                       ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL);
+                               }
                                if (ibuf) {
-                                       toscreen(picture, ibuf);
+                                       playanim_toscreen(picture, ibuf, fontid);
                                        IMB_freeImBuf(ibuf);
                                }
                                pupdate_time();
                                ptottime = 0.0;
                        }
-                       
-                       BLI_newname(name, +fstep);
-                       
-                       while(qtest()){
-                               switch(qreadN(&val)){
-                               case ESCKEY:
-                                       if (val) return;
-                                       break;
+
+                       BLI_newname(filepath, +fstep);
+
+#if 0 // XXX25
+                       while (qtest()) {
+                               switch (qreadN(&val)) {
+                                       case ESCKEY:
+                                               if (val) return;
+                                               break;
                                }
                        }
+#endif
                        totframes--;
                }
        }
        return;
 }
 
-void playanim(int argc, char **argv)
+static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
+{
+       PlayState *ps = (PlayState *)ps_void;
+       GHOST_TEventType type = GHOST_GetEventType(evt);
+       int val;
+
+       // print_ps(ps);
+
+       playanim_event_qual_update();
+
+       /* convert ghost event into value keyboard or mouse */
+       val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown);
+
+       if (ps->wait2 && ps->stopped) {
+               ps->stopped = FALSE;
+       }
+
+       switch (type) {
+               case GHOST_kEventKeyDown:
+               case GHOST_kEventKeyUp:
+               {
+                       GHOST_TEventKeyData *key_data;
+
+                       key_data = (GHOST_TEventKeyData *)GHOST_GetEventData(evt);
+                       switch (key_data->key) {
+                               case GHOST_kKeyA:
+                                       if (val) ps->noskip = !ps->noskip;
+                                       break;
+                               case GHOST_kKeyP:
+                                       if (val) ps->pingpong = !ps->pingpong;
+                                       break;
+                               case GHOST_kKeyNumpad1:
+                                       if (val) swaptime = fstep / 60.0;
+                                       break;
+                               case GHOST_kKeyNumpad2:
+                                       if (val) swaptime = fstep / 50.0;
+                                       break;
+                               case GHOST_kKeyNumpad3:
+                                       if (val) swaptime = fstep / 30.0;
+                                       break;
+                               case GHOST_kKeyNumpad4:
+                                       if (g_WS.qual & WS_QUAL_SHIFT)
+                                               swaptime = fstep / 24.0;
+                                       else
+                                               swaptime = fstep / 25.0;
+                                       break;
+                               case GHOST_kKeyNumpad5:
+                                       if (val) swaptime = fstep / 20.0;
+                                       break;
+                               case GHOST_kKeyNumpad6:
+                                       if (val) swaptime = fstep / 15.0;
+                                       break;
+                               case GHOST_kKeyNumpad7:
+                                       if (val) swaptime = fstep / 12.0;
+                                       break;
+                               case GHOST_kKeyNumpad8:
+                                       if (val) swaptime = fstep / 10.0;
+                                       break;
+                               case GHOST_kKeyNumpad9:
+                                       if (val) swaptime = fstep / 6.0;
+                                       break;
+                               case GHOST_kKeyLeftArrow:
+                                       if (val) {
+                                               ps->sstep = TRUE;
+                                               ps->wait2 = FALSE;
+                                               if (g_WS.qual & WS_QUAL_SHIFT) {
+                                                       ps->picture = picsbase.first;
+                                                       ps->next = 0;
+                                               }
+                                               else {
+                                                       ps->next = -1;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyDownArrow:
+                                       if (val) {
+                                               ps->wait2 = FALSE;
+                                               if (g_WS.qual & WS_QUAL_SHIFT) {
+                                                       ps->next = ps->direction = -1;
+                                               }
+                                               else {
+                                                       ps->next = -10;
+                                                       ps->sstep = TRUE;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyRightArrow:
+                                       if (val) {
+                                               ps->sstep = TRUE;
+                                               ps->wait2 = FALSE;
+                                               if (g_WS.qual & WS_QUAL_SHIFT) {
+                                                       ps->picture = picsbase.last;
+                                                       ps->next = 0;
+                                               }
+                                               else {
+                                                       ps->next = 1;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyUpArrow:
+                                       if (val) {
+                                               ps->wait2 = FALSE;
+                                               if (g_WS.qual & WS_QUAL_SHIFT) {
+                                                       ps->next = ps->direction = 1;
+                                               }
+                                               else {
+                                                       ps->next = 10;
+                                                       ps->sstep = TRUE;
+                                               }
+                                       }
+                                       break;
+
+                               case GHOST_kKeySlash:
+                               case GHOST_kKeyNumpadSlash:
+                                       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);
+                                               }
+                                               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;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyNumpad0:
+                                       if (val) {
+                                               if (ps->once) {
+                                                       ps->once = ps->wait2 = FALSE;
+                                               }
+                                               else {
+                                                       ps->picture = NULL;
+                                                       ps->once = TRUE;
+                                                       ps->wait2 = FALSE;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyEnter:
+                               case GHOST_kKeyNumpadEnter:
+                                       if (val) {
+                                               ps->wait2 = ps->sstep = FALSE;
+                                       }
+                                       break;
+                               case GHOST_kKeyNumpadPeriod:
+                                       if (val) {
+                                               if (ps->sstep) ps->wait2 = FALSE;
+                                               else {
+                                                       ps->sstep = TRUE;
+                                                       ps->wait2 = !ps->wait2;
+                                               }
+                                       }
+                                       break;
+                               case GHOST_kKeyNumpadPlus:
+                                       if (val == 0) break;
+                                       zoomx += 2.0;
+                                       zoomy += 2.0;
+                                       /* no break??? - is this intentional? - campbell XXX25 */
+                               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);
+                                       break;
+                               }
+                               case GHOST_kKeyEsc:
+                                       ps->go = FALSE;
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case GHOST_kEventCursorMove:
+               {
+                       if (g_WS.qual & WS_QUAL_LMOUSE) {
+                               int sizex, sizey;
+                               int i;
+
+                               GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
+                               int cx, cy;
+
+                               GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
+
+                               playanim_window_get_size(&sizex, &sizey);
+                               ps->picture = picsbase.first;
+                               /* TODO - store in ps direct? */
+                               i = 0;
+                               while (ps->picture) {
+                                       i++;
+                                       ps->picture = ps->picture->next;
+                               }
+                               i = (i * cx) / sizex;
+                               ps->picture = picsbase.first;
+                               for (; i > 0; i--) {
+                                       if (ps->picture->next == NULL) break;
+                                       ps->picture = ps->picture->next;
+                               }
+                               ps->sstep = TRUE;
+                               ps->wait2 = FALSE;
+                               ps->next = 0;
+                       }
+                       break;
+               }
+               case GHOST_kEventWindowSize:
+               case GHOST_kEventWindowMove:
+               {
+                       int sizex, sizey;
+
+                       playanim_window_get_size(&sizex, &sizey);
+                       GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+
+                       glViewport(0, 0, sizex, sizey);
+                       glScissor(0, 0, sizex, sizey);
+
+                       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;
+
+                       sizex = zoomx * ps->ibufx;
+                       sizey = zoomy * ps->ibufy;
+
+                       glPixelZoom(zoomx, zoomy);
+                       glEnable(GL_DITHER);
+                       ptottime = 0.0;
+                       playanim_toscreen(ps->picture, ps->curframe_ibuf, ps->fontid);
+
+                       break;
+               }
+               case GHOST_kEventQuit:
+               case GHOST_kEventWindowClose:
+               {
+                       ps->go = FALSE;
+                       break;
+               }
+               default:
+                       /* quiet warnings */
+                       break;
+       }
+
+       return 1;
+}
+
+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;
+
+       GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h);
+
+       posy = (scr_h - posy - sizey);
+
+       if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
+               inital_state = start_maximized ? GHOST_kWindowStateFullScreen : GHOST_kWindowStateNormal;
+       else
+               inital_state = start_maximized ? GHOST_kWindowStateMaximized : GHOST_kWindowStateNormal;
+
+       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);
+       //}
+       //}
+}
+
+
+void WM_main_playanim(int argc, const char **argv)
 {
-       struct ImBuf *ibuf = 0;
-       struct pict *picture = 0;
-       char name[512];
-       short val = 0, go = TRUE, ibufx = 0, ibufy = 0;
-       int event, stopped = FALSE, maxwinx, maxwiny;
-       short /*  c233 = FALSE, */ /*  yuvx = FALSE, */ once = FALSE, sstep = FALSE, wait2 = FALSE, /*  resetmap = FALSE, */ pause = 0;
-       short pingpong = FALSE, direction = 1, next = 1, turbo = FALSE, /*  doubleb = TRUE, */ noskip = FALSE;
-       int sizex, sizey, ofsx, ofsy, i;
+       struct ImBuf *ibuf = NULL;
+       char filepath[FILE_MAX];
+       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 = 0;
-       int start_x= 0, start_y= 0;
-       int sfra= -1;
-       int efra= -1;
+       struct anim *anim = NULL;
+       int start_x = 0, start_y = 0;
+       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.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;
+       /* resetmap = FALSE */
+
+       ps.fontid = -1;
+
        while (argc > 1) {
-               if (argv[1][0] == '-'){
-                       switch(argv[1][1]) {
+               if (argv[1][0] == '-') {
+                       switch (argv[1][1]) {
                                case 'm':
                                        fromdisk = TRUE;
                                        break;
                                case 'p':
-                                       if (argc>3) {
-                                               start_x= atoi(argv[2]);
-                                               start_y= atoi(argv[3]);
-                                               argc-= 2; 
-                                               argv+= 2;
-                                       } else {
+                                       if (argc > 3) {
+                                               start_x = atoi(argv[2]);
+                                               start_y = atoi(argv[3]);
+                                               argc -= 2;
+                                               argv += 2;
+                                       }
+                                       else {
                                                printf("too few arguments for -p (need 2): skipping\n");
                                        }
                                        break;
                                case 'f':
-                                       if (argc>3) {
+                                       if (argc > 3) {
                                                double fps = atof(argv[2]);
-                                               double fps_base= atof(argv[3]);
-                                               if (fps == 0) {
+                                               double fps_base = atof(argv[3]);
+                                               if (fps == 0.0) {
                                                        fps = 1;
                                                        printf("invalid fps,"
                                                               "forcing 1\n");
                                                }
                                                swaptime = fps_base / fps;
-                                               argc-= 2; 
-                                               argv+= 2;
-                                       } else {
+                                               argc -= 2;
+                                               argv += 2;
+                                       }
+                                       else {
                                                printf("too few arguments for -f (need 2): skipping\n");
                                        }
                                        break;
                                case 's':
-                                       sfra= MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
+                                       sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
                                        argc--;
                                        argv++;
                                        break;
                                case 'e':
-                                       efra= MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
+                                       efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
                                        argc--;
                                        argv++;
                                        break;
                                case 'j':
-                                       fstep= MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
-                                       swaptime*= fstep;
+                                       fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
+                                       swaptime *= fstep;
                                        argc--;
                                        argv++;
                                        break;
@@ -410,445 +813,290 @@ void playanim(int argc, char **argv)
                        }
                        argc--;
                        argv++;
-               } else break;
+               }
+               else {
+                       break;
+               }
        }
-       
-#ifdef WITH_QUICKTIME
-#if defined (_WIN32) || defined (__APPLE__)
-       /* 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__ */
-               G.have_quicktime = TRUE;
-#endif /* WITH_QUICKTIME */
 
-       if (argc > 1) strcpy(name,argv[1]);
+       if (argc > 1) {
+               BLI_strncpy(filepath, argv[1], sizeof(filepath));
+       }
        else {
-               BLI_getwdN(name);
-               if (name[strlen(name)-1] != '/') strcat(name,"/");
+               BLI_current_working_dir(filepath, sizeof(filepath));
+               BLI_add_slash(filepath);
        }
-               
-       if (IMB_isanim(name)) {
-               anim = IMB_open_anim(name, IB_rect);
+
+       if (IMB_isanim(filepath)) {
+               /* OCIO_TODO: support different input color spaces */
+               anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
                if (anim) {
-                       ibuf = IMB_anim_absolute(anim, 0);
+                       ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
                        IMB_close_anim(anim);
                        anim = NULL;
                }
-       } else if (!IMB_ispic(name)) {
+       }
+       else if (!IMB_ispic(filepath)) {
                exit(1);
        }
 
-       if (ibuf == 0) ibuf = IMB_loadiffname(name, IB_rect);
-       if (ibuf == 0){
-               printf("couldn't open %s\n",name);
+       if (ibuf == NULL) {
+               /* OCIO_TODO: support different input color space */
+               ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
+       }
+
+       if (ibuf == NULL) {
+               printf("couldn't open %s\n", filepath);
                exit(1);
        }
-       
+
+#if 0 //XXX25
        #if !defined(WIN32) && !defined(__APPLE__)
        if (fork()) exit(0);
        #endif
-       
-       winlay_get_screensize(&maxwinx, &maxwiny);
+#endif //XXX25
 
-               /* XXX, fixme zr */
+       /* XXX, fixme zr */
        {
-               extern void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
+//             extern void add_to_mainqueue(wmWindow *win, void *user_data, short evt, short val, char ascii);
+
+               GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
+
+               g_WS.ghost_system = GHOST_CreateSystem();
+               GHOST_AddEventConsumer(g_WS.ghost_system, consumer);
+
+
+
+               playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
+//XXX25                window_set_handler(g_WS.ghost_window, add_to_mainqueue, NULL);
 
-               g_window = window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
-               window_set_handler(g_window, add_to_mainqueue, NULL);
-               
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
                glMatrixMode(GL_MODELVIEW);
        }
 
-       G.fonts= BMF_GetFont(BMF_kHelvetica10);
-       
-       ibufx = ibuf->x;
-       ibufy = ibuf->y;
-       
+       GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);
+
+       //GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+
+       /* initialize the font */
+       BLF_init(11, 72);
+       ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
+       BLF_size(ps.fontid, 11, 72);
+
+       ps.ibufx = ibuf->x;
+       ps.ibufy = ibuf->y;
+
        if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
        if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
-       
+
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
-       
-       window_swap_buffers(g_window);
-       
+
+       GHOST_SwapWindowBuffers(g_WS.ghost_window);
+
        if (sfra == -1 || efra == -1) {
                /* one of the frames was invalid, just use all images */
                sfra = 1;
                efra = MAXFRAME;
        }
-       
-       build_pict_list(name, (efra - sfra) + 1, fstep);
-       
-       for (i = 2; i < argc; i++){
-               strcpy(name, argv[i]);
-               build_pict_list(name, (efra - sfra) + 1, fstep);
+
+       build_pict_list(filepath, (efra - sfra) + 1, 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);
        }
 
-       IMB_freeImBuf(ibuf); 
-       ibuf = 0;
+       IMB_freeImBuf(ibuf);
+       ibuf = NULL;
 
        pupdate_time();
        ptottime = 0;
 
-       while (go){
-               if (pingpong) direction = -direction;
+       /* newly added in 2.6x, without this images never get freed */
+#define USE_IMB_CACHE
 
-               if (direction == 1) picture = picsbase->first;
-               else picture = picsbase->last;
+       while (ps.go) {
+               if (ps.pingpong)
+                       ps.direction = -ps.direction;
 
-               if (picture == 0){
+               if (ps.direction == 1) {
+                       ps.picture = picsbase.first;
+               }
+               else {
+                       ps.picture = picsbase.last;
+               }
+
+               if (ps.picture == NULL) {
                        printf("couldn't find pictures\n");
-                       go = FALSE;
+                       ps.go = FALSE;
                }
-               if (pingpong){
-                       if (direction == 1) picture = picture->next;
-                       else picture = picture->prev;
+               if (ps.pingpong) {
+                       if (ps.direction == 1) {
+                               ps.picture = ps.picture->next;
+                       }
+                       else {
+                               ps.picture = ps.picture->prev;
+                       }
                }
                if (ptottime > 0.0) ptottime = 0.0;
 
-               while (picture){
-                       if (ibuf != 0 && ibuf->type == 0) IMB_freeImBuf(ibuf);
-
-                       if (picture->ibuf) ibuf = picture->ibuf;
-                       else if (picture->anim) ibuf = IMB_anim_absolute(picture->anim, picture->frame);
-                       else if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
-                       else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
-                       
-                       if (ibuf){
-                               strcpy(ibuf->name, picture->name);
-                               
-#ifdef _WIN32  
-                               window_set_title(g_window, picture->name);
+               while (ps.picture) {
+#ifndef USE_IMB_CACHE
+                       if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
+#endif
+                       if (ps.picture->ibuf) {
+                               ibuf = ps.picture->ibuf;
+                       }
+                       else if (ps.picture->anim) {
+                               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, NULL, ps.picture->name);
+                       }
+                       else {
+                               /* 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 */
+#ifdef _WIN32
+                               GHOST_SetTitle(g_WS.ghost_window, ps.picture->name);
 #endif
 
                                while (pupdate_time()) PIL_sleep_ms(1);
                                ptottime -= swaptime;
-                               toscreen(picture, ibuf);
+                               playanim_toscreen(ps.picture, ibuf, ps.fontid);
                        } /* else deleten */
                        else {
                                printf("error: can't play this image type\n");
                                exit(0);
                        }
-                       
-                       if (once){
-                               if (picture->next == 0) wait2 = TRUE;
-                               else if (picture->prev == 0) wait2 = TRUE;
-                       }
-                       
-                       next = direction;
-                       
-                       while ((qtest() != 0 ) || ( wait2 != 0)){
-                               if (wait2 && stopped) {
-                                       stopped = FALSE;
+
+                       if (ps.once) {
+                               if (ps.picture->next == NULL) {
+                                       ps.wait2 = TRUE;
                                }
-                       
-                               event = qreadN(&val);
-                               /* printf("%d %d\n", event, val); */
-                               
-                               if (wait2){
-                                       pupdate_time();
-                                       ptottime = 0;
+                               else if (ps.picture->prev == NULL) {
+                                       ps.wait2 = TRUE;
                                }
-                               switch (event){
-                               case AKEY:
-                                       if (val)
-                                               noskip = !noskip;
-                                       break;
-                               case PKEY:
-                                       if (val)
-                                               pingpong = !pingpong;
-                                       break;
-                               case SLASHKEY:
-                                       if (val) {
-                                               if (qualN & SHIFT) {
-                                                       if (ibuf)
-                                                               printf(" Name: %s | Speed: %.2f frames/s\n", ibuf->name, fstep / swaptime);
-                                               } else {
-                                                       swaptime = fstep / 5.0;
-                                               }
-                                       }
-                                       break;
-                               case LEFTARROWKEY:
-                                       if (val){
-                                               sstep = TRUE;
-                                               wait2 = FALSE;
-                                               if (qualN & SHIFT) {
-                                                       picture = picsbase->first;
-                                                       next = 0;
-                                               } else {
-                                                       next = -1;
-                                               }
-                                       }
-                                       break;
-                               case DOWNARROWKEY:
-                                       if (val){
-                                               wait2 = FALSE;
-                                               if (qualN & SHIFT) {
-                                                       next = direction = -1;
-                                               } else {
-                                                       next = -10;
-                                                       sstep = TRUE;
-                                               }
-                                       }
-                                       break;
-                               case RIGHTARROWKEY:
-                                       if (val){
-                                               sstep = TRUE;
-                                               wait2 = FALSE;
-                                               if (qualN & SHIFT) {
-                                                       picture = picsbase->last;
-                                                       next = 0;
-                                               } else {
-                                                       next = 1;
-                                               }
-                                       }
-                                       break;
-                               case UPARROWKEY:
-                                       if (val){
-                                               wait2 = FALSE;
-                                               if (qualN & SHIFT) {
-                                                       next = direction = 1;
-                                               } else {
-                                                       next = 10;
-                                                       sstep = TRUE;
-                                               }
-                                       }
-                                       break;
-                               case LEFTMOUSE:
-                               case MOUSEX:
-                                       if (qualN & LMOUSE) {
-                                               window_get_size(g_window,&sizex,&sizey);
-                                               picture = picsbase->first;
-                                               i = 0;
-                                               while (picture){
-                                                       i ++;
-                                                       picture = picture->next;
-                                               }
-                                               i = (i * val) / sizex;
-                                               picture = picsbase->first;
-                                               for (; i > 0; i--){
-                                                       if (picture->next == 0) break;
-                                                       picture = picture->next;
-                                               }
-                                               sstep = TRUE;
-                                               wait2 = FALSE;
-                                               next = 0;
-                                       }
-                                       break;
-                                       go= FALSE;
-                                       break;
-                               case EQUALKEY:
-                                       if (val) {
-                                               if (qualN & SHIFT) {
-                                                       pause ++;
-                                                       printf("pause:%d\n", pause);
-                                               } else swaptime /= 1.1;
-                                       }
-                                       break;
-                               case MINUSKEY:
-                                       if (val) {
-                                               if (qualN & SHIFT) {
-                                                       pause --;
-                                                       printf("pause:%d\n", pause);
-                                               } else swaptime *= 1.1;
-                                       }
-                                       break;
-                               case PAD0:
-                                       if (val){
-                                               if (once) once = wait2 = FALSE;
-                                               else {
-                                                       picture = 0;
-                                                       once = TRUE;
-                                                       wait2 = FALSE;
-                                               }
-                                       }
-                                       break;
-                               case RETKEY:
-                               case PADENTER:
-                                       if (val){
-                                               wait2 = sstep = FALSE;
-                                       }
-                                       break;
-                               case PADPERIOD:
-                                       if (val){
-                                               if (sstep) wait2 = FALSE;
-                                               else {
-                                                       sstep = TRUE;
-                                                       wait2 = !wait2;
-                                               }
-                                       }
-                                       break;
-                               case PAD1:
-                                       swaptime = fstep / 60.0;
-                                       break;
-                               case PAD2:
-                                       swaptime = fstep / 50.0;
-                                       break;
-                               case PAD3:
-                                       swaptime = fstep / 30.0;
-                                       break;
-                               case PAD4:
-                                       if (qualN & SHIFT)
-                                               swaptime = fstep / 24.0;
-                                       else
-                                               swaptime = fstep / 25.0;
-                                       break;
-                               case PAD5:
-                                       swaptime = fstep / 20.0;
-                                       break;
-                               case PAD6:
-                                       swaptime = fstep / 15.0;
-                                       break;
-                               case PAD7:
-                                       swaptime = fstep / 12.0;
-                                       break;
-                               case PAD8:
-                                       swaptime = fstep / 10.0;
-                                       break;
-                               case PAD9:
-                                       swaptime = fstep / 6.0;
-                                       break;
-                               case PADPLUSKEY:
-                                       if (val == 0) break;
-                                       zoomx += 2.0;
-                                       zoomy += 2.0;
-                               case PADMINUS:
-                                       if (val == 0) break;
-                                       if (zoomx > 1.0) zoomx -= 1.0;
-                                       if (zoomy > 1.0) zoomy -= 1.0;
-                                       window_get_position(g_window,&ofsx,&ofsy);
-                                       window_get_size(g_window,&sizex,&sizey);
-                                       ofsx += sizex/2;
-                                       ofsy += sizey/2;
-                                       sizex = zoomx * ibufx;
-                                       sizey = zoomy * ibufy;
-                                       ofsx -= sizex/2;
-                                       ofsy -= sizey/2;
-/*                                     window_set_position(g_window,sizex,sizey); */
-                                       window_set_size(g_window,sizex,sizey);
-                                       break;
-                               case RESHAPE:
-                               case REDRAW:
-                                       window_get_size(g_window,&sizex,&sizey);
-                                       window_make_active(g_window);
-                                       
-                                       glViewport(0,  0, sizex, sizey);
-                                       glScissor(0,  0, sizex, sizey);
-
-                                       zoomx = (float) sizex / ibufx;
-                                       zoomy = (float) sizey / 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;
-
-                                       sizex = zoomx * ibufx;
-                                       sizey = zoomy * ibufy;
-
-                                       glPixelZoom(zoomx, zoomy);
-                                       glEnable(GL_DITHER);
-                                       ptottime = 0.0;
-                                       toscreen(picture, ibuf);
-                                       while (qtest()) qreadN(&val);
-                                       
-                                       break;
-                               case ESCKEY:
-                               case WINCLOSE:
-                               case WINQUIT:
-                                       go = FALSE;
-                                       break;
+                       }
+
+                       ps.next = ps.direction;
+
+
+                       {
+                               int hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0);
+                               if (hasevent) {
+                                       GHOST_DispatchEvents(g_WS.ghost_system);
                                }
-                               if (go == FALSE) break;
                        }
-                       
-                       wait2 = sstep;
-                       
-                       if (wait2 == 0 && stopped == 0) {
-                               stopped = TRUE;
+
+                       /* 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;
+                       }
+
+                       ps.wait2 = ps.sstep;
+
+                       if (ps.wait2 == 0 && ps.stopped == 0) {
+                               ps.stopped = TRUE;
                        }
 
                        pupdate_time();
-                                       
-                       if (picture && next) {
+
+                       if (ps.picture && ps.next) {
                                /* always at least set one step */
-                               while (picture){
-                                       if (next < 0) picture = picture->prev;
-                                       else picture = picture->next;
-       
-                                       if (once && picture != 0){
-                                               if (picture->next == 0) wait2 = TRUE;
-                                               else if (picture->prev == 0) wait2 = TRUE;
+                               while (ps.picture) {
+                                       if (ps.next < 0) {
+                                               ps.picture = ps.picture->prev;
+                                       }
+                                       else {
+                                               ps.picture = ps.picture->next;
                                        }
 
-                                       if (wait2 || ptottime < swaptime || turbo || noskip) break;
+                                       if (ps.once && ps.picture != NULL) {
+                                               if (ps.picture->next == NULL) {
+                                                       ps.wait2 = TRUE;
+                                               }
+                                               else if (ps.picture->prev == NULL) {
+                                                       ps.wait2 = TRUE;
+                                               }
+                                       }
+
+                                       if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
                                        ptottime -= swaptime;
                                }
-                               if (picture == 0 && sstep) {
-                                       if (next < 0) picture = picsbase->last;
-                                       else if (next > 0) picture = picsbase->first;                                                                   
+                               if (ps.picture == NULL && ps.sstep) {
+                                       if (ps.next < 0) {
+                                               ps.picture = picsbase.last;
+                                       }
+                                       else if (ps.next > 0) {
+                                               ps.picture = picsbase.first;
+                                       }
                                }
                        }
-                       if (go == FALSE) break;
+                       if (ps.go == FALSE) {
+                               break;
+                       }
                }
        }
-       picture = picsbase->first;
+       ps.picture = picsbase.first;
        anim = NULL;
-       while (picture) {
-               if (picture && picture->anim && (anim != picture->anim)) {
+       while (ps.picture) {
+               if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
                        // to prevent divx crashes
-                       anim = picture->anim;
+                       anim = ps.picture->anim;
                        IMB_close_anim(anim);
                }
-               if(picture->ibuf) IMB_freeImBuf(picture->ibuf);
-               if(picture->mem) MEM_freeN(picture->mem);
-               
-               picture = picture->next;
-       }
-#ifdef WITH_QUICKTIME
-#if defined (_WIN32) || defined (__APPLE__)
-       if(G.have_quicktime) {
-               ExitMovies();
-#ifdef _WIN32
-               TerminateQTML();
-#endif /* _WIN32 */
+
+               if (ps.picture->ibuf) {
+                       IMB_freeImBuf(ps.picture->ibuf);
+               }
+               if (ps.picture->mem) {
+                       MEM_freeN(ps.picture->mem);
+               }
+
+               ps.picture = ps.picture->next;
        }
-#endif /* _WIN32 || __APPLE__ */
-#endif /* WITH_QUICKTIME */
 
        /* cleanup */
-       if(ibuf) IMB_freeImBuf(ibuf); 
-       BLI_freelistN(picsbase);
+#ifndef USE_IMB_CACHE
+       if (ibuf) IMB_freeImBuf(ibuf);
+#endif
+
+       BLI_freelistN(&picsbase);
+#if 0 // XXX25
        free_blender();
-       window_destroy(g_window);
+#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);
 
-       totblock= MEM_get_memory_blocks_in_use();
-       if(totblock!=0) {
-               printf("Error Totblock: %d\n",totblock);
+       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
-
-void playanim(int argc, const char **argv)
-{
-       (void)argc;
-       (void)argv;
+       }
 }