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