update playanim for 2.6x, playback works, events don't.
[blender.git] / source / blender / windowmanager / intern / wm_playanim.c
1 /**
2  * $Id: playanim.c 17755 2008-12-09 04:57:42Z bdiego $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #include <sys/times.h>
42 #include <sys/wait.h>
43 #else
44 #include <io.h>
45 #endif
46 #include "MEM_guardedalloc.h"
47
48 #include "PIL_time.h"
49
50 #include <math.h>
51
52 #include "BLI_blenlib.h"
53 #include "BLI_math.h"
54
55 #include "IMB_imbuf_types.h"
56 #include "IMB_imbuf.h"
57
58 #include "BKE_blender.h"
59 #include "BKE_global.h"
60 #include "BKE_utildefines.h"
61
62 #include "BIF_gl.h"
63 #include "BIF_glutil.h"
64
65 #ifdef WITH_QUICKTIME
66 #ifdef _WIN32
67 #include <QTML.h>
68 #include <Movies.h>
69 #elif defined(__APPLE__)
70 #include <QuickTime/Movies.h>
71 #endif /* __APPLE__ */
72 #endif /* WITH_QUICKTIME */
73
74 #include "DNA_scene_types.h"
75 #include "BLI_utildefines.h"
76 #include "wm_event_types.h"
77 #include "GHOST_C-api.h"
78
79 #define WINCLOSE -1
80 #define REDRAW -3
81 #define RESHAPE -2
82 #define WINQUIT -4
83
84 static int qtest(void)
85 {
86         return 0;
87 }
88
89 /* ***************** gl_util.c ****************** */
90
91 static GHOST_SystemHandle g_system = NULL;
92 static void *g_window = NULL;
93
94 static int qualN = 0;
95
96 #define LSHIFT  (1 << 0)
97 #define RSHIFT  (1 << 1)
98 #define SHIFT   (LSHIFT | RSHIFT)
99 #define LALT    (1 << 2)
100 #define RALT    (1 << 3)
101 #define ALT (LALT | RALT)
102 #define LCTRL   (1 << 4)
103 #define RCTRL   (1 << 5)
104 #define LMOUSE  (1 << 16)
105 #define MMOUSE  (1 << 17)
106 #define RMOUSE  (1 << 18)
107 #define MOUSE   (LMOUSE | MMOUSE | RMOUSE)
108
109 unsigned short screen_qread(short *val, char *ascii);
110
111 void playanim_window_get_size(int *width_r, int *height_r)
112 {
113         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_window);
114         *width_r = GHOST_GetWidthRectangle(bounds);
115         *height_r = GHOST_GetHeightRectangle(bounds);
116         GHOST_DisposeRectangle(bounds);
117 }
118
119 /* implementation */
120 static int qreadN(short *val)
121 {
122 #if 0 // XXX25
123         char ascii;
124         int event = screen_qread(val, &ascii);
125 #else
126         int event = 123456789;
127 #endif
128
129         switch (event) {
130                 case LEFTMOUSE:
131                         if (*val) qualN |= LMOUSE;
132                         else qualN &= ~LMOUSE;
133                         break;
134                 case MIDDLEMOUSE:
135                         if (*val) qualN |= MMOUSE;
136                         else qualN &= ~MMOUSE;
137                         break;
138                 case RIGHTMOUSE:
139                         if (*val) qualN |= RMOUSE;
140                         else qualN &= ~RMOUSE;
141                         break;
142                 case LEFTSHIFTKEY:
143                         if (*val) qualN |= LSHIFT;
144                         else qualN &= ~LSHIFT;
145                         break;
146                 case RIGHTSHIFTKEY:
147                         if (*val) qualN |= RSHIFT;
148                         else qualN &= ~RSHIFT;
149                         break;
150                 case LEFTCTRLKEY:
151                         if (*val) qualN |= LCTRL;
152                         else qualN &= ~LCTRL;
153                         break;
154                 case RIGHTCTRLKEY:
155                         if (*val) qualN |= RCTRL;
156                         else qualN &= ~RCTRL;
157                         break;
158                 case LEFTALTKEY:
159                         if (*val) qualN |= LALT;
160                         else qualN &= ~LALT;
161                         break;
162                 case RIGHTALTKEY:
163                         if (*val) qualN |= RALT;
164                         else qualN &= ~RALT;
165                         break;
166         }
167
168         return(event);
169 }
170
171 /* ***************** gl_util.c ****************** */
172
173
174
175
176 typedef struct pict {
177         struct pict *next, *prev;
178         char *mem;
179         int size;
180         char *name;
181         struct ImBuf *ibuf;
182         struct anim *anim;
183         int frame;
184         int IB_flags;
185 }Pict;
186
187 static struct ListBase _picsbase = {0, 0};
188 static struct ListBase *picsbase = &_picsbase;
189 static int fromdisk = FALSE;
190 static int fstep = 1;
191 static float zoomx = 1.0, zoomy = 1.0;
192 static double ptottime = 0.0, swaptime = 0.04;
193
194 static int pupdate_time(void)
195 {
196         static double ltime;
197         double time;
198
199         time = PIL_check_seconds_timer();
200
201         ptottime += (time - ltime);
202         ltime = time;
203         return (ptottime < 0);
204 }
205
206 static void toscreen(Pict *picture, struct ImBuf *ibuf)
207 {
208
209         if (ibuf == 0) {
210                 printf("no ibuf !\n");
211                 return;
212         }
213         if (ibuf->rect == NULL && ibuf->rect_float) {
214                 IMB_rect_from_float(ibuf);
215                 imb_freerectfloatImBuf(ibuf);
216         }
217         if (ibuf->rect == NULL)
218                 return;
219
220         glRasterPos2f(0.0f, 0.0f);
221
222         glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
223
224         pupdate_time();
225
226         if (picture && (qualN & (SHIFT | LMOUSE))) {
227                 char str[512];
228                 cpack(-1);
229                 glRasterPos2f(0.02f,  0.03f);
230                 sprintf(str, "%s | %.2f frames/s\n", picture->name, fstep / swaptime);
231 #if 0 // XXX25
232                 BMF_DrawString(G.fonts, str);
233 #endif
234         }
235
236         GHOST_SwapWindowBuffers(g_window);
237 }
238
239 static void build_pict_list(char *first, int totframes, int fstep)
240 {
241         int size, pic, file;
242         char *mem, name[512];
243 //      short val;
244         struct pict *picture = 0;
245         struct ImBuf *ibuf = 0;
246         int count = 0;
247         char str[512];
248         struct anim *anim;
249
250         if (IMB_isanim(first)) {
251                 anim = IMB_open_anim(first, IB_rect, 0);
252                 if (anim) {
253                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
254                         if (ibuf) {
255                                 toscreen(NULL, ibuf);
256                                 IMB_freeImBuf(ibuf);
257                         }
258
259                         for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
260                                 picture = (Pict *)MEM_callocN(sizeof(Pict), "Pict");
261                                 picture->anim = anim;
262                                 picture->frame = pic;
263                                 picture->IB_flags = IB_rect;
264                                 sprintf(str, "%s : %d", first, pic + 1);
265                                 picture->name = strdup(str);
266                                 BLI_addtail(picsbase, picture);
267                         }
268                 }
269                 else printf("couldn't open anim %s\n", first);
270         }
271         else {
272
273                 strcpy(name, first);
274
275                 pupdate_time();
276                 ptottime = 1.0;
277
278 /*
279      O_DIRECT
280             If set, all reads and writes on the resulting file descriptor will
281             be performed directly to or from the user program buffer, provided
282             appropriate size and alignment restrictions are met.  Refer to the
283             F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
284             information about how to determine the alignment constraints.
285             O_DIRECT is a Silicon Graphics extension and is only supported on
286             local EFS and XFS file systems.
287  */
288
289                 while (IMB_ispic(name) && totframes) {
290                         file = open(name, O_BINARY | O_RDONLY, 0);
291                         if (file < 0) return;
292                         picture = (struct pict *)MEM_callocN(sizeof(struct pict), "picture");
293                         if (picture == 0) {
294                                 printf("Not enough memory for pict struct \n");
295                                 close(file);
296                                 return;
297                         }
298                         size = BLI_file_descriptor_size(file);
299
300                         if (size < 1) {
301                                 close(file);
302                                 MEM_freeN(picture);
303                                 return;
304                         }
305
306                         picture->size = size;
307                         picture->IB_flags = IB_rect;
308
309                         if (fromdisk == FALSE) {
310                                 mem = (char *)MEM_mallocN(size, "build pic list");
311                                 if (mem == 0) {
312                                         printf("Couldn't get memory\n");
313                                         close(file);
314                                         MEM_freeN(picture);
315                                         return;
316                                 }
317
318                                 if (read(file, mem, size) != size) {
319                                         printf("Error while reading %s\n", name);
320                                         close(file);
321                                         MEM_freeN(picture);
322                                         MEM_freeN(mem);
323                                         return;
324                                 }
325                         }
326                         else mem = 0;
327
328                         picture->mem = mem;
329                         picture->name = strdup(name);
330                         close(file);
331                         BLI_addtail(picsbase, picture);
332                         count++;
333
334                         pupdate_time();
335
336                         if (ptottime > 1.0) {
337                                 if (picture->mem) ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size, picture->IB_flags, picture->name);
338                                 else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
339                                 if (ibuf) {
340                                         toscreen(picture, ibuf);
341                                         IMB_freeImBuf(ibuf);
342                                 }
343                                 pupdate_time();
344                                 ptottime = 0.0;
345                         }
346
347                         BLI_newname(name, +fstep);
348
349 #if 0 // XXX25
350                         while (qtest()) {
351                                 switch (qreadN(&val)) {
352                                         case ESCKEY:
353                                                 if (val) return;
354                                                 break;
355                                 }
356                         }
357 #endif
358                         totframes--;
359                 }
360         }
361         return;
362 }
363
364 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
365 {
366         (void)evt;
367         (void)C_void_ptr;
368
369         return 1;
370 }
371
372 void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
373 {
374         GHOST_TWindowState inital_state;
375         GHOST_TUns32 scr_w, scr_h;
376
377         GHOST_GetMainDisplayDimensions(g_system, &scr_w, &scr_h);
378
379         posy = (scr_h - posy - sizey);
380
381         if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
382                 inital_state = start_maximized ? GHOST_kWindowStateFullScreen : GHOST_kWindowStateNormal;
383         else
384                 inital_state = start_maximized ? GHOST_kWindowStateMaximized : GHOST_kWindowStateNormal;
385 #ifdef __APPLE__
386         inital_state += macPrefState;
387 #endif
388
389         g_window = GHOST_CreateWindow(g_system,
390                                       title,
391                                       posx, posy, sizex, sizey,
392                                       inital_state,
393                                       GHOST_kDrawingContextTypeOpenGL,
394                                       FALSE /* no stereo */, FALSE);
395
396         //if (ghostwin) {
397         //if (win) {
398         // GHOST_SetWindowUserData(ghostwin, win);
399         //} else {
400         //      GHOST_DisposeWindow(g_system, ghostwin);
401         //}
402         //}
403 }
404
405
406 void playanim(int argc, const char **argv)
407 {
408         struct ImBuf *ibuf = 0;
409         struct pict *picture = 0;
410         char name[512];
411         short val = 0, go = TRUE, ibufx = 0, ibufy = 0;
412         int event, stopped = FALSE;
413         GHOST_TUns32 maxwinx, maxwiny;
414         short /*  c233 = FALSE, */ /*  yuvx = FALSE, */ once = FALSE, sstep = FALSE, wait2 = FALSE, /*  resetmap = FALSE, */ pause = 0;
415         short pingpong = FALSE, direction = 1, next = 1, turbo = FALSE, /*  doubleb = TRUE, */ noskip = FALSE;
416         int sizex, sizey, ofsx, ofsy, i;
417         /* This was done to disambiguate the name for use under c++. */
418         struct anim *anim = 0;
419         int start_x = 0, start_y = 0;
420         int sfra = -1;
421         int efra = -1;
422         int totblock;
423
424         while (argc > 1) {
425                 if (argv[1][0] == '-') {
426                         switch (argv[1][1]) {
427                                 case 'm':
428                                         fromdisk = TRUE;
429                                         break;
430                                 case 'p':
431                                         if (argc > 3) {
432                                                 start_x = atoi(argv[2]);
433                                                 start_y = atoi(argv[3]);
434                                                 argc -= 2;
435                                                 argv += 2;
436                                         }
437                                         else {
438                                                 printf("too few arguments for -p (need 2): skipping\n");
439                                         }
440                                         break;
441                                 case 'f':
442                                         if (argc > 3) {
443                                                 double fps = atof(argv[2]);
444                                                 double fps_base = atof(argv[3]);
445                                                 if (fps == 0) {
446                                                         fps = 1;
447                                                         printf("invalid fps,"
448                                                                "forcing 1\n");
449                                                 }
450                                                 swaptime = fps_base / fps;
451                                                 argc -= 2;
452                                                 argv += 2;
453                                         }
454                                         else {
455                                                 printf("too few arguments for -f (need 2): skipping\n");
456                                         }
457                                         break;
458                                 case 's':
459                                         sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
460                                         argc--;
461                                         argv++;
462                                         break;
463                                 case 'e':
464                                         efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
465                                         argc--;
466                                         argv++;
467                                         break;
468                                 case 'j':
469                                         fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
470                                         swaptime *= fstep;
471                                         argc--;
472                                         argv++;
473                                         break;
474                                 default:
475                                         printf("unknown option '%c': skipping\n", argv[1][1]);
476                                         break;
477                         }
478                         argc--;
479                         argv++;
480                 }
481                 else break;
482         }
483
484 #ifdef WITH_QUICKTIME
485 #if defined(_WIN32) || defined(__APPLE__)
486         /* Initialize QuickTime */
487 #ifndef noErr
488 #define noErr 0
489 #endif
490
491 #ifdef _WIN32
492         if (InitializeQTML(0) != noErr)
493                 G.have_quicktime = FALSE;
494         else
495                 G.have_quicktime = TRUE;
496 #endif /* _WIN32 */
497         if (EnterMovies() != noErr)
498                 G.have_quicktime = FALSE;
499         else
500 #endif /* _WIN32 || __APPLE__ */
501         G.have_quicktime = TRUE;
502 #endif /* WITH_QUICKTIME */
503
504         if (argc > 1) strcpy(name, argv[1]);
505         else {
506                 BLI_current_working_dir(name, sizeof(name));
507                 if (name[strlen(name) - 1] != '/') strcat(name, "/");
508         }
509
510         if (IMB_isanim(name)) {
511                 anim = IMB_open_anim(name, IB_rect, 0);
512                 if (anim) {
513                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
514                         IMB_close_anim(anim);
515                         anim = NULL;
516                 }
517         }
518         else if (!IMB_ispic(name)) {
519                 exit(1);
520         }
521
522         if (ibuf == 0) ibuf = IMB_loadiffname(name, IB_rect);
523         if (ibuf == 0) {
524                 printf("couldn't open %s\n", name);
525                 exit(1);
526         }
527
528 #if 0 //XXX25
529         #if !defined(WIN32) && !defined(__APPLE__)
530         if (fork()) exit(0);
531         #endif
532 #endif //XXX25
533
534         /* XXX, fixme zr */
535         {
536 //              extern void add_to_mainqueue(wmWindow *win, void *user_data, short evt, short val, char ascii);
537
538                 void *some_handle = NULL; // XXX25, fixme
539                 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, some_handle);
540
541                 g_system = GHOST_CreateSystem();
542                 GHOST_AddEventConsumer(g_system, consumer);
543
544
545
546                 playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
547 //XXX25         window_set_handler(g_window, add_to_mainqueue, NULL);
548
549                 glMatrixMode(GL_PROJECTION);
550                 glLoadIdentity();
551                 glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
552                 glMatrixMode(GL_MODELVIEW);
553         }
554
555         GHOST_GetMainDisplayDimensions(g_system, &maxwinx, &maxwiny);
556
557 #if 0 //XXX25
558         G.fonts = BMF_GetFont(BMF_kHelvetica10);
559 #endif
560
561         ibufx = ibuf->x;
562         ibufy = ibuf->y;
563
564         if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
565         if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
566
567         glClearColor(0.0, 0.0, 0.0, 0.0);
568         glClear(GL_COLOR_BUFFER_BIT);
569
570         GHOST_SwapWindowBuffers(g_window);
571
572         if (sfra == -1 || efra == -1) {
573                 /* one of the frames was invalid, just use all images */
574                 sfra = 1;
575                 efra = MAXFRAME;
576         }
577
578         build_pict_list(name, (efra - sfra) + 1, fstep);
579
580         for (i = 2; i < argc; i++) {
581                 strcpy(name, argv[i]);
582                 build_pict_list(name, (efra - sfra) + 1, fstep);
583         }
584
585         IMB_freeImBuf(ibuf);
586         ibuf = 0;
587
588         pupdate_time();
589         ptottime = 0;
590
591         while (go) {
592                 if (pingpong) direction = -direction;
593
594                 if (direction == 1) picture = picsbase->first;
595                 else picture = picsbase->last;
596
597                 if (picture == 0) {
598                         printf("couldn't find pictures\n");
599                         go = FALSE;
600                 }
601                 if (pingpong) {
602                         if (direction == 1) picture = picture->next;
603                         else picture = picture->prev;
604                 }
605                 if (ptottime > 0.0) ptottime = 0.0;
606
607                 while (picture) {
608                         if (ibuf != 0 && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
609
610                         if (picture->ibuf) ibuf = picture->ibuf;
611                         else if (picture->anim) ibuf = IMB_anim_absolute(picture->anim, picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
612                         else if (picture->mem) ibuf = IMB_ibImageFromMemory((unsigned char *) picture->mem, picture->size, picture->IB_flags, picture->name);
613                         else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
614
615                         if (ibuf) {
616                                 strcpy(ibuf->name, picture->name);
617
618 #ifdef _WIN32
619                                 window_set_title(g_window, picture->name);
620 #endif
621
622                                 while (pupdate_time()) PIL_sleep_ms(1);
623                                 ptottime -= swaptime;
624                                 toscreen(picture, ibuf);
625                         } /* else deleten */
626                         else {
627                                 printf("error: can't play this image type\n");
628                                 exit(0);
629                         }
630
631                         if (once) {
632                                 if (picture->next == 0) wait2 = TRUE;
633                                 else if (picture->prev == 0) wait2 = TRUE;
634                         }
635
636                         next = direction;
637
638                         while ((qtest() != 0) || (wait2 != 0)) {
639                                 if (wait2 && stopped) {
640                                         stopped = FALSE;
641                                 }
642
643                                 event = qreadN(&val);
644                                 /* printf("%d %d\n", event, val); */
645
646                                 if (wait2) {
647                                         pupdate_time();
648                                         ptottime = 0;
649                                 }
650                                 switch (event) {
651                                         case AKEY:
652                                                 if (val)
653                                                         noskip = !noskip;
654                                                 break;
655                                         case PKEY:
656                                                 if (val)
657                                                         pingpong = !pingpong;
658                                                 break;
659                                         case SLASHKEY:
660                                                 if (val) {
661                                                         if (qualN & SHIFT) {
662                                                                 if (ibuf)
663                                                                         printf(" Name: %s | Speed: %.2f frames/s\n", ibuf->name, fstep / swaptime);
664                                                         }
665                                                         else {
666                                                                 swaptime = fstep / 5.0;
667                                                         }
668                                                 }
669                                                 break;
670                                         case LEFTARROWKEY:
671                                                 if (val) {
672                                                         sstep = TRUE;
673                                                         wait2 = FALSE;
674                                                         if (qualN & SHIFT) {
675                                                                 picture = picsbase->first;
676                                                                 next = 0;
677                                                         }
678                                                         else {
679                                                                 next = -1;
680                                                         }
681                                                 }
682                                                 break;
683                                         case DOWNARROWKEY:
684                                                 if (val) {
685                                                         wait2 = FALSE;
686                                                         if (qualN & SHIFT) {
687                                                                 next = direction = -1;
688                                                         }
689                                                         else {
690                                                                 next = -10;
691                                                                 sstep = TRUE;
692                                                         }
693                                                 }
694                                                 break;
695                                         case RIGHTARROWKEY:
696                                                 if (val) {
697                                                         sstep = TRUE;
698                                                         wait2 = FALSE;
699                                                         if (qualN & SHIFT) {
700                                                                 picture = picsbase->last;
701                                                                 next = 0;
702                                                         }
703                                                         else {
704                                                                 next = 1;
705                                                         }
706                                                 }
707                                                 break;
708                                         case UPARROWKEY:
709                                                 if (val) {
710                                                         wait2 = FALSE;
711                                                         if (qualN & SHIFT) {
712                                                                 next = direction = 1;
713                                                         }
714                                                         else {
715                                                                 next = 10;
716                                                                 sstep = TRUE;
717                                                         }
718                                                 }
719                                                 break;
720                                         case LEFTMOUSE:
721                                         case MOUSEX:
722                                                 if (qualN & LMOUSE) {
723                                                         playanim_window_get_size(&sizex, &sizey);
724                                                         picture = picsbase->first;
725                                                         i = 0;
726                                                         while (picture) {
727                                                                 i++;
728                                                                 picture = picture->next;
729                                                         }
730                                                         i = (i * val) / sizex;
731                                                         picture = picsbase->first;
732                                                         for (; i > 0; i--) {
733                                                                 if (picture->next == 0) break;
734                                                                 picture = picture->next;
735                                                         }
736                                                         sstep = TRUE;
737                                                         wait2 = FALSE;
738                                                         next = 0;
739                                                 }
740                                                 break;
741                                                 go = FALSE;
742                                                 break;
743                                         case EQUALKEY:
744                                                 if (val) {
745                                                         if (qualN & SHIFT) {
746                                                                 pause++;
747                                                                 printf("pause:%d\n", pause);
748                                                         }
749                                                         else swaptime /= 1.1;
750                                                 }
751                                                 break;
752                                         case MINUSKEY:
753                                                 if (val) {
754                                                         if (qualN & SHIFT) {
755                                                                 pause--;
756                                                                 printf("pause:%d\n", pause);
757                                                         }
758                                                         else swaptime *= 1.1;
759                                                 }
760                                                 break;
761                                         case PAD0:
762                                                 if (val) {
763                                                         if (once) once = wait2 = FALSE;
764                                                         else {
765                                                                 picture = 0;
766                                                                 once = TRUE;
767                                                                 wait2 = FALSE;
768                                                         }
769                                                 }
770                                                 break;
771                                         case RETKEY:
772                                         case PADENTER:
773                                                 if (val) {
774                                                         wait2 = sstep = FALSE;
775                                                 }
776                                                 break;
777                                         case PADPERIOD:
778                                                 if (val) {
779                                                         if (sstep) wait2 = FALSE;
780                                                         else {
781                                                                 sstep = TRUE;
782                                                                 wait2 = !wait2;
783                                                         }
784                                                 }
785                                                 break;
786                                         case PAD1:
787                                                 swaptime = fstep / 60.0;
788                                                 break;
789                                         case PAD2:
790                                                 swaptime = fstep / 50.0;
791                                                 break;
792                                         case PAD3:
793                                                 swaptime = fstep / 30.0;
794                                                 break;
795                                         case PAD4:
796                                                 if (qualN & SHIFT)
797                                                         swaptime = fstep / 24.0;
798                                                 else
799                                                         swaptime = fstep / 25.0;
800                                                 break;
801                                         case PAD5:
802                                                 swaptime = fstep / 20.0;
803                                                 break;
804                                         case PAD6:
805                                                 swaptime = fstep / 15.0;
806                                                 break;
807                                         case PAD7:
808                                                 swaptime = fstep / 12.0;
809                                                 break;
810                                         case PAD8:
811                                                 swaptime = fstep / 10.0;
812                                                 break;
813                                         case PAD9:
814                                                 swaptime = fstep / 6.0;
815                                                 break;
816                                         case PADPLUSKEY:
817                                                 if (val == 0) break;
818                                                 zoomx += 2.0;
819                                                 zoomy += 2.0;
820                                         case PADMINUS:
821                                                 if (val == 0) break;
822                                                 if (zoomx > 1.0) zoomx -= 1.0;
823                                                 if (zoomy > 1.0) zoomy -= 1.0;
824                                                 // playanim_window_get_position(&ofsx, &ofsy);
825                                                 playanim_window_get_size(&sizex, &sizey);
826                                                 ofsx += sizex / 2;
827                                                 ofsy += sizey / 2;
828                                                 sizex = zoomx * ibufx;
829                                                 sizey = zoomy * ibufy;
830                                                 ofsx -= sizex / 2;
831                                                 ofsy -= sizey / 2;
832                                                 // window_set_position(g_window,sizex,sizey);
833                                                 GHOST_SetClientSize(g_window, sizex, sizey);
834                                                 break;
835                                         case RESHAPE:
836                                         case REDRAW:
837                                                 playanim_window_get_size(&sizey, &sizey);
838                                                 GHOST_ActivateWindowDrawingContext(g_window);
839
840                                                 glViewport(0,  0, sizex, sizey);
841                                                 glScissor(0,  0, sizex, sizey);
842
843                                                 zoomx = (float) sizex / ibufx;
844                                                 zoomy = (float) sizey / ibufy;
845                                                 zoomx = floor(zoomx + 0.5);
846                                                 zoomy = floor(zoomy + 0.5);
847                                                 if (zoomx < 1.0) zoomx = 1.0;
848                                                 if (zoomy < 1.0) zoomy = 1.0;
849
850                                                 sizex = zoomx * ibufx;
851                                                 sizey = zoomy * ibufy;
852
853                                                 glPixelZoom(zoomx, zoomy);
854                                                 glEnable(GL_DITHER);
855                                                 ptottime = 0.0;
856                                                 toscreen(picture, ibuf);
857                                                 while (qtest()) qreadN(&val);
858
859                                                 break;
860                                         case ESCKEY:
861                                         case WINCLOSE:
862                                         case WINQUIT:
863                                                 go = FALSE;
864                                                 break;
865                                 }
866                                 if (go == FALSE) break;
867                         }
868
869                         wait2 = sstep;
870
871                         if (wait2 == 0 && stopped == 0) {
872                                 stopped = TRUE;
873                         }
874
875                         pupdate_time();
876
877                         if (picture && next) {
878                                 /* always at least set one step */
879                                 while (picture) {
880                                         if (next < 0) picture = picture->prev;
881                                         else picture = picture->next;
882
883                                         if (once && picture != 0) {
884                                                 if (picture->next == 0) wait2 = TRUE;
885                                                 else if (picture->prev == 0) wait2 = TRUE;
886                                         }
887
888                                         if (wait2 || ptottime < swaptime || turbo || noskip) break;
889                                         ptottime -= swaptime;
890                                 }
891                                 if (picture == 0 && sstep) {
892                                         if (next < 0) picture = picsbase->last;
893                                         else if (next > 0) picture = picsbase->first;
894                                 }
895                         }
896                         if (go == FALSE) break;
897                 }
898         }
899         picture = picsbase->first;
900         anim = NULL;
901         while (picture) {
902                 if (picture && picture->anim && (anim != picture->anim)) {
903                         // to prevent divx crashes
904                         anim = picture->anim;
905                         IMB_close_anim(anim);
906                 }
907                 if (picture->ibuf) IMB_freeImBuf(picture->ibuf);
908                 if (picture->mem) MEM_freeN(picture->mem);
909
910                 picture = picture->next;
911         }
912 #ifdef WITH_QUICKTIME
913 #if defined(_WIN32) || defined(__APPLE__)
914         if (G.have_quicktime) {
915                 ExitMovies();
916 #ifdef _WIN32
917                 TerminateQTML();
918 #endif /* _WIN32 */
919         }
920 #endif /* _WIN32 || __APPLE__ */
921 #endif /* WITH_QUICKTIME */
922
923         /* cleanup */
924         if (ibuf) IMB_freeImBuf(ibuf);
925         BLI_freelistN(picsbase);
926         free_blender();
927         GHOST_DisposeWindow(g_system, g_window);
928
929         totblock = MEM_get_memory_blocks_in_use();
930         if (totblock != 0) {
931                 printf("Error Totblock: %d\n", totblock);
932                 MEM_printmemlist();
933         }
934 }