ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.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 #else  /* !STANDALONE */
40 # include "xlock.h"                                     /* from the xlockmore distribution */
41 #endif /* !STANDALONE */
42
43 ModeSpecOpt forest_opts = {
44   0, NULL, 0, NULL, NULL };
45
46
47 #define MINTREES   1
48
49 #define MINHEIGHT  20           /* Tree height range */
50 #define MAXHEIGHT  40
51
52 #define MINANGLE   15           /* (degree) angle between soon */
53 #define MAXANGLE   35
54 #define RANDANGLE  15           /* (degree) Max random angle from default */
55
56 #define REDUCE     90           /* Height % from father */
57
58 #define ITERLEVEL  10           /* Tree iteration */
59
60 #define COLORSPEED  2           /* Color increment */
61
62 /* degree to radian */
63 #define DEGTORAD(x) (((float)(x)) * M_PI / 180.0)
64
65 #define RANGE_RAND(min,max) ((min) + NRAND((max) - (min)))
66
67 typedef struct {
68         int         width;
69         int         height;
70         int         time;       /* up time */
71         int         ntrees;
72 } foreststruct;
73
74 static foreststruct *forests = NULL;
75
76 static void
77 draw_tree(ModeInfo * mi,
78           short int x, short int y, short int len,
79           float a, float as, short int c, short int level)
80                                 /* Father's end */
81                                 /* Length */
82                                 /* color */
83                                 /* Height level */
84                                 /* Father's angle */
85                                 /* Father's angle step */
86 {
87         Display    *display = MI_DISPLAY(mi);
88         Window      window = MI_WINDOW(mi);
89         GC          gc = MI_GC(mi);
90         short       x_1, y_1, x_2, y_2;
91         float       a1, a2;
92
93         /* left */
94
95         a1 = a + as + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
96
97         x_1 = x + (short) (COSF(a1) * ((float) len));
98         y_1 = y + (short) (SINF(a1) * ((float) len));
99
100         /* right */
101
102         a2 = a - as + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
103
104         x_2 = x + (short) (COSF(a2) * ((float) len));
105         y_2 = y + (short) (SINF(a2) * ((float) len));
106
107         if (MI_NPIXELS(mi) > 2) {
108                 XSetForeground(display, gc, MI_PIXEL(mi, c));
109                 c = (c + COLORSPEED) % MI_NPIXELS(mi);
110         } else
111                 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
112
113         XDrawLine(display, window, gc, x, y, x_1, y_1);
114         XDrawLine(display, window, gc, x, y, x_2, y_2);
115
116         if (level < 2) {
117                 XDrawLine(display, window, gc, x + 1, y, x_1 + 1, y_1);
118                 XDrawLine(display, window, gc, x + 1, y, x_2 + 1, y_2);
119         }
120         len = (len * REDUCE * 10) / 1000;
121
122         if (level < ITERLEVEL) {
123                 draw_tree(mi, x_1, y_1, len, a1, as, c, level + 1);
124                 draw_tree(mi, x_2, y_2, len, a2, as, c, level + 1);
125         }
126 }
127
128 void
129 init_forest(ModeInfo * mi)
130 {
131         foreststruct *fp;
132
133         if (forests == NULL) {
134                 if ((forests = (foreststruct *) calloc(MI_NUM_SCREENS(mi),
135                                              sizeof (foreststruct))) == NULL)
136                         return;
137         }
138         fp = &forests[MI_SCREEN(mi)];
139
140         fp->width = MI_WIN_WIDTH(mi);
141         fp->height = MI_WIN_HEIGHT(mi);
142         fp->time = 0;
143
144         fp->ntrees = MI_BATCHCOUNT(mi);
145         if (fp->ntrees < -MINTREES)
146                 fp->ntrees = NRAND(-fp->ntrees - MINTREES + 1) + MINTREES;
147         else if (fp->ntrees < MINTREES)
148                 fp->ntrees = MINTREES;
149         XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
150 }
151
152 void
153 draw_forest(ModeInfo * mi)
154 {
155         Display    *display = MI_DISPLAY(mi);
156         GC          gc = MI_GC(mi);
157         foreststruct *fp = &forests[MI_SCREEN(mi)];
158         short       x, y, x_2, y_2, len, c = 0;
159         float       a, as;
160
161         if (fp->time < fp->ntrees) {
162
163                 x = RANGE_RAND(0, fp->width);
164                 y = RANGE_RAND(0, fp->height + MAXHEIGHT);
165                 a = -M_PI / 2.0 + DEGTORAD(NRAND(2 * RANDANGLE) - RANDANGLE);
166                 as = DEGTORAD(RANGE_RAND(MINANGLE, MAXANGLE));
167                 len = ((RANGE_RAND(MINHEIGHT, MAXHEIGHT) * (fp->width / 20)) / 50) + 2;
168
169                 if (MI_NPIXELS(mi) > 2) {
170                         c = NRAND(MI_NPIXELS(mi));
171                         XSetForeground(display, gc, MI_PIXEL(mi, c));
172                         c = (c + COLORSPEED) % MI_NPIXELS(mi);
173                 } else
174                         XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
175
176                 x_2 = x + (short) (COSF(a) * ((float) len));
177                 y_2 = y + (short) (SINF(a) * ((float) len));
178
179                 XDrawLine(display, MI_WINDOW(mi), gc, x, y, x_2, y_2);
180                 XDrawLine(display, MI_WINDOW(mi), gc, x + 1, y, x_2 + 1, y_2);
181
182                 draw_tree(mi, x_2, y_2, (len * REDUCE) / 100, a, as, c, 1);
183         }
184         if (++fp->time > MI_CYCLES(mi))
185                 init_forest(mi);
186 }
187
188 void
189 release_forest(ModeInfo * mi)
190 {
191         if (forests != NULL) {
192                 (void) free((void *) forests);
193                 forests = NULL;
194         }
195 }
196
197 void
198 refresh_forest(ModeInfo * mi)
199 {
200         foreststruct *fp = &forests[MI_SCREEN(mi)];
201
202         if (fp->time < fp->ntrees)
203                 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
204         else
205                 init_forest(mi);
206 }