8cab4ebf11ed12d69081059599bc7bb1cc0071c5
[dragonfly.git] / release / picobsd / tinyware / view / view.c
1 /*-
2  * Copyright (c) 1998 Andrzej Bialecki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/release/picobsd/tinyware/view/view.c,v 1.4 1999/08/28 01:34:02 peter Exp $
27  * $DragonFly: src/release/picobsd/tinyware/view/Attic/view.c,v 1.2 2003/06/17 04:27:21 dillon Exp $
28  */
29
30 /*
31  * Small PNG viewer with scripting abilities
32  */
33
34 #include <stdio.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <termios.h>
39 #include <sys/types.h>
40 #include <machine/console.h>
41 #include <machine/mouse.h>
42 #include <vgl.h>
43 #include <png.h>
44
45 #define NUMBER  8
46
47 extern char *optarg;
48 extern int optind;
49
50 /* Prototypes */
51 int kbd_action __P((int x, int y, char hotkey));
52
53 struct action {
54         int zoom;
55         int rotate;
56         int Xshift,Yshift;
57 };
58
59 struct menu_item {
60         char *descr;
61         char hotkey;
62         int (*func)(int x, int y, char hotkey);
63 };
64
65 struct menu_item std_menu[]= {
66         {"q  Quit",'q',kbd_action},
67         {"n  Next",'n',kbd_action},
68         {"p  Previous",'p',kbd_action},
69         {"Z  Zoom in",'Z',kbd_action},
70         {"z  Zoom out",'z',kbd_action},
71         {"r  Rotate",'r',kbd_action},
72         {"R  Refresh",'R',kbd_action},
73         {"l  Left",'l',kbd_action},
74         {"h  Right",'h',kbd_action},
75         {"j  Up",'j',kbd_action},
76         {"k  Down",'k',kbd_action},
77         {NULL,0,NULL}
78 };
79
80 char *progname;
81 VGLBitmap pic,bkg;
82 struct action a;
83 byte pal_red[256];
84 byte pal_green[256];
85 byte pal_blue[256];
86 byte pal_colors;
87 double screen_gamma;
88 int max_screen_colors=15;
89 int quit,changed;
90 char **pres;
91 int nimg=0;
92 int auto_chg=0;
93 int cur_img=0;
94 char act;
95 FILE *log;
96
97 void
98 usage()
99 {
100         fprintf(stderr,"\nVGL graphics viewer, 1.0 (c) Andrzej Bialecki.\n");
101         fprintf(stderr,"\nUsage:\n");
102         fprintf(stderr,"\t%s [-r n] [-g n.n] filename\n",progname);
103         fprintf(stderr,"\nwhere:\n");
104         fprintf(stderr,"\t-r n\tchoose resolution:\n");
105         fprintf(stderr,"\t\t0 - 640x480x16 (default)\n");
106         fprintf(stderr,"\t\t1 - 640x200x256\n");
107         fprintf(stderr,"\t\t2 - 320x240x256\n");
108         fprintf(stderr,"\t-g n.n\tset screen gamma (1.3 by default)\n");
109         fprintf(stderr,"\n");
110 }
111
112 int
113 pop_up(char *title,int x, int y)
114 {
115         VGLBitmap sav,clr;
116         int x1,y1,width,height,i,j;
117         int last_pos,cur_pos,max_item;
118         char buttons;
119         char *t;
120
121         sav.Type=VGLDisplay->Type;
122         clr.Type=VGLDisplay->Type;
123         width=0;
124         height=0;
125         max_item=0;
126         i=0;
127         while(std_menu[i].descr!=NULL) {
128                 height++;
129                 max_item++;
130                 if(strlen(std_menu[i].descr)>width) width=strlen(std_menu[i].descr);
131                 i++;
132         }
133         width=width*8+2;
134         height=height*9+4+8;
135         sav.Xsize=width;
136         sav.Ysize=height;
137         clr.Xsize=width;
138         clr.Ysize=height;
139         sav.Bitmap=(byte *)calloc(width*height,1);
140         clr.Bitmap=(byte *)calloc(width*height,1);
141         if(x>(VGLDisplay->Xsize-width)) x1=VGLDisplay->Xsize-width;
142         else x1=x;
143         if(y>(VGLDisplay->Ysize-height)) y1=VGLDisplay->Ysize-height;
144         else y1=y;
145         VGLMouseMode(VGL_MOUSEHIDE);
146         VGLBitmapCopy(VGLDisplay,x1,y1,&sav,0,0,width,height);
147         VGLFilledBox(VGLDisplay,x1,y1,x1+width-1,y1+height-1,pal_colors-1);
148         VGLBitmapString(VGLDisplay,x1+1,y1+1,title,0,pal_colors-1,0,0);
149         VGLLine(VGLDisplay,x1,y1+9,x1+width,y1+9,0);
150         i=0;
151         while(std_menu[i].descr!=NULL) {
152                 VGLBitmapString(VGLDisplay,x1+1,y1+11+i*9,std_menu[i].descr,0,pal_colors-1,0,0);
153                 i++;
154         }
155         last_pos=-1;
156         VGLMouseMode(VGL_MOUSESHOW);
157         do {
158                 pause();
159                 VGLMouseStatus(&x,&y,&buttons);
160                 cur_pos=(y-y1-11)/9;
161                 if((cur_pos<0)||(cur_pos>max_item-1)) {
162                         if(last_pos==-1) last_pos=0;
163                         VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0);
164                         last_pos=-1;
165                 } else if(last_pos!=cur_pos) {
166                         if(last_pos==-1) last_pos=0;
167                         VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0);
168                         VGLBitmapString(VGLDisplay,x1+1,y1+11+cur_pos*9,std_menu[cur_pos].descr,pal_colors/2+1,pal_colors-1,0,0);
169                         last_pos=cur_pos;
170                 }
171         } while (buttons & MOUSE_BUTTON3DOWN);
172         VGLMouseMode(VGL_MOUSEHIDE);
173         /* XXX Screws up totally when r==3. Libvgl bug! */
174         VGLBitmapCopy(&clr,0,0,VGLDisplay,x1,y1,width,height);
175         VGLBitmapCopy(&sav,0,0,VGLDisplay,x1,y1,width,height);
176         VGLMouseMode(VGL_MOUSESHOW);
177         free(sav.Bitmap);
178         free(clr.Bitmap);
179         changed++;
180         if((cur_pos>=0) && (cur_pos<max_item)) {
181                 std_menu[cur_pos].func(x,y,std_menu[cur_pos].hotkey);
182         }
183         changed++;
184         return(0);
185 }
186
187 void
188 display(        VGLBitmap *pic,
189                 byte *red,
190                 byte *green,
191                 byte *blue,
192                 struct action *e)
193 {
194         VGLBitmap target;
195         int x,y,i=0,j=0;
196
197         VGLMouseMode(VGL_MOUSEHIDE);
198         VGLRestorePalette();
199         /* XXX Broken in r!=2. Libvgl bug. */
200         //VGLClear(VGLDisplay,0);
201         VGLBitmapCopy(&bkg,0,0,VGLDisplay,0,0,bkg.Xsize,bkg.Ysize);
202
203         if(e!=NULL) {
204                 if(e->zoom!=1 || e->rotate) {
205                         target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize*e->zoom*e->zoom,1);
206                         if(e->rotate) {
207                                 target.Xsize=pic->Ysize*e->zoom;
208                                 target.Ysize=pic->Xsize*e->zoom;
209                         } else {
210                                 target.Xsize=pic->Xsize*e->zoom;
211                                 target.Ysize=pic->Ysize*e->zoom;
212                         }
213                         target.Type=pic->Type;
214                         for(x=0;x<pic->Xsize;x++) {
215                                 for(y=0;y<pic->Ysize;y++) {
216                                         for(i=0;i<e->zoom;i++) {
217                                                 for(j=0;j<e->zoom;j++) {
218                                                         if(e->rotate) {
219                                                                 VGLSetXY(&target,target.Xsize-(e->zoom*y+i),e->zoom*x+j,VGLGetXY(pic,x,y));
220                                                         } else {
221                                                                 VGLSetXY(&target,e->zoom*x+i,e->zoom*y+j,VGLGetXY(pic,x,y));
222                                                         }
223                                                 }
224                                         }
225                                 }
226                         }
227                 } else {
228                         target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte));
229                         target.Xsize=pic->Xsize;
230                         target.Ysize=pic->Ysize;
231                         target.Type=pic->Type;
232                         VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize);
233                 }
234         } else {
235                 target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte));
236                 target.Xsize=pic->Xsize;
237                 target.Ysize=pic->Ysize;
238                 target.Type=pic->Type;
239                 VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize);
240         }
241         VGLSetPalette(red, green, blue);
242         if(e!=NULL) {
243                 VGLBitmapCopy(&target,0,0,VGLDisplay,e->Xshift,e->Yshift,target.Xsize,target.Ysize);
244         } else {
245                 VGLBitmapCopy(&target,0,0,VGLDisplay,0,0,target.Xsize,target.Ysize);
246         }
247         VGLMouseMode(VGL_MOUSESHOW);
248         free(target.Bitmap);
249 }
250
251 int
252 png_load(char *filename)
253 {
254         int i,j,k;
255         FILE *fd;
256         u_char header[NUMBER];
257         png_structp png_ptr;
258         png_infop info_ptr,end_info;
259         png_uint_32 width,height;
260         int bit_depth,color_type,interlace_type;
261         int compression_type,filter_type;
262         int channels,rowbytes;
263         double gamma;
264         png_colorp palette;
265         int num_palette;
266         png_bytep *row_pointers;
267         char c;
268         int res=0;
269
270         fd=fopen(filename,"rb");
271         
272         if(fd==NULL) {
273                 VGLEnd();
274                 perror("fopen");
275                 exit(1);
276         }
277         fread(header,1,NUMBER,fd);
278         if(!png_check_sig(header,NUMBER)) {
279                 fprintf(stderr,"Not a PNG file.\n");
280                 return(-1);
281         }
282         png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,
283                 NULL,NULL);
284         info_ptr=png_create_info_struct(png_ptr);
285         end_info=png_create_info_struct(png_ptr);
286         if(!png_ptr || !info_ptr || !end_info) {
287                 VGLEnd();
288                 fprintf(stderr,"failed to allocate needed structs!\n");
289                 png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
290                 return(-1);
291         }
292         png_set_sig_bytes(png_ptr,NUMBER);
293         png_init_io(png_ptr,fd);
294         png_read_info(png_ptr,info_ptr);
295         png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
296                 &color_type,&interlace_type,&compression_type,&filter_type);
297         png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
298         channels=png_get_channels(png_ptr,info_ptr);
299         rowbytes=png_get_rowbytes(png_ptr,info_ptr);
300         if(bit_depth==16)
301                 png_set_strip_16(png_ptr);
302         if(color_type & PNG_COLOR_MASK_ALPHA) 
303                 png_set_strip_alpha(png_ptr);
304         if(png_get_gAMA(png_ptr,info_ptr,&gamma))
305                 png_set_gamma(png_ptr,screen_gamma,gamma);
306         else
307         png_set_gamma(png_ptr,screen_gamma,0.45);
308         if(res==0) {
309                 /* Dither */
310                 if(color_type & PNG_COLOR_MASK_COLOR) {
311                         if(png_get_valid(png_ptr,info_ptr,PNG_INFO_PLTE)) {
312                                 png_uint_16p histogram;
313                                 png_get_hIST(png_ptr,info_ptr,&histogram);
314                                 png_set_dither(png_ptr,palette,num_palette,max_screen_colors,histogram,0);
315                         } else {
316                                 png_color std_color_cube[16]={
317                                         {0x00,0x00,0x00},
318                                         {0x02,0x02,0x02},
319                                         {0x04,0x04,0x04},
320                                         {0x06,0x06,0x06},
321                                         {0x08,0x08,0x08},
322                                         {0x0a,0x0a,0x0a},
323                                         {0x0c,0x0c,0x0c},
324                                         {0x0e,0x0e,0x0e},
325                                         {0x10,0x10,0x10},
326                                         {0x12,0x12,0x12},
327                                         {0x14,0x14,0x14},
328                                         {0x16,0x16,0x16},
329                                         {0x18,0x18,0x18},
330                                         {0x1a,0x1a,0x1a},
331                                         {0x1d,0x1d,0x1d},
332                                         {0xff,0xff,0xff},
333                                 };
334                                 png_set_dither(png_ptr,std_color_cube,max_screen_colors,max_screen_colors,NULL,0);
335                         }
336                 }
337         }
338         png_set_packing(png_ptr);
339         if(png_get_valid(png_ptr,info_ptr,PNG_INFO_sBIT)) {
340                 png_color_8p sig_bit;
341
342                 png_get_sBIT(png_ptr,info_ptr,&sig_bit);
343                 png_set_shift(png_ptr,sig_bit);
344         }
345         png_read_update_info(png_ptr,info_ptr);
346         png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
347                 &color_type,&interlace_type,&compression_type,&filter_type);
348         png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
349         channels=png_get_channels(png_ptr,info_ptr);
350         rowbytes=png_get_rowbytes(png_ptr,info_ptr);
351         row_pointers=malloc(height*sizeof(png_bytep));
352         for(i=0;i<height;i++) {
353                 row_pointers[i]=malloc(rowbytes);
354         }
355         png_read_image(png_ptr,row_pointers);
356         png_read_end(png_ptr,end_info);
357         png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
358         fclose(fd);
359         /* Set palette */
360         if(res) k=2;
361         else k=2;
362         for(i=0;i<256;i++) {
363                 pal_red[i]=255;
364                 pal_green[i]=255;
365                 pal_blue[i]=255;
366         }
367         for(i=0;i<num_palette;i++) {
368                 pal_red[i]=(palette+i)->red>>k;
369                 pal_green[i]=(palette+i)->green>>k;
370                 pal_blue[i]=(palette+i)->blue>>k;
371         }
372         pal_colors=num_palette;
373         if(pic.Bitmap!=NULL) free(pic.Bitmap);
374         pic.Bitmap=(byte *)calloc(rowbytes*height,sizeof(byte));
375         pic.Type=MEMBUF;
376         pic.Xsize=rowbytes;
377         pic.Ysize=height;
378         for(i=0;i<rowbytes;i++) {
379                 for(j=0;j<height;j++) {
380                         VGLSetXY(&pic,
381                         i,j,row_pointers[j][i]);
382                 }
383         }
384         a.zoom=1;
385         a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2;
386         a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2;
387         a.rotate=0;
388         return(0);
389 }
390
391 void
392 kbd_handler(int sig)
393 {
394         u_char buf[10];
395         int res;
396
397         res=read(0,&buf,10);
398         changed++;
399         act=buf[res-1];
400 }
401
402 int
403 kbd_action(int x, int y, char key)
404 {
405         changed=0;
406         if(key!='n') auto_chg=0;
407         switch(key) {
408         case 'q':
409                 quit=1;
410                 break;
411         case 'Z':
412                 a.zoom++;
413                 changed++;
414                 break;
415         case 'z':
416                 a.zoom--;
417                 if(a.zoom<1) a.zoom=1;
418                 changed++;
419                 break;
420         case 'l':
421                 a.Xshift+=VGLDisplay->Xsize/5;
422                 changed++;
423                 break;
424         case 'h':
425                 a.Xshift-=VGLDisplay->Xsize/5;
426                 changed++;
427                 break;
428         case 'k':
429                 a.Yshift+=VGLDisplay->Ysize/5;
430                 changed++;
431                 break;
432         case 'j':
433                 a.Yshift-=VGLDisplay->Ysize/5;
434                 changed++;
435                 break;
436         case 'R':
437                 changed++;
438                 break;
439         case 'r':
440                 if(a.rotate) a.rotate=0;
441                 else a.rotate=1;
442                 changed++;
443                 break;
444         case '\n':
445         case 'n':
446                 if(nimg>0) {
447                         if(cur_img<nimg-1) {
448                                 cur_img++;
449                         } else {
450                                 cur_img=0;
451                         }
452                         png_load(pres[cur_img]);
453                         changed++;
454                 }
455                 break;
456         case 'p':
457                 if(nimg>0) {
458                         if(cur_img>0) {
459                                 cur_img--;
460                         } else {
461                                 cur_img=nimg-1;
462                         }
463                         png_load(pres[cur_img]);
464                         changed++;
465                 }
466                 break;
467         }
468         act=0;
469 }
470
471 int
472 main(int argc, char *argv[])
473 {
474         int i,j,k;
475         char c;
476         int res=0;
477         int x,y;
478         char buttons;
479         struct termios t_new,t_old;
480         FILE *fsc;
481
482         char buf[100];
483
484         progname=argv[0];
485         screen_gamma=1.5;
486 #ifdef DEBUG
487         log=fopen("/png/view.log","w");
488 #endif
489         while((c=getopt(argc,argv,"r:g:"))!=-1) {
490                 switch(c) {
491                 case 'r':
492                         res=atoi(optarg);
493                         if(res>0) max_screen_colors=256;
494                         break;
495                 case 'g':
496                         screen_gamma=atof(optarg);
497                         break;
498                 case '?':
499                 default:
500                         usage();
501                         exit(0);
502                 }
503         }
504         switch(res) {
505         case 0:
506                 VGLInit(SW_CG640x480);
507                 break;
508         case 1:
509                 VGLInit(SW_VGA_CG320);
510                 break;
511         case 2:
512                 VGLInit(SW_VGA_MODEX);
513                 break;
514         default:
515                 fprintf(stderr,"No such resolution!\n");
516                 usage();
517                 exit(-1);
518         }
519 #ifdef DEBUG
520         fprintf(log,"VGL initialised\n");
521 #endif
522         VGLSavePalette();
523         if(argc>optind) {
524                 res=png_load(argv[optind]);
525         } else {
526                 VGLEnd();
527                 usage();
528                 exit(0);
529         }
530         if(res) {
531                 /* Hmm... Script? */
532                 fsc=fopen(argv[optind],"r");
533 #ifdef DEBUG
534                 fprintf(log,"Trying script %s\n",argv[optind]);
535 #endif
536                 fgets(buf,99,fsc);
537                 buf[strlen(buf)-1]='\0';
538                 if(strncmp("VIEW SCRIPT",buf,11)!=NULL) {
539                         VGLEnd();
540                         usage();
541                 }
542                 if(strlen(buf)>12) {
543                         auto_chg=atoi(buf+12);
544                 }
545                 fgets(buf,99,fsc);
546                 buf[strlen(buf)-1]='\0';
547                 nimg=atoi(buf);
548                 if(nimg==0) {
549                         VGLEnd();
550                         usage();
551                 }
552                 pres=(char **)calloc(nimg,sizeof(char *));
553                 for(i=0;i<nimg;i++) {
554                         fgets(buf,99,fsc);
555                         buf[strlen(buf)-1]='\0';
556                         pres[i]=strdup(buf);
557                 }
558                 fclose(fsc);
559                 cur_img=0;
560 #ifdef DEBUG
561                 fprintf(log,"Script with %d entries\n",nimg);
562 #endif
563                 png_load(pres[cur_img]);
564         }
565         VGLMouseInit(VGL_MOUSEHIDE);
566         /* Prepare the keyboard */
567         tcgetattr(0,&t_old);
568         memcpy(&t_new,&t_old,sizeof(struct termios));
569         cfmakeraw(&t_new);
570         tcsetattr(0,TCSAFLUSH,&t_new);
571         fcntl(0,F_SETFL,O_ASYNC);
572         /* XXX VGLClear doesn't work.. :-(( Prepare a blank background */
573         bkg.Bitmap=(byte *)calloc(VGLDisplay->Xsize*VGLDisplay->Ysize,1);
574         bkg.Xsize=VGLDisplay->Xsize;
575         bkg.Ysize=VGLDisplay->Ysize;
576         bkg.Type=VGLDisplay->Type;
577         signal(SIGIO,kbd_handler);
578         a.zoom=1;
579         a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2;
580         a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2;
581         a.rotate=0;
582         quit=0;
583         changed=0;
584         display(&pic,pal_red,pal_green,pal_blue,&a);
585         while(!quit) {
586                 if(act) {
587 #ifdef DEBUG
588                         fprintf(log,"kbd_action(%c)\n",act);
589 #endif
590                         kbd_action(x,y,act);
591                 }
592                 if(quit) break;
593                 if(changed) {
594 #ifdef DEBUG
595                         fprintf(log,"changed, redisplaying\n");
596 #endif
597                         display(&pic,pal_red,pal_green,pal_blue,&a);
598                         changed=0;
599                 }
600                 if(auto_chg) {
601                         sleep(auto_chg);
602                         kbd_action(x,y,'n');
603                 } else {
604                         pause();
605                 }
606                 VGLMouseStatus(&x,&y,&buttons);
607                 if(buttons & MOUSE_BUTTON3DOWN) {
608 #ifdef DEBUG
609                         fprintf(log,"pop_up called\n");
610 #endif
611                         pop_up("View",x,y);
612                 }
613         }
614         VGLEnd();
615 #ifdef DEBUG
616         fclose(log);
617 #endif
618         exit(0);
619 }