Cleanup: commas at the end of enums
[blender.git] / source / blender / windowmanager / intern / wm_playanim.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Campbell Barton
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/windowmanager/intern/wm_playanim.c
29  *  \ingroup wm
30  *
31  * Animation player for image sequences & video's with sound support.
32  * Launched in a separate process from Blender's #RENDER_OT_play_rendered_anim
33  *
34  * \note This file uses ghost directly and none of the WM definitions.
35  * this could be made into its own module, alongside creator.
36  */
37
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <math.h>
43
44 #ifndef WIN32
45 #  include <unistd.h>
46 #  include <sys/times.h>
47 #  include <sys/wait.h>
48 #else
49 #  include <io.h>
50 #endif
51 #include "MEM_guardedalloc.h"
52
53 #include "PIL_time.h"
54
55 #include "BLI_utildefines.h"
56 #include "BLI_fileops.h"
57 #include "BLI_listbase.h"
58 #include "BLI_path_util.h"
59 #include "BLI_string.h"
60
61 #include "IMB_imbuf_types.h"
62 #include "IMB_imbuf.h"
63
64 #include "BKE_depsgraph.h"
65 #include "BKE_image.h"
66
67 #include "BIF_gl.h"
68 #include "BIF_glutil.h"
69
70 #include "DNA_scene_types.h"
71 #include "ED_datafiles.h" /* for fonts */
72 #include "GHOST_C-api.h"
73 #include "BLF_api.h"
74
75 #include "WM_api.h"  /* only for WM_main_playanim */
76
77 #ifdef WITH_AUDASPACE
78 #  include AUD_DEVICE_H
79 #  include AUD_HANDLE_H
80 #  include AUD_SOUND_H
81 #  include AUD_SPECIAL_H
82
83 static AUD_Sound *source = NULL;
84 static AUD_Handle *playback_handle = NULL;
85 static AUD_Handle *scrub_handle = NULL;
86 static AUD_Device *audio_device = NULL;
87 #endif
88
89 /* simple limiter to avoid flooding memory */
90 #define USE_FRAME_CACHE_LIMIT
91 #ifdef USE_FRAME_CACHE_LIMIT
92 #  define PLAY_FRAME_CACHE_MAX 30
93 #endif
94
95 struct PlayState;
96 static void playanim_window_zoom(struct PlayState *ps, const float zoom_offset);
97
98 typedef struct PlayState {
99
100         /* window and viewport size */
101         int win_x, win_y;
102
103         /* current zoom level */
104         float zoom;
105
106         /* playback state */
107         short direction;
108         short next_frame;
109
110         bool  once;
111         bool  turbo;
112         bool  pingpong;
113         bool  noskip;
114         bool  indicator;
115         bool  sstep;
116         bool  wait2;
117         bool  stopped;
118         bool  go;
119         /* waiting for images to load */
120         bool  loading;
121         /* x/y image flip */
122         bool draw_flip[2];
123
124         int fstep;
125
126         /* current picture */
127         struct PlayAnimPict *picture;
128
129         /* set once at the start */
130         int ibufx, ibufy;
131         int fontid;
132
133         /* saves passing args */
134         struct ImBuf *curframe_ibuf;
135
136         /* restarts player for file drop */
137         char dropped_file[FILE_MAX];
138
139         bool need_frame_update;
140         int frame_cursor_x;
141 } PlayState;
142
143 /* for debugging */
144 #if 0
145 void print_ps(PlayState *ps)
146 {
147         printf("ps:\n");
148         printf("    direction=%d,\n", (int)ps->direction);
149         printf("    next=%d,\n", ps->next);
150         printf("    once=%d,\n", ps->once);
151         printf("    turbo=%d,\n", ps->turbo);
152         printf("    pingpong=%d,\n", ps->pingpong);
153         printf("    noskip=%d,\n", ps->noskip);
154         printf("    sstep=%d,\n", ps->sstep);
155         printf("    pause=%d,\n", ps->pause);
156         printf("    wait2=%d,\n", ps->wait2);
157         printf("    stopped=%d,\n", ps->stopped);
158         printf("    go=%d,\n\n", ps->go);
159         fflush(stdout);
160 }
161 #endif
162
163 /* global for window and events */
164 typedef enum eWS_Qual {
165         WS_QUAL_LSHIFT  = (1 << 0),
166         WS_QUAL_RSHIFT  = (1 << 1),
167         WS_QUAL_SHIFT   = (WS_QUAL_LSHIFT | WS_QUAL_RSHIFT),
168         WS_QUAL_LALT    = (1 << 2),
169         WS_QUAL_RALT    = (1 << 3),
170         WS_QUAL_ALT     = (WS_QUAL_LALT | WS_QUAL_RALT),
171         WS_QUAL_LCTRL   = (1 << 4),
172         WS_QUAL_RCTRL   = (1 << 5),
173         WS_QUAL_CTRL    = (WS_QUAL_LCTRL | WS_QUAL_RCTRL),
174         WS_QUAL_LMOUSE  = (1 << 16),
175         WS_QUAL_MMOUSE  = (1 << 17),
176         WS_QUAL_RMOUSE  = (1 << 18),
177         WS_QUAL_MOUSE   = (WS_QUAL_LMOUSE | WS_QUAL_MMOUSE | WS_QUAL_RMOUSE),
178 } eWS_Qual;
179
180 static struct WindowStateGlobal {
181         GHOST_SystemHandle ghost_system;
182         void *ghost_window;
183
184         /* events */
185         eWS_Qual qual;
186 } g_WS = {NULL};
187
188 static void playanim_window_get_size(int *r_width, int *r_height)
189 {
190         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_WS.ghost_window);
191         *r_width = GHOST_GetWidthRectangle(bounds);
192         *r_height = GHOST_GetHeightRectangle(bounds);
193         GHOST_DisposeRectangle(bounds);
194 }
195
196 static void playanim_gl_matrix(void)
197 {
198         /* unified matrix, note it affects offset for drawing */
199         glMatrixMode(GL_PROJECTION);
200         glLoadIdentity();
201         glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
202         glMatrixMode(GL_MODELVIEW);
203 }
204
205 /* implementation */
206 static void playanim_event_qual_update(void)
207 {
208         int val;
209
210         /* Shift */
211         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val);
212         if (val) g_WS.qual |=  WS_QUAL_LSHIFT;
213         else     g_WS.qual &= ~WS_QUAL_LSHIFT;
214
215         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightShift, &val);
216         if (val) g_WS.qual |=  WS_QUAL_RSHIFT;
217         else     g_WS.qual &= ~WS_QUAL_RSHIFT;
218
219         /* Control */
220         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftControl, &val);
221         if (val) g_WS.qual |=  WS_QUAL_LCTRL;
222         else     g_WS.qual &= ~WS_QUAL_LCTRL;
223
224         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightControl, &val);
225         if (val) g_WS.qual |=  WS_QUAL_RCTRL;
226         else     g_WS.qual &= ~WS_QUAL_RCTRL;
227
228         /* Alt */
229         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftAlt, &val);
230         if (val) g_WS.qual |=  WS_QUAL_LALT;
231         else     g_WS.qual &= ~WS_QUAL_LALT;
232
233         GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyRightAlt, &val);
234         if (val) g_WS.qual |=  WS_QUAL_RALT;
235         else     g_WS.qual &= ~WS_QUAL_RALT;
236 }
237
238 typedef struct PlayAnimPict {
239         struct PlayAnimPict *next, *prev;
240         char *mem;
241         int size;
242         const char *name;
243         struct ImBuf *ibuf;
244         struct anim *anim;
245         int frame;
246         int IB_flags;
247 } PlayAnimPict;
248
249 static struct ListBase picsbase = {NULL, NULL};
250 /* frames in memory - store them here to for easy deallocation later */
251 static bool fromdisk = false;
252 static double ptottime = 0.0, swaptime = 0.04;
253 #ifdef WITH_AUDASPACE
254 static double fps_movie;
255 #endif
256
257 #ifdef USE_FRAME_CACHE_LIMIT
258 static struct ListBase inmempicsbase = {NULL, NULL};
259 static int added_images = 0;
260 #endif
261
262 static PlayAnimPict *playanim_step(PlayAnimPict *playanim, int step)
263 {
264         if (step > 0) {
265                 while (step-- && playanim) {
266                         playanim = playanim->next;
267                 }
268         }
269         else if (step < 0) {
270                 while (step++ && playanim) {
271                         playanim = playanim->prev;
272                 }
273         }
274         return playanim;
275 }
276
277 static int pupdate_time(void)
278 {
279         static double ltime;
280         double time;
281
282         time = PIL_check_seconds_timer();
283
284         ptottime += (time - ltime);
285         ltime = time;
286         return (ptottime < 0);
287 }
288
289 static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf *ibuf, int fontid, int fstep)
290 {
291         float offs_x, offs_y;
292         float span_x, span_y;
293
294         if (ibuf == NULL) {
295                 printf("%s: no ibuf for picture '%s'\n", __func__, picture ? picture->name : "<NIL>");
296                 return;
297         }
298         if (ibuf->rect == NULL && ibuf->rect_float) {
299                 IMB_rect_from_float(ibuf);
300                 imb_freerectfloatImBuf(ibuf);
301         }
302         if (ibuf->rect == NULL)
303                 return;
304
305         GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
306
307         /* size within window */
308         span_x = (ps->zoom * ibuf->x) / (float)ps->win_x;
309         span_y = (ps->zoom * ibuf->y) / (float)ps->win_y;
310
311         /* offset within window */
312         offs_x = 0.5f * (1.0f - span_x);
313         offs_y = 0.5f * (1.0f - span_y);
314
315         CLAMP(offs_x, 0.0f, 1.0f);
316         CLAMP(offs_y, 0.0f, 1.0f);
317         glRasterPos2f(offs_x, offs_y);
318
319         glClearColor(0.1, 0.1, 0.1, 0.0);
320         glClear(GL_COLOR_BUFFER_BIT);
321
322         /* checkerboard for case alpha */
323         if (ibuf->planes == 32) {
324                 glEnable(GL_BLEND);
325                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
326
327                 fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
328         }
329
330         glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
331                       offs_y + (ps->draw_flip[1] ? span_y : 0.0f));
332
333         glPixelZoom(ps->zoom * (ps->draw_flip[0] ? -1.0f : 1.0f),
334                     ps->zoom * (ps->draw_flip[1] ? -1.0f : 1.0f));
335
336         glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
337
338         glDisable(GL_BLEND);
339
340         pupdate_time();
341
342         if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {
343                 int sizex, sizey;
344                 float fsizex_inv, fsizey_inv;
345                 char str[32 + FILE_MAX];
346                 cpack(-1);
347                 BLI_snprintf(str, sizeof(str), "%s | %.2f frames/s", picture->name, fstep / swaptime);
348
349                 playanim_window_get_size(&sizex, &sizey);
350                 fsizex_inv = 1.0f / sizex;
351                 fsizey_inv = 1.0f / sizey;
352
353                 BLF_enable(fontid, BLF_ASPECT);
354                 BLF_aspect(fontid, fsizex_inv, fsizey_inv, 1.0f);
355                 BLF_position(fontid, 10.0f * fsizex_inv, 10.0f * fsizey_inv, 0.0f);
356                 BLF_draw(fontid, str, sizeof(str));
357         }
358
359         if (ps->indicator) {
360                 float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame);
361
362                 fac = 2.0f * fac - 1.0f;
363                 glMatrixMode(GL_PROJECTION);
364                 glPushMatrix();
365                 glLoadIdentity();
366                 glMatrixMode(GL_MODELVIEW);
367                 glPushMatrix();
368                 glLoadIdentity();
369
370                 glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
371
372                 glBegin(GL_LINES);
373                 glVertex2f(fac, -1.0f);
374                 glVertex2f(fac, 1.0f);
375                 glEnd();
376
377                 glPopMatrix();
378                 glMatrixMode(GL_PROJECTION);
379                 glPopMatrix();
380                 glMatrixMode(GL_MODELVIEW);
381         }
382
383         GHOST_SwapWindowBuffers(g_WS.ghost_window);
384 }
385
386 static void build_pict_list_ex(PlayState *ps, const char *first, int totframes, int fstep, int fontid)
387 {
388         char *mem, filepath[FILE_MAX];
389 //      short val;
390         PlayAnimPict *picture = NULL;
391         struct ImBuf *ibuf = NULL;
392         struct anim *anim;
393
394         if (IMB_isanim(first)) {
395                 /* OCIO_TODO: support different input color space */
396                 anim = IMB_open_anim(first, IB_rect, 0, NULL);
397                 if (anim) {
398                         int pic;
399                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
400                         if (ibuf) {
401                                 playanim_toscreen(ps, NULL, ibuf, fontid, fstep);
402                                 IMB_freeImBuf(ibuf);
403                         }
404
405                         for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
406                                 picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict");
407                                 picture->anim = anim;
408                                 picture->frame = pic;
409                                 picture->IB_flags = IB_rect;
410                                 picture->name = BLI_sprintfN("%s : %4.d", first, pic + 1);
411                                 BLI_addtail(&picsbase, picture);
412                         }
413                 }
414                 else {
415                         printf("couldn't open anim %s\n", first);
416                 }
417         }
418         else {
419                 int count = 0;
420
421                 int fp_framenr;
422                 struct {
423                         char head[FILE_MAX], tail[FILE_MAX];
424                         unsigned short digits;
425                 } fp_decoded;
426
427                 BLI_strncpy(filepath, first, sizeof(filepath));
428                 fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
429
430                 pupdate_time();
431                 ptottime = 1.0;
432
433                 /* O_DIRECT
434                  *
435                  * If set, all reads and writes on the resulting file descriptor will
436                  * be performed directly to or from the user program buffer, provided
437                  * appropriate size and alignment restrictions are met.  Refer to the
438                  * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
439                  * information about how to determine the alignment constraints.
440                  * O_DIRECT is a Silicon Graphics extension and is only supported on
441                  * local EFS and XFS file systems.
442                  */
443
444                 while (IMB_ispic(filepath) && totframes) {
445                         bool hasevent;
446                         size_t size;
447                         int file;
448
449                         file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
450                         if (file < 0) {
451                                 /* print errno? */
452                                 return;
453                         }
454
455                         picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture");
456                         if (picture == NULL) {
457                                 printf("Not enough memory for pict struct '%s'\n", filepath);
458                                 close(file);
459                                 return;
460                         }
461                         size = BLI_file_descriptor_size(file);
462
463                         if (size < 1) {
464                                 close(file);
465                                 MEM_freeN(picture);
466                                 return;
467                         }
468
469                         picture->size = size;
470                         picture->IB_flags = IB_rect;
471
472                         if (fromdisk == false) {
473                                 mem = (char *)MEM_mallocN(size, "build pic list");
474                                 if (mem == NULL) {
475                                         printf("Couldn't get memory\n");
476                                         close(file);
477                                         MEM_freeN(picture);
478                                         return;
479                                 }
480
481                                 if (read(file, mem, size) != size) {
482                                         printf("Error while reading %s\n", filepath);
483                                         close(file);
484                                         MEM_freeN(picture);
485                                         MEM_freeN(mem);
486                                         return;
487                                 }
488                         }
489                         else {
490                                 mem = NULL;
491                         }
492
493                         picture->mem = mem;
494                         picture->name = BLI_strdup(filepath);
495                         picture->frame = count;
496                         close(file);
497                         BLI_addtail(&picsbase, picture);
498                         count++;
499
500                         pupdate_time();
501
502                         if (ptottime > 1.0) {
503                                 /* OCIO_TODO: support different input color space */
504                                 if (picture->mem) {
505                                         ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size,
506                                                                      picture->IB_flags, NULL, picture->name);
507                                 }
508                                 else {
509                                         ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL);
510                                 }
511                                 if (ibuf) {
512                                         playanim_toscreen(ps, picture, ibuf, fontid, fstep);
513                                         IMB_freeImBuf(ibuf);
514                                 }
515                                 pupdate_time();
516                                 ptottime = 0.0;
517                         }
518
519                         /* create a new filepath each time */
520                         fp_framenr += fstep;
521                         BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
522
523                         while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
524                                 if (hasevent) {
525                                         GHOST_DispatchEvents(g_WS.ghost_system);
526                                 }
527                                 if (ps->loading == false) {
528                                         return;
529                                 }
530                         }
531
532                         totframes--;
533                 }
534         }
535         return;
536 }
537
538 static void build_pict_list(PlayState *ps, const char *first, int totframes, int fstep, int fontid)
539 {
540         ps->loading = true;
541         build_pict_list_ex(ps, first, totframes, fstep, fontid);
542         ps->loading = false;
543 }
544
545 static void update_sound_fps(void)
546 {
547 #ifdef WITH_AUDASPACE
548         if (playback_handle) {
549                 /* swaptime stores the 1.0/fps ratio */
550                 double speed = 1.0 / (swaptime * fps_movie);
551
552                 AUD_Handle_setPitch(playback_handle, speed);
553         }
554 #endif
555 }
556
557 static void tag_change_frame(PlayState *ps, int cx)
558 {
559         ps->need_frame_update = true;
560         ps->frame_cursor_x = cx;
561 }
562
563 static void change_frame(PlayState *ps)
564 {
565         if (!ps->need_frame_update) {
566                 return;
567         }
568
569         int sizex, sizey;
570         int i, i_last;
571
572         if (BLI_listbase_is_empty(&picsbase)) {
573                 return;
574         }
575
576         playanim_window_get_size(&sizex, &sizey);
577         i_last = ((struct PlayAnimPict *)picsbase.last)->frame;
578         i = (i_last * ps->frame_cursor_x) / sizex;
579         CLAMP(i, 0, i_last);
580
581 #ifdef WITH_AUDASPACE
582         if (scrub_handle) {
583                 AUD_Handle_stop(scrub_handle);
584                 scrub_handle = NULL;
585         }
586
587         if (playback_handle) {
588                 AUD_Status status = AUD_Handle_getStatus(playback_handle);
589                 if (status != AUD_STATUS_PLAYING) {
590                         AUD_Handle_stop(playback_handle);
591                         playback_handle = AUD_Device_play(audio_device, source, 1);
592                         if (playback_handle) {
593                                 AUD_Handle_setPosition(playback_handle, i / fps_movie);
594                                 scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
595                         }
596                         update_sound_fps();
597                 }
598                 else {
599                         AUD_Handle_setPosition(playback_handle, i / fps_movie);
600                         scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
601                 }
602         }
603         else if (source) {
604                 playback_handle = AUD_Device_play(audio_device, source, 1);
605                 if (playback_handle) {
606                         AUD_Handle_setPosition(playback_handle, i / fps_movie);
607                         scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
608                 }
609                 update_sound_fps();
610         }
611 #endif
612
613         ps->picture = BLI_findlink(&picsbase, i);
614         BLI_assert(ps->picture != NULL);
615
616         ps->sstep = true;
617         ps->wait2 = false;
618         ps->next_frame = 0;
619
620         ps->need_frame_update = false;
621 }
622
623 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
624 {
625         PlayState *ps = (PlayState *)ps_void;
626         GHOST_TEventType type = GHOST_GetEventType(evt);
627         int val;
628
629         // print_ps(ps);
630
631         playanim_event_qual_update();
632
633         /* convert ghost event into value keyboard or mouse */
634         val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown);
635
636         /* first check if we're busy loading files */
637         if (ps->loading) {
638                 switch (type) {
639                         case GHOST_kEventKeyDown:
640                         case GHOST_kEventKeyUp:
641                         {
642                                 GHOST_TEventKeyData *key_data;
643
644                                 key_data = (GHOST_TEventKeyData *)GHOST_GetEventData(evt);
645                                 switch (key_data->key) {
646                                         case GHOST_kKeyEsc:
647                                                 ps->loading = false;
648                                                 break;
649                                         default:
650                                                 break;
651                                 }
652                                 break;
653                         }
654                         default:
655                                 break;
656                 }
657                 return 1;
658         }
659
660
661         if (ps->wait2 && ps->stopped) {
662                 ps->stopped = false;
663         }
664
665         if (ps->wait2) {
666                 pupdate_time();
667                 ptottime = 0;
668         }
669
670         switch (type) {
671                 case GHOST_kEventKeyDown:
672                 case GHOST_kEventKeyUp:
673                 {
674                         GHOST_TEventKeyData *key_data;
675
676                         key_data = (GHOST_TEventKeyData *)GHOST_GetEventData(evt);
677                         switch (key_data->key) {
678                                 case GHOST_kKeyA:
679                                         if (val) ps->noskip = !ps->noskip;
680                                         break;
681                                 case GHOST_kKeyI:
682                                         if (val) ps->indicator = !ps->indicator;
683                                         break;
684                                 case GHOST_kKeyP:
685                                         if (val) ps->pingpong = !ps->pingpong;
686                                         break;
687                                 case GHOST_kKeyF:
688                                 {
689                                         if (val) {
690                                                 int axis = (g_WS.qual & WS_QUAL_SHIFT) ? 1 : 0;
691                                                 ps->draw_flip[axis] = !ps->draw_flip[axis];
692                                         }
693                                         break;
694                                 }
695                                 case GHOST_kKey1:
696                                 case GHOST_kKeyNumpad1:
697                                         if (val) {
698                                                 swaptime = ps->fstep / 60.0;
699                                                 update_sound_fps();
700                                         }
701                                         break;
702                                 case GHOST_kKey2:
703                                 case GHOST_kKeyNumpad2:
704                                         if (val) {
705                                                 swaptime = ps->fstep / 50.0;
706                                                 update_sound_fps();
707                                         }
708                                         break;
709                                 case GHOST_kKey3:
710                                 case GHOST_kKeyNumpad3:
711                                         if (val) {
712                                                 swaptime = ps->fstep / 30.0;
713                                                 update_sound_fps();
714                                         }
715                                         break;
716                                 case GHOST_kKey4:
717                                 case GHOST_kKeyNumpad4:
718                                         if (g_WS.qual & WS_QUAL_SHIFT) {
719                                                 swaptime = ps->fstep / 24.0;
720                                                 update_sound_fps();
721                                         }
722                                         else {
723                                                 swaptime = ps->fstep / 25.0;
724                                                 update_sound_fps();
725                                         }
726                                         break;
727                                 case GHOST_kKey5:
728                                 case GHOST_kKeyNumpad5:
729                                         if (val) {
730                                                 swaptime = ps->fstep / 20.0;
731                                                 update_sound_fps();
732                                         }
733                                         break;
734                                 case GHOST_kKey6:
735                                 case GHOST_kKeyNumpad6:
736                                         if (val) {
737                                                 swaptime = ps->fstep / 15.0;
738                                                 update_sound_fps();
739                                         }
740                                         break;
741                                 case GHOST_kKey7:
742                                 case GHOST_kKeyNumpad7:
743                                         if (val) {
744                                                 swaptime = ps->fstep / 12.0;
745                                                 update_sound_fps();
746                                         }
747                                         break;
748                                 case GHOST_kKey8:
749                                 case GHOST_kKeyNumpad8:
750                                         if (val) {
751                                                 swaptime = ps->fstep / 10.0;
752                                                 update_sound_fps();
753                                         }
754                                         break;
755                                 case GHOST_kKey9:
756                                 case GHOST_kKeyNumpad9:
757                                         if (val) {
758                                                 swaptime = ps->fstep / 6.0;
759                                                 update_sound_fps();
760                                         }
761                                         break;
762                                 case GHOST_kKeyLeftArrow:
763                                         if (val) {
764                                                 ps->sstep = true;
765                                                 ps->wait2 = false;
766                                                 if (g_WS.qual & WS_QUAL_SHIFT) {
767                                                         ps->picture = picsbase.first;
768                                                         ps->next_frame = 0;
769                                                 }
770                                                 else {
771                                                         ps->next_frame = -1;
772                                                 }
773                                         }
774                                         break;
775                                 case GHOST_kKeyDownArrow:
776                                         if (val) {
777                                                 ps->wait2 = false;
778                                                 if (g_WS.qual & WS_QUAL_SHIFT) {
779                                                         ps->next_frame = ps->direction = -1;
780                                                 }
781                                                 else {
782                                                         ps->next_frame = -10;
783                                                         ps->sstep = true;
784                                                 }
785                                         }
786                                         break;
787                                 case GHOST_kKeyRightArrow:
788                                         if (val) {
789                                                 ps->sstep = true;
790                                                 ps->wait2 = false;
791                                                 if (g_WS.qual & WS_QUAL_SHIFT) {
792                                                         ps->picture = picsbase.last;
793                                                         ps->next_frame = 0;
794                                                 }
795                                                 else {
796                                                         ps->next_frame = 1;
797                                                 }
798                                         }
799                                         break;
800                                 case GHOST_kKeyUpArrow:
801                                         if (val) {
802                                                 ps->wait2 = false;
803                                                 if (g_WS.qual & WS_QUAL_SHIFT) {
804                                                         ps->next_frame = ps->direction = 1;
805                                                 }
806                                                 else {
807                                                         ps->next_frame = 10;
808                                                         ps->sstep = true;
809                                                 }
810                                         }
811                                         break;
812
813                                 case GHOST_kKeySlash:
814                                 case GHOST_kKeyNumpadSlash:
815                                         if (val) {
816                                                 if (g_WS.qual & WS_QUAL_SHIFT) {
817                                                         if (ps->curframe_ibuf)
818                                                                 printf(" Name: %s | Speed: %.2f frames/s\n",
819                                                                        ps->curframe_ibuf->name, ps->fstep / swaptime);
820                                                 }
821                                                 else {
822                                                         swaptime = ps->fstep / 5.0;
823                                                         update_sound_fps();
824                                                 }
825                                         }
826                                         break;
827                                 case GHOST_kKey0:
828                                 case GHOST_kKeyNumpad0:
829                                         if (val) {
830                                                 if (ps->once) {
831                                                         ps->once = ps->wait2 = false;
832                                                 }
833                                                 else {
834                                                         ps->picture = NULL;
835                                                         ps->once = true;
836                                                         ps->wait2 = false;
837                                                 }
838                                         }
839                                         break;
840
841                                 case GHOST_kKeySpace:
842                                         if (val) {
843                                                 if (ps->wait2 || ps->sstep) {
844                                                         ps->wait2 = ps->sstep = false;
845 #ifdef WITH_AUDASPACE
846                                                         {
847                                                                 PlayAnimPict *picture = picsbase.first;
848                                                                 /* TODO - store in ps direct? */
849                                                                 int i = 0;
850
851                                                                 while (picture && picture != ps->picture) {
852                                                                         i++;
853                                                                         picture = picture->next;
854                                                                 }
855                                                                 if (playback_handle)
856                                                                         AUD_Handle_stop(playback_handle);
857                                                                 playback_handle = AUD_Device_play(audio_device, source, 1);
858                                                                 if (playback_handle)
859                                                                         AUD_Handle_setPosition(playback_handle, i / fps_movie);
860                                                                 update_sound_fps();
861                                                         }
862 #endif
863                                                 }
864                                                 else {
865                                                         ps->sstep = true;
866                                                         ps->wait2 = true;
867 #ifdef WITH_AUDASPACE
868                                                         if (playback_handle) {
869                                                                 AUD_Handle_stop(playback_handle);
870                                                                 playback_handle = NULL;
871                                                         }
872 #endif
873                                                 }
874                                         }
875                                         break;
876                                 case GHOST_kKeyEnter:
877                                 case GHOST_kKeyNumpadEnter:
878                                         if (val) {
879                                                 ps->wait2 = ps->sstep = false;
880 #ifdef WITH_AUDASPACE
881                                                 {
882                                                         PlayAnimPict *picture = picsbase.first;
883                                                         /* TODO - store in ps direct? */
884                                                         int i = 0;
885                                                         while (picture && picture != ps->picture) {
886                                                                 i++;
887                                                                 picture = picture->next;
888                                                         }
889                                                         if (playback_handle)
890                                                                 AUD_Handle_stop(playback_handle);
891                                                         playback_handle = AUD_Device_play(audio_device, source, 1);
892                                                         if (playback_handle)
893                                                                 AUD_Handle_setPosition(playback_handle, i / fps_movie);
894                                                         update_sound_fps();
895                                                 }
896 #endif
897                                         }
898                                         break;
899                                 case GHOST_kKeyPeriod:
900                                 case GHOST_kKeyNumpadPeriod:
901                                         if (val) {
902                                                 if (ps->sstep) {
903                                                         ps->wait2 = false;
904                                                 }
905                                                 else {
906                                                         ps->sstep = true;
907                                                         ps->wait2 = !ps->wait2;
908 #ifdef WITH_AUDASPACE
909                                                         if (playback_handle) {
910                                                                 AUD_Handle_stop(playback_handle);
911                                                                 playback_handle = NULL;
912                                                         }
913 #endif
914                                                 }
915                                         }
916                                         break;
917                                 case GHOST_kKeyEqual:
918                                 case GHOST_kKeyPlus:
919                                 case GHOST_kKeyNumpadPlus:
920                                 {
921                                         if (val == 0) break;
922                                         if (g_WS.qual & WS_QUAL_CTRL) {
923                                                 playanim_window_zoom(ps, 1.0f);
924                                         }
925                                         else {
926                                                 if (swaptime > ps->fstep / 60.0) {
927                                                         swaptime /= 1.1;
928                                                         update_sound_fps();
929                                                 }
930                                         }
931                                         break;
932                                 }
933                                 case GHOST_kKeyMinus:
934                                 case GHOST_kKeyNumpadMinus:
935                                 {
936                                         if (val == 0) break;
937                                         if (g_WS.qual & WS_QUAL_CTRL) {
938                                                 playanim_window_zoom(ps, -1.0f);
939                                         }
940                                         else {
941                                                 if (swaptime < ps->fstep / 5.0) {
942                                                         swaptime *= 1.1;
943                                                         update_sound_fps();
944                                                 }
945                                         }
946                                         break;
947                                 }
948                                 case GHOST_kKeyEsc:
949                                         ps->go = false;
950                                         break;
951                                 default:
952                                         break;
953                         }
954                         break;
955                 }
956                 case GHOST_kEventButtonDown:
957                 case GHOST_kEventButtonUp:
958                 {
959                         GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
960                         int cx, cy, sizex, sizey, inside_window;
961
962                         GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy);
963                         GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy);
964                         playanim_window_get_size(&sizex, &sizey);
965
966                         inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
967
968                         if (bd->button == GHOST_kButtonMaskLeft) {
969                                 if (type == GHOST_kEventButtonDown) {
970                                         if (inside_window) {
971                                                 g_WS.qual |= WS_QUAL_LMOUSE;
972                                                 tag_change_frame(ps, cx);
973                                         }
974                                 }
975                                 else
976                                         g_WS.qual &= ~WS_QUAL_LMOUSE;
977                         }
978                         else if (bd->button == GHOST_kButtonMaskMiddle) {
979                                 if (type == GHOST_kEventButtonDown) {
980                                         if (inside_window)
981                                                 g_WS.qual |= WS_QUAL_MMOUSE;
982                                 }
983                                 else
984                                         g_WS.qual &= ~WS_QUAL_MMOUSE;
985                         }
986                         else if (bd->button == GHOST_kButtonMaskRight) {
987                                 if (type == GHOST_kEventButtonDown) {
988                                         if (inside_window)
989                                                 g_WS.qual |= WS_QUAL_RMOUSE;
990                                 }
991                                 else
992                                         g_WS.qual &= ~WS_QUAL_RMOUSE;
993                         }
994                         break;
995                 }
996                 case GHOST_kEventCursorMove:
997                 {
998                         if (g_WS.qual & WS_QUAL_LMOUSE) {
999                                 GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
1000                                 int cx, cy;
1001
1002                                 /* Ignore 'in-between' events, since they can make scrubbing lag.
1003                                  *
1004                                  * Ideally we would keep into the event queue and see if this is the last motion event.
1005                                  * however the API currently doesn't support this. */
1006                                 {
1007                                         int x_test, y_test;
1008                                         GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
1009                                         if (x_test != cd->x || y_test != cd->y) {
1010                                                 /* we're not the last event... skipping */
1011                                                 break;
1012                                         }
1013                                 }
1014
1015                                 GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
1016
1017                                 tag_change_frame(ps, cx);
1018                         }
1019                         break;
1020                 }
1021                 case GHOST_kEventWindowActivate:
1022                 case GHOST_kEventWindowDeactivate:
1023                 {
1024                         g_WS.qual &= ~WS_QUAL_MOUSE;
1025                         break;
1026                 }
1027                 case GHOST_kEventWindowSize:
1028                 case GHOST_kEventWindowMove:
1029                 {
1030                         float zoomx, zoomy;
1031
1032                         playanim_window_get_size(&ps->win_x, &ps->win_y);
1033                         GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
1034
1035                         zoomx = (float) ps->win_x / ps->ibufx;
1036                         zoomy = (float) ps->win_y / ps->ibufy;
1037
1038                         /* zoom always show entire image */
1039                         ps->zoom = MIN2(zoomx, zoomy);
1040
1041                         /* zoom steps of 2 for speed */
1042                         ps->zoom = floor(ps->zoom + 0.5f);
1043                         if (ps->zoom < 1.0f) ps->zoom = 1.0f;
1044
1045                         glViewport(0, 0, ps->win_x, ps->win_y);
1046                         glScissor(0, 0, ps->win_x, ps->win_y);
1047
1048                         playanim_gl_matrix();
1049
1050                         ptottime = 0.0;
1051                         playanim_toscreen(ps, ps->picture, ps->curframe_ibuf, ps->fontid, ps->fstep);
1052
1053                         break;
1054                 }
1055                 case GHOST_kEventQuit:
1056                 case GHOST_kEventWindowClose:
1057                 {
1058                         ps->go = false;
1059                         break;
1060                 }
1061                 case GHOST_kEventDraggingDropDone:
1062                 {
1063                         GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
1064
1065                         if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
1066                                 GHOST_TStringArray *stra = ddd->data;
1067                                 int a;
1068
1069                                 for (a = 0; a < stra->count; a++) {
1070                                         BLI_strncpy(ps->dropped_file, (char *)stra->strings[a], sizeof(ps->dropped_file));
1071                                         ps->go = false;
1072                                         printf("drop file %s\n", stra->strings[a]);
1073                                         break; /* only one drop element supported now */
1074                                 }
1075                         }
1076                         break;
1077                 }
1078                 default:
1079                         /* quiet warnings */
1080                         break;
1081         }
1082
1083         return 1;
1084 }
1085
1086 static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
1087 {
1088         GHOST_GLSettings glsettings = {0};
1089         GHOST_TUns32 scr_w, scr_h;
1090
1091         GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h);
1092
1093         posy = (scr_h - posy - sizey);
1094
1095         g_WS.ghost_window = GHOST_CreateWindow(g_WS.ghost_system,
1096                                                title,
1097                                                posx, posy, sizex, sizey,
1098                                                /* could optionally start fullscreen */
1099                                                GHOST_kWindowStateNormal,
1100                                                GHOST_kDrawingContextTypeOpenGL,
1101                                                glsettings);
1102 }
1103
1104 static void playanim_window_zoom(PlayState *ps, const float zoom_offset)
1105 {
1106         int sizex, sizey;
1107         /* int ofsx, ofsy; */ /* UNUSED */
1108
1109         if (ps->zoom + zoom_offset > 0.0f) ps->zoom += zoom_offset;
1110
1111         // playanim_window_get_position(&ofsx, &ofsy);
1112         playanim_window_get_size(&sizex, &sizey);
1113         /* ofsx += sizex / 2; */ /* UNUSED */
1114         /* ofsy += sizey / 2; */ /* UNUSED */
1115         sizex = ps->zoom * ps->ibufx;
1116         sizey = ps->zoom * ps->ibufy;
1117         /* ofsx -= sizex / 2; */ /* UNUSED */
1118         /* ofsy -= sizey / 2; */ /* UNUSED */
1119         // window_set_position(g_WS.ghost_window, sizex, sizey);
1120         GHOST_SetClientSize(g_WS.ghost_window, sizex, sizey);
1121 }
1122
1123 /* return path for restart */
1124 static char *wm_main_playanim_intern(int argc, const char **argv)
1125 {
1126         struct ImBuf *ibuf = NULL;
1127         static char filepath[FILE_MAX]; /* abused to return dropped file path */
1128         GHOST_TUns32 maxwinx, maxwiny;
1129         int i;
1130         /* This was done to disambiguate the name for use under c++. */
1131         int start_x = 0, start_y = 0;
1132         int sfra = -1;
1133         int efra = -1;
1134         int totblock;
1135
1136         PlayState ps = {0};
1137
1138         /* ps.doubleb   = true;*/ /* UNUSED */
1139         ps.go        = true;
1140         ps.direction = true;
1141         ps.next_frame = 1;
1142         ps.once      = false;
1143         ps.turbo     = false;
1144         ps.pingpong  = false;
1145         ps.noskip    = false;
1146         ps.sstep     = false;
1147         ps.wait2     = false;
1148         ps.stopped   = false;
1149         ps.loading   = false;
1150         ps.picture   = NULL;
1151         ps.indicator = false;
1152         ps.dropped_file[0] = 0;
1153         ps.zoom      = 1.0f;
1154         /* resetmap = false */
1155         ps.draw_flip[0] = false;
1156         ps.draw_flip[1] = false;
1157
1158         ps.fstep     = 1;
1159
1160         ps.fontid = -1;
1161
1162         while (argc > 1) {
1163                 if (argv[1][0] == '-') {
1164                         switch (argv[1][1]) {
1165                                 case 'm':
1166                                         fromdisk = true;
1167                                         break;
1168                                 case 'p':
1169                                         if (argc > 3) {
1170                                                 start_x = atoi(argv[2]);
1171                                                 start_y = atoi(argv[3]);
1172                                                 argc -= 2;
1173                                                 argv += 2;
1174                                         }
1175                                         else {
1176                                                 printf("too few arguments for -p (need 2): skipping\n");
1177                                         }
1178                                         break;
1179                                 case 'f':
1180                                         if (argc > 3) {
1181                                                 double fps = atof(argv[2]);
1182                                                 double fps_base = atof(argv[3]);
1183                                                 if (fps == 0.0) {
1184                                                         fps = 1;
1185                                                         printf("invalid fps,"
1186                                                                "forcing 1\n");
1187                                                 }
1188                                                 swaptime = fps_base / fps;
1189                                                 argc -= 2;
1190                                                 argv += 2;
1191                                         }
1192                                         else {
1193                                                 printf("too few arguments for -f (need 2): skipping\n");
1194                                         }
1195                                         break;
1196                                 case 's':
1197                                         sfra = atoi(argv[2]);
1198                                         CLAMP(sfra, 1, MAXFRAME);
1199                                         argc--;
1200                                         argv++;
1201                                         break;
1202                                 case 'e':
1203                                         efra = atoi(argv[2]);
1204                                         CLAMP(efra, 1, MAXFRAME);
1205                                         argc--;
1206                                         argv++;
1207                                         break;
1208                                 case 'j':
1209                                         ps.fstep = atoi(argv[2]);
1210                                         CLAMP(ps.fstep, 1, MAXFRAME);
1211                                         swaptime *= ps.fstep;
1212                                         argc--;
1213                                         argv++;
1214                                         break;
1215                                 default:
1216                                         printf("unknown option '%c': skipping\n", argv[1][1]);
1217                                         break;
1218                         }
1219                         argc--;
1220                         argv++;
1221                 }
1222                 else {
1223                         break;
1224                 }
1225         }
1226
1227         if (argc > 1) {
1228                 BLI_strncpy(filepath, argv[1], sizeof(filepath));
1229         }
1230         else {
1231                 printf("%s: no filepath argument given\n", __func__);
1232                 exit(1);
1233         }
1234
1235         if (IMB_isanim(filepath)) {
1236                 /* OCIO_TODO: support different input color spaces */
1237                 struct anim *anim;
1238                 anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
1239                 if (anim) {
1240                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
1241                         IMB_close_anim(anim);
1242                         anim = NULL;
1243                 }
1244         }
1245         else if (!IMB_ispic(filepath)) {
1246                 printf("%s: '%s' not an image file\n", __func__, filepath);
1247                 exit(1);
1248         }
1249
1250         if (ibuf == NULL) {
1251                 /* OCIO_TODO: support different input color space */
1252                 ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
1253         }
1254
1255         if (ibuf == NULL) {
1256                 printf("%s: '%s' couldn't open\n", __func__, filepath);
1257                 exit(1);
1258         }
1259
1260         {
1261
1262                 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
1263
1264                 g_WS.ghost_system = GHOST_CreateSystem();
1265                 GHOST_AddEventConsumer(g_WS.ghost_system, consumer);
1266
1267                 playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y);
1268
1269                 playanim_gl_matrix();
1270         }
1271
1272         GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);
1273
1274         //GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
1275
1276         /* initialize the font */
1277         BLF_init();
1278         ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
1279         BLF_size(ps.fontid, 11, 72);
1280
1281         ps.ibufx = ibuf->x;
1282         ps.ibufy = ibuf->y;
1283
1284         ps.win_x = ps.ibufx;
1285         ps.win_y = ps.ibufy;
1286
1287         if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
1288         if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
1289
1290
1291         glClearColor(0.1, 0.1, 0.1, 0.0);
1292         glClear(GL_COLOR_BUFFER_BIT);
1293
1294         GHOST_SwapWindowBuffers(g_WS.ghost_window);
1295
1296         if (sfra == -1 || efra == -1) {
1297                 /* one of the frames was invalid, just use all images */
1298                 sfra = 1;
1299                 efra = MAXFRAME;
1300         }
1301
1302         build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
1303
1304 #ifdef WITH_AUDASPACE
1305         source = AUD_Sound_file(filepath);
1306         {
1307                 struct anim *anim_movie = ((struct PlayAnimPict *)picsbase.first)->anim;
1308                 if (anim_movie) {
1309                         short frs_sec = 25;
1310                         float frs_sec_base = 1.0;
1311
1312                         IMB_anim_get_fps(anim_movie, &frs_sec, &frs_sec_base, true);
1313
1314                         fps_movie = (double) frs_sec / (double) frs_sec_base;
1315                         /* enforce same fps for movie as sound */
1316                         swaptime = ps.fstep / fps_movie;
1317                 }
1318         }
1319 #endif
1320
1321         for (i = 2; i < argc; i++) {
1322                 BLI_strncpy(filepath, argv[i], sizeof(filepath));
1323                 build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
1324         }
1325
1326         IMB_freeImBuf(ibuf);
1327         ibuf = NULL;
1328
1329         pupdate_time();
1330         ptottime = 0;
1331
1332         /* newly added in 2.6x, without this images never get freed */
1333 #define USE_IMB_CACHE
1334
1335         while (ps.go) {
1336                 if (ps.pingpong)
1337                         ps.direction = -ps.direction;
1338
1339                 if (ps.direction == 1) {
1340                         ps.picture = picsbase.first;
1341                 }
1342                 else {
1343                         ps.picture = picsbase.last;
1344                 }
1345
1346                 if (ps.picture == NULL) {
1347                         printf("couldn't find pictures\n");
1348                         ps.go = false;
1349                 }
1350                 if (ps.pingpong) {
1351                         if (ps.direction == 1) {
1352                                 ps.picture = ps.picture->next;
1353                         }
1354                         else {
1355                                 ps.picture = ps.picture->prev;
1356                         }
1357                 }
1358                 if (ptottime > 0.0) ptottime = 0.0;
1359
1360 #ifdef WITH_AUDASPACE
1361                 if (playback_handle)
1362                         AUD_Handle_stop(playback_handle);
1363                 playback_handle = AUD_Device_play(audio_device, source, 1);
1364                 update_sound_fps();
1365 #endif
1366
1367                 while (ps.picture) {
1368                         int hasevent;
1369 #ifndef USE_IMB_CACHE
1370                         if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
1371 #endif
1372                         if (ps.picture->ibuf) {
1373                                 ibuf = ps.picture->ibuf;
1374                         }
1375                         else if (ps.picture->anim) {
1376                                 ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
1377                         }
1378                         else if (ps.picture->mem) {
1379                                 /* use correct colorspace here */
1380                                 ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
1381                                                              ps.picture->IB_flags, NULL, ps.picture->name);
1382                         }
1383                         else {
1384                                 /* use correct colorspace here */
1385                                 ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags, NULL);
1386                         }
1387
1388                         if (ibuf) {
1389 #ifdef USE_FRAME_CACHE_LIMIT
1390                                 LinkData *node;
1391 #endif
1392
1393 #ifdef USE_IMB_CACHE
1394                                 ps.picture->ibuf = ibuf;
1395 #endif
1396
1397 #ifdef USE_FRAME_CACHE_LIMIT
1398                                 /* really basic memory conservation scheme. Keep frames in a fifo queue */
1399                                 node = inmempicsbase.last;
1400
1401                                 while (node && added_images > PLAY_FRAME_CACHE_MAX) {
1402                                         PlayAnimPict *pic = node->data;
1403
1404                                         if (pic->ibuf && pic->ibuf != ibuf) {
1405                                                 LinkData *node_tmp;
1406                                                 IMB_freeImBuf(pic->ibuf);
1407                                                 pic->ibuf = NULL;
1408                                                 node_tmp = node->prev;
1409                                                 BLI_freelinkN(&inmempicsbase, node);
1410                                                 added_images--;
1411                                                 node = node_tmp;
1412                                         }
1413                                         else {
1414                                                 node = node->prev;
1415                                         }
1416                                 }
1417
1418                                 BLI_addhead(&inmempicsbase, BLI_genericNodeN(ps.picture));
1419                                 added_images++;
1420 #endif  /* USE_FRAME_CACHE_LIMIT */
1421
1422                                 BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));
1423
1424                                 /* why only windows? (from 2.4x) - campbell */
1425 #ifdef _WIN32
1426                                 GHOST_SetTitle(g_WS.ghost_window, ps.picture->name);
1427 #endif
1428
1429                                 while (pupdate_time()) PIL_sleep_ms(1);
1430                                 ptottime -= swaptime;
1431                                 playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
1432                         } /* else delete */
1433                         else {
1434                                 printf("error: can't play this image type\n");
1435                                 exit(0);
1436                         }
1437
1438                         if (ps.once) {
1439                                 if (ps.picture->next == NULL) {
1440                                         ps.wait2 = true;
1441                                 }
1442                                 else if (ps.picture->prev == NULL) {
1443                                         ps.wait2 = true;
1444                                 }
1445                         }
1446
1447                         ps.next_frame = ps.direction;
1448
1449                         while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
1450                                 GHOST_DispatchEvents(g_WS.ghost_system);
1451                         }
1452                         if (ps.go == false) {
1453                                 break;
1454                         }
1455                         change_frame(&ps);
1456                         if (!hasevent) {
1457                                 PIL_sleep_ms(1);
1458                         }
1459                         if (ps.wait2) {
1460                                 continue;
1461                         }
1462
1463                         ps.wait2 = ps.sstep;
1464
1465                         if (ps.wait2 == false && ps.stopped == false) {
1466                                 ps.stopped = true;
1467                         }
1468
1469                         pupdate_time();
1470
1471                         if (ps.picture && ps.next_frame) {
1472                                 /* always at least set one step */
1473                                 while (ps.picture) {
1474                                         ps.picture = playanim_step(ps.picture, ps.next_frame);
1475
1476                                         if (ps.once && ps.picture != NULL) {
1477                                                 if (ps.picture->next == NULL) {
1478                                                         ps.wait2 = true;
1479                                                 }
1480                                                 else if (ps.picture->prev == NULL) {
1481                                                         ps.wait2 = true;
1482                                                 }
1483                                         }
1484
1485                                         if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
1486                                         ptottime -= swaptime;
1487                                 }
1488                                 if (ps.picture == NULL && ps.sstep) {
1489                                         ps.picture = playanim_step(ps.picture, ps.next_frame);
1490                                 }
1491                         }
1492                         if (ps.go == false) {
1493                                 break;
1494                         }
1495                 }
1496         }
1497         while ((ps.picture = BLI_pophead(&picsbase))) {
1498                 if (ps.picture->anim) {
1499                         if ((ps.picture->next == NULL) ||
1500                             (ps.picture->next->anim != ps.picture->anim))
1501                         {
1502                                 IMB_close_anim(ps.picture->anim);
1503                         }
1504                 }
1505
1506                 if (ps.picture->ibuf) {
1507                         IMB_freeImBuf(ps.picture->ibuf);
1508                 }
1509                 if (ps.picture->mem) {
1510                         MEM_freeN(ps.picture->mem);
1511                 }
1512
1513                 MEM_freeN((void *)ps.picture->name);
1514                 MEM_freeN(ps.picture);
1515         }
1516
1517         /* cleanup */
1518 #ifndef USE_IMB_CACHE
1519         if (ibuf) IMB_freeImBuf(ibuf);
1520 #endif
1521
1522         BLI_freelistN(&picsbase);
1523         BLI_freelistN(&inmempicsbase);
1524         added_images = 0;
1525
1526 #ifdef WITH_AUDASPACE
1527         if (playback_handle) {
1528                 AUD_Handle_stop(playback_handle);
1529                 playback_handle = NULL;
1530         }
1531         if (scrub_handle) {
1532                 AUD_Handle_stop(scrub_handle);
1533                 scrub_handle = NULL;
1534         }
1535         AUD_Sound_free(source);
1536         source = NULL;
1537 #endif
1538         /* we still miss freeing a lot!,
1539          * but many areas could skip initialization too for anim play */
1540
1541         BLF_exit();
1542
1543         GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
1544
1545         /* early exit, IMB and BKE should be exited only in end */
1546         if (ps.dropped_file[0]) {
1547                 BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
1548                 return filepath;
1549         }
1550
1551         IMB_exit();
1552         BKE_images_exit();
1553         DAG_exit();
1554
1555         totblock = MEM_get_memory_blocks_in_use();
1556         if (totblock != 0) {
1557                 /* prints many bAKey, bArgument's which are tricky to fix */
1558 #if 0
1559                 printf("Error Totblock: %d\n", totblock);
1560                 MEM_printmemlist();
1561 #endif
1562         }
1563
1564         return NULL;
1565 }
1566
1567
1568 void WM_main_playanim(int argc, const char **argv)
1569 {
1570         const char *argv_next[2];
1571         bool looping = true;
1572
1573 #ifdef WITH_AUDASPACE
1574         {
1575                 AUD_DeviceSpecs specs;
1576
1577                 specs.rate = AUD_RATE_48000;
1578                 specs.format = AUD_FORMAT_S16;
1579                 specs.channels = AUD_CHANNELS_STEREO;
1580
1581                 AUD_initOnce();
1582
1583                 if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender"))) {
1584                         audio_device = AUD_init("Null", specs, 0, "Blender");
1585                 }
1586         }
1587 #endif
1588
1589         while (looping) {
1590                 const char *filepath = wm_main_playanim_intern(argc, argv);
1591
1592                 if (filepath) { /* use simple args */
1593                         argv_next[0] = argv[0];
1594                         argv_next[1] = filepath;
1595                         argc = 2;
1596
1597                         /* continue with new args */
1598                         argv = argv_next;
1599                 }
1600                 else {
1601                         looping = false;
1602                 }
1603         }
1604
1605 #ifdef WITH_AUDASPACE
1606         AUD_exit(audio_device);
1607         AUD_exitOnce();
1608 #endif
1609 }