xenocara/app/xlockmore/modes/space.c
2006-11-26 11:07:42 +00:00

454 lines
12 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* space --- A journey into deep space */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)space.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Copyright (c) 1998 by Vincent Caron [Vincent.Caron@ecl1999.ec-lyon.fr]
*
* 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
* 1998: Written.
*/
#ifdef STANDALONE
#define MODE_space
#define PROGCLASS "Space"
#define HACK_INIT init_space
#define HACK_DRAW draw_space
#define space_opts xlockmore_opts
#define DEFAULTS "*delay: 10000 \n" \
"*count: 100 \n" \
"*ncolors: 64 \n" \
"*use3d: False \n" \
"*delta3d: 1.5 \n" \
"*right3d: red \n" \
"*left3d: blue \n" \
"*both3d: magenta \n" \
"*none3d: black \n"
#define SMOOTH_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#ifdef MODE_space
ModeSpecOpt space_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct space_description =
{"space", "init_space", "draw_space", "release_space",
"refresh_space", "init_space", (char *) NULL, &space_opts,
10000, 100, 1, 1, 64, 1.0, "",
"a journey into deep space", 0, NULL};
#endif
#define X_LIMIT 400 /* space coords clipping */
#define Y_LIMIT 300
#define Z_MAX 450
#define Z_MIN (-330)
#define Z_L2 200 /* far-distance level */
#define Z_L3 (-150) /* close-distance level */
#define DIST 400 /* observer-starfield distance */
#define TRANS_X_MAX 3 /* cinetic parameters auto-change : */
#define TRANS_Y_MAX 3 /* defines limits for cinetic parameters randomizer */
#define TRANS_Z_MAX 7 /* idem */
#define ROT_X_MAX 60 /* idem */
#define ROT_Y_MAX 80 /* idem */
#define ROT_Z_MAX 50 /* idem */
#define TIME_MIN 500 /* idem */
#define TIME_AMP 800 /* idem */
#define DEGREE 0.01/100 /* custom angle unit :) */
typedef struct {
int nb; /* stars number */
int originX, originY; /* screen width/2,height/2 */
double zoom; /* adapt to screen dimensions */
double *starX; /* star buffer */
double *starY; /* holds X,Y,Z coords */
double *starZ;
int ddxn, ddyn, ddzn, daxn, dayn, dazn; /* counters */
double dx, ddx, dy, ddy, dz, ddz, ax, dax, ay, day, az, daz; /* cinetic params */
int pixel_nb; /* number of XPoints in last used pixel buffer */
XPoint *stars1; /* pixel buffer 1 */
XPoint *stars1copy; /* left eye or 2D mode */
XPoint *stars1a; /* two buffers in stars1a,stars1b */
XPoint *stars1b;
XPoint *stars2; /* pixel buffer 2 */
XPoint *stars2copy; /* right eye (3D mode only) */
XPoint *stars2a; /* two buffers in stars2a,stars2b */
XPoint *stars2b;
} SpaceStruct;
static SpaceStruct *spaces = (SpaceStruct *) NULL;
static void
free_space(SpaceStruct *sp)
{
if (sp->starX != NULL) {
free(sp->starX);
sp->starX = (double *) NULL;
}
if (sp->starY != NULL) {
free(sp->starY);
sp->starY = (double *) NULL;
}
if (sp->starZ != NULL) {
free(sp->starZ);
sp->starY = (double *) NULL;
}
if (sp->stars1a != NULL) {
free(sp->stars1a);
sp->stars1a = (XPoint *) NULL;
}
if (sp->stars1b != NULL) {
free(sp->stars1b);
sp->stars1b = (XPoint *) NULL;
}
if (sp->stars2a != NULL) {
free(sp->stars2a);
sp->stars2a = (XPoint *) NULL;
}
if (sp->stars2b != NULL) {
free(sp->stars2b);
sp->stars2b = (XPoint *) NULL;
}
}
void
init_space(ModeInfo * mi)
{
int i;
SpaceStruct *sp;
/* allocate a SpaceStruct for every screen */
if (spaces == NULL) {
if ((spaces = (SpaceStruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (SpaceStruct))) == NULL)
return;
}
sp = &spaces[MI_SCREEN(mi)];
/* star density is linked to screen surface */
sp->nb = MI_COUNT(mi);
sp->originX = MI_WIDTH(mi) / 2;
sp->originY = MI_HEIGHT(mi) / 2;
sp->zoom = (double) MI_WIDTH(mi) * 0.54 + 40;
/* allocate stars buffers for current screen */
if (((sp->starX = (double *) calloc(sp->nb, sizeof (double))) == NULL) ||
((sp->starY = (double *) calloc(sp->nb, sizeof (double))) == NULL) ||
((sp->starZ = (double *) calloc(sp->nb, sizeof (double))) == NULL)) {
free_space(sp);
return;
}
/* allocate pixels buffers for current screen */
if (((sp->stars1a = (XPoint *) calloc(9 * sp->nb,
sizeof (XPoint))) == NULL) ||
((sp->stars1b = (XPoint *) calloc(9 * sp->nb,
sizeof (XPoint))) == NULL)) {
free_space(sp);
return;
}
if (MI_IS_USE3D(mi)) {
if (((sp->stars2a = (XPoint *) calloc(9 * sp->nb,
sizeof (XPoint))) == NULL) ||
((sp->stars2b = (XPoint *) calloc(9 * sp->nb,
sizeof (XPoint))) == NULL)) {
free_space(sp);
return;
}
}
sp->pixel_nb = 0;
sp->stars1 = sp->stars1a;
sp->stars1copy = sp->stars1b;
sp->stars2 = sp->stars2a;
sp->stars2copy = sp->stars2b;
/* place stars randomly */
for (i = 0; i < sp->nb; i++) {
sp->starX[i] = ((double) NRAND(10000) / 5000 - 1) * X_LIMIT;
sp->starY[i] = ((double) NRAND(10000) / 5000 - 1) * Y_LIMIT;
sp->starZ[i] = (double) NRAND(10000) / 10000 * (Z_MAX - Z_MIN) + Z_MIN;
}
sp->dx = 0;
sp->ddxn = 0;
sp->dy = 0;
sp->ddyn = 0;
sp->dz = 3;
sp->ddzn = 0;
sp->ax = 0;
sp->daxn = 0;
sp->ay = 0;
sp->dayn = 0;
sp->az = 0;
sp->dazn = 0;
/* clear screen */
MI_CLEARWINDOW(mi);
}
void
draw_space(ModeInfo * mi)
{
int i, n, originX, originY, x, x2 = 0, y, IS_SMALL;
double _x, _y, _z, cosX, sinX, cosY, sinY, cosZ, sinZ, k, z, zoom;
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
int is3D = MI_IS_USE3D(mi);
double delta = MI_DELTA3D(mi) * 8;
SpaceStruct *sp;
if (spaces == NULL)
return;
sp = &spaces[MI_SCREEN(mi)];
if (sp->stars1a == NULL)
return;
originX = sp->originX;
originY = sp->originY;
zoom = sp->zoom;
IS_SMALL = ((originX * originY) < (160 * 100));
MI_IS_DRAWN(mi) = True;
/* get cos & sin of rotations */
cosX = COSF(sp->ax);
sinX = SINF(sp->ax);
cosY = COSF(sp->ay);
sinY = SINF(sp->ay);
cosZ = COSF(sp->az);
sinZ = SINF(sp->az);
/* move stars ! */
for (i = 0; i < sp->nb; i++) {
_x = sp->starX[i];
_y = sp->starY[i];
_z = sp->starZ[i];
/* X,Y & Z axis rotations */
k = _y * cosX + _z * sinX;
_z = _z * cosX - _y * sinX;
_y = k;
k = _x * cosY + _z * sinY;
_z = _z * cosY - _x * sinY;
_x = k;
k = _x * cosZ + _y * sinZ;
_y = _y * cosZ - _x * sinZ;
_x = k;
/* translations + space boundary overflow */
_x += sp->dx;
if (_x < (-X_LIMIT))
_x = X_LIMIT;
else if (_x > X_LIMIT)
_x = -X_LIMIT;
_y += sp->dy;
if (_y < (-Y_LIMIT))
_y = Y_LIMIT;
else if (_y > Y_LIMIT)
_y = -Y_LIMIT;
_z -= sp->dz;
if (_z < Z_MIN)
_z = Z_MAX;
else if (_z > Z_MAX)
_z = Z_MIN;
sp->starX[i] = _x;
sp->starY[i] = _y;
sp->starZ[i] = _z;
}
/* update translation parameters */
if (sp->ddxn == 0) {
k = (double) NRAND(TRANS_X_MAX * 2) - TRANS_X_MAX;
sp->ddxn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->ddx = (k - sp->dx) / sp->ddxn;
} else {
sp->dx += sp->ddx;
sp->ddxn--;
}
if (sp->ddyn == 0) {
k = (double) NRAND(TRANS_Y_MAX * 2) - TRANS_Y_MAX;
sp->ddyn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->ddy = (k - sp->dy) / sp->ddyn;
} else {
sp->dy += sp->ddy;
sp->ddyn--;
}
if (sp->ddzn == 0) {
k = (double) NRAND(TRANS_Z_MAX * 2) - TRANS_Z_MAX;
sp->ddzn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->ddz = (k - sp->dz) / sp->ddzn;
} else {
sp->dz += sp->ddz;
sp->ddzn--;
}
/* update rotation parameters */
if (sp->daxn == 0) {
k = (double) (NRAND(ROT_X_MAX * 2) - ROT_X_MAX) * DEGREE;
sp->daxn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->dax = (k - sp->ax) / sp->daxn;
} else {
sp->ax += sp->dax;
sp->daxn--;
}
if (sp->dayn == 0) {
k = (double) (NRAND(ROT_Y_MAX * 2) - ROT_Y_MAX) * DEGREE;
sp->dayn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->day = (k - sp->ay) / sp->dayn;
} else {
sp->ay += sp->day;
sp->dayn--;
}
if (sp->dazn == 0) {
k = (double) (NRAND(ROT_Z_MAX * 2) - ROT_Z_MAX) * DEGREE;
sp->dazn = (int) NRAND(TIME_AMP) + TIME_MIN;
sp->daz = (k - sp->az) / sp->dazn;
} else {
sp->az += sp->daz;
sp->dazn--;
}
/* project stars and create corresponding pixels */
n = 0;
for (i = 0; i < sp->nb; i++) {
z = sp->starZ[i];
k = zoom / (z + DIST);
y = sp->stars1[n].y = originY - (int) (k * sp->starY[i]);
if (is3D) {
x = sp->stars1[n].x = originX + (int) (k * (sp->starX[i] - delta));
x2 = sp->stars2[n].x = originX + (int) (k * (sp->starX[i] + delta));
sp->stars2[n].y = y;
} else
x = sp->stars1[n].x = originX + (int) (k * sp->starX[i]);
n++;
if (z < Z_L2) {
/* not to close but closer : use 4 more pixels for this star */
sp->stars1[n].x = x + 1;
sp->stars1[n].y = y;
sp->stars1[n + 1].x = x - 1;
sp->stars1[n + 1].y = y;
sp->stars1[n + 2].x = x;
sp->stars1[n + 2].y = y + 1;
sp->stars1[n + 3].x = x;
sp->stars1[n + 3].y = y - 1;
if (is3D) {
sp->stars2[n].x = x2 + 1;
sp->stars2[n].y = y;
sp->stars2[n + 1].x = x2 - 1;
sp->stars2[n + 1].y = y;
sp->stars2[n + 2].x = x2;
sp->stars2[n + 2].y = y + 1;
sp->stars2[n + 3].x = x2;
sp->stars2[n + 3].y = y - 1;
}
n += 4;
}
if ((z < Z_L3) && (!IS_SMALL)) {
/* very close : use again 4 more pixels (makes 9 for this star) */
sp->stars1[n].x = x - 1;
sp->stars1[n].y = y + 1;
sp->stars1[n + 1].x = x - 1;
sp->stars1[n + 1].y = y - 1;
sp->stars1[n + 2].x = x + 1;
sp->stars1[n + 2].y = y + 1;
sp->stars1[n + 3].x = x + 1;
sp->stars1[n + 3].y = y - 1;
if (is3D) {
sp->stars2[n].x = x2 - 1;
sp->stars2[n].y = y + 1;
sp->stars2[n + 1].x = x2 - 1;
sp->stars2[n + 1].y = y - 1;
sp->stars2[n + 2].x = x2 + 1;
sp->stars2[n + 2].y = y + 1;
sp->stars2[n + 3].x = x2 + 1;
sp->stars2[n + 3].y = y - 1;
}
n += 4;
}
}
/* erase pixels with previous pixel buffer */
if (MI_IS_INSTALL(mi) && is3D)
XSetForeground(display, gc, MI_NONE_COLOR(mi));
else
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XDrawPoints(display, window, gc, sp->stars1copy, sp->pixel_nb, CoordModeOrigin);
if (is3D)
XDrawPoints(display, window, gc, sp->stars2copy, sp->pixel_nb, CoordModeOrigin);
/* draw pixels */
sp->pixel_nb = n;
if (is3D) {
if (MI_IS_INSTALL(mi))
XSetFunction(display, gc, GXor);
XSetForeground(display, gc, MI_LEFT_COLOR(mi));
XDrawPoints(display, window, gc, sp->stars1, sp->pixel_nb, CoordModeOrigin);
XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
XDrawPoints(display, window, gc, sp->stars2, sp->pixel_nb, CoordModeOrigin);
if (MI_IS_INSTALL(mi))
XSetFunction(display, gc, GXcopy);
} else {
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
XDrawPoints(display, window, gc, sp->stars1, sp->pixel_nb, CoordModeOrigin);
}
XFlush(display);
/* swap pixel buffers a & b */
if (sp->stars1 == sp->stars1a) {
sp->stars1 = sp->stars1b;
sp->stars1copy = sp->stars1a;
} else {
sp->stars1 = sp->stars1a;
sp->stars1copy = sp->stars1b;
}
if (sp->stars2 == sp->stars2a) {
sp->stars2 = sp->stars2b;
sp->stars2copy = sp->stars2a;
} else {
sp->stars2 = sp->stars2a;
sp->stars2copy = sp->stars2b;
}
}
void
refresh_space(ModeInfo * mi)
{
/* Do nothing, it will refresh by itself */
}
void
release_space(ModeInfo * mi)
{
if (spaces != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_space(&spaces[screen]);
free(spaces);
spaces = (SpaceStruct *) NULL;
}
}
#endif /* MODE_space */