[comp.sources.unix] v10i092: A graphics editor, Part02/04

rs@uunet.UU.NET (Rich Salz) (08/06/87)

Submitted-by: "Alan W. Paeth" <awpaeth%watcgl.waterloo.edu@RELAY.CS.NET>
Posting-number: Volume 10, Issue 92
Archive-name: lemming/Part02

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	lemmain.c
#	lemmark.c
#	lemmisc.c
#	lemobj.c
#	lemobjsup.c
#	lemop.c
#	lempic.c
#	lemrc.c
#	lemselect.c
#	lemspecial.c
#	lemstart.c
#	lemstop.c
#	lemtext.c
#	lemtick.c
#	lemundo.c
#	lemvec.c
#	lemx.c
# This archive created: Fri Jun 12 18:35:10 1987
# By:	watcgl!awpaethexport PATH; PATH=/bin:$PATH
if test -f 'lemmain.c'
then
	echo shar: over-writing existing file "'lemmain.c'"
fi
cat << \SHAR_EOF > 'lemmain.c'
/*
 * lemmain.c - little editor for mice and other furry rodents (aka lemming)
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

main(argc, argv)
    char **argv;
    {
    int x, y, xup, yup, mup;
    int event, near, drag, dragdist;
    char ch;

    startup(argc, argv);

    while(1)
	{
	event = getevent(&x, &y, &xup, &yup, &ch);
	if (event != NOEVT) msgclear();
	switch(event)
	    {
case NOEVT: idle(); break;
case ALPHA: charadd(line, ch); break;
case CNTRL: switch(ch)
		{
		case C(Q): if (quitconfirm()) break;
		case C(A): all(SELECT, 0); break;
		case C(B): remake(BOX); break;
		case C(C): copysel(); break;
		case C(D): objcompress(); all(DELETE, 0); undo=UNDODEL; break;
		case C(E): remake(ELLI); break;
		case C(F): forceattr(); break;
		case C(G): addgroup(); break;
		case '\177': 					/* <DEL>  */
		case C(H): chardel(line,1); break;		/* <BS>  */
		case C(I): cycleselect(); markdelete(); break;	/* <TAB> */
		case C(J):					/* <LF>, */
		case C(M): if (markon) stringadd(); break;	/* <CR>  */
/*		case C(K): curveify(); break; */
		case C(L): redraw(); break;
		case C(N): all(DESELECT, 0); break;
		case C(O): writepic(); break;
		case C(P): removegroup(); break;
		case C(R): readfile(); break;
		case C(S): specialfunc(); break;
		case C(T): tickset(); break;
		case C(U): undocmd(); break;
		case C(V): remake(LINE); break;
		case C(W): writefile(); break;
		case C(X): cutlines(); break;
		case C([): all(DESELECT, 0); markdelete(); break; /* <ESC> */
		case C(^): help(); break;			/* ^^ */
		default:   break;
		} break;
case MOUSE: markobj = objnearany(x, y);
	    near = markon && (dist(x, y, markx, marky) < MARKTOL);
	    dragdist = near ? (anysel ? 0 : MARKTOL) : DRAGTOL;
	    drag = dist(x,y,xup,yup) > dragdist;
	    if (markobj) objectalign(markobj, &x, &y); else spacealign(&x, &y);
	    if (drag)		/* drag stuff */
		{
		if (near)
		    {
		    markhide();		/* for cleaner update */
		    mup = objnearany(xup, yup);
		    if (mup && (mup != markobj)) objectalign(mup, &xup, &yup);
		    else spacealign(&xup, &yup);
		    if (anysel) moveselect(xup-markx, yup-marky);
		    else if (markobj) tugunselect(markx, marky, xup, yup);
		    markupdate(xup, yup);
		    }
		else rectselect(x, y, xup, yup);
		}
	    else		/* draw (move mark) cases */
		{
		if (near) markdelete();
		else
		    {
		    markhide();		/* for cleaner update */
		    if (markon && !anysel) lineadd(markx, marky, x, y);
		    markupdate(x, y);
		    }
		}
	    break;
	    }
	}
    }
SHAR_EOF
if test -f 'lemmark.c'
then
	echo shar: over-writing existing file "'lemmark.c'"
fi
cat << \SHAR_EOF > 'lemmark.c'
/*
 * lemmark.c - mark control
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

markadd(x, y)
    {
    markdraw(x, y, markobj ? MARKONOBJCOL : MARKONREGCOL);
    markx = x;
    marky = y;
    markon = 1;
    }

markdelete()
    {
    markhide();
    markon = 0;
    }

markhide()
    {
    if (markon) markdraw(markx, marky, MARKOFFCOL);
    }

markupdate(x, y)
    {
    markdelete();
    markobj = objnearany(x, y);
    markadd(x, y);
    }

markdraw(x, y, col)
    {
    drawvec(x-MARKSIZE, y, x+MARKSIZE, y, col, 1, EMPHNONE);
    drawvec(x, y-MARKSIZE, x, y+MARKSIZE, col, 1, EMPHNONE);
    }
SHAR_EOF
if test -f 'lemmisc.c'
then
	echo shar: over-writing existing file "'lemmisc.c'"
fi
cat << \SHAR_EOF > 'lemmisc.c'
/*
 * lemmisc.c - low-level routines
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

redraw()
    {
    int i;
    erase();
    if (tickflag) tickdraw();
    forobjects
	{
	objectop(i, UNDEL, UNDEL);
	objectop(i, SEL, SEL);
	}
    if (markon) markadd(markx, marky);
    }

idle()
    {
    }
SHAR_EOF
if test -f 'lemobj.c'
then
	echo shar: over-writing existing file "'lemobj.c'"
fi
cat << \SHAR_EOF > 'lemobj.c'
/*
 * lemobj.c - object dispatch
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

objresize(i)
    {
    switch(Otype)
	{
	case LINE: lineresize(i); break;
	case TEXT: textresize(i); break;
	case BOX:  boxresize(i); break;
	case ELLI: elliresize(i); break;
	}
    }

objnearpt(i, x, y)
    {
    switch(Otype)
	{
	case LINE: return(linenearpt(i, x, y)); break;
	case TEXT: return(textnearpt(i, x, y)); break;
	case BOX:  return( boxnearpt(i, x, y)); break;
	case ELLI: return(ellinearpt(i, x, y)); break;
	}
    }

objinrect(i, xl, yl, xh, yh)
    {
    switch(Otype)
	{
	case TEXT: return(textinrect(i, xl, yl, xh, yh)); break;
	case LINE: return(lineinrect(i, xl, yl, xh, yh)); break;
	case BOX:  return( boxinrect(i, xl, yl, xh, yh)); break;
	case ELLI: return(elliinrect(i, xl, yl, xh, yh)); break;
	}
    }

objcantug(i, x, y)
    {
    switch(Otype)
	{
	case TEXT: return(textcantug(i, x, y)); break;
	case LINE: return(linecantug(i, x, y)); break;
	case BOX:  return( boxcantug(i, x, y)); break;
	case ELLI: return(ellicantug(i, x, y)); break;
	}
    }

objtug(i, xs, ys, xe, ye)
    {
    switch(Otype)
	{
	case TEXT: texttug(i, xs, ys, xe, ye); break;
	case LINE: linetug(i, xs, ys, xe, ye); break;
	case BOX:   boxtug(i, xs, ys, xe, ye); break;
	case ELLI: ellitug(i, xs, ys, xe, ye); break;
	}
    }

objectalign(i, x, y)
    int *x, *y;
    {
    switch(Otype)
	{
	case TEXT: textalign(i, x, y); break;
	case BOX:   boxalign(i, x, y); break;
	case LINE: linealign(i, x, y); break;
	case ELLI: ellialign(i, x, y); break;
	}
    }

objmove(i, x, y)
    {
    switch(Otype)
	{
	case LINE: linemove(i, x, y); break;
	case TEXT: textmove(i, x, y); break;
	case BOX:   boxmove(i, x, y); break;
	case ELLI: ellimove(i, x, y); break;
	}
    }

objaffine(i, m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    switch(Otype)
	{
	case LINE: lineaffine(i, m11, m12, m21, m22); break;
	case TEXT: textaffine(i, m11, m12, m21, m22); break;
	case BOX:   boxaffine(i, m11, m12, m21, m22); break;
	case ELLI: elliaffine(i, m11, m12, m21, m22); break;
	}
    }

objdraw(i, col)
    {
    switch(Otype)
	{
	case LINE: linedraw(i, col); break;
	case TEXT: textdraw(i, col); break;
	case BOX:   boxdraw(i, col); break;
	case ELLI: ellidraw(i, col); break;
	}
    }
SHAR_EOF
if test -f 'lemobjsup.c'
then
	echo shar: over-writing existing file "'lemobjsup.c'"
fi
cat << \SHAR_EOF > 'lemobjsup.c'
/*
 * lemobjsup.c - superclass for generic object operations
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include <math.h>		/* to define "double floor()" */
#include "lem.h"

objsupnearpt(i, x, y)
    {
    if (ptinrect(x, y, Oxl, Oyl, Oxh, Oyh, LINETOL) == 0) return(0);
    return(1);
    }

objsupinrect(i, xl, yl, xh, yh)
    {
    return(ptinrect(Oxl, Oyl, xl, yl, xh, yh, LINETOL) &&
	ptinrect(Oxh, Oyh, xl, yl, xh, yh, LINETOL));
    }

objsupcantug(i, x, y)
    {
    return(objnearpt(i, x, y));
    }

objsuptug(i, xs, ys, xe, ye)
    {
    if (dist(Oxs, Oys, xs, ys) < TUGPROX) objmove(i, xe-xs, ye-ys);
    }

objsupalign(i, x, y)
    int *x, *y;
    {
    if (dist(Oxs, Oys, *x, *y) < ENDTOL)
	{
	*x = Oxs;
	*y = Oys;
	}
    }

objsupmove(i, x, y)
    {
    Oxs += x;
    Oxe += x;
    Oys += y;
    Oye += y;
    }

objsupaffine(i, m11, m12, m21, m22, both)
    float m11, m12, m21, m22;
    {
    float x1, y1;
    if (both)
	{
	x1 = floor((m11*Oxs + m12*Oys) + 0.5);
        y1 = floor((m21*Oxs + m22*Oys) + 0.5);
	Oxs = x1;
	Oys = y1;
	x1 = floor((m11*Oxe + m12*Oye) + 0.5);
        y1 = floor((m21*Oxe + m22*Oye) + 0.5);
	Oxe = x1;
	Oye = y1;
	}
    else
	{
        x1 = floor((m11*Oxcen + m12*Oycen) + 0.5);
        y1 = floor((m21*Oxcen + m22*Oycen) + 0.5);
/*
 *  move only the center point, don't the other endpoint
 * (presumably object dimensions -- this is a text element).
 */
	objmove(i, (int)(x1-Oxcen), (int)(y1-Oycen));
	}
    }
SHAR_EOF
if test -f 'lemop.c'
then
	echo shar: over-writing existing file "'lemop.c'"
fi
cat << \SHAR_EOF > 'lemop.c'
/*
 * lemop.c - operate on objects (and update the display)
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

objectop(i, instatus, outstatus)
    {
    int col;
    if (i && (Ostat == instatus))
	{
	if ( instatus == SEL) anysel--;
	if (outstatus == SEL) anysel++;
	Ostat = outstatus;
	switch(Ostat)
	    {
	    case DEL:   col = ERASECOL; break;
	    case UNDEL: col = DRAWCOL; break;
	    case SEL:   col = SELECTCOL; break;
	    }
	objdraw(i, col);
	if (Odel && (i == markobj)) markobj = 0;
	changes |= ( (instatus == DEL) || (outstatus == DEL) );
	if ( instatus == DEL)
	return(1);
	}
    return(0);
    }

any(i, opcode)
    {
    if (Ogroup) all(opcode, Ogroup);
    else
    switch(opcode)
	{
	case SELECT:   objectop(i, UNDEL, SEL); break;
	case DESELECT: objectop(i, SEL, UNDEL); break;
	case DELETE:   objectop(i, SEL, DEL);  break;
	case UNDELETE: objectop(i, DEL, SEL);  break;
	}
    }

all(opcode, group)
    {
    int i, saveg;
    forobjects
	{
	if (!group || Ogroup == group)
	    {
	    saveg = Ogroup;
	    Ogroup = 0;
	    any(i, opcode);
	    Ogroup = saveg;
	    }
	}
    }
SHAR_EOF
if test -f 'lempic.c'
then
	echo shar: over-writing existing file "'lempic.c'"
fi
cat << \SHAR_EOF > 'lempic.c'
/*
 * lempic.c - PIC output processor
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

#define PTSSCALE 96.0
#define PENSCALE 12	/* ln03 dimp troff drivers like 13 (!a common PntSz) */

int curx, cury, curw, curh, ps, pemph;

FILE *f;

writepicint(fname)
    char *fname;
    {
    int i;
    f = (fname && (strlen(fname) > 1)) ? fopen(fname, "w") : 0;
    if (f)
	{
	curx = cury = curw = curh = ps = pemph= -1;
	fprintf(f, ".PS\n");
	forobjects
	    {
	    if (Odel) continue;
	    switch (Otype)
		{
		case TEXT:	ptext(i);
				at(Oxs, Oys);
				break;
		case LINE:	thick(i);
				pline(i);
				em(i);
				from(Oxs, Oys);
				to(Oxe, Oye);
				break;
		case BOX:	thick(i);
				fprintf(f, "box");
				em(i);
				at(Ox, Oy);
				size(Ow, Oh);
				break;
		case ELLI:	thick(i);
				fprintf(f, "ellipse");
				em(i);
				at(Ox, Oy);
				size(Ow,Oh);
				break;
		}
	    fprintf(f, ";\n");
	    }
	fprintf(f, ".PE\n");
	fclose(f);
	msgpost("pic output done");
	}
    else msgpost("pic output failed");
    free(fname);
    }


writepic()
    {
    char *fname;
    fname = prompt("pic file: ");
    writepicint(fname);
    free(fname);
    }

thick(i)
    {
    if (ps != lemfont[Osizer].thick)
	{
	ps = lemfont[Osizer].thick;
	fprintf(f, ".ps %d\n", ps*PENSCALE);
	}
    }

pt(x, y)
    {
    fprintf(f, " %.3fi,%.3fi", (float)(x)/PTSSCALE, (float)(y)/PTSSCALE);
    }

at(x, y)
    {
    fprintf(f, " at");
    pt(x, y);
    }

from(x, y)
    {
    if ((x == curx) && (y == cury)) return;
    fprintf(f, " from");
    pt(x, y);
    curx = x;
    cury = y;
    }

to(x, y)
    {
    fprintf(f, " to");
    pt(x,y);
    curx = x;
    cury = y;
    }

size(w, h)
    {
    w = ABS(w);
    h = ABS(h);
    if ((w == curw) && (h == curh)) fprintf(f, " same");
    else
	{
	fprintf(f, " wid %.3fi ht %.3fi",
	    (float)(w)/PTSSCALE, (float)(h)/PTSSCALE);
	curw = w;
	curh = h;
	}
    }

ptext(i)
    {
    int fontflag;
    char *ft;
    fontflag = ((Oemph != pemph) || (lemfont[Osizer].psize != ps));
    pemph = Oemph;
    ps = lemfont[Osizer].psize;
    fprintf(f, "\"");
    if (fontflag)
	{
	switch(Oemph)
	    {
	    case EMPHNONE: ft = lemfont[Osizer].tyr; break;
	    case EMPHBOLD: ft = lemfont[Osizer].tyb; break;
	    case EMPHITAL: ft = lemfont[Osizer].tyi; break;
	    }
	fprintf(f, "\\f%s%s", strlen(ft) > 1 ? "(" : "", ft );
	}
    fprintf(f, "\\s%d%s\"",lemfont[Osizer].psize, Otext);
    switch(Oalign)
	{
	case ALIGNLEFT:	fprintf(f, " ljust"); break;
	case ALIGNRGHT:	fprintf(f, " rjust"); break;
	case ALIGNCENT:
	default:	break;
	}
    }

pline(i)
    {
    fprintf(f, "line");
    switch(Oalign)
	{
	case ALIGNLEFT: fprintf(f, " <-"); break;
	case ALIGNRGHT: fprintf(f, " ->"); break;
	case ALIGNCENT:
	default:	break;
	}
    }

em(i)
    {
    switch(Oemph)
	{
	case EMPHBOLD: fprintf(f, " dashed"); break;
	case EMPHITAL: fprintf(f, " dotted"); break;
	case EMPHNONE:
	default:  break;
	}
    }
SHAR_EOF
if test -f 'lemrc.c'
then
	echo shar: over-writing existing file "'lemrc.c'"
fi
cat << \SHAR_EOF > 'lemrc.c'
/*
 * lemrc.c - get default fonts from local file.
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include "lemfont.h"

#define FONTPATH "/usr/local/lib/BFont/"
#define FONTEXTN ".bf"

char *getenv();

leminit()
    {
    char rcname[100], rcline[RCLINE];
    FILE *f;
    int i, items;
/*
 * generate local and global names
 */
    sprintf(rcname, "./%s", RCNAME);
    f = fopen(rcname, "r");
    if (!f)
	{
        sprintf(rcname, "%s/%s", getenv("HOME"), RCNAME);
	f = fopen(rcname, "r");
	}
    if (!f)
	{
/*	err("no %s file exists", RCGLOBAL); */
	lemfont[1].psize = DEFPSIZEFT;
	lemfont[1].thick = DEFDENSEFT;
	lemfont[1].dsp = DEFIKRFT;
	lemfont[1].tyr = DEFTYRFT;
	lemfont[1].tyb = DEFTYBFT;
	lemfont[1].tyi = DEFTYIFT;
	lemfont[1].psr = DEFPSRFT;
	lemfont[1].psb = DEFPSBFT;
	lemfont[1].psi = DEFPSIFT;
	rclen = 1;
	}
    else
	{
	while(1)
	    {
	    char dsp[20], tyr[20], tyb[20], tyi[20];
	    char psr[20], psb[20], psi[20];
	    fgets(rcline, RCLINE, f);
	    if (feof(f)) break;
	    if ((rcline[0] >= '0') && (rcline[0] <= '9'))
		{
		rclen++;
		if (rclen >= RCLEN) err(".rc file too long");
		items = sscanf(rcline, "%d %d %s %s %s %s %s %s %s",
		    &lemfont[rclen].psize, &lemfont[rclen].thick,
		    dsp, tyr, tyb, tyi, psr, psb, psi);
		if (items != RCWIDTH) err("wrong line length in .rc file");
		lemfont[rclen].dsp = salloc(dsp);
		lemfont[rclen].tyr = salloc(tyr);
		lemfont[rclen].tyb = salloc(tyb);
		lemfont[rclen].tyi = salloc(tyi);
		lemfont[rclen].psr = salloc(psr);
		lemfont[rclen].psb = salloc(psb);
		lemfont[rclen].psi = salloc(psi);
		}
	    }
	if (rclen == 0) err(".lemrc file was empty");
	}
    rclen++;
    if (f) fclose(f);
/*
 * now set up default display fonts
 */
    for (i=1; i<rclen; i++)
	{
	char fontname[100];
	sprintf(fontname, "%s%s%d%s",
	    FONTPATH, lemfont[i].dsp, lemfont[i].psize, FONTEXTN);
	bfont[i] = fontload(fontname);
	if (!bfont[i]) err("can't load font \"%s\"", fontname);
	}
    }
SHAR_EOF
if test -f 'lemselect.c'
then
	echo shar: over-writing existing file "'lemselect.c'"
fi
cat << \SHAR_EOF > 'lemselect.c'
/*
 * lemselect.c - object selection and proximity testing
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

cycleselect()
    {
    if (markobj)
	{
	if (objs[markobj]->stat == UNDEL) any(markobj, SELECT);
	else if (objs[markobj]->stat == SEL) any(markobj, DESELECT);
	}
    }

rectselect(x0, y0, x1, y1)
    {
    int i, mode, xl, yl, xh, yh;
    xl = MIN(x0, x1);
    yl = MIN(y0, y1);
    xh = MAX(x0, x1);
    yh = MAX(y0, y1);
    mode = (y0 < y1) ? DESELECT : SELECT;
    forobjects
	{
	if (objinrect(i, xl, yl, xh, yh)) any(i, mode);
	}
    }

objnearany(x, y)
    {
    int i;
    if (i = objnear(x, y, UNDEL)) return(i);
    return(objnear(x, y, SEL));
    }

objnear(x, y, stat)
    {
    int i;
    forobjsrev		/* reverse order search - most recent appears first */
	{
	if (Ostat == stat)
	    {
	    if (objnearpt(i, x, y)) return(i);
	    }
	}
    return(0);
    }
SHAR_EOF
if test -f 'lemspecial.c'
then
	echo shar: over-writing existing file "'lemspecial.c'"
fi
cat << \SHAR_EOF > 'lemspecial.c'
/*
 * lemspecial.c - extra functions for random applications
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include <math.h>

specialfunc()
    {
    char ch;
    msgpost("<F>lip <C>cw <M>agnify <R>otate <S>tretch <A>lign: ");
    ch = getstroke();
    switch(UC(ch))
	{
	case 'F': flip(); break;
	case 'C': ccw(); break;
	case 'M': magnify(); break;
	case 'R': rotate(); break;
	case 'S': stretch(); break;
	case 'A': align(); break;
	default: msgpost("unknown transformation"); break;
	}
    }

transform(m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    int i;
/*
 * record inverse transformation and set undo flag for undoing
 */
    undo = UNDOAFF;
    unx = markx;
    uny = marky;
    un11 = m11;
    un12 = m12;
    un21 = m21;
    un22 = m22;
/*
 * now do the transformations
 */
 forobjects
	{
	if (Osel)
	    {
	    objectop(i, SEL, DEL);
	    objmove(i, -markx, -marky);
	    objaffine(i, m11, m12, m21, m22);
	    objmove(i,  markx,  marky);
	    objresize(i);
	    objectop(i, DEL, SEL);
	    }
	}
    }

flip()
    {
    if (markon)
	{
	transform(-1.0, 0.0, 0.0, 1.0, 1);
	msgpost("flip done");
	}
    else msgpost("flip -- no mark present");
    }

ccw()
    {
    if (markon)
	{
	transform(0.0, -1.0, 1.0, 0.0, 0);
	msgpost("ccw turn done");
	}
    else msgpost("ccw -- no mark present");
    }

magnify()
    {
    int x1, y1, x2, y2, xs, ys, xe, ye;
    float mag, outlen;
    if (findmark(&x1, &y1, &x2, &y2))
	{
	xs = x2-markx;
	ys = y2-marky;
	xe = x1-markx;
	ye = y1-marky;
	outlen = xs*xs+ys*ys;
	if (outlen != 0.0)
	    {
	    mag = sqrt((float)(xe*xe+ye*ye)/outlen);
	    mag = (mag < 0.1) ? 0.1 : (mag > 10.0 ? 10.0 : mag);
	    transform(mag, 0.0, 0.0, mag, 1);
	    msgpost("magnify done");
	    }
	msgpost("null magnify ignored");
	}
    }

stretch()
    {
    int x1, y1, x2, y2, xs, ys, xe, ye;
    float xmag, ymag;
    if (findmark(&x1, &y1, &x2, &y2))
	{
	xs = x2-markx;
	ys = y2-marky;
	xe = x1-markx;
	ye = y1-marky;
	xmag = (xs == 0) ? 1.0 : (float)(xe)/xs;
	ymag = (ys == 0) ? 1.0 : (float)(ye)/ys;
	xmag = (xmag < 0.1) ? 0.1 : (xmag > 10.0 ? 10.0 : xmag);
	ymag = (ymag < 0.1) ? 0.1 : (ymag > 10.0 ? 10.0 : ymag);
	transform(xmag, 0.0, 0.0, ymag, 1);
	msgpost("stretch done");
	}
    }

rotate()
    {
    int x1, y1, x2, y2, xs, ys, xe, ye;
    float s, c, hy;
    if (findmark(&x1, &y1, &x2, &y2))
	{
	xs = x2-markx;
	ys = y2-marky;
	xe = x1-markx;
	ye = y1-marky;
	hy = sqrt((float)( (xs*xs + ys*ys) * (xe*xe + ye*ye) ));
	if (hy != 0.0)
	    {
	    c =  (xs*xe+ys*ye)/hy;
	    s =  (xs*ye-xe*ys)/hy;
	    transform(c, -s, s, c, 0);
	    msgpost("rotate done");
	    }
	else msgpost("null rotation ignored");
	}
    }

align()
    {
    int x1, y1, x2, y2, xs, ys, xe, ye, scale;
    float m11, m12, m21, m22, det;
    if (findmark(&x1, &y1, &x2, &y2))
	{
	xs = x2-markx;
	ys = y2-marky;
	xe = x1-markx;
	ye = y1-marky;
	scale = MAX(MAX(ABS(xs),ABS(ys)),MAX(ABS(xe),ABS(ye)));
	det = xe*ys - xs*ye; 
	m11 = (float)( ys*scale)/det;
	m12 = (float)(-xs*scale)/det;
	m21 = (float)(-ye*scale)/det;
	m22 = (float)( xe*scale)/det;
	transform(m11, m12, m21, m22, 1);
	msgpost("align done");
	}
    }
    
findmark(x1, y1, x2, y2)
    int *x1, *y1, *x2, *y2;
    {
    int i, s, e, arrow, straight;
    arrow = straight = 0;
    if (!markon)
	{
	msgpost("transform: no mark present");
	return(0);
	}
    else
	{
	forobjects
	    {
	    if (Otype != LINE) continue;
	    s = (Oxs == markx) && (Oys == marky);
	    e = (Oxe == markx) && (Oye == marky);
	    if (s || e) 
		{
		switch (Oalign)
		    {
case ALIGNCENT:	    *x1 = s ? Oxe : Oxs;
		    *y1 = s ? Oye : Oys;
		    straight++;
		    break;
case ALIGNLEFT:	    if (s)
			{
			msgpost("transform: arrowhead at origin");
			return(0);
			}
		    *x2 = Oxs;
		    *y2 = Oys;
		    arrow++;
		    break;
case ALIGNRGHT:	    if (e)
			{
			msgpost("transform: arrowhead at origin");
			return(0);
			}
		    *x2 = Oxe;
		    *y2 = Oye;
		    arrow++;
		    break;
		    }
		}
	    }
	}
    if ((arrow == 1) && (straight == 1)) return(1);
/*
 * errors 
 */
    if (arrow+straight == 0)
	msgpost("transform: no basis vectors at mark");
    else if (arrow != 1)
	msgpost("transform: exactly one arrow basis vector needed");
    else if (straight != 1)
	msgpost("transform: exactly one non-arrow basis vector needed");
    return(0);
    }
SHAR_EOF
if test -f 'lemstart.c'
then
	echo shar: over-writing existing file "'lemstart.c'"
fi
cat << \SHAR_EOF > 'lemstart.c'
/*
 * lemstart.c - check command line, plus some housecleaning
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

startup(argc, argv)
    char **argv;
    {
    int i, plotmode;
    plotmode = 0;
/*
 * initialize based on probable .rc file
 */
    leminit();
/*
 * set up object defaults
 */
    lastobj = 1;		/* no objects */
    setattr('0');		/* default attr's (as if '0' typed) */
    gtype = LINE;		/* draw lines by default */
    undo = UNDONONE;		/* no operation to undo */
/*
 * start user code and refresh the display
 */
    start();	
    redraw();
/*
 * command line prompt
 */
    msgpost("lemming ver 1 -- 'ctrl ^' for help");
/*
 * possible file name on cmd line
 */
    changes = 0;	/* no changes at present */
/*
 * do all command line parsing
 */
    for(i=1; i<argc; i++)
        {
	if (argv[i][0] == '-')
	    {
	    switch(argv[i][1])
		{
		case 'p':
		case 'P': plotmode = 1; break;
		default: err("unknown command line flag"); break;
		}
	    }
	else
	    {
	    if (!firstfile) firstfile = argv[i]; /* record first input file */
	    readfileint(argv[i]);
	    }
	}
    if (plotmode)
	{
	char outname[80];
	sprintf(outname, "%s.pic", firstfile);
	writepicint(outname);
	stop();
	exit(0);
	}
    }
SHAR_EOF
if test -f 'lemstop.c'
then
	echo shar: over-writing existing file "'lemstop.c'"
fi
cat << \SHAR_EOF > 'lemstop.c'
/*
 * lemstop.c - quit and error returns from lemming.
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

quitconfirm()
    {
    char c;
    if (changes)
	{
	msgpost("quit: [y] to confirm: ");
	c = getstroke();
	if (UC(c) != 'Y')
	    {
	    msgpost("quit aborted.");
	    return(1);
	    }
	}
    markdelete();
    stop();
    exit(0);
    }

err(msg, arg)
    char *msg;
    {
    fprintf(stderr, "\nlem: ", msg, arg);
    fprintf(stderr, msg, arg);
    fprintf(stderr, "\n");
    exit(1);
    }
SHAR_EOF
if test -f 'lemtext.c'
then
	echo shar: over-writing existing file "'lemtext.c'"
fi
cat << \SHAR_EOF > 'lemtext.c'
/*
 * lemtext.c - text primitives
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include "lemfont.h"

textadd(x0, y0, s)
    char *s;
    {
    int i;
    if ((!s) || (strlen(s) == 0)) return;
    i = objalloc(TEXT);
    Otext = salloc(s);
    Oxs = x0;
    Oys = y0;
    textresize(i);
    objnew(i);
    }

textresize(i)
    {
    Oxe = fontmeasure(bfont[Osizer], Otext, Oemph);
    Oye = lemfont[Osizer].psize;
    }

textnearpt(i, x, y)
    {
    return(ptinrect(x, y, Oxlt, Oylt, Oxht, Oyht, TEXTTOL));	/* must be ON the text */
    }

textinrect(i, xl, yl, xh, yh)
    {
    return(ptinrect(Oxlt, Oylt, xl, yl, xh, yh, TEXTTOL) &&
	ptinrect(Oxht, Oyht, xl, yl, xh, yh, TEXTTOL) );
    }

textcantug(i, x, y)
    {
    return(textnearpt(i, x, y));
    }

texttug(i, xs, ys, xe, ye)
    {
    Oxs += xe-xs;
    Oys += ye-ys;
    }

textalign(i, x, y)
    int *x, *y;
    {
    *x = Oxs;
    *y = Oys;
    }

textmove(i, x, y)
    {
    Oxs += x;
    Oys += y;
    }

textaffine(i, m11, m12, m21, m22)
    float m11, m12, m21, m22;
    {
    objsupaffine(i, m11, m12, m21, m22, 0);
    }

textdraw(i, col)
    {
    fontwrite(Osizer, Oxlt, Oys, Otext, Oemph, col);
    }
SHAR_EOF
if test -f 'lemtick.c'
then
	echo shar: over-writing existing file "'lemtick.c'"
fi
cat << \SHAR_EOF > 'lemtick.c'
/*
 * lemtick.c - perform ticking
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include "lemfont.h"

tickalign(x, y)
    int *x, *y;
    {
    if (tickflag && (ticksize < 6))
	{
	tx = 1<<ticksize;
	ty = 1<<ticksize;
	*x = ((*x-txoff+tx/2) / tx) * tx + txoff;
        *y = ((*y-tyoff+ty/2) / ty) * ty + tyoff;
	}
    if (tickflag && (ticksize >= 6))
	{
	int xl, yi, yl, d1, d2, d3, d4;
	tx = 1<<(ticksize-3);
	ty = (tx*14+7)/16;
        yi = ((*y-tyoff)/ty);
        yl = yi*ty + tyoff;
	xl = (((*x-txoff+((yi&0x1)?tx/2:0))/tx)*tx-((yi&0x1)?tx/2:0))+txoff;
	
	d1 = dist(*x,*y,xl       ,yl);
	d2 = dist(*x,*y,xl+tx/2  ,yl+ty);
	d3 = dist(*x,*y,xl+tx    ,yl);
	d4 = dist(*x,*y,xl+3*tx/2,yl+ty);
	if ((d1<=d2) && (d1<=d3) && (d1<=d4)) { *x = xl;        *y = yl; }
	if ((d2<=d1) && (d2<=d3) && (d2<=d4)) { *x = xl+tx/2;   *y = yl+ty; }
	if ((d3<=d1) && (d3<=d2) && (d3<=d4)) { *x = xl+tx;     *y = yl; }
	if ((d4<=d1) && (d4<=d2) && (d4<=d3)) { *x = xl+3*tx/2; *y = yl+ty; }
	}
    }

tickset()
    {
    char ch;
    int tmpx, tmpy;
    tickflag = !tickflag;
    if (tickflag)
	{
	msgpost("ticksize[1-5/6-9]: ");
	ch = getstroke();
	msgclear();
	if ((ch < '0') || (ch > '9'))
	    {
	    tickflag = 0;
	    return;
	    }
	ticksize = ch - '0';
	tmpx = markon ? markx : 0;
	tmpy = markon ? marky : 0;
        txoff = 0;
        tyoff = 0;
	tickalign(&tmpx, &tmpy);	/* sets tx and ty as well */
	txoff = (markon ? markx : 0) - tmpx;
	tyoff = (markon ? marky : 0) - tmpy;
	while (tyoff > 0) tyoff -= ty;
	while (tyoff < 0) tyoff += ty;
	while (txoff > 0) txoff -= tx;
	while (txoff < 0) txoff += tx;
	}
    tickdraw();
    if (!tickflag)
	{
        txoff = 0;
        tyoff = 0;
	}
    }
    
tickdraw()
    {
    int x, y, xstep, ystep;
    xstep = tx;
    ystep = ty;
    while (xstep<MINTICK) xstep *= 2;
    while (ystep<MINTICK) ystep *= 2;
    if (ticksize < 6)
	{
	for(y = tyoff ; y<screenh; y+=ystep)
	    for (x = txoff; x<screenw; x+=xstep)
	        {
		drawvec(x, y, x + tickdot, y, tickflag ? TICKONCOL:TICKOFFCOL,
			1,EMPHNONE); /* tickdot sets 0/1 width dot */
		}
	}
    else
        {
	int ylim, iy;
	ylim = screenh/ty;
	y = tyoff;
	for(iy=0; iy<ylim; iy++)
	    {
	    y += ty;
	    for (x = txoff + ((iy&0x1) ? 0 : (tx/2)); x<screenw; x+=tx)
		if ((x>0) && (y>0))
	            drawvec(x, y, x + tickdot, y,
			tickflag ? TICKONCOL:TICKOFFCOL,1,EMPHNONE);
	    }
	}
    }
SHAR_EOF
if test -f 'lemundo.c'
then
	echo shar: over-writing existing file "'lemundo.c'"
fi
cat << \SHAR_EOF > 'lemundo.c'
/*
 * lemundo.c - undo last operation
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"

undocmd()
    {
    float d;
    switch(undo)
	{
case UNDOMOVE:	moveselect(-unx, -uny);
		break;
case UNDOTUG:	tugunselect(unxe, unye, unx, uny);
		break;
case UNDOAFF:	d = (un11 * un22) - (un21 * un12);
    		if (d == 0.0) return;	/* no-op if singular */
    		transform(un22/d, -un12/d, -un21/d, un11/d);
		break;
case UNDODEL:	all(UNDELETE, 0);
		undo = UNDONONE;
		break;
default:	undo = UNDONONE;
case UNDONONE:	msgpost("cannot undo last operation"); break;
	}
    }
SHAR_EOF
if test -f 'lemvec.c'
then
	echo shar: over-writing existing file "'lemvec.c'"
fi
cat << \SHAR_EOF > 'lemvec.c'
/*
 * lemvec.c - line to point scan conversion
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

/*
 *
 * Programmed by Alan Paeth, University of Waterloo, January, 1984
 *
 * This code rasterizes vectors. A call of the form:
 *
 * drawline(x0, y0, x1, y1, wid, val, emph)
 *
 * with val the output color, and emph one of EMPHITAL, EMPHBOLD, (otherwise)
 * generates a vector of specified which is dotted, dashed, or plain,
 * respectively.
 *
 * output pixels are set by calls to:
 *
 * setpixelrun(x, y, wid, val, parity)
 *
 * which should set pixels (x,y) through (x+wid-1,y) to color (val) if
 * parity is 0 (as it is at endpoints and some intermediate locations).
 *
 * viewport clipping is done (using integer math) to the dimensions specified
 * in the globals "screenw" and "screenh"
 *
 */

#include "lem.h"

#define Nextflag { mask>>=1; if (++flag >= 16) { flag = 0; mask = emph; } }

#define SOLID  0xffffffff	/* only solid should have sign bit set */
#define DASHES 0x00ff00ff
#define DOTS   0x03030303

#define ONE		0x4000
#define POINT_FIVE	0x2000
#define SCALEUP	14

#define TOPFLAG 8
#define BOTTOMFLAG 4
#define LEFTFLAG 2
#define RIGHTFLAG 1

code(x, y)
    float x, y;
    {
    int c = 0;
    if (x < 0) c |= LEFTFLAG; else if (x >= screenw) c |= RIGHTFLAG;
    if (y < 0) c |= BOTTOMFLAG; else if (y >= screenh) c |= TOPFLAG;
    return c;
    }

drawline(x1, y1, x2, y2, wid, val, emph) /* generic brand clipped line code */
    {
    int c, c1, c2;
    long x, y;

    if ((x1==x2) && (y1==y2)) return;	/* no motion -- fast return */

    c1 = code((float)(x1), (float)(y1));
    c2 = code((float)(x2), (float)(y2));

    while (c1 || c2)
	{
	if (c1 & c2) return;	/* bitwise AND, not statement AND */
	c = c1 ? c1 : c2;
	
	if (c & LEFTFLAG)
	    y = y1 + ((y2 - y1) * ( (x = 0) - x1)) / (x2 - x1);
	else if (c & RIGHTFLAG)
	    y = y1 + ((y2 - y1) * ( (x = screenw) - x1)) / (x2 - x1);
	else if (c & TOPFLAG)	
	    x = x1 + ((x2 - x1) * ( (y = screenh) - y1)) / (y2 - y1);
	else if (c & BOTTOMFLAG)	
	    x = x1 + ((x2 - x1) * ( (y = 0) - y1)) / (y2 - y1);
	
	if (c == c1)
	    {
	    x1 = x;
	    y1 = y;
	    c1 = code(x, y);
	    }
	else
	    {
	    x2 = x;
	    y2 = y;
	    c2 = code(x, y);
	    }
	}
    fastdrawline(x1, y1, x2, y2, wid, val, emph);
    }

fastdrawline(x1, y1, x2, y2, wid, val, emph)

/*
 *
 *  Draws a line of pixels=val from (x1, y1) to (x2, y2) very fast.
 *
 *  This is algorithm A1 from "Filtering Edges for Grey-Scale Displays" by
 *  Gupta & Sproull (Computer Graphics 15,3 August 1981). No anti-aliasing
 *  is being done here. However the variable 'v' can be *  used to turn on
 *  pixels to the left and right (above and below) the line since v is
 *  horizontal distance from the center of the line to the pixel at (x, y).
 *
 *  Last Hacked by: Alan Paeth
 */

    int x1, y1, x2, y2, val, emph;
    {
    register	x, y;			/* current position in line */
    int		incr;			/* y increment = + or - 1 */
    int		dx, dy;			/* change in x, y */
    int		m;			/* slope of line ( * 2 ** 14 ) */
    int		s;			/* threshold for diagonal move */
    register	v;			/* dist from line to pixel */
    int		mm1;			/* m - (1 << 9) */
    int		mask;
    int		flag;

    flag = 0;
    emph = (emph == EMPHITAL) ? DOTS : ((emph == EMPHBOLD) ? DASHES : SOLID);
    mask = emph;

    if (y2 > y1)			/* make y1 > y2 by symmetries */
	{
	x = x1;   x1 = x2;   x2 = x;
	y = y1;   y1 = y2;   y2 = y;
	}

    incr = 1;
    dy   = y1 - y2;

    if ((dx = x2 - x1) < 0)
	{
	dx   = -dx;
	incr = -1;
	}

    v = 0;
    if (dx > dy)
	{
	m = ((long)dy << SCALEUP) / (long)dx;
	s = POINT_FIVE - m;
	mm1 = m - ONE;
	y = y1;

	for( x = x1; x != x2; x += incr )
	    {
	    if (mask & 0x1) setpixelrunv(x, y, wid, val, flag & 0x1);
	    Nextflag;
	    if( v >= s ) { --y; v += mm1; }	/* diagonal move */
		else v += m;			/* horizontal move */
	    }
	setpixelrunv(x, y, wid, val, 0);
	}
    else
	{
	if( dy > 0 )
	    {
	    m = ((long)dx << SCALEUP) / (long)dy;
	    s = POINT_FIVE - m;
	    mm1 = m - ONE;
	    }
	x = x1;

	for( y = y1; y > y2; --y )
	    {
	    if (mask & 0x1) setpixelrunh(x, y, wid, val, flag&0x1);
	    Nextflag;
	    if ( v >= s ) { x += incr; v += mm1; }	/* diagonal move */
		else v += m;				/* vertical move */
	    }
	setpixelrunh(x, y, wid, val, 0);
	}
    }
SHAR_EOF
if test -f 'lemx.c'
then
	echo shar: over-writing existing file "'lemx.c'"
fi
cat << \SHAR_EOF > 'lemx.c'
/*
 * lemx.c - lemming driver for X window software
 *
 * copyright (c) by Alan W. Paeth, 1987. All rights reserved.
 */

#include "lem.h"
#include <X/Xlib.h>

#define EV (ButtonPressed | ButtonReleased | KeyPressed | ExposeWindow | ExposeRegion)

Window win;
int xsave, ysave, drawcol, erasecol, selectcol, markoncol, markoffcol, lut;
int sysmsgloc;
char sysmsg[120];
unsigned char maptab[256];	/* bit reversing table */

start()
    {
    screenw = 512;
    screenh = 512;
    if ((XOpenDisplay("")) == NULL) err("display open failed");
    win = XCreateWindow(RootWindow, screenw/2, screenh/2, screenw, screenh,
				2, WhitePixmap, BlackPixmap);
    if (win == NULL) err("window open failed");
    lut = DisplayCells() > 2;
    XMapWindow(win);
    XSelectInput(win, EV);
    if (lut)
	{
	cblack = findcolor(0,0,0);
	cwhite = findcolor(1,1,1);
	cred   = findcolor(1,0,0);
	cgreen = findcolor(0,1,0);
	tickdot = 0;
	}
    else
	{
	cwhite = 1;
	cblack = 0;
	cred   = 2;
	cgreen = 1;
	tickdot = 1;
	}
    setcursor();
    }

stop()
    {
    }

getevent(xdn, ydn, xup, yup, ch)
    int *xdn, *ydn, *xup, *yup;
    char *ch;
    {
    int ret, count;
    XEvent ev;
    XWindowEvent(win, EV, &ev);
    ret = NOEVT;
    switch(ev.type)
	{
	case ButtonPressed:	xsave = mx(&ev);
				ysave = my(&ev);
				break;
	case ButtonReleased:	*xdn = xsave;
				*ydn = ysave;
				*xup = mx(&ev);
				*yup = my(&ev);
				ret = MOUSE;
				break;
	case KeyPressed:	*ch = *XLookupMapping(&ev, &count);
				if (*ch)
				   {
				   if ((*ch >= ' ') && (*ch != '\177'))
				       ret = ALPHA;
				   else if (*ch > 0) ret = CNTRL;
				   } 	
				break;
	case ExposeRegion:
	case ExposeWindow:	checkwindowsize();
				redraw();
				break;
	}
    XFlush();
    return(ret);
    }

checkwindowsize()
    {
    WindowInfo winfo;
    XQueryWindow(win, &winfo);
    screenw = winfo.width;
    screenh = winfo.height;
    }

setcursor()
    {
    Cursor c;
    static short cur_bgnd[] = {
	0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x03e0, 0x0630, 0x7c1f, 0x7c1f,
	0x7c1f, 0x0630, 0x03e0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0000 };
    static short cur_fgnd[] = {
	0x0080, 0x0080, 0x0080, 0x0080, 0x03e0, 0x0630, 0x0410, 0x7c1f,
	0x0410, 0x0630, 0x03e0, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 };
    c = XCreateCursor(16, 16, cur_fgnd, cur_bgnd, 7,7,cwhite,cblack,GXcopy);
    XDefineCursor(win, c);
    }

setpixelrunh(x0, y0, wid, col, dotflag)
    {
    if (col == cred)
	{
	col = (dotflag) ? cblack: cwhite;	/* checkerboard select */
	}
    XPixSet(win, x0, (screenh-1)-y0, wid, 1, col);
    }

setpixelrunv(x0, y0, wid, col, dotflag)
    {
    if (col == cred)
	{
	col = (dotflag) ? cblack: cwhite;	/* checkerboard select */
	}
    XPixSet(win, x0, (screenh-1)-y0, 1, wid, col);
    }

drawvec(x0, y0, x1, y1, col, wid, emph)
    {
#define SOLID  SolidLine
#define DASHES XMakePattern(0x00ff,16,1)
#define DOTS   XMakePattern(0x0303,16,1)
    Vertex chain[2];
    int pattern;
    if (lut)
	{
/*	XLine(win,x0,screenh-y0,x1,screenh-y1,wid,wid,col,GXcopy,AllPlanes); */
	chain[0].x = x0 - wid/2;
	chain[0].y = screenh-y0 - wid/2;
	chain[0].flags = VertexDrawLastPoint;
	chain[1].x = x1 - wid/2;
	chain[1].y = screenh-y1 - wid/2;
	chain[1].flags = VertexDrawLastPoint;
	pattern = (emph==EMPHNONE) ? SOLID : ((emph==EMPHBOLD) ? DASHES : DOTS);
	XDrawDashed(win, chain, 2, wid, wid, col, pattern, GXcopy, AllPlanes);
	}
    else drawline(x0-wid/2, y0+wid/2, x1-wid/2, y1+wid/2, wid, col, emph);
/* SUN version does not understand dots and dashes -- we must do it all */
    }

charshow(str)
    char *str;
    {
    int i;
    for(i=0; i<strlen(str); i++) sysmsg[sysmsgloc++] = str[i];
    sysmsg[sysmsgloc] = '\0';
    fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
    XFlush();
    }

charunshow(n)
    {
    fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cblack);
    while (n--)
	{
	if (sysmsgloc) sysmsg[--sysmsgloc] = '\0';
	}
    fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
    XFlush();
    }

erase()
    {
    XPixSet(win, 0, 0, screenw, screenh, cblack);
    fontwrite(SYSFONT, 10, 10, sysmsg, EMPHNONE, cgreen);
    XFlush();
    }

/*
 * internal stuff
 */

findcolor(r, g, b)
    int r, g, b;
    {
    Color c;
    c.red = r*65535;
    c.green= g*65535;
    c.blue = b*65535;
    if (!XGetHardwareColor(&c))
	{
/*	err("no more room in color table"); */
	return(b*4+g*2+r);
	}
    return(c.pixel);
    }

mx(ev)
    XKeyEvent *ev;
    {
    return(ev->x);
    }

my(ev)
    XKeyEvent *ev;
    {
    return(screenh - ev->y + 1);
    }

writescan(x, y, pixels, outaddr, color)
    int x, y, pixels, *outaddr, color;
    {
    if (pixels <= 0) return;	/* PARANOIA: should not ever happen */
    if (!lut && color == cred)
	{
	register int i, lim;
	lim = (pixels+31)/32;
	if ((x^y) & 0x1) for(i=0; i<lim; i++) outaddr[i] &= 0x55555555;
	else for(i=0; i<lim; i++) outaddr[i] &= 0xaaaaaaaa;
	color = cwhite;
	}
    swapshorts(outaddr, (pixels+31)/8);
    XBitmapBitsPut(win, x, y, pixels, 1,
	outaddr, color, cblack, 0, GXcopy, AllPlanes);
    }

swapshorts(buf, len)
    register unsigned char *buf;
    {
    unsigned char c1, c2, c3, c4;
    register int count, i;
    if (!maptab[1]) maptabinit();
    count = len/4;
    for (i=0; i<count; i++)
	{
	c1 = *buf++;
	c2 = *buf++;
	c3 = *buf++;
	c4 = *buf;
	*buf-- = maptab[c1];
	*buf-- = maptab[c2];
	*buf-- = maptab[c3];
	*buf   = maptab[c4];
	buf += 4;
	}
    }

maptabinit()
    {
    register int i, j;
    unsigned char mask;
    for(i = 0; i<256; i++)
	{
	mask = 0;
	for(j = 0; j < 8; j++) if (i & (1<<j)) mask |= 1<<(7-j);
	maptab[i] = mask;
	}
    }
SHAR_EOF
#	End of shell archive
exit 0


-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.c
c
cs)