/* * Copyright (c) 1993, 1999 Alexandre Wennmacher (wennmach@geo.Uni-Koeln.DE) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Alexandre Wennmacher. * 4. The name of Alexandre Wennmacher may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY ALEXANDRE WENNMACHER AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL ALEXANDRE WENNMACHER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "const.h" #include "Sphere.h" #include "SphereDim.h" #include "SphereData.h" #include "color.h" #include "level.h" /* Solaris hack */ #ifndef MAP_FILE #define MAP_FILE 0x0 #endif #define SIZE 150 #define MIN_SIZE 50 #define X_POS +0 #define Y_POS +0 #define BORDER 5 #define SLEEP 120 #define MIN(x,y) (((x)<(y))?(x):(y)) char *MainTitle[] = {"Hello, world"}; char *IconTitle[] = {"xworld"}; XWMHints xwmh = { (InputHint|StateHint), False, NormalState, 0, 0, 0, 0, 0, 0, }; int GetSpherePoint(Sphere *, SPHERETYPE *, double, double); long int JulianDate(int, int, int); double EqunofTime(double, double *, double *); char *getmyabspath(char *, char *); int usage(void); int main(int, char **); int usage() { fprintf(stderr, "usage: xworld [-geometry [=]widthxheight+x+y]" " [-display dpy]\n"); exit(1); } static char * alloc_image(XImage *image) { char *Map; int ix, iy, j; Map = (char *)malloc(image->height * image->bytes_per_line); if (Map == NULL) { fprintf(stderr, "xworld: not enough memory\n"); exit(1); } image->data = Map; for(j = 0, ix = 0; ix < image->width; ix++) for (iy = 0; iy < image->height; iy++) XPutPixel(image, ix, iy, j++ % NCOLORS); return Map; } int main(int argc, char **argv) { Display *display; char *displayname = NULL; Window win; GC gc; Visual *visual; unsigned int class; unsigned int depth; int screen; XEvent event; XConfigureEvent *ConfigureEvent; Mask InputSelectMask; XSizeHints xsh; XSetWindowAttributes xswa; unsigned int xswamask; XTextProperty xtptitle; XColor xcolor[NCOLORS]; Colormap cmap; int format; int bitmap_pad; XImage *image; unsigned long foreground, background; int mask; int x_return, y_return; unsigned int width_return, height_return; unsigned int size, old_size; unsigned int x_pos, y_pos; unsigned int border = 1; int n; int r1, r2; int jr, m, d, hr, min, sec; double juldat, sunra, sundec; double daypart, phi; struct tm *gmt; time_t clock; int i, j, ix, iy; double tTheta, tPhi; double x, y, z; double x2, y2, z2; double xp, yp, zp; double cost, sint; double cosp, sinp; double m11, m12, m13, m21, m22, m23, m32, m33; SPHERETYPE Dummy = 1; SPHERETYPE Value; Sphere Earth; char *Map; char *progname; FILE *f_o; register_t *addr; const size_t len = NPOINTS*sizeof(register_t); off_t offset; char **argp; char *geometry; int opt_geometry = 0; int opt_display = 0; /* * Check if xworld is installed correctly. * Determine the absolute path with which xworld was invoked, * open and mmap the data portion, appended to the executable. */ progname = getmyabspath(argv[0], getenv("PATH")); if (progname == NULL) { fprintf(stderr, "xworld: could not determine my absolute filename.\n" "Abort.\n"); exit(1); } f_o = fopen(progname, "r"); if (f_o == NULL) { perror("xworld: could not open myself"); exit(1); } offset = lseek(fileno(f_o), (off_t)0, SEEK_END) - len; addr = (register_t *)mmap(NULL, len, PROT_READ, MAP_FILE | MAP_SHARED, fileno(f_o), offset); if (addr == (register_t *)MAP_FAILED) { perror("xworld: could not mmap"); exit(1); } /* Next, parse command line */ argp = argv; while (*++argp != NULL) { if (strcmp(*argp, "-geometry") == 0) { geometry = *++argp; if (geometry == NULL) usage(); mask = XParseGeometry(geometry, &x_return, &y_return, &width_return, &height_return); if (mask == 0) usage(); if (mask & WidthValue && mask & HeightValue) if (width_return != height_return) { fprintf(stderr, "xworld: error: width must equal height!\n"); exit(1); } opt_geometry++; break; } if (strcmp(*argp, "-display") == 0) { displayname = *++argp; if (displayname == NULL) usage(); opt_display++; break; } usage(); } /* Open display */ if ((display = XOpenDisplay(displayname)) == NULL) { fprintf(stderr, "xworld: can't open display %s\n", XDisplayName(displayname)); exit(1); } screen = DefaultScreen(display); depth = DefaultDepth(display, screen); if (depth == 1) { fprintf(stderr, "xworld: Sorry, I can't yet work with a display of" " depth 1\n"); exit(1); } else { format = ZPixmap; bitmap_pad = 8; if (depth > 8) bitmap_pad = 32; } visual = DefaultVisual(display, screen); /* Set default values */ size = SIZE; x_pos = X_POS; y_pos = Y_POS; if (opt_geometry > 0) { if (mask & WidthValue) size = width_return; if (mask & HeightValue) size = height_return; if (size < MIN_SIZE) { fprintf(stderr, "xworld: warning: using minumum size of %d in" " lieu of user supplied value.\n", MIN_SIZE); size = MIN_SIZE; } if (mask & XValue) { if (mask & XNegative) x_pos = DisplayWidth(display, screen) - size + x_return; else x_pos = x_return; } if (mask & YValue) { if (mask & YNegative) y_pos = DisplayHeight(display, screen) - size + y_return; else y_pos = y_return; } } old_size = size; n = size - 2*BORDER; r1 = n/2; r2 = size/2; foreground = WhitePixel(display, screen); background = BlackPixel(display, screen); image = XCreateImage(display, visual, depth, format, 0, 0, size, size, bitmap_pad, 0); if (image == 0) { fprintf(stderr, "xworld: can't create XImage\n"); exit(1); } xswa.event_mask = ExposureMask | StructureNotifyMask; xswa.background_pixel = BlackPixel(display, screen); xswamask = CWEventMask | CWBackPixel; class = InputOutput; win = XCreateWindow(display, RootWindow(display, screen), x_pos, y_pos, size, size, border, depth, class, visual, xswamask, &xswa); if (XStringListToTextProperty(MainTitle, 1, &xtptitle)) XSetWMName(display, win, &xtptitle); if (XStringListToTextProperty(IconTitle, 1, &xtptitle)) XSetWMIconName(display, win, &xtptitle); xsh.flags = USPosition | USSize | PPosition | PSize | PMinSize | PAspect; xsh.x = x_pos; xsh.y = y_pos; xsh.min_width = MIN_SIZE; xsh.base_width = size; xsh.min_height = MIN_SIZE; xsh.base_height = size; xsh.min_aspect.x = 1; xsh.min_aspect.y = 1; xsh.max_aspect.x = 1; xsh.max_aspect.y = 1; XSetWMHints(display, win, &xwmh); XSetWMNormalHints(display, win, &xsh); /* Allocate colors */ cmap = DefaultColormap(display, screen); for (i = 0; i < NCOLORS; i++) { xcolor[i].red = color[i].red; xcolor[i].green = color[i].green; xcolor[i].blue = color[i].blue; if (XAllocColor(display, cmap, &xcolor[i]) == 0) { fprintf(stderr, "xworld: can't allocate colors\n"); #if 0 exit(-1); #endif } } /* * generate startup image */ Map = alloc_image(image); gc = XCreateGC(display, win, 0, 0); InputSelectMask = ExposureMask | StructureNotifyMask; XSelectInput(display, win, InputSelectMask); XPutImage(display, win, gc, image, 0, 0, 0, 0, size, size); XMapWindow(display, win); Earth.SphereBuffer = addr; Earth.CoLatitude = CoLatitude; Earth.PointSeparation = PointSeparation; Earth.FirstPointOfLatitude = FirstPointOfLatitude; Earth.PointsPerLatitude = PointsPerLatitude; Earth.DeltaLatitude = PI/NINTERVALS; Earth.LastPoint = Earth.FirstPointOfLatitude[NINTERVALS]; Earth.Dummy = Dummy; /* * begin of main loop -- xworld will run until the process is killed */ for ( ; ; ) { /* * read the clock */ clock = time((time_t *)NULL); if (clock == (time_t)-1) { fprintf(stderr, "xworld: can't read clock\n"); exit(1); } /* * deal with gm time */ gmt = gmtime(&clock); jr = gmt->tm_year + 1900; m = gmt->tm_mon + 1; d = gmt->tm_mday; hr = gmt->tm_hour; min = gmt->tm_min; sec = gmt->tm_sec; /* * do some basic astronomy */ juldat = (double)JulianDate(jr, m, d) - 0.5; daypart = (sec + 60*(min + 60*hr))/86400.0; juldat += daypart; phi = daypart*TWO_PI + EqunofTime(juldat, &sunra, &sundec); sint = sin(sundec); cost = cos(sundec); sinp = sin(PI - phi); cosp = cos(PI - phi); m11 = -sinp; m12 = -cosp*sint; m13 = cosp*cost; m21 = cosp; m22 = -sinp*sint; m23 = sinp*cost; /* m31 = 0.0; therfore we omit it here */ m32 = cost; m33 = sint; j = -1; for (iy = 0; iy < size; iy++) { y = (double)(r2 - iy)/r1; y2 = y*y; for (ix = 0; ix < size; ix++) { j++; x = (double)(ix - r2)/r1; x2 = x*x; z2 = (double)1.0 - (x2 + y2); if (z2 >= (double)0.0) { z = sqrt(z2); xp = m11*x + m12*y + m13*z; yp = m21*x + m22*y + m23*z; zp = m32*y + m33*z; tTheta = acos(zp); tPhi = atan2(yp, xp); i = GetSpherePoint(&Earth, &Value, tTheta, tPhi); /* * Map elevations to colors */ if (i != SOK) { XPutPixel(image, ix, iy, xcolor[BLACK].pixel); continue; } if (Value > level[NLEVELS - 1]) { XPutPixel(image, ix, iy, xcolor[HIGH].pixel); continue; } for (i = 0; i <= NLEVELS - 1; i++) { if (Value <= level[i]) { XPutPixel(image, ix, iy, xcolor[i].pixel); break; } } } else XPutPixel(image, ix, iy, xcolor[BLACK].pixel); } } XPutImage(display, win, gc, image, 0, 0, 0, 0, size, size); for (i = 0; i < SLEEP; i++) { sleep(1); if (XCheckMaskEvent(display, InputSelectMask, &event)) { if (event.type == Expose && event.xexpose.count == 0) { while (XCheckTypedEvent(display, Expose, &event)); XPutImage(display, win, gc, image, 0, 0, 0, 0, size, size); } if (event.type == ConfigureNotify) { while (XCheckTypedEvent(display, ConfigureNotify, &event)); ConfigureEvent = (XConfigureEvent *)&event; size = ConfigureEvent->width; if (ConfigureEvent->height != size) { #if 0 fprintf(stderr, "xworld: error: width != height\n"); exit(1); #else size = MIN(size, ConfigureEvent->height); #endif } if (size != old_size) { old_size = size; n = size - 2*BORDER; r1 = n/2; r2 = size/2; XDestroyImage(image); image = XCreateImage(display, visual, depth, format, 0, 0, size, size, bitmap_pad, 0); if (image == NULL) { fprintf(stderr, "xworld: can't create XImage\n"); exit(1); } Map = alloc_image(image); XPutImage(display, win, gc, image, 0, 0, 0, 0, size, size); break; } } } } } }