1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* daisy --- flowers in a field */
3 
4 #if 0
5 static const char sccsid[] = "@(#)daisy.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1996 by David Bagley.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 01-Nov-2000: Allocation checks
26  * 10-May-1997: Compatible with xscreensaver
27  * 07-Aug-1996: written.  Initially copied forest.c and made continual
28  *              refinements, pyro was helpful too.  Based on a program
29  *              I saw on a PC.
30  *
31  */
32 
33 #ifdef STANDALONE
34 #define MODE_daisy
35 #define DEFAULTS "*delay: 100000 \n" \
36 	"*count: 300 \n" \
37 	"*cycles: 350 \n" \
38 	"*ncolors: 200 \n" \
39 	"*fullrandom: True \n" \
40 
41 # define free_daisy 0
42 # define reshape_daisy 0
43 # define daisy_handle_event 0
44 #define BRIGHT_COLORS
45 #define UNIFORM_COLORS
46 #include "xlockmore.h"		/* in xscreensaver distribution */
47 #else /* STANDALONE */
48 #include "xlock.h"		/* in xlockmore distribution */
49 
50 #endif /* STANDALONE */
51 
52 #ifdef MODE_daisy
53 
54 #define DEF_GARDEN  "False"
55 
56 static Bool garden;
57 
58 static XrmOptionDescRec opts[] =
59 {
60 	{(char *) "-garden", (char *) ".daisy.garden", XrmoptionNoArg, (caddr_t) "on"},
61 	{(char *) "+garden", (char *) ".daisy.garden", XrmoptionNoArg, (caddr_t) "off"}
62 };
63 static argtype vars[] =
64 {
65 	{(void *) & garden, (char *) "garden", (char *) "Garden", (char *) DEF_GARDEN, t_Bool}
66 };
67 static OptionStruct desc[] =
68 {
69 	{(char *) "-/+garden", (char *) "turn on/off garden"}
70 };
71 
72 ENTRYPOINT ModeSpecOpt daisy_opts =
73 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
74 
75 #ifdef USE_MODULES
76 ModStruct   daisy_description =
77 {"daisy", "init_daisy", "draw_daisy", "release_daisy",
78  "refresh_daisy", "init_daisy", (char *) NULL, &daisy_opts,
79  100000, 300, 350, 1, 64, 1.0, "",
80  "Shows a meadow of daisies", 0, NULL};
81 
82 #endif
83 
84 #define GREEN	(23 * MI_NPIXELS(mi) / 64)
85 #define NOTGREEN	(7 * MI_NPIXELS(mi) / 64)
86 #define MINDAISIES   1
87 
88 #define DROOP 20		/* Percentage x with relation to y */
89 #define MINHEIGHT  20		/* Daisy height range */
90 #define MAXHEIGHT  40
91 
92 typedef struct {
93 	int         width;
94 	int         height;
95 	int         time;	/* up time */
96 	int         ndaisies;
97 	int         meadow_y;
98 	Bool        garden;
99 	float       step;
100 } daisystruct;
101 
102 static daisystruct *daisies = (daisystruct *) NULL;
103 
104 /* always green, straight for now, parabolic later */
105 static void
drawstem(ModeInfo * mi,XPoint start,XPoint stop)106 drawstem(ModeInfo * mi, XPoint start, XPoint stop)
107 {
108 	Display    *display = MI_DISPLAY(mi);
109 	Window      window = MI_WINDOW(mi);
110 	GC          gc = MI_GC(mi);
111 
112 	if (MI_NPIXELS(mi) > 2)
113 		XSetForeground(display, gc, MI_PIXEL(mi, GREEN));
114 	else
115 		XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
116 #if 1
117 	XDrawLine(display, window, gc, start.x, start.y, stop.x, stop.y);
118 #else
119 	XDrawArc(display, window, gc, stop.x, stop.y,
120 		 NRAND(50) + 30, start.y - stop.y + 1, 90 * 64, 170 * 64);
121 #endif
122 }
123 
124 /* not green */
125 static unsigned long
drawpetals(ModeInfo * mi,XPoint center,int size,int circles,int delta,int offset,int petals)126 drawpetals(ModeInfo * mi, XPoint center,
127 	   int size, int circles, int delta, int offset, int petals)
128 {
129 	Display    *display = MI_DISPLAY(mi);
130 	Window      window = MI_WINDOW(mi);
131 	GC          gc = MI_GC(mi);
132 	unsigned long colour = 0;
133 	float       start_angle, inc_angle;
134 	XPoint      newcenter;
135 	int         petal, inc;
136 	float       sine, cosine;
137 
138 	if (MI_NPIXELS(mi) > GREEN + NOTGREEN) {
139 		do {
140 			colour = NRAND(MI_NPIXELS(mi));
141 		} while ((long) colour >= GREEN - NOTGREEN &&
142 			 (long) colour <= GREEN + NOTGREEN);
143 	}
144 	start_angle = NRAND(360) * M_PI / 180;
145 	inc_angle = 2 * M_PI / petals;
146 	XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
147 	if (size > 2)
148 		XFillArc(display, window, gc,
149 			 center.x - size / 2, center.y - size / 2, size, size,
150 			 0, 23040);
151 	for (petal = 0; petal < petals; petal++) {
152 		sine = SINF(start_angle + petal * inc_angle);
153 		cosine = COSF(start_angle + petal * inc_angle);
154 		if (size > 2)
155 			if (MI_NPIXELS(mi) <= 2) {
156 				XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
157 				for (inc = 0; inc < circles; inc++) {
158 					newcenter.x = center.x + (int) (sine * (offset + delta * inc));
159 					newcenter.y = center.y + (int) (cosine * (offset + delta * inc));
160 					XDrawArc(display, window, gc,
161 						 newcenter.x - size / 2, newcenter.y - size / 2, size, size,
162 						 0, 23040);
163 				}
164 			}
165 		if (MI_NPIXELS(mi) > 2 && MI_NPIXELS(mi) > GREEN + NOTGREEN)
166 			XSetForeground(display, gc, MI_PIXEL(mi, colour));
167 		else
168 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
169 		for (inc = 0; inc < circles; inc++) {
170 			newcenter.x = center.x + (int) (sine * (offset + delta * inc));
171 			newcenter.y = center.y + (int) (cosine * (offset + delta * inc));
172 			if (size < 2)
173 				XDrawPoint(display, window, gc, newcenter.x, newcenter.y);
174 			else
175 				XFillArc(display, window, gc,
176 					 newcenter.x - size / 2, newcenter.y - size / 2, size, size,
177 					 0, 23040);
178 		}
179 	}
180 	return colour;
181 }
182 
183 /* not green */
184 static void
drawcenter(ModeInfo * mi,XPoint center,int size,unsigned long petalcolour)185 drawcenter(ModeInfo * mi, XPoint center, int size, unsigned long petalcolour)
186 {
187 	Display    *display = MI_DISPLAY(mi);
188 	Window      window = MI_WINDOW(mi);
189 	GC          gc = MI_GC(mi);
190 	unsigned long colour;
191 
192 	if (MI_NPIXELS(mi) > GREEN + NOTGREEN) {
193 		do {
194 			/* Insure good contrast */
195 			colour = (NRAND(2 * MI_NPIXELS(mi) / 3) + petalcolour +
196 				  MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
197 		} while ((long) colour >= GREEN - NOTGREEN &&
198 			 (long) colour <= GREEN + NOTGREEN);
199 		XSetForeground(display, gc, MI_PIXEL(mi, colour));
200 	} else
201 		XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
202 	if (size < 2)
203 		XDrawPoint(display, window, gc, center.x, center.y);
204 	else
205 		XFillArc(display, window, gc,
206 			 center.x - size / 2, center.y - size / 2, size, size, 0, 23040);
207 }
208 
209 static void
drawdaisy(ModeInfo * mi)210 drawdaisy(ModeInfo * mi)
211 {
212 	Display    *display = MI_DISPLAY(mi);
213 	GC          gc = MI_GC(mi);
214 	daisystruct *dp = &daisies[MI_SCREEN(mi)];
215 	XPoint      stem_start, stem_stop;
216 	int         height, droop;
217 	unsigned long colour;
218 
219 	/* Care more about the flower being on the screen rather than the stem */
220 #ifdef LINEAR
221 	stem_stop.y = dp->meadow_y + dp->time * dp->step;
222 	height = (NRAND(MAXHEIGHT - MINHEIGHT + 1) + MINHEIGHT) * dp->height / 300 *
223 		2 * (dp->time + 20) / (dp->ndaisies + 20);
224 #else
225 	stem_stop.y = dp->meadow_y + (int) ((float) dp->time * dp->time *
226 					    dp->step / dp->ndaisies);
227 	height = (NRAND(MAXHEIGHT - MINHEIGHT + 1) + MINHEIGHT) * dp->height / 300 *
228 		2 * (dp->time * dp->time + 1) / (dp->ndaisies * dp->ndaisies + 1);
229 #endif
230 	stem_start.y = stem_stop.y + height;
231 	if (dp->garden) {
232 		stem_stop.x = ((LRAND() & 1) ? 1 : -1) *
233 			NRAND(dp->width / 4 * (dp->time + 1) / (dp->ndaisies + 20) +
234 			      dp->width / 4 + 1) + dp->width / 2;
235 	} else {
236 		stem_stop.x = NRAND(dp->width);
237 	}
238 	/* Give about droop left or right with 25% randomness */
239 	droop = ((LRAND() & 1) ? 1 : -1) * DROOP * (NRAND(50) + 75) / 100;
240 	stem_start.x = stem_stop.x + droop * height / 100;
241 	XSetLineAttributes(display, gc, height / 24 + 1,
242 			   LineSolid, CapNotLast, JoinRound);
243 	drawstem(mi, stem_start, stem_stop);
244 	XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinRound);
245 	colour = drawpetals(mi, stem_stop, height / 6, 5, height / 32 + 1,
246 			    height / 7, NRAND(6) + 6);
247 	drawcenter(mi, stem_stop, height / 7, colour);
248 }
249 
250 ENTRYPOINT void
init_daisy(ModeInfo * mi)251 init_daisy(ModeInfo * mi)
252 {
253 	daisystruct *dp;
254 
255 	MI_INIT(mi, daisies);
256 	dp = &daisies[MI_SCREEN(mi)];
257 
258 	dp->width = MI_WIDTH(mi);
259 	dp->height = MI_HEIGHT(mi);
260 	dp->time = 0;
261 	if (MI_IS_FULLRANDOM(mi))
262 		dp->garden = (Bool) (LRAND() & 1);
263 	else
264 		dp->garden = garden;
265 
266 	dp->ndaisies = MI_COUNT(mi);
267 	if (dp->ndaisies < -MINDAISIES)
268 		dp->ndaisies = NRAND(-dp->ndaisies - MINDAISIES + 1) + MINDAISIES;
269 	else if (dp->ndaisies < MINDAISIES)
270 		dp->ndaisies = MINDAISIES;
271 	dp->meadow_y = dp->height / 5;
272 	dp->step = (float) (dp->height - 2 * dp->meadow_y) / (dp->ndaisies + 1.0);
273 	MI_CLEARWINDOW(mi);
274 }
275 
276 ENTRYPOINT void
draw_daisy(ModeInfo * mi)277 draw_daisy(ModeInfo * mi)
278 {
279 	daisystruct *dp;
280 
281 	if (daisies == NULL)
282 		return;
283 	dp = &daisies[MI_SCREEN(mi)];
284 
285 	MI_IS_DRAWN(mi) = True;
286 
287 	if (dp->time < dp->ndaisies)
288 		drawdaisy(mi);
289 	if (++dp->time > MI_CYCLES(mi))
290 		init_daisy(mi);
291 }
292 
293 ENTRYPOINT void
release_daisy(ModeInfo * mi)294 release_daisy(ModeInfo * mi)
295 {
296 	if (daisies != NULL) {
297 		free(daisies);
298 		daisies = (daisystruct *) NULL;
299 	}
300 }
301 
302 #ifndef STANDALONE
303 ENTRYPOINT void
refresh_daisy(ModeInfo * mi)304 refresh_daisy(ModeInfo * mi)
305 {
306 	daisystruct *dp;
307 
308 	if (daisies == NULL)
309 		return;
310 	dp = &daisies[MI_SCREEN(mi)];
311 
312 	if (dp->time < dp->ndaisies) {
313 		MI_CLEARWINDOW(mi);
314 	} else {
315 		init_daisy(mi);
316 	}
317 }
318 #endif
319 
320 XSCREENSAVER_MODULE ("Daisy", daisy)
321 
322 #endif /* MODE_daisy */
323