324 lines
8.9 KiB
C
324 lines
8.9 KiB
C
/* -*- Mode: C; tab-width: 4 -*- */
|
|
/* daisy --- flowers in a field */
|
|
|
|
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)daisy.c 5.00 2000/11/01 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* Copyright (c) 1996 by David Bagley.
|
|
*
|
|
* 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
|
|
* 10-May-1997: Compatible with xscreensaver
|
|
* 07-Aug-1996: written. Initially copied forest.c and made continual
|
|
* refinements, pyro was helpful too. Based on a program
|
|
* I saw on a PC.
|
|
*
|
|
*/
|
|
|
|
#ifdef STANDALONE
|
|
#define MODE_daisy
|
|
#define PROGCLASS "Daisy"
|
|
#define HACK_INIT init_daisy
|
|
#define HACK_DRAW draw_daisy
|
|
#define daisy_opts xlockmore_opts
|
|
#define DEFAULTS "*delay: 100000 \n" \
|
|
"*count: 300 \n" \
|
|
"*cycles: 350 \n" \
|
|
"*ncolors: 200 \n" \
|
|
"*fullrandom: True \n"
|
|
#define BRIGHT_COLORS
|
|
#define UNIFORM_COLORS
|
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
|
#else /* STANDALONE */
|
|
#include "xlock.h" /* in xlockmore distribution */
|
|
|
|
#endif /* STANDALONE */
|
|
|
|
#ifdef MODE_daisy
|
|
|
|
#define DEF_GARDEN "False"
|
|
|
|
static Bool garden;
|
|
|
|
static XrmOptionDescRec opts[] =
|
|
{
|
|
{(char *) "-garden", (char *) ".daisy.garden", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+garden", (char *) ".daisy.garden", XrmoptionNoArg, (caddr_t) "off"}
|
|
};
|
|
static argtype vars[] =
|
|
{
|
|
{(void *) & garden, (char *) "garden", (char *) "Garden", (char *) DEF_GARDEN, t_Bool}
|
|
};
|
|
static OptionStruct desc[] =
|
|
{
|
|
{(char *) "-/+garden", (char *) "turn on/off garden"}
|
|
};
|
|
|
|
ModeSpecOpt daisy_opts =
|
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
|
|
|
#ifdef USE_MODULES
|
|
ModStruct daisy_description =
|
|
{"daisy", "init_daisy", "draw_daisy", "release_daisy",
|
|
"refresh_daisy", "init_daisy", (char *) NULL, &daisy_opts,
|
|
100000, 300, 350, 1, 64, 1.0, "",
|
|
"Shows a meadow of daisies", 0, NULL};
|
|
|
|
#endif
|
|
|
|
#define GREEN (23 * MI_NPIXELS(mi) / 64)
|
|
#define NOTGREEN (7 * MI_NPIXELS(mi) / 64)
|
|
#define MINDAISIES 1
|
|
|
|
#define DROOP 20 /* Percentage x with relation to y */
|
|
#define MINHEIGHT 20 /* Daisy height range */
|
|
#define MAXHEIGHT 40
|
|
|
|
typedef struct {
|
|
int width;
|
|
int height;
|
|
int time; /* up time */
|
|
int ndaisies;
|
|
int meadow_y;
|
|
Bool garden;
|
|
float step;
|
|
} daisystruct;
|
|
|
|
static daisystruct *daisies = (daisystruct *) NULL;
|
|
|
|
/* always green, straight for now, parabolic later */
|
|
static void
|
|
drawstem(ModeInfo * mi, XPoint start, XPoint stop)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
GC gc = MI_GC(mi);
|
|
|
|
if (MI_NPIXELS(mi) > 2)
|
|
XSetForeground(display, gc, MI_PIXEL(mi, GREEN));
|
|
else
|
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
|
#if 1
|
|
XDrawLine(display, window, gc, start.x, start.y, stop.x, stop.y);
|
|
#else
|
|
XDrawArc(display, window, gc, stop.x, stop.y,
|
|
NRAND(50) + 30, start.y - stop.y + 1, 90 * 64, 170 * 64);
|
|
#endif
|
|
}
|
|
|
|
/* not green */
|
|
static unsigned long
|
|
drawpetals(ModeInfo * mi, XPoint center,
|
|
int size, int circles, int delta, int offset, int petals)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
GC gc = MI_GC(mi);
|
|
unsigned long colour = 0;
|
|
float start_angle, inc_angle;
|
|
XPoint newcenter;
|
|
int petal, inc;
|
|
float sine, cosine;
|
|
|
|
if (MI_NPIXELS(mi) > GREEN + NOTGREEN) {
|
|
do {
|
|
colour = NRAND(MI_NPIXELS(mi));
|
|
} while ((long) colour >= GREEN - NOTGREEN &&
|
|
(long) colour <= GREEN + NOTGREEN);
|
|
}
|
|
start_angle = NRAND(360) * M_PI / 180;
|
|
inc_angle = 2 * M_PI / petals;
|
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
|
if (size > 2)
|
|
XFillArc(display, window, gc,
|
|
center.x - size / 2, center.y - size / 2, size, size,
|
|
0, 23040);
|
|
for (petal = 0; petal < petals; petal++) {
|
|
sine = SINF(start_angle + petal * inc_angle);
|
|
cosine = COSF(start_angle + petal * inc_angle);
|
|
if (size > 2)
|
|
if (MI_NPIXELS(mi) <= 2) {
|
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
|
for (inc = 0; inc < circles; inc++) {
|
|
newcenter.x = center.x + (int) (sine * (offset + delta * inc));
|
|
newcenter.y = center.y + (int) (cosine * (offset + delta * inc));
|
|
XDrawArc(display, window, gc,
|
|
newcenter.x - size / 2, newcenter.y - size / 2, size, size,
|
|
0, 23040);
|
|
}
|
|
}
|
|
if (MI_NPIXELS(mi) > 2 && MI_NPIXELS(mi) > GREEN + NOTGREEN)
|
|
XSetForeground(display, gc, MI_PIXEL(mi, colour));
|
|
else
|
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
|
for (inc = 0; inc < circles; inc++) {
|
|
newcenter.x = center.x + (int) (sine * (offset + delta * inc));
|
|
newcenter.y = center.y + (int) (cosine * (offset + delta * inc));
|
|
if (size < 2)
|
|
XDrawPoint(display, window, gc, newcenter.x, newcenter.y);
|
|
else
|
|
XFillArc(display, window, gc,
|
|
newcenter.x - size / 2, newcenter.y - size / 2, size, size,
|
|
0, 23040);
|
|
}
|
|
}
|
|
return colour;
|
|
}
|
|
|
|
/* not green */
|
|
static void
|
|
drawcenter(ModeInfo * mi, XPoint center, int size, unsigned long petalcolour)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
GC gc = MI_GC(mi);
|
|
unsigned long colour;
|
|
|
|
if (MI_NPIXELS(mi) > GREEN + NOTGREEN) {
|
|
do {
|
|
/* Insure good contrast */
|
|
colour = (NRAND(2 * MI_NPIXELS(mi) / 3) + petalcolour +
|
|
MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
|
|
} while ((long) colour >= GREEN - NOTGREEN &&
|
|
(long) colour <= GREEN + NOTGREEN);
|
|
XSetForeground(display, gc, MI_PIXEL(mi, colour));
|
|
} else
|
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
|
if (size < 2)
|
|
XDrawPoint(display, window, gc, center.x, center.y);
|
|
else
|
|
XFillArc(display, window, gc,
|
|
center.x - size / 2, center.y - size / 2, size, size, 0, 23040);
|
|
}
|
|
|
|
static void
|
|
drawdaisy(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
GC gc = MI_GC(mi);
|
|
daisystruct *dp = &daisies[MI_SCREEN(mi)];
|
|
XPoint stem_start, stem_stop;
|
|
int height, droop;
|
|
unsigned long colour;
|
|
|
|
/* Care more about the flower being on the screen rather than the stem */
|
|
#ifdef LINEAR
|
|
stem_stop.y = dp->meadow_y + dp->time * dp->step;
|
|
height = (NRAND(MAXHEIGHT - MINHEIGHT + 1) + MINHEIGHT) * dp->height / 300 *
|
|
2 * (dp->time + 20) / (dp->ndaisies + 20);
|
|
#else
|
|
stem_stop.y = dp->meadow_y + (int) ((float) dp->time * dp->time *
|
|
dp->step / dp->ndaisies);
|
|
height = (NRAND(MAXHEIGHT - MINHEIGHT + 1) + MINHEIGHT) * dp->height / 300 *
|
|
2 * (dp->time * dp->time + 1) / (dp->ndaisies * dp->ndaisies + 1);
|
|
#endif
|
|
stem_start.y = stem_stop.y + height;
|
|
if (dp->garden) {
|
|
stem_stop.x = ((LRAND() & 1) ? 1 : -1) *
|
|
NRAND(dp->width / 4 * (dp->time + 1) / (dp->ndaisies + 20) +
|
|
dp->width / 4 + 1) + dp->width / 2;
|
|
} else {
|
|
stem_stop.x = NRAND(dp->width);
|
|
}
|
|
/* Give about droop left or right with 25% randomness */
|
|
droop = ((LRAND() & 1) ? 1 : -1) * DROOP * (NRAND(50) + 75) / 100;
|
|
stem_start.x = stem_stop.x + droop * height / 100;
|
|
XSetLineAttributes(display, gc, height / 24 + 1,
|
|
LineSolid, CapNotLast, JoinRound);
|
|
drawstem(mi, stem_start, stem_stop);
|
|
XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinRound);
|
|
colour = drawpetals(mi, stem_stop, height / 6, 5, height / 32 + 1,
|
|
height / 7, NRAND(6) + 6);
|
|
drawcenter(mi, stem_stop, height / 7, colour);
|
|
}
|
|
|
|
|
|
void
|
|
init_daisy(ModeInfo * mi)
|
|
{
|
|
daisystruct *dp;
|
|
|
|
if (daisies == NULL) {
|
|
if ((daisies = (daisystruct *) calloc(MI_NUM_SCREENS(mi),
|
|
sizeof (daisystruct))) == NULL)
|
|
return;
|
|
}
|
|
dp = &daisies[MI_SCREEN(mi)];
|
|
|
|
dp->width = MI_WIDTH(mi);
|
|
dp->height = MI_HEIGHT(mi);
|
|
dp->time = 0;
|
|
if (MI_IS_FULLRANDOM(mi))
|
|
dp->garden = (Bool) (LRAND() & 1);
|
|
else
|
|
dp->garden = garden;
|
|
|
|
dp->ndaisies = MI_COUNT(mi);
|
|
if (dp->ndaisies < -MINDAISIES)
|
|
dp->ndaisies = NRAND(-dp->ndaisies - MINDAISIES + 1) + MINDAISIES;
|
|
else if (dp->ndaisies < MINDAISIES)
|
|
dp->ndaisies = MINDAISIES;
|
|
dp->meadow_y = dp->height / 5;
|
|
dp->step = (float) (dp->height - 2 * dp->meadow_y) / (dp->ndaisies + 1.0);
|
|
MI_CLEARWINDOW(mi);
|
|
}
|
|
|
|
void
|
|
draw_daisy(ModeInfo * mi)
|
|
{
|
|
daisystruct *dp;
|
|
|
|
if (daisies == NULL)
|
|
return;
|
|
dp = &daisies[MI_SCREEN(mi)];
|
|
|
|
MI_IS_DRAWN(mi) = True;
|
|
|
|
if (dp->time < dp->ndaisies)
|
|
drawdaisy(mi);
|
|
if (++dp->time > MI_CYCLES(mi))
|
|
init_daisy(mi);
|
|
}
|
|
|
|
void
|
|
release_daisy(ModeInfo * mi)
|
|
{
|
|
if (daisies != NULL) {
|
|
free(daisies);
|
|
daisies = (daisystruct *) NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
refresh_daisy(ModeInfo * mi)
|
|
{
|
|
daisystruct *dp;
|
|
|
|
if (daisies == NULL)
|
|
return;
|
|
dp = &daisies[MI_SCREEN(mi)];
|
|
|
|
if (dp->time < dp->ndaisies) {
|
|
MI_CLEARWINDOW(mi);
|
|
} else {
|
|
init_daisy(mi);
|
|
}
|
|
}
|
|
|
|
#endif /* MODE_daisy */
|