/* -*- 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 */