/*
* 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 <sys/types.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#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;
}
}
}
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1