Fun dynamic sketching program for IRISes.

Patrick Naughton naughton at wind.Eng.Sun.COM
Sun Feb 17 18:37:55 AEST 1991


In article <85040 at sgi.sgi.com>, paul at manray.asd.sgi.com (Paul Haeberli) writes:
|> Here's a little program that uses a very simple dynamics model
|> to draw caligraphic strokes. Please give it a try if you have
|> an IRIS workstation.
|> 
|> paul haeberli
|> paul at sgi.com
|> 415-962-3665
|>
|> ... dynadraw.c deleted ...

Here's another set of X11 compatibility routines for us Paul Haeberli
fans without IRISes...

compile it like this:

	cc -O dynadraw.c glx.c -o dynadraw -lm -lX


#! /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:
#	glx.c
#	gl.h
#	device.h
# This archive created: Sat Feb 16 23:30:16 1991
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'glx.c'
then
	echo shar: "will not over-write existing file 'glx.c'"
else
cat << \SHAR_EOF > 'glx.c'
#ident "@(#)glx.c	1.1 91/02/16 GL"
/*-
 * glx.c - simple replacements for SGI GL functions for X11.
 *
 * Copyright (c) 1991 by Patrick J. Naughton
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind. The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof. In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 * Comments and additions should be sent to the author:
 *
 * Patrick J. Naughton
 * Sun Microsystems
 * 2550 Garcia Ave, MS 10-20
 * Mountain View, CA 94043
 * (415) 336-1080
 *
 */

#include <stdio.h>
#include <sys/times.h>
#include <string.h>
#include <strings.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/bitmaps/gray1>
#include "gl.h"

#define POLYBATCH 40
#define FONTNAME "bembo-bold-24"

static Display *dsp;
static int  screen;
static Colormap cmap;
static GC   gc;
static Window win;
static Window root;
static int  winw;
static int  winh;
static int  cpx;
static int  cpy;
static XPoint *poly = 0;
static int  curpoly;
static int  npoly;
static XFontStruct *textfont;
static XFontStruct *font;
static XCharStruct fontextent;
static int  fontascent;
static int  fontdescent;
static int  fontheight;
static int  menux;
static int  menuy;
static long black;
static long white;
static float xoff;
static float xscale;
static float yoff;
static float yscale;
static Pixmap stipple;
static int  mousex;
static int  mousey;

void
prefsize(w, h)
{
    winw = w;
    winh = h;
}

void
winopen(name)
    char       *name;
{
    XSetWindowAttributes xswa;
    XWMHints    xwmh;
    int         tmp;
    int         mask;

    dsp = XOpenDisplay(0);
    screen = DefaultScreen(dsp);
    cmap = DefaultColormap(dsp, screen);
    gc = DefaultGC(dsp, screen);
    root = RootWindow(dsp, screen);
    black = BlackPixel(dsp, screen);
    white = WhitePixel(dsp, screen);
    stipple = XCreatePixmapFromBitmapData(dsp, root,
				       gray1_bits, gray1_width, gray1_height,
					  black, white, 1);
    XSetStipple(dsp, gc, stipple);
    font = XLoadQueryFont(dsp, "fixed");
    textfont = XLoadQueryFont(dsp, FONTNAME);
    if (!textfont)
	textfont = font;
    XSetFont(dsp, gc, textfont->fid);
    XQueryTextExtents(dsp, textfont->fid, "Q", 1,
		      &tmp, &fontascent, &fontdescent, &fontextent);
    fontheight = fontascent + fontdescent + 1;

    xswa.event_mask = ExposureMask | KeyPressMask
	| ButtonPressMask | Button2MotionMask;
    mask = CWEventMask;
    win = XCreateWindow(dsp, root, 0, 0, winw, winh, 0,
			CopyFromParent, InputOutput, CopyFromParent,
			mask, &xswa);
    xwmh.flags = InputHint;
    xwmh.input = True;
    XChangeProperty(dsp, win, XA_WM_HINTS, XA_WM_HINTS, 32,
       PropModeReplace, (unsigned char *) &xwmh, sizeof(xwmh) / sizeof(int));
    XStoreName(dsp, win, name);
    XMapWindow(dsp, win);
    while (1) {
	XEvent      ev;
	XNextEvent(dsp, &ev);
	if (ev.type == Expose)
	    break;
    }
}

/* this is a hack to make Sun's times return the time value just like SYSV */

#undef times
long
mytimes(ct)
    struct tms *ct;
{
    times(ct);
    return ct->tms_utime;
}

void
RGBcolor(r, g, b)
{
    XColor      color;

    color.pixel = 0;
    color.red = r << 8;
    color.green = g << 8;
    color.blue = b << 8;
    color.flags = DoRed | DoGreen | DoBlue;
    XAllocColor(dsp, cmap, &color);
    XSetForeground(dsp, gc, color.pixel);
}

void
clear()
{
    XFillRectangle(dsp, win, gc, 0, 0, winw, winh);
}

void
pnt2i(x, y)
    int         x;
    int         y;
{
    XDrawPoint(dsp, win, gc, x, winh - y);
}

int
getvaluator(which)
    int         which;
{
    switch (which) {
    case MOUSEX:
	return mousex;
    case MOUSEY:
	return winh - mousey;
    default:
	return 0;
    }
}

int
getbutton(which)
    int         which;
{
    Window      qroot;
    Window      qwin;
    int         rootx;
    int         rooty;
    int         winx;
    int         winy;
    static int  mask;

    XQueryPointer(dsp, win, &qroot, &qwin, &rootx, &rooty, &winx, &winy, &mask);
    switch (which) {
    case LEFTMOUSE:
	mousex = winx;
	mousey = winy;
	return (mask & Button1Mask);
    case RIGHTSHIFTKEY:
	return (mask & ShiftMask);
    default:
	return 0;
    }
}

int
qread(val)
    short      *val;
{
    XEvent      ev;
    *val = 1;
    XNextEvent(dsp, &ev);
    switch (ev.type) {
    case Expose:
	if (((XExposeEvent *) & ev)->window == win)
	    return REDRAW;
	break;
    case KeyPress:
	{
	    XKeyEvent  *xke = (XKeyEvent *) & ev;
	    KeySym      keysym = XLookupKeysym(xke, 0);
	    switch (keysym) {
	    case XK_Up:
		return UPARROWKEY;
	    case XK_Down:
		return DOWNARROWKEY;
	    default:
		break;
	    }
	}
	break;
    case ButtonPress:
	{
	    XButtonEvent *xbe = (XButtonEvent *) & ev;
	    switch (xbe->button) {
	    case Button1:
		mousex = xbe->x;
		mousey = xbe->y;
		return LEFTMOUSE;
	    case Button2:
		return MIDDLEMOUSE;
	    case Button3:
		menux = xbe->x_root;
		menuy = xbe->y_root;
		return MENUBUTTON;
	    default:
		break;
	    }
	}
	break;
    case MotionNotify:
	break;
    }
}

void
getorigin(xo, yo)
    int        *xo;
    int        *yo;
{
    *xo = 0;
    *yo = 0;
}

void
getsize(xs, ys)
    int        *xs;
    int        *ys;
{
    *xs = winw;
    *ys = winh;
}

void
move2i(x, y)
    int         x,
                y;
{
    cpx = x;
    cpy = y;
}

/* NB: what's the difference between cmov2i and move2i??? */
void
cmov2i(x, y)
    int         x,
                y;
{
    cpx = x;
    cpy = y;
}

void
draw2i(x, y)
    int         x,
                y;
{
    XDrawLine(dsp, win, gc, cpx, winh - cpy, x, winh - y);
    cpx = x;
    cpy = y;
}

void
rectfi(x1, y1, x2, y2)
    int         x1;
    int         y1;
    int         x2;
    int         y2;
{
    XFillRectangle(dsp, win, gc, x1, winh - y2, x2 - x1, y2 - y1);
}

void
charstr(str)
    char       *str;
{
    XSetFont(dsp, gc, font->fid);
    XDrawString(dsp, win, gc, cpx, winh - cpy, str, strlen(str));
    XSetFont(dsp, gc, textfont->fid);
}

void
sginap(len)
    int         len;
{
    usleep(len);
}

void
bgnpolygon()
{
    if (poly == 0) {
	poly = (XPoint *) malloc(POLYBATCH * sizeof(XPoint));
	npoly = POLYBATCH;
    }
    curpoly = 0;
}

static void
addpoint(x, y)
    int         x;
    int         y;
{
    if (curpoly >= npoly) {
	npoly += POLYBATCH;
	poly = (XPoint *) realloc(poly, npoly * sizeof(XPoint));
    }
    poly[curpoly].x = x;
    poly[curpoly].y = y;
    curpoly++;
}

void
v2f(p)
    float      *p;
{
    addpoint((int) ((xoff + p[0]) * xscale), winh - (int) ((yoff + p[1]) * yscale));
}

void
endpolygon()
{
    XFillPolygon(dsp, win, gc, poly, curpoly, Nonconvex, CoordModeOrigin);
}

void
bgnclosedline()
{
    if (poly == 0) {
	poly = (XPoint *) malloc(POLYBATCH * sizeof(XPoint));
	npoly = POLYBATCH;
    }
    curpoly = 0;
}

void
endclosedline()
{
    addpoint(poly[0].x, poly[0].y);
    XDrawLines(dsp, win, gc, poly, curpoly, CoordModeOrigin);
}

void
ortho2(xmin, xmax, ymin, ymax)
    float       xmin;
    float       xmax;
    float       ymin;
    float       ymax;
{
    xoff = xmin;
    xscale = winw / (xmax - xmin);
    yoff = ymin;
    yscale = winh / (ymax - ymin);
}


/*
 * these routines are a cheesy ten minute hack to do menus with GL's API.
 */

#define MAXMENUS 10
#define MAXMENUITEMS 10
typedef struct {
    char       *title;
    int         titlewidth;
    int         nitems;
    char       *item[MAXMENUITEMS];
    Window      win;
    int         w;
    int         h;
}           MenuStruct;
MenuStruct  menu[10];
int         nummenus = 0;

#define MENUPADW 20
#define MENUPADH 4
#define MENUPADTITLE 8
#define SHADE 16

int
defpup(s)
    char       *s;
{
    int         n = nummenus++;
    char       *val = strtok(s, "|");
    int         w;
    int         mask;
    int         maxw;
    XSetWindowAttributes xswa;
    char       *p;

    if (nummenus >= MAXMENUS) {
	fprintf(stderr, "too many menus\n");
	exit(1);
    }
    p = rindex(val, '%');
    *p = 0;			/* nuke the %t */
    menu[n].title = strdup(val);
    menu[n].titlewidth = maxw = XTextWidth(textfont, val, strlen(val));
    while (val = strtok((char *) 0, "|")) {
	menu[n].item[menu[n].nitems++] = strdup(val);
	w = XTextWidth(textfont, val, strlen(val));
	if (w > maxw)
	    maxw = w;
	if (menu[n].nitems >= MAXMENUITEMS) {
	    fprintf(stderr, "too many menu items\n");
	    exit(1);
	}
    }
    menu[n].w = maxw + 2 * MENUPADW;
    menu[n].h = (menu[n].nitems + 1) * (fontheight + MENUPADH) + MENUPADTITLE;
    xswa.background_pixmap = None;
    xswa.save_under = True;
    xswa.event_mask = ExposureMask;
    xswa.override_redirect = True;
    mask = CWBackPixmap | CWEventMask | CWSaveUnder | CWOverrideRedirect;
    menu[n].win = XCreateWindow(dsp, root,
				0, 0, menu[n].w + SHADE, menu[n].h + SHADE, 0,
				CopyFromParent, InputOutput, CopyFromParent,
				mask, &xswa);
    return n;
}


static void
displayitem(menu, i, fg, bg)
    MenuStruct *menu;
    int         i;
    long        fg;
    long        bg;
{
    XSetForeground(dsp, gc, bg);
    XFillRectangle(dsp, menu->win, gc,
		   1, MENUPADTITLE + (fontheight + MENUPADH) * i,
		   menu->w - 1, (fontheight + MENUPADH));
    XSetForeground(dsp, gc, fg);
    XDrawString(dsp, menu->win, gc,
	   MENUPADW, MENUPADTITLE + (fontheight + MENUPADH) * i + fontascent,
		menu->item[i - 1], strlen(menu->item[i - 1]));
}

void
XDrawOString(d, w, g, x, y, s, n)
{
    XSetForeground(dsp, gc, black);
    XDrawString(d, w, g, x - 1, y - 1, s, n);
    XDrawString(d, w, g, x, y - 1, s, n);
    XDrawString(d, w, g, x + 1, y - 1, s, n);
    XDrawString(d, w, g, x - 1, y, s, n);
    XDrawString(d, w, g, x + 1, y, s, n);
    XDrawString(d, w, g, x - 1, y + 1, s, n);
    XDrawString(d, w, g, x, y + 1, s, n);
    XDrawString(d, w, g, x + 1, y + 1, s, n);
    XSetForeground(dsp, gc, white);
    XDrawString(d, w, g, x, y, s, n);
    XSetForeground(dsp, gc, black);
}

int
dopup(n)
    int         n;
{
    int         menuval = 0;
    int         oldmenuval = 0;
    int         i;
    XEvent      ev;
    Window      r;
    Window      w;
    int         rx;
    int         ry;
    int         wx;
    int         wy;
    int         mask;

    XMoveWindow(dsp, menu[n].win,
		menux - 2, menuy - fontheight - MENUPADH - MENUPADTITLE / 2);
    XMapRaised(dsp, menu[n].win);

    do {
	XNextEvent(dsp, &ev);
    } while (ev.type != Expose);

    XSetForeground(dsp, gc, white);
    XFillRectangle(dsp, menu[n].win, gc, 0, 0, menu[n].w, menu[n].h);
    XSetForeground(dsp, gc, black);
    XDrawRectangle(dsp, menu[n].win, gc, 0, 0, menu[n].w, menu[n].h);
    XSetFillStyle(dsp, gc, FillStippled);
    XFillRectangle(dsp, menu[n].win, gc, menu[n].w, SHADE, SHADE, menu[n].h);
    XFillRectangle(dsp, menu[n].win, gc, SHADE, menu[n].h, menu[n].w - SHADE, SHADE);
    XSetFillStyle(dsp, gc, FillSolid);
    XDrawOString(dsp, menu[n].win, gc,
		 (menu[n].w - menu[n].titlewidth) / 2, MENUPADH + fontascent,
		 menu[n].title, strlen(menu[n].title));
    XDrawRectangle(dsp, menu[n].win, gc, 2, 2,
		menu[n].w - 4, MENUPADH + fontheight + MENUPADTITLE / 2 - 4);
    XDrawLine(dsp, menu[n].win, gc, 0, MENUPADH + fontheight + MENUPADTITLE / 2,
	      menu[n].w, MENUPADH + fontheight + MENUPADTITLE / 2);
    for (i = 1; i <= menu[n].nitems; i++)
	displayitem(&menu[n], i, black, white);
    do {
	XQueryPointer(dsp, menu[n].win, &r, &w, &rx, &ry, &wx, &wy, &mask);

	if (wx > 0 && wx < menu[n].w &&
		wy > MENUPADTITLE + fontheight + MENUPADH &&
	wy < MENUPADTITLE + (fontheight + MENUPADH) * (1 + menu[n].nitems)) {
	    menuval = (wy - MENUPADTITLE) / (fontheight + MENUPADH);

	    if (oldmenuval != menuval) {
		if (oldmenuval)
		    displayitem(&menu[n], oldmenuval, black, white);
		displayitem(&menu[n], menuval, white, black);
		oldmenuval = menuval;
	    }
	} else if (oldmenuval) {
	    displayitem(&menu[n], oldmenuval, black, white);
	    oldmenuval = menuval = 0;
	}
    } while (mask & Button3Mask);
    XUnmapWindow(dsp, menu[n].win);
    return menuval;
}

void
RGBmode()
{
/* NOP */
}

void
gconfig()
{
/* NOP */
}

void
glcompat()
{
/* NOP */
}

void
subpixel()
{
/* NOP */
}

void
setpattern()
{
/* NOP */
}

void
reshapeviewport()
{
/* NOP */
}

void
qdevice(mask)
    int         mask;
{
/* NOP */
}
SHAR_EOF
fi
if test -f 'gl.h'
then
	echo shar: "will not over-write existing file 'gl.h'"
else
cat << \SHAR_EOF > 'gl.h'
#ident "@(#)gl.h	1.1 91/02/16 GL"
/*
 * gl.h - the beginnings of the defines to keep SGI GL programs happy.
 */

extern long mytimes();

#define REDRAW 0
#define UPARROWKEY 100
#define DOWNARROWKEY 101
#define RIGHTSHIFTKEY 103
#define LEFTMOUSE 200
#define MIDDLEMOUSE 201
#define MENUBUTTON 202
#define MOUSEX 0
#define MOUSEY 1
#define times mytimes

#define GLC_OLDPOLYGON 0
SHAR_EOF
fi
if test -f 'device.h'
then
	echo shar: "will not over-write existing file 'device.h'"
else
cat << \SHAR_EOF > 'device.h'
#ident "@(#)device.h	1.1 91/02/16 GL"
/*
 * device.h - empty file to keep SGI GL programs happy.
 */
SHAR_EOF
fi
exit 0
#	End of shell archive

-- 
    ______________________________________________________________________
    Patrick J. Naughton				   email: naughton at sun.com
    Sun Laboratories				   voice: (415) 336 - 1080



More information about the Comp.sys.sgi mailing list