/* * dynadraw - * Use a simple dynamics model to create caligraphic * strokes. * * Paul Haeberli - 1989 * to compile: * 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 (10000) #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.0; float width, shrink; float odelx, odely; float curmass, curdrag; float polyverts[4*2*MAXPOLYS]; int npolys; filter mouse; long xsize, ysize; long xorg, yorg; 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 dx, dy, force; mass = flerp(1.0,2.0*80.0,curmass); drag = flerp(0.00,0.5,curdrag*curdrag); dx = mx-f->curx; dy = my-f->cury; f->acc = sqrt(dx*dx+dy*dy); if(f->acc<0.00000001) return; f->accx = dx/f->acc; f->accy = dy/f->acc; force = f->acc/mass; f->accx *= force; f->accy *= force; f->velx = f->velx+f->accx; f->vely = f->vely+f->accy; f->vel = f->velx*f->velx+f->vely*f->vely; f->angx = -f->vely; f->angy = f->velx; if(f->vel>0.00000001) { f->vel = sqrt(f->vel); f->angx /= f->vel; f->angy /= f->vel; } if(f->fixedangle) { f->angx = 0.6; f->angy = 0.2; } f->velx = f->velx*(1.0-drag); f->vely = f->vely*(1.0-drag); f->lastx = f->curx; f->lasty = f->cury; f->curx = f->curx+f->velx; f->cury = f->cury+f->vely; } 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); RGBmode(); gconfig(); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); qdevice(MENUBUTTON); qdevice(RIGHTSHIFTKEY); qdevice(UPARROWKEY); qdevice(DOWNARROWKEY); qdevice(RIGHTSHIFTKEY); makeframe(); menu = defpup("calligraphy %t|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: savepolys(); break; case 2: 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(); #ifdef ZEDPEN pres = getvaluator(DIAL0); width = (initwidth*pres)/100.0; #endif 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,5+1*SLIDERHIGH); charstr(str); sprintf(str,"Drag %g",curdrag); cmov2i(20,5+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); } #define DELTA (0.002); drawsegment(f) filter *f; { float delx, dely; float v; float *fptr; float px, py, nx, ny; v = f->vel; #ifdef ZEDPEN v = 0.0; #endif v = 0.04-v; v = v*width; if(v<0.00001) v = 0.00001; v *= shrink; #ifndef SHRINK v = 0.04*width; #endif delx = f->angx*v; dely = f->angy*v; 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\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