/* * (c) SPDsoft 1993 + ATIC * Display a JFIF file using Silicon Graphics gl * version 2 * Uses IJG code v6b */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <gl/gl.h> #include <gl/device.h> #include <get.h> #include <jpeglib.h> #include <setjmp.h> #ifndef PATH_SEP # define PATH_SEP '/' #endif #define ALPHA_OPAC 0x00 #define YSTEREO 491 #define YOFFSET_LEFT 532 #define SCREEN_W G_prefs.screen_w #define SCREEN_H G_prefs.screen_h #define Boolean int #define Output if (G_prefs.Verbose) printf #ifndef MIN #define MIN(a,b) ((a)>(b)?(b):(a)) #endif typedef struct { char *AppName; Boolean Foreground; Boolean FullScreen; Boolean FillScreen; Boolean Stereo; Boolean Nosetmon; Boolean Growable; Boolean KeepAspectRatio; Boolean Verbose; int SlideShow; long screen_w; long screen_h; } pref; /* * Prototypes */ void init_graphics(void); int event_loop(void); void redraw(void); void usage(char *name); void fatalError(char *str); void get_options(int argc,char *argv[]); int is_stereo(void); /* * JPEG Prototypes */ static void my_error_exit (j_common_ptr cinfo); int read_JPEG_file (char * filename, unsigned char **fb); extern char *optarg; extern int optind,opterr; unsigned image_H; unsigned image_W; long monitor; long mouse; long offset=0; int f; #define framebuffer_r framebuffer unsigned char *framebuffer, *framebuffer_l, *pix; pref G_prefs; static char __ident[] = "@(#)(c) SPDsoft, (Uses IJG code v6b), Jul 1998"; #define VERS_STR ((char*)&__ident[4]) /*****************************************************/ void usage(char *name) { fprintf(stderr, "usage: %s [-b|-F|-g|-G][-s sec][-f][-v][-h][-3|-4 left right|files...]" "\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", name, "-f: Don't fork (run in foreground)", "-b: Full screen", "-3: Stereo", "-4: Stereo w/o setmon", "-F: Fill full screen", "-g: Growable, Keep aspect ratio", "-G: Growable", "-s: Slide Show (seconds)", "-v: Version, debug", "-h: This text. Note: Press <esc> to go to next image" ); exit(-1); } void fatalError(char *str) { fprintf(stderr, "%s: Fatal Error: %s. bye...\n",G_prefs.AppName,str); fprintf(stderr, "%s: %s\n",G_prefs.AppName,strerror(errno)); exit(-2); } struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; static void my_error_exit (j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message) (cinfo); longjmp(myerr->setjmp_buffer, 1); } int read_JPEG_file (char * filename, unsigned char **fb) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ register JSAMPROW inptr; int j; if (filename != NULL) { if ((infile = fopen(filename, "rb")) == NULL) { fatalError(filename); } } else infile = stdin; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); fclose(infile); return NULL; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); image_H = cinfo.output_height; image_W = cinfo.output_width; row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* * Framebuffer */ Output("%03d %s\t%u\t%u\t",f,filename,image_H,image_W ); if((( image_W > SCREEN_W ) || ( image_H > SCREEN_H))&&(G_prefs.FullScreen)) G_prefs.FillScreen=1; *fb = (unsigned char *)calloc( (size_t)image_H * (size_t)image_W , (size_t)4); if ((*fb==NULL)||(buffer==NULL)) fatalError("Out of memory"); pix = *fb + (size_t)4*image_W*(image_H-1); /* * Draw to framebuffer */ if ( cinfo.output_components != 1 ) { Output("RGB image\n"); while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); for (j=0, inptr=*buffer; j<cinfo.output_width; j++) { *pix++ = ALPHA_OPAC; *pix++ = (char)inptr[2]; *pix++ = (char)inptr[1]; *pix++ = (char)inptr[0]; inptr += 3; } pix -= 8* image_W; } } else { Output("Grayscale image\n"); while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); for (j=0, inptr=*buffer; j<cinfo.output_width; j++) { *pix++ = ALPHA_OPAC; *pix++ = (char)inptr[0]; *pix++ = (char)inptr[0]; *pix++ = (char)inptr[0]; inptr += 1; } pix -= 8* image_W; } } /* * Finish */ (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } /*****************************************************/ void get_options(int argc,char *argv[]) { int opcion; int theError=0; if ((G_prefs.AppName = strrchr(argv[0], PATH_SEP)) != NULL) G_prefs.AppName = G_prefs.AppName+1; else G_prefs.AppName = argv[0]; G_prefs.Foreground = 0; G_prefs.FullScreen = 0; G_prefs.FillScreen = 0; G_prefs.SlideShow = -1; G_prefs.Growable = 0; G_prefs.Stereo = 0; G_prefs.Nosetmon = 0; G_prefs.KeepAspectRatio = 1; G_prefs.Verbose=0; while ( (opcion=getopt(argc,argv,"s:43fbFgGvh")) != EOF ) { switch(opcion) { case '4': G_prefs.Stereo = 1; G_prefs.Nosetmon = 1; G_prefs.FullScreen = 1; break; case '3': G_prefs.Stereo = 1; G_prefs.FullScreen = 1; break; case 'f': G_prefs.Foreground = 1; break; case 'b': G_prefs.FullScreen = 1; break; case 'F': G_prefs.FullScreen = 1; G_prefs.FillScreen = 1; break; case 'g': G_prefs.Growable = 1; break; case 's': G_prefs.SlideShow = atoi(optarg); break; case 'G': G_prefs.Growable = 1; G_prefs.KeepAspectRatio = 0; break; case 'v': printf("%s:%s\n",G_prefs.AppName,VERS_STR); G_prefs.Verbose=1; break; default: usage(G_prefs.AppName); } if ( theError!=0) usage(G_prefs.AppName); } } main(int argc,char *argv[]) { Boolean Fill; long gwid; long gw_x, gw_y; char tmpStr[64]; get_options(argc,argv); init_graphics(); if (G_prefs.Stereo) { if (is_stereo()) { /* save original display mode and switch to stereo */ monitor = getmonitor (); mouse = getvaluator(MOUSEY); if (!G_prefs.Nosetmon) { setmonitor (STR_RECT); /* limit cursor range to one eye's subfield */ setvaluator (MOUSEY, (short) SCREEN_H / 2, 0, (short) SCREEN_H/2); } } else { fprintf(stderr,"Sorry, can't do stereo\n"); G_prefs.Stereo = 0; } } if(G_prefs.FullScreen|G_prefs.Stereo) { prefposition( 0, SCREEN_W, 0, SCREEN_H ); gwid=winopen(""); RGBmode(); gconfig(); } if (optind==argc) { argc ++; } if (G_prefs.Stereo) { read_JPEG_file(argv[optind],&framebuffer_l); read_JPEG_file(argv[optind+1],&framebuffer_r); redraw(); event_loop(); if(!G_prefs.FullScreen) winclose(gwid); if(framebuffer_l) free(framebuffer_l); if(framebuffer_r) free(framebuffer_r); } else { Fill = G_prefs.FillScreen; for(f=optind; f<argc; f++) { G_prefs.FillScreen = Fill; read_JPEG_file(argv[f],&framebuffer); if(G_prefs.FullScreen) { if(G_prefs.FillScreen) { float scale=1.0; getsize(&gw_x, &gw_y); scale= MIN( (float)gw_x/(float)image_W, (float)gw_y/(float)image_H); rectzoom(scale,scale); } redraw(); } else { sprintf(tmpStr,"%s: %s", G_prefs.AppName, (argv[f]==NULL?"stdin":argv[f])); prefsize((long)image_W,(long)image_H); gwid=winopen(tmpStr); clear(); RGBmode(); gconfig(); if(G_prefs.Growable) { if(G_prefs.KeepAspectRatio) keepaspect((long)image_W,(long)image_H); winconstraints(); } } if (event_loop()) f=argc; if(!G_prefs.FullScreen) winclose(gwid); if(framebuffer) free(framebuffer); } } if(G_prefs.FullScreen) winclose(gwid); if(G_prefs.Stereo) { /* restore to original display, cursor range */ if (!G_prefs.Nosetmon) { setmonitor ((short)monitor); setvaluator (MOUSEY, mouse , 0, (short) SCREEN_H); } } return(0); } int event_loop(void) { Boolean quitting=0; Boolean end=0; short val; long MyEvent; static Boolean NeedRedraw=1; /* * just for IRIX 5.3 (and later, I guess) * * IRIX 5.2 sends REDRAW properly */ redraw(); /* */ for (quitting=0;!quitting;) { if ( 0 <= G_prefs.SlideShow ) { redraw(); if ( 0 < G_prefs.SlideShow ) { sleep(G_prefs.SlideShow); } quitting=1; } else { while (qtest() || (!NeedRedraw )) { /* Event Loop */ switch(MyEvent=qread(&val)) { case ESCKEY: quitting=!val; break; case LEFTARROWKEY: if (val) { offset--; redraw(); } break; case RIGHTARROWKEY: if (val) { offset++; redraw(); } break; case REDRAW: NeedRedraw=1; redraw(); break; case WINQUIT: quitting=1; end=1; break; case INPUTCHANGE: break; default: if(G_prefs.Verbose) { printf("Event: %ld\n", MyEvent); fflush(stdout); } break; } if (quitting) break; } /* while */ redraw(); NeedRedraw=0; } } return end; } void init_graphics(void) { long savescrn; #ifdef _CAN_LRECTWRITE_OVER_SOCKET_ char *display; if (NULL!=(display=getenv("DISPLAY"))) { if ( 0 > dglopen(display,DGLTSOCKET)) { fatalError("Can't open dgl socket"); } } #endif qdevice(ESCKEY); qdevice(REDRAW); qdevice(WINSHUT); qdevice(WINQUIT); if (G_prefs.Stereo) { qdevice(LEFTARROWKEY); qdevice(RIGHTARROWKEY); } savescrn = scrnselect(getwscrn()); G_prefs.screen_w = getgdesc(GD_XPMAX); G_prefs.screen_h = getgdesc(GD_YPMAX); scrnselect(savescrn); if (( G_prefs.screen_w == -1 ) || ( G_prefs.screen_h == -1 )) fatalError("getgdesc failed"); if(G_prefs.Foreground) foreground(); } void redraw(void) { long gw_x, gw_y; if(G_prefs.FullScreen) { if(G_prefs.Stereo) { if ( image_H > YSTEREO ) { rectzoom( (float)YSTEREO/(float)image_H, (float)YSTEREO/(float)image_H *0.5); } else { rectzoom(1.0, 0.5); } /* viewport (0, SCREEN_W, YOFFSET_LEFT, SCREEN_H);*/ clear(); lrectwrite( (Screencoord)(SCREEN_W-image_W+1)/2-offset, (Screencoord)((SCREEN_H-YOFFSET_LEFT)+image_H-1)/2+YOFFSET_LEFT, (Screencoord)(SCREEN_W+image_W-1)/2-offset, (Screencoord)((SCREEN_H-YOFFSET_LEFT)-image_H+1)/2+YOFFSET_LEFT, (unsigned long *)framebuffer_l); /* viewport (0, SCREEN_W, 0, YSTEREO);*/ lrectwrite( (Screencoord)(SCREEN_W-image_W+1)/2+offset, (Screencoord)(YSTEREO+image_H-1)/2, (Screencoord)(SCREEN_W+image_W-1)/2+offset, (Screencoord)(YSTEREO-image_H+1)/2, (unsigned long *)framebuffer_r); } else { clear(); if(G_prefs.FillScreen) { lrectwrite( 0,(image_H-1),(image_W-1),0, (unsigned long *)framebuffer); } else { lrectwrite( (Screencoord)(SCREEN_W-image_W+1)/2, (Screencoord)(SCREEN_H+image_H-1)/2, (Screencoord)(SCREEN_W+image_W-1)/2, (Screencoord)(SCREEN_H-image_H+1)/2, (unsigned long *)framebuffer); } } } else { if(G_prefs.Growable) { getsize(&gw_x, &gw_y); viewport(0,(Screencoord)gw_x-1,0,(Screencoord)gw_y-1); rectzoom( (float)gw_x/(float)image_W, (float)gw_y/(float)image_H); } lrectwrite( 0,(image_H-1),(image_W-1),0, (unsigned long *)framebuffer); } } /* --------------------------------------------------------------------- */ int is_stereo(void) { /* This routine returns 1 if Hardware is STEREO READY, 0 IF NOT*/ #ifdef PRE_IRIX33 /* for: pre-IRIX 3.3 systems, */ /* is read/write or read-onl:*/ long rw1, rw2; rw1 = getvideo(DE_R1); rw2 = rw1 ^= DER1_STEREO; setvideo(DE_R1, rw2); rw2 = getvideo(DE_R1); if (! (rw1 == rw2)) return(1); rw1 = rw2 ^= DER1_STEREO; setvideo(DE_R1, rw2); rw2 = getvideo(DE_R1); return ( ! (rw1 == rw2 ) ) ; #else return(getgdesc(GD_STEREO)); #endif }