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 >flag,
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