Initial revision
[blender.git] / source / blender / src / playanim.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #ifndef WIN32
37 #include <unistd.h>
38 #include <sys/times.h>
39 #include <sys/wait.h>
40 #else
41 #include <io.h>
42 #include "BLI_winstuff.h"
43 #endif   
44 #include "MEM_guardedalloc.h"
45
46 #include "PIL_time.h"
47
48 #include <math.h>
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52 #include "BLI_editVert.h"
53
54 #include "IMB_imbuf_types.h"
55 #include "IMB_imbuf.h"
56
57 #include "BDR_editcurve.h"
58
59 #include "BKE_global.h"
60 #include "BKE_utildefines.h"
61
62 #include "BIF_gl.h"
63 #include "BIF_screen.h"
64 #include "BIF_mywindow.h"
65
66 #include "playanim_ext.h"
67 #include "mydevice.h"
68 #include "blendef.h"
69 #include "winlay.h"
70
71 /* ***************** gl_util.c ****************** */
72
73 static Window *g_window = NULL;
74 static int qualN = 0;
75
76 #define LSHIFT  (1<<0)
77 #define RSHIFT  (1<<1)
78 #define SHIFT   (LSHIFT | RSHIFT)
79 #define LALT    (1<<2)
80 #define RALT    (1<<3)
81 #define ALT     (LALT | RALT)
82 #define LCTRL   (1<<4)
83 #define RCTRL   (1<<5)
84 #define LMOUSE  (1<<16)
85 #define MMOUSE  (1<<17)
86 #define RMOUSE  (1<<18)
87 #define MOUSE   (LMOUSE | MMOUSE | RMOUSE)
88
89 unsigned short screen_qread(short *val, char *ascii);
90
91 /* implementation */
92 static int qreadN(short *val)
93 {
94         char ascii;
95         int event = screen_qread(val, &ascii);
96
97         switch(event){
98         case LEFTMOUSE:
99                 if (*val) qualN |= LMOUSE;
100                 else qualN &= ~LMOUSE;
101                 break;
102         case MIDDLEMOUSE:
103                 if (*val) qualN |= MMOUSE;
104                 else qualN &= ~MMOUSE;
105                 break;
106         case RIGHTMOUSE:
107                 if (*val) qualN |= RMOUSE;
108                 else qualN &= ~RMOUSE;
109                 break;
110         case LEFTSHIFTKEY:
111                 if (*val) qualN |= LSHIFT;
112                 else qualN &= ~LSHIFT;
113                 break;
114         case RIGHTSHIFTKEY:
115                 if (*val) qualN |= RSHIFT;
116                 else qualN &= ~RSHIFT;
117                 break;
118         case LEFTCTRLKEY:
119                 if (*val) qualN |= LCTRL;
120                 else qualN &= ~LCTRL;
121                 break;
122         case RIGHTCTRLKEY:
123                 if (*val) qualN |= RCTRL;
124                 else qualN &= ~RCTRL;
125                 break;
126         case LEFTALTKEY:
127                 if (*val) qualN |= LALT;
128                 else qualN &= ~LALT;
129                 break;
130         case RIGHTALTKEY:
131                 if (*val) qualN |= RALT;
132                 else qualN &= ~RALT;
133                 break;
134         }
135
136         return(event);
137 }
138
139 /* ***************** gl_util.c ****************** */
140
141
142
143
144 typedef struct pict{
145         struct pict *next, *prev;
146         char *mem;
147         int size;
148         char *name;
149         struct ImBuf *ibuf;
150         struct anim *anim;
151         int frame;
152         int IB_flags;
153 }Pict;
154
155 static struct ListBase _picsbase = {0,0};
156 static struct ListBase *picsbase = &_picsbase;
157 static int fromdisk = FALSE;
158 static float zoomx = 1.0 , zoomy = 1.0;
159 static double ptottime = 0.0, swaptime = 0.04;
160
161 static int pupdate_time(void)
162 {
163         static double ltime;
164         double time;
165
166         time = PIL_check_seconds_timer();
167
168         ptottime += (time - ltime);
169         ltime = time;
170         return (ptottime < 0);
171 }
172
173 static void toscreen(struct ImBuf *ibuf)
174 {
175         if (ibuf == 0){
176                 printf("no ibuf !\n");
177                 return;
178         }
179
180         glRasterPos2f(-1, -1);
181
182         glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
183         
184         pupdate_time();
185         
186         window_swap_buffers(g_window);
187 }
188
189 static void build_pict_list(char * first)
190 {
191         int size,pic,file;
192         char *mem, name[256];
193         short val;
194         struct pict * picture = 0;
195         struct ImBuf *ibuf = 0;
196         int count = 0;
197         char str[100];
198         struct anim * anim;
199         
200         if (IMB_isanim(first)) {
201                 anim = IMB_open_anim(first, IB_rect);
202                 if (anim) {
203                         ibuf = IMB_anim_absolute(anim, 0);
204                         if (ibuf) {
205                                 toscreen(ibuf);
206                                 IMB_freeImBuf(ibuf);
207                         }
208                         
209                         for (pic = 0; pic < IMB_anim_get_duration(anim); pic ++) {
210                                 picture = (Pict*)MEM_callocN(sizeof(Pict),"Pict");
211                                 picture->anim = anim;
212                                 picture->frame = pic;
213                                 picture->IB_flags = IB_rect;
214                                 sprintf(str, "%s : %d", first, pic + 1);
215                                 picture->name = strdup(str);
216                                 BLI_addtail(picsbase, picture);
217                         }
218                 } else printf("couldn't open anim %s\n", first);
219         } else {
220         
221                 strcpy(name,first);
222         
223                 pupdate_time();
224                 ptottime = 1.0;
225                 
226 /*
227      O_DIRECT
228             If set, all reads and writes on the resulting file descriptor will
229             be performed directly to or from the user program buffer, provided
230             appropriate size and alignment restrictions are met.  Refer to the
231             F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
232             information about how to determine the alignment constraints.
233             O_DIRECT is a Silicon Graphics extension and is only supported on
234             local EFS and XFS file systems.
235 */
236                 while(IMB_ispic(name)){
237                         file = open(name, O_BINARY|O_RDONLY, 0);
238                         if (file < 0) return;
239                         picture = (struct pict*)calloc(1, sizeof(struct pict));
240                         if (picture == 0){
241                                 printf("Not enough memory for pict struct \n");
242                                 close(file);
243                                 return;
244                         }
245                         size = BLI_filesize(file);
246                         picture->size = size;
247                         picture->IB_flags = IB_rect;
248                                                 
249                         if (fromdisk == FALSE) {
250                                 mem=(char *)malloc(size);
251                                 if (mem==0){
252                                         printf("Couldn't get memory\n");
253                                         close(file);
254                                         free(picture);
255                                         return;
256                                 }
257                 
258                                 if (read(file,mem,size) != size){
259                                         printf("Error while reading %s\n",name);
260                                         close(file);
261                                         free(picture);
262                                         free(mem);
263                                         return;
264                                 }
265                         } else mem = 0;
266                         
267                         picture->mem = mem;
268                         picture->name = strdup(name);
269                         close(file);
270                         BLI_addtail(picsbase,picture);
271                         count++;
272                         
273                         pupdate_time();
274                         
275                         if (ptottime > 1.0) {                           
276                                 if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
277                                 else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
278                                 if (ibuf) {
279                                         toscreen(ibuf);
280                                         IMB_freeImBuf(ibuf);
281                                         glDrawBuffer(GL_FRONT);
282
283                                         cpack(-1);
284                                         glRasterPos2i(10,  10);
285                                         sprintf(str, "%4d: %s", count, name);
286                                         glCallLists(strlen(str), GL_UNSIGNED_BYTE, str);
287                                         glDrawBuffer(GL_BACK);
288                                 }
289                                 pupdate_time();
290                                 ptottime = 0.0;
291                         }
292                         
293                         BLI_newname(name, +1);
294                         
295                         while(qtest()){
296                                 switch(qreadN(&val)){
297                                 case ESCKEY:
298                                         if (val) return;
299                                         break;
300                                 }
301                         }
302                 }
303         }
304         return;
305 }
306
307 void playanim(int argc, char **argv)
308 {
309         struct ImBuf *ibuf = 0;
310         struct pict *picture = 0;
311         char name[256];
312         short val = 0, go = TRUE, ibufx = 0, ibufy = 0;
313         int event, stopped = FALSE, maxwinx, maxwiny;
314         short /*  c233 = FALSE, */ /*  yuvx = FALSE, */ once = FALSE, sstep = FALSE, wait2 = FALSE, /*  resetmap = FALSE, */ pause = 0;
315         short pingpong = FALSE, direction = 1, next = 1, turbo = FALSE, /*  doubleb = TRUE, */ noskip = FALSE;
316         int sizex, sizey, ofsx, ofsy, i;
317         /* This was done to disambiguate the name for use under c++. */
318         struct anim * anim = 0;
319         int start_x= 0, start_y= 0;
320
321         while (argc > 1) {
322                 if (argv[1][0] == '-'){
323                         switch(argv[1][1]) {
324                                 case 'm':
325                                         fromdisk = TRUE;
326                                         break;
327                                 case 'p':
328                                         if (argc>3) {
329                                                 start_x= atoi(argv[2]);
330                                                 start_y= atoi(argv[3]);
331                                                 argc-= 2; 
332                                                 argv+= 2;
333                                         } else {
334                                                 printf("too few arguments for -p (need 2): skipping\n");
335                                         }
336                                         break;
337                                 default:
338                                         printf("unknown option '%c': skipping\n", argv[1][1]);
339                                         break;
340                         }
341                         argc--;
342                         argv++;
343                 } else break;
344         }
345         
346         if (argc > 1) strcpy(name,argv[1]);
347         else {
348                 BLI_getwdN(name);
349                 if (name[strlen(name)-1] != '/') strcat(name,"/");
350         }
351                 
352         if (IMB_isanim(name)) {
353                 anim = IMB_open_anim(name, IB_rect);
354                 if (anim) {
355                         ibuf = IMB_anim_absolute(anim, 0);
356                         IMB_close_anim(anim);
357                         anim = NULL;
358                 }
359         } else if (!IMB_ispic(name)) {
360                 exit(1);
361         }
362
363         if (ibuf == 0) ibuf = IMB_loadiffname(name, IB_rect);
364         if (ibuf == 0){
365                 printf("couldn't open %s\n",name);
366                 exit(1);
367         }
368         
369         #if !defined(WIN32) && !defined(__APPLE__)
370         if (fork()) exit(0);
371         #endif
372         
373         winlay_get_screensize(&maxwinx, &maxwiny);
374
375                 /* XXX, fixme zr */
376         {
377                 extern void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
378
379                 g_window = window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
380                 window_set_handler(g_window, add_to_mainqueue, NULL);
381         }
382
383         ibufx = ibuf->x;
384         ibufy = ibuf->y;
385         
386         if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
387         if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
388         
389         glClearColor(0.0, 0.0, 0.0, 0.0);
390         glClear(GL_COLOR_BUFFER_BIT);
391         
392         window_swap_buffers(g_window);
393         
394         build_pict_list(name);
395         
396         for (i = 2; i < argc; i++){
397                 strcpy(name, argv[i]);
398                 build_pict_list(name);
399         }
400
401         IMB_freeImBuf(ibuf); 
402         ibuf = 0;
403
404         pupdate_time();
405         ptottime = 0;
406
407         while (go){
408                 if (pingpong) direction = -direction;
409
410                 if (direction == 1) picture = picsbase->first;
411                 else picture = picsbase->last;
412
413                 if (picture == 0){
414                         printf("couldn't find pictures\n");
415                         go = FALSE;
416                 }
417                 if (pingpong){
418                         if (direction == 1) picture = picture->next;
419                         else picture = picture->prev;
420                 }
421                 if (ptottime > 0.0) ptottime = 0.0;
422
423                 while (picture){
424                         if (ibuf != 0 && ibuf->type == 0) IMB_freeImBuf(ibuf);
425
426                         if (picture->ibuf) ibuf = picture->ibuf;
427                         else if (picture->anim) ibuf = IMB_anim_absolute(picture->anim, picture->frame);
428                         else if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
429                         else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
430                         
431                         if (ibuf){
432                                 strcpy(ibuf->name, picture->name);
433                                 
434                                 while (pupdate_time()) PIL_sleep_ms(1);
435                                 ptottime -= swaptime;
436                                 toscreen(ibuf);
437                         } /* else deleten */
438                         else {
439                                 printf("error: can't play this image type\n");
440                                 exit(0);
441                         }
442                         
443                         if (once){
444                                 if (picture->next == 0) wait2 = TRUE;
445                                 else if (picture->prev == 0) wait2 = TRUE;
446                         }
447                         
448                         next = direction;
449                         
450                         while ((qtest() != 0 ) || ( wait2 != 0)){
451                                 if (wait2 && stopped) {
452                                         stopped = FALSE;
453                                 }
454                         
455                                 event = qreadN(&val);
456                                 /* printf("%d %d\n", event, val); */
457                                 
458                                 if (wait2){
459                                         pupdate_time();
460                                         ptottime = 0;
461                                 }
462                                 switch (event){
463                                 case AKEY:
464                                         if (val)
465                                                 noskip = !noskip;
466                                         break;
467                                 case PKEY:
468                                         if (val)
469                                                 pingpong = !pingpong;
470                                         break;
471                                 case SLASHKEY:
472                                         if (val) {
473                                                 if (qualN & SHIFT) {
474                                                         if (ibuf)
475                                                                 printf(" Name: %s | Speed: %.2f frames/s\n", ibuf->name, 1.0 / swaptime);
476                                                 } else {
477                                                         swaptime = 1.0 / 5.0;
478                                                 }
479                                         }
480                                         break;
481                                 case LEFTARROWKEY:
482                                         if (val){
483                                                 sstep = TRUE;
484                                                 wait2 = FALSE;
485                                                 if (qualN & SHIFT) {
486                                                         picture = picsbase->first;
487                                                         next = 0;
488                                                 } else {
489                                                         next = -1;
490                                                 }
491                                         }
492                                         break;
493                                 case DOWNARROWKEY:
494                                         if (val){
495                                                 wait2 = FALSE;
496                                                 if (qualN & SHIFT) {
497                                                         next = direction = -1;
498                                                 } else {
499                                                         next = -10;
500                                                         sstep = TRUE;
501                                                 }
502                                         }
503                                         break;
504                                 case RIGHTARROWKEY:
505                                         if (val){
506                                                 sstep = TRUE;
507                                                 wait2 = FALSE;
508                                                 if (qualN & SHIFT) {
509                                                         picture = picsbase->last;
510                                                         next = 0;
511                                                 } else {
512                                                         next = 1;
513                                                 }
514                                         }
515                                         break;
516                                 case UPARROWKEY:
517                                         if (val){
518                                                 wait2 = FALSE;
519                                                 if (qualN & SHIFT) {
520                                                         next = direction = 1;
521                                                 } else {
522                                                         next = 10;
523                                                         sstep = TRUE;
524                                                 }
525                                         }
526                                         break;
527                                 case LEFTMOUSE:
528                                 case MOUSEX:
529                                         if (qualN & LMOUSE) {
530                                                 window_get_size(g_window,&sizex,&sizey);
531                                                 picture = picsbase->first;
532                                                 i = 0;
533                                                 while (picture){
534                                                         i ++;
535                                                         picture = picture->next;
536                                                 }
537                                                 i = (i * val) / sizex;
538                                                 picture = picsbase->first;
539                                                 for (; i > 0; i--){
540                                                         if (picture->next == 0) break;
541                                                         picture = picture->next;
542                                                 }
543                                                 sstep = TRUE;
544                                                 wait2 = FALSE;
545                                                 next = 0;
546                                         }
547                                         break;
548                                         go= FALSE;
549                                         break;
550                                 case EQUALKEY:
551                                         if (val) {
552                                                 if (qualN & SHIFT) {
553                                                         pause ++;
554                                                         printf("pause:%d\n", pause);
555                                                 } else swaptime /= 1.1;
556                                         }
557                                         break;
558                                 case MINUSKEY:
559                                         if (val) {
560                                                 if (qualN & SHIFT) {
561                                                         pause --;
562                                                         printf("pause:%d\n", pause);
563                                                 } else swaptime *= 1.1;
564                                         }
565                                         break;
566                                 case PAD0:
567                                         if (val){
568                                                 if (once) once = wait2 = FALSE;
569                                                 else {
570                                                         picture = 0;
571                                                         once = TRUE;
572                                                         wait2 = FALSE;
573                                                 }
574                                         }
575                                         break;
576                                 case RETKEY:
577                                 case PADENTER:
578                                         if (val){
579                                                 wait2 = sstep = FALSE;
580                                         }
581                                         break;
582                                 case PADPERIOD:
583                                         if (val){
584                                                 if (sstep) wait2 = FALSE;
585                                                 else {
586                                                         sstep = TRUE;
587                                                         wait2 = !wait2;
588                                                 }
589                                         }
590                                         break;
591                                 case PAD1:
592                                         swaptime = 1.0 / 60.0;
593                                         break;
594                                 case PAD2:
595                                         swaptime = 1.0 / 50.0;
596                                         break;
597                                 case PAD3:
598                                         swaptime = 1.0 / 30.0;
599                                         break;
600                                 case PAD4:
601                                         swaptime = 1.0 / 25.0;
602                                         break;
603                                 case PAD5:
604                                         swaptime = 1.0 / 20.0;
605                                         break;
606                                 case PAD6:
607                                         swaptime = 1.0 / 15.0;
608                                         break;
609                                 case PAD7:
610                                         swaptime = 1.0 / 12.0;
611                                         break;
612                                 case PAD8:
613                                         swaptime = 1.0 / 10.0;
614                                         break;
615                                 case PAD9:
616                                         swaptime = 1.0 / 6.0;
617                                         break;
618                                 case PADPLUSKEY:
619                                         if (val == 0) break;
620                                         zoomx += 2.0;
621                                         zoomy += 2.0;
622                                 case PADMINUS:
623                                         if (val == 0) break;
624                                         if (zoomx > 1.0) zoomx -= 1.0;
625                                         if (zoomy > 1.0) zoomy -= 1.0;
626                                         window_get_position(g_window,&ofsx,&ofsy);
627                                         window_get_size(g_window,&sizex,&sizey);
628                                         ofsx += sizex/2;
629                                         ofsy += sizey/2;
630                                         sizex = zoomx * ibufx;
631                                         sizey = zoomy * ibufy;
632                                         ofsx -= sizex/2;
633                                         ofsy -= sizey/2;
634 /*                                      window_set_position(g_window,sizex,sizey); */
635                                         window_set_size(g_window,sizex,sizey);
636                                         break;
637                                 case RESHAPE:
638                                 case REDRAW:
639                                         window_get_size(g_window,&sizex,&sizey);
640                                         window_make_active(g_window);
641                                         
642                                         glViewport(0,  0, sizex, sizey);
643                                         glScissor(0,  0, sizex, sizey);
644
645                                         zoomx = (float) sizex / ibufx;
646                                         zoomy = (float) sizey / ibufy;
647                                         zoomx = floor(zoomx + 0.5);
648                                         zoomy = floor(zoomy + 0.5);
649                                         if (zoomx < 1.0) zoomx = 1.0;
650                                         if (zoomy < 1.0) zoomy = 1.0;
651
652                                         sizex = zoomx * ibufx;
653                                         sizey = zoomy * ibufy;
654
655                                         glPixelZoom(zoomx, zoomy);
656                                         glEnable(GL_DITHER);
657                                         ptottime = 0.0;
658                                         toscreen(ibuf);
659                                         while (qtest()) qreadN(&val);
660                                         
661                                         break;
662                                 case ESCKEY:
663                                 case WINCLOSE:
664                                 case WINQUIT:
665                                         go = FALSE;
666                                         break;
667                                 }
668                                 if (go == FALSE) break;
669                         }
670                         
671                         wait2 = sstep;
672                         
673                         if (wait2 == 0 && stopped == 0) {
674                                 stopped = TRUE;
675                         }
676
677                         pupdate_time();
678                                         
679                         if (picture && next) {
680                                 /* altijd minstens 1 stap zetten */
681                                 while (picture){
682                                         if (next < 0) picture = picture->prev;
683                                         else picture = picture->next;
684         
685                                         if (once && picture != 0){
686                                                 if (picture->next == 0) wait2 = TRUE;
687                                                 else if (picture->prev == 0) wait2 = TRUE;
688                                         }
689
690                                         if (wait2 || ptottime < swaptime || turbo || noskip) break;
691                                         ptottime -= swaptime;
692                                 }
693                                 if (picture == 0 && sstep) {
694                                         if (next < 0) picture = picsbase->last;
695                                         else if (next > 0) picture = picsbase->first;                                                                   
696                                 }
697                         }
698                         if (go == FALSE) break;
699                 }
700         }
701         picture = picsbase->first;
702         anim = NULL;
703         while (picture) {
704                 if (picture && picture->anim && (anim != picture->anim)) {
705                         // to prevent divx crashes
706                         anim = picture->anim;
707                         IMB_close_anim(anim);
708                 }
709                 picture = picture->next;
710         }
711 }