1 /* -*- Mode: C; tab-width: 4 -*-
2 Ported from xlockmore 4.03a12 to be a standalone program and thus usable
3 with xscreensaver by Jamie Zawinski <jwz@jwz.org> on 15-May-97.
5 Original copyright notice from xlock.c:
7 * Copyright (c) 1988-91 by Patrick J. Naughton.
9 * Permission to use, copy, modify, and distribute this software and its
10 * documentation for any purpose and without fee is hereby granted,
11 * provided that the above copyright notice appear in all copies and that
12 * both that copyright notice and this permission notice appear in
13 * supporting documentation.
15 * This file is provided AS IS with no warranties of any kind. The author
16 * shall have no liability with respect to the infringement of copyrights,
17 * trade secrets or any patents by this file or any part thereof. In no
18 * event will the author be liable for any lost revenue or profits or
19 * other special, indirect and consequential damages.
23 static const char sccsid[] = "@(#)bouboule.c 4.00 97/01/01 xlockmore";
27 * bouboule.c (bouboule mode for xlockmore)
29 * Sort of starfield for xlockmore. I found that making a starfield for
30 * a 3D engine and thought it could be a nice lock mode. For a real starfield,
31 * I only scale the sort of sphere you see to the whole sky and clip the stars
32 * to the camera screen.
34 * Code Copyright 1996 by Jeremie PETIT (jeremie_petit@geocities.com)
36 * Use: batchcount is the number of stars.
37 * cycles is the maximum size for a star
39 * 15-May-97: jwz@jwz.org: turned into a standalone program.
40 * 04-Sep-96: Added 3d support (Henrik Theiling, theiling@coli-uni-sb.de)
41 * 20-Feb-96: Added tests so that already malloced objects are not
42 * malloced twice, thanks to the report from <mccomb@interport.net>
43 * 01-Feb-96: Patched by Jouk Jansen <joukj@alpha.chem.uva.nl> for VMS
44 * Patched by <bagleyd@bigfoot.com> for TrueColor displays
45 * 30-Jan-96: Wrote all that I wanted to.
47 * DONE: Build up a XArc list and Draw everything once with XFillArcs
48 * That idea came from looking at swarm code.
49 * DONE: Add an old arcs list for erasing.
50 * DONE: Make center of starfield SinVariable.
51 * DONE: Add some random in the sinvary() function.
52 * DONE: check time for erasing the stars with the two methods and use the
53 * better one. Note that sometimes the time difference between
54 * beginning of erasing and its end is negative! I check this, and
55 * do not use this result when it occurs. If all values are negative,
56 * the erasing will continue being done in the currently tested mode.
57 * DONE: Allow stars size customization.
58 * DONE: Make sizey be no less than half sizex or no bigger than twice sizex.
60 * IDEA: A simple check can be performed to know which stars are "behind"
61 * and which are "in front". So is possible to very simply change
62 * the drawing mode for these two sorts of stars. BUT: this would lead
63 * to a rewrite of the XArc list code because drawing should be done
64 * in two steps: "behind" stars then "in front" stars. Also, what could
65 * be the difference between the rendering of these two types of stars?
66 * IDEA: Calculate the distance of each star to the "viewer" and render the
67 * star accordingly to this distance. Same remarks as for previous
68 * ideas can be pointed out. This would even lead to reget the old stars
69 * drawing code, that has been replaced by the XFillArcs. On another
70 * hand, this would allow particular stars (own color, shape...), as
71 * far as they would be individually drawn. One should be careful to
72 * draw them according to their distance, that is not drawing a far
73 * star after a close one.
77 # define DEFAULTS "*count: 100 \n" \
85 "*both3d: magenta \n" \
87 "*fpsSolid: true \n" \
88 "*ignoreRotation: True \n"
90 # define SMOOTH_COLORS
91 # define bouboule_handle_event 0
92 # include "xlockmore.h" /* from the xscreensaver distribution */
93 #else /* !STANDALONE */
94 # include "xlock.h" /* from the xlockmore distribution */
95 # define ENTRYPOINT /**/
96 #endif /* !STANDALONE */
98 ENTRYPOINT ModeSpecOpt bouboule_opts = {
99 0, NULL, 0, NULL, NULL };
101 #define USEOLDXARCS 1 /* If 1, we use old xarcs list for erasing.
102 * else we just roughly erase the window.
103 * This mainly depends on the number of stars,
104 * because when they are many, it is faster to
105 * erase the whole window than to erase each star
108 #if HAVE_GETTIMEOFDAY
109 #define ADAPT_ERASE 1 /* If 1, then we try ADAPT_CHECKS black XFillArcs,
110 * and after, ADAPT_CHECKS XFillRectangle.
111 * We check which method seems better, knowing that
112 * XFillArcs is generally visually better. So we
113 * consider that XFillArcs is still better if its time
114 * is about XFillRectangle * ADAPT_ARC_PREFERED
115 * We need gettimeofday
116 * for this... Does it exist on other systems ? Do we
117 * have to use another function for others ?
118 * This value overrides USEOLDXARCS.
123 # include "../xvmsutils/unix_time.h"
125 # include <X11/unix_time.h>
129 #include <sys/time.h>
131 #define ADAPT_CHECKS 50
132 #define ADAPT_ARC_PREFERED 150 /* Maybe the value that is the most important
133 * for adapting to a system */
136 #define dtor(x) (((x) * M_PI) / 180.0) /* Degrees to radians */
140 /* jwz: I think slower color changes look better */
141 #define COLOR_CHANGES 50 /* How often we change colors (1 = always)
142 * This value should be tuned accordingly to
143 * the number of stars */
144 #define MAX_SIZEX_SIZEY 2. /* This controls whether the sphere can be very
145 * very large and have a small height (or the
146 * opposite) or no. */
148 #define THETACANRAND 80 /* percentage of changes for the speed of
149 * change of the 3 theta values */
150 #define SIZECANRAND 80 /* percentage of changes for the speed of
151 * change of the sizex and sizey values */
152 #define POSCANRAND 80 /* percentage of changes for the speed of
153 * change of the x and y values */
154 /* Note that these XXXCANRAND values can be 0, that is no rand acceleration *
157 #define VARRANDALPHA (NRAND((int) (M_PI * 1000.0))/1000.0)
158 #define VARRANDSTEP (M_PI/(NRAND(100)+100.0))
159 #define VARRANDMIN (-70.0)
160 #define VARRANDMAX 70.0
162 #define MINZVAL 100 /* stars can come this close */
163 #define SCREENZ 2000 /* this is where the screen is */
164 #define MAXZVAL 10000 /* stars can go this far away */
166 #define GETZDIFF(z) ((MI_DELTA3D(mi))*20.0*(1.0-(SCREENZ)/(z+1000)))
167 #define MAXDIFF MAX(-GETZDIFF(MINZVAL),GETZDIFF(MAXZVAL))
169 /* These values are the variation parameters of the acceleration variation *
170 of the SinVariables that are randomized. */
172 /******************************/
173 typedef struct SinVariableStruct
174 /******************************/
177 * Alpha is the current state of the sinvariable
178 * alpha should be initialized to a value between
182 * Speed of evolution of alpha. It should be a reasonable
183 * fraction of 2 * M_PI. This value directly influence
184 * the variable speed of variation.
186 double minimum; /* Minimum value for the variable */
187 double maximum; /* Maximum value for the variable */
188 double value; /* Current value */
189 int mayrand; /* Flag for knowing whether some randomization can be
190 * applied to the variable */
191 struct SinVariableStruct *varrand; /* Evolving Variable: the variation of
195 /***********************/
196 typedef struct StarStruct
197 /***********************/
199 double x, y, z; /* Position of the star */
200 short size; /* Try to guess */
203 /****************************/
204 typedef struct StarFieldStruct
205 /****************************/
207 short width, height; /* width and height of the starfield window */
208 short max_star_size; /* Maximum radius for stars. stars radius will
209 * vary from 1 to MAX_STAR_SIZE */
210 SinVariable x; /* Evolving variables: */
211 SinVariable y; /* Center of the field on the screen */
213 SinVariable sizex; /* Evolving variable: half width of the field */
214 SinVariable sizey; /* Evolving variable: half height of the field */
215 SinVariable thetax; /* Evolving Variables: */
216 SinVariable thetay; /* rotation angles of the starfield */
217 SinVariable thetaz; /* around x, y and z local axis */
218 Star *star; /* List of stars */
219 XArc *xarc; /* Current List of arcs */
220 XArc *xarcleft; /* additional list for the left arcs */
221 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
222 XArc *oldxarc; /* Old list of arcs */
225 unsigned long color; /* Current color of the starfield */
226 int colorp; /* Pointer to color of the starfield */
227 int NbStars; /* Number of stars */
228 short colorchange; /* Counter for the color change */
229 #if (ADAPT_ERASE == 1)
230 short hasbeenchecked;
236 static StarField *starfield = NULL;
240 sinvary(SinVariable * v)
244 v->value = v->minimum +
245 (v->maximum - v->minimum) * (sin(v->alpha) + 1.0) / 2.0;
250 int vaval = NRAND(100);
252 if (vaval <= v->mayrand)
254 v->alpha += (100.0 + (v->varrand->value)) * v->step / 100.0;
257 if (v->alpha > 2 * M_PI)
258 v->alpha -= 2 * M_PI;
261 /*************************************************/
263 sininit(SinVariable * v,
264 double alpha, double step, double minimum, double maximum,
269 v->minimum = minimum;
270 v->maximum = maximum;
271 v->mayrand = mayrand;
273 if (v->varrand == NULL)
274 v->varrand = (SinVariable *) calloc(1, sizeof (SinVariable));
283 /* We calculate the values at least once for initialization */
288 sinfree(SinVariable * point)
290 SinVariable *temp, *next;
292 next = point->varrand;
295 next = temp->varrand;
296 (void) free((void *) temp);
303 init_bouboule(ModeInfo * mi)
307 * The stars init part was first inspirated from the net3d game starfield
308 * code. But net3d starfield is not really 3d starfield, and I needed real 3d,
309 * so only remains the net3d starfield initialization main idea, that is
310 * the stars distribution on a sphere (theta and omega computing)
314 int size = MI_SIZE(mi);
318 if (starfield == NULL) {
319 if ((starfield = (StarField *) calloc(MI_NUM_SCREENS(mi),
320 sizeof (StarField))) == NULL)
323 sp = &starfield[MI_SCREEN(mi)];
325 sp->width = MI_WIN_WIDTH(mi);
326 sp->height = MI_WIN_HEIGHT(mi);
328 /* use the right `black' pixel values: */
329 if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) {
330 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi));
331 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
332 0, 0, sp->width, sp->height);
334 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
337 sp->max_star_size = NRAND(-size - MINSIZE + 1) + MINSIZE;
338 else if (size < MINSIZE)
339 sp->max_star_size = MINSIZE;
341 sp->max_star_size = size;
343 sp->NbStars = MI_BATCHCOUNT(mi);
344 if (sp->NbStars < -MINSTARS) {
346 (void) free((void *) sp->star);
350 (void) free((void *) sp->xarc);
354 (void) free((void *) sp->xarcleft);
357 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
359 (void) free((void *) sp->oldxarc);
362 if (sp->oldxarcleft) {
363 (void) free((void *) sp->oldxarcleft);
364 sp->oldxarcleft = NULL;
367 sp->NbStars = NRAND(-sp->NbStars - MINSTARS + 1) + MINSTARS;
368 } else if (sp->NbStars < MINSTARS)
369 sp->NbStars = MINSTARS;
371 /* We get memory for lists of objects */
372 if (sp->star == NULL)
373 sp->star = (Star *) malloc(sp->NbStars * sizeof (Star));
374 if (sp->xarc == NULL)
375 sp->xarc = (XArc *) malloc(sp->NbStars * sizeof (XArc));
376 if (MI_WIN_IS_USE3D(mi) && sp->xarcleft == NULL)
377 sp->xarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc));
378 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
379 if (sp->oldxarc == NULL)
380 sp->oldxarc = (XArc *) malloc(sp->NbStars * sizeof (XArc));
381 if (MI_WIN_IS_USE3D(mi) && sp->oldxarcleft == NULL)
382 sp->oldxarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc));
386 /* We initialize evolving variables */
388 NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
389 ((double) sp->width) / 4.0,
390 3.0 * ((double) sp->width) / 4.0,
393 NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
394 ((double) sp->height) / 4.0,
395 3.0 * ((double) sp->height) / 4.0,
398 /* for z, we have to ensure that the bouboule does not get behind */
399 /* the eyes of the viewer. His/Her eyes are at 0. Because the */
400 /* bouboule uses the x-radius for the z-radius, too, we have to */
401 /* use the x-values. */
403 NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
404 ((double) sp->width / 2.0 + MINZVAL),
405 ((double) sp->width / 2.0 + MAXZVAL),
410 NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
411 MIN(((double) sp->width) - sp->x.value,
413 MIN(((double) sp->width) - sp->x.value,
418 NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
419 MAX(sp->sizex.value / MAX_SIZEX_SIZEY,
420 sp->sizey.maximum / 5.0),
421 MIN(sp->sizex.value * MAX_SIZEX_SIZEY,
422 MIN(((double) sp->height) -
428 NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
432 NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
436 NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0),
440 for (i = 0; i < sp->NbStars; i++) {
442 XArc *arc = NULL, *arcleft = NULL;
443 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
444 XArc *oarc = NULL, *oarcleft = NULL;
447 star = &(sp->star[i]);
448 arc = &(sp->xarc[i]);
449 if (MI_WIN_IS_USE3D(mi))
450 arcleft = &(sp->xarcleft[i]);
451 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
452 oarc = &(sp->oldxarc[i]);
453 if (MI_WIN_IS_USE3D(mi))
454 oarcleft = &(sp->oldxarcleft[i]);
456 /* Elevation and bearing of the star */
457 theta = dtor((NRAND(1800)) / 10.0 - 90.0);
458 omega = dtor((NRAND(3600)) / 10.0 - 180.0);
460 /* Stars coordinates in a 3D space */
461 star->x = cos(theta) * sin(omega);
462 star->y = sin(omega) * sin(theta);
463 star->z = cos(omega);
465 /* We set the stars size */
466 star->size = NRAND(2 * sp->max_star_size);
467 if (star->size < sp->max_star_size)
470 star->size -= sp->max_star_size;
472 /* We set default values for the XArc lists elements */
474 if (MI_WIN_IS_USE3D(mi)) {
475 arcleft->x = arcleft->y = 0;
477 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
478 oarc->x = oarc->y = 0;
479 if (MI_WIN_IS_USE3D(mi)) {
480 oarcleft->x = oarcleft->y = 0;
483 arc->width = 2 + star->size;
484 arc->height = 2 + star->size;
485 if (MI_WIN_IS_USE3D(mi)) {
486 arcleft->width = 2 + star->size;
487 arcleft->height = 2 + star->size;
489 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
490 oarc->width = 2 + star->size;
491 oarc->height = 2 + star->size;
492 if (MI_WIN_IS_USE3D(mi)) {
493 oarcleft->width = 2 + star->size;
494 oarcleft->height = 2 + star->size;
499 arc->angle2 = 360 * 64;
500 if (MI_WIN_IS_USE3D(mi)) {
502 arcleft->angle2 = 360 * 64;
504 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
506 oarc->angle2 = 360 * 64; /* ie. we draw whole disks:
507 * from 0 to 360 degrees */
508 if (MI_WIN_IS_USE3D(mi)) {
509 oarcleft->angle1 = 0;
510 oarcleft->angle2 = 360 * 64;
515 if (MI_NPIXELS(mi) > 2)
516 sp->colorp = NRAND(MI_NPIXELS(mi));
517 /* We set up the starfield color */
518 if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2)
519 sp->color = MI_PIXEL(mi, sp->colorp);
521 sp->color = MI_WIN_WHITE_PIXEL(mi);
523 #if (ADAPT_ERASE == 1)
524 /* We initialize the adaptation code for screen erasing */
525 sp->hasbeenchecked = ADAPT_CHECKS * 2;
533 draw_bouboule(ModeInfo * mi)
537 Display *display = MI_DISPLAY(mi);
538 Window window = MI_WINDOW(mi);
540 StarField *sp = &starfield[MI_SCREEN(mi)];
542 double CX, CY, CZ, SX, SY, SZ;
544 XArc *arc = NULL, *arcleft = NULL;
546 #ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
547 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
550 #if (ADAPT_ERASE == 1)
556 #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1))
557 short x_1, y_1, x_2, y_2;
559 /* bounding rectangle around the old starfield,
560 * for erasing with the smallest rectangle
561 * instead of filling the whole screen */
562 int maxdiff = 0; /* maximal distance between left and right */
564 /* star in 3d mode, otherwise 0 */
567 #if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1))
568 if (MI_WIN_IS_USE3D(mi)) {
569 maxdiff = (int) MAXDIFF;
571 x_1 = (int) sp->x.value - (int) sp->sizex.value -
572 sp->max_star_size - maxdiff;
573 y_1 = (int) sp->y.value - (int) sp->sizey.value -
575 x_2 = 2 * ((int) sp->sizex.value + sp->max_star_size + maxdiff);
576 y_2 = 2 * ((int) sp->sizey.value + sp->max_star_size);
578 /* We make variables vary. */
579 sinvary(&sp->thetax);
580 sinvary(&sp->thetay);
581 sinvary(&sp->thetaz);
585 if (MI_WIN_IS_USE3D(mi))
588 /* A little trick to prevent the bouboule from being
589 * bigger than the screen */
591 MIN(((double) sp->width) - sp->x.value,
593 sp->sizex.minimum = sp->sizex.maximum / 3.0;
595 /* Another trick to make the ball not too flat */
597 MAX(sp->sizex.value / MAX_SIZEX_SIZEY,
598 sp->sizey.maximum / 3.0);
600 MIN(sp->sizex.value * MAX_SIZEX_SIZEY,
601 MIN(((double) sp->height) - sp->y.value,
608 * We calculate the rotation matrix values. We just make the
609 * rotation on the fly, without using a matrix.
610 * Star positions are recorded as unit vectors pointing in various
611 * directions. We just make them all rotate.
613 CX = cos(sp->thetax.value);
614 SX = sin(sp->thetax.value);
615 CY = cos(sp->thetay.value);
616 SY = sin(sp->thetay.value);
617 CZ = cos(sp->thetaz.value);
618 SZ = sin(sp->thetaz.value);
620 for (i = 0; i < sp->NbStars; i++) {
621 star = &(sp->star[i]);
622 arc = &(sp->xarc[i]);
623 if (MI_WIN_IS_USE3D(mi)) {
624 arcleft = &(sp->xarcleft[i]);
625 /* to help the eyes, the starfield is always as wide as */
626 /* deep, so .sizex.value can be used. */
627 diff = (int) GETZDIFF(sp->sizex.value *
628 ((SY * CX) * star->x + (SX) * star->y +
629 (CX * CY) * star->z) + sp->z.value);
631 arc->x = (short) ((sp->sizex.value *
632 ((CY * CZ - SX * SY * SZ) * star->x +
633 (-CX * SZ) * star->y +
634 (SY * CZ + SZ * SX * CY) * star->z) +
636 arc->y = (short) ((sp->sizey.value *
637 ((CY * SZ + SX * SY * CZ) * star->x +
638 (CX * CZ) * star->y +
639 (SY * SZ - SX * CY * CZ) * star->z) +
642 if (MI_WIN_IS_USE3D(mi)) {
643 arcleft->x = (short) ((sp->sizex.value *
644 ((CY * CZ - SX * SY * SZ) * star->x +
645 (-CX * SZ) * star->y +
646 (SY * CZ + SZ * SX * CY) * star->z) +
648 arcleft->y = (short) ((sp->sizey.value *
649 ((CY * SZ + SX * SY * CZ) * star->x +
650 (CX * CZ) * star->y +
651 (SY * SZ - SX * CY * CZ) * star->z) +
656 if (star->size != 0) {
657 arc->x -= star->size;
658 arc->y -= star->size;
659 if (MI_WIN_IS_USE3D(mi)) {
660 arcleft->x -= star->size;
661 arcleft->y -= star->size;
666 /* First, we erase the previous starfield */
667 if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi))
668 XSetForeground(display, gc, MI_NONE_COLOR(mi));
670 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
672 #if (ADAPT_ERASE == 1)
673 if (sp->hasbeenchecked == 0) {
674 /* We just calculate which method is the faster and eventually free
675 * the oldxarc list */
677 ADAPT_ARC_PREFERED * sp->rect_time) {
678 sp->hasbeenchecked = -2; /* XFillRectangle mode */
679 (void) free((void *) sp->oldxarc);
681 if (MI_WIN_IS_USE3D(mi)) {
682 (void) free((void *) sp->oldxarcleft);
683 sp->oldxarcleft = NULL;
686 sp->hasbeenchecked = -1; /* XFillArcs mode */
689 if (sp->hasbeenchecked == -2) {
690 /* Erasing is done with XFillRectangle */
691 XFillRectangle(display, window, gc,
693 } else if (sp->hasbeenchecked == -1) {
694 /* Erasing is done with XFillArcs */
695 XFillArcs(display, window, gc,
696 sp->oldxarc, sp->NbStars);
697 if (MI_WIN_IS_USE3D(mi))
698 XFillArcs(display, window, gc,
699 sp->oldxarcleft, sp->NbStars);
703 if (sp->hasbeenchecked > ADAPT_CHECKS) {
704 #ifdef GETTIMEOFDAY_TWO_ARGS
705 (void) gettimeofday(&tv1, NULL);
707 (void) gettimeofday(&tv1);
709 XFillRectangle(display, window, gc,
711 #ifdef GETTIMEOFDAY_TWO_ARGS
712 (void) gettimeofday(&tv2, NULL);
714 (void) gettimeofday(&tv2);
716 usec = (tv2.tv_sec - tv1.tv_sec) * 1000000;
717 if (usec + tv2.tv_usec - tv1.tv_usec > 0) {
718 sp->rect_time += usec + tv2.tv_usec - tv1.tv_usec;
719 sp->hasbeenchecked--;
722 #ifdef GETTIMEOFDAY_TWO_ARGS
723 (void) gettimeofday(&tv1, NULL);
725 (void) gettimeofday(&tv1);
727 XFillArcs(display, window, gc,
728 sp->oldxarc, sp->NbStars);
729 if (MI_WIN_IS_USE3D(mi))
730 XFillArcs(display, window, gc,
731 sp->oldxarcleft, sp->NbStars);
732 #ifdef GETTIMEOFDAY_TWO_ARGS
733 (void) gettimeofday(&tv2, NULL);
735 (void) gettimeofday(&tv2);
737 usec = (tv2.tv_sec - tv1.tv_sec) * 1000000;
738 if (usec + tv2.tv_usec - tv1.tv_usec > 0) {
739 sp->xarc_time += usec + tv2.tv_usec - tv1.tv_usec;
740 sp->hasbeenchecked--;
745 #if (USEOLDXARCS == 1)
746 XFillArcs(display, window, gc,
747 sp->oldxarc, sp->NbStars);
748 if (MI_WIN_IS_USE3D(mi))
749 XFillArcs(display, window, gc,
750 sp->oldxarcleft, sp->NbStars);
752 XFillRectangle(display, window, gc,
757 /* Then we draw the new one */
758 if (MI_WIN_IS_USE3D(mi)) {
759 if (MI_WIN_IS_INSTALL(mi))
760 XSetFunction(display, gc, GXor);
761 XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
762 XFillArcs(display, window, gc, sp->xarc, sp->NbStars);
763 XSetForeground(display, gc, MI_LEFT_COLOR(mi));
764 XFillArcs(display, window, gc, sp->xarcleft, sp->NbStars);
765 if (MI_WIN_IS_INSTALL(mi))
766 XSetFunction(display, gc, GXcopy);
768 XSetForeground(display, gc, sp->color);
769 XFillArcs(display, window, gc, sp->xarc, sp->NbStars);
772 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
773 #if (ADAPT_ERASE == 1)
774 if (sp->hasbeenchecked >= -1) {
776 sp->xarc = sp->oldxarc;
778 if (MI_WIN_IS_USE3D(mi)) {
779 arcleft = sp->xarcleft;
780 sp->xarcleft = sp->oldxarcleft;
781 sp->oldxarcleft = arcleft;
786 sp->xarc = sp->oldxarc;
788 if (MI_WIN_IS_USE3D(mi)) {
789 arcleft = sp->xarcleft;
790 sp->xarcleft = sp->oldxarcleft;
791 sp->oldxarcleft = arcleft;
796 /* We set up the color for the next drawing */
797 if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2 &&
798 (++sp->colorchange >= COLOR_CHANGES)) {
800 if (++sp->colorp >= MI_NPIXELS(mi))
802 sp->color = MI_PIXEL(mi, sp->colorp);
807 release_bouboule(ModeInfo * mi)
809 if (starfield != NULL) {
812 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
813 StarField *sp = &starfield[screen];
816 (void) free((void *) sp->star);
818 (void) free((void *) sp->xarc);
820 (void) free((void *) sp->xarcleft);
821 #if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
823 (void) free((void *) sp->oldxarc);
825 (void) free((void *) sp->oldxarcleft);
830 sinfree(&(sp->sizex));
831 sinfree(&(sp->sizey));
832 sinfree(&(sp->thetax));
833 sinfree(&(sp->thetay));
834 sinfree(&(sp->thetaz));
836 (void) free((void *) starfield);
842 reshape_bouboule(ModeInfo * mi, int width, int height)
844 StarField *sp = &starfield[MI_SCREEN(mi)];
848 sp->x.alpha, sp->x.step,
849 ((double) sp->width) / 4.0,
850 3.0 * ((double) sp->width) / 4.0,
853 sp->y.alpha, sp->y.step,
854 ((double) sp->height) / 4.0,
855 3.0 * ((double) sp->height) / 4.0,
860 refresh_bouboule(ModeInfo * mi)
862 /* Do nothing, it will refresh by itself */
865 XSCREENSAVER_MODULE ("Bouboule", bouboule)