xenocara/app/xlockmore/modes/bouboule.c
2006-11-26 11:07:42 +00:00

912 lines
25 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* bouboule --- glob of spheres twisting and changing size */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)bouboule.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Copyright 1996 by Jeremie PETIT <petit@eurecom.fr>, <jpetit@essi.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
* 15-May-1997: jwz@jwz.org: turned into a standalone program.
* 04-Sep-1996: Added 3d support Henrik Theiling <theiling@coli-uni-sb.de>
* 20-Feb-1996: Added tests so that already malloced objects are not
* malloced twice, thanks to the report from
* <mccomb@interport.net>
* 01-Feb-1996: Patched by Jouk Jansen <joukj@hrem.stm.tudelft.nl> for VMS
* Patched by <bagleyd@tux.org> for TrueColor displays
* 30-Jan-1996: Wrote all that I wanted to.
*
* Sort of starfield with a 3D engine. 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.
*
* Use: batchcount is the number of stars.
* cycles is the maximum size for a star
*
* 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 MODE_bouboule
#define PROGCLASS "Bouboule"
#define HACK_INIT init_bouboule
#define HACK_DRAW draw_bouboule
#define bouboule_opts xlockmore_opts
#define DEFAULTS "*delay: 10000 \n" \
"*count: 100 \n" \
"*size: 15 \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_bouboule
ModeSpecOpt bouboule_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
const ModStruct bouboule_description =
{"bouboule", "init_bouboule", "draw_bouboule", "release_bouboule",
"refresh_bouboule", "init_bouboule", (char *) NULL, &bouboule_opts,
10000, 100, 1, 15, 64, 1.0, "",
"Shows Mimi's bouboule of moving stars", 0, NULL};
#endif
#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 <X11/unix_time.h>
#endif
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#endif
#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
#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 = (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 Bool
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) {
if ((v->varrand = (SinVariable *) calloc(1,
sizeof (SinVariable))) == NULL) {
return False;
}
}
if (!sininit(v->varrand,
VARRANDALPHA,
VARRANDSTEP,
VARRANDMIN,
VARRANDMAX,
0))
return False;
sinvary(v->varrand);
}
/* We calculate the values at least once for initialization */
sinvary(v);
return True;
}
static void
sinfree(SinVariable * point)
{
SinVariable *temp, *next;
next = point->varrand;
while (next) {
temp = next;
next = temp->varrand;
free(temp);
}
}
static void
free_stars(StarField *sp)
{
if (sp->star != NULL) {
free(sp->star);
sp->star = (Star *) NULL;
}
if (sp->xarc != NULL) {
free(sp->xarc);
sp->xarc = (XArc *) NULL;
}
if (sp->xarcleft != NULL) {
free(sp->xarcleft);
sp->xarcleft = (XArc *) NULL;
}
#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
if (sp->oldxarc != NULL) {
free(sp->oldxarc);
sp->oldxarc = (XArc *) NULL;
}
if (sp->oldxarcleft != NULL) {
free(sp->oldxarcleft);
sp->oldxarcleft = (XArc *) NULL;
}
#endif
}
static void
free_bouboule(StarField *sp)
{
free_stars(sp);
sinfree(&(sp->x));
sinfree(&(sp->y));
sinfree(&(sp->z));
sinfree(&(sp->sizex));
sinfree(&(sp->sizey));
sinfree(&(sp->thetax));
sinfree(&(sp->thetay));
sinfree(&(sp->thetaz));
}
/***************/
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 (starfield == NULL) {
if ((starfield = (StarField *) calloc(MI_NUM_SCREENS(mi),
sizeof (StarField))) == NULL)
return;
}
sp = &starfield[MI_SCREEN(mi)];
sp->width = MI_WIDTH(mi);
sp->height = MI_HEIGHT(mi);
/* use the right `black' pixel values: */
if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) {
MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi));
} else {
MI_CLEARWINDOW(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_COUNT(mi);
if (sp->NbStars < -MINSTARS) {
free_stars(sp);
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) {
if ((sp->star = (Star *) malloc(sp->NbStars *
sizeof (Star))) == NULL) {
free_bouboule(sp);
return;
}
}
if (sp->xarc == NULL) {
if ((sp->xarc = (XArc *) malloc(sp->NbStars *
sizeof (XArc))) == NULL) {
free_bouboule(sp);
return;
}
}
if (MI_IS_USE3D(mi) && sp->xarcleft == NULL) {
if ((sp->xarcleft = (XArc *) malloc(sp->NbStars *
sizeof (XArc))) == NULL) {
free_bouboule(sp);
return;
}
}
#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
if (sp->oldxarc == NULL) {
if ((sp->oldxarc = (XArc *) malloc(sp->NbStars *
sizeof (XArc))) == NULL) {
free_bouboule(sp);
return;
}
}
if (MI_IS_USE3D(mi) && sp->oldxarcleft == NULL) {
if ((sp->oldxarcleft = (XArc *) malloc(sp->NbStars *
sizeof (XArc))) == NULL) {
free_bouboule(sp);
return;
}
}
#endif
{
/* We initialize evolving variables */
if (!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)) {
free_bouboule(sp);
return;
}
if (!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)) {
free_bouboule(sp);
return;
}
/* 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. */
if (!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)) {
free_bouboule(sp);
return;
}
if (!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)) {
free_bouboule(sp);
return;
}
if (!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)) {
free_bouboule(sp);
return;
}
if (!sininit(&sp->thetax,
NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
-M_PI, M_PI,
THETACANRAND)) {
free_bouboule(sp);
return;
}
if (!sininit(&sp->thetay,
NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0),
-M_PI, M_PI,
THETACANRAND)) {
free_bouboule(sp);
return;
}
if (!sininit(&sp->thetaz,
NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0),
-M_PI, M_PI,
THETACANRAND)) {
free_bouboule(sp);
return;
}
}
for (i = 0; i < sp->NbStars; i++) {
Star *star;
XArc *arc, *arcleft = (XArc *) NULL;
#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
XArc *oarc, *oarcleft = (XArc *) NULL;
#endif
star = &(sp->star[i]);
arc = &(sp->xarc[i]);
if (MI_IS_USE3D(mi))
arcleft = &(sp->xarcleft[i]);
#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
oarc = &(sp->oldxarc[i]);
if (MI_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, but offscreen */
arc->x = MI_WIDTH(mi);
arc->y = MI_HEIGHT(mi);
if (MI_IS_USE3D(mi)) {
arcleft->x = MI_WIDTH(mi);
arcleft->y = MI_HEIGHT(mi);
}
#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1))
oarc->x = MI_WIDTH(mi);
oarc->y = MI_HEIGHT(mi);
if (MI_IS_USE3D(mi)) {
oarcleft->x = MI_WIDTH(mi);
oarcleft->y = MI_HEIGHT(mi);
}
#endif
arc->width = 2 + star->size;
arc->height = 2 + star->size;
if (MI_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_IS_USE3D(mi)) {
oarcleft->width = 2 + star->size;
oarcleft->height = 2 + star->size;
}
#endif
arc->angle1 = 0;
arc->angle2 = 360 * 64;
if (MI_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_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_IS_USE3D(mi) && MI_NPIXELS(mi) > 2)
sp->color = MI_PIXEL(mi, sp->colorp);
else
sp->color = MI_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
}
/****************/
void
draw_bouboule(ModeInfo * mi)
/****************/
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
int i, diff = 0;
double CX, CY, CZ, SX, SY, SZ;
Star *star;
XArc *arc, *arcleft = (XArc *) NULL;
StarField *sp;
#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 (starfield == NULL)
return;
sp = &starfield[MI_SCREEN(mi)];
if (sp->star == NULL)
return;
MI_IS_DRAWN(mi) = True;
#if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1))
if (MI_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_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_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_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_IS_USE3D(mi)) {
arcleft->x -= star->size;
arcleft->y -= star->size;
}
}
}
/* First, we erase the previous starfield */
if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi))
XSetForeground(display, gc, MI_NONE_COLOR(mi));
else
XSetForeground(display, gc, MI_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 */
free(sp->oldxarc);
sp->oldxarc = (XArc *) NULL;
if (MI_IS_USE3D(mi)) {
free(sp->oldxarcleft);
sp->oldxarcleft = (XArc *) 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_IS_USE3D(mi))
XFillArcs(display, window, gc,
sp->oldxarcleft, sp->NbStars);
} else {
long usec;
if (sp->hasbeenchecked > ADAPT_CHECKS) {
GETTIMEOFDAY(&tv1);
XFillRectangle(display, window, gc,
x_1, y_1, x_2, y_2);
GETTIMEOFDAY(&tv2);
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 {
GETTIMEOFDAY(&tv1);
XFillArcs(display, window, gc,
sp->oldxarc, sp->NbStars);
if (MI_IS_USE3D(mi))
XFillArcs(display, window, gc,
sp->oldxarcleft, sp->NbStars);
GETTIMEOFDAY(&tv2);
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_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_IS_USE3D(mi)) {
if (MI_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_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_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_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_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);
}
}
void
release_bouboule(ModeInfo * mi)
{
if (starfield != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_bouboule(&starfield[screen]);
free(starfield);
starfield = (StarField *) NULL;
}
}
void
refresh_bouboule(ModeInfo * mi)
{
/* use the right `black' pixel values: */
if (MI_IS_INSTALL(mi) && MI_IS_USE3D(mi)) {
MI_CLEARWINDOWCOLOR(mi, MI_NONE_COLOR(mi));
} else {
MI_CLEARWINDOW(mi);
}
}
#endif /* MODE_bouboule */