source: trunk/third/xscreensaver/hacks/bouboule.c @ 20148

Revision 20148, 24.9 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
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.
4
5   Original copyright notice from xlock.c:
6
7    * Copyright (c) 1988-91 by Patrick J. Naughton.
8    *
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.
14    *
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.
20 */
21
22#if 0
23static const char sccsid[] = "@(#)bouboule.c    4.00 97/01/01 xlockmore";
24#endif
25
26/*-
27 * bouboule.c (bouboule mode for xlockmore)
28 *
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.
33 *
34 *   Code Copyright 1996 by Jeremie PETIT (jeremie_petit@geocities.com)
35 *
36 *   Use: batchcount is the number of stars.
37 *        cycles is the maximum size for a star
38 *
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.
46 *
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.
59 *
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.
74 */
75
76#ifdef STANDALONE
77# define PROGCLASS                                      "Bouboule"
78# define HACK_INIT                                      init_bouboule
79# define HACK_DRAW                                      draw_bouboule
80# define bouboule_opts                          xlockmore_opts
81# define DEFAULTS       "*count:                100     \n"                     \
82                                        "*size:                 15      \n"                     \
83                                        "*delay:                5000    \n"                     \
84                                        "*ncolors:              64      \n"                     \
85                                        "*use3d:                False   \n"                     \
86                                        "*delta3d:              1.5             \n"                     \
87                                        "*right3d:              red             \n"                     \
88                                        "*left3d:               blue    \n"                     \
89                                        "*both3d:               magenta \n"                     \
90                                        "*none3d:               black   \n"
91
92# define SMOOTH_COLORS
93# include "xlockmore.h"                         /* from the xscreensaver distribution */
94#else  /* !STANDALONE */
95# include "xlock.h"                                     /* from the xlockmore distribution */
96#endif /* !STANDALONE */
97
98ModeSpecOpt bouboule_opts = {
99  0, NULL, 0, NULL, NULL };
100
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
106                                 */
107
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.
119                                 */
120
121#ifdef USE_XVMSUTILS
122# if 0
123#  include "../xvmsutils/unix_time.h"
124# else
125#  include <X11/unix_time.h>
126# endif
127#endif
128
129#include <sys/time.h>
130
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 */
134#endif
135
136#define dtor(x)    (((x) * M_PI) / 180.0)       /* Degrees to radians */
137
138#define MINSTARS      1
139#define MINSIZE       1
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. */
147
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 *
155   variation. */
156
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
161
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 */
165
166#define GETZDIFF(z) ((MI_DELTA3D(mi))*20.0*(1.0-(SCREENZ)/(z+1000)))
167#define MAXDIFF  MAX(-GETZDIFF(MINZVAL),GETZDIFF(MAXZVAL))
168
169/* These values are the variation parameters of the acceleration variation *
170   of the SinVariables that are randomized. */
171
172/******************************/
173typedef struct SinVariableStruct
174/******************************/
175{
176        double      alpha;      /*
177                                 * Alpha is the current state of the sinvariable
178                                 * alpha should be initialized to a value between
179                                 * 0.0 and 2 * M_PI
180                                 */
181        double      step;       /*
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.
185                                 */
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
192                                                   * alpha */
193} SinVariable;
194
195/***********************/
196typedef struct StarStruct
197/***********************/
198{
199        double      x, y, z;    /* Position of the star */
200        short       size;       /* Try to guess */
201} Star;
202
203/****************************/
204typedef struct StarFieldStruct
205/****************************/
206{
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 */
212        SinVariable z;
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 */
223        XArc       *oldxarcleft;
224#endif
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;
231        long        rect_time;
232        long        xarc_time;
233#endif
234} StarField;
235
236static StarField *starfield = NULL;
237
238/*********/
239static void
240sinvary(SinVariable * v)
241/*********/
242
243{
244        v->value = v->minimum +
245                (v->maximum - v->minimum) * (sin(v->alpha) + 1.0) / 2.0;
246
247        if (v->mayrand == 0)
248                v->alpha += v->step;
249        else {
250                int         vaval = NRAND(100);
251
252                if (vaval <= v->mayrand)
253                        sinvary(v->varrand);
254                v->alpha += (100.0 + (v->varrand->value)) * v->step / 100.0;
255        }
256
257        if (v->alpha > 2 * M_PI)
258                v->alpha -= 2 * M_PI;
259}
260
261/*************************************************/
262static void
263sininit(SinVariable * v,
264        double alpha, double step, double minimum, double maximum,
265        short int mayrand)
266{
267        v->alpha = alpha;
268        v->step = step;
269        v->minimum = minimum;
270        v->maximum = maximum;
271        v->mayrand = mayrand;
272        if (mayrand != 0) {
273                if (v->varrand == NULL)
274                        v->varrand = (SinVariable *) calloc(1, sizeof (SinVariable));
275                sininit(v->varrand,
276                        VARRANDALPHA,
277                        VARRANDSTEP,
278                        VARRANDMIN,
279                        VARRANDMAX,
280                        0);
281                sinvary(v->varrand);
282        }
283        /* We calculate the values at least once for initialization */
284        sinvary(v);
285}
286
287static void
288sinfree(SinVariable * point)
289{
290        SinVariable *temp, *next;
291
292        next = point->varrand;
293        while (next) {
294                temp = next;
295                next = temp->varrand;
296                (void) free((void *) temp);
297        }
298}
299
300/***************/
301void
302init_bouboule(ModeInfo * mi)
303/***************/
304
305/*-
306 *  The stars init part was first inspirated from the net3d game starfield
307 * code.  But net3d starfield is not really 3d starfield, and I needed real 3d,
308 * so only remains the net3d starfield initialization main idea, that is
309 * the stars distribution on a sphere (theta and omega computing)
310 */
311{
312        StarField  *sp;
313        int         size = MI_SIZE(mi);
314        int         i;
315        double      theta, omega;
316
317        if (starfield == NULL) {
318                if ((starfield = (StarField *) calloc(MI_NUM_SCREENS(mi),
319                                                sizeof (StarField))) == NULL)
320                        return;
321        }
322        sp = &starfield[MI_SCREEN(mi)];
323
324        sp->width = MI_WIN_WIDTH(mi);
325        sp->height = MI_WIN_HEIGHT(mi);
326
327        /* use the right `black' pixel values: */
328        if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) {
329                XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi));
330                XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
331                               0, 0, sp->width, sp->height);
332        } else
333                XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
334
335        if (size < -MINSIZE)
336                sp->max_star_size = NRAND(-size - MINSIZE + 1) + MINSIZE;
337        else if (size < MINSIZE)
338                sp->max_star_size = MINSIZE;
339        else
340                sp->max_star_size = size;
341
342        sp->NbStars = MI_BATCHCOUNT(mi);
343        if (sp->NbStars < -MINSTARS) {
344                if (sp->star) {
345                        (void) free((void *) sp->star);
346                        sp->star = NULL;
347                }
348                if (sp->xarc) {
349                        (void) free((void *) sp->xarc);
350                        sp->xarc = NULL;
351                }
352                if (sp->xarcleft) {
353                        (void) free((void *) sp->xarcleft);
354                        sp->xarcleft = NULL;
355                }
356#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
357                if (sp->oldxarc) {
358                        (void) free((void *) sp->oldxarc);
359                        sp->oldxarc = NULL;
360                }
361                if (sp->oldxarcleft) {
362                        (void) free((void *) sp->oldxarcleft);
363                        sp->oldxarcleft = NULL;
364                }
365#endif
366                sp->NbStars = NRAND(-sp->NbStars - MINSTARS + 1) + MINSTARS;
367        } else if (sp->NbStars < MINSTARS)
368                sp->NbStars = MINSTARS;
369
370        /* We get memory for lists of objects */
371        if (sp->star == NULL)
372                sp->star = (Star *) malloc(sp->NbStars * sizeof (Star));
373        if (sp->xarc == NULL)
374                sp->xarc = (XArc *) malloc(sp->NbStars * sizeof (XArc));
375        if (MI_WIN_IS_USE3D(mi) && sp->xarcleft == NULL)
376                sp->xarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc));
377#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
378        if (sp->oldxarc == NULL)
379                sp->oldxarc = (XArc *) malloc(sp->NbStars * sizeof (XArc));
380        if (MI_WIN_IS_USE3D(mi) && sp->oldxarcleft == NULL)
381                sp->oldxarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc));
382#endif
383
384        {
385                /* We initialize evolving variables */
386                sininit(&sp->x,
387                        NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
388                        ((double) sp->width) / 4.0,
389                        3.0 * ((double) sp->width) / 4.0,
390                        POSCANRAND);
391                sininit(&sp->y,
392                        NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
393                        ((double) sp->height) / 4.0,
394                        3.0 * ((double) sp->height) / 4.0,
395                        POSCANRAND);
396
397                /* for z, we have to ensure that the bouboule does not get behind */
398                /* the eyes of the viewer.  His/Her eyes are at 0.  Because the */
399                /* bouboule uses the x-radius for the z-radius, too, we have to */
400                /* use the x-values. */
401                sininit(&sp->z,
402                        NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
403                        ((double) sp->width / 2.0 + MINZVAL),
404                        ((double) sp->width / 2.0 + MAXZVAL),
405                        POSCANRAND);
406
407
408                sininit(&sp->sizex,
409                        NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
410                        MIN(((double) sp->width) - sp->x.value,
411                            sp->x.value) / 5.0,
412                        MIN(((double) sp->width) - sp->x.value,
413                            sp->x.value),
414                        SIZECANRAND);
415
416                sininit(&sp->sizey,
417                        NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0),
418                        MAX(sp->sizex.value / MAX_SIZEX_SIZEY,
419                            sp->sizey.maximum / 5.0),
420                        MIN(sp->sizex.value * MAX_SIZEX_SIZEY,
421                            MIN(((double) sp->height) -
422                                sp->y.value,
423                                sp->y.value)),
424                        SIZECANRAND);
425
426                sininit(&sp->thetax,
427                        NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
428                        -M_PI, M_PI,
429                        THETACANRAND);
430                sininit(&sp->thetay,
431                        NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
432                        -M_PI, M_PI,
433                        THETACANRAND);
434                sininit(&sp->thetaz,
435                        NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0),
436                        -M_PI, M_PI,
437                        THETACANRAND);
438        }
439        for (i = 0; i < sp->NbStars; i++) {
440                Star       *star;
441                XArc       *arc = NULL, *arcleft = NULL;
442#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
443        XArc       *oarc = NULL, *oarcleft = NULL;
444#endif
445
446                star = &(sp->star[i]);
447                arc = &(sp->xarc[i]);
448                if (MI_WIN_IS_USE3D(mi))
449                        arcleft = &(sp->xarcleft[i]);
450#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
451                oarc = &(sp->oldxarc[i]);
452                if (MI_WIN_IS_USE3D(mi))
453                        oarcleft = &(sp->oldxarcleft[i]);
454#endif
455                /* Elevation and bearing of the star */
456                theta = dtor((NRAND(1800)) / 10.0 - 90.0);
457                omega = dtor((NRAND(3600)) / 10.0 - 180.0);
458
459                /* Stars coordinates in a 3D space */
460                star->x = cos(theta) * sin(omega);
461                star->y = sin(omega) * sin(theta);
462                star->z = cos(omega);
463
464                /* We set the stars size */
465                star->size = NRAND(2 * sp->max_star_size);
466                if (star->size < sp->max_star_size)
467                        star->size = 0;
468                else
469                        star->size -= sp->max_star_size;
470
471                /* We set default values for the XArc lists elements */
472                arc->x = arc->y = 0;
473                if (MI_WIN_IS_USE3D(mi)) {
474                        arcleft->x = arcleft->y = 0;
475                }
476#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
477                oarc->x = oarc->y = 0;
478                if (MI_WIN_IS_USE3D(mi)) {
479                        oarcleft->x = oarcleft->y = 0;
480                }
481#endif
482                arc->width = 2 + star->size;
483                arc->height = 2 + star->size;
484                if (MI_WIN_IS_USE3D(mi)) {
485                        arcleft->width = 2 + star->size;
486                        arcleft->height = 2 + star->size;
487                }
488#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
489                oarc->width = 2 + star->size;
490                oarc->height = 2 + star->size;
491                if (MI_WIN_IS_USE3D(mi)) {
492                        oarcleft->width = 2 + star->size;
493                        oarcleft->height = 2 + star->size;
494                }
495#endif
496
497                arc->angle1 = 0;
498                arc->angle2 = 360 * 64;
499                if (MI_WIN_IS_USE3D(mi)) {
500                        arcleft->angle1 = 0;
501                        arcleft->angle2 = 360 * 64;
502                }
503#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
504                oarc->angle1 = 0;
505                oarc->angle2 = 360 * 64;        /* ie. we draw whole disks:
506                                                 * from 0 to 360 degrees */
507                if (MI_WIN_IS_USE3D(mi)) {
508                        oarcleft->angle1 = 0;
509                        oarcleft->angle2 = 360 * 64;
510                }
511#endif
512        }
513
514        if (MI_NPIXELS(mi) > 2)
515                sp->colorp = NRAND(MI_NPIXELS(mi));
516        /* We set up the starfield color */
517        if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2)
518                sp->color = MI_PIXEL(mi, sp->colorp);
519        else
520                sp->color = MI_WIN_WHITE_PIXEL(mi);
521
522#if (ADAPT_ERASE == 1)
523        /* We initialize the adaptation code for screen erasing */
524        sp->hasbeenchecked = ADAPT_CHECKS * 2;
525        sp->rect_time = 0;
526        sp->xarc_time = 0;
527#endif
528}
529
530/****************/
531void
532draw_bouboule(ModeInfo * mi)
533/****************/
534
535{
536        Display    *display = MI_DISPLAY(mi);
537        Window      window = MI_WINDOW(mi);
538        GC          gc = MI_GC(mi);
539        StarField  *sp = &starfield[MI_SCREEN(mi)];
540        int         i, diff = 0;
541        double      CX, CY, CZ, SX, SY, SZ;
542        Star       *star;
543        XArc       *arc = NULL, *arcleft = NULL;
544
545#if (ADAPT_ERASE == 1)
546        struct timeval tv1;
547        struct timeval tv2;
548
549#endif
550
551#if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1))
552        short       x_1, y_1, x_2, y_2;
553
554        /* bounding rectangle around the old starfield,
555         * for erasing with the smallest rectangle
556         * instead of filling the whole screen */
557        int         maxdiff = 0;        /* maximal distance between left and right */
558
559        /* star in 3d mode, otherwise 0 */
560#endif
561
562#if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1))
563        if (MI_WIN_IS_USE3D(mi)) {
564                maxdiff = (int) MAXDIFF;
565        }
566        x_1 = (int) sp->x.value - (int) sp->sizex.value -
567                sp->max_star_size - maxdiff;
568        y_1 = (int) sp->y.value - (int) sp->sizey.value -
569                sp->max_star_size;
570        x_2 = 2 * ((int) sp->sizex.value + sp->max_star_size + maxdiff);
571        y_2 = 2 * ((int) sp->sizey.value + sp->max_star_size);
572#endif
573        /* We make variables vary. */
574        sinvary(&sp->thetax);
575        sinvary(&sp->thetay);
576        sinvary(&sp->thetaz);
577
578        sinvary(&sp->x);
579        sinvary(&sp->y);
580        if (MI_WIN_IS_USE3D(mi))
581                sinvary(&sp->z);
582
583        /* A little trick to prevent the bouboule from being
584         * bigger than the screen */
585        sp->sizex.maximum =
586                MIN(((double) sp->width) - sp->x.value,
587                    sp->x.value);
588        sp->sizex.minimum = sp->sizex.maximum / 3.0;
589
590        /* Another trick to make the ball not too flat */
591        sp->sizey.minimum =
592                MAX(sp->sizex.value / MAX_SIZEX_SIZEY,
593                    sp->sizey.maximum / 3.0);
594        sp->sizey.maximum =
595                MIN(sp->sizex.value * MAX_SIZEX_SIZEY,
596                    MIN(((double) sp->height) - sp->y.value,
597                        sp->y.value));
598
599        sinvary(&sp->sizex);
600        sinvary(&sp->sizey);
601
602        /*
603         * We calculate the rotation matrix values. We just make the
604         * rotation on the fly, without using a matrix.
605         * Star positions are recorded as unit vectors pointing in various
606         * directions. We just make them all rotate.
607         */
608        CX = cos(sp->thetax.value);
609        SX = sin(sp->thetax.value);
610        CY = cos(sp->thetay.value);
611        SY = sin(sp->thetay.value);
612        CZ = cos(sp->thetaz.value);
613        SZ = sin(sp->thetaz.value);
614
615        for (i = 0; i < sp->NbStars; i++) {
616                star = &(sp->star[i]);
617                arc = &(sp->xarc[i]);
618                if (MI_WIN_IS_USE3D(mi)) {
619                        arcleft = &(sp->xarcleft[i]);
620                        /* to help the eyes, the starfield is always as wide as */
621                        /* deep, so .sizex.value can be used. */
622                        diff = (int) GETZDIFF(sp->sizex.value *
623                                      ((SY * CX) * star->x + (SX) * star->y +
624                                       (CX * CY) * star->z) + sp->z.value);
625                }
626                arc->x = (short) ((sp->sizex.value *
627                                   ((CY * CZ - SX * SY * SZ) * star->x +
628                                    (-CX * SZ) * star->y +
629                                    (SY * CZ + SZ * SX * CY) * star->z) +
630                                   sp->x.value));
631                arc->y = (short) ((sp->sizey.value *
632                                   ((CY * SZ + SX * SY * CZ) * star->x +
633                                    (CX * CZ) * star->y +
634                                    (SY * SZ - SX * CY * CZ) * star->z) +
635                                   sp->y.value));
636
637                if (MI_WIN_IS_USE3D(mi)) {
638                        arcleft->x = (short) ((sp->sizex.value *
639                                        ((CY * CZ - SX * SY * SZ) * star->x +
640                                         (-CX * SZ) * star->y +
641                                         (SY * CZ + SZ * SX * CY) * star->z) +
642                                               sp->x.value));
643                        arcleft->y = (short) ((sp->sizey.value *
644                                        ((CY * SZ + SX * SY * CZ) * star->x +
645                                         (CX * CZ) * star->y +
646                                         (SY * SZ - SX * CY * CZ) * star->z) +
647                                               sp->y.value));
648                        arc->x += diff;
649                        arcleft->x -= diff;
650                }
651                if (star->size != 0) {
652                        arc->x -= star->size;
653                        arc->y -= star->size;
654                        if (MI_WIN_IS_USE3D(mi)) {
655                                arcleft->x -= star->size;
656                                arcleft->y -= star->size;
657                        }
658                }
659        }
660
661        /* First, we erase the previous starfield */
662        if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi))
663                XSetForeground(display, gc, MI_NONE_COLOR(mi));
664        else
665                XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
666
667#if (ADAPT_ERASE == 1)
668        if (sp->hasbeenchecked == 0) {
669                /* We just calculate which method is the faster and eventually free
670                 * the oldxarc list */
671                if (sp->xarc_time >
672                    ADAPT_ARC_PREFERED * sp->rect_time) {
673                        sp->hasbeenchecked = -2;        /* XFillRectangle mode */
674                        (void) free((void *) sp->oldxarc);
675                        sp->oldxarc = NULL;
676                        if (MI_WIN_IS_USE3D(mi)) {
677                                (void) free((void *) sp->oldxarcleft);
678                          sp->oldxarcleft = NULL;
679                        }
680                } else {
681                        sp->hasbeenchecked = -1;        /* XFillArcs mode */
682                }
683        }
684        if (sp->hasbeenchecked == -2) {
685                /* Erasing is done with XFillRectangle */
686                XFillRectangle(display, window, gc,
687                               x_1, y_1, x_2, y_2);
688        } else if (sp->hasbeenchecked == -1) {
689                /* Erasing is done with XFillArcs */
690                XFillArcs(display, window, gc,
691                          sp->oldxarc, sp->NbStars);
692                if (MI_WIN_IS_USE3D(mi))
693                        XFillArcs(display, window, gc,
694                                  sp->oldxarcleft, sp->NbStars);
695        } else {
696                long        usec;
697
698                if (sp->hasbeenchecked > ADAPT_CHECKS) {
699#ifdef GETTIMEOFDAY_TWO_ARGS
700                        (void) gettimeofday(&tv1, NULL);
701#else
702                        (void) gettimeofday(&tv1);
703#endif
704                        XFillRectangle(display, window, gc,
705                                       x_1, y_1, x_2, y_2);
706#ifdef GETTIMEOFDAY_TWO_ARGS
707                        (void) gettimeofday(&tv2, NULL);
708#else
709                        (void) gettimeofday(&tv2);
710#endif
711                        usec = (tv2.tv_sec - tv1.tv_sec) * 1000000;
712                        if (usec + tv2.tv_usec - tv1.tv_usec > 0) {
713                                sp->rect_time += usec + tv2.tv_usec - tv1.tv_usec;
714                                sp->hasbeenchecked--;
715                        }
716                } else {
717#ifdef GETTIMEOFDAY_TWO_ARGS
718                        (void) gettimeofday(&tv1, NULL);
719#else
720                        (void) gettimeofday(&tv1);
721#endif
722                        XFillArcs(display, window, gc,
723                                  sp->oldxarc, sp->NbStars);
724                        if (MI_WIN_IS_USE3D(mi))
725                                XFillArcs(display, window, gc,
726                                          sp->oldxarcleft, sp->NbStars);
727#ifdef GETTIMEOFDAY_TWO_ARGS
728                        (void) gettimeofday(&tv2, NULL);
729#else
730                        (void) gettimeofday(&tv2);
731#endif
732                        usec = (tv2.tv_sec - tv1.tv_sec) * 1000000;
733                        if (usec + tv2.tv_usec - tv1.tv_usec > 0) {
734                                sp->xarc_time += usec + tv2.tv_usec - tv1.tv_usec;
735                                sp->hasbeenchecked--;
736                        }
737                }
738        }
739#else
740#if (USEOLDXARCS == 1)
741        XFillArcs(display, window, gc,
742                  sp->oldxarc, sp->NbStars);
743        if (MI_WIN_IS_USE3D(mi))
744                XFillArcs(display, window, gc,
745                          sp->oldxarcleft, sp->NbStars);
746#else
747        XFillRectangle(display, window, gc,
748                       x_1, y_1, x_2, y_2);
749#endif
750#endif
751
752        /* Then we draw the new one */
753        if (MI_WIN_IS_USE3D(mi)) {
754                if (MI_WIN_IS_INSTALL(mi))
755                        XSetFunction(display, gc, GXor);
756                XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
757                XFillArcs(display, window, gc, sp->xarc, sp->NbStars);
758                XSetForeground(display, gc, MI_LEFT_COLOR(mi));
759                XFillArcs(display, window, gc, sp->xarcleft, sp->NbStars);
760                if (MI_WIN_IS_INSTALL(mi))
761                        XSetFunction(display, gc, GXcopy);
762        } else {
763                XSetForeground(display, gc, sp->color);
764                XFillArcs(display, window, gc, sp->xarc, sp->NbStars);
765        }
766
767#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
768#if (ADAPT_ERASE == 1)
769        if (sp->hasbeenchecked >= -1) {
770                arc = sp->xarc;
771                sp->xarc = sp->oldxarc;
772                sp->oldxarc = arc;
773                if (MI_WIN_IS_USE3D(mi)) {
774                        arcleft = sp->xarcleft;
775                        sp->xarcleft = sp->oldxarcleft;
776                        sp->oldxarcleft = arcleft;
777                }
778        }
779#else
780        arc = sp->xarc;
781        sp->xarc = sp->oldxarc;
782        sp->oldxarc = arc;
783        if (MI_WIN_IS_USE3D(mi)) {
784                arcleft = sp->xarcleft;
785                sp->xarcleft = sp->oldxarcleft;
786                sp->oldxarcleft = arcleft;
787        }
788#endif
789#endif
790
791        /* We set up the color for the next drawing */
792        if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2 &&
793            (++sp->colorchange >= COLOR_CHANGES)) {
794                sp->colorchange = 0;
795                if (++sp->colorp >= MI_NPIXELS(mi))
796                        sp->colorp = 0;
797                sp->color = MI_PIXEL(mi, sp->colorp);
798        }
799}
800
801void
802release_bouboule(ModeInfo * mi)
803{
804        if (starfield != NULL) {
805                int         screen;
806
807                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
808                        StarField  *sp = &starfield[screen];
809
810                        if (sp->star)
811                                (void) free((void *) sp->star);
812                        if (sp->xarc)
813                                (void) free((void *) sp->xarc);
814                        if (sp->xarcleft)
815                                (void) free((void *) sp->xarcleft);
816#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
817                        if (sp->oldxarc)
818                                (void) free((void *) sp->oldxarc);
819                        if (sp->oldxarcleft)
820                                (void) free((void *) sp->oldxarcleft);
821#endif
822                        sinfree(&(sp->x));
823                        sinfree(&(sp->y));
824                        sinfree(&(sp->z));
825                        sinfree(&(sp->sizex));
826                        sinfree(&(sp->sizey));
827                        sinfree(&(sp->thetax));
828                        sinfree(&(sp->thetay));
829                        sinfree(&(sp->thetaz));
830                }
831                (void) free((void *) starfield);
832                starfield = NULL;
833        }
834}
835
836void
837refresh_bouboule(ModeInfo * mi)
838{
839        /* Do nothing, it will refresh by itself */
840}
Note: See TracBrowser for help on using the repository browser.