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