Edit

IABSD.fr/xenocara/app/xlockmore/modes/space.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-26 11:07:42
    Hash : 110b2a92
    Message : Importing xlockmore 5.22

  • app/xlockmore/modes/space.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 */