Пример #1
0
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);
	}
}
Пример #2
0
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);
	}
}
Пример #3
0
ENTRYPOINT void
init_worm (ModeInfo * mi)
{
	wormstruct *wp;
	int         size = MI_SIZE(mi);
	int         i, j;

	if (worms == NULL) {
		if ((worms = (wormstruct *) calloc(MI_NUM_SCREENS(mi),
					       sizeof (wormstruct))) == NULL)
			return;
	}
	wp = &worms[MI_SCREEN(mi)];
	if (MI_NPIXELS(mi) <= 2 || MI_WIN_IS_USE3D(mi))
		wp->nc = 2;
	else
		wp->nc = MI_NPIXELS(mi);
	if (wp->nc > NUMCOLORS)
		wp->nc = NUMCOLORS;

	free_worms(wp);
	wp->nw = MI_BATCHCOUNT(mi);
	if (wp->nw < -MINWORMS)
		wp->nw = NRAND(-wp->nw - MINWORMS + 1) + MINWORMS;
	else if (wp->nw < MINWORMS)
		wp->nw = MINWORMS;
	if (!wp->worm)
		wp->worm = (wormstuff *) malloc(wp->nw * sizeof (wormstuff));

	if (!wp->size)
		wp->size = (int *) malloc(NUMCOLORS * sizeof (int));

	wp->maxsize = (REDRAWSTEP + 1) * wp->nw;	/*  / wp->nc + 1; */
	if (!wp->rects)
		wp->rects =
			(XRectangle *) malloc(wp->maxsize * NUMCOLORS * sizeof (XRectangle));


	if (!init_table) {
		init_table = 1;
		for (i = 0; i < SEGMENTS; i++) {
			sintab[i] = SINF(i * 2.0 * M_PI / SEGMENTS);
			costab[i] = COSF(i * 2.0 * M_PI / SEGMENTS);
		}
	}
	wp->xsize = MI_WIN_WIDTH(mi);
	wp->ysize = MI_WIN_HEIGHT(mi);
	wp->zsize = MAXZ - MINZ + 1;
	if (MI_NPIXELS(mi) > 2)
		wp->chromo = NRAND(MI_NPIXELS(mi));

	if (size < -MINSIZE)
		wp->circsize = NRAND(-size - MINSIZE + 1) + MINSIZE;
	else if (size < MINSIZE)
		wp->circsize = MINSIZE;
	else
		wp->circsize = size;

	for (i = 0; i < wp->nc; i++) {
		for (j = 0; j < wp->maxsize; j++) {
			wp->rects[i * wp->maxsize + j].width = wp->circsize;
			wp->rects[i * wp->maxsize + j].height = wp->circsize;

		}
	}
	(void) memset((char *) wp->size, 0, wp->nc * sizeof (int));

	wp->wormlength = (int) sqrt(wp->xsize + wp->ysize) *
		MI_CYCLES(mi) / 8;	/* Fudge this to something reasonable */
	for (i = 0; i < wp->nw; i++) {
		wp->worm[i].circ = (XPoint *) malloc(wp->wormlength * sizeof (XPoint));
		wp->worm[i].diffcirc = (int *) malloc(wp->wormlength * sizeof (int));

		for (j = 0; j < wp->wormlength; j++) {
			wp->worm[i].circ[j].x = wp->xsize / 2;
			wp->worm[i].circ[j].y = wp->ysize / 2;
			if (MI_WIN_IS_USE3D(mi))
				wp->worm[i].diffcirc[j] = 0;
		}
		wp->worm[i].dir = NRAND(SEGMENTS);
		wp->worm[i].dir2 = NRAND(SEGMENTS);
		wp->worm[i].tail = 0;
		wp->worm[i].x = wp->xsize / 2;
		wp->worm[i].y = wp->ysize / 2;
		wp->worm[i].z = SCREENZ - MINZ;
		wp->worm[i].redrawing = 0;
	}

	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, wp->xsize, wp->ysize);
	} else
		XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
}
Пример #4
0
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
}
Пример #5
0
static void
worm_doit(ModeInfo * mi, int which, unsigned long color)
{
	Display    *display = MI_DISPLAY(mi);
	Window      window = MI_WINDOW(mi);
	GC          gc = MI_GC(mi);
	wormstruct *wp = &worms[MI_SCREEN(mi)];
	wormstuff  *ws = &wp->worm[which];
	int         x, y, z;
	int         diff;

	ws->tail++;
	if (ws->tail == wp->wormlength)
		ws->tail = 0;

	x = ws->circ[ws->tail].x;
	y = ws->circ[ws->tail].y;

	if (MI_WIN_IS_USE3D(mi)) {
		diff = ws->diffcirc[ws->tail];
		if (MI_WIN_IS_INSTALL(mi)) {
			XSetForeground(display, gc, MI_NONE_COLOR(mi));
			XFillRectangle(display, window, gc, x - diff, y,
				       wp->circsize, wp->circsize);
			XFillRectangle(display, window, gc, x + diff, y,
				       wp->circsize, wp->circsize);
		} else {
			XClearArea(display, window, x - diff, y,
				   wp->circsize, wp->circsize, False);
			XClearArea(display, window, x + diff, y,
				   wp->circsize, wp->circsize, False);
		}
	} else
		XClearArea(display, window, x, y, wp->circsize, wp->circsize, False);

	if (LRAND() & 1)
		ws->dir = (ws->dir + 1) % SEGMENTS;
	else
		ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS;

	x = (ws->x + IRINT((float) wp->circsize * costab[ws->dir]) +
	     wp->xsize) % wp->xsize;
	y = (ws->y + IRINT((float) wp->circsize * sintab[ws->dir]) +
	     wp->ysize) % wp->ysize;

	ws->circ[ws->tail].x = x;
	ws->circ[ws->tail].y = y;
	ws->x = x;
	ws->y = y;

	if (MI_WIN_IS_USE3D(mi)) {
		if (LRAND() & 1)
			ws->dir2 = (ws->dir2 + 1) % SEGMENTS;
		else
			ws->dir2 = (ws->dir2 + SEGMENTS - 1) % SEGMENTS;
		/* for the z-axis the wrap-around looks bad, so worms should just turn around. */
		z = (int) (ws->z + wp->circsize * sintab[ws->dir2]);
		if (z < 0 || z >= wp->zsize)
			z = (int) (ws->z - wp->circsize * sintab[ws->dir2]);

		diff = (int) (GETZDIFF(z) + 0.5);	/* ROUND */
		ws->diffcirc[ws->tail] = diff;

		ws->z = z;

		/* right eye */
		color = 0;
		wp->rects[color * wp->maxsize + wp->size[color]].x = x + diff;
		wp->rects[color * wp->maxsize + wp->size[color]].y = y;
		wp->size[color]++;

		/* left eye */
		color = 1;
		wp->rects[color * wp->maxsize + wp->size[color]].x = x - diff;
		wp->rects[color * wp->maxsize + wp->size[color]].y = y;
		wp->size[color]++;

#if 0
		if (ws->redrawing) {	/* Too hard for now */
			int         j;

			for (j = 0; j < REDRAWSTEP; j++) {
				int         k = (ws->tail - ws->redrawpos + wp->wormlength)
				% wp->wormlength;

				color = 0;
				wp->rects[color * wp->maxsize + wp->size[color]].x =
					ws->circ[k].x + ws->diffcirc[k];
				wp->rects[color * wp->maxsize + wp->size[color]].y =
					ws->circ[k].y;
				wp->size[color]++;

				color = 1;
				wp->rects[color * wp->maxsize + wp->size[color]].x =
					ws->circ[k].x - ws->diffcirc[k];
				wp->rects[color * wp->maxsize + wp->size[color]].y =
					ws->circ[k].y;
				wp->size[color]++;

				if (++(ws->redrawpos) >= wp->wormlength) {
					ws->redrawing = 0;
					break;
				}
			}
		}
#endif

	} else {

		wp->rects[color * wp->maxsize + wp->size[color]].x = x;
		wp->rects[color * wp->maxsize + wp->size[color]].y = y;
		wp->size[color]++;
		if (ws->redrawing) {
			int         j;

			ws->redrawpos++;
			/* Compensates for the changed ws->tail
			   since the last callback. */

			for (j = 0; j < REDRAWSTEP; j++) {
				int         k = (ws->tail - ws->redrawpos + wp->wormlength)
				% wp->wormlength;

				wp->rects[color * wp->maxsize + wp->size[color]].x = ws->circ[k].x;
				wp->rects[color * wp->maxsize + wp->size[color]].y = ws->circ[k].y;
				wp->size[color]++;

				if (++(ws->redrawpos) >= wp->wormlength) {
					ws->redrawing = 0;
					break;
				}
			}
		}
	}
}