ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / mountain.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* mountain -- square grid mountains */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)mountain.c    4.04 97/07/28 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1995 Pascal Pensa <pensa@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 "Mountain"
30 # define HACK_INIT init_mountain
31 # define HACK_DRAW draw_mountain
32 # define mountain_opts xlockmore_opts
33 # define DEFAULTS       "*delay: 0 \n"          \
34                                         "*count: 30 \n"         \
35                                         "*cycles: 100 \n"       \
36                                         "*ncolors: 64 \n"
37 # define SMOOTH_COLORS
38 #include "xlockmore.h"          /* in xscreensaver distribution */
39 #else /* STANDALONE */
40 #include "xlock.h"              /* in xlockmore distribution */
41 #endif /* STANDALONE */
42
43 ModeSpecOpt mountain_opts =
44 {0, NULL, 0, NULL, NULL};
45
46 /* ~ 5000 Max mountain height (1000 - 10000) */
47 #define MAXHEIGHT  (3 * (mp->width + mp->height))
48
49 #define WORLDWIDTH 50           /* World size x * y */
50
51 #define RANGE_RAND(min,max) ((min) + NRAND((max) - (min)))
52
53 typedef struct {
54         int         pixelmode;
55         int         width;
56         int         height;
57         int         x, y;
58         int         offset;
59         int         stage;
60         int         h[WORLDWIDTH][WORLDWIDTH];
61         int         time;       /* up time */
62         int         first;
63         GC          stippled_GC;
64 } mountainstruct;
65
66 static mountainstruct *mountains = NULL;
67
68 static void
69 spread(int  (*m)[50], int x, int y)
70 {
71         int         x2, y2;
72         int         h = m[x][y];
73
74         for (y2 = y - 1; y2 <= y + 1; y2++)
75                 for (x2 = x - 1; x2 <= x + 1; x2++)
76                         if (x2 >= 0 && y2 >= 0 && x2 < WORLDWIDTH && y2 < WORLDWIDTH)
77                                 m[x2][y2] = (m[x2][y2] + h) / 2;
78 }
79
80 static void
81 drawamountain(ModeInfo * mi)
82 {
83         Display    *display = MI_DISPLAY(mi);
84         Window      window = MI_WINDOW(mi);
85         GC          gc = MI_GC(mi);
86         mountainstruct *mp = &mountains[MI_SCREEN(mi)];
87         int         x2, y2, x3, y3, y4, y5, c = 0;
88         XPoint      p[5];
89
90         if (MI_NPIXELS(mi) > 2) {
91                 c = (mp->h[mp->x][mp->y] + mp->h[mp->x + 1][mp->y] +
92                   mp->h[mp->x][mp->y + 1] + mp->h[mp->x + 1][mp->y + 1]) / 4;
93                 c = (c / 10 + mp->offset) % MI_NPIXELS(mi);
94         }
95         x2 = mp->x * (2 * mp->width) / (3 * WORLDWIDTH);
96         y2 = mp->y * (2 * mp->height) / (3 * WORLDWIDTH);
97         p[0].x = (x2 - y2 / 2) + (mp->width / 4);
98         p[0].y = (y2 - mp->h[mp->x][mp->y]) + mp->height / 4;
99
100         x3 = (mp->x + 1) * (2 * mp->width) / (3 * WORLDWIDTH);
101         y3 = mp->y * (2 * mp->height) / (3 * WORLDWIDTH);
102         p[1].x = (x3 - y3 / 2) + (mp->width / 4);
103         p[1].y = (y3 - mp->h[mp->x + 1][mp->y]) + mp->height / 4;
104
105         y4 = (mp->y + 1) * (2 * mp->height) / (3 * WORLDWIDTH);
106         p[2].x = (x3 - y4 / 2) + (mp->width / 4);
107         p[2].y = (y4 - mp->h[mp->x + 1][mp->y + 1]) + mp->height / 4;
108
109         y5 = (mp->y + 1) * (2 * mp->height) / (3 * WORLDWIDTH);
110         p[3].x = (x2 - y5 / 2) + (mp->width / 4);
111         p[3].y = (y5 - mp->h[mp->x][mp->y + 1]) + mp->height / 4;
112
113         p[4].x = p[0].x;
114         p[4].y = p[0].y;
115
116         if (MI_NPIXELS(mi) > 2)
117                 XSetForeground(display, gc, MI_PIXEL(mi, c));
118         else
119                 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
120         XFillPolygon(display, window, gc, p, 4, Complex, CoordModeOrigin);
121
122         if (!mp->pixelmode) {
123                 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
124                 XDrawLines(display, window, gc, p, 5, CoordModeOrigin);
125         }
126         mp->x++;
127         if (mp->x == WORLDWIDTH - 1) {
128                 mp->y++;
129                 mp->x = 0;
130         }
131         if (mp->y == WORLDWIDTH - 1)
132                 mp->stage++;
133 }
134
135 void
136 init_mountain(ModeInfo * mi)
137 {
138         mountainstruct *mp;
139         int         i, j, x, y;
140         XGCValues   gcv;
141
142         if (mountains == NULL) {
143                 if ((mountains = (mountainstruct *) calloc(MI_NUM_SCREENS(mi),
144                                            sizeof (mountainstruct))) == NULL)
145                         return;
146         }
147         mp = &mountains[MI_SCREEN(mi)];
148         mp->width = MI_WIN_WIDTH(mi);
149         mp->height = MI_WIN_HEIGHT(mi);
150         mp->pixelmode = (mp->width + mp->height < 200);
151         mp->stage = 0;
152         mp->time = 0;
153         mp->x = mp->y = 0;
154         if (!mp->first) {
155                 mp->first = 1;
156                 gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
157                 gcv.background = MI_WIN_BLACK_PIXEL(mi);
158
159                 mp->stippled_GC = XCreateGC(MI_DISPLAY(mi), MI_WINDOW(mi),
160                                           GCForeground | GCBackground, &gcv);
161         }
162         XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
163
164         for (y = 0; y < WORLDWIDTH; y++)
165                 for (x = 0; x < WORLDWIDTH; x++)
166                         mp->h[x][y] = 0;
167
168         j = MI_BATCHCOUNT(mi);
169         if (j < 0)
170                 j = NRAND(-j) + 1;
171         for (i = 0; i < j; i++)
172                 mp->h[RANGE_RAND(1, WORLDWIDTH - 1)][RANGE_RAND(1, WORLDWIDTH - 1)] =
173                         NRAND(MAXHEIGHT);
174
175         for (y = 0; y < WORLDWIDTH; y++)
176                 for (x = 0; x < WORLDWIDTH; x++)
177                         spread(mp->h, x, y);
178
179         for (y = 0; y < WORLDWIDTH; y++)
180                 for (x = 0; x < WORLDWIDTH; x++) {
181                         mp->h[x][y] = mp->h[x][y] + NRAND(10) - 5;
182                         if (mp->h[x][y] < 10)
183                                 mp->h[x][y] = 0;
184                 }
185
186         if (MI_NPIXELS(mi) > 2)
187                 mp->offset = NRAND(MI_NPIXELS(mi));
188         else
189                 mp->offset = 0;
190 }
191
192 void
193 draw_mountain(ModeInfo * mi)
194 {
195         mountainstruct *mp = &mountains[MI_SCREEN(mi)];
196
197         switch (mp->stage) {
198                 case 0:
199                         drawamountain(mi);
200                         break;
201                 case 1:
202                         MI_PAUSE(mi) = 2000000;
203                         /*if (++mp->time > MI_CYCLES(mi)); */
204                         mp->stage++;
205                         break;
206                 case 2:
207                         init_mountain(mi);
208                         break;
209         }
210 }
211
212 void
213 release_mountain(ModeInfo * mi)
214 {
215         if (mountains != NULL) {
216                 int         screen;
217
218                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
219                         mountainstruct *mp = &mountains[screen];
220
221                         XFreeGC(MI_DISPLAY(mi), mp->stippled_GC);
222                 }
223                 (void) free((void *) mountains);
224                 mountains = NULL;
225         }
226 }
227
228 void
229 refresh_mountain(ModeInfo * mi)
230 {
231         mountainstruct *mp = &mountains[MI_SCREEN(mi)];
232
233         mp->x = 0;
234         mp->y = 0;
235 }