This is getmex.c in view mode; [Download] [Up]
/*
* getmex.c - Put RLE images on the Iris display under the window manager.
*
* Author: Russell D. Fish (Based on getX.c .)
* Computer Science Dept.
* University of Utah
* Date: Wed Nov 19 1986
* Copyright (c) 1986, University of Utah
*
*/
#include <stdio.h>
#include <math.h>
#include "gl.h"
#include "device.h"
#include "rle.h"
#ifdef USE_STDLIB_H
#include <stdlib.h>
#else
#ifdef USE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#ifdef VOID_STAR
extern void *malloc();
#else
extern char *malloc();
#endif
extern void free();
#endif
#define MAX(i,j) ( (i) > (j) ? (i) : (j) )
#define MIN(i,j) ( (i) < (j) ? (i) : (j) )
/* Global variables. */
Colorindex color_start = 512; /* Default color map start of 3/3/3 rgb cube. */
Colorindex bw_start = 128; /* Default color map start of 128 slot grey ramp. */
long window_number; /* Window number from MEX. */
int x_size, y_size; /* Size of image. */
int dbg = 0; /* Set if debug mode. */
int forkflg = 0; /* Set if not to run in background. */
int bwflag = 0; /* Set for greyscale output. */
Colorindex *image; /* Image data buffer pointer. */
#define levels 8 /* Compute 3 bits per channel. */
int modN[256], divN[256]; /* Speed up with precomputed lookup tables. */
/*
* Basic 4x4 magic square for dithering
*/
int magic[4][4] = {
0, 14, 3, 13,
11, 5, 8, 6,
12, 2, 15, 1,
7, 9, 4, 10
};
int dm16[16][16]; /* 16x16 magic square, filled in by init_dither. */
/* From Kitaoka's dithering code */
#if 0
int dm4[4][4] = {
0, 43, 9, 40,
34, 15, 25, 18,
37, 6, 46, 3,
21, 28, 12, 31 };
#endif
/*****************************************************************
* TAG( main )
*
* Usage:
* getmex [-f] [-D] [-w] [file]
* Inputs:
* -f: Don't fork after putting image on screen.
* -D: Debug mode: print input file as read.
* -w: Black & white: reduce color images to B&W before display.
* Advantage is that smoother shading can be achieved.
* -m mapstart Where to start using the color map. 128 colors are
* used for B&W images, starting at 128 by default unless
* overridden by this flag. 512 colors are used for color images,
* starting at color map location 512.
* file: Input Run Length Encoded file. Uses stdin if not
* specified.
* Outputs:
* Puts image in a window on the screen.
* Assumptions:
* Input file is in RLE format.
*/
main(argc, argv)
char **argv;
{
int mapstart, mapflag = 0;
char *infname = NULL;
FILE * infile = stdin;
/* Handle arguments. */
if ( scanargs( argc, argv, "% f%- w%- D%- m%-mapstart!d file%s",
&forkflg, &bwflag, &dbg, &mapflag, &mapstart, &infname ) == 0 )
exit( 1 );
if ( mapflag )
if ( bwflag ) bw_start = mapstart; else color_start = mapstart;
infile = rle_open_f("getmex", infname, "r");
init_dither(); /* Set up the dither matrices. */
get_pic( infile, infname ); /* Read image and make a window for it. */
update_pic(); /* Keep drawing the window. */
}
/*
* Read an image from the input file and display it.
*/
get_pic( infile, infname )
FILE * infile;
char * infname;
{
register int i, y;
int ncolors;
unsigned char *scan[3];
/*
* Read setup info from file.
*/
rle_dflt_hdr.rle_file = infile;
if ( rle_get_setup( &rle_dflt_hdr ) < 0 )
{
fprintf(stderr, "getmex: Error reading setup information from %s\n",
infname ? infname : "stdin");
exit(1);
}
if ( dbg )
rle_debug( 1 );
/* We`re only interested in R, G, & B */
RLE_CLR_BIT(rle_dflt_hdr, RLE_ALPHA);
for (i = 3; i < rle_dflt_hdr.ncolors; i++)
RLE_CLR_BIT(rle_dflt_hdr, i);
ncolors = rle_dflt_hdr.ncolors > 3 ? 3 : rle_dflt_hdr.ncolors;
if ( ncolors == 1 ) bwflag = TRUE;
/*
* Compute image size and allocate storage for colormapped image.
*/
x_size = (rle_dflt_hdr.xmax - rle_dflt_hdr.xmin + 1);
y_size = (rle_dflt_hdr.ymax - rle_dflt_hdr.ymin + 1);
image = (Colorindex *) malloc(x_size * y_size * sizeof( Colorindex ));
/*
* Set up for rle_getrow. Pretend image x origin is 0.
*/
for (i = 0; i < 3; i++)
scan[i] = (unsigned char *) malloc(x_size);
rle_dflt_hdr.xmax -= rle_dflt_hdr.xmin;
rle_dflt_hdr.xmin = 0;
/* For each scan line, dither it into the image memory. */
while ((y = rle_getrow(&rle_dflt_hdr, scan)) <= rle_dflt_hdr.ymax)
{
if ( bwflag && ncolors > 1 )
{
rgb_to_bw( scan[0], scan[1], scan[ncolors - 1], scan[0], x_size );
/* Note: map_scanline only uses channel 0 for B&W */
}
map_scanline( scan, x_size, y,
&image[(y - rle_dflt_hdr.ymin) * x_size] );
}
/*
* Free temp storage
*/
for (i = 0; i < 3; i++)
free(scan[i]);
/*
* Get a window of the right size (user positions it with the mouse).
*/
if ( forkflg ) foreground(); /* Don`t fork. */
maxsize( x_size, y_size );
window_number = winopen( "getmex" );
if ( infname ) wintitle( infname );
makemap(); /* Initialize the Iris color map. */
qdevice( REDRAW );
qdevice( LEFTMOUSE ); /* Pan the image under mouse control. */
qdevice( SETUPKEY ); /* Reset panning. */
unqdevice( INPUTCHANGE ); /* We don`t pay attention to these. */
/* There was a redraw event sent when the window was created,
* but we weren`t listening for them yet.
*/
qenter( REDRAW, window_number );
}
/*
* Track events & redraw image when necessary.
*/
update_pic()
{
short data;
long event;
int window_x_size, window_y_size, window_x_origin, window_y_origin;
int x_min, x_max, y_min, y_max, x_start, y_start, x_end, y_end, x_len;
int x_origin, y_origin, new_x_center, new_y_center;
int x_center, y_center, saved_x_center, saved_y_center;
register int y;
register Colorindex *y_ptr;
/* Looking at the center, at first. */
x_center = saved_x_center = x_size / 2;
y_center = saved_y_center = y_size / 2;
/* Redraw the window when necessary. */
while ( TRUE )
{
event = qread( &data );
# ifdef DEBUG
printf( "event %d, data %d\n", event, data );
#endif
switch ( event )
{
case REDRAW:
winset( window_number );
reshapeviewport();
color( 22 );
clear();
/* Lower left corner of screen, in image coordinates.
* (Keep the center of the image in the center of the window.)
*/
getsize( &window_x_size, &window_y_size );
x_min = x_center - window_x_size/2;
x_max = x_min + (window_x_size-1);
y_min = y_center - window_y_size/2;
y_max = y_min + (window_y_size-1);
/* Coordinate bounds have half a pixel added all around. */
ortho2( x_min - .5, x_max + .5, y_min - .5, y_max + .5 );
/* Draw just the part of the image in the window. */
x_start = MAX( x_min, 0 );
y_start = MAX( y_min, 0 );
x_end = MIN( x_max, x_size-1 );
y_end = MIN( y_max, y_size-1 );
x_len = x_end - x_start + 1;
/* Dump the scanlines. Check once in a while for another
* redraw event queued up, and quit early if one is seen.
*/
for ( y = y_start, y_ptr = image + y_start*x_size + x_start;
y <= y_end && (y%16 != 0 || qtest() != REDRAW);
y++, y_ptr += x_size )
{
cmov2i( x_start, y );
writepixels( x_len, y_ptr );
}
break;
/* Setup key - Reset viewing to look at the center of the image.
* Shift-Setup - Restores a saved view center.
* Control-Setup - Saves the current view center for Shift-Setup.
*/
case SETUPKEY:
if ( data == 1 ) /* Ignore button up events. */
{
if ( getbutton(RIGHTSHIFTKEY) || getbutton(LEFTSHIFTKEY) )
{
x_center = saved_x_center; /* Restore. */
y_center = saved_y_center;
qenter( REDRAW, window_number );
}
else if ( getbutton(CTRLKEY) )
{
saved_x_center = x_center; /* Save. */
saved_y_center = y_center;
}
else
{
x_center = x_size / 2; /* Reset. */
y_center = y_size / 2;
qenter( REDRAW, window_number );
}
}
break;
/* Pan a point picked with the left mouse button to the center
* of attention. Beep if cursor is not on the image.
*/
case LEFTMOUSE:
if ( data == 1 ) /* Ignore button up events. */
{
getorigin( &x_origin, &y_origin );
new_x_center = getvaluator( MOUSEX ) - x_origin + x_min;
new_y_center = getvaluator( MOUSEY ) - y_origin + y_min;
if ( new_x_center >= x_start &&
new_x_center <= x_end &&
new_y_center >= y_start &&
new_y_center <= y_end )
{
x_center = new_x_center;
y_center = new_y_center;
qenter( REDRAW, window_number );
}
else
ringbell();
}
break;
}
}
}
/*
* Map a scanline to 8 bits through the dither matrix.
*
* Inputs:
* rgb: Pointers to buffers containing the red, green,
* and blue color rows.
* n: Length of row.
* s: Skip between pixels in original image.
* y: Y position of row (necessary for dither)
* line: Pointer to output buffer for dithered color data.
*/
map_scanline( rgb, n, y, line )
unsigned char *rgb[3];
Colorindex *line;
{
register int i, col;
int row, *row_ptr;
# define DMAP(v,x) (modN[v]>row_ptr[x] ? divN[v] + 1 : divN[v])
row = y % 16;
row_ptr = dm16[ row ]; /* Cache ptr to row of dither array. */
if ( !bwflag ) /* Color display. */
{
register unsigned char *r, *g, *b;
for ( col = 0, i = 0, r = rgb[0], g = rgb[1], b = rgb[2];
i < n; i++, r++, g++, b++, col = ((col + 1) & 15) )
{
/* Combine 3 3-bit colors into a 3/3/3 color map index. */
line[i] = color_start + DMAP(*r, col) + (DMAP(*g, col)<<3) +
(DMAP(*b, col)<<6);
}
}
else /* Gray scale display. */
{
register unsigned char *bw;
for ( i = 0, bw = rgb[0]; i < n; i++, bw++ )
line[i] = bw_start + (*bw>>1);
}
}
#if 0
/* From Kitaoka's dithering code */
dmap(v,x,y)
register v;
int x,y ;
{
int d ;
v = gammamap[v];
d = dm4[x%4][y%4] ;
if ((v%51)>d) return (v/51)+1 ; else return (v/51) ;
}
#endif
init_dither() /* Miscellaneous global setup. */
{
int i, j, k, l, planes, pixels[216];
unsigned int value;
float N, magicfact;
N = (255.0 / (levels - 1)); /* Size of each step in intensity. */
for ( i = 0; i < 256; i++ )
{
divN[i] = (int)(i / N);
modN[i] = i - (int)(N * divN[i]);
}
modN[255] = 0;
#ifdef DEBUG
printf( "divN.modN:\n" );
for ( i = 0; i < 256; i += 8 )
{
for ( j = i; j < i + 8; j++ )
printf( "%3d.%3d ", divN[j], modN[j] );
printf( "\n" );
}
#endif /* DEBUG */
/*
* Expand 4x4 dither pattern to 16x16. 4x4 leaves obvious patterning,
* and doesn`t give us full intensity range (only 17 sublevels,
* we want at least 51). Note that 8x8 would be sufficient, but
* 16x16 is easier to build.
*
* magicfact is (N - 2)/16 so that we get numbers in the matrix from 0 to
* N - 2: mod N gives numbers in 0 to N - 1, we want some chance that the
* number is greater than a matrix entry, so the highest matrix
* entry must be N - 2.
*/
magicfact = (N - 2) / 16.;
for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
for ( k = 0; k < 4; k++ )
for ( l = 0; l < 4; l++ )
dm16[4*k+i][4*l+j] =
(int)(0.5 + magic[i][j] * magicfact +
(magic[k][l] / 16.) * magicfact);
#ifdef DEBUG
printf( "Magic square: \n" );
for ( i = 0; i < 16; i++ )
{
for ( j = 0; j < 16; j++ )
printf( "%4d", dm16[i][j] );
printf( "\n" );
}
#endif
}
/** NOTE: This is the makemap program from /usr/people/gifts/mextools/tools,
** with the gamma and getset routines from /usr/people/gifts/mextools/portlib
** appended. The only modification is that it only does the part of the map
** required here, and expands the RGB map to 512 colors.
**/
/*
* Make the color map using the clues provided by ~/.desktop
* most of the mextools need the colors mapped by this program.
*
* Paul Haeberli - 1984
*
*/
/** #include "gl.h" **/
/** #include "gl2/port.h" **/
float getgamma();
makemap()
{
register int i, j, v;
register int r, g, b, w;
int planes;
planes = getplanes();
/* if there are more than 8 planes make a ramp at 128 */
/** Position as specified, and only do it if showing a b&w image. **/
if (planes > 8 /**>**/ && bwflag /**<**/ )
for (i=0; i<128; i++) {
gammapcolor(i+ /**128>**/ bw_start /**<**/,i<<1,i<<1,i<<1);
}
/* if there are more than 8 planes make an ordered color map at 256 */
/** but if more than 9 planes, make the map at 512, 512 colors long. **/
if (planes > 9 /**>**/ && ! bwflag /**<**/ ) /** => **/
for (i=0; i<512; i++) {
r = (i>>0) & 7;
g = (i>>3) & 7;
b = (i>>6) & 7;
r = (255*r)/7;
g = (255*g)/7;
b = (255*b)/7;
gammapcolor(i+ /**512>**/ color_start /**<**/,r,g,b);
}
}
/*
* gamma -
* Some support for gamma correction when reading and writing
* color map entries.
*
* Paul Haeberli - 1984
*
*/
/** #include "math.h" **/
/** #include "port.h" **/
/** #include "gl.h" **/
/** #include "stdio.h" **/
FILE *configopen();
float gammacorrect();
float ungammacorrect();
static unsigned char rgamtable[256];
static unsigned char ggamtable[256];
static unsigned char bgamtable[256];
static unsigned char rungamtable[256];
static unsigned char gungamtable[256];
static unsigned char bungamtable[256];
static short firsted;
gammapcolor(index,r,g,b)
register int index,r,g,b;
{
short i;
if (!firsted) {
readgamtables();
firsted++;
}
r = rgamtable[r&0xff];
g = ggamtable[g&0xff];
b = bgamtable[b&0xff];
mapcolor(index,r,g,b);
}
static makegamtables()
{
register float gamval;
register float val;
register short i;
int rbal, gbal, bbal;
gamval = getgamma();
getcolorbal(&rbal,&gbal,&bbal);
for (i=0; i<256; i++) {
rgamtable[i] = 255*gammacorrect((rbal*i)/(255.0*255.0),gamval);
ggamtable[i] = 255*gammacorrect((gbal*i)/(255.0*255.0),gamval);
bgamtable[i] = 255*gammacorrect((bbal*i)/(255.0*255.0),gamval);
}
bzero(rungamtable,256);
bzero(gungamtable,256);
bzero(bungamtable,256);
for (i=0; i<256; i++) {
rungamtable[rgamtable[i]] = i;
gungamtable[ggamtable[i]] = i;
bungamtable[bgamtable[i]] = i;
}
fixup(rungamtable);
fixup(gungamtable);
fixup(bungamtable);
}
static fixup(cptr)
register unsigned char *cptr;
{
register short i, lowval;
for (i=256; i--; ) {
if (*cptr == 0)
*cptr = lowval;
else
lowval = *cptr;
}
}
gamgetmcolor(index,r,g,b)
int index;
unsigned short *r, *g, *b;
{
static short firsted;
unsigned short tr, tg, tb;
if (!firsted) {
readgamtables();
firsted++;
}
getmcolor(index,&tr,&tg,&tb);
*r = rungamtable[tr&0xff];
*g = gungamtable[tg&0xff];
*b = bungamtable[tb&0xff];
}
float gammacorrect( i, gamma)
float i, gamma;
{
return pow(i,1.0/gamma);
}
float ungammacorrect( i, gamma)
float i, gamma;
{
return pow(i,gamma);
}
newgamma()
{
firsted = firsted = 0;
}
newgamtables()
{
FILE *outf;
if ((outf = configopen(".gamtables","w")) == 0) {
fprintf(stderr,"couldn't open .gamtables\n");
return;
}
makegamtables();
fwrite(rgamtable,256,1,outf);
fwrite(ggamtable,256,1,outf);
fwrite(bgamtable,256,1,outf);
fwrite(rungamtable,256,1,outf);
fwrite(gungamtable,256,1,outf);
fwrite(bungamtable,256,1,outf);
fclose(outf);
}
readgamtables()
{
FILE *inf;
if ((inf = configopen(".gamtables","r")) == 0) {
newgamtables();
if ((inf = configopen(".gamtables","r")) == 0) {
fprintf(stderr,"couldn't open .gamtables\n");
return;
}
}
fread(rgamtable,256,1,inf);
fread(ggamtable,256,1,inf);
fread(bgamtable,256,1,inf);
fread(rungamtable,256,1,inf);
fread(gungamtable,256,1,inf);
fread(bungamtable,256,1,inf);
fclose(inf);
}
/*
* getset -
* Get and set values stored in ~/.desktop and ~/.gamma
*
* Paul Haeberli - 1984
*
*/
/** #include "stdio.h" **/
/** #include "port.h" **/
/** #include "gl.h" **/
FILE *configopen();
/** savecolors and restorecolors **/
float getgamma()
{
FILE *gamfile;
float gam;
if ((gamfile = configopen(".gamma","r")) ) {
if (fscanf(gamfile,"%f\n",&gam) == 1) {
fclose(gamfile);
return gam;
} else
fclose(gamfile);
}
return 2.2;
}
setgamma( gam )
float gam;
{
FILE *gamfile;
if ((gamfile = configopen(".gamma","w")) == 0) {
fprintf(stderr,"couldn't open .gamma\n");
return;
}
fprintf(gamfile,"%f\n",gam);
fclose(gamfile);
newgamtables();
}
getcolorbal(r,g,b)
unsigned int *r, *g, *b;
{
FILE *cbfile;
if ((cbfile = configopen(".cbal","r")) ) {
if (fscanf(cbfile,"%d %d %d\n",r,g,b) == 3) {
if (*r>255)
*r = 255;
if (*g>255)
*g = 255;
if (*b>255)
*b = 255;
fclose(cbfile);
return;
} else
fclose(cbfile);
}
*r = 255;
*g = 255;
*b = 255;
return;
}
setcolorbal(r,g,b)
int r, g, b;
{
FILE *cbfile;
if ((cbfile = configopen(".cbal","w")) == 0) {
fprintf(stderr,"couldn't open .cbal\n");
return;
}
fprintf(cbfile,"%d %d %d\n",r,g,b);
fclose(cbfile);
newgamtables();
}
FILE *configopen( name, mode )
char name[];
char mode[];
{
char homepath[100];
FILE *f;
char *cptr;
cptr = (char *)getenv("HOME");
if (!cptr)
return 0;
strcpy(homepath,cptr);
strcat(homepath,"/");
strcat(homepath,name);
return fopen(homepath,mode);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.