a14fa789d9172cb56cbd9fd9424b1ff0b391f4ef
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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  * \note This file uses ghost directly and none of the WM definitions.
32  *       this could be made into its own module, alongside creator/
33  */
34
35 #include <sys/types.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #ifndef WIN32
41 #  include <unistd.h>
42 #  include <sys/times.h>
43 #  include <sys/wait.h>
44 #else
45 #  include <io.h>
46 #endif
47 #include "MEM_guardedalloc.h"
48
49 #include "PIL_time.h"
50
51 #include <math.h>
52
53 #include "BLI_blenlib.h"
54 #include "BLI_math.h"
55
56 #include "IMB_imbuf_types.h"
57 #include "IMB_imbuf.h"
58
59 #include "BKE_blender.h"
60 #include "BKE_global.h"
61 #include "BKE_utildefines.h"
62
63 #include "BIF_gl.h"
64 #include "BIF_glutil.h"
65
66 #ifdef WITH_QUICKTIME
67 #  ifdef _WIN32
68 #    include <QTML.h>
69 #    include <Movies.h>
70 #  elif defined(__APPLE__)
71 #    include <QuickTime/Movies.h>
72 #  endif /* __APPLE__ */
73 #endif /* WITH_QUICKTIME */
74
75 #include "DNA_scene_types.h"
76 #include "BLI_utildefines.h"
77 #include "ED_datafiles.h" /* for fonts */
78 #include "wm_event_types.h"
79 #include "GHOST_C-api.h"
80 #include "BLF_api.h"
81
82 #define WINCLOSE -1
83 #define REDRAW -3
84 #define RESHAPE -2
85 #define WINQUIT -4
86
87 /* use */
88 typedef struct PlayState {
89         short direction;
90         short next;
91         short once;
92         short turbo;
93         short pingpong;
94         short noskip;
95         short sstep;
96         short pause;
97         short wait2;
98         short stopped;
99         short go;
100
101         struct PlayAnimPict *picture;
102
103         /* set once at the start */
104         int ibufx, ibufy;
105         int fontid;
106
107         /* saves passing args */
108         struct ImBuf *curframe_ibuf;
109 } PlayState;
110
111 /* ***************** gl_util.c ****************** */
112
113 static GHOST_SystemHandle g_system = NULL;
114 static void *g_window = NULL;
115
116 static int qualN = 0;
117
118 #define LSHIFT  (1 << 0)
119 #define RSHIFT  (1 << 1)
120 #define SHIFT   (LSHIFT | RSHIFT)
121 #define LALT    (1 << 2)
122 #define RALT    (1 << 3)
123 #define ALT (LALT | RALT)
124 #define LCTRL   (1 << 4)
125 #define RCTRL   (1 << 5)
126 #define LMOUSE  (1 << 16)
127 #define MMOUSE  (1 << 17)
128 #define RMOUSE  (1 << 18)
129 #define MOUSE   (LMOUSE | MMOUSE | RMOUSE)
130
131 unsigned short screen_qread(short *val, char *ascii);
132
133 void playanim_window_get_size(int *width_r, int *height_r)
134 {
135         GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_window);
136         *width_r = GHOST_GetWidthRectangle(bounds);
137         *height_r = GHOST_GetHeightRectangle(bounds);
138         GHOST_DisposeRectangle(bounds);
139 }
140
141 /* implementation */
142 #if 0
143 static int qreadN(short *val)
144 {
145 #if 0 // XXX25
146         char ascii;
147         int event = screen_qread(val, &ascii);
148 #else
149         int event = 123456789;
150 #endif
151
152         switch (event) {
153                 case LEFTMOUSE:
154                         if (*val) qualN |= LMOUSE;
155                         else qualN &= ~LMOUSE;
156                         break;
157                 case MIDDLEMOUSE:
158                         if (*val) qualN |= MMOUSE;
159                         else qualN &= ~MMOUSE;
160                         break;
161                 case RIGHTMOUSE:
162                         if (*val) qualN |= RMOUSE;
163                         else qualN &= ~RMOUSE;
164                         break;
165                 case LEFTSHIFTKEY:
166                         if (*val) qualN |= LSHIFT;
167                         else qualN &= ~LSHIFT;
168                         break;
169                 case RIGHTSHIFTKEY:
170                         if (*val) qualN |= RSHIFT;
171                         else qualN &= ~RSHIFT;
172                         break;
173                 case LEFTCTRLKEY:
174                         if (*val) qualN |= LCTRL;
175                         else qualN &= ~LCTRL;
176                         break;
177                 case RIGHTCTRLKEY:
178                         if (*val) qualN |= RCTRL;
179                         else qualN &= ~RCTRL;
180                         break;
181                 case LEFTALTKEY:
182                         if (*val) qualN |= LALT;
183                         else qualN &= ~LALT;
184                         break;
185                 case RIGHTALTKEY:
186                         if (*val) qualN |= RALT;
187                         else qualN &= ~RALT;
188                         break;
189         }
190
191         return(event);
192 }
193 #endif
194
195 typedef struct PlayAnimPict {
196         struct PlayAnimPict *next, *prev;
197         char *mem;
198         int size;
199         char *name;
200         struct ImBuf *ibuf;
201         struct anim *anim;
202         int frame;
203         int IB_flags;
204 } PlayAnimPict;
205
206 static struct ListBase _picsbase = {NULL, NULL};
207 static struct ListBase *picsbase = &_picsbase;
208 static int fromdisk = FALSE;
209 static int fstep = 1;
210 static float zoomx = 1.0, zoomy = 1.0;
211 static double ptottime = 0.0, swaptime = 0.04;
212
213 static int pupdate_time(void)
214 {
215         static double ltime;
216         double time;
217
218         time = PIL_check_seconds_timer();
219
220         ptottime += (time - ltime);
221         ltime = time;
222         return (ptottime < 0);
223 }
224
225 static void toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fontid)
226 {
227
228         if (ibuf == NULL) {
229                 printf("no ibuf !\n");
230                 return;
231         }
232         if (ibuf->rect == NULL && ibuf->rect_float) {
233                 IMB_rect_from_float(ibuf);
234                 imb_freerectfloatImBuf(ibuf);
235         }
236         if (ibuf->rect == NULL)
237                 return;
238
239         GHOST_ActivateWindowDrawingContext(g_window);
240
241         glRasterPos2f(0.0f, 0.0f);
242
243         glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
244
245         pupdate_time();
246
247         //if (picture && (qualN & (SHIFT | LMOUSE))) {
248         if (picture && fontid != -1) {
249                 char str[32 + FILE_MAX];
250                 cpack(-1);
251 //              glRasterPos2f(0.02f, 0.03f);
252                 BLI_snprintf(str, sizeof(str), "%s | %.2f frames/s", picture->name, fstep / swaptime);
253 //              BMF_DrawString(font, str);
254
255                 BLF_enable(fontid, BLF_ASPECT);
256                 BLF_aspect(fontid, 1.0f / ibuf->x, 1.0f / ibuf->y, 1.0f);
257                 BLF_position(fontid, 0.02f, 0.03f, 0.0f);
258                 BLF_draw(fontid, str, 256); // XXX
259                 printf("Drawing text '%s'\n", str);
260         }
261
262         GHOST_SwapWindowBuffers(g_window);
263 }
264
265 static void build_pict_list(char *first, int totframes, int fstep, int fontid)
266 {
267         char *mem, filepath[FILE_MAX];
268 //      short val;
269         PlayAnimPict *picture = NULL;
270         struct ImBuf *ibuf = NULL;
271         char str[32 + FILE_MAX];
272         struct anim *anim;
273
274         if (IMB_isanim(first)) {
275                 anim = IMB_open_anim(first, IB_rect, 0);
276                 if (anim) {
277                         int pic;
278                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
279                         if (ibuf) {
280                                 toscreen(NULL, ibuf, fontid);
281                                 IMB_freeImBuf(ibuf);
282                         }
283
284                         for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) {
285                                 picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict");
286                                 picture->anim = anim;
287                                 picture->frame = pic;
288                                 picture->IB_flags = IB_rect;
289                                 BLI_snprintf(str, sizeof(str), "%s : %d", first, pic + 1);
290                                 picture->name = strdup(str);
291                                 BLI_addtail(picsbase, picture);
292                         }
293                 }
294                 else {
295                         printf("couldn't open anim %s\n", first);
296                 }
297         }
298         else {
299                 int count = 0;
300
301                 BLI_strncpy(filepath, first, sizeof(filepath));
302
303                 pupdate_time();
304                 ptottime = 1.0;
305
306                 /* O_DIRECT
307                  *
308                  * If set, all reads and writes on the resulting file descriptor will
309                  * be performed directly to or from the user program buffer, provided
310                  * appropriate size and alignment restrictions are met.  Refer to the
311                  * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
312                  * information about how to determine the alignment constraints.
313                  * O_DIRECT is a Silicon Graphics extension and is only supported on
314                  * local EFS and XFS file systems.
315                  */
316
317                 while (IMB_ispic(filepath) && totframes) {
318                         size_t size;
319                         int file;
320
321                         file = open(filepath, O_BINARY | O_RDONLY, 0);
322                         if (file < 0) return;
323                         picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture");
324                         if (picture == NULL) {
325                                 printf("Not enough memory for pict struct \n");
326                                 close(file);
327                                 return;
328                         }
329                         size = BLI_file_descriptor_size(file);
330
331                         if (size < 1) {
332                                 close(file);
333                                 MEM_freeN(picture);
334                                 return;
335                         }
336
337                         picture->size = size;
338                         picture->IB_flags = IB_rect;
339
340                         if (fromdisk == FALSE) {
341                                 mem = (char *)MEM_mallocN(size, "build pic list");
342                                 if (mem == NULL) {
343                                         printf("Couldn't get memory\n");
344                                         close(file);
345                                         MEM_freeN(picture);
346                                         return;
347                                 }
348
349                                 if (read(file, mem, size) != size) {
350                                         printf("Error while reading %s\n", filepath);
351                                         close(file);
352                                         MEM_freeN(picture);
353                                         MEM_freeN(mem);
354                                         return;
355                                 }
356                         }
357                         else {
358                                 mem = NULL;
359                         }
360
361                         picture->mem = mem;
362                         picture->name = strdup(filepath);
363                         close(file);
364                         BLI_addtail(picsbase, picture);
365                         count++;
366
367                         pupdate_time();
368
369                         if (ptottime > 1.0) {
370                                 if (picture->mem) {
371                                         ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size,
372                                                                      picture->IB_flags, picture->name);
373                                 }
374                                 else {
375                                         ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
376                                 }
377                                 if (ibuf) {
378                                         toscreen(picture, ibuf, fontid);
379                                         IMB_freeImBuf(ibuf);
380                                 }
381                                 pupdate_time();
382                                 ptottime = 0.0;
383                         }
384
385                         BLI_newname(filepath, +fstep);
386
387 #if 0 // XXX25
388                         while (qtest()) {
389                                 switch (qreadN(&val)) {
390                                         case ESCKEY:
391                                                 if (val) return;
392                                                 break;
393                                 }
394                         }
395 #endif
396                         totframes--;
397                 }
398         }
399         return;
400 }
401
402 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
403 {
404         PlayState *ps = (PlayState *)ps_void;
405         {
406                 GHOST_TEventType type = GHOST_GetEventType(evt);
407                 int val;
408                 int event;
409
410                 /* convert ghost event into value keyboard or mouse */
411                 val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown);
412
413                 if (ps->wait2 && ps->stopped) {
414                         ps->stopped = FALSE;
415                 }
416
417                 switch (type) {
418                         case GHOST_kEventWindowSize:
419                         case GHOST_kEventWindowMove:
420                         {
421                                 int sizex, sizey;
422
423                                 playanim_window_get_size(&sizex, &sizey);
424                                 GHOST_ActivateWindowDrawingContext(g_window);
425
426                                 glViewport(0, 0, sizex, sizey);
427                                 glScissor(0, 0, sizex, sizey);
428
429                                 zoomx = (float) sizex / ps->ibufx;
430                                 zoomy = (float) sizey / ps->ibufy;
431                                 zoomx = floor(zoomx + 0.5);
432                                 zoomy = floor(zoomy + 0.5);
433                                 if (zoomx < 1.0) zoomx = 1.0;
434                                 if (zoomy < 1.0) zoomy = 1.0;
435
436                                 sizex = zoomx * ps->ibufx;
437                                 sizey = zoomy * ps->ibufy;
438
439                                 glPixelZoom(zoomx, zoomy);
440                                 glEnable(GL_DITHER);
441                                 ptottime = 0.0;
442                                 toscreen(ps->picture, ps->curframe_ibuf, ps->fontid);
443 //XXX25                         while (qtest()) qreadN(&val);
444
445                                 break;
446                         }
447                         case GHOST_kEventQuit:
448                         case GHOST_kEventWindowClose:
449                         {
450                                 ps->go = FALSE;
451                                 break;
452                         }
453                         default:
454                                 /* quiet warnings */
455                                 break;
456                 }
457
458                 return 1; // XXX25
459
460                 event = -1;
461
462
463 //XXX25         int event = qreadN(&val);
464                 /* printf("%d %d\n", event, val); */
465
466                 if (ps->wait2) {
467                         pupdate_time();
468                         ptottime = 0;
469                 }
470                 switch (event) {
471                         case AKEY:
472                                 if (val)
473                                         ps->noskip = !ps->noskip;
474                                 break;
475                         case PKEY:
476                                 if (val)
477                                         ps->pingpong = !ps->pingpong;
478                                 break;
479                         case SLASHKEY:
480                                 if (val) {
481                                         if (qualN & SHIFT) {
482                                                 if (ps->curframe_ibuf)
483                                                         printf(" Name: %s | Speed: %.2f frames/s\n", ps->curframe_ibuf->name, fstep / swaptime);
484                                         }
485                                         else {
486                                                 swaptime = fstep / 5.0;
487                                         }
488                                 }
489                                 break;
490                         case LEFTARROWKEY:
491                                 if (val) {
492                                         ps->sstep = TRUE;
493                                         ps->wait2 = FALSE;
494                                         if (qualN & SHIFT) {
495                                                 ps->picture = picsbase->first;
496                                                 ps->next = 0;
497                                         }
498                                         else {
499                                                 ps->next = -1;
500                                         }
501                                 }
502                                 break;
503                         case DOWNARROWKEY:
504                                 if (val) {
505                                         ps->wait2 = FALSE;
506                                         if (qualN & SHIFT) {
507                                                 ps->next = ps->direction = -1;
508                                         }
509                                         else {
510                                                 ps->next = -10;
511                                                 ps->sstep = TRUE;
512                                         }
513                                 }
514                                 break;
515                         case RIGHTARROWKEY:
516                                 if (val) {
517                                         ps->sstep = TRUE;
518                                         ps->wait2 = FALSE;
519                                         if (qualN & SHIFT) {
520                                                 ps->picture = picsbase->last;
521                                                 ps->next = 0;
522                                         }
523                                         else {
524                                                 ps->next = 1;
525                                         }
526                                 }
527                                 break;
528                         case UPARROWKEY:
529                                 if (val) {
530                                         ps->wait2 = FALSE;
531                                         if (qualN & SHIFT) {
532                                                 ps->next = ps->direction = 1;
533                                         }
534                                         else {
535                                                 ps->next = 10;
536                                                 ps->sstep = TRUE;
537                                         }
538                                 }
539                                 break;
540                         case LEFTMOUSE:
541                         case MOUSEX:
542                                 if (qualN & LMOUSE) {
543                                         int sizex, sizey;
544                                         int i;
545                                         playanim_window_get_size(&sizex, &sizey);
546                                         ps->picture = picsbase->first;
547                                         i = 0;
548                                         while (ps->picture) {
549                                                 i++;
550                                                 ps->picture = ps->picture->next;
551                                         }
552                                         i = (i * val) / sizex;
553                                         ps->picture = picsbase->first;
554                                         for (; i > 0; i--) {
555                                                 if (ps->picture->next == NULL) break;
556                                                 ps->picture = ps->picture->next;
557                                         }
558                                         ps->sstep = TRUE;
559                                         ps->wait2 = FALSE;
560                                         ps->next = 0;
561                                 }
562                                 break;
563                         case EQUALKEY:
564                                 if (val) {
565                                         if (qualN & SHIFT) {
566                                                 ps->pause++;
567                                                 printf("pause:%d\n", ps->pause);
568                                         }
569                                         else {
570                                                 swaptime /= 1.1;
571                                         }
572                                 }
573                                 break;
574                         case MINUSKEY:
575                                 if (val) {
576                                         if (qualN & SHIFT) {
577                                                 ps->pause--;
578                                                 printf("pause:%d\n", ps->pause);
579                                         }
580                                         else {
581                                                 swaptime *= 1.1;
582                                         }
583                                 }
584                                 break;
585                         case PAD0:
586                                 if (val) {
587                                         if (ps->once) {
588                                                 ps->once = ps->wait2 = FALSE;
589                                         }
590                                         else {
591                                                 ps->picture = NULL;
592                                                 ps->once = TRUE;
593                                                 ps->wait2 = FALSE;
594                                         }
595                                 }
596                                 break;
597                         case RETKEY:
598                         case PADENTER:
599                                 if (val) {
600                                         ps->wait2 = ps->sstep = FALSE;
601                                 }
602                                 break;
603                         case PADPERIOD:
604                                 if (val) {
605                                         if (ps->sstep) ps->wait2 = FALSE;
606                                         else {
607                                                 ps->sstep = TRUE;
608                                                 ps->wait2 = !ps->wait2;
609                                         }
610                                 }
611                                 break;
612                         case PAD1:
613                                 swaptime = fstep / 60.0;
614                                 break;
615                         case PAD2:
616                                 swaptime = fstep / 50.0;
617                                 break;
618                         case PAD3:
619                                 swaptime = fstep / 30.0;
620                                 break;
621                         case PAD4:
622                                 if (qualN & SHIFT)
623                                         swaptime = fstep / 24.0;
624                                 else
625                                         swaptime = fstep / 25.0;
626                                 break;
627                         case PAD5:
628                                 swaptime = fstep / 20.0;
629                                 break;
630                         case PAD6:
631                                 swaptime = fstep / 15.0;
632                                 break;
633                         case PAD7:
634                                 swaptime = fstep / 12.0;
635                                 break;
636                         case PAD8:
637                                 swaptime = fstep / 10.0;
638                                 break;
639                         case PAD9:
640                                 swaptime = fstep / 6.0;
641                                 break;
642                         case PADPLUSKEY:
643                                 if (val == 0) break;
644                                 zoomx += 2.0;
645                                 zoomy += 2.0;
646                         case PADMINUS:
647                         {
648                                 int sizex, sizey;
649                                 /* int ofsx, ofsy; */ /* UNUSED */
650
651                                 if (val == 0) break;
652                                 if (zoomx > 1.0) zoomx -= 1.0;
653                                 if (zoomy > 1.0) zoomy -= 1.0;
654                                 // playanim_window_get_position(&ofsx, &ofsy);
655                                 playanim_window_get_size(&sizex, &sizey);
656                                 /* ofsx += sizex / 2; */ /* UNUSED */
657                                 /* ofsy += sizey / 2; */ /* UNUSED */
658                                 sizex = zoomx * ps->ibufx;
659                                 sizey = zoomy * ps->ibufy;
660                                 /* ofsx -= sizex / 2; */ /* UNUSED */
661                                 /* ofsy -= sizey / 2; */ /* UNUSED */
662                                 // window_set_position(g_window,sizex,sizey);
663                                 GHOST_SetClientSize(g_window, sizex, sizey);
664                                 break;
665                         }
666                         case RESHAPE:
667                         case REDRAW:
668                         {
669 //XXX25 DONE!
670                         }
671                         case ESCKEY:
672                         case WINCLOSE:
673                         case WINQUIT:
674 //XXX25 DONE!
675                         break;
676                 }
677 //XXX25         if (go == FALSE) break;
678         }
679
680         return 1;
681 }
682
683 void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
684 {
685         GHOST_TWindowState inital_state;
686         GHOST_TUns32 scr_w, scr_h;
687
688         GHOST_GetMainDisplayDimensions(g_system, &scr_w, &scr_h);
689
690         posy = (scr_h - posy - sizey);
691
692         if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
693                 inital_state = start_maximized ? GHOST_kWindowStateFullScreen : GHOST_kWindowStateNormal;
694         else
695                 inital_state = start_maximized ? GHOST_kWindowStateMaximized : GHOST_kWindowStateNormal;
696 #if defined(__APPLE__) && !defined(GHOST_COCOA)
697         {
698                 extern int macPrefState; /* creator.c */
699                 initial_state += macPrefState;
700         }
701 #endif
702
703         g_window = GHOST_CreateWindow(g_system,
704                                       title,
705                                       posx, posy, sizex, sizey,
706                                       inital_state,
707                                       GHOST_kDrawingContextTypeOpenGL,
708                                       FALSE /* no stereo */, FALSE);
709
710         //if (ghostwin) {
711         //if (win) {
712         // GHOST_SetWindowUserData(ghostwin, win);
713         //} else {
714         //      GHOST_DisposeWindow(g_system, ghostwin);
715         //}
716         //}
717 }
718
719
720 void playanim(int argc, const char **argv)
721 {
722         struct ImBuf *ibuf = NULL;
723         char filepath[FILE_MAX];
724         GHOST_TUns32 maxwinx, maxwiny;
725         /* short c233 = FALSE, yuvx = FALSE; */ /* UNUSED */
726         int i;
727         /* This was done to disambiguate the name for use under c++. */
728         struct anim *anim = NULL;
729         int start_x = 0, start_y = 0;
730         int sfra = -1;
731         int efra = -1;
732         int totblock;
733
734         PlayState ps = {0};
735
736         /* ps.doubleb   = TRUE;*/ /* UNUSED */
737         ps.go        = TRUE;
738         ps.direction = TRUE;
739         ps.next      = TRUE;
740         ps.once      = FALSE;
741         ps.turbo     = FALSE;
742         ps.pingpong  = FALSE;
743         ps.noskip    = FALSE;
744         ps.sstep     = FALSE;
745         ps.pause     = FALSE;
746         ps.wait2     = FALSE;
747         ps.stopped   = FALSE;
748         ps.picture   = NULL;
749         /* resetmap = FALSE */
750
751         ps.fontid = -1;
752
753         while (argc > 1) {
754                 if (argv[1][0] == '-') {
755                         switch (argv[1][1]) {
756                                 case 'm':
757                                         fromdisk = TRUE;
758                                         break;
759                                 case 'p':
760                                         if (argc > 3) {
761                                                 start_x = atoi(argv[2]);
762                                                 start_y = atoi(argv[3]);
763                                                 argc -= 2;
764                                                 argv += 2;
765                                         }
766                                         else {
767                                                 printf("too few arguments for -p (need 2): skipping\n");
768                                         }
769                                         break;
770                                 case 'f':
771                                         if (argc > 3) {
772                                                 double fps = atof(argv[2]);
773                                                 double fps_base = atof(argv[3]);
774                                                 if (fps == 0.0) {
775                                                         fps = 1;
776                                                         printf("invalid fps,"
777                                                                "forcing 1\n");
778                                                 }
779                                                 swaptime = fps_base / fps;
780                                                 argc -= 2;
781                                                 argv += 2;
782                                         }
783                                         else {
784                                                 printf("too few arguments for -f (need 2): skipping\n");
785                                         }
786                                         break;
787                                 case 's':
788                                         sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
789                                         argc--;
790                                         argv++;
791                                         break;
792                                 case 'e':
793                                         efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
794                                         argc--;
795                                         argv++;
796                                         break;
797                                 case 'j':
798                                         fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
799                                         swaptime *= fstep;
800                                         argc--;
801                                         argv++;
802                                         break;
803                                 default:
804                                         printf("unknown option '%c': skipping\n", argv[1][1]);
805                                         break;
806                         }
807                         argc--;
808                         argv++;
809                 }
810                 else {
811                         break;
812                 }
813         }
814
815 #ifdef WITH_QUICKTIME
816 #if defined(_WIN32) || defined(__APPLE__) && !defined(GHOST_COCOA)
817         /* Initialize QuickTime */
818 #ifndef noErr
819 #define noErr 0
820 #endif
821
822 #ifdef _WIN32
823         if (InitializeQTML(0) != noErr)
824                 G.have_quicktime = FALSE;
825         else
826                 G.have_quicktime = TRUE;
827 #endif /* _WIN32 */
828         if (EnterMovies() != noErr)
829                 G.have_quicktime = FALSE;
830         else
831 #endif /* _WIN32 || __APPLE__  && !defined(GHOST_COCOA)*/
832         G.have_quicktime = TRUE;
833 #endif /* WITH_QUICKTIME */
834
835         if (argc > 1) {
836                 BLI_strncpy(filepath, argv[1], sizeof(filepath));
837         }
838         else {
839                 BLI_current_working_dir(filepath, sizeof(filepath));
840                 BLI_add_slash(filepath);
841         }
842
843         if (IMB_isanim(filepath)) {
844                 anim = IMB_open_anim(filepath, IB_rect, 0);
845                 if (anim) {
846                         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
847                         IMB_close_anim(anim);
848                         anim = NULL;
849                 }
850         }
851         else if (!IMB_ispic(filepath)) {
852                 exit(1);
853         }
854
855         if (ibuf == NULL) {
856                 ibuf = IMB_loadiffname(filepath, IB_rect);
857         }
858
859         if (ibuf == NULL) {
860                 printf("couldn't open %s\n", filepath);
861                 exit(1);
862         }
863
864 #if 0 //XXX25
865         #if !defined(WIN32) && !defined(__APPLE__)
866         if (fork()) exit(0);
867         #endif
868 #endif //XXX25
869
870         /* XXX, fixme zr */
871         {
872 //              extern void add_to_mainqueue(wmWindow *win, void *user_data, short evt, short val, char ascii);
873
874                 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
875
876                 g_system = GHOST_CreateSystem();
877                 GHOST_AddEventConsumer(g_system, consumer);
878
879
880
881                 playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
882 //XXX25         window_set_handler(g_window, add_to_mainqueue, NULL);
883
884                 glMatrixMode(GL_PROJECTION);
885                 glLoadIdentity();
886                 glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
887                 glMatrixMode(GL_MODELVIEW);
888         }
889
890         GHOST_GetMainDisplayDimensions(g_system, &maxwinx, &maxwiny);
891
892         //GHOST_ActivateWindowDrawingContext(g_window);
893
894         /* initialize the font */
895         BLF_init(11, 72);
896         ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
897         BLF_size(ps.fontid, 11, 72);
898
899         ps.ibufx = ibuf->x;
900         ps.ibufy = ibuf->y;
901
902         if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
903         if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
904
905         glClearColor(0.0, 0.0, 0.0, 0.0);
906         glClear(GL_COLOR_BUFFER_BIT);
907
908         GHOST_SwapWindowBuffers(g_window);
909
910         if (sfra == -1 || efra == -1) {
911                 /* one of the frames was invalid, just use all images */
912                 sfra = 1;
913                 efra = MAXFRAME;
914         }
915
916         build_pict_list(filepath, (efra - sfra) + 1, fstep, ps.fontid);
917
918         for (i = 2; i < argc; i++) {
919                 BLI_strncpy(filepath, argv[i], sizeof(filepath));
920                 build_pict_list(filepath, (efra - sfra) + 1, fstep, ps.fontid);
921         }
922
923         IMB_freeImBuf(ibuf);
924         ibuf = NULL;
925
926         pupdate_time();
927         ptottime = 0;
928
929         while (ps.go) {
930                 if (ps.pingpong)
931                         ps.direction = -ps.direction;
932
933                 if (ps.direction == 1) {
934                         ps.picture = picsbase->first;
935                 }
936                 else {
937                         ps.picture = picsbase->last;
938                 }
939
940                 if (ps.picture == NULL) {
941                         printf("couldn't find pictures\n");
942                         ps.go = FALSE;
943                 }
944                 if (ps.pingpong) {
945                         if (ps.direction == 1) {
946                                 ps.picture = ps.picture->next;
947                         }
948                         else {
949                                 ps.picture = ps.picture->prev;
950                         }
951                 }
952                 if (ptottime > 0.0) ptottime = 0.0;
953
954                 while (ps.picture) {
955                         if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
956
957                         if (ps.picture->ibuf) {
958                                 ibuf = ps.picture->ibuf;
959                         }
960                         else if (ps.picture->anim) {
961                                 ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
962                         }
963                         else if (ps.picture->mem) {
964                                 ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
965                                                              ps.picture->IB_flags, ps.picture->name);
966                         }
967                         else {
968                                 ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags);
969                         }
970
971                         if (ibuf) {
972                                 BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));
973
974 #ifdef _WIN32
975                                 GHOST_SetTitle(g_window, picture->name);
976 #endif
977
978                                 while (pupdate_time()) PIL_sleep_ms(1);
979                                 ptottime -= swaptime;
980                                 toscreen(ps.picture, ibuf, ps.fontid);
981                         } /* else deleten */
982                         else {
983                                 printf("error: can't play this image type\n");
984                                 exit(0);
985                         }
986
987                         if (ps.once) {
988                                 if (ps.picture->next == NULL) {
989                                         ps.wait2 = TRUE;
990                                 }
991                                 else if (ps.picture->prev == NULL) {
992                                         ps.wait2 = TRUE;
993                                 }
994                         }
995
996                         ps.next = ps.direction;
997
998
999                         {
1000                                 int hasevent = GHOST_ProcessEvents(g_system, 0);
1001                                 if (hasevent) {
1002                                         GHOST_DispatchEvents(g_system);
1003                                 }
1004                         }
1005
1006                         ps.wait2 = ps.sstep;
1007
1008                         if (ps.wait2 == 0 && ps.stopped == 0) {
1009                                 ps.stopped = TRUE;
1010                         }
1011
1012                         pupdate_time();
1013
1014                         if (ps.picture && ps.next) {
1015                                 /* always at least set one step */
1016                                 while (ps.picture) {
1017                                         if (ps.next < 0) {
1018                                                 ps.picture = ps.picture->prev;
1019                                         }
1020                                         else {
1021                                                 ps.picture = ps.picture->next;
1022                                         }
1023
1024                                         if (ps.once && ps.picture != NULL) {
1025                                                 if (ps.picture->next == NULL) {
1026                                                         ps.wait2 = TRUE;
1027                                                 }
1028                                                 else if (ps.picture->prev == NULL) {
1029                                                         ps.wait2 = TRUE;
1030                                                 }
1031                                         }
1032
1033                                         if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
1034                                         ptottime -= swaptime;
1035                                 }
1036                                 if (ps.picture == NULL && ps.sstep) {
1037                                         if (ps.next < 0) {
1038                                                 ps.picture = picsbase->last;
1039                                         }
1040                                         else if (ps.next > 0) {
1041                                                 ps.picture = picsbase->first;
1042                                         }
1043                                 }
1044                         }
1045                         if (ps.go == FALSE) {
1046                                 break;
1047                         }
1048                 }
1049         }
1050         ps.picture = picsbase->first;
1051         anim = NULL;
1052         while (ps.picture) {
1053                 if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
1054                         // to prevent divx crashes
1055                         anim = ps.picture->anim;
1056                         IMB_close_anim(anim);
1057                 }
1058
1059                 if (ps.picture->ibuf) {
1060                         IMB_freeImBuf(ps.picture->ibuf);
1061                 }
1062                 if (ps.picture->mem) {
1063                         MEM_freeN(ps.picture->mem);
1064                 }
1065
1066                 ps.picture = ps.picture->next;
1067         }
1068 #ifdef WITH_QUICKTIME
1069 #if defined(_WIN32) || defined(__APPLE__) && !defined(GHOST_COCOA)
1070         if (G.have_quicktime) {
1071                 ExitMovies();
1072 #ifdef _WIN32
1073                 TerminateQTML();
1074 #endif /* _WIN32 */
1075         }
1076 #endif /* _WIN32 || __APPLE__ && !defined(GHOST_COCOA) */
1077 #endif /* WITH_QUICKTIME */
1078
1079         /* cleanup */
1080         if (ibuf) IMB_freeImBuf(ibuf);
1081         BLI_freelistN(picsbase);
1082         free_blender();
1083         GHOST_DisposeWindow(g_system, g_window);
1084
1085         totblock = MEM_get_memory_blocks_in_use();
1086         if (totblock != 0) {
1087                 printf("Error Totblock: %d\n", totblock);
1088                 MEM_printmemlist();
1089         }
1090 }