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