/* * paint.c - * A minimal object space paint program. * * Paul Haeberli - 1985 */
#include <gl/gl.h> #include <gl/device.h> #include <math.h>
#define ABS( a ) (((a) > 0) ? (a) : -(a)) #define MOUSE 12 #define TABLET 13 #define DRAWLINE 2 #define NEWCOLOR 3 #define CLEAR 4 #define NEWSIZE 5 #define MOUSEXMAP(x) ( (100.0*((x)-xorg))/(xsize) ) #define MOUSEYMAP(y) ( (100.0*((y)-yorg))/(ysize) ) #define BPSCALE 16.0
struct event {
struct event *next;
int func;
float arg1;
float arg2;
float arg3;
float arg4;
};
int xsize, ysize; int xorg, yorg; int mx, my; int bpx, bpy; int mmiddle, mleft; int curcolor = 7; int lastcurcolor = 7; float curx, cury, cursize; int curdev = MOUSE; struct event *histstart = 0; struct event *histend = 0; float xpos, ypos; int pendown; int brushsides; float brushcoords[30][2]; int menu;
main()
{
cursize = 1.0;
prefposition(XMAXSCREEN/4,XMAXSCREEN*3/4,YMAXSCREEN/4,
YMAXSCREEN*3/4);
winopen("paint");
menu = defpup("paint %t|mouse|tablet");
makebrush();
makeframe();
getinput();
}
getinput()
{
Device dev;
short val;
float x, y;
while(TRUE) {
do {
dev = qread(&val);
switch (dev) {
case MOUSEX:
mx = val;
if (curdev == MOUSE)
xpos = MOUSEXMAP(val);
break;
case MOUSEY:
my = val;
if (curdev == MOUSE)
ypos = MOUSEYMAP(val);
break;
case BPADX:
bpx = val;
if (curdev == TABLET)
xpos = val/BPSCALE;
break;
case BPADY:
bpy = val;
if (curdev == TABLET)
ypos = val/BPSCALE;
break;
case BPAD0:
if (curdev == TABLET)
pendown = val;
if (val) {
curx = xpos = bpx/BPSCALE;
cury = ypos = bpy/BPSCALE;
}
break;
case MENUBUTTON:
if(val) {
switch (dopup(menu)) {
case 1:
curdev = MOUSE;
break;
case 2:
curdev = TABLET;
break;
}
}
break;
case MIDDLEMOUSE:
mmiddle = val;
if (mmiddle) {
clearscreen();
history(CLEAR);
}
break;
case LEFTMOUSE:
mleft = val;
if (mleft) {
if (!inside(mx-xorg, my-yorg,
0, xsize, 0, ysize, 0)) {
newcolor(getapixel(mx,my));
history(NEWCOLOR,(float)curcolor);
}
}
if (curdev == MOUSE) {
pendown = val;
curx = xpos = MOUSEXMAP(mx);
cury = ypos = MOUSEYMAP(my);
}
break; case REDRAW: makeframe(); replay(); break; case ESCKEY: gexit(); exit(0); break; }
} while (qtest());
if (pendown) {
x = xpos;
y = ypos;
drawbrush(x,y,curx,cury);
history(DRAWLINE,x,y,curx,cury);
curx = x;
cury = y;
}
}
}
clearscreen()
{
color(curcolor);
clear();
}
newcolor(c)
int c;
{
lastcurcolor = curcolor;
curcolor = c;
paintport();
}
makeframe()
{
qdevice(ESCKEY);
qdevice(MOUSEX);
qdevice(MOUSEY);
qdevice(MENUBUTTON);
qdevice(MIDDLEMOUSE);
qdevice(LEFTMOUSE);
qdevice(BPADX);
qdevice(BPADY);
qdevice(BPAD0);
getsize(&xsize,&ysize);
getorigin(&xorg,&yorg);
paintport();
newcolor(0);
clearscreen();
newcolor(255);
newcolor(128+32);
}
paintport()
{
viewport(0,xsize-1,0,ysize);
ortho2(-0.5,99.5,-0.5,99.5);
}
inside(x,y,xmin,xmax,ymin,ymax,fudge)
int x, y, xmin, xmax, ymin, ymax, fudge;
{
if (x>xmin-fudge && x<xmax+fudge &&
y>ymin-fudge && y<ymax+fudge)
return 1;
else
return 0;
}
makebrush()
{
int i;
brushsides = 4;
brushcoords[0][0] = -0.6;
brushcoords[0][1] = -0.2;
brushcoords[1][0] = -0.6;
brushcoords[1][1] = -0.4;
brushcoords[2][0] = 0.6;
brushcoords[2][1] = 0.2;
brushcoords[3][0] = 0.6;
brushcoords[3][1] = 0.4;
for (i=0; i<brushsides; i++) {
brushcoords[i][0] = 0.5*brushcoords[i][0];
brushcoords[i][1] = 0.5*brushcoords[i][1];
}
}
drawbrush(x,y,ox,oy)
float x, y, ox, oy;
{
register int i, n;
register float dx, dy;
float quad[4][2];
float delta;
int c;
dx = ox-x;
dy = oy-y;
if (lastcurcolor != curcolor) {
delta = sqrt(dx*dx+dy*dy);
if (delta<0.001)
return;
c = (int) (curcolor + (lastcurcolor-curcolor) *
(ABS(dx)/delta) );
color(c);
}
else
color(curcolor);
pushmatrix();
translate(x,y,0.0);
for (i=0; i<brushsides; i++) {
n = (i+1) % brushsides;
quad[0][0] = brushcoords[i][0];
quad[0][1] = brushcoords[i][1];
quad[1][0] = brushcoords[n][0];
quad[1][1] = brushcoords[n][1];
quad[2][0] = quad[1][0]+dx;
quad[2][1] = quad[1][1]+dy;
quad[3][0] = quad[0][0]+dx;
quad[3][1] = quad[0][1]+dy;
polf2(4,quad);
}
polf2(brushsides,brushcoords); popmatrix(); }
history(func,arg1,arg2,arg3,arg4)
int func;
float arg1, arg2, arg3, arg4;
{
register struct event *e, *n;
e = (struct event *)malloc(sizeof(struct event));
switch (func) {
case CLEAR:
zaphistory();
history(NEWCOLOR,(float)curcolor);
break;
case NEWCOLOR:
case DRAWLINE:
e->func = func;
e->arg1 = arg1;
e->arg2 = arg2;
e->arg3 = arg3;
e->arg4 = arg4;
e->next = 0;
if (!histstart) {
histstart = histend = e;
}
else {
histend->next = e;
histend = e;
}
break; }
}
zaphistory()
{
register struct event *e, *n;
e = histstart;
while (e) {
n = e->next;
free(e);
e = n;
}
histstart = histend = 0; }
replay()
{
register struct event *e;
register int i;
i = 0;
e = histstart;
while (e) {
switch (e->func) {
case NEWCOLOR:
newcolor((int)e->arg1);
break;
case DRAWLINE:
drawbrush(e->arg1,e->arg2,e->arg3,e->arg4);
break;
case CLEAR:
clearscreen();
break;
}
e = e->next;
i++;
}
}
/*
* getapixel -
* Read a pixel from a specific screen location.
*
*/
getapixel(mousex, mousey)
short mousex, mousey;
{
short pixel;
int xmin, ymin; /* Convert position to window relative coordinates */
getorigin(&xmin, &ymin);
mousex -= xmin;
mousey -= ymin;
rectread(mousex, mousey, mousex+1, mousey+1, &pixel);
return(pixel); }
The getorigin subroutine, getsize subroutine, ortho or ortho2 subroutine, rectread or lrectread subroutine, viewport subroutine.