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