source: trunk/third/xscreensaver/hacks/triangle.c @ 20148

Revision 20148, 9.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 4 -*- */
2/* triangle --- create a triangle-mountain */
3
4#if 0
5static const char sccsid[] = "@(#)triangle.c    4.04 97/07/28 xlockmore";
6#endif
7
8/*-
9 * Copyright (c) 1995 by Tobias Gloth
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind.  The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof.  In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * Revision History:
24 * 10-May-97: Compatible with xscreensaver
25 * 10-Mar-96: re-arranged and re-formatted the code for appearance and
26 *            to make common subroutines.  Simplified.
27 *                Ron Hitchens <ron@idiom.com>
28 * 07-Mar-96: Removed internal delay code, set MI_PAUSE(mi) for inter-scene
29 *            delays.  No other delays are needed here.
30 *            Made pause time sensitive to value of cycles (in 10ths of a
31 *            second).  Removed (hopefully) all references to globals.
32 *                Ron Hitchens <ron@idiom.com>
33 * 27-Feb-96: Undid the changes listed below.  Added ModeInfo argument.
34 *                Implemented delay between scenes using the MI_PAUSE(mi)
35 *            scheme.  Ron Hitchens <ron@idiom.com>
36 * 27-Dec-95: Ron Hitchens <ron@idiom.com>
37 *            Modified logic of draw_triangle() to provide a delay
38 *            (sensitive to the value of cycles) between each iteration.
39 *            Because this mode is so compute intensive, when the new
40 *            event loop adjusted the delay to compensate, this mode had
41 *            almost no delay time left.  This change pauses between each
42 *            new landscape, but could still be done better (it is not
43 *            sensitive to input events while drawing, for example).
44 * 03-Nov-95: Many changes (hopefully some good ones) by David Bagley
45 * 01-Oct-95: Written by Tobias Gloth
46 */
47
48#ifdef STANDALONE
49# define PROGCLASS "Triangle"
50# define HACK_INIT init_triangle
51# define HACK_DRAW draw_triangle
52# define triangle_opts xlockmore_opts
53# define DEFAULTS       "*delay: 10000 \n"      \
54                                        "*ncolors: 128 \n"
55# define SMOOTH_COLORS
56# include "xlockmore.h"         /* in xscreensaver distribution */
57#else /* STANDALONE */
58# include "xlock.h"                     /* in xlockmore distribution */
59#endif /* STANDALONE */
60
61ModeSpecOpt triangle_opts =
62{0, NULL, 0, NULL, NULL};
63
64#define MAX_STEPS 8
65#define MAX_SIZE  (1<<MAX_STEPS)
66#define MAX_LEVELS 1000
67
68#undef TOP  /* FTSO AIX */
69
70#define DELTA  0.4
71#define LEFT   (-0.25)
72#define RIGHT  1.25
73#define TOP    0.3
74#define BOTTOM 1.0
75#define BLUE   45               /* Just the right shade of blue */
76
77#define BACKFACE_REMOVAL
78
79#define DISPLACE(h,d) ((h)/2+LRAND()/(MAXRAND/(2*(d)+1))-d)
80
81typedef struct {
82        int         width;
83        int         height;
84        int         size;
85        int         steps;
86        int         stage;
87        int         init_now;
88        int         fast;
89        int         i;
90        int         j;
91        int         d;
92        short       level[MAX_LEVELS];
93        int         xpos[2 * MAX_SIZE + 1];
94        int         ypos[MAX_SIZE + 1];
95        short       H[(MAX_SIZE + 1) * (MAX_SIZE + 2) / 2];
96        short      *h[MAX_SIZE + 1];
97        short       delta[MAX_STEPS];
98} trianglestruct;
99
100static trianglestruct *triangles = NULL;
101
102static
103void
104draw_atriangle(ModeInfo * mi, XPoint * p, int y_0, int y_1, int y_2, double dinv)
105{
106        Display    *display = MI_DISPLAY(mi);
107        Window      window = MI_WINDOW(mi);
108        GC          gc = MI_GC(mi);
109
110        if (MI_NPIXELS(mi) > 2) {       /* color */
111                int         dmax, dmin;
112                long        color;
113
114                dmin = MIN(y_0, y_1);
115                dmin = MIN(dmin, y_2);
116                dmax = MAX(y_0, y_1);
117                dmax = MAX(dmax, y_2);
118
119                if (dmax == 0) {
120                        color = BLUE;
121                } else {
122                        color = MI_NPIXELS(mi) -
123                                (int) ((double) MI_NPIXELS(mi) / M_PI_2 * atan(dinv * (dmax - dmin)));
124                }
125
126                XSetForeground(display, gc, MI_PIXEL(mi, color % MI_NPIXELS(mi)));
127                XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
128        } else {
129                /* mono */
130#ifdef BACKFACE_REMOVAL
131                XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
132                XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
133#endif
134                XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
135                XDrawLine(display, window, gc, p[0].x, p[0].y, p[1].x, p[1].y);
136                XDrawLine(display, window, gc, p[1].x, p[1].y, p[2].x, p[2].y);
137                XDrawLine(display, window, gc, p[2].x, p[2].y, p[0].x, p[0].y);
138        }
139}
140
141static
142void
143calc_points1(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
144{
145        *y0_p = tp->level[MAX(tp->h[tp->i][tp->j], 0)];
146        *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
147        *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
148
149        p[0].x = tp->xpos[2 * tp->i + tp->j];
150        p[1].x = tp->xpos[2 * (tp->i + d) + tp->j];
151        p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
152
153        p[0].y = tp->ypos[tp->j] - *y0_p;
154        p[1].y = tp->ypos[tp->j] - *y1_p;
155        p[2].y = tp->ypos[tp->j + d] - *y2_p;
156}
157
158static
159void
160calc_points2(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
161{
162        *y0_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
163        *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j + d], 0)];
164        *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
165
166        p[0].x = tp->xpos[2 * (tp->i + d) + tp->j];
167        p[1].x = tp->xpos[2 * (tp->i + d) + (tp->j + d)];
168        p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
169
170        p[0].y = tp->ypos[tp->j] - *y0_p;
171        p[1].y = tp->ypos[tp->j + d] - *y1_p;
172        p[2].y = tp->ypos[tp->j + d] - *y2_p;
173}
174
175
176static
177void
178draw_mesh(ModeInfo * mi, trianglestruct * tp, int d, int count)
179{
180        XPoint      p[3];
181        int         first = 1;
182        int         y_0, y_1, y_2;
183        double      dinv = 0.2 / d;
184
185        if ((tp->j == 0) && (tp->i == 0)) {
186#if 0 /* jwz */
187                XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
188#else
189                {
190                  int x = 0;
191                  int y = 0;
192                  int x2 = MI_WIN_WIDTH(mi);
193                  int y2 = tp->ypos[0];
194                  XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
195                  XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
196                                                 x, y, x2, y2);
197                }
198#endif
199        }
200        for (; (tp->j < tp->size) && (count > 0); tp->j += ((count) ? d : 0)) {
201                for (tp->i = (first) ? tp->i : 0, first = 0;
202                     (tp->i < MAX_SIZE - tp->j) && (count > 0);
203                     tp->i += d, count--) {
204                        if (tp->i + tp->j < tp->size) {
205                                calc_points1(tp, d, &y_0, &y_1, &y_2, p);
206                                draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
207                        }
208                        if (tp->i + tp->j + d < tp->size) {
209                                calc_points2(tp, d, &y_0, &y_1, &y_2, p);
210                                draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
211                        }
212                }
213        }
214
215        if (tp->j == tp->size) {
216                tp->init_now = 1;
217        }
218}
219
220void
221init_triangle(ModeInfo * mi)
222{
223        trianglestruct *tp;
224        short      *tmp;
225        int         i, dim, one;
226
227        if (triangles == NULL) {
228                if ((triangles = (trianglestruct *) calloc(MI_NUM_SCREENS(mi),
229                                           sizeof (trianglestruct))) == NULL)
230                        return;
231        }
232        tp = &triangles[MI_SCREEN(mi)];
233
234        tp->width = MI_WIN_WIDTH(mi);
235        tp->height = MI_WIN_HEIGHT(mi);
236        tp->init_now = 1;
237        tp->fast = 2;
238
239        XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
240
241
242
243        tp->steps = MAX_STEPS;
244        do {
245                tp->size = 1 << --tp->steps;
246        } while (tp->size * 5 > tp->width);
247        tmp = tp->H;
248        for (i = 0; i < tp->size + 1; i++) {
249                tp->h[i] = tmp;
250                tmp += (tp->size) + 1 - i;
251        }
252
253        tp->stage = -1;
254        dim = MIN(tp->width, tp->height);
255
256        for (i = 0; i < 2 * tp->size + 1; i++) {
257                tp->xpos[i] = (short) ((((double) i)
258                         / ((double) (2 * tp->size)) * (RIGHT - LEFT) + LEFT)
259                                       * dim) + (tp->width - dim) / 2;
260        }
261
262        for (i = 0; i < (tp->size + 1); i++) {
263                tp->ypos[i] = (short) ((((double) i)
264                         / ((double) tp->size) * (BOTTOM - TOP) + TOP) * dim)
265                        + (tp->height - dim) / 2;
266        }
267
268        for (i = 0; i < tp->steps; i++) {
269                tp->delta[i] = ((short) (DELTA * dim)) >> i;
270        }
271
272        one = tp->delta[0];
273
274        if (one > 0)
275                for (i = 0; i < MAX_LEVELS; i++) {
276                        tp->level[i] = (i * i) / one;
277                }
278}
279
280void
281draw_triangle(ModeInfo * mi)
282{
283        trianglestruct *tp = &triangles[MI_SCREEN(mi)];
284        int         d, d2, i, j, delta;
285
286        if (!tp->init_now) {
287                draw_mesh(mi, tp, tp->d / 2, MAX_SIZE / tp->d);
288
289                /* The init_now flag will pop up when the scene is complete.
290                 * Cycles specifies how long to wait, in 1/10 secs.
291                 TODO: This is wrong for multi-screens ***
292                 */
293                if (tp->init_now) {
294#ifndef STANDALONE
295                        MI_PAUSE(mi) = 2000000;
296#else
297                        if (tp->stage == -1)
298                          {
299                                XSync(MI_DISPLAY(mi), False);
300                                usleep(2000000);
301                                XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
302# if 1
303                                if (!mono_p)
304                                  {
305                                        free_colors(mi->dpy, mi->xgwa.colormap, mi->colors,
306                                                                mi->npixels);
307                                        make_smooth_colormap (mi->dpy,
308                                                                                  mi->xgwa.visual, mi->xgwa.colormap,
309                                                                                  mi->colors, &mi->npixels,
310                                                                                  True, &mi->writable_p, True);
311                                  }
312# endif /* 0 */
313                          }
314#endif
315                }
316                return;
317        }
318        if (tp->delta[0] > 0) {
319                if (!(++tp->stage)) {
320                        tp->h[0][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
321                        tp->h[tp->size][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
322                        tp->h[0][tp->size] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
323                } else {
324                        d = 2 << (tp->steps - tp->stage);
325                        d2 = d / 2;
326                        delta = tp->delta[tp->stage - 1];
327
328                        for (i = 0; i < tp->size; i += d) {
329                                for (j = 0; j < (tp->size - i); j += d) {
330                                        tp->h[i + d2][j] = (short int) DISPLACE(tp->h[i][j] +
331                                                     tp->h[i + d][j], delta);
332                                        tp->h[i][j + d2] = (short int) DISPLACE(tp->h[i][j] +
333                                                     tp->h[i][j + d], delta);
334                                        tp->h[i + d2][j + d2] = (short int) DISPLACE(tp->h[i + d][j] +
335                                                     tp->h[i][j + d], delta);
336                                }
337
338                                tp->init_now = 0;
339                                tp->i = 0;
340                                tp->j = 0;
341                                tp->d = d;
342                        }
343                }
344        }
345        if (tp->stage == tp->steps) {
346                tp->stage = -1;
347        }
348}
349
350void
351release_triangle(ModeInfo * mi)
352{
353        if (triangles != NULL) {
354                (void) free((void *) triangles);
355                triangles = NULL;
356        }
357}
358
359void
360refresh_triangle(ModeInfo * mi)
361{
362        /* Do nothing, it will refresh by itself */
363}
Note: See TracBrowser for help on using the repository browser.