ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / forest.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  * forest.c --- draw a fractal forest.
3  */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)forest.c      4.03 97/05/10 xlockmore";
6 #endif
7
8 /* Copyright (c) 1995 Pascal Pensa <pensa@aurora.unice.fr>
9  *
10  * Original idea : Guillaume Ramey <ramey@aurora.unice.fr>
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  * 10-May-97: Compatible with xscreensaver
26  */
27
28 #ifdef STANDALONE
29 # define PROGCLASS                                      "Forest"
30 # define HACK_INIT                                      init_forest
31 # define HACK_DRAW                                      draw_forest
32 # define forest_opts                            xlockmore_opts
33 # define DEFAULTS       "*count:                100     \n"                     \
34                                         "*cycles:               200     \n"                     \
35                                         "*delay:                400000  \n"                     \
36                                         "*ncolors:              100     \n"
37 # define UNIFORM_COLORS
38 # include "xlockmore.h"                         /* from the xscreensaver distribution */
39 # include "erase.h"
40 #else  /* !STANDALONE */
41 # include "xlock.h"                                     /* from the xlockmore distribution */
42 #endif /* !STANDALONE */
43
44 ModeSpecOpt forest_opts = {
45   0, NULL, 0, NULL, NULL };
46
47
48 #define MINTREES   1
49
50 #define MINHEIGHT  20           /* Tree height range */
51 #define MAXHEIGHT  40
52
53 #define MINANGLE   15           /* (degree) angle between soon */
54 #define MAXANGLE   35
55 #define RANDANGLE  15           /* (degree) Max random angle from default */
56
57 #define REDUCE     90           /* Height % from father */
58
59 #define ITERLEVEL  10           /* Tree iteration */
60
61 #define COLORSPEED  2           /* Color increment */
62
63 /* degree to radian */
64 #define DEGTORAD(x) (((float)(x)) * M_PI / 180.0)
65
66 #define RANGE_RAND(min,max) ((min) + NRAND((max) - (min)))
67
68 typedef struct {
69         int         width;
70         int         height;
71         int         time;       /* up time */
72         int         ntrees;
73 } foreststruct;
74
75 static foreststruct *forests = NULL;
76
77 static void
78 draw_tree(ModeInfo * mi,
79           short int x, short int y, short int len,
80           float a, float as, short int c, short int level)
81                                 /* Father's end */
82                                 /* Length */
83                                 /* color */
84                                 /* Height level */
85                                 /* Father's angle */
86                                 /* Father's angle step */
87 {
88         Display    *display = MI_DISPLAY(mi);
89         Window      window = MI_WINDOW(mi);
90         GC          gc = MI_GC(mi);
91         short       x_1, y_1, x_2, y_2;
92         float       a1, a2;
93
94         /* left */
95
96         a1 = a + as + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
97
98         x_1 = x + (short) (COSF(a1) * ((float) len));
99         y_1 = y + (short) (SINF(a1) * ((float) len));
100
101         /* right */
102
103         a2 = a - as + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
104
105         x_2 = x + (short) (COSF(a2) * ((float) len));
106         y_2 = y + (short) (SINF(a2) * ((float) len));
107
108         if (MI_NPIXELS(mi) > 2) {
109                 XSetForeground(display, gc, MI_PIXEL(mi, c));
110                 c = (c + COLORSPEED) % MI_NPIXELS(mi);
111         } else
112                 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
113
114         XDrawLine(display, window, gc, x, y, x_1, y_1);
115         XDrawLine(display, window, gc, x, y, x_2, y_2);
116
117         if (level < 2) {
118                 XDrawLine(display, window, gc, x + 1, y, x_1 + 1, y_1);
119                 XDrawLine(display, window, gc, x + 1, y, x_2 + 1, y_2);
120         }
121         len = (len * REDUCE * 10) / 1000;
122
123         if (level < ITERLEVEL) {
124                 draw_tree(mi, x_1, y_1, len, a1, as, c, level + 1);
125                 draw_tree(mi, x_2, y_2, len, a2, as, c, level + 1);
126         }
127 }
128
129 void
130 init_forest(ModeInfo * mi)
131 {
132         foreststruct *fp;
133
134         if (forests == NULL) {
135                 if ((forests = (foreststruct *) calloc(MI_NUM_SCREENS(mi),
136                                              sizeof (foreststruct))) == NULL)
137                         return;
138         }
139         fp = &forests[MI_SCREEN(mi)];
140
141         fp->width = MI_WIN_WIDTH(mi);
142         fp->height = MI_WIN_HEIGHT(mi);
143         fp->time = 0;
144
145         fp->ntrees = MI_BATCHCOUNT(mi);
146         if (fp->ntrees < -MINTREES)
147                 fp->ntrees = NRAND(-fp->ntrees - MINTREES + 1) + MINTREES;
148         else if (fp->ntrees < MINTREES)
149                 fp->ntrees = MINTREES;
150         XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
151 }
152
153 void
154 draw_forest(ModeInfo * mi)
155 {
156         Display    *display = MI_DISPLAY(mi);
157         GC          gc = MI_GC(mi);
158         foreststruct *fp = &forests[MI_SCREEN(mi)];
159         short       x, y, x_2, y_2, len, c = 0;
160         float       a, as;
161
162         if (fp->time < fp->ntrees) {
163
164                 x = RANGE_RAND(0, fp->width);
165                 y = RANGE_RAND(0, fp->height + MAXHEIGHT);
166                 a = -M_PI / 2.0 + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
167                 as = DEGTORAD(RANGE_RAND(MINANGLE, MAXANGLE));
168                 len = ((RANGE_RAND(MINHEIGHT, MAXHEIGHT) * (fp->width / 20)) / 50) + 2;
169
170                 if (MI_NPIXELS(mi) > 2) {
171                         c = NRAND(MI_NPIXELS(mi));
172                         XSetForeground(display, gc, MI_PIXEL(mi, c));
173                         c = (c + COLORSPEED) % MI_NPIXELS(mi);
174                 } else
175                         XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
176
177                 x_2 = x + (short) (COSF(a) * ((float) len));
178                 y_2 = y + (short) (SINF(a) * ((float) len));
179
180                 XDrawLine(display, MI_WINDOW(mi), gc, x, y, x_2, y_2);
181                 XDrawLine(display, MI_WINDOW(mi), gc, x + 1, y, x_2 + 1, y_2);
182
183                 draw_tree(mi, x_2, y_2, (len * REDUCE) / 100, a, as, c, 1);
184         }
185         if (++fp->time > MI_CYCLES(mi)) {
186 #ifdef STANDALONE
187           erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
188 #endif /* STANDALONE */
189           init_forest(mi);
190         }
191 }
192
193 void
194 release_forest(ModeInfo * mi)
195 {
196         if (forests != NULL) {
197                 (void) free((void *) forests);
198                 forests = NULL;
199         }
200 }
201
202 void
203 refresh_forest(ModeInfo * mi)
204 {
205         foreststruct *fp = &forests[MI_SCREEN(mi)];
206
207         if (fp->time < fp->ntrees)
208                 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
209         else
210                 init_forest(mi);
211 }