/* -*- Mode: C; tab-width: 4 -*- Ported from xlockmore 4.03a12 to be a standalone program and thus usable with xscreensaver by Jamie Zawinski on 15-May-97. Original copyright notice from xlock.c: * Copyright (c) 1988-91 by Patrick J. Naughton. * * 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. */ #if 0 static const char sccsid[] = "@(#)bouboule.c 4.00 97/01/01 xlockmore"; #endif /*- * bouboule.c (bouboule mode for xlockmore) * * Sort of starfield for xlockmore. I found that making a starfield for * a 3D engine and thought it could be a nice lock mode. For a real starfield, * I only scale the sort of sphere you see to the whole sky and clip the stars * to the camera screen. * * Code Copyright 1996 by Jeremie PETIT (jeremie_petit@geocities.com) * * Use: batchcount is the number of stars. * cycles is the maximum size for a star * * 15-May-97: jwz@jwz.org: turned into a standalone program. * 04-Sep-96: Added 3d support (Henrik Theiling, theiling@coli-uni-sb.de) * 20-Feb-96: Added tests so that already malloced objects are not * malloced twice, thanks to the report from * 01-Feb-96: Patched by Jouk Jansen for VMS * Patched by for TrueColor displays * 30-Jan-96: Wrote all that I wanted to. * * DONE: Build up a XArc list and Draw everything once with XFillArcs * That idea came from looking at swarm code. * DONE: Add an old arcs list for erasing. * DONE: Make center of starfield SinVariable. * DONE: Add some random in the sinvary() function. * DONE: check time for erasing the stars with the two methods and use the * better one. Note that sometimes the time difference between * beginning of erasing and its end is negative! I check this, and * do not use this result when it occurs. If all values are negative, * the erasing will continue being done in the currently tested mode. * DONE: Allow stars size customization. * DONE: Make sizey be no less than half sizex or no bigger than twice sizex. * * IDEA: A simple check can be performed to know which stars are "behind" * and which are "in front". So is possible to very simply change * the drawing mode for these two sorts of stars. BUT: this would lead * to a rewrite of the XArc list code because drawing should be done * in two steps: "behind" stars then "in front" stars. Also, what could * be the difference between the rendering of these two types of stars? * IDEA: Calculate the distance of each star to the "viewer" and render the * star accordingly to this distance. Same remarks as for previous * ideas can be pointed out. This would even lead to reget the old stars * drawing code, that has been replaced by the XFillArcs. On another * hand, this would allow particular stars (own color, shape...), as * far as they would be individually drawn. One should be careful to * draw them according to their distance, that is not drawing a far * star after a close one. */ #ifdef STANDALONE # define DEFAULTS "*count: 100 \n" \ "*size: 15 \n" \ "*delay: 20000 \n" \ "*ncolors: 64 \n" \ "*use3d: True \n" \ "*delta3d: 1.5 \n" \ "*right3d: red \n" \ "*left3d: blue \n" \ "*both3d: magenta \n" \ "*none3d: black \n" \ "*fpsSolid: true \n" \ "*ignoreRotation: True \n" # define SMOOTH_COLORS # define release_bouboule 0 # define bouboule_handle_event 0 # include "xlockmore.h" /* from the xscreensaver distribution */ #else /* !STANDALONE */ # include "xlock.h" /* from the xlockmore distribution */ # define ENTRYPOINT /**/ #endif /* !STANDALONE */ ENTRYPOINT ModeSpecOpt bouboule_opts = { 0, NULL, 0, NULL, NULL }; #define USEOLDXARCS 1 /* If 1, we use old xarcs list for erasing. * else we just roughly erase the window. * This mainly depends on the number of stars, * because when they are many, it is faster to * erase the whole window than to erase each star */ #if HAVE_GETTIMEOFDAY #define ADAPT_ERASE 1 /* If 1, then we try ADAPT_CHECKS black XFillArcs, * and after, ADAPT_CHECKS XFillRectangle. * We check which method seems better, knowing that * XFillArcs is generally visually better. So we * consider that XFillArcs is still better if its time * is about XFillRectangle * ADAPT_ARC_PREFERED * We need gettimeofday * for this... Does it exist on other systems ? Do we * have to use another function for others ? * This value overrides USEOLDXARCS. */ #ifdef USE_XVMSUTILS # if 0 # include "../xvmsutils/unix_time.h" # else # include # endif #endif #include #define ADAPT_CHECKS 50 #define ADAPT_ARC_PREFERED 150 /* Maybe the value that is the most important * for adapting to a system */ #endif #define dtor(x) (((x) * M_PI) / 180.0) /* Degrees to radians */ #define MINSTARS 1 #define MINSIZE 1 /* jwz: I think slower color changes look better */ #define COLOR_CHANGES 50 /* How often we change colors (1 = always) * This value should be tuned accordingly to * the number of stars */ #define MAX_SIZEX_SIZEY 2. /* This controls whether the sphere can be very * very large and have a small height (or the * opposite) or no. */ #define THETACANRAND 80 /* percentage of changes for the speed of * change of the 3 theta values */ #define SIZECANRAND 80 /* percentage of changes for the speed of * change of the sizex and sizey values */ #define POSCANRAND 80 /* percentage of changes for the speed of * change of the x and y values */ /* Note that these XXXCANRAND values can be 0, that is no rand acceleration * variation. */ #define VARRANDALPHA (NRAND((int) (M_PI * 1000.0))/1000.0) #define VARRANDSTEP (M_PI/(NRAND(100)+100.0)) #define VARRANDMIN (-70.0) #define VARRANDMAX 70.0 #define MINZVAL 100 /* stars can come this close */ #define SCREENZ 2000 /* this is where the screen is */ #define MAXZVAL 10000 /* stars can go this far away */ #define GETZDIFF(z) ((MI_DELTA3D(mi))*20.0*(1.0-(SCREENZ)/(z+1000))) #define MAXDIFF MAX(-GETZDIFF(MINZVAL),GETZDIFF(MAXZVAL)) /* These values are the variation parameters of the acceleration variation * of the SinVariables that are randomized. */ /******************************/ typedef struct SinVariableStruct /******************************/ { double alpha; /* * Alpha is the current state of the sinvariable * alpha should be initialized to a value between * 0.0 and 2 * M_PI */ double step; /* * Speed of evolution of alpha. It should be a reasonable * fraction of 2 * M_PI. This value directly influence * the variable speed of variation. */ double minimum; /* Minimum value for the variable */ double maximum; /* Maximum value for the variable */ double value; /* Current value */ int mayrand; /* Flag for knowing whether some randomization can be * applied to the variable */ struct SinVariableStruct *varrand; /* Evolving Variable: the variation of * alpha */ } SinVariable; /***********************/ typedef struct StarStruct /***********************/ { double x, y, z; /* Position of the star */ short size; /* Try to guess */ } Star; /****************************/ typedef struct StarFieldStruct /****************************/ { short width, height; /* width and height of the starfield window */ short max_star_size; /* Maximum radius for stars. stars radius will * vary from 1 to MAX_STAR_SIZE */ SinVariable x; /* Evolving variables: */ SinVariable y; /* Center of the field on the screen */ SinVariable z; SinVariable sizex; /* Evolving variable: half width of the field */ SinVariable sizey; /* Evolving variable: half height of the field */ SinVariable thetax; /* Evolving Variables: */ SinVariable thetay; /* rotation angles of the starfield */ SinVariable thetaz; /* around x, y and z local axis */ Star *star; /* List of stars */ XArc *xarc; /* Current List of arcs */ XArc *xarcleft; /* additional list for the left arcs */ #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) XArc *oldxarc; /* Old list of arcs */ XArc *oldxarcleft; #endif unsigned long color; /* Current color of the starfield */ int colorp; /* Pointer to color of the starfield */ int NbStars; /* Number of stars */ short colorchange; /* Counter for the color change */ #if (ADAPT_ERASE == 1) short hasbeenchecked; long rect_time; long xarc_time; #endif } StarField; static StarField *starfield = NULL; /*********/ static void sinvary(SinVariable * v) /*********/ { v->value = v->minimum + (v->maximum - v->minimum) * (sin(v->alpha) + 1.0) / 2.0; if (v->mayrand == 0) v->alpha += v->step; else { int vaval = NRAND(100); if (vaval <= v->mayrand) sinvary(v->varrand); v->alpha += (100.0 + (v->varrand->value)) * v->step / 100.0; } if (v->alpha > 2 * M_PI) v->alpha -= 2 * M_PI; } /*************************************************/ static void sininit(SinVariable * v, double alpha, double step, double minimum, double maximum, short int mayrand) { v->alpha = alpha; v->step = step; v->minimum = minimum; v->maximum = maximum; v->mayrand = mayrand; if (mayrand != 0) { if (v->varrand == NULL) v->varrand = (SinVariable *) calloc(1, sizeof (SinVariable)); sininit(v->varrand, VARRANDALPHA, VARRANDSTEP, VARRANDMIN, VARRANDMAX, 0); sinvary(v->varrand); } /* We calculate the values at least once for initialization */ sinvary(v); } static void sinfree(SinVariable * point) { SinVariable *temp, *next; next = point->varrand; while (next) { temp = next; next = temp->varrand; (void) free((void *) temp); } } /***************/ ENTRYPOINT void init_bouboule(ModeInfo * mi) /***************/ /*- * The stars init part was first inspirated from the net3d game starfield * code. But net3d starfield is not really 3d starfield, and I needed real 3d, * so only remains the net3d starfield initialization main idea, that is * the stars distribution on a sphere (theta and omega computing) */ { StarField *sp; int size = MI_SIZE(mi); int i; double theta, omega; if (MI_WIDTH(mi) > 2560) size *= 2; /* Retina displays */ MI_INIT (mi, starfield); sp = &starfield[MI_SCREEN(mi)]; sp->width = MI_WIN_WIDTH(mi); sp->height = MI_WIN_HEIGHT(mi); /* use the right `black' pixel values: */ if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi)); XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), 0, 0, sp->width, sp->height); } else XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); 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; sp->NbStars = MI_BATCHCOUNT(mi); if (sp->NbStars < -MINSTARS) { if (sp->star) { (void) free((void *) sp->star); sp->star = NULL; } if (sp->xarc) { (void) free((void *) sp->xarc); sp->xarc = NULL; } if (sp->xarcleft) { (void) free((void *) sp->xarcleft); sp->xarcleft = NULL; } #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) if (sp->oldxarc) { (void) free((void *) sp->oldxarc); sp->oldxarc = NULL; } if (sp->oldxarcleft) { (void) free((void *) sp->oldxarcleft); sp->oldxarcleft = NULL; } #endif sp->NbStars = NRAND(-sp->NbStars - MINSTARS + 1) + MINSTARS; } else if (sp->NbStars < MINSTARS) sp->NbStars = MINSTARS; /* We get memory for lists of objects */ if (sp->star == NULL) sp->star = (Star *) malloc(sp->NbStars * sizeof (Star)); if (sp->xarc == NULL) sp->xarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); if (MI_WIN_IS_USE3D(mi) && sp->xarcleft == NULL) sp->xarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) if (sp->oldxarc == NULL) sp->oldxarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); if (MI_WIN_IS_USE3D(mi) && sp->oldxarcleft == NULL) sp->oldxarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); #endif { /* We initialize evolving variables */ sininit(&sp->x, NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), ((double) sp->width) / 4.0, 3.0 * ((double) sp->width) / 4.0, POSCANRAND); sininit(&sp->y, NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), ((double) sp->height) / 4.0, 3.0 * ((double) sp->height) / 4.0, POSCANRAND); /* for z, we have to ensure that the bouboule does not get behind */ /* the eyes of the viewer. His/Her eyes are at 0. Because the */ /* bouboule uses the x-radius for the z-radius, too, we have to */ /* use the x-values. */ sininit(&sp->z, NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), ((double) sp->width / 2.0 + MINZVAL), ((double) sp->width / 2.0 + MAXZVAL), POSCANRAND); sininit(&sp->sizex, NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), MIN(((double) sp->width) - sp->x.value, sp->x.value) / 5.0, MIN(((double) sp->width) - sp->x.value, sp->x.value), SIZECANRAND); sininit(&sp->sizey, NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), MAX(sp->sizex.value / MAX_SIZEX_SIZEY, sp->sizey.maximum / 5.0), MIN(sp->sizex.value * MAX_SIZEX_SIZEY, MIN(((double) sp->height) - sp->y.value, sp->y.value)), SIZECANRAND); sininit(&sp->thetax, NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), -M_PI, M_PI, THETACANRAND); sininit(&sp->thetay, NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), -M_PI, M_PI, THETACANRAND); sininit(&sp->thetaz, NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0), -M_PI, M_PI, THETACANRAND); } for (i = 0; i < sp->NbStars; i++) { Star *star; XArc *arc = NULL, *arcleft = NULL; #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) XArc *oarc = NULL, *oarcleft = NULL; #endif star = &(sp->star[i]); arc = &(sp->xarc[i]); if (MI_WIN_IS_USE3D(mi)) arcleft = &(sp->xarcleft[i]); #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) oarc = &(sp->oldxarc[i]); if (MI_WIN_IS_USE3D(mi)) oarcleft = &(sp->oldxarcleft[i]); #endif /* Elevation and bearing of the star */ theta = dtor((NRAND(1800)) / 10.0 - 90.0); omega = dtor((NRAND(3600)) / 10.0 - 180.0); /* Stars coordinates in a 3D space */ star->x = cos(theta) * sin(omega); star->y = sin(omega) * sin(theta); star->z = cos(omega); /* We set the stars size */ star->size = NRAND(2 * sp->max_star_size); if (star->size < sp->max_star_size) star->size = 0; else star->size -= sp->max_star_size; /* We set default values for the XArc lists elements */ arc->x = arc->y = 0; if (MI_WIN_IS_USE3D(mi)) { arcleft->x = arcleft->y = 0; } #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) oarc->x = oarc->y = 0; if (MI_WIN_IS_USE3D(mi)) { oarcleft->x = oarcleft->y = 0; } #endif arc->width = 2 + star->size; arc->height = 2 + star->size; if (MI_WIN_IS_USE3D(mi)) { arcleft->width = 2 + star->size; arcleft->height = 2 + star->size; } #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) oarc->width = 2 + star->size; oarc->height = 2 + star->size; if (MI_WIN_IS_USE3D(mi)) { oarcleft->width = 2 + star->size; oarcleft->height = 2 + star->size; } #endif arc->angle1 = 0; arc->angle2 = 360 * 64; if (MI_WIN_IS_USE3D(mi)) { arcleft->angle1 = 0; arcleft->angle2 = 360 * 64; } #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) oarc->angle1 = 0; oarc->angle2 = 360 * 64; /* ie. we draw whole disks: * from 0 to 360 degrees */ if (MI_WIN_IS_USE3D(mi)) { oarcleft->angle1 = 0; oarcleft->angle2 = 360 * 64; } #endif } if (MI_NPIXELS(mi) > 2) sp->colorp = NRAND(MI_NPIXELS(mi)); /* We set up the starfield color */ if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2) sp->color = MI_PIXEL(mi, sp->colorp); else sp->color = MI_WIN_WHITE_PIXEL(mi); #if (ADAPT_ERASE == 1) /* We initialize the adaptation code for screen erasing */ sp->hasbeenchecked = ADAPT_CHECKS * 2; sp->rect_time = 0; sp->xarc_time = 0; #endif } /****************/ ENTRYPOINT void draw_bouboule(ModeInfo * mi) /****************/ { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); StarField *sp = &starfield[MI_SCREEN(mi)]; int i, diff = 0; double CX, CY, CZ, SX, SY, SZ; Star *star; XArc *arc = NULL, *arcleft = NULL; #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); #endif #if (ADAPT_ERASE == 1) struct timeval tv1; struct timeval tv2; #endif #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) short x_1, y_1, x_2, y_2; /* bounding rectangle around the old starfield, * for erasing with the smallest rectangle * instead of filling the whole screen */ int maxdiff = 0; /* maximal distance between left and right */ /* star in 3d mode, otherwise 0 */ #endif #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) if (MI_WIN_IS_USE3D(mi)) { maxdiff = (int) MAXDIFF; } x_1 = (int) sp->x.value - (int) sp->sizex.value - sp->max_star_size - maxdiff; y_1 = (int) sp->y.value - (int) sp->sizey.value - sp->max_star_size; x_2 = 2 * ((int) sp->sizex.value + sp->max_star_size + maxdiff); y_2 = 2 * ((int) sp->sizey.value + sp->max_star_size); #endif /* We make variables vary. */ sinvary(&sp->thetax); sinvary(&sp->thetay); sinvary(&sp->thetaz); sinvary(&sp->x); sinvary(&sp->y); if (MI_WIN_IS_USE3D(mi)) sinvary(&sp->z); /* A little trick to prevent the bouboule from being * bigger than the screen */ sp->sizex.maximum = MIN(((double) sp->width) - sp->x.value, sp->x.value); sp->sizex.minimum = sp->sizex.maximum / 3.0; /* Another trick to make the ball not too flat */ sp->sizey.minimum = MAX(sp->sizex.value / MAX_SIZEX_SIZEY, sp->sizey.maximum / 3.0); sp->sizey.maximum = MIN(sp->sizex.value * MAX_SIZEX_SIZEY, MIN(((double) sp->height) - sp->y.value, sp->y.value)); sinvary(&sp->sizex); sinvary(&sp->sizey); /* * We calculate the rotation matrix values. We just make the * rotation on the fly, without using a matrix. * Star positions are recorded as unit vectors pointing in various * directions. We just make them all rotate. */ CX = cos(sp->thetax.value); SX = sin(sp->thetax.value); CY = cos(sp->thetay.value); SY = sin(sp->thetay.value); CZ = cos(sp->thetaz.value); SZ = sin(sp->thetaz.value); for (i = 0; i < sp->NbStars; i++) { star = &(sp->star[i]); arc = &(sp->xarc[i]); if (MI_WIN_IS_USE3D(mi)) { arcleft = &(sp->xarcleft[i]); /* to help the eyes, the starfield is always as wide as */ /* deep, so .sizex.value can be used. */ diff = (int) GETZDIFF(sp->sizex.value * ((SY * CX) * star->x + (SX) * star->y + (CX * CY) * star->z) + sp->z.value); } arc->x = (short) ((sp->sizex.value * ((CY * CZ - SX * SY * SZ) * star->x + (-CX * SZ) * star->y + (SY * CZ + SZ * SX * CY) * star->z) + sp->x.value)); arc->y = (short) ((sp->sizey.value * ((CY * SZ + SX * SY * CZ) * star->x + (CX * CZ) * star->y + (SY * SZ - SX * CY * CZ) * star->z) + sp->y.value)); if (MI_WIN_IS_USE3D(mi)) { arcleft->x = (short) ((sp->sizex.value * ((CY * CZ - SX * SY * SZ) * star->x + (-CX * SZ) * star->y + (SY * CZ + SZ * SX * CY) * star->z) + sp->x.value)); arcleft->y = (short) ((sp->sizey.value * ((CY * SZ + SX * SY * CZ) * star->x + (CX * CZ) * star->y + (SY * SZ - SX * CY * CZ) * star->z) + sp->y.value)); arc->x += diff; arcleft->x -= diff; } if (star->size != 0) { arc->x -= star->size; arc->y -= star->size; if (MI_WIN_IS_USE3D(mi)) { arcleft->x -= star->size; arcleft->y -= star->size; } } } /* First, we erase the previous starfield */ if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) XSetForeground(display, gc, MI_NONE_COLOR(mi)); else XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); #if (ADAPT_ERASE == 1) if (sp->hasbeenchecked == 0) { /* We just calculate which method is the faster and eventually free * the oldxarc list */ if (sp->xarc_time > ADAPT_ARC_PREFERED * sp->rect_time) { sp->hasbeenchecked = -2; /* XFillRectangle mode */ (void) free((void *) sp->oldxarc); sp->oldxarc = NULL; if (MI_WIN_IS_USE3D(mi)) { (void) free((void *) sp->oldxarcleft); sp->oldxarcleft = NULL; } } else { sp->hasbeenchecked = -1; /* XFillArcs mode */ } } if (sp->hasbeenchecked == -2) { /* Erasing is done with XFillRectangle */ XFillRectangle(display, window, gc, x_1, y_1, x_2, y_2); } else if (sp->hasbeenchecked == -1) { /* Erasing is done with XFillArcs */ XFillArcs(display, window, gc, sp->oldxarc, sp->NbStars); if (MI_WIN_IS_USE3D(mi)) XFillArcs(display, window, gc, sp->oldxarcleft, sp->NbStars); } else { long usec; if (sp->hasbeenchecked > ADAPT_CHECKS) { #ifdef GETTIMEOFDAY_TWO_ARGS (void) gettimeofday(&tv1, NULL); #else (void) gettimeofday(&tv1); #endif XFillRectangle(display, window, gc, x_1, y_1, x_2, y_2); #ifdef GETTIMEOFDAY_TWO_ARGS (void) gettimeofday(&tv2, NULL); #else (void) gettimeofday(&tv2); #endif usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; if (usec + tv2.tv_usec - tv1.tv_usec > 0) { sp->rect_time += usec + tv2.tv_usec - tv1.tv_usec; sp->hasbeenchecked--; } } else { #ifdef GETTIMEOFDAY_TWO_ARGS (void) gettimeofday(&tv1, NULL); #else (void) gettimeofday(&tv1); #endif XFillArcs(display, window, gc, sp->oldxarc, sp->NbStars); if (MI_WIN_IS_USE3D(mi)) XFillArcs(display, window, gc, sp->oldxarcleft, sp->NbStars); #ifdef GETTIMEOFDAY_TWO_ARGS (void) gettimeofday(&tv2, NULL); #else (void) gettimeofday(&tv2); #endif usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; if (usec + tv2.tv_usec - tv1.tv_usec > 0) { sp->xarc_time += usec + tv2.tv_usec - tv1.tv_usec; sp->hasbeenchecked--; } } } #else #if (USEOLDXARCS == 1) XFillArcs(display, window, gc, sp->oldxarc, sp->NbStars); if (MI_WIN_IS_USE3D(mi)) XFillArcs(display, window, gc, sp->oldxarcleft, sp->NbStars); #else XFillRectangle(display, window, gc, x_1, y_1, x_2, y_2); #endif #endif /* Then we draw the new one */ if (MI_WIN_IS_USE3D(mi)) { if (MI_WIN_IS_INSTALL(mi)) XSetFunction(display, gc, GXor); XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); XFillArcs(display, window, gc, sp->xarc, sp->NbStars); XSetForeground(display, gc, MI_LEFT_COLOR(mi)); XFillArcs(display, window, gc, sp->xarcleft, sp->NbStars); if (MI_WIN_IS_INSTALL(mi)) XSetFunction(display, gc, GXcopy); } else { XSetForeground(display, gc, sp->color); XFillArcs(display, window, gc, sp->xarc, sp->NbStars); } #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) #if (ADAPT_ERASE == 1) if (sp->hasbeenchecked >= -1) { arc = sp->xarc; sp->xarc = sp->oldxarc; sp->oldxarc = arc; if (MI_WIN_IS_USE3D(mi)) { arcleft = sp->xarcleft; sp->xarcleft = sp->oldxarcleft; sp->oldxarcleft = arcleft; } } #else arc = sp->xarc; sp->xarc = sp->oldxarc; sp->oldxarc = arc; if (MI_WIN_IS_USE3D(mi)) { arcleft = sp->xarcleft; sp->xarcleft = sp->oldxarcleft; sp->oldxarcleft = arcleft; } #endif #endif /* We set up the color for the next drawing */ if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2 && (++sp->colorchange >= COLOR_CHANGES)) { sp->colorchange = 0; if (++sp->colorp >= MI_NPIXELS(mi)) sp->colorp = 0; sp->color = MI_PIXEL(mi, sp->colorp); } } ENTRYPOINT void free_bouboule(ModeInfo * mi) { StarField *sp = &starfield[MI_SCREEN(mi)]; if (sp->star) (void) free((void *) sp->star); if (sp->xarc) (void) free((void *) sp->xarc); if (sp->xarcleft) (void) free((void *) sp->xarcleft); #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) if (sp->oldxarc) (void) free((void *) sp->oldxarc); if (sp->oldxarcleft) (void) free((void *) sp->oldxarcleft); #endif sinfree(&(sp->x)); sinfree(&(sp->y)); sinfree(&(sp->z)); sinfree(&(sp->sizex)); sinfree(&(sp->sizey)); sinfree(&(sp->thetax)); sinfree(&(sp->thetay)); sinfree(&(sp->thetaz)); } ENTRYPOINT void reshape_bouboule(ModeInfo * mi, int width, int height) { StarField *sp = &starfield[MI_SCREEN(mi)]; sp->width = width; sp->height = height; sininit(&sp->x, sp->x.alpha, sp->x.step, ((double) sp->width) / 4.0, 3.0 * ((double) sp->width) / 4.0, POSCANRAND); sininit(&sp->y, sp->y.alpha, sp->y.step, ((double) sp->height) / 4.0, 3.0 * ((double) sp->height) / 4.0, POSCANRAND); } #ifndef STANDALONE ENTRYPOINT void refresh_bouboule(ModeInfo * mi) { /* Do nothing, it will refresh by itself */ } #endif XSCREENSAVER_MODULE ("Bouboule", bouboule)