paul@manray.asd.sgi.com (Paul Haeberli) (02/12/91)
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@sgi.com 415-962-3665 /* * dynadraw - * Use a simple dynamics model to create caligraphic * strokes. * * Paul Haeberli - 1989 * to compile on an IRIS: * cc -O dynadraw.c -o dynadraw -lgl_s -lm * * leftmouse - used for drawing * middlemouse - clears page * rightmouse - menu. * * uparrow - wider strokes * downarrow - narrower strokes * */ #include "gl.h" #include "device.h" #include "math.h" #include "stdio.h" #include "sys/types.h" #include "sys/times.h" #include "sys/param.h" #define SLIDERHIGH (15) #define SLIDERLEFT (200) #define TIMESLICE (0.005) #define MAXPOLYS (20000) #define SHRINK typedef struct filter { float curx, cury; float velx, vely, vel; float accx, accy, acc; float angx, angy; float mass, drag; float lastx, lasty; int fixedangle; } filter; float initwidth = 1.5; float width, shrink; float odelx, odely; float curmass, curdrag; float polyverts[4*2*MAXPOLYS]; int npolys; long xsize, ysize; long xorg, yorg; filter mouse; float flerp(); float fgetmousex(); float fgetmousey(); float gettime(); unsigned long getltime(); filtersetpos(f,x,y) filter *f; float x, y; { f->curx = x; f->cury = y; f->lastx = x; f->lasty = y; f->velx = 0.0; f->vely = 0.0; f->accx = 0.0; f->accy = 0.0; } filterapply(f,mx,my) filter *f; float mx, my; { float mass, drag; float fx, fy, force; /* calculate mass and drag */ mass = flerp(1.0,160.0,curmass); drag = flerp(0.00,0.5,curdrag*curdrag); /* calculate force and acceleration */ fx = mx-f->curx; fy = my-f->cury; f->acc = sqrt(fx*fx+fy*fy); if(f->acc<0.000001) return 0; f->accx = fx/mass; f->accy = fy/mass; /* calculate new velocity */ f->velx += f->accx; f->vely += f->accy; f->vel = sqrt(f->velx*f->velx+f->vely*f->vely); f->angx = -f->vely; f->angy = f->velx; if(f->vel<0.000001) return 0; /* calculate angle of drawing tool */ f->angx /= f->vel; f->angy /= f->vel; if(f->fixedangle) { f->angx = 0.6; f->angy = 0.2; } /* apply drag */ f->velx = f->velx*(1.0-drag); f->vely = f->vely*(1.0-drag); /* update position */ f->lastx = f->curx; f->lasty = f->cury; f->curx = f->curx+f->velx; f->cury = f->cury+f->vely; return 1; } float paramval() { float p; p = (float)(getmousex()-SLIDERLEFT)/(xsize-SLIDERLEFT); if(p<0.0) return 0.0; if(p>1.0) return 1.0; return p; } main() { short val; int menu, pres; float p, mx, my; curmass = 0.5; curdrag = 0.15; prefsize(1000,800); initbuzz(); winopen("dynadraw"); glcompat(GLC_OLDPOLYGON,1); subpixel(1); RGBmode(); gconfig(); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); qdevice(MENUBUTTON); qdevice(RIGHTSHIFTKEY); qdevice(UPARROWKEY); qdevice(DOWNARROWKEY); qdevice(RIGHTSHIFTKEY); makeframe(); menu = defpup("calligraphy %t|toggle line style|save ps|save image"); width = initwidth; mouse.fixedangle = 1; while(1) { switch(qread(&val)) { case REDRAW: makeframe(); break; case MIDDLEMOUSE: if(val) clearscreen(); break; case UPARROWKEY: if(val) initwidth *= 1.414213; width = initwidth; break; case DOWNARROWKEY: if(val) initwidth /= 1.414213; width = initwidth; break; case MENUBUTTON: if(val) { switch(dopup(menu)) { case 1: mouse.fixedangle = 1-mouse.fixedangle; break; case 2: savepolys(); break; case 3: savewindow("drag.rgb"); break; } } break; case LEFTMOUSE: if(val) { my = getmousey(); if(my>0*SLIDERHIGH && my<2*SLIDERHIGH) { if(my>SLIDERHIGH) { while(getbutton(LEFTMOUSE)) { p = paramval(); if(p != curmass) { curmass = p; showsettings(); } } } else { while(getbutton(LEFTMOUSE)) { p = paramval(); if(p != curdrag) { curdrag = p; showsettings(); } } } } else { mx = 1.25*fgetmousex(); my = fgetmousey(); filtersetpos(&mouse,mx,my); odelx = 0.0; odely = 0.0; shrink = 1.0; while(getbutton(LEFTMOUSE)) { mx = 1.25*fgetmousex(); my = fgetmousey(); if(filterapply(&mouse,mx,my)) { drawsegment(&mouse); RGBcolor(0,0,0); buzz(); if(getbutton(RIGHTSHIFTKEY)) shrink = shrink*0.98; } } } } break; } } } makeframe() { reshapeviewport(); getsize(&xsize,&ysize); getorigin(&xorg,&yorg); clearscreen(); } clearscreen() { int x, y; ortho2(0.0,1.25,0.0,1.0); RGBcolor(200,200,200); setpattern(0); clear(); npolys = 0; showsettings(); RGBcolor(0,0,0); } showsettings() { char str[256]; int xpos; ortho2(-0.5,xsize-0.5,-0.5,ysize-0.5); RGBcolor(200,200,200); rectfi(0,0,xsize,2*SLIDERHIGH); RGBcolor(0,0,0); sprintf(str,"Mass %g",curmass); cmov2i(20,3+1*SLIDERHIGH); charstr(str); sprintf(str,"Drag %g",curdrag); cmov2i(20,3+0*SLIDERHIGH); charstr(str); move2i(SLIDERLEFT,0); draw2i(SLIDERLEFT,2*SLIDERHIGH); move2i(0,1*SLIDERHIGH); draw2i(xsize,1*SLIDERHIGH); move2i(0,2*SLIDERHIGH); draw2i(xsize,2*SLIDERHIGH); RGBcolor(255,0,0); xpos = SLIDERLEFT+curmass*(xsize-SLIDERLEFT); rectfi(xpos,1*SLIDERHIGH,xpos+4,2*SLIDERHIGH); xpos = SLIDERLEFT+curdrag*(xsize-SLIDERLEFT); rectfi(xpos,0*SLIDERHIGH,xpos+4,1*SLIDERHIGH); ortho2(0.0,1.25,0.0,1.0); } drawsegment(f) filter *f; { float delx, dely; float wid, *fptr; float px, py, nx, ny; wid = 0.04-f->vel; wid = wid*width; if(wid<0.00001) wid = 0.00001; wid *= shrink; delx = f->angx*wid; dely = f->angy*wid; RGBcolor(0,0,0); px = f->lastx; py = f->lasty; nx = f->curx; ny = f->cury; fptr = polyverts+8*npolys; bgnpolygon(); fptr[0] = px+odelx; fptr[1] = py+odely; v2f(fptr); fptr += 2; fptr[0] = px-odelx; fptr[1] = py-odely; v2f(fptr); fptr += 2; fptr[0] = nx-delx; fptr[1] = ny-dely; v2f(fptr); fptr += 2; fptr[0] = nx+delx; fptr[1] = ny+dely; v2f(fptr); fptr += 2; endpolygon(); npolys++; if(npolys>=MAXPOLYS) { printf("out of polys - increase the define MAXPOLYS\n"); exit(1); } #define DOLINES #ifdef DOLINES fptr -= 8; bgnclosedline(); v2f(fptr); fptr += 2; v2f(fptr); fptr += 2; v2f(fptr); fptr += 2; v2f(fptr); fptr += 2; endclosedline(); #endif odelx = delx; odely = dely; } int buzztemp, buzzmax; buzz() { int i; for(i=0; i<buzzmax; i++) buzztemp++; } initbuzz() { long t0, t1; buzzmax = 1000000; sginap(10); t0 = getltime(); buzz(); t1 = getltime(); buzzmax = TIMESLICE*(100.0*1000000.0)/(t1-t0); } savepolys() { FILE *of; int i; float *fptr; of = fopen("/tmp/drag.ps","w"); fprintf(of,"%%!\n"); fprintf(of,"%f %f translate\n",0.25*72,(11.0-0.75)*72); fprintf(of,"-90 rotate\n"); fprintf(of,"%f %f scale\n",8.0*72,8.0*72); fprintf(of,"0.0 setgray\n"); printf("npolys %d\n",npolys); fptr = polyverts; for(i=0; i<npolys; i++) { fprintf(of,"newpath\n"); fprintf(of,"%f %f moveto\n",fptr[0],fptr[1]); fptr+=2; fprintf(of,"%f %f lineto\n",fptr[0],fptr[1]); fptr+=2; fprintf(of,"%f %f lineto\n",fptr[0],fptr[1]); fptr+=2; fprintf(of,"%f %f lineto\n",fptr[0],fptr[1]); fptr+=2; fprintf(of,"closepath\n"); fprintf(of,"fill\n"); } fprintf(of,"showpage\n"); fclose(of); fprintf(stderr,"PostScript saved to /tmp/drag.ps\n"); } /* * winlib routines follow * */ float fgetmousex() { return ((float)getvaluator(MOUSEX)-xorg)/(float)xsize; } float fgetmousey() { return ((float)getvaluator(MOUSEY)-yorg)/(float)ysize; } int getmousex() { return getvaluator(MOUSEX)-xorg; } int getmousey() { return getvaluator(MOUSEY)-yorg; } float flerp(f0,f1,p) float f0, f1, p; { return ((f0*(1.0-p))+(f1*p)); } savewindow(name) char *name; { char cmd[256]; long xorg, yorg; long xsize, ysize; getorigin(&xorg,&yorg); getsize(&xsize,&ysize); sprintf(cmd,"scrsave %s %d %d %d %d\n",name,xorg,xorg+xsize-1,yorg,yorg+ysize-1); system(cmd); } unsigned long getltime() { struct tms ct; return times(&ct); }
pdc@sgi.com (Paul Close) (02/14/91)
In article <85040@sgi.sgi.com> paul@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. This is indeed a *highly cool* program! If however, you have 8-bit graphics on your PI, you'll want to apply the following unoffical patch (the line numbers might be off because I didn't strip the headers): *** dynadraw.c.old Wed Feb 13 09:38:06 1991 --- dynadraw.c Wed Feb 13 09:39:56 1991 *************** *** 164,170 **** winopen("dynadraw"); glcompat(GLC_OLDPOLYGON,1); subpixel(1); ! RGBmode(); gconfig(); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); --- 164,170 ---- winopen("dynadraw"); glcompat(GLC_OLDPOLYGON,1); subpixel(1); ! shademodel(FLAT); gconfig(); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); *************** *** 244,250 **** my = fgetmousey(); if(filterapply(&mouse,mx,my)) { drawsegment(&mouse); ! RGBcolor(0,0,0); buzz(); if(getbutton(RIGHTSHIFTKEY)) shrink = shrink*0.98; --- 244,250 ---- my = fgetmousey(); if(filterapply(&mouse,mx,my)) { drawsegment(&mouse); ! color(0); buzz(); if(getbutton(RIGHTSHIFTKEY)) shrink = shrink*0.98; *************** *** 270,281 **** int x, y; ortho2(0.0,1.25,0.0,1.0); ! RGBcolor(200,200,200); setpattern(0); clear(); npolys = 0; showsettings(); ! RGBcolor(0,0,0); } showsettings() --- 270,281 ---- int x, y; ortho2(0.0,1.25,0.0,1.0); ! color(51); setpattern(0); clear(); npolys = 0; showsettings(); ! color(0); } showsettings() *************** *** 284,292 **** int xpos; ortho2(-0.5,xsize-0.5,-0.5,ysize-0.5); ! RGBcolor(200,200,200); rectfi(0,0,xsize,2*SLIDERHIGH); ! RGBcolor(0,0,0); sprintf(str,"Mass %g",curmass); cmov2i(20,3+1*SLIDERHIGH); charstr(str); --- 284,292 ---- int xpos; ortho2(-0.5,xsize-0.5,-0.5,ysize-0.5); ! color(51); rectfi(0,0,xsize,2*SLIDERHIGH); ! color(0); sprintf(str,"Mass %g",curmass); cmov2i(20,3+1*SLIDERHIGH); charstr(str); *************** *** 299,305 **** draw2i(xsize,1*SLIDERHIGH); move2i(0,2*SLIDERHIGH); draw2i(xsize,2*SLIDERHIGH); ! RGBcolor(255,0,0); xpos = SLIDERLEFT+curmass*(xsize-SLIDERLEFT); rectfi(xpos,1*SLIDERHIGH,xpos+4,2*SLIDERHIGH); xpos = SLIDERLEFT+curdrag*(xsize-SLIDERLEFT); --- 299,305 ---- draw2i(xsize,1*SLIDERHIGH); move2i(0,2*SLIDERHIGH); draw2i(xsize,2*SLIDERHIGH); ! color(1); xpos = SLIDERLEFT+curmass*(xsize-SLIDERLEFT); rectfi(xpos,1*SLIDERHIGH,xpos+4,2*SLIDERHIGH); xpos = SLIDERLEFT+curdrag*(xsize-SLIDERLEFT); *************** *** 322,328 **** delx = f->angx*wid; dely = f->angy*wid; ! RGBcolor(0,0,0); px = f->lastx; py = f->lasty; nx = f->curx; --- 322,328 ---- delx = f->angx*wid; dely = f->angy*wid; ! color(0); px = f->lastx; py = f->lasty; nx = f->curx; -- Paul Close pdc@sgi.com ...!{ames, decwrl, ucbvax}!sgi!pdc It is pitch dark. You are likely to be eaten by a grue.
naughton@wind.Eng.Sun.COM (Patrick Naughton) (02/17/91)
In article <85040@sgi.sgi.com>, paul@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@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@sun.com Sun Laboratories voice: (415) 336 - 1080