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