810 lines
24 KiB
C
810 lines
24 KiB
C
|
/* -*- 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 <johnn@hx.lcs.mit.edu>
|
||
|
* 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
|
||
|
* <rice@asl.dl.nec.com>.
|
||
|
* The Enterprise flys by from a few different views.
|
||
|
* Romulan ship has some trouble.
|
||
|
* 07-Sep-1996: Fixed problems with 3d mode <theiling@coli.uni-sb.de>
|
||
|
* 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 <theiling@coli.uni-sb.de>.
|
||
|
* Get out your 3D glasses, Red on left and Blue on right.
|
||
|
* 14-Apr-1995: Jeremie PETIT <petit@aurora.unice.fr> added a "move" feature.
|
||
|
* 02-Sep-1993: xlock version David Bagley <bagleyd@tux.org>
|
||
|
* 1992: xscreensaver version Jamie Zawinski <jwz@jwz.org>
|
||
|
*/
|
||
|
|
||
|
/*-
|
||
|
* 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 */
|