1 /*
2  * get4d.c - Put RLE images on the Iris/4D display under the window manager.
3  *
4  * Author:	Russell D. Fish (Based on getmex.c .)
5  * 		Computer Science Dept.
6  * 		University of Utah
7  * Date:	Thu May 26 20:49:11 1988
8  * Copyright (c) 1988, University of Utah
9  *
10  */
11 /* modified for Personal Iris with only 8 bit planes (no RGB mode)
12  * as well as the other Iris displays.
13  * Michael Hart - September 1991
14  *    forced limitations - B&W display only, -G option forced
15  */
16 
17 #include <stdio.h>
18 #include <math.h>
19 #include "gl.h"
20 #include "device.h"
21 #include "rle.h"
22 
23 #define MAX(i,j)   ( (i) > (j) ? (i) : (j) )
24 #define MIN(i,j)   ( (i) < (j) ? (i) : (j) )
25 
26 /* Global variables. */
27 long window_number;			/* Window number from MAX. */
28 int x_size, y_size;			/* Size of image. */
29 int i;					/* General loop counter */
30 int dbg = 0;				/* Set if debug mode. */
31 int forkflg = 0;			/* Set if not to run in background. */
32 int bwflag = 0;				/* Set for greyscale output. */
33 int NoBorder = 0;			/* Turn off border */
34 int gt;			/* Whether we're using GT fast rectangle drawing. */
35 double disp_gamma = 1.0;		/* Gamma of Iris display. */
36 double img_gamma = 0.0;			/* Gamma of input image. */
37 short colmap[128][3];			/* Area to hold the old colormap */
38 long bitsavail;				/* 0 if not enough for RGB mode */
39 
40 /* Window preferences. */
41 int posflag = 0, w_xpos, w_ypos, sizeflag = 0, w_xsize, w_ysize;
42 
43 unsigned long *rect_image;            /* GT Image data buffer pointer. */
44 unsigned char *rgb_image;             /* Non-GT Image data buffer pointer. */
45 
46 rle_hdr		hdr;
47 rle_pixel **cmap;
48 
49 /*****************************************************************
50  * TAG( main )
51  *
52  * Usage:
53  *	get4d [-G][-S] [-p xpos ypos] [-f] [-D] [-w] [file]
54  * Inputs:
55  *	-D:	Debug mode: print input file as read.
56  * 	-f:	Don't fork after putting image on screen.
57  * 	-G:	GT mode: single fast rectangle, panning disabled.
58  *		(GT mode is the default on GT, GTX, and Personal Iris 4Ds.)
59  *	-S:	Slow mode: Allows resizing the window, and panning with the
60  *		mouse.  (Slow mode is the default on non-GT 4Ds.)
61  *	-g disp_gamma:	Gamma of the output display.
62  *	-i image_gamma:	Gamma the image was calculated for.
63  *	-I image_gamma:	Gamma of the image pixels (1.0 / (-i gamma)).
64  *	-n:	No border will be drawn.
65  *	-p xpos ypos:   Position of the lower left corner of the window.
66  *	-s xsize ysize: Initial size of the window (slow mode only.)
67  *
68  *	-w:	Black & white: reduce color images to B&W before display.
69  *		Advantage is that smoother shading can be achieved.
70  *
71  *	file:	Input Run Length Encoded file.  Uses stdin if not
72  *		specified.
73  * Outputs:
74  * 	Puts image in a window on the screen.
75  * Assumptions:
76  * 	Input file is in RLE format.
77  */
78 
main(argc,argv)79 main(argc, argv)
80 char **argv;
81 {
82     char *infname = NULL;
83     FILE * infile = stdin;
84     char vbuff[50];
85     char *var;
86     int gtflag = 0, slowflag = 0, gflag = 0, iflag = 0;
87 
88     hdr = *rle_hdr_init( (rle_hdr *)NULL );
89     rle_names( &hdr, cmd_name( argv ), NULL, 0 );
90 
91     /* Handle arguments. */
92     if ( scanargs( argc, argv,
93 		   "% D%- f%- GS%- g%-disp_gamma!F iI%-image_gamma!F n%- \n\
94 	p%-xpos!dypos!d s%-xsize!dysize!d w%- file%s",
95 		   &dbg, &forkflg,
96 		   &gtflag,
97 		   &gflag, &disp_gamma,
98 		   &iflag, &img_gamma,
99 		   &NoBorder,
100 		   &posflag, &w_xpos, & w_ypos,
101 		   &sizeflag, &w_xsize, &w_ysize,
102 		   &bwflag,
103 		   &infname ) == 0 )
104 	exit( 1 );
105 
106     if ( gtflag )		/* Mode args override if specified. */
107 	gt = gtflag - 1;	/* -G->2 means yes GT, -S->1 means no GT. */
108     else
109     {
110 #ifndef _IBMR2
111 	/* See if we`re on a GT.  For this purpose, a Personal Iris is a GT. */
112 	gversion( vbuff );	/* String like "GL4DGTX-3.1". */
113 	gt = strncmp( vbuff+4, "GT", 2 ) == 0 ||
114 	     strncmp( vbuff+4, "PI", 2 ) == 0;
115 #else
116 	gt = 1;
117 #endif
118     }
119 
120     /* Diddle with gammas. */
121     if ( iflag == 2 )		/* -i flag. */
122 	if ( img_gamma != 0.0 )	/* Paranoid. */
123 	    img_gamma = 1.0 / img_gamma;
124 
125 #ifndef _IBMR2
126     /* Look at home for .gamma file. */
127     if ( !gflag )
128     {
129 	char *var = getenv( "HOME" );
130 	char buf[BUFSIZ];
131 	FILE *gamfile;
132 	float flt_gam = 0;	/* Just in case of 68000 iris botch. */
133 
134 	if ( var != NULL && *var != '\0' )
135 	{
136 	    sprintf( buf, "%s/.gamma", var );
137 	    if ( (gamfile = fopen( buf, "r" )) != NULL )
138 	    {
139 		fscanf( gamfile, "%f", &flt_gam );
140 		if ( flt_gam != 0 )
141 		    disp_gamma = 2.4/flt_gam;/* SGI displays have gamma 2.4. */
142 		fclose( gamfile );
143 	    }
144 	}
145     }
146 #endif
147     /* check machine graphics capability */
148     bitsavail = getgdesc(GD_BITS_NORM_SNG_GREEN); /* Can it support RGB mode */
149     if(bitsavail==0)
150     {
151                 /* set configuration to force reading in B&W and -G ode disp */
152         bwflag = 1;
153         gt = 1;
154     }
155     infile = rle_open_f(hdr.cmd, infname, "r");
156     get_pic( infile, infname );	/* Read image and make a window for it. */
157     if(bitsavail==0)            /* modify gey levels if necessary */
158         convertgreylevels();
159     update_pic();		/* Keep drawing the window. */
160 }
161 
162 /*
163  * Read an image from the input file and display it.
164  */
get_pic(infile,infname)165 get_pic( infile, infname )
166 FILE * infile;
167 char * infname;
168 {
169     register int i, y;
170     int ncolors;
171     unsigned char *scan[3];
172 
173     /*
174      * Read setup info from file.
175      */
176     rle_hdr_init( &hdr );
177     rle_names( &hdr, hdr.cmd, infile, 0 );
178     hdr.rle_file = infile;
179     if ( rle_get_setup( &hdr ) < 0 )
180     {
181 	fprintf(stderr, "%s: Error reading setup information from %s\n",
182 		hdr.cmd, infname ? infname : "stdin");
183 	exit(1);
184     }
185 
186     if ( dbg )
187 	rle_debug( 1 );
188 
189     /* We`re only interested in R, G, & B */
190     RLE_CLR_BIT(hdr, RLE_ALPHA);
191     for (i = 3; i < hdr.ncolors; i++)
192 	RLE_CLR_BIT(hdr, i);
193     ncolors = hdr.ncolors > 3 ? 3 : hdr.ncolors;
194 
195     /* Do nicer b&w rendering if only one color channel in input. */
196     if ( ncolors == 1 && hdr.ncmap <= 1 )
197 	bwflag = 1;
198 
199     /*
200      * Compute image size and allocate storage for colormapped image.
201      */
202     x_size = (hdr.xmax - hdr.xmin + 1);
203     y_size = (hdr.ymax - hdr.ymin + 1);
204     if ( gt )
205       rect_image = (unsigned long *) malloc(x_size * y_size * sizeof( long ));
206     else
207       rgb_image = (unsigned char *) malloc(x_size * y_size * 3 * sizeof( char ));
208 
209     /*
210      * Set up for rle_getrow.  Pretend image x origin is 0.
211      */
212     for (i = 0; i < 3; i++)
213 	scan[i] = (unsigned char *) malloc(x_size);
214     hdr.xmax -= hdr.xmin;
215     hdr.xmin = 0;
216 
217     cmap = buildmap( &hdr, 3, img_gamma, disp_gamma );
218 
219     /* For each scan line, pack RGBs into the image memory. */
220     while ((y = rle_getrow(&hdr, scan)) <= hdr.ymax)
221     {
222 	switch ( ncolors )
223 	{
224 	case 1:
225 	    /* Colormapped image */
226 	    for (i = 0; i < x_size; i++) {
227 		scan[2][i] = cmap[2][scan[0][i]];
228 		scan[1][i] = cmap[1][scan[0][i]];
229 		scan[0][i] = cmap[0][scan[0][i]];
230 	    }
231 	    break;
232 
233 	case 2:
234 	    /* Weird image. */
235 	    for (i = 0; i < x_size; i++) {
236 		scan[2][i] = cmap[2][scan[1][i]];
237 		scan[1][i] = cmap[1][scan[1][i]];
238 		scan[0][i] = cmap[0][scan[0][i]];
239 	    }
240 	    break;
241 	case 3:
242 	    /* Normal image. */
243 	    for (i = 0; i < x_size; i++) {
244 		scan[2][i] = cmap[2][scan[2][i]];
245 		scan[1][i] = cmap[1][scan[1][i]];
246 		scan[0][i] = cmap[0][scan[0][i]];
247 	    }
248 	    break;
249 	}
250 	if ( bwflag )
251 	{
252 	    if (ncolors == 1)
253 		rgb_to_bw (scan[0], scan[1], scan[2], scan[0], x_size );
254 	    else
255 	        rgb_to_bw( scan[0], scan[1], scan[ncolors - 1],
256 		    scan[0], x_size );
257 	    /* Note: pack_scanline only uses channel 0 for B&W */
258 	}
259 
260 	if ( gt )
261 	    pack_rect_scanline( scan, x_size,
262 		&rect_image[(y - hdr.ymin) * x_size] );
263 	else
264 	    pack_rgb_scanline( scan, x_size,
265 		&rgb_image[(y - hdr.ymin) * x_size * 3] );
266     }
267 
268     /*
269      * Free temp storage
270      */
271     for (i = 0; i < 3; i++)
272 	free(scan[i]);
273 
274     /* Size flag can cut down the window size, except in GT rectangle mode. */
275     w_xsize = sizeflag && !gt ? MIN( w_xsize, x_size ) : x_size;
276     w_ysize = sizeflag && !gt ? MIN( w_ysize, y_size ) : y_size;
277 
278     /* Window should be completely on the screen in GT rectangle mode. */
279     if ( posflag && gt )
280     {
281 	w_xpos = MIN( w_xpos, XMAXSCREEN - w_xsize );
282 	w_ypos = MIN( w_ypos, YMAXSCREEN - w_ysize);
283     }
284 
285     w_xpos = MAX( 0, w_xpos );	/* Be positive. */
286     w_ypos = MAX( 0, w_ypos );
287 
288     /* Register our preferences for the window size and location. */
289     if ( posflag )
290 	prefposition( w_xpos, w_xpos + w_xsize - 1,
291 		      w_ypos, w_ypos + w_ysize - 1 );
292     else if ( sizeflag || gt )
293         /* Have to keep the window full size to use the fast pixel commands. */
294           prefsize( w_xsize, w_ysize );
295     else
296         maxsize( x_size, y_size );
297 
298     /*
299      * Get a window of the right size (user positions it with the mouse).
300      */
301 #ifndef _IBMR2
302     if ( forkflg ) foreground();	/* Don`t fork. */
303 #endif
304     if ( NoBorder ) noborder();
305     window_number = winopen( hdr.cmd );
306     if ( infname ) wintitle( infname );
307 
308     /* Loosen the constraints once the window is created. */
309     if ( !gt )
310 	maxsize( x_size, y_size );
311     winconstraints();
312 
313     if(bitsavail==0)
314     {		/* only color map available so make a grey scale */
315         for(i=0;i<=127;i++)
316 	{
317 		getmcolor((i+128),&colmap[i][0],&colmap[i][1],&colmap[i][2]);
318 		mapcolor((i+128),(i*2),(i*2),(i*2));
319 	}
320     }
321     else /* do the normal thing */
322         RGBmode();
323     gconfig();
324 
325     qdevice( ESCKEY );
326     qdevice ( WINQUIT );
327     qdevice( REDRAW );
328     unqdevice( INPUTCHANGE );	/* We don`t pay attention to these. */
329 
330     if ( !gt )		/* Disable panning when in gt rectangle mode. */
331     {
332 	qdevice( LEFTMOUSE );	/* Pan the image under mouse control. */
333 	qdevice( LEFTALTKEY );	/* Reset panning. */
334 	qdevice( RIGHTALTKEY );
335 	qdevice( F9KEY );
336     }
337 
338     /* There was a redraw event sent when the window was created,
339      * but we weren`t listening for them yet.
340      */
341     qenter( REDRAW, window_number );
342 }
343 
344 /*
345  * Track events & redraw image when necessary.
346  */
update_pic()347 update_pic()
348 {
349     short data;
350     long event;
351     long window_x_size, window_y_size, window_x_origin, window_y_origin;
352     int x_min, x_max, y_min, y_max, x_start, y_start, x_end, y_end, x_len;
353     long x_origin, y_origin, new_x_center, new_y_center;
354     int x_center, y_center, saved_x_center, saved_y_center;
355 
356     register int y;
357     register unsigned char *y_ptr;
358 
359     /* Looking at the center, at first. */
360     x_center = saved_x_center = x_size / 2;
361     y_center = saved_y_center = y_size / 2;
362 
363     /* Redraw the window when necessary. */
364     while ( TRUE )
365     {
366         event = qread( &data );
367 # ifdef DEBUG
368 	printf( "event %d, data %d\n", event, data );
369 #endif
370 	switch ( event )
371 	{
372  	    case ESCKEY:
373             case WINQUIT:
374                 if(bitsavail==0) /* restore colormap */
375                     for(i=0;i<=127;i++)
376                         mapcolor((i+128),colmap[i][0],colmap[i][1],colmap[i][2]);
377  		gexit();
378  		exit(0);
379  		break;
380 	    case REDRAW:
381 		winset( window_number );
382 		reshapeviewport();
383 
384  		if ( gt )
385 		{
386 		    /* On a GT, just blast out the whole rectangle.  If the
387 		     * origin is off the screen to the left, it kills the
388 		     * window server.  Could duplicate the slow output logic
389 		     * below, but avoid the complication for now...
390 		     */
391 		    getorigin( &x_origin, &y_origin );
392 		    if ( x_origin < 0 )
393 		    {
394 			RGBcolor( 128, 128, 128 );	/* Punt. */
395 			clear();
396 		    }
397 		    else
398 			lrectwrite( 0, 0, x_size-1, y_size-1, rect_image );
399 		}
400 		else
401 		{
402 		    /* Do panning in a resizable window.  (Slow mode.) */
403 		    RGBcolor( 128, 128, 128 );
404 		    clear();
405 
406 		    /* Lower left corner of screen, in image coordinates.
407 		     * (Keep the center of the image in the center of the
408 		     * window.)
409 		     */
410 		    getsize( &window_x_size, &window_y_size );
411 		    x_min = x_center - window_x_size/2;
412 		    x_max = x_min + (window_x_size-1);
413 		    y_min = y_center - window_y_size/2;
414 		    y_max = y_min + (window_y_size-1);
415 
416 		    /* Coordinate bounds have half a pixel added all around. */
417 		    ortho2( x_min - .5, x_max + .5, y_min - .5, y_max + .5 );
418 
419 		    /* Draw just the part of the image in the window. */
420 		    x_start = MAX( x_min, 0 );
421 		    y_start = MAX( y_min, 0 );
422 		    x_end = MIN( x_max, x_size-1 );
423 		    y_end = MIN( y_max, y_size-1 );
424 		    x_len = x_end - x_start + 1;
425 
426 		    /* Dump the scanlines.  Check once in a while for another
427 		     * redraw event queued up, and quit early if one is seen.
428 		     */
429 		    y_ptr = rgb_image + y_start*x_size*3 + x_start;
430 		    for ( y = y_start;
431 			  y <= y_end && (y%16 != 0 || qtest() != REDRAW);
432 			  y++, y_ptr += x_size * 3 )
433 		    {
434 			cmov2i( x_start, y );
435 			writeRGB( x_len,
436 				  y_ptr, y_ptr + x_size, y_ptr + x_size * 2 );
437 		    }
438 		}
439 		break;
440 
441 	    /* Alt key - Reset viewing to look at the center of the image.
442 	     * Shift-Alt - Restores a saved view center.
443 	     * Control-alt - Saves the current view center for Shift-Setup.
444 	     * F9 is the same as the Alt keys.
445 	     */
446 	    case LEFTALTKEY:
447 	    case RIGHTALTKEY:
448 	    case F9KEY:
449 		if ( data == 1 )	/* Ignore button up events. */
450 		{
451 		    if ( getbutton(RIGHTSHIFTKEY) || getbutton(LEFTSHIFTKEY) )
452 		    {
453 			x_center = saved_x_center;	/* Restore. */
454 			y_center = saved_y_center;
455 			qenter( REDRAW, window_number );
456 		    }
457 		    else if ( getbutton(CTRLKEY) )
458 		    {
459 			saved_x_center = x_center;	/* Save. */
460 			saved_y_center = y_center;
461 		    }
462 		    else
463 		    {
464 			x_center = x_size / 2;		/* Reset. */
465 			y_center = y_size / 2;
466 			qenter( REDRAW, window_number );
467 		    }
468 
469 		}
470 		break;
471 
472 	    /* Pan a point picked with the left mouse button to the center
473 	     * of attention.  Beep if cursor is not on the image.
474 	     */
475 	    case LEFTMOUSE:
476 		if ( data == 1 ) 	/* Ignore button up events. */
477 		{
478 		    getorigin( &x_origin, &y_origin );
479 		    new_x_center = getvaluator( MOUSEX ) - x_origin + x_min;
480 		    new_y_center = getvaluator( MOUSEY ) - y_origin + y_min;
481 		    if ( new_x_center >= x_start &&
482 			 new_x_center <= x_end &&
483 			 new_y_center >= y_start &&
484 			 new_y_center <= y_end )
485 		    {
486 			x_center = new_x_center;
487 			y_center = new_y_center;
488 			qenter( REDRAW, window_number );
489 		    }
490 		    else
491 			ringbell();
492 		}
493 		break;
494 	}
495     }
496 }
497 
498 /*
499  * Pack a scanline into a vector of RGB longs.
500  *
501  * Inputs:
502  * 	rgb:		Pointers to buffers containing the red, green,
503  *			and blue color rows.
504  *	n:		Length of row.
505  *	line:		Pointer to output buffer for packed color data.
506  */
pack_rect_scanline(rgb,n,line)507 pack_rect_scanline( rgb, n, line )
508 unsigned char *rgb[3];
509 int n;
510 long *line;
511 {
512     register int i;
513     register long *dest = line;
514 
515     if ( !bwflag )			/* Color display. */
516     {
517 	register unsigned char *r, *g, *b;
518 
519 	for ( i = 0, r = rgb[0], g = rgb[1], b = rgb[2];
520 	      i < n; i++, r++, g++, b++ )
521 	    /* Combine 3 8-bit colors into a long. */
522 	    *dest++ = *r + (*g<<8) + (*b<<16);
523     }
524     else				/* Gray scale display. */
525     {
526 	register unsigned char *bw;
527 
528 	for ( i = 0, bw = rgb[0]; i < n; i++, bw++ )
529 	    *dest++ = *bw + (*bw<<8) + (*bw<<16);
530     }
531 }
532 
533 /*
534  * Pack a scanline into an RGB trio of vectors of bytes.
535  *
536  * Inputs:
537  * 	rgb:		Pointers to buffers containing the red, green,
538  *			and blue color rows.
539  *	n:		Length of row.
540  *	line:		Pointer to output buffer for packed color data.
541  */
pack_rgb_scanline(rgb,n,lines)542 pack_rgb_scanline( rgb, n, lines )
543 unsigned char *rgb[3];
544 int n;
545 unsigned char *lines;
546 {
547     int chnl;
548     register int i;
549     register unsigned char *src, *dest;
550 
551     for ( chnl = 0, dest = lines; chnl < 3; chnl++ )
552     {
553 	src = rgb[ bwflag ? 0 : chnl ];	/* Use just channel 0 for greyscale. */
554 	for ( i = 0; i < n; i++ )
555 	    *dest++ = *src++;
556     }
557 }
558 
559 /*
560  * This routine is called only if the color map is required.  It converts
561  * the 8 bit grey scale levels to 7 bit grey scale levels starting at 128
562  * and going through to 255.  We can't use the full 256 grey levels to
563  * display the image because the windows and text of other applications
564  * can't be seen if they are remapped to a grey scale.
565  */
convertgreylevels(void)566 convertgreylevels(void)
567 {
568     for(i=0;i<(x_size*y_size);i++)
569         (*(rect_image+i)) = (((*(rect_image+i))&255)>>1)|128;
570 }
571 
572 
573