]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/demos/nanox/world.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / demos / nanox / world.c
1 /*
2  * Draw a crude map of the world using mini-X graphics on MINIX.
3  * Converted from an Amiga program by Mike Groshart and Bob Dufford.
4  * Author: David I. Bell
5  *
6  * ported to 16 bit systems by Greg Haerr
7  */
8 #include <stdio.h>
9 #include <string.h>
10 #define MWINCLUDECOLORS
11 #include "nano-X.h"
12
13 #if defined(MSDOS) || defined(__ECOS)
14 #include <fcntl.h>
15 #endif
16
17 #if LINUX | DOS_DJGPP
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #endif
23
24 #ifndef O_BINARY
25 #define O_BINARY        0
26 #endif
27
28 #if defined(DOS_DJGPP) || defined(__ECOS)
29 #define MAPFILE "world.map"
30 #else
31 #define MAPFILE "demos/nanox/world.map"         /* was /usr/lib*/
32 #endif
33
34 #define SELECTBUTTON    GR_BUTTON_L
35 #define COORDBUTTON     GR_BUTTON_R
36
37
38 /*
39  * Definitions to use fixed point in place of true floating point.
40  */
41 typedef long    FLOAT;
42
43 #define SCALE   100             /* fixed point scaling factor */
44
45 #define FFMUL(a,b)      (((FLOAT)(a) * (b) + (SCALE / 2)) / SCALE)
46 #define FFDIV(a,b)      (((FLOAT)(a) * SCALE) / (b))
47 #define FIMUL(a,b)      ((FLOAT)(a) * (b))
48 #define FIDIV(a,b)      ((FLOAT)(a) / (b))
49 #define ITOF(a)         ((FLOAT)(a) * SCALE)
50 #define FTOI(a)         (((FLOAT)(a) + (SCALE / 2)) / SCALE)
51
52
53 #define QSPAN   (90L*60*SCALE)  /* equator to pole (90 degrees) */
54 #define HSPAN   (QSPAN*2)       /* pole to pole (180 degrees) */
55 #define WSPAN   (QSPAN*4)       /* around equator (360 degrees) */
56
57 #define ABS(n)  (((n) < 0) ? -(n) : (n))
58
59
60 /*
61  * Structure of a point in the database file.
62  */
63 typedef struct {
64         short   Code;           /* type of point (see code_colors below) */
65         short   Lat;            /* latitude in minutes */
66         short   Lon;            /* longitude in minutes */
67 } MWPACKED DBPOINT;
68
69 #if BIGENDIAN
70 #define SHORT_SWAP(p) (p = ((p & 0xff) << 8) | ((p >> 8) & 0xff))
71 #define DBPOINT_CONVERT(p) (SHORT_SWAP(p->Code),SHORT_SWAP(p->Lat),SHORT_SWAP(p->Lon))
72 #else
73 #define DBPOINT_CONVERT(p)      ((void)p)
74 #endif
75
76 #define POINTSize       sizeof(DBPOINT)
77 #define PCount          128             /* number of points to read at once */
78
79
80 /*
81  * The following variables are the scaling factors to be used when drawing
82  * points.  However, they are larger than the true value by a factor of 60.
83  * This is done because without real floating point, their true values are
84  * too small to be accurate enough.  I cannot just increase the fixed point
85  * precision because that causes overflows.  What a pain!
86  */
87 static  FLOAT           X_Scale;
88 static  FLOAT           Y_Scale;
89
90 /*
91  * Other variables.
92  */
93 static  FLOAT           Latitude, Longitude;    /* current center of view */
94 static  FLOAT           zoom;           /* current zoom scaling factor */
95
96 static  FLOAT           latradius;      /* half of view of latitide */
97 static  FLOAT           longradius;     /* half of view of longitude */
98 static  FLOAT           viewlong;       /* amount of longitide in view */
99 static  FLOAT           viewlat;        /* amount of latitude in view */
100
101 static  GR_SIZE         mapwidth;       /* width of map in pixels */
102 static  GR_SIZE         mapheight;      /* height of map in pixels */
103 static  GR_COORD        mapxorig;       /* one half of map width */
104 static  GR_COORD        mapyorig;       /* one half of map height */
105 static  GR_COORD        selectx;        /* x position of current selection */
106 static  GR_COORD        selecty;        /* y position of current selection */
107 static  GR_COORD        selectptrx;     /* x position of pointer in selection */
108 static  GR_COORD        selectptry;     /* y position of pointer in selection */
109 static  GR_SIZE         selectwidth;    /* width of current selection */
110 static  GR_SIZE         selectheight;   /* height of current selection */
111 static  int             selectmode;     /* selection mode */
112 static  GR_BOOL         selectvisible;  /* TRUE if selection is visible on screen */
113 static  GR_SIZE         selectxscale;   /* x scaling factor for selection rectangle */
114 static  GR_SIZE         selectyscale;   /* y scaling factor for selection rectangle */
115 static  GR_BOOL         coordvisible;   /* TRUE if coordinates are visible on screen */
116 static  GR_BOOL         coordenabled;   /* TRUE if coordinate display is enabled */
117 static  GR_COORD        coordx;         /* x position of coordinates */
118 static  GR_COORD        coordy;         /* y position of coordinates */
119 static  GR_COORD        ptrx;           /* latest x position of pointer */
120 static  GR_COORD        ptry;           /* latest y position of pointer */
121 static  char            coordstring[32];        /* coordinate string */
122
123 static  GR_WINDOW_ID    mainwid;        /* main window id */
124 static  GR_WINDOW_ID    mapwid;         /* window id for map */
125 static  GR_GC_ID        mapgc;          /* GC used for drawing map */
126 static  GR_GC_ID        xorgc;          /* GC used for rubber banding */
127 static  GR_SIZE         COLS, ROWS;
128
129
130 /*
131  * Current selection mode
132  */
133 #define SELECT_NONE     0
134 #define SELECT_SCALE    1
135 #define SELECT_MOVE     2
136
137 /*
138  * Order of color table (indexed by type of point):
139  *      unused
140  *      continents
141  *      countries
142  *      unused
143  *      USA states
144  *      islands
145  *      lakes
146  *      rivers
147  */
148 static  GR_COLOR        code_colors[] = {
149         BLACK, GREEN, RED, BLACK, BROWN, GREEN, BLUE, BLUE
150 };
151
152
153 static  void    load();
154 static  void    setzoom();
155 static  void    checkevent();
156 static  void    doexposure();
157 static  void    dobuttondown();
158 static  void    dobuttonup();
159 static  void    doposition();
160 static  void    dokeydown();
161 static  void    showselection();
162 static  void    showcoords();
163 static  void    mintostr();
164
165
166 #ifdef __ECOS
167 int
168 world_main(int argc, char **argv)
169 #else
170 int
171 main(int argc, char **argv)
172 #endif
173 {
174         GR_SCREEN_INFO  si;
175         GR_WM_PROPERTIES props;
176
177         if (GrOpen() < 0) {
178                 fprintf(stderr, "Cannot open graphics\n");
179                 exit(1);
180         }
181
182         GrReqShmCmds(65536); /* Test by Morten Rolland for shm support */
183
184         GrGetScreenInfo(&si);
185 #ifdef __ECOS
186 /* 240x320 screen*/
187 COLS = si.cols - 10;
188 ROWS = si.rows - 40;
189 #else
190 COLS = si.cols - 40;
191 ROWS = si.rows - 80;
192 #endif
193
194         mainwid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, COLS, ROWS,
195                 0, BLACK, BLACK);
196
197         /* set title */
198         props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS;
199         props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION;
200         props.title = "NanoX World Map";
201         GrSetWMProperties(mainwid, &props);
202
203         mapwidth = COLS - 2;
204         mapheight = ROWS - 2;
205         mapxorig = mapwidth / 2;
206         mapyorig = mapheight / 2;
207         selectxscale = 4;
208         selectyscale = 3;
209         coordx = 0;
210         coordy = ROWS - 1;
211         mapwid = GrNewWindow(mainwid, 1, 1, mapwidth, mapheight,
212 #if 0
213                 1, BLACK, WHITE);
214 #else
215                 1, LTGRAY, BLACK);
216 #endif
217         GrSelectEvents(mainwid, GR_EVENT_MASK_CLOSE_REQ);
218         GrSelectEvents(mapwid, GR_EVENT_MASK_EXPOSURE |
219                 GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_BUTTON_UP |
220                 GR_EVENT_MASK_MOUSE_POSITION | GR_EVENT_MASK_KEY_DOWN);
221
222         GrMapWindow(mainwid);
223         GrMapWindow(mapwid);
224
225         mapgc = GrNewGC();
226         xorgc = GrNewGC();
227         GrSetGCMode(xorgc, GR_MODE_XOR);
228
229         Longitude = ITOF(0);
230         Latitude = ITOF(0);
231         setzoom(ITOF(1));
232
233         while (1)
234                 checkevent();
235 }
236
237
238 static void
239 checkevent()
240 {
241         GR_EVENT        event;
242
243         GrGetNextEvent(&event);
244         switch (event.type) {
245                 case GR_EVENT_TYPE_EXPOSURE:
246                         doexposure(&event.exposure);
247                         break;
248                 case GR_EVENT_TYPE_BUTTON_DOWN:
249                         dobuttondown(&event.button);
250                         break;
251                 case GR_EVENT_TYPE_BUTTON_UP:
252                         dobuttonup(&event.button);
253                         break;
254                 case GR_EVENT_TYPE_MOUSE_POSITION:
255                         doposition(&event.mouse);
256                         break;
257                 case GR_EVENT_TYPE_KEY_DOWN:
258                         dokeydown(&event.keystroke);
259                         break;
260                 case GR_EVENT_TYPE_CLOSE_REQ:
261                         GrClose();
262                         exit(0);
263         }
264 }
265
266
267 static void
268 doexposure(ep)
269         GR_EVENT_EXPOSURE       *ep;
270 {
271         if (ep->wid != mapwid)
272                 return;
273
274         /* removed: helps with blink with nanowm*/
275         /*GrClearWindow(mapwid, GR_FALSE);*/
276         selectvisible = GR_FALSE;
277         coordvisible = GR_FALSE;
278         load(MAPFILE);
279         showselection(GR_TRUE);
280         showcoords(GR_TRUE);
281 }
282
283
284 static void
285 dobuttondown(bp)
286         GR_EVENT_BUTTON *bp;
287 {
288         if (bp->wid != mapwid)
289                 return;
290
291         if (bp->changebuttons & SELECTBUTTON) {
292                 showselection(GR_FALSE);
293                 selectx = bp->x;
294                 selecty = bp->y;
295                 selectptrx = bp->x;
296                 selectptry = bp->y;
297                 selectwidth = 0;
298                 selectheight = 0;
299                 selectmode = SELECT_SCALE;
300                 showselection(GR_TRUE);
301         }
302
303         if (bp->changebuttons & COORDBUTTON) {
304                 showcoords(GR_FALSE);
305                 ptrx = bp->x;
306                 ptry = bp->y;
307                 coordenabled = GR_TRUE;
308                 showcoords(GR_TRUE);
309         }
310 }
311
312
313 static void
314 dobuttonup(bp)
315         GR_EVENT_BUTTON *bp;
316 {
317         if (bp->wid != mapwid)
318                 return;
319
320         if (bp->changebuttons & COORDBUTTON) {
321                 showcoords(GR_FALSE);
322                 coordenabled = GR_FALSE;
323         }
324
325         if (bp->changebuttons & SELECTBUTTON) {
326                 showselection(GR_FALSE);
327                 if (selectmode == SELECT_NONE)
328                         return;
329                 selectmode = SELECT_NONE;
330                 if (selectwidth <= 0)
331                         return;
332                 Longitude +=
333                         FIDIV(FIMUL(viewlong, selectx - mapxorig), mapwidth);
334                 Latitude -=
335                         FIDIV(FIMUL(viewlat, selecty - mapyorig), mapheight);
336                 setzoom(FIDIV(FIMUL(zoom, mapwidth), selectwidth));
337                 GrClearWindow(mapwid, GR_TRUE);
338         }
339 }
340
341
342 static void
343 doposition(mp)
344         GR_EVENT_MOUSE  *mp;
345 {
346         GR_SIZE temp;
347
348         if (mp->wid != mapwid)
349                 return;
350
351         if (coordenabled) {
352                 showcoords(GR_FALSE);
353                 ptrx = mp->x;
354                 ptry = mp->y;
355                 showcoords(GR_TRUE);
356         }
357
358         showselection(GR_FALSE);
359         switch (selectmode) {
360                 case SELECT_SCALE:
361                         selectwidth = ABS(mp->x - selectx) * 2 + 1;
362                         selectheight = ABS(mp->y - selecty) * 2 + 1;
363                         temp = ((long) selectwidth) * selectyscale
364                                 / selectxscale;
365                         if (selectheight < temp)
366                                 selectheight = temp;
367                         temp = ((long) selectheight) * selectxscale
368                                 / selectyscale;
369                         if (selectwidth < temp)
370                                 selectwidth = temp;
371                         break;
372
373                 case SELECT_MOVE:
374                         selectx += (mp->x - selectptrx);
375                         selecty += (mp->y - selectptry);
376                         break;
377         }
378
379         selectptrx = mp->x;
380         selectptry = mp->y;
381         showselection(GR_TRUE);
382 }
383
384
385 static void
386 dokeydown(kp)
387         GR_EVENT_KEYSTROKE      *kp;
388 {
389         if (kp->wid != mapwid)
390                 return;
391
392         if (selectmode != SELECT_NONE) {
393                 switch (kp->ch) {
394                         case 's':       /* scale selection */
395                                 selectmode = SELECT_SCALE;
396                                 break;
397
398                         case 'm':       /* move selection */
399                                 selectmode = SELECT_MOVE;
400                                 break;
401
402                         case '\033':    /* cancel selection */
403                                 showselection(GR_FALSE);
404                                 selectmode = SELECT_NONE;
405                                 break;
406                 }
407                 return;
408         }
409
410         switch (kp->ch) {
411                 case 'q':               /* quit */
412                 case 'Q':
413                         GrClose();
414                         exit(0);
415
416                 case 't':               /* redraw total map */
417                         Longitude = ITOF(0);
418                         Latitude = ITOF(0);
419                         setzoom(ITOF(1));
420                         GrClearWindow(mapwid, GR_TRUE);
421         }
422 }
423
424
425 /*
426  * Draw or erase the current selection if any is defined.
427  * The selection is a rectangle centered on a specified point, and with a
428  * specified width and height.  Drawing and erasing the selection are the
429  * same drawing operation because of the XOR operation.
430  */
431 static void
432 showselection(show)
433         GR_BOOL show;           /* TRUE if show the selection */
434 {
435         if ((show == 0) == (selectvisible == 0))
436                 return;
437         if (selectmode == SELECT_NONE)
438                 return;
439         GrRect(mapwid, xorgc, selectx - selectwidth / 2,
440                 selecty - selectheight / 2, selectwidth, selectheight);
441         selectvisible = show;
442 }
443
444
445 /*
446  * Draw or erase the coordinate string of the current pointer position.
447  * Both of these are the same operation because of the XOR operation.
448  */
449 static void
450 showcoords(show)
451         GR_BOOL show;           /* TRUE if show the coordinates */
452 {
453         long    curlong;
454         long    curlat;
455         FLOAT   ptrlat;
456         FLOAT   ptrlong;
457
458         if (((show == 0) == (coordvisible == 0)) || !coordenabled)
459                 return;
460
461         if (show) {
462                 ptrlat = FIDIV(FIMUL(viewlat, ptry), mapheight - 1);
463                 ptrlong = FIDIV(FIMUL(viewlong, ptrx), mapwidth - 1);
464
465                 curlat = FTOI(Latitude + latradius - ptrlat);
466                 curlong = FTOI(Longitude - longradius + ptrlong);
467
468                 if (curlong > 180*60)
469                         curlong -= 360*60;
470                 if (curlong < -180*60)
471                         curlong += 360*60;
472
473                 mintostr(coordstring, curlong);
474                 strcat(coordstring, "  ");
475                 mintostr(coordstring + strlen(coordstring), curlat);
476         }
477
478         GrText(mapwid, xorgc, coordx, coordy, coordstring, -1, GR_TFBOTTOM);
479         coordvisible = show;
480 }
481
482
483 /*
484  * Convert minutes to a string of the form "ddd'mm" and store it
485  * into the indicated buffer.
486  */
487 static void
488 mintostr(buf, minutes)
489         char    *buf;
490         long    minutes;
491 {
492         if (minutes < 0) {
493                 minutes = -minutes;
494                 *buf++ = '-';
495         }
496         sprintf(buf, "%ld'%02ld", (long)(minutes / 60), (long)(minutes % 60));
497 }
498
499
500 #if 0
501 /*
502  * Convert "ddd'mm" to mins
503  */
504 static long
505 degtomin(s)
506         char    *s;
507 {
508         int     deg, minutes;
509         char    str[10],*strchr(),*cp;
510
511         strcpy(str,s);
512         if (cp = strchr(str,'\047')) {
513                 *cp = '\0';
514                 minutes = atoi(++cp);
515         } else
516                 minutes = 0;
517         if ((deg = atoi(str)) < 0)
518                 minutes = -minutes;
519         return(deg * 60 + minutes);
520 }
521 #endif
522
523
524 /*
525  * Set the scale factors for the given zoom factor.
526  * The factors 3 and 4 are here to compensate for the screen aspect ratio.
527  */
528 static void
529 setzoom(newzoom)
530         FLOAT   newzoom;
531 {
532         zoom = newzoom;
533
534         Y_Scale = FIDIV(FIMUL(zoom, mapheight * 3), 180 * 4);
535         X_Scale = FIDIV(FIMUL(zoom, mapwidth), 360);
536
537         viewlong = FFDIV(WSPAN, zoom);
538         viewlat = FFDIV(HSPAN * 4 / 3, zoom);
539         longradius = FIDIV(viewlong, 2);
540         latradius = FIDIV(viewlat, 2);
541 }
542
543
544 /*
545  * Read the database file and draw the world.
546  */
547 static void
548 load(fn)
549         char    *fn;
550 {
551         register DBPOINT        *pp;
552         DBPOINT         *pend;
553         FLOAT           x, y, LonPrv, LatPrv;
554         long            oldlong = 0L;
555         GR_COORD        xnew, ynew;
556         GR_COORD        xold = 0, yold = 0;
557         GR_BOOL         is_out;
558         GR_BOOL         was_out;
559         GR_BOOL         newseg = GR_FALSE;
560         GR_COLOR        oldcolor;
561         GR_COLOR        newcolor;
562         int             n;
563         int             fh;
564         DBPOINT         p[PCount];
565
566         LonPrv = ITOF(0);
567         LatPrv = ITOF(0);
568         oldcolor = -1;
569         is_out = GR_FALSE;
570         was_out = GR_FALSE;
571
572         fh = open(fn, O_BINARY | O_RDONLY);
573         if (fh < 0) {
574                 GrClose();
575                 fprintf(stderr, "Cannot open %s\n", fn);
576                 exit(1);
577         }
578
579         while ((n = read(fh, p, PCount * POINTSize)) > 0) {
580                 for (pp = p,pend = p + n/POINTSize; pp < pend; pp++)
581                 {
582                         DBPOINT_CONVERT(pp);
583                         /* do displacement */
584                         x = ITOF(pp->Lon) - Longitude;
585                         y = ITOF(pp->Lat) - Latitude;
586
587                         /* wrap around for East-West */
588                         if (x < -HSPAN)
589                                 x += WSPAN;
590                         if (x > HSPAN)
591                                 x -= WSPAN;
592
593                         if (pp->Code > 5) {
594                                 newcolor = code_colors[pp->Code / 1000];
595                                 if (newcolor != oldcolor) {
596                                         oldcolor = newcolor;
597                                         GrSetGCForeground(mapgc, oldcolor);
598                                 }
599                                 newseg = GR_TRUE;
600                         }
601
602                         if (oldcolor == BLACK)
603                                 goto go_on;
604
605                         /* ignore points outside magnified area */
606                         if ((x < -longradius || x > longradius ||
607                                 y < -latradius || y > latradius))
608                         {
609                                 is_out = 1;
610                                 if (was_out) {          /* out to out */
611                                         LonPrv = x;
612                                         LatPrv = y;
613                                         goto go_on;
614                                 }
615
616                                 /* in to out */
617                                 xold = mapxorig + FTOI(FFMUL(LonPrv, X_Scale)) / 60;
618                                 yold = mapyorig - FTOI(FFMUL(LatPrv, Y_Scale)) / 60;
619                         } else {                        /* out to in */
620                                 is_out = 0;
621                                 if (was_out) {
622                                         xold = mapxorig +
623                                                 FTOI(FFMUL(LonPrv, X_Scale)) / 60;
624                                         yold = mapyorig -
625                                                 FTOI(FFMUL(LatPrv, Y_Scale)) / 60;
626                                 }
627                                 /* in to in */
628                         }
629                         LonPrv = x;
630                         LatPrv = y;
631
632                         /* scale points w/in area to interlace screen */
633                         xnew = mapxorig + FTOI(FFMUL(x, X_Scale)) / 60;
634                         ynew = mapyorig - FTOI(FFMUL(y, Y_Scale)) / 60;
635
636                         /* if new segment, move to place */
637                         if (newseg || ABS(oldlong - pp->Lon) > 180*60) {
638                                 xold = xnew;
639                                 yold = ynew;
640                         }
641                         oldlong = pp->Lon;
642
643                         GrLine(mapwid, mapgc, xold, yold, xnew, ynew);
644                         xold = xnew;
645                         yold = ynew;
646 go_on:
647                         was_out = is_out;
648                         newseg = GR_FALSE;
649                 }
650         }
651         close(fh);
652 }
653
654 /* END CODE */