]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/catclock.c
bring games/swar from 1ed sources.
[plan9front.git] / sys / src / games / catclock.c
1 /* Copyright 1985 Massachusetts Institute of Technology */
2 #include <u.h>
3 #include <libc.h>
4 #include <draw.h>
5 #include <event.h>
6
7 #define add addpt
8 #define sub subpt
9 int wind = 1;
10
11 typedef enum{
12         Odd=1,
13         Nonzero=~0
14 }Windrule;
15 #include "catback.p"
16 #include "eyes.p"
17 #define CATWID  150             /* width of body bitmap */
18 #define CATHGT  300             /* height of body bitmap */
19 #define TAILWID 150             /* width of tail bitmap */
20 #define TAILHGT 89              /* height of tail bitmap */
21 #define MINULEN 27              /* length of minute hand */
22 #define HOURLEN 15              /* length of hour hand */
23 #define HANDWID 4               /* width of clock hands */
24 #define UPDATE  (1000/NTAIL)    /* ms/update -- tail waves at roughly 1/2 hz */
25 #define BLACK   (~0)
26 #define WHITE   0
27 #define NTP     7
28 Point tp[NTP]={                 /* tail polygon */
29          0, 0,
30          0,76,
31          3,82,
32         10,84,
33         18,82,
34         21,76,
35         21,70,
36 };
37 #define NTAIL   16
38 Image *eye[NTAIL+1];
39 Image *tail[NTAIL+1];
40 Image *cat;                     /* cat body */
41 Image *eyes;                    /* eye background */
42 Point toffs={ 74, -15 };        /* tail polygon offset */
43 Point tailoffs={0, 211};        /* tail bitmap offset, relative to body */
44 Point eyeoffs={49, 30};         /* eye bitmap offset, relative to body */
45 Point catoffs;                  /* cat offset, relative to screen */
46 int xredraw;
47 int crosseyed;
48 void drawclock(void);
49 void drawhand(int, int, double);
50 void init(void);
51 Image *draweye(double);
52 Image *drawtail(double);
53 Image *eballoc(Rectangle, int);
54 //int myfillpoly(Image *, Point [], int, Windrule, int, Fcode);
55 //void mydrawpoly(Image *, Point [], int, int, Fcode);
56 Image *eballoc(Rectangle r, int chan){
57         Image *b=allocimage(display, r, chan, 0, DWhite);
58         if(b==0){
59                 fprint(2, "catclock: can't allocate bitmap\n");
60                 exits("allocimage");
61         }
62         return b;
63 }
64
65 void
66 eloadimage(Image *i, Rectangle r, uchar *d, int nd)
67 {
68         int n;
69         n = loadimage(i, r, d, nd);
70         if(n < nd) {
71                 fprint(2, "loadimage fails: %r\n");
72                 exits("loadimage");
73         }
74 }
75
76 int round(double x){
77         return x>=0.?x+.5:x-.5;
78 }
79
80 void
81 redraw(Image *screen)
82 {
83         Rectangle r = Rect(0,0,Dx(screen->r), Dy(screen->r));
84         catoffs.x=(Dx(r)-CATWID)/2;
85         catoffs.y=(Dy(r)-CATHGT)/2;
86         xredraw=1;
87 }
88
89 void
90 eresized(int new)
91 {
92         if(new && getwindow(display, Refmesg) < 0)
93                 fprint(2,"can't reattach to window");
94         redraw(screen);
95 }
96
97 void main(int argc, char *argv[]){
98         int i;
99         ARGBEGIN{
100         case 'c': crosseyed++; break;
101         default:
102                 fprint(2, "Usage: %s [-c]\n", argv0);
103                 exits("usage");
104         }ARGEND
105         if(initdraw(0, 0, "cat clock") < 0)
106                 sysfatal("initdraw: %r");
107         einit(Emouse);
108         redraw(screen);
109         for(i=0; i<nelem(catback_bits); i++)
110                 catback_bits[i] ^= 0xFF;
111         for(i=0; i<nelem(eyes_bits); i++)
112                 eyes_bits[i] ^= 0xFF;
113         cat=eballoc(Rect(0, 0, CATWID, CATHGT), GREY1);
114         eloadimage(cat, cat->r, catback_bits, sizeof(catback_bits));
115 //      wrbitmap(cat, cat->r.min.y, cat->r.max.y, catback_bits);
116         for(i=0;i<=NTAIL;i++){
117                 tail[i]=drawtail(i*PI/NTAIL);
118                 eye[i]=draweye(i*PI/NTAIL);
119         }
120         for(;;){
121                 while(ecanmouse()) emouse();    /* don't get resize events without this! */
122                 drawclock();
123                 flushimage(display, 1);
124 //              bflush();
125                 sleep(UPDATE);
126         }
127 }
128 /*
129  * Draw a clock hand, theta is clockwise angle from noon
130  */
131 void drawhand(int length, int width, double theta){
132         double c=cos(theta), s=sin(theta);
133         double ws=width*s, wc=width*c;
134         Point vhand[4];
135         vhand[0]=add(screen->r.min, add(catoffs, Pt(CATWID/2+round(length*s), CATHGT/2-round(length*c))));
136         vhand[1]=add(screen->r.min, add(catoffs, Pt(CATWID/2-round(ws+wc), CATHGT/2+round(wc-ws))));
137         vhand[2]=add(screen->r.min, add(catoffs, Pt(CATWID/2-round(ws-wc), CATHGT/2+round(wc+ws))));
138         vhand[3] = vhand[0];
139         fillpoly(screen, vhand, 4, wind, display->white, 
140                 addpt(screen->r.min, vhand[0]));
141         poly(screen, vhand, 4, Endsquare, Endsquare, 0, display->black,
142                 addpt(screen->r.min, vhand[0]));
143 //      myfillpoly(&screen, vhand, 3, Nonzero, WHITE, S);
144 //      mydrawpoly(&screen, vhand, 3, BLACK, S);
145 }
146 /*
147  * draw a cat tail, t is time (mod 1 second)
148  */
149 Image *drawtail(double t){
150         Image *bp;
151         double theta=.4*sin(t+3.*PIO2)-.08;     /* an assymetric tail leans to one side */
152         double s=sin(theta), c=cos(theta);
153         Point rtp[NTP];
154         int i;
155         bp=eballoc(Rect(0, 0, TAILWID, TAILHGT), GREY1);
156         for(i=0;i!=NTP;i++)
157                 rtp[i]=add(Pt(tp[i].x*c+tp[i].y*s, -tp[i].x*s+tp[i].y*c), toffs);
158         fillpoly(bp, rtp, NTP, wind, display->black, rtp[0]);
159         return bp;
160 }
161 /*
162  * draw the cat's eyes, t is time (mod 1 second)
163  */
164 Image *draweye(double t){
165         Image *bp;
166         double u;
167         double angle=0.7*sin(t+3*PIO2)+PI/2.0;  /* direction eyes point */
168         Point pts[100];
169         int i, j;
170         struct{
171                 double  x, y, z;
172         }pt;
173         if(eyes==0){
174                 eyes=eballoc(Rect(0, 0, eyes_width, eyes_height), GREY1);
175                 eloadimage(eyes, eyes->r, eyes_bits, sizeof(eyes_bits));
176 //              wrbitmap(eyes, eyes->r.min.y, eyes->r.max.y, eyes_bits);
177         }
178         bp=eballoc(eyes->r, GREY1);
179         draw(bp, bp->r, eyes, nil, ZP);
180 //      bitblt(bp, bp->r.min, eyes, eyes->r, S);
181         for(i=0,u=-PI/2.0;u<PI/2.0;i++,u+=0.25){
182                 pt.x=cos(u)*cos(angle+PI/7.0);
183                 pt.y=sin(u);
184                 pt.z=2.+cos(u)*sin(angle+PI/7.0);
185                 pts[i].x=(pt.z==0.0?pt.x:pt.x/pt.z)*23.0+12.0;
186                 pts[i].y=(pt.z==0.0?pt.y:pt.y/pt.z)*23.0+11.0;
187         }
188         for(u=PI/2.0;u>-PI/2.0;i++,u-=0.25){
189                 pt.x=cos(u)*cos(angle-PI/7.0);
190                 pt.y=sin(u);
191                 pt.z=2.+cos(u)*sin(angle-PI/7.0);
192                 pts[i].x=(pt.z==0.0?pt.x:pt.x/pt.z)*23.0+12.0;
193                 pts[i].y=(pt.z==0.0?pt.y:pt.y/pt.z)*23.0+11.0;
194         }
195         fillpoly(bp, pts, i, wind, display->black, pts[0]);
196 //      fillpoly(bp, pts, i, Nonzero, BLACK, S);
197         if(crosseyed){
198                 angle=0.7*sin(PI-t+3*PIO2)+PI/2.0;
199                 for(i=0,u=-PI/2.0;u<PI/2.0;i++,u+=0.25){
200                         pt.x=cos(u)*cos(angle+PI/7.0);
201                         pt.y=sin(u);
202                         pt.z=2.+cos(u)*sin(angle+PI/7.0);
203                         pts[i].x=(pt.z==0.0?pt.x:pt.x/pt.z)*23.0+12.0;
204                         pts[i].y=(pt.z==0.0?pt.y:pt.y/pt.z)*23.0+11.0;
205                 }
206                 for(u=PI/2.0;u>-PI/2.0;i++,u-=0.25){
207                         pt.x=cos(u)*cos(angle-PI/7.0);
208                         pt.y=sin(u);
209                         pt.z=2.+cos(u)*sin(angle-PI/7.0);
210                         pts[i].x=(pt.z==0.0?pt.x:pt.x/pt.z)*23.0+12.0;
211                         pts[i].y=(pt.z==0.0?pt.y:pt.y/pt.z)*23.0+11.0;
212                 }
213         }
214         for(j=0;j<i;j++) pts[j].x+=31;
215         fillpoly(bp, pts, i, wind, display->black, pts[0]);
216 //      fillpoly(bp, pts, i, Nonzero, BLACK, S);
217         return bp;
218 }
219 void
220 drawclock(void){
221         static int t=0, dt=1;
222         static Tm otm;
223         Tm tm=*localtime(time(0));
224         tm.hour%=12;
225         if(xredraw || tm.min!=otm.min || tm.hour!=otm.hour){
226                 if(xredraw){
227                         draw(screen, screen->r, display->white, nil, ZP);
228                         border(screen, screen->r, 4, display->black, ZP);
229                         replclipr(screen, 0, insetrect(screen->r, 4));
230                         //bitblt(&screen, screen.r.min, &screen, screen.r, Zero);
231                         //border(&screen, screen.r, 4, F);
232                 }
233                 draw(screen, screen->r, cat, nil, mulpt(catoffs, -1));
234                 flushimage(display, 1);
235                 //bitblt(&screen, catoffs, cat, cat->r, S);
236                 drawhand(MINULEN, HANDWID, 2.*PI*tm.min/60.);
237                 drawhand(HOURLEN, HANDWID, 2.*PI*(tm.hour+tm.min/60.)/12.);
238                 xredraw=0;
239         }
240         draw(screen, screen->r, tail[t], nil, 
241                 mulpt(add(catoffs, tailoffs), -1));
242         draw(screen, screen->r, eye[t], nil, 
243                 mulpt(add(catoffs, eyeoffs), -1));
244         //bitblt(&screen, add(catoffs, tailoffs), tail[t], tail[t]->r, S);
245         //bitblt(&screen, add(catoffs, eyeoffs), eye[t], eye[t]->r, S);
246         t+=dt;
247         if(t<0 || t>NTAIL){
248                 t-=2*dt;
249                 dt=-dt;
250         }
251         otm=tm;
252 }
253 #ifdef NOTDEF
254 void drawpoly(Bitmap *dst, Point p[], int np, int v, Fcode f){
255         int i;
256         Point q=p[np-1];
257         for(i=0;i!=np;i++){
258                 segment(dst, p[i], q, v, f);
259                 q=p[i];
260         }
261 }
262 /*
263  * Fillpoly -- a polygon tiler
264  * Updating the edgelist from scanline to scanline could be quicker if no
265  * edges cross:  we can just merge the incoming edges.  The code can handle
266  * multiply-connected polygons with holes, but the interface can't.  If
267  * the scan-line filling routine were a parameter, we could do textured
268  * polygons, polyblt, and other such stuff.
269  */
270 typedef struct edge Edge;
271 struct edge{
272         Point p;        /* point of crossing current scan-line */
273         int maxy;       /* scan line at which to discard edge */
274         int dx;         /* x increment if x fraction<1 */
275         int dx1;        /* x increment if x fraction>=1 */
276         int x;          /* x fraction, scaled by den */
277         int num;        /* x fraction increment for unit y change, scaled by den */
278         int den;        /* x fraction increment for unit x change, scaled by num */
279         int dwind;      /* increment of winding number on passing this edge */
280         Edge *next;     /* next edge on current scanline */
281         Edge *prev;     /* previous edge on current scanline */
282 };
283 void insert(Edge *ep, Edge **yp){
284         while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
285         ep->next=*yp;
286         *yp=ep;
287         if(ep->next){
288                 ep->prev=ep->next->prev;
289                 ep->next->prev=ep;
290                 if(ep->prev)
291                         ep->prev->next=ep;
292         }
293         else
294                 ep->prev=0;
295 }
296 int myfillpoly(Bitmap *b, Point vert[], int nvert, Windrule w, int v, Fcode f){
297         Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
298         Point *p, *q, *evert, p0, p1, p10;
299         int dy, nbig, y, left, right, wind, nwind;
300         edges=(Edge *)malloc(nvert*sizeof(Edge));
301         if(edges==0){
302         NoSpace:
303                 return 0;
304         }
305         ylist=(Edge **)malloc((b->r.max.y-b->r.min.y)*sizeof(Edge *));
306         if(ylist==0) goto NoSpace;
307         eylist=ylist+(b->r.max.y-b->r.min.y);
308         for(yp=ylist;yp!=eylist;yp++) *yp=0;
309         evert=vert+nvert;
310         for(p=evert-1, q=vert, ep=edges;q!=evert;p=q, q++, ep++){
311                 if(p->y==q->y) continue;
312                 if(p->y<q->y){
313                         p0=*p;
314                         p1=*q;
315                         ep->dwind=1;
316                 }
317                 else{
318                         p0=*q;
319                         p1=*p;
320                         ep->dwind=-1;
321                 }
322                 if(p1.y<=b->r.min.y) continue;
323                 if(p0.y>=b->r.max.y) continue;
324                 ep->p=p0;
325                 if(p1.y>b->r.max.y)
326                         ep->maxy=b->r.max.y;
327                 else
328                         ep->maxy=p1.y;
329                 p10=sub(p1, p0);
330                 if(p10.x>=0){
331                         ep->dx=p10.x/p10.y;
332                         ep->dx1=ep->dx+1;
333                 }
334                 else{
335                         p10.x=-p10.x;
336                         ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
337                         ep->dx1=ep->dx-1;
338                 }
339                 ep->x=0;
340                 ep->num=p10.x%p10.y;
341                 ep->den=p10.y;
342                 if(ep->p.y<b->r.min.y){
343                         dy=b->r.min.y-ep->p.y;
344                         ep->x+=dy*ep->num;
345                         nbig=ep->x/ep->den;
346                         ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
347                         ep->x%=ep->den;
348                         ep->p.y=b->r.min.y;
349                 }
350                 insert(ep, ylist+(ep->p.y-b->r.min.y));
351         }
352         left=0;
353         for(yp=ylist,y=b->r.min.y;yp!=eylist;yp++,y++){
354                 wind=0;
355                 for(ep=*yp;ep;ep=nextep){
356                         nwind=wind+ep->dwind;
357                         if(nwind&w){    /* inside */
358                                 if(!(wind&w)){
359                                         left=ep->p.x;
360                                         if(left<b->r.min.x) left=b->r.min.x;
361                                 }
362                         }
363                         else if(wind&w){
364                                 right=ep->p.x;
365                                 if(right>=b->r.max.x) right=b->r.max.x;
366                                 if(right>left)
367                                         segment(b, Pt(left, y), Pt(right, y), v, f);
368                         }
369                         wind=nwind;
370                         nextep=ep->next;
371                         if(++ep->p.y!=ep->maxy){
372                                 ep->x+=ep->num;
373                                 if(ep->x>=ep->den){
374                                         ep->x-=ep->den;
375                                         ep->p.x+=ep->dx1;
376                                 }
377                                 else
378                                         ep->p.x+=ep->dx;
379                                 insert(ep, yp+1);
380                         }
381                 }
382         }
383         free((char *)edges);
384         free((char *)ylist);
385         return 1;
386 }
387 #endif