]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/demos/nxroach/nxroach.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / demos / nxroach / nxroach.c
1 /*
2     Xroach - A game of skill.  Try to find the roaches under your windows.
3     Ported to Nano-X by Greg Haerr
4     
5     Copyright 1991 by J.T. Anderson
6     jta@locus.com
7     
8     This program may be freely distributed provided that all
9     copyright notices are retained.
10
11     Dedicated to Greg McFarlane.   (gregm@otc.otca.oz.au)
12 */
13 char Copyright[] = "nxroach\nCopyright 1991 J.T. Anderson";
14
15 #include <stdio.h>
16 #include <math.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <time.h>
20 #define MWINCLUDECOLORS
21 #include "nano-X.h"
22
23 #define None    0
24 #define Pixmap  GR_WINDOW_ID
25 #include "roachmap.h"
26
27 #define SCAMPER_EVENT   99
28
29 typedef struct Roach {
30     RoachMap *rp;
31     int index;
32     float x;
33     float y;
34     int intX;
35     int intY;
36     int hidden;
37     int turnLeft;
38     int steps;
39 } Roach;
40
41 GR_COORD display_width, display_height;
42 GR_GC_ID gc;
43 GR_COLOR roachColor = BLACK;
44 GR_REGION_ID rootVisible = 0;
45 GR_BOOL done = GR_FALSE;
46 GR_BOOL eventBlock = GR_FALSE;
47
48 Roach *roaches;
49 int maxRoaches = 10;
50 int curRoaches = 0;
51 float roachSpeed = 20.0;
52
53 void Usage(void);
54 void SigHandler(int sig);
55 void AddRoach(void);
56 void MoveRoach(int Rx);
57 void DrawRoaches(void);
58 void CoverRoot(void);
59 int CalcRootVisible(void);
60 int MarkHiddenRoaches(void);
61
62 int
63 main(int ac, char **av)
64 {
65     int ax;
66     char *arg;
67     RoachMap *rp;
68     int rx;
69     float angle;
70     GR_EVENT ev;
71     int nVis;
72     int needCalc;
73     GR_SCREEN_INFO sinfo;
74     
75     /*
76        Process command line options.
77     */
78     for (ax=1; ax<ac; ax++) {
79         arg = av[ax];
80         if (strcmp(arg, "-rc") == 0) {
81             roachColor = atoi(av[++ax]);
82         }
83         else if (strcmp(arg, "-speed") == 0) {
84             roachSpeed = atof(av[++ax]);
85         }
86         else if (strcmp(arg, "-roaches") == 0) {
87             maxRoaches = strtol(av[++ax], (char **)NULL, 0);
88         }
89         else {
90             Usage();
91         }
92     }
93
94     srand((int)time((long *)NULL));
95     
96     /*
97        Catch some signals so we can erase any visible roaches.
98     */
99     signal(SIGKILL, SigHandler);
100     signal(SIGINT, SigHandler);
101     signal(SIGTERM, SigHandler);
102     signal(SIGHUP, SigHandler);
103
104     if (GrOpen() < 0) {
105         fprintf(stderr, "can't open graphics\n");
106         exit(1);
107     }
108
109     GrGetScreenInfo(&sinfo);
110     display_width = sinfo.cols;
111     display_height = sinfo.rows;
112     
113     /*
114        Create roach pixmaps at several orientations.
115     */
116     for (ax=0; ax<360; ax+=ROACH_ANGLE) {
117         rx = ax / ROACH_ANGLE;
118         angle = rx * 0.261799387799;
119         rp = &roachPix[rx];
120         rp->pixmap = GrNewPixmapFromData(rp->width, rp->height, WHITE, BLACK,
121                 rp->roachBits, GR_BMDATA_BYTEREVERSE|GR_BMDATA_BYTESWAP);
122         rp->sine = sin(angle);
123         rp->cosine = cos(angle);
124     }
125
126     roaches = (Roach *)malloc(sizeof(Roach) * maxRoaches);
127
128     gc = GrNewGC();
129     
130     while (curRoaches < maxRoaches)
131         AddRoach();
132     
133     GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CHLD_UPDATE);
134     
135     needCalc = 1;
136     while (!done) {
137         if (GrPeekEvent(&ev))
138             GrGetNextEvent(&ev);
139         else {
140             if (needCalc) {
141                 needCalc = CalcRootVisible();
142             }
143             nVis = MarkHiddenRoaches();
144             if (nVis) {
145                 ev.type = SCAMPER_EVENT;
146             }
147             else {
148                 DrawRoaches();
149                 eventBlock = GR_TRUE;
150                 GrGetNextEvent(&ev);
151                 eventBlock = GR_FALSE;
152             }
153         }
154         
155         switch (ev.type) {
156             case SCAMPER_EVENT:
157                 for (rx=0; rx<curRoaches; rx++) {
158                     if (!roaches[rx].hidden)
159                         MoveRoach(rx);
160                 }
161                 DrawRoaches();
162                 GrDelay(100);
163                 break;
164                 
165             case GR_EVENT_TYPE_EXPOSURE:
166             case GR_EVENT_TYPE_CHLD_UPDATE:
167                 needCalc = 1;
168                 break;
169                 
170         }
171     }
172     
173     CoverRoot();
174     GrClose();
175     return 0;
176 }
177
178 void
179 Usage(void)
180 {
181     fprintf(stderr, "Usage: nxroach [options]\n\n");
182     fprintf(stderr, "Options:\n");
183     fprintf(stderr, "       -rc      roachcolor\n");
184     fprintf(stderr, "       -roaches numroaches\n");
185     fprintf(stderr, "       -speed   roachspeed\n");
186     
187     exit(1);
188 }
189
190 void
191 SigHandler(int sig)
192 {
193     /*
194        If we are blocked, no roaches are visible and we can just bail
195        out.  If we are not blocked, then let the main procedure clean
196        up the root window.
197     */
198     if (eventBlock) {
199         GrClose();
200         exit(0);
201     }
202     else {
203         done = GR_TRUE;
204     }
205 }
206
207 /*
208    Generate random integer between 0 and maxVal-1.
209 */
210 int
211 RandInt(int maxVal)
212 {
213         return rand() % maxVal;
214 }
215
216 /*
217    Check for roach completely in specified rectangle.
218 */
219 int
220 RoachInRect(Roach *roach, int rx, int ry, int x, int y,
221         unsigned int width, unsigned int height)
222 {
223     if (rx < x) return 0;
224     if ((rx + roach->rp->width) > (x + width)) return 0;
225     if (ry < y) return 0;
226     if ((ry + roach->rp->height) > (y + height)) return 0;
227     
228     return 1;
229 }
230
231 /*
232    Check for roach overlapping specified rectangle.
233 */
234 int
235 RoachOverRect(Roach *roach, int rx, int ry, int x, int y,
236         unsigned int width, unsigned int height)
237 {
238     if (rx >= (x + width)) return 0;
239     if ((rx + roach->rp->width) <= x) return 0;
240     if (ry >= (y + height)) return 0;
241     if ((ry + roach->rp->height) <= y) return 0;
242     
243     return 1;
244 }
245
246 /*
247    Give birth to a roach.
248 */
249 void
250 AddRoach(void)
251 {
252     Roach *r;
253     
254     if (curRoaches < maxRoaches) {
255         r = &roaches[curRoaches++];
256         r->index = RandInt(ROACH_HEADINGS);
257         r->rp = &roachPix[r->index];
258         r->x = RandInt(display_width - r->rp->width);
259         r->y = RandInt(display_height - r->rp->height);
260         r->intX = -1;
261         r->intY = -1;
262         r->hidden = 0;
263         r->steps = RandInt(200);
264         r->turnLeft = RandInt(100) >= 50;
265     }
266 }
267
268 /*
269    Turn a roach.
270 */
271 void
272 TurnRoach(Roach *roach)
273 {
274     if (roach->index != (roach->rp - roachPix)) return;
275
276     if (roach->turnLeft) {
277         roach->index += (RandInt(30) / 10) + 1;
278         if (roach->index >= ROACH_HEADINGS)
279             roach->index -= ROACH_HEADINGS;
280     }
281     else {
282         roach->index -= (RandInt(30) / 10) + 1;
283         if (roach->index < 0)
284             roach->index += ROACH_HEADINGS;
285     }
286 }
287
288 /*
289    Move a roach.
290 */
291 void
292 MoveRoach(int rx)
293 {
294     Roach *roach;
295     Roach *r2;
296     float newX;
297     float newY;
298     int ii;
299     
300     roach = &roaches[rx];
301     newX = roach->x + (roachSpeed * roach->rp->cosine);
302     newY = roach->y - (roachSpeed * roach->rp->sine);
303     
304     if (RoachInRect(roach, (int)newX, (int)newY, 
305                             0, 0, display_width, display_height)) {
306         
307         roach->x = newX;
308         roach->y = newY;
309
310         if (roach->steps-- <= 0) {
311             TurnRoach(roach);
312             roach->steps = RandInt(200);
313         }
314
315         for (ii=rx+1; ii<curRoaches; ii++) {
316             r2 = &roaches[ii];
317             if (RoachOverRect(roach, (int)newX, (int)newY,
318                 r2->intX, r2->intY, r2->rp->width, r2->rp->height)) {
319         
320                 TurnRoach(roach);
321             }
322         }
323     }
324     else {
325         TurnRoach(roach);
326     }
327 }
328     
329 /*
330    Draw all roaches.
331 */
332 void
333 DrawRoaches(void)
334 {
335     Roach *roach;
336     int rx;
337     
338     for (rx=0; rx<curRoaches; rx++) {
339         roach = &roaches[rx];
340         
341         if (roach->intX >= 0) {
342             GrClearArea(GR_ROOT_WINDOW_ID, roach->intX, roach->intY,
343                 roach->rp->width, roach->rp->height, GR_FALSE);
344         }
345     }
346     
347     for (rx=0; rx<curRoaches; rx++) {
348         roach = &roaches[rx];
349         
350         if (!roach->hidden) {
351             int size = roach->rp->width * roach->rp->height;
352             GR_PIXELVAL roachbuf[size];
353             GR_PIXELVAL screenbuf[size];
354             int i;
355
356             roach->intX = roach->x;
357             roach->intY = roach->y;
358             roach->rp = &roachPix[roach->index];
359
360             /*
361             //XSetForeground(display, gc, AllocNamedColor(roachColor, black));
362             //XSetFillStyle(display, gc, FillStippled);
363             //XSetStipple(display, gc, roach->rp->pixmap);
364             //XSetTSOrigin(display, gc, roach->intX, roach->intY);
365             //XFillRectangle(display, rootWin, gc,
366                 //roach->intX, roach->intY, roach->rp->width, roach->rp->height);
367             */
368
369             /* read roach bitmap*/
370             GrReadArea(roach->rp->pixmap, 0, 0,
371                 roach->rp->width, roach->rp->height, roachbuf);
372
373             /* read root window*/
374             GrReadArea(GR_ROOT_WINDOW_ID, roach->intX, roach->intY,
375                 roach->rp->width, roach->rp->height, screenbuf);
376
377             /* convert fg roach bitmap bits to roach color on root window bits*/
378             for (i=0; i<size; ++i)
379                     if (roachbuf[i] != BLACK)
380                             screenbuf[i] = roachColor;
381
382             /* write root window*/
383             GrArea(GR_ROOT_WINDOW_ID, gc, roach->intX, roach->intY,
384                 roach->rp->width, roach->rp->height, screenbuf, MWPF_PIXELVAL);
385         }
386         else {
387             roach->intX = -1;
388         }
389     }
390     GrFlush();
391 }
392
393 /*
394    Cover root window to erase roaches.
395 */
396 void
397 CoverRoot(void)
398 {
399     GR_WINDOW_ID roachWin;
400     
401     roachWin = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, display_width, display_height,
402                     0, CYAN, BLACK);
403     GrLowerWindow(roachWin);
404     GrMapWindow(roachWin);
405     GrFlush();
406 }    
407
408 /*
409    Calculate Visible region of root window.
410 */
411 int
412 CalcRootVisible(void)
413 {
414     GR_REGION_ID covered;
415     GR_REGION_ID visible;
416     GR_WINDOW_ID parent;
417     GR_WINDOW_ID *children;
418     GR_COUNT nChildren;
419     GR_COUNT wx;
420     GR_RECT rect;
421     GR_WINDOW_INFO info;
422     
423     /*
424        Get children of root.
425     */
426     GrQueryTree(GR_ROOT_WINDOW_ID, &parent, &children, &nChildren);
427     
428     /*
429        For each mapped child, add the window rectangle to the covered
430        region.
431     */
432     covered = GrNewRegion();
433     for (wx=0; wx<nChildren; wx++) {
434         GrGetWindowInfo(children[wx], &info);
435         if (info.unmapcount == 0) {
436             rect.x = info.x;
437             rect.y = info.y;
438             rect.width = info.width;
439             rect.height = info.height;
440             GrUnionRectWithRegion(covered, &rect);
441         }
442     }
443     free(children);
444
445     /*
446        Subtract the covered region from the root window region.
447     */
448     visible = GrNewRegion();
449     rect.x = 0;
450     rect.y = 0;
451     rect.width = display_width;
452     rect.height = display_height;
453     GrUnionRectWithRegion(visible, &rect);
454     GrSubtractRegion(visible, visible, covered);
455     GrDestroyRegion(covered);
456     
457     /*
458        Save visible region globally.
459     */
460     if (rootVisible)
461         GrDestroyRegion(rootVisible);
462     rootVisible = visible;
463
464     /*
465        Mark all roaches visible.
466     */
467     for (wx=0; wx<curRoaches; wx++) 
468         roaches[wx].hidden = 0;
469
470     return 0;
471 }
472
473 /*
474    Mark hidden roaches.
475 */
476 int
477 MarkHiddenRoaches(void)
478 {
479     int rx;
480     Roach *r;
481     int nVisible;
482     
483     nVisible = 0;
484     for (rx=0; rx<curRoaches; rx++) {
485         r = &roaches[rx];
486         
487         if (!r->hidden) {
488             if (r->intX > 0 && GrRectInRegion(rootVisible, r->intX, r->intY,
489                             r->rp->width, r->rp->height) == MWRECT_OUT) {
490                 r->hidden = 1;
491             }
492             else {
493                 nVisible++;
494             }
495         }
496     }
497     
498     return nVisible;
499 }