[comp.os.minix] Bitmapped screen driver

7103_300@uwovax.uwo.ca (Eric Smith) (02/09/89)

Here's a screen driver that allows low level access to the bitmapped
graphics screen. It's specifically written for the Atari ST, but may be
portable to the IBM without undue work (I've tried hard to make the
interface as general as possible). This may give us something on
which to base a screen manager like MGR; that's what I hope, anyways.
--
Eric R. Smith                     email:
Dept. of Mathematics            7103_300@uwovax.uwo.ca
University of Western Ontario   7103_300@uwovax.bitnet
London, Ont. Canada N6A 5B7     (a shared mailbox: put my name on
ph: (519) 661-3638              the message, please!)
------------ cut here ------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README h.cdiff kernel.cdiff lib.cdiff sttools.cdiff
#   setcolr.c showpic.c
# Wrapped by eric@Eric's Minix/ST on Wed Feb  8 23:41:18 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3468 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XEnclosed are the diffs and files necessary to install a screen
Xdriver for the Atari ST version of Minix. All of the files ending
Xin .cdiff should be run through 'patch' in the appropriate directory
X(e.g. lib.cdiff are the patches for the C library, and kernel.cdiff
Xare the patches for the kernel). The file "h/screen.h" contains
Xdefinitions for accessing the screen, and should also be copied
Xto /usr/include/minix.
X
XFinally, you should cd to /dev and enter:
Xmknod screen c 1 4; chmod 666 screen
X
XTwo sample programs are also included. Showpic.c is a program for
Xdisplaying DEGAS format picture files; it takes one argument,
Xthe name of the file to display. Setcolr.c is a program for changing
Xscreen colors. It takes 4 arguments; the first is the index of the
Xcolor to change (0-16), and the second, third, and fourth are the
Xred, green, and blue values respectively to set the color to. These
Xmay range from 0 (minimum) to 255 (maximum). For example, the commands
X   setcolr 0 255 255 255; setcolr 1 0 0 0
Xchange the foreground color to white and the background color to black.
XIn medium resolution, only colors 0-3 are meaningful; in high res only
Xcolor 0 is meaningful, and can only assume two values, 0 (black) or
X255 (white).
X
XThings you can do with the screen driver:
X
XFirstly, it's a normal device; so
X   cp /dev/screen junk
Xcreates a screen dump in the file junk; later you can type
X   cp junk /dev/screen
Xto restore the old screen image.
X
XSecondly, various ioctl options are provided to allow for getting/setting
Xvarious screen parameters:
X
Xstruct scr_palette sc;
X
Xioctl(fd, SCRGETCOLOR, &sc):
Xioctl(fd, SCRSETCOLOR, &sc):
X	Get/set the screen color palette. This is a structure which
X	contains one member, an array called scr_rgb. sc.scr_rgb[i][0]
X	contains the red value (0..255) for color i, sc.scr_rgb[i][1] the
X	green value, and sc.scr_rgb[i][2] the blue.
X
Xstruct scr_param sp;
X
Xioctl(fd, SCRGETPARAM, &sp):
Xioctl(fd, SCRGETPARAM, &sp):
X	Get/set various screen parameters. The members of sp are:
X	  scr_width, scr_height: 	width and height of screen
X	  scr_depth:	number of bits used for each pixel
X	  scr_mode:	resolution: 0 for low, 1 for medium, 2 for high
X	  scr_base:	physical address of the screen
X	At present, only scr_mode and scr_base can be changed with the
X	SCRSETPARAM call (although changes to scr_mode will automatically
X	imply changes to the screen's height, width, and depth).
X
XVarious useful constants are defined in <minix/screen.h>; the comments
Xshould explain them.
X
XBUGS:
X	The console output routines and the screen driver don't know
Xabout each other. If you change the screen's physical address, you have
Xto send the appropriate ANSI codes to reset the tty, or no output
Xwill appear on screen (this could be construed as a feature, since it
Xmeans no interference with your graphics display).
X	The screen driver does its work without concern for the
Xniceties of video refresh; rapid page-flipping is likely to produce
Xugly results.
X	If you're running a multi-user system, security could be
Xa problem; allowing anyone else either read OR write access to
Xthe screen means that they can basically do what they want to it.
X	I haven't tested this in monochrome, but it should work
XOK.
X
XIf you find bugs, let me know at the e-mail address below.
X
XPLEASE NOTE: I share this mailbox with the rest of my department, so
Xif you want to make sure I get your mail, put "To: Eric Smith" as
Xthe subject line!
X
XEric R. Smith
X7103_300@uwovax.uwo.ca
END_OF_FILE
if test 3468 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'h.cdiff' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'h.cdiff'\"
else
echo shar: Extracting \"'h.cdiff'\" \(2623 characters\)
sed "s/^X//" >'h.cdiff' <<'END_OF_FILE'
X*** /tmp/,RCSt1000097	Wed Feb  8 23:09:51 1989
X--- com.h	Wed Feb  8 23:08:41 1989
X***************
X*** 34,39 ****
X--- 34,40 ----
X  #	define MEM_DEV     1	/* minor device for /dev/mem */
X  #	define KMEM_DEV    2	/* minor device for /dev/kmem */
X  #	define NULL_DEV    3	/* minor device for /dev/null */
X+ #	define SCR_DEV     4	/* minor device for /dev/screen */
X  
X  #define FLOPPY            -5	/* floppy disk class */
X  #define WINCHESTER        -6	/* winchester (hard) disk class */
X*** screen.h.B	Wed Feb  8 23:10:13 1989
X--- screen.h	Wed Feb  8 23:07:42 1989
X***************
X*** 0 ****
X--- 1,57 ----
X+ /* Data structures for IOCTL on /dev/screen */
X+ 
X+ #define SCR_NUM_COLORS	16	/* max possible num. of colors */
X+ 
X+ /* SCR_ALIGN gives a mask telling how the physical screen must be
X+    aligned (for the SCRSETP ioctl call. A typical use might be
X+       newscrn = malloc(size + SCR_ALIGN) & (~SCR_ALIGN)
X+    If SCR_ALIGN is -1, then the physical screen may not be remapped
X+ */
X+ #define SCR_ALIGN	0x0ffL
X+ 
X+ /* define the following only if the physical memory occupied by the
X+    screen is not accessible to user programs without an operating
X+    system request to re-map or shar memory (i.e. don't define this
X+    unless you have a version of Minix with a hardware memory
X+    manager
X+ */
X+ /* #define SCR_VIRT_MEM		/* screen lives in virtual memory */
X+ 
X+ 
X+ /* physical screen attributes; information returned by the
X+    SCRGETPARAM ioctl call */
X+ 
X+ struct scr_param {
X+ 	long	scr_base;	/* physical address of screen */
X+ 	short	scr_width;	/* width of screen (pixels) */
X+ 	short	scr_height;	/* height of screen (pixels) */
X+ 	short	scr_depth;	/* no. of bitplanes on screen */
X+ 	short	scr_mode;	/* special mode info about screen */
X+ };
X+ 
X+ /* Each palette entry for the screen colors holds three entries;
X+    the red, green, and blue values for this color, from 0 (no color)
X+    to 255 (max. color).
X+    The actual number of different values recognized by the hardware
X+    is given by SCR_RGB_VALUES; for example, the atari ST recognizes
X+    only 8 possible values for each of red, green, and blue, for
X+    a total of 512 colors; for it, SCR_RGB_VALUES == 8.
X+ */
X+ 
X+ #define SCR_RGB_VALUES 8
X+ 
X+ /* constants for accessing the scr_rgb array */
X+ #define RED 	0
X+ #define BLUE 	1
X+ #define GREEN	2
X+ 
X+ /* data structure returned by SCRGETCOLOR ioctl call */
X+ struct scr_palette {
X+ 	unsigned char scr_rgb[SCR_NUM_COLORS][3];
X+ };
X+ 
X+ 
X+ #define SCRGETPARAM     (('S'<<8) | 1)
X+ #define SCRSETPARAM	(('S'<<8) | 2)
X+ #define SCRGETCOLOR	(('S'<<8) | 3)
X+ #define SCRSETCOLOR	(('S'<<8) | 4)
END_OF_FILE
if test 2623 -ne `wc -c <'h.cdiff'`; then
    echo shar: \"'h.cdiff'\" unpacked with wrong size!
fi
# end of 'h.cdiff'
fi
if test -f 'kernel.cdiff' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'kernel.cdiff'\"
else
echo shar: Extracting \"'kernel.cdiff'\" \(6339 characters\)
sed "s/^X//" >'kernel.cdiff' <<'END_OF_FILE'
X*** /tmp/,RCSt1000068	Wed Feb  8 23:05:04 1989
X--- memory.c	Wed Feb  8 22:14:13 1989
X***************
X*** 3,8 ****
X--- 3,10 ----
X   *     /dev/mem		- absolute memory
X   *     /dev/kmem	- kernel virtual memory
X   *     /dev/ram		- RAM disk
X+  *     /dev/screen      - screen memory
X+  *
X   * It accepts three messages, for reading, for writing, and for
X   * control. All use message format m2 and with these parameters:
X   *
X***************
X*** 14,19 ****
X--- 16,31 ----
X   * |------------+---------+---------+---------+---------+---------|
X   * | DISK_IOCTL | device  |         |  blocks | ram org |         |
X   * ----------------------------------------------------------------
X+  *
X+  * In addition, the screen driver accepts ioctl messages like the
X+  * ones sent to the TTY driver (actually, they're the same message
X+  * format, but it seems more logical to use the TTY names for the
X+  * fields).
X+  *
X+  *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
X+  * ---------------------------------------------------------------------------
X+  * | TTY_IOCTL   | device | proc nr | func code| buf ptr |flags    |         |
X+  * ---------------------------------------------------------------------------
X   *  
X   *
X   * The file contains one entry point:
X***************
X*** 27,37 ****
X  #include "../h/callnr.h"
X  #include "../h/com.h"
X  #include "../h/error.h"
X  #include "const.h"
X  #include "type.h"
X  #include "proc.h"
X  
X! #define NR_RAMS            4	/* number of RAM-type devices */
X  #ifdef i8088
X  #define EM_ORIGIN   0x100000	/* origin of extended memory on the AT */
X  #endif
X--- 39,57 ----
X  #include "../h/callnr.h"
X  #include "../h/com.h"
X  #include "../h/error.h"
X+ #include "../h/screen.h"
X  #include "const.h"
X  #include "type.h"
X  #include "proc.h"
X  
X! #define MULT (256/SCR_RGB_VALUES)
X! 
X! #ifdef ATARI_ST
X! #include "staddr.h"
X! #include "stvideo.h"		/* for screen driver */
X! #endif
X! 
X! #define NR_RAMS            5	/* number of RAM-type devices */
X  #ifdef i8088
X  #define EM_ORIGIN   0x100000	/* origin of extended memory on the AT */
X  #endif
X***************
X*** 60,65 ****
X--- 80,93 ----
X    ram_limit[KMEM_DEV] = (sizes[0] + sizes[1]) << CLICK_SHIFT;
X    ram_limit[MEM_DEV] = MEM_BYTES;
X  
X+ #ifdef ATARI_ST
X+   ram_origin[SCR_DEV] = (phys_bytes) (
X+ 			( (VIDEO->vd_ramh & 0xFF) << 16L)
X+ 			|
X+ 			((VIDEO->vd_ramm & 0xFF) << 8L) );
X+   ram_limit[SCR_DEV] = ram_origin[SCR_DEV] + 32000L;
X+ #endif
X+ 
X    /* Here is the main loop of the memory task.  It waits for a message, carries
X     * it out, and sends a reply.
X     */
X***************
X*** 75,80 ****
X--- 103,109 ----
X  	switch(mess.m_type) {
X  	    case DISK_READ:	r = do_mem(&mess);	break;
X  	    case DISK_WRITE:	r = do_mem(&mess);	break;
X+ /* case TTY_IOCTL:    -- same value as DISK_IOCTL */
X  	    case DISK_IOCTL:	r = do_setup(&mess);	break;
X  	    default:		r = EINVAL;		break;
X  	}
X***************
X*** 94,100 ****
X  PRIVATE int do_mem(m_ptr)
X  register message *m_ptr;	/* pointer to read or write message */
X  {
X! /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
X  
X  #ifdef i8088
X    int device, count, words, status;
X--- 123,129 ----
X  PRIVATE int do_mem(m_ptr)
X  register message *m_ptr;	/* pointer to read or write message */
X  {
X! /* Read or write /dev/null, /dev/mem, /dev/kmem, /dev/ram, or /dev/screen. */
X  
X  #ifdef i8088
X    int device, count, words, status;
X***************
X*** 160,167 ****
X--- 189,293 ----
X    int device;
X  
X    device = m_ptr->DEVICE;
X+   if (device == SCR_DEV)
X+ 	return do_ioctl(m_ptr);
X    if (device != RAM_DEV) return(ENXIO);	/* bad minor device */
X    ram_origin[device] = m_ptr->POSITION;
X    ram_limit[device] = m_ptr->POSITION + (long) m_ptr->COUNT * BLOCK_SIZE;
X    return(OK);
X+ }
X+ 
X+ /*===========================================================================*
X+  *				do_ioctl				     *
X+  *===========================================================================*/
X+ PRIVATE do_ioctl(m_ptr)
X+ message *m_ptr;			/* pointer to message sent to task */
X+ {
X+ 
X+ 	static struct scr_param sp;
X+ 	static struct scr_palette sc;
X+ 
X+ 	int r, count, set, request, i;
X+ 	unsigned short color;
X+ 	phys_bytes user_buf, our_buf;
X+ 	struct proc *rp;
X+ 	extern phys_bytes umap();
X+ 
X+ 	r = OK;
X+ 	rp = proc_addr(m_ptr->PROC_NR);
X+ 	request = m_ptr->TTY_REQUEST;
X+ 	if (request == SCRGETPARAM || request == SCRSETPARAM) {
X+ 		count = sizeof(sp);
X+ 		our_buf = (phys_bytes) &sp;
X+ 		set = (request == SCRSETPARAM);
X+ 	}
X+ 	else if (request == SCRGETCOLOR || request == SCRSETCOLOR) {
X+ 		count = sizeof(sc);
X+ 		our_buf = (phys_bytes) &sc;
X+ 		set = (request == SCRSETCOLOR);
X+ 	}
X+ 	else
X+ 		return EINVAL;
X+ 
X+ 	user_buf = umap(rp,D,(vir_bytes) m_ptr->TTY_SPEK,(vir_bytes) count);
X+ 	if (set)
X+ 		phys_copy(user_buf, our_buf, (long) count);
X+ 
X+ 	switch (request) {
X+ 	   case SCRGETPARAM:
X+ 		sp.scr_base = ram_origin[SCR_DEV];
X+ #ifdef ATARI_ST
X+ 		sp.scr_mode = (VIDEO->vd_res) & 0x03;
X+ 		switch (sp.scr_mode) {
X+ 		   case RES_LOW:
X+ 			sp.scr_width = 320;
X+ 			sp.scr_height = 200;
X+ 			sp.scr_depth = 4;
X+ 			break;
X+ 		   case RES_MID:
X+ 			sp.scr_width = 640;
X+ 			sp.scr_height = 200;
X+ 			sp.scr_depth = 2;
X+ 			break;
X+ 		   default:
X+ 			sp.scr_width = 640;
X+ 			sp.scr_height = 400;
X+ 			sp.scr_depth = 1;
X+ 			break;
X+ 		}
X+ #endif
X+ 		break;
X+ 	   case SCRSETPARAM:
X+ 		VIDEO->vd_res = sp.scr_mode & 0x03;
X+ 		ram_origin[SCR_DEV] = sp.scr_base & 0x00ffff00L;
X+ 		ram_limit[SCR_DEV] = ram_origin[SCR_DEV] + 32000L;
X+ 		VIDEO->vd_ramh = (sp.scr_base & 0x00ff0000L) >> 16;
X+ 		VIDEO->vd_ramm = (sp.scr_base & 0x0000ff00L) >> 8;
X+ 		break;
X+ 	   case SCRGETCOLOR:
X+ 		for (i = 0; i < SCR_NUM_COLORS; i++) {
X+ #ifdef ATARI_ST
X+ 			color = VIDEO->vd_rgb[i];
X+ 			sc.scr_rgb[i][BLUE] = MULT * (color & RGB_B);
X+ 			sc.scr_rgb[i][GREEN] = MULT * ((color & RGB_G) >> 4);
X+ 			sc.scr_rgb[i][RED] = MULT * ((color & RGB_R) >> 8);
X+ #endif
X+ 		}
X+ 		break;
X+ 	   case SCRSETCOLOR:
X+ 		for (i = 0; i < SCR_NUM_COLORS; i++) {
X+ #ifdef ATARI_ST
X+ 			color = sc.scr_rgb[i][RED] / MULT;
X+ 			color = color << 4;
X+ 			color |= (sc.scr_rgb[i][GREEN] / MULT);
X+ 			color = color << 4;
X+ 			color |= (sc.scr_rgb[i][BLUE] / MULT);
X+ 			VIDEO->vd_rgb[i] = color;
X+ #endif
X+ 		}
X+ 		break;
X+ 	}
X+ 	if (!set)
X+ 		phys_copy(our_buf, user_buf, (long) count);
X+ 	return r;
X  }
END_OF_FILE
if test 6339 -ne `wc -c <'kernel.cdiff'`; then
    echo shar: \"'kernel.cdiff'\" unpacked with wrong size!
fi
# end of 'kernel.cdiff'
fi
if test -f 'lib.cdiff' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lib.cdiff'\"
else
echo shar: Extracting \"'lib.cdiff'\" \(785 characters\)
sed "s/^X//" >'lib.cdiff' <<'END_OF_FILE'
X*** /tmp/,RCSt1000122	Wed Feb  8 23:14:07 1989
X--- ioctl.c	Wed Feb  8 16:03:49 1989
X***************
X*** 1,6 ****
X--- 1,7 ----
X  #include "lib.h"
X  #include <minix/com.h>
X  #include <sgtty.h>
X+ #include <minix/screen.h>
X  
X  PUBLIC int ioctl(fd, request, u)
X  int fd;
X***************
X*** 8,13 ****
X--- 9,16 ----
X  union {
X    struct sgttyb *argp;
X    struct tchars *argt;
X+   struct scr_param *args1;
X+   struct scr_palette *args2;
X  } u;
X  
X  {
X***************
X*** 55,60 ****
X--- 58,71 ----
X    	u.argt->t_brkc   = (M.TTY_FLAGS >> 8) & 0377;
X    	return(n);
X  
X+      case SCRSETPARAM:
X+      case SCRGETPARAM:
X+      case SCRSETCOLOR:
X+      case SCRGETCOLOR:
X+ 	M.TTY_SPEK = (long) u.args1;
X+ 	n = callx(FS, IOCTL);
X+ 	return(n);
X+ 	
X       default:
X  	n = -1;
X  	errno = -(EINVAL);
END_OF_FILE
if test 785 -ne `wc -c <'lib.cdiff'`; then
    echo shar: \"'lib.cdiff'\" unpacked with wrong size!
fi
# end of 'lib.cdiff'
fi
if test -f 'sttools.cdiff' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sttools.cdiff'\"
else
echo shar: Extracting \"'sttools.cdiff'\" \(367 characters\)
sed "s/^X//" >'sttools.cdiff' <<'END_OF_FILE'
X*** /tmp/,RCSt1000111	Wed Feb  8 23:12:41 1989
X--- Makedev	Wed Feb  8 23:02:58 1989
X***************
X*** 2,7 ****
X--- 2,8 ----
X  mknod mem c 1 1; chmod 640 mem
X  mknod kmem c 1 2; chmod 640 kmem
X  mknod null c 1 3; chmod 666 null
X+ mknod screen c 1 4; chmod 666 screen
X  mknod fd0 b 2 0; chmod 666 fd0
X  mknod fd1 b 2 1; chmod 666 fd1
X  mknod dd0 b 2 8; chmod 666 dd0
END_OF_FILE
if test 367 -ne `wc -c <'sttools.cdiff'`; then
    echo shar: \"'sttools.cdiff'\" unpacked with wrong size!
fi
# end of 'sttools.cdiff'
fi
if test -f 'setcolr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'setcolr.c'\"
else
echo shar: Extracting \"'setcolr.c'\" \(648 characters\)
sed "s/^X//" >'setcolr.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <minix/screen.h>
X
Xmain(argc, argv)
Xint argc; char *argv[];
X{
X	int n, red, green, blue, fd;
X	struct scr_palette sc;
X
X	if (argc != 5) {
X		fprintf(stderr, "Usage: setcolr n red green blue\n");
X		exit(1);
X	}
X	n = atoi(argv[1]);
X	if (n < 0 || n >= SCR_NUM_COLORS) {
X		fprintf(stderr, "Illegal color number\n");
X		exit(1);
X	}
X	red = atoi(argv[2]);
X	green = atoi(argv[3]);
X	blue = atoi(argv[4]);
X	if ( (fd = open("/dev/screen", 0)) < 0) {
X		perror("/dev/screen");
X		exit(2);
X	}
X	ioctl(fd, SCRGETCOLOR, &sc);
X	sc.scr_rgb[n][RED] = red;
X	sc.scr_rgb[n][GREEN] = green;
X	sc.scr_rgb[n][BLUE] = blue;
X	ioctl(fd, SCRSETCOLOR, &sc);
X}
END_OF_FILE
if test 648 -ne `wc -c <'setcolr.c'`; then
    echo shar: \"'setcolr.c'\" unpacked with wrong size!
fi
# end of 'setcolr.c'
fi
if test -f 'showpic.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'showpic.c'\"
else
echo shar: Extracting \"'showpic.c'\" \(2115 characters\)
sed "s/^X//" >'showpic.c' <<'END_OF_FILE'
X/* Program to display DEGAS format pictures on the screen */
X
X#include <stdio.h>
X#include <minix/screen.h>
X#define MULT (256/SCR_RGB_VALUES)
X
Xstruct scr_palette newsc, oldsc;
Xstruct scr_param sp;
X
Xmain(argc, argv)
Xint argc; char *argv[];
X{
X	extern char *malloc();
X	long screen, buff;
X	int scr, pic;
X	int red, green, blue;
X	unsigned short color, res, oldres;
X	int i;
X
X	if (argc != 2) {
X		fprintf(stderr, "Usage: showpic file\n");
X		exit(1);
X	}
X
X	if ( (buff = (long) malloc(32000 + SCR_ALIGN)) == 0L) {
X		fprintf(stderr, "Couldn't allocate 32K\n");
X		exit(1);
X	}
X	buff &= (~SCR_ALIGN);
X
X/* open picture file */
X	if ( (pic = open(argv[1], 0)) < 0 ) {
X		perror(argv[1]);
X		exit(1);
X	}
X
X/* open screen */
X	if ( (scr = open("/dev/screen", 0)) < 0 ) {
X		perror("/dev/screen");
X		exit(2);
X	}
X
X/* get screen parameters and colors */
X	ioctl(scr, SCRGETPARAM, &sp);
X	ioctl(scr, SCRGETCOLOR, &oldsc);
X
X	read(pic, &res, 2);		/* read resolution */
X	if (res < 0 || res > 2) {
X		fprintf(stderr, "%s: not a DEGAS picture file!\n", argv[1]);
X		exit(1);
X	}
X	if (res == 2 && sp.scr_mode != 2) {
X		fprintf(stderr, "Can't view mono picture in color.\n");
X		exit(1);
X	}
X	else if (sp.scr_mode == 2 && res != 2) {
X		fprintf(stderr, "Can't view color picture in mono.\n");
X		exit(1);
X	}
X
X/* set up screen colors to match picture */
X	for (i = 0; i < 16; i++) {
X		read(pic, &color, 2);
X		newsc.scr_rgb[i][BLUE] = MULT * (color & 0x007);
X		newsc.scr_rgb[i][GREEN] = MULT * ((color & 0x070) >> 4);
X		newsc.scr_rgb[i][RED] = MULT * ((color & 0x0700) >> 8);
X	}
X
X/* read picture */
X	read(pic, buff, 32000);
X
X/* set screen resolution to match picture */
X	oldres = sp.scr_mode;
X	sp.scr_mode = res;
X
X/* save old screen address, then set the new address and new colors */
X	screen = sp.scr_base;
X	sp.scr_base = buff;
X	ioctl(scr, SCRSETPARAM, &sp);
X	ioctl(scr, SCRSETCOLOR, &newsc);
X
X/* wait for user to hit return */
X	read(0, &color, 1);
X
X/* restore former screen attributes, colors, and address */
X	sp.scr_mode = oldres;
X	sp.scr_base = screen;
X	ioctl(scr, SCRSETPARAM, &sp);
X	ioctl(scr, SCRSETCOLOR, &oldsc);
X
X/* tidy up */
X	close(pic);
X	close(scr);
X}
END_OF_FILE
if test 2115 -ne `wc -c <'showpic.c'`; then
    echo shar: \"'showpic.c'\" unpacked with wrong size!
fi
# end of 'showpic.c'
fi
echo shar: End of shell archive.
exit 0