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