1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* triangle --- create a triangle-mountain */
5 static const char sccsid[] = "@(#)triangle.c 4.04 97/07/28 xlockmore";
9 * Copyright (c) 1995 by Tobias Gloth
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.
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.
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
49 # define DEFAULTS "*delay: 10000 \n" \
51 "*fpsSolid: true \n" \
53 # define SMOOTH_COLORS
54 # include "xlockmore.h" /* in xscreensaver distribution */
55 #else /* STANDALONE */
56 # include "xlock.h" /* in xlockmore distribution */
57 #endif /* STANDALONE */
59 ENTRYPOINT ModeSpecOpt triangle_opts =
60 {0, NULL, 0, NULL, NULL};
63 #define MAX_SIZE (1<<MAX_STEPS)
64 #define MAX_LEVELS 1000
66 #undef TOP /* FTSO AIX */
73 #define BLUE 45 /* Just the right shade of blue */
75 #define BACKFACE_REMOVAL
77 #define DISPLACE(h,d) ((h)/2+LRAND()/(MAXRAND/(2*(d)+1))-d)
90 short level[MAX_LEVELS];
91 int xpos[2 * MAX_SIZE + 1];
92 int ypos[MAX_SIZE + 1];
93 short H[(MAX_SIZE + 1) * (MAX_SIZE + 2) / 2];
94 short *h[MAX_SIZE + 1];
95 short delta[MAX_STEPS];
98 static trianglestruct *triangles = NULL;
102 draw_atriangle(ModeInfo * mi, XPoint * p, int y_0, int y_1, int y_2, double dinv)
104 Display *display = MI_DISPLAY(mi);
105 Window window = MI_WINDOW(mi);
108 if (MI_NCOLORS(mi) > 2) { /* color */
112 dmin = MIN(y_0, y_1);
113 dmin = MIN(dmin, y_2);
114 dmax = MAX(y_0, y_1);
115 dmax = MAX(dmax, y_2);
120 color = MI_NCOLORS(mi) -
121 (int) ((double) MI_NCOLORS(mi) / M_PI_2 * atan(dinv * (dmax - dmin)));
124 XSetForeground(display, gc, mi->colors[color % MI_NCOLORS(mi)].pixel);
125 XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
128 #ifdef BACKFACE_REMOVAL
129 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
130 XFillPolygon(display, window, gc, p, 3, Convex, CoordModeOrigin);
132 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
133 XDrawLine(display, window, gc, p[0].x, p[0].y, p[1].x, p[1].y);
134 XDrawLine(display, window, gc, p[1].x, p[1].y, p[2].x, p[2].y);
135 XDrawLine(display, window, gc, p[2].x, p[2].y, p[0].x, p[0].y);
141 calc_points1(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
143 *y0_p = tp->level[MAX(tp->h[tp->i][tp->j], 0)];
144 *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
145 *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
147 p[0].x = tp->xpos[2 * tp->i + tp->j];
148 p[1].x = tp->xpos[2 * (tp->i + d) + tp->j];
149 p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
151 p[0].y = tp->ypos[tp->j] - *y0_p;
152 p[1].y = tp->ypos[tp->j] - *y1_p;
153 p[2].y = tp->ypos[tp->j + d] - *y2_p;
158 calc_points2(trianglestruct * tp, int d, int *y0_p, int *y1_p, int *y2_p, XPoint * p)
160 *y0_p = tp->level[MAX(tp->h[tp->i + d][tp->j], 0)];
161 *y1_p = tp->level[MAX(tp->h[tp->i + d][tp->j + d], 0)];
162 *y2_p = tp->level[MAX(tp->h[tp->i][tp->j + d], 0)];
164 p[0].x = tp->xpos[2 * (tp->i + d) + tp->j];
165 p[1].x = tp->xpos[2 * (tp->i + d) + (tp->j + d)];
166 p[2].x = tp->xpos[2 * tp->i + (tp->j + d)];
168 p[0].y = tp->ypos[tp->j] - *y0_p;
169 p[1].y = tp->ypos[tp->j + d] - *y1_p;
170 p[2].y = tp->ypos[tp->j + d] - *y2_p;
176 draw_mesh(ModeInfo * mi, trianglestruct * tp, int d, int count)
181 double dinv = 0.2 / d;
183 if ((tp->j == 0) && (tp->i == 0)) {
185 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
190 int x2 = MI_WIN_WIDTH(mi);
191 int y2 = tp->ypos[0];
192 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
193 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
198 for (; (tp->j < tp->size) && (count > 0); tp->j += ((count) ? d : 0)) {
199 for (tp->i = (first) ? tp->i : 0, first = 0;
200 (tp->i < MAX_SIZE - tp->j) && (count > 0);
201 tp->i += d, count--) {
202 if (tp->i + tp->j < tp->size) {
203 calc_points1(tp, d, &y_0, &y_1, &y_2, p);
204 draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
206 if (tp->i + tp->j + d < tp->size) {
207 calc_points2(tp, d, &y_0, &y_1, &y_2, p);
208 draw_atriangle(mi, p, y_0, y_1, y_2, dinv);
213 if (tp->j == tp->size) {
219 init_triangle (ModeInfo * mi)
225 if (triangles == NULL) {
226 if ((triangles = (trianglestruct *) calloc(MI_NUM_SCREENS(mi),
227 sizeof (trianglestruct))) == NULL)
230 tp = &triangles[MI_SCREEN(mi)];
232 tp->width = MI_WIN_WIDTH(mi);
233 tp->height = MI_WIN_HEIGHT(mi);
237 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
241 tp->steps = MAX_STEPS;
243 tp->size = 1 << --tp->steps;
244 } while (tp->size * 5 > tp->width);
246 for (i = 0; i < tp->size + 1; i++) {
248 tmp += (tp->size) + 1 - i;
252 dim = MIN(tp->width, tp->height);
254 for (i = 0; i < 2 * tp->size + 1; i++) {
255 tp->xpos[i] = (short) ((((double) i)
256 / ((double) (2 * tp->size)) * (RIGHT - LEFT) + LEFT)
257 * dim) + (tp->width - dim) / 2;
260 for (i = 0; i < (tp->size + 1); i++) {
261 tp->ypos[i] = (short) ((((double) i)
262 / ((double) tp->size) * (BOTTOM - TOP) + TOP) * dim)
263 + (tp->height - dim) / 2;
266 for (i = 0; i < tp->steps; i++) {
267 tp->delta[i] = ((short) (DELTA * dim)) >> i;
273 for (i = 0; i < MAX_LEVELS; i++) {
274 tp->level[i] = (i * i) / one;
279 draw_triangle (ModeInfo * mi)
281 trianglestruct *tp = &triangles[MI_SCREEN(mi)];
282 int d, d2, i, j, delta;
285 draw_mesh(mi, tp, tp->d / 2, MAX_SIZE / tp->d);
287 /* The init_now flag will pop up when the scene is complete.
288 * Cycles specifies how long to wait, in 1/10 secs.
289 TODO: This is wrong for multi-screens ***
293 MI_PAUSE(mi) = 2000000;
297 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
300 free_colors(mi->xgwa.screen, mi->xgwa.colormap, mi->colors,
303 get_integer_resource (mi->dpy, "ncolors", "Integer");
304 make_smooth_colormap (mi->xgwa.screen,
305 mi->xgwa.visual, mi->xgwa.colormap,
306 mi->colors, &mi->npixels,
307 True, &mi->writable_p, True);
314 if (tp->delta[0] > 0) {
315 if (!(++tp->stage)) {
316 tp->h[0][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
317 tp->h[tp->size][0] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
318 tp->h[0][tp->size] = (short int) MAX(0, DISPLACE(0, tp->delta[0]));
320 d = 2 << (tp->steps - tp->stage);
322 delta = tp->delta[tp->stage - 1];
324 for (i = 0; i < tp->size; i += d) {
325 for (j = 0; j < (tp->size - i); j += d) {
326 tp->h[i + d2][j] = (short int) DISPLACE(tp->h[i][j] +
327 tp->h[i + d][j], delta);
328 tp->h[i][j + d2] = (short int) DISPLACE(tp->h[i][j] +
329 tp->h[i][j + d], delta);
330 tp->h[i + d2][j + d2] = (short int) DISPLACE(tp->h[i + d][j] +
331 tp->h[i][j + d], delta);
341 if (tp->stage == tp->steps) {
347 reshape_triangle(ModeInfo * mi, int width, int height)
349 XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi));
354 release_triangle(ModeInfo * mi)
356 if (triangles != NULL) {
357 (void) free((void *) triangles);
363 refresh_triangle (ModeInfo * mi)
365 /* Do nothing, it will refresh by itself */
369 triangle_handle_event (ModeInfo *mi, XEvent *event)
371 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
373 reshape_triangle (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
380 XSCREENSAVER_MODULE ("Triangle", triangle)