/* -*- Mode: C; tab-width: 4 -*- */ /* star --- flying through an asteroid field */ #if !defined( lint ) && !defined( SABER ) static const char sccsid[] = "@(#)star.c 5.00 2000/11/01 xlockmore"; #endif /*- * Based on TI Explorer Lisp code by John Nguyen * Copyright (c) 1992 by Jamie Zawinski * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 01-Nov-2000: Allocation checks * 10-Oct-1996: Renamed from rock. Added trek and rock options. * Combined with features from star by Heath Rice * . * The Enterprise flys by from a few different views. * Romulan ship has some trouble. * 07-Sep-1996: Fixed problems with 3d mode * 08-May-1996: Blue on left instead of green for 3d. It seems more common * than green. Use "-left3d Green" if you have the other kind. * 17-Jan-1996: 3D mode for star thanks to . * Get out your 3D glasses, Red on left and Blue on right. * 14-Apr-1995: Jeremie PETIT added a "move" feature. * 02-Sep-1993: xlock version David Bagley * 1992: xscreensaver version Jamie Zawinski */ /*- * original copyright * Copyright (c) 1992 by Jamie Zawinski * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #ifdef STANDALONE #define MODE_star #define PROGCLASS "Star" #define HACK_INIT init_star #define HACK_DRAW draw_star #define star_opts xlockmore_opts #define DEFAULTS "*delay: 40000 \n" \ "*count: 100 \n" \ "*size: 100 \n" \ "*ncolors: 200 \n" \ "*use3d: False \n" \ "*delta3d: 1.5 \n" \ "*right3d: red \n" \ "*left3d: blue \n" \ "*both3d: magenta \n" \ "*none3d: black \n" #define BRIGHT_COLORS #include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ #include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ #ifdef MODE_star #define DEF_TREK "50" #define DEF_ROCK "False" #define DEF_STRAIGHT "False" static int trek; static Bool rock; static Bool straight; static XrmOptionDescRec opts[] = { {(char *) "-trek", (char *) ".star.trek", XrmoptionSepArg, (caddr_t) NULL}, {(char *) "-rock", (char *) ".star.rock", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+rock", (char *) ".star.rock", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-straight", (char *) ".star.straight", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+straight", (char *) ".star.straight", XrmoptionNoArg, (caddr_t) "off"} }; static argtype vars[] = { {(void *) & trek, (char *) "trek", (char *) "Trek", (char *) DEF_TREK, t_Int}, {(void *) & rock, (char *) "rock", (char *) "Rock", (char *) DEF_ROCK, t_Bool}, {(void *) & straight, (char *) "straight", (char *) "Straight", (char *) DEF_STRAIGHT, t_Bool} }; static OptionStruct desc[] = { {(char *) "-trek num", (char *) "chance of a Star Trek encounter"}, {(char *) "-/+rock", (char *) "turn on/off rocks"}, {(char *) "-/+straight", (char *) "turn on/off spin and shifting origin"} }; ModeSpecOpt star_opts = {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; #ifdef USE_MODULES ModStruct star_description = {"star", "init_star", "draw_star", "release_star", "refresh_star", "init_star", (char *) NULL, &star_opts, 40000, 100, 1, 100, 64, 0.3, "", "Shows a star field with a twist", 0, NULL}; #endif typedef struct _BitmapType { int direction, width, height; } BitmapType; #include "bitmaps/enterprise-2.xbm" /* Enterprise EAST */ #include "bitmaps/enterprise-3.xbm" /* Enterprise SOUTH EAST */ #include "bitmaps/enterprise-5.xbm" /* Enterprise SOUTH WEST */ #include "bitmaps/enterprise-6.xbm" /* Enterprise WEST */ #define TREKIES 4 static BitmapType trekie[] = { {2, enterprise2_width, enterprise2_height}, {3, enterprise3_width, enterprise3_height}, {5, enterprise5_width, enterprise5_height}, {6, enterprise6_width, enterprise6_height} }; /*- * For 3d effect get some 3D glasses, left lens red, and right lens blue. * Too bad monitors do not emit polarized light. */ #define MIN_STARS 1 #define MIN_DEPTH 2 /* stars disappear when they get this close */ #define MAX_DEPTH 60 /* this is where stars appear */ #define MINSIZE 3 /* how small where pixmaps are not used */ #define MAXSIZE 200 /* how big (in pixels) stars are at depth 1 */ #define DEPTH_SCALE 100 /* how many ticks there are between depths */ #define RESOLUTION 1000 #define MAX_DEP 1.0 /* how far the displacement can be (percents) */ #define DIRECTION_CHANGE_RATE 60 #define MAX_DEP_SPEED 5 /* Maximum speed for movement */ #define MOVE_STYLE 0 /* Only 0 and 1. Distinguishes the fact that these are the stars that are moving (1) or the stars source (0). */ #define GETZDIFF(z) \ (MI_DELTA3D(mi)*40.0*(1.0-((MAX_DEPTH*DEPTH_SCALE/2)/(z+20.0*DEPTH_SCALE)))) /* the compiler needs to optimize the calculations here */ /*- there's not much point in the above being user-customizable, but those numbers might want to be tweaked for displays with an order of magnitude higher resolution or compute power. */ #define TREKBITS(n,w,h)\ if ((sp->trekPixmaps[sp->init_treks]=\ XCreateBitmapFromData(display,window,(char *)n,w,h))==None){\ return False;} else {sp->init_treks++;} typedef struct { int real_size; int r; unsigned long color; int theta; int depth; int size, x, y; int diff; } astar; typedef struct { XPoint loc, delta, size; } trekstruct; typedef struct { int current_delta; /* observer Z rotation */ int new_delta; int dchange_tick; int width, height; int midx, midy; int current_dep[2]; int speed_dep[2]; short direction[2]; int rotate_p, speed, nstars; float max_dep; int move_p; int dep_x, dep_y; int max_star_size; astar *astars; Pixmap *pixmaps; Pixmap trekPixmaps[TREKIES]; int init_treks; int current_trek; GC stippledGC; trekstruct trek; } starstruct; static float cos_array[RESOLUTION], sin_array[RESOLUTION]; static float depths[(MAX_DEPTH + 1) * DEPTH_SCALE]; static starstruct *stars = (starstruct *) NULL; static void star_draw(ModeInfo * mi, astar * astars, int draw_p); static int compute_move(starstruct * sp, int axe); static void star_compute(ModeInfo * mi, astar * astars) { starstruct *sp = &stars[MI_SCREEN(mi)]; double factor = depths[astars->depth]; double rsize = astars->real_size * factor; astars->size = (int) (rsize + 0.5); astars->diff = (int) (int) GETZDIFF(astars->depth); astars->x = sp->midx + (int) (cos_array[astars->theta] * astars->r * factor); astars->y = sp->midy + (int) (sin_array[astars->theta] * astars->r * factor); if (sp->move_p) { double move_factor = (double) (MOVE_STYLE - (double) astars->depth / (double) ((MAX_DEPTH + 1) * (double) DEPTH_SCALE)); /* move_factor is 0 when the star is close, 1 when far */ astars->x += (int) ((double) sp->dep_x * move_factor); astars->y += (int) ((double) sp->dep_y * move_factor); } } static void star_reset(ModeInfo * mi, astar * astars) { starstruct *sp = &stars[MI_SCREEN(mi)]; astars->real_size = sp->max_star_size; astars->r = (int) (RESOLUTION * 0.7 + NRAND(30 * RESOLUTION)); astars->theta = NRAND(RESOLUTION); astars->depth = MAX_DEPTH * DEPTH_SCALE; if (MI_NPIXELS(mi) > 2) astars->color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); else astars->color = MI_WHITE_PIXEL(mi); star_compute(mi, astars); star_draw(mi, astars, True); } static void star_tick(ModeInfo * mi, astar * astars, int d) { starstruct *sp = &stars[MI_SCREEN(mi)]; if (astars->depth > 0) { star_draw(mi, astars, False); astars->depth -= sp->speed; if (sp->rotate_p) astars->theta = (astars->theta + d) % RESOLUTION; while (astars->theta < 0) astars->theta += RESOLUTION; if (astars->depth < (MIN_DEPTH * DEPTH_SCALE)) astars->depth = 0; else if (astars->depth > (MAX_DEPTH * DEPTH_SCALE)) astars->depth = MAX_DEPTH * DEPTH_SCALE; else { star_compute(mi, astars); star_draw(mi, astars, True); } } else if (!NRAND(40)) star_reset(mi, astars); } static void move_trek(starstruct * sp, int direction, int width, int height) { switch (direction) { /* Format: 0 = N, 1 = NE, etc */ case 2: /* EAST */ sp->trek.loc.x = -width; sp->trek.loc.y = NRAND(sp->height); sp->trek.delta.x = NRAND(3) + 1; sp->trek.delta.y = NRAND(7) - 4; break; case 3: /* SOUTH EAST */ if (LRAND() & 1) { /* Top to Right */ sp->trek.loc.x = NRAND(sp->width); sp->trek.loc.y = -height; } else { /* Left to Bottom */ sp->trek.loc.x = -width; sp->trek.loc.y = NRAND(sp->height); } sp->trek.delta.x = NRAND(3) + 1; sp->trek.delta.y = NRAND(3) + 1; break; case 4: /* SOUTH */ sp->trek.loc.x = NRAND(sp->width); sp->trek.loc.y = sp->height; sp->trek.delta.x = NRAND(7) - 4; sp->trek.delta.y = -(NRAND(3) + 1); break; case 5: /* SOUTH EAST */ if (LRAND() & 1) { /* Top to Right */ sp->trek.loc.x = NRAND(sp->width); sp->trek.loc.y = -height; } else { /* Left to Bottom */ sp->trek.loc.x = sp->width; sp->trek.loc.y = NRAND(sp->height); } sp->trek.delta.x = -(NRAND(3) + 1); sp->trek.delta.y = NRAND(3) + 1; break; case 6: /* WEST */ sp->trek.loc.x = sp->width; sp->trek.loc.y = NRAND(sp->height); sp->trek.delta.x = -(NRAND(3) + 1); sp->trek.delta.y = NRAND(7) - 4; break; default: (void) printf("not implemented for direction %d", direction); break; } sp->trek.size.x = width; sp->trek.size.y = height; } static void free_star(Display *display, starstruct *sp) { int i; if (sp->astars != NULL) { free(sp->astars); sp->astars = (astar *) NULL; } if (sp->pixmaps != None) { for (i = 0; i < sp->max_star_size; i++) XFreePixmap(display, sp->pixmaps[i]); free(sp->pixmaps); sp->pixmaps = None; } if (sp->stippledGC != None) { XFreeGC(display, sp->stippledGC); sp->stippledGC = None; } for (i = 0; i < sp->init_treks; i++) { XFreePixmap(display, sp->trekPixmaps[i]); } sp->init_treks = 0; } static void draw_trek(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); starstruct *sp = &stars[MI_SCREEN(mi)]; int new_one = 0; if (TREKIES == sp->current_trek) if (NRAND(10000) < trek) { sp->current_trek = NRAND(TREKIES); new_one = 1; move_trek(sp, trekie[sp->current_trek].direction, trekie[sp->current_trek].width, trekie[sp->current_trek].height); } if (TREKIES != sp->current_trek) { sp->trek.loc.x += sp->trek.delta.x; sp->trek.loc.y += sp->trek.delta.y; if ((sp->trek.loc.x < -sp->trek.size.x) || (sp->trek.loc.y < -sp->trek.size.y) || (sp->trek.loc.y >= sp->height) || (sp->trek.loc.x >= sp->width)) { sp->current_trek = TREKIES; XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); XFillRectangle(display, window, gc, sp->trek.loc.x - sp->trek.delta.x, sp->trek.loc.y - sp->trek.delta.y, sp->trek.size.x, sp->trek.size.y); } else { int trekx, treky, trekwidth, trekheight; XSetForeground(display, sp->stippledGC, MI_WHITE_PIXEL(mi)); XSetTSOrigin(display, sp->stippledGC, sp->trek.loc.x, sp->trek.loc.y); XSetStipple(display, sp->stippledGC, sp->trekPixmaps[sp->current_trek]); XSetFillStyle(display, sp->stippledGC, FillOpaqueStippled); trekx = sp->trek.loc.x; treky = sp->trek.loc.y, trekwidth = sp->trek.size.x; trekheight = sp->trek.size.y; /* Bound checks needed for Sun but does not hurt elsewhere */ if (trekx < 0) { trekwidth = sp->trek.size.x + trekx; trekx = 0; } if (treky < 0) { trekheight = sp->trek.size.y + treky; treky = 0; } /* This part is not needed but it jives with above */ if (trekx + trekwidth >= sp->width) { trekwidth = sp->width - trekx; } if (treky + trekheight >= sp->height) { trekheight = sp->height - treky; } XFillRectangle(display, window, sp->stippledGC, trekx, treky, trekwidth, trekheight); if (!new_one) { XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); ERASE_IMAGE(display, window, gc, sp->trek.loc.x, sp->trek.loc.y, (sp->trek.loc.x - sp->trek.delta.x), (sp->trek.loc.y - sp->trek.delta.y), sp->trek.size.x, sp->trek.size.y); } } } } static void star_draw(ModeInfo * mi, astar * astars, int draw_p) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); starstruct *sp = &stars[MI_SCREEN(mi)]; if (draw_p) { if (MI_IS_USE3D(mi)) { if (MI_IS_INSTALL(mi)) XSetForeground(MI_DISPLAY(mi), gc, MI_NONE_COLOR(mi)); else XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); } else XSetForeground(display, gc, astars->color); } else XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); if (astars->x <= 0 || astars->y <= 0 || astars->x >= sp->width || astars->y >= sp->height) { /* This means that if a star were to go off the screen at 12:00, but would have been visible at 3:00, it won't come back once the observer rotates around so that the star would have been visible again. Oh well. */ if (!sp->move_p) astars->depth = 0; return; } if (astars->size <= 1) { if (MI_IS_USE3D(mi)) { if (draw_p) { if (MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXor); XSetForeground(display, gc, MI_LEFT_COLOR(mi)); } XDrawPoint(display, window, gc, astars->x - astars->diff, astars->y); if (draw_p) XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); XDrawPoint(display, window, gc, astars->x + astars->diff, astars->y); if (draw_p && MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXcopy); } else XDrawPoint(display, window, gc, astars->x, astars->y); } else if (astars->size <= MINSIZE || !draw_p) { if (MI_IS_USE3D(mi)) { if (draw_p) { if (MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXor); XSetForeground(display, gc, MI_LEFT_COLOR(mi)); } XFillRectangle(display, window, gc, astars->x - astars->size / 2 - astars->diff, astars->y - astars->size / 2, astars->size, astars->size); if (draw_p) XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); XFillRectangle(display, window, gc, astars->x - astars->size / 2 + astars->diff, astars->y - astars->size / 2, astars->size, astars->size); if (draw_p && MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXcopy); } else XFillRectangle(display, window, gc, astars->x - astars->size / 2, astars->y - astars->size / 2, astars->size, astars->size); } else if (astars->size < sp->max_star_size) { if (MI_IS_USE3D(mi)) { if (MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXor); XSetForeground(display, gc, MI_LEFT_COLOR(mi)); XCopyPlane(display, sp->pixmaps[astars->size - MINSIZE], window, gc, 0, 0, astars->size, astars->size, astars->x - astars->size / 2 - astars->diff, astars->y - astars->size / 2, 1L); XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); XCopyPlane(display, sp->pixmaps[astars->size - MINSIZE], window, gc, 0, 0, astars->size, astars->size, astars->x - astars->size / 2 + astars->diff, astars->y - astars->size / 2, 1L); if (MI_IS_INSTALL(mi)) XSetFunction(display, gc, GXcopy); } else XCopyPlane(display, sp->pixmaps[astars->size - MINSIZE], window, gc, 0, 0, astars->size, astars->size, astars->x - astars->size / 2, astars->y - astars->size / 2, 1L); } } static Bool init_pixmaps(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); starstruct *sp = &stars[MI_SCREEN(mi)]; int size = MI_SIZE(mi); int i; XGCValues gcv; GC fg_gc = 0, bg_gc = 0; if (size < -MINSIZE) sp->max_star_size = NRAND(-size - MINSIZE + 1) + MINSIZE; else if (size < MINSIZE) sp->max_star_size = MINSIZE; else sp->max_star_size = size; if (sp->max_star_size > MAXSIZE) sp->max_star_size = MAXSIZE; if ((sp->pixmaps = (Pixmap *) calloc(sp->max_star_size, sizeof (Pixmap))) == None) { return False; } for (i = 0; i < sp->max_star_size; i++) { int h = i + MINSIZE; Pixmap p; XPoint points[7]; if (rock) p = XCreatePixmap(display, window, h, h, 1); else /* Dunno why this is required */ p = XCreatePixmap(display, window, 2 * h, 2 * h, 1); sp->pixmaps[i] = p; if (p == None) { return False; } if (fg_gc == None) { /* must use drawable of pixmap, not window (fmh) */ gcv.foreground = 1; gcv.background = 0; if ((fg_gc = XCreateGC(display, p, GCForeground | GCBackground, &gcv)) == None) { return False; } } if (bg_gc == None) { /* must use drawable of pixmap, not window (fmh) */ gcv.foreground = 0; gcv.background = 1; if ((bg_gc = XCreateGC(display, p, GCForeground | GCBackground, &gcv)) == None) { XFreeGC(display, fg_gc); return False; } } XFillRectangle(display, p, bg_gc, 0, 0, h, h); if (rock) { points[0].x = (int) ((double) h * 0.15); points[0].y = (int) ((double) h * 0.85); points[1].x = (int) ((double) h * 0.00); points[1].y = (int) ((double) h * 0.20); points[2].x = (int) ((double) h * 0.30); points[2].y = (int) ((double) h * 0.00); points[3].x = (int) ((double) h * 0.40); points[3].y = (int) ((double) h * 0.10); points[4].x = (int) ((double) h * 0.90); points[4].y = (int) ((double) h * 0.10); points[5].x = (int) ((double) h * 1.00); points[5].y = (int) ((double) h * 0.55); points[6].x = (int) ((double) h * 0.45); points[6].y = (int) ((double) h * 1.00); XFillPolygon(display, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin); } else { XFillArc(display, p, fg_gc, 0, 0, h, h, 0, 23040); } } XFreeGC(display, fg_gc); XFreeGC(display, bg_gc); if (sp->stippledGC == None) { gcv.foreground = MI_BLACK_PIXEL(mi); gcv.background = MI_BLACK_PIXEL(mi); if ((sp->stippledGC = XCreateGC(display, window, GCForeground | GCBackground, &gcv)) == None) return False; } if (!sp->init_treks && trek) { /* PURIFY 4.0.1 on SunOS4 reports a 3264 byte memory leak on the next line. * PURIFY 4.0.1 on Solaris 2 does not report this memory leak. */ TREKBITS(enterprise2_bits, enterprise2_width, enterprise2_height); TREKBITS(enterprise3_bits, enterprise3_width, enterprise3_height); TREKBITS(enterprise5_bits, enterprise5_width, enterprise5_height); TREKBITS(enterprise6_bits, enterprise6_width, enterprise6_height); } return True; } static void tick_stars(ModeInfo * mi, int d) { starstruct *sp = &stars[MI_SCREEN(mi)]; int i; if (sp->move_p) { sp->dep_x = compute_move(sp, 0); sp->dep_y = compute_move(sp, 1); } for (i = 0; i < sp->nstars; i++) star_tick(mi, &sp->astars[i], d); } static int compute_move(starstruct * sp, int axe) /* 0 for x, 1 for y */ { int limit[2]; limit[0] = sp->midx; limit[1] = sp->midy; sp->current_dep[axe] += sp->speed_dep[axe]; /* We adjust the displacement */ if (sp->current_dep[axe] > (int) (limit[axe] * sp->max_dep)) { if (sp->current_dep[axe] > limit[axe]) sp->current_dep[axe] = limit[axe]; sp->direction[axe] = -1; } /* This is when we reach the upper screen limit */ if (sp->current_dep[axe] < (int) (-limit[axe] * sp->max_dep)) { if (sp->current_dep[axe] < -limit[axe]) sp->current_dep[axe] = -limit[axe]; sp->direction[axe] = 1; } /* This is when we reach the lower screen limit */ if (sp->direction[axe] == 1) /* We adjust the sp->speed_dep */ sp->speed_dep[axe] += 1; else if (sp->direction[axe] == -1) sp->speed_dep[axe] -= 1; if (sp->speed_dep[axe] > MAX_DEP_SPEED) sp->speed_dep[axe] = MAX_DEP_SPEED; else if (sp->speed_dep[axe] < -MAX_DEP_SPEED) sp->speed_dep[axe] = -MAX_DEP_SPEED; if (!straight && !NRAND(DIRECTION_CHANGE_RATE)) { int change = (int) (LRAND() & 1); if (change != 1) { /* We change direction */ if (sp->direction[axe] == 0) sp->direction[axe] = change - 1; /* 0 becomes either 1 or -1 */ else sp->direction[axe] = 0; /* -1 or 1 become 0 */ } } return (sp->current_dep[axe]); } void init_star(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); int i; starstruct *sp; if (stars == NULL) { if ((stars = (starstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (starstruct))) == NULL) return; for (i = 0; i < RESOLUTION; i++) { sin_array[i] = SINF((((float) i) / (RESOLUTION / 2.0)) * M_PI); cos_array[i] = COSF((((float) i) / (RESOLUTION / 2.0)) * M_PI); } /* We actually only need i/speed of these. Oh well. */ for (i = 1; i < (int) (sizeof (depths) / sizeof (depths[0])); i++) depths[i] = (float) atan(((double) 0.5) / (((double) i) / DEPTH_SCALE)); depths[0] = M_PI_2; /* avoid division by 0 */ } sp = &stars[MI_SCREEN(mi)]; sp->width = MI_WIDTH(mi); sp->height = MI_HEIGHT(mi); sp->midx = sp->width / 2; sp->midy = sp->height / 2; sp->speed = 100; sp->rotate_p = !straight; sp->max_dep = (straight) ? 0 : MAX_DEP; sp->move_p = True; sp->dep_x = 0; sp->dep_y = 0; sp->current_trek = TREKIES; sp->nstars = MI_COUNT(mi); if (sp->nstars < -MIN_STARS) { if (sp->astars) { free(sp->astars); sp->astars = (astar *) NULL; } sp->nstars = NRAND(-sp->nstars - MIN_STARS + 1) + MIN_STARS; } else if (sp->nstars < MIN_STARS) sp->nstars = MIN_STARS; if (sp->speed > 100) sp->speed = 100; if (sp->astars == NULL) if ((sp->astars = (astar *) calloc(sp->nstars, sizeof (astar))) == NULL) { free_star(display, sp); return; } if (sp->pixmaps == NULL) if (!init_pixmaps(mi)) { free_star(display, sp); return; } /* don't want any exposure events from XCopyPlane */ XSetGraphicsExposures(display, MI_GC(mi), False); if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) { MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi)); } else { MI_CLEARWINDOW(mi); } } void draw_star(ModeInfo * mi) { starstruct *sp; if (stars == NULL) return; sp = &stars[MI_SCREEN(mi)]; if (sp->astars == NULL) return; MI_IS_DRAWN(mi) = True; if (sp->current_delta != sp->new_delta) { if (sp->dchange_tick++ == 5) { sp->dchange_tick = 0; if (sp->current_delta < sp->new_delta) sp->current_delta++; else sp->current_delta--; } } else { if (!NRAND(50)) { sp->new_delta = (NRAND(11) - 5); if (!NRAND(10)) sp->new_delta *= 5; } } tick_stars(mi, sp->current_delta); draw_trek(mi); #if 0 /* this is for making stars go backwards, not ready for prime-time */ if (!NRAND(500)) { sp->speed = -sp->speed; } #endif } void release_star(ModeInfo * mi) { if (stars != NULL) { int screen; for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) free_star(MI_DISPLAY(mi), &stars[screen]); free(stars); stars = (starstruct *) NULL; } } void refresh_star(ModeInfo * mi) { if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) { MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi)); } else { MI_CLEARWINDOW(mi); } } #endif /* MODE_star */