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

Revision 20148, 16.6 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/* lightning --- fractal lightning bolds */
3
4#if 0
5static const char sccsid[] = "@(#)lightning.c   5.00 2000/11/01 xlockmore";
6#endif
7
8/*-
9 * Copyright (c) 1996 by Keith Romberg <kromberg@saxe.com>
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 * 01-Nov-2000: Allocation checks
25 * 10-May-1997: Compatible with xscreensaver
26 * 14-Jul-1996: Cleaned up code.
27 * 27-Jun-1996: Written and submitted by Keith Romberg <kromberg@saxe.com>.
28 */
29
30#ifdef STANDALONE
31#define MODE_lightning
32#define PROGCLASS "Lightning"
33#define HACK_INIT init_lightning
34#define HACK_DRAW draw_lightning
35#define lightning_opts xlockmore_opts
36#define DEFAULTS "*delay: 10000 \n"
37#define BRIGHT_COLORS
38#include "xlockmore.h"          /* in xscreensaver distribution */
39#else /* STANDALONE */
40#include "xlock.h"              /* in xlockmore distribution */
41#endif /* STANDALONE */
42
43#ifdef MODE_lightning
44
45ModeSpecOpt lightning_opts =
46{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
47
48#ifdef USE_MODULES
49ModStruct   lightning_description =
50{"lightning", "init_lightning", "draw_lightning", "release_lightning",
51 "refresh_lightning", "init_lightning", (char *) NULL, &lightning_opts,
52 10000, 1, 1, 1, 64, 0.6, "",
53 "Shows Keith's fractal lightning bolts", 0, NULL};
54
55#endif
56
57#define BOLT_NUMBER 4
58#define BOLT_ITERATION 4
59#define LONG_FORK_ITERATION 3
60#define MEDIUM_FORK_ITERATION 2
61#define SMALL_FORK_ITERATION 1
62
63#define WIDTH_VARIATION 30
64#define HEIGHT_VARIATION 15
65
66#define DELAY_TIME_AMOUNT 15
67#define MULTI_DELAY_TIME_BASE 5
68
69#define MAX_WIGGLES 16
70#define WIGGLE_BASE 8
71#define WIGGLE_AMOUNT 14
72
73#define RANDOM_FORK_PROBILITY   4
74
75#define FIRST_LEVEL_STRIKE 0
76#define LEVEL_ONE_STRIKE 1
77#define LEVEL_TWO_STRIKE 2
78
79#define BOLT_VERTICIES ((1<<BOLT_ITERATION)-1)
80  /* BOLT_ITERATION = 4. 2^(BOLT_ITERATION) - 1 = 15 */
81
82#define NUMBER_FORK_VERTICIES 9
83
84#define FLASH_PROBILITY 20
85#define MAX_FLASH_AMOUNT 2      /*  half the total duration of the bolt  */
86
87typedef struct {
88        XPoint      ForkVerticies[NUMBER_FORK_VERTICIES];
89        int         num_used;
90} Fork;
91
92typedef struct {
93        XPoint      end1, end2;
94        XPoint      middle[BOLT_VERTICIES];
95        int         fork_number;
96        int         forks_start[2];
97        Fork        branch[2];
98        int         wiggle_number;
99        int         wiggle_amount;
100        int         delay_time;
101        int         flash;
102        int         flash_begin, flash_stop;
103        int         visible;
104        int         strike_level;
105} Lightning;
106
107typedef struct {
108        Lightning   bolts[BOLT_NUMBER];
109        int         scr_width, scr_height;
110        int         multi_strike;
111        int         give_it_hell;
112        int         draw_time;
113        int         stage;
114        int         busyLoop;
115        unsigned long color;
116} Storm;
117
118static Storm *Helga = (Storm *) NULL;
119
120/*-------------------   function prototypes  ----------------------------*/
121
122static int  distance(XPoint a, XPoint b);
123
124static int  setup_multi_strike(void);
125static int  flashing_strike(void);
126static void flash_duration(int *start, int *end, int total_duration);
127static void random_storm(Storm * st);
128static void generate(XPoint A, XPoint B, int iter, XPoint * verts, int *vert_index);
129static void create_fork(Fork * f, XPoint start, XPoint end, int level);
130
131static void first_strike(Lightning bolt, ModeInfo * mi);
132static void draw_bolt(Lightning * bolt, ModeInfo * mi);
133static void draw_line(ModeInfo * mi, XPoint * p, int number, GC use, int x_offset);
134static void level1_strike(Lightning bolt, ModeInfo * mi);
135static void level2_strike(Lightning bolt, ModeInfo * mi);
136
137static int  storm_active(Storm * st);
138static void update_bolt(Lightning * bolt, int time_now);
139static void wiggle_bolt(Lightning * bolt);
140static void wiggle_line(XPoint * p, int number, int wiggle_amount);
141
142/*-------------------------  functions  ---------------------------------*/
143
144static int
145setup_multi_strike(void)
146{
147        int         result, multi_prob;
148
149        multi_prob = NRAND(100);
150
151        if (multi_prob < 50)
152                result = 1;
153        else if ((multi_prob >= 51) && (multi_prob < 75))
154                result = 2;
155        else if ((multi_prob >= 76) && (multi_prob < 92))
156                result = 3;
157        else
158                result = BOLT_NUMBER;   /* 4 */
159
160        return (result);
161}
162
163/*-------------------------------------------------------------------------*/
164
165static int
166flashing_strike(void)
167{
168        int         tmp = NRAND(FLASH_PROBILITY);
169
170        if (tmp <= FLASH_PROBILITY)
171                return (1);
172        return (0);
173}
174
175/*-------------------------------------------------------------------------*/
176
177static void
178flash_duration(int *start, int *end, int total_duration)
179{
180        int         mid, d;
181
182        mid = total_duration / MAX_FLASH_AMOUNT;
183        d = NRAND(total_duration / MAX_FLASH_AMOUNT) / 2;
184        *start = mid - d;
185        *end = mid + d;
186}
187
188/*-------------------------------------------------------------------------*/
189
190static void
191random_storm(Storm * st)
192{
193        int         i, j, tmp;
194        XPoint      p;
195
196        for (i = 0; i < st->multi_strike; i++) {
197                st->bolts[i].end1.x = NRAND(st->scr_width);
198                st->bolts[i].end1.y = 0;
199                st->bolts[i].end2.x = NRAND(st->scr_width);
200                st->bolts[i].end2.y = st->scr_height;
201                st->bolts[i].wiggle_number = WIGGLE_BASE + NRAND(MAX_WIGGLES);
202                if ((st->bolts[i].flash = flashing_strike()))
203                        flash_duration(&(st->bolts[i].flash_begin), &(st->bolts[i].flash_stop),
204                                       st->bolts[i].wiggle_number);
205                else
206                        st->bolts[i].flash_begin = st->bolts[i].flash_stop = 0;
207                st->bolts[i].wiggle_amount = WIGGLE_AMOUNT;
208                if (i == 0)
209                        st->bolts[i].delay_time = NRAND(DELAY_TIME_AMOUNT);
210                else
211                        st->bolts[i].delay_time = NRAND(DELAY_TIME_AMOUNT) +
212                                (MULTI_DELAY_TIME_BASE * i);
213                st->bolts[i].strike_level = FIRST_LEVEL_STRIKE;
214                tmp = 0;
215                generate(st->bolts[i].end1, st->bolts[i].end2, BOLT_ITERATION,
216                         st->bolts[i].middle, &tmp);
217                st->bolts[i].fork_number = 0;
218                st->bolts[i].visible = 0;
219                for (j = 0; j < BOLT_VERTICIES; j++) {
220                        if (st->bolts[i].fork_number >= 2)
221                                break;
222                        if (NRAND(100) < RANDOM_FORK_PROBILITY) {
223                                p.x = NRAND(st->scr_width);
224                                p.y = st->scr_height;
225                                st->bolts[i].forks_start[st->bolts[i].fork_number] = j;
226                                create_fork(&(st->bolts[i].branch[st->bolts[i].fork_number]),
227                                            st->bolts[i].middle[j], p, j);
228                                st->bolts[i].fork_number++;
229                        }
230                }
231        }
232}
233
234static void
235generate(XPoint A, XPoint B, int iter, XPoint * verts, int *vert_index)
236{
237        XPoint      mid;
238
239        mid.x = (A.x + B.x) / 2 + NRAND(WIDTH_VARIATION) - WIDTH_VARIATION / 2;
240        mid.y = (A.y + B.y) / 2 + NRAND(HEIGHT_VARIATION) - HEIGHT_VARIATION / 2;
241
242        if (!iter) {
243                verts[*vert_index].x = mid.x;
244                verts[*vert_index].y = mid.y;
245                (*vert_index)++;
246                return;
247        }
248        generate(A, mid, iter - 1, verts, vert_index);
249        generate(mid, B, iter - 1, verts, vert_index);
250}
251
252/*------------------------------------------------------------------------*/
253
254static void
255create_fork(Fork * f, XPoint start, XPoint end, int level)
256{
257        int         tmp = 1;
258
259        f->ForkVerticies[0].x = start.x;
260        f->ForkVerticies[0].y = start.y;
261
262        if (level <= 6) {
263                generate(start, end, LONG_FORK_ITERATION, f->ForkVerticies, &tmp);
264                f->num_used = 9;
265        } else if ((level > 6) && (level <= 11)) {
266                generate(start, end, MEDIUM_FORK_ITERATION, f->ForkVerticies, &tmp);
267                f->num_used = 5;
268        } else {
269                if (distance(start, end) > 100) {
270                        generate(start, end, MEDIUM_FORK_ITERATION, f->ForkVerticies, &tmp);
271                        f->num_used = 5;
272                } else {
273                        generate(start, end, SMALL_FORK_ITERATION, f->ForkVerticies, &tmp);
274                        f->num_used = 3;
275                }
276        }
277
278        f->ForkVerticies[f->num_used - 1].x = end.x;
279        f->ForkVerticies[f->num_used - 1].y = end.y;
280}
281
282/*------------------------------------------------------------------------*/
283
284static void
285update_bolt(Lightning * bolt, int time_now)
286{
287        wiggle_bolt(bolt);
288        if ((bolt->wiggle_amount == 0) && (bolt->wiggle_number > 2))
289                bolt->wiggle_number = 0;
290        if (((time_now % 3) == 0))
291                bolt->wiggle_amount++;
292
293        if (((time_now >= bolt->delay_time) && (time_now < bolt->flash_begin)) ||
294            (time_now > bolt->flash_stop))
295                bolt->visible = 1;
296        else
297                bolt->visible = 0;
298
299        if (time_now == bolt->delay_time)
300                bolt->strike_level = FIRST_LEVEL_STRIKE;
301        else if (time_now == (bolt->delay_time + 1))
302                bolt->strike_level = LEVEL_ONE_STRIKE;
303        else if ((time_now > (bolt->delay_time + 1)) &&
304                 (time_now <= (bolt->delay_time + bolt->flash_begin - 2)))
305                bolt->strike_level = LEVEL_TWO_STRIKE;
306        else if (time_now == (bolt->delay_time + bolt->flash_begin - 1))
307                bolt->strike_level = LEVEL_ONE_STRIKE;
308        else if (time_now == (bolt->delay_time + bolt->flash_stop + 1))
309                bolt->strike_level = LEVEL_ONE_STRIKE;
310        else
311                bolt->strike_level = LEVEL_TWO_STRIKE;
312}
313
314/*------------------------------------------------------------------------*/
315
316static void
317draw_bolt(Lightning * bolt, ModeInfo * mi)
318{
319        if (bolt->visible) {
320                if (bolt->strike_level == FIRST_LEVEL_STRIKE)
321                        first_strike(*bolt, mi);
322                else if (bolt->strike_level == LEVEL_ONE_STRIKE)
323                        level1_strike(*bolt, mi);
324                else
325                        level2_strike(*bolt, mi);
326        }
327}
328
329/*------------------------------------------------------------------------*/
330
331static void
332first_strike(Lightning bolt, ModeInfo * mi)
333{
334        Display    *display = MI_DISPLAY(mi);
335        Window      window = MI_WINDOW(mi);
336        GC          gc = MI_GC(mi);
337        int         i;
338
339        XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
340        XDrawLine(display, window, gc,
341               bolt.end1.x, bolt.end1.y, bolt.middle[0].x, bolt.middle[0].y);
342        draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 0);
343        XDrawLine(display, window, gc,
344        bolt.middle[BOLT_VERTICIES - 1].x, bolt.middle[BOLT_VERTICIES - 1].y,
345                  bolt.end2.x, bolt.end2.y);
346
347        for (i = 0; i < bolt.fork_number; i++)
348                draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used,
349                          gc, 0);
350}
351
352/*------------------------------------------------------------------------*/
353
354static void
355draw_line(ModeInfo * mi, XPoint * points, int number, GC to_use, int offset)
356{
357        int         i;
358
359        for (i = 0; i < number - 1; i++) {
360                if (points[i].y <= points[i + 1].y)
361                        XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x + offset,
362                                  points[i].y, points[i + 1].x + offset, points[i + 1].y);
363                else {
364                        if (points[i].x < points[i + 1].x)
365                                XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x +
366                                          offset, points[i].y + offset, points[i + 1].x + offset,
367                                          points[i + 1].y + offset);
368                        else
369                                XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), to_use, points[i].x -
370                                          offset, points[i].y + offset, points[i + 1].x - offset,
371                                          points[i + 1].y + offset);
372                }
373        }
374}
375
376/*------------------------------------------------------------------------*/
377
378static void
379level1_strike(Lightning bolt, ModeInfo * mi)
380{
381        Display    *display = MI_DISPLAY(mi);
382        Window      window = MI_WINDOW(mi);
383        Storm      *st = &Helga[MI_SCREEN(mi)];
384        GC          gc = MI_GC(mi);
385        int         i;
386
387        if (MI_NPIXELS(mi) > 2) /* color */
388                XSetForeground(display, gc, MI_PIXEL(mi, st->color));
389        else
390                XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
391        XDrawLine(display, window, gc,
392        bolt.end1.x - 1, bolt.end1.y, bolt.middle[0].x - 1, bolt.middle[0].y);
393        draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, -1);
394        XDrawLine(display, window, gc,
395                  bolt.middle[BOLT_VERTICIES - 1].x - 1,
396            bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x - 1, bolt.end2.y);
397        XDrawLine(display, window, gc,
398        bolt.end1.x + 1, bolt.end1.y, bolt.middle[0].x + 1, bolt.middle[0].y);
399        draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 1);
400        XDrawLine(display, window, gc,
401                  bolt.middle[BOLT_VERTICIES - 1].x + 1,
402            bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x + 1, bolt.end2.y);
403
404        for (i = 0; i < bolt.fork_number; i++) {
405                draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used,
406                          gc, -1);
407                draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used,
408                          gc, 1);
409        }
410        first_strike(bolt, mi);
411}
412
413/*------------------------------------------------------------------------*/
414
415static int
416distance(XPoint a, XPoint b)
417{
418        return ((int) sqrt((double) (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)));
419}
420
421/*------------------------------------------------------------------------*/
422
423static void
424level2_strike(Lightning bolt, ModeInfo * mi)
425{
426        Display    *display = MI_DISPLAY(mi);
427        Window      window = MI_WINDOW(mi);
428        Storm      *st = &Helga[MI_SCREEN(mi)];
429        GC          gc = MI_GC(mi);
430        int         i;
431
432        /* This was originally designed to be a little darker then the
433           level1 strike.  This was changed to get it to work on
434           multiscreens and to add more color variety.   I tried
435           stippling but it did not look good. */
436        if (MI_NPIXELS(mi) > 2)
437                XSetForeground(display, gc, MI_PIXEL(mi, st->color));
438        else
439                XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
440        XDrawLine(display, window, gc,
441        bolt.end1.x - 2, bolt.end1.y, bolt.middle[0].x - 2, bolt.middle[0].y);
442        draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, -2);
443        XDrawLine(display, window, gc,
444                  bolt.middle[BOLT_VERTICIES - 1].x - 2,
445            bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x - 2, bolt.end2.y);
446
447        XDrawLine(display, window, gc,
448        bolt.end1.x + 2, bolt.end1.y, bolt.middle[0].x + 2, bolt.middle[0].y);
449        draw_line(mi, bolt.middle, BOLT_VERTICIES, gc, 2);
450        XDrawLine(display, window, gc,
451                  bolt.middle[BOLT_VERTICIES - 1].x + 2,
452            bolt.middle[BOLT_VERTICIES - 1].y, bolt.end2.x + 2, bolt.end2.y);
453
454        for (i = 0; i < bolt.fork_number; i++) {
455                draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used,
456                          gc, -2);
457                draw_line(mi, bolt.branch[i].ForkVerticies, bolt.branch[i].num_used,
458                          gc, 2);
459        }
460        level1_strike(bolt, mi);
461}
462
463/*------------------------------------------------------------------------*/
464
465static int
466storm_active(Storm * st)
467{
468        int         i, atleast_1 = 0;
469
470        for (i = 0; i < st->multi_strike; i++)
471                if (st->bolts[i].wiggle_number > 0)
472                        atleast_1++;
473
474        return (atleast_1);
475}
476
477/*------------------------------------------------------------------------*/
478
479static void
480wiggle_bolt(Lightning * bolt)
481{
482        int         i;
483
484        wiggle_line(bolt->middle, BOLT_VERTICIES, bolt->wiggle_amount);
485        bolt->end2.x += NRAND(bolt->wiggle_amount) - bolt->wiggle_amount / 2;
486        bolt->end2.y += NRAND(bolt->wiggle_amount) - bolt->wiggle_amount / 2;
487
488        for (i = 0; i < bolt->fork_number; i++) {
489                wiggle_line(bolt->branch[i].ForkVerticies, bolt->branch[i].num_used,
490                            bolt->wiggle_amount);
491                bolt->branch[i].ForkVerticies[0].x = bolt->middle[bolt->forks_start[i]].x;
492                bolt->branch[i].ForkVerticies[0].y = bolt->middle[bolt->forks_start[i]].y;
493        }
494
495        if (bolt->wiggle_amount > 1)
496                bolt->wiggle_amount -= 1;
497        else
498                bolt->wiggle_amount = 0;
499}
500
501/*------------------------------------------------------------------------*/
502
503static void
504wiggle_line(XPoint * p, int number, int amount)
505{
506        int         i;
507
508        for (i = 0; i < number; i++) {
509                p[i].x += NRAND(amount) - amount / 2;
510                p[i].y += NRAND(amount) - amount / 2;
511        }
512}
513
514/*------------------------------------------------------------------------*/
515
516void
517init_lightning(ModeInfo * mi)
518{
519        Storm      *st;
520
521        if (Helga == NULL) {
522                if ((Helga = (Storm *) calloc(MI_NUM_SCREENS(mi),
523                                              sizeof (Storm))) == NULL)
524                        return;
525        }
526        st = &Helga[MI_SCREEN(mi)];
527
528        st->scr_width = MI_WIDTH(mi);
529        st->scr_height = MI_HEIGHT(mi);
530
531        st->multi_strike = setup_multi_strike();
532        random_storm(st);
533        st->stage = 0;
534}
535
536/*------------------------------------------------------------------------*/
537
538void
539draw_lightning(ModeInfo * mi)
540{
541        int         i;
542        Storm      *st;
543
544        if (Helga == NULL)
545                return;
546        st = &Helga[MI_SCREEN(mi)];
547        MI_IS_DRAWN(mi) = True;
548        switch (st->stage) {
549                case 0:
550                        MI_IS_DRAWN(mi) = False;
551                        MI_CLEARWINDOW(mi);
552                        MI_IS_DRAWN(mi) = True;
553
554                        st->color = NRAND(MI_NPIXELS(mi));
555                        st->draw_time = 0;
556                        if (storm_active(st))
557                                st->stage++;
558                        else
559                                st->stage = 4;
560                        break;
561                case 1:
562                        for (i = 0; i < st->multi_strike; i++) {
563                                if (st->bolts[i].visible)
564                                        draw_bolt(&(st->bolts[i]), mi);
565                                update_bolt(&(st->bolts[i]), st->draw_time);
566                        }
567                        st->draw_time++;
568                        st->stage++;
569                        st->busyLoop = 0;
570                        break;
571                case 2:
572                        if (++st->busyLoop > 6) {
573                                st->stage++;
574                                st->busyLoop = 0;
575                        }
576                        break;
577                case 3:
578                        MI_IS_DRAWN(mi) = False;
579                        MI_CLEARWINDOW(mi);
580                        MI_IS_DRAWN(mi) = True;
581
582                        if (storm_active(st))
583                                st->stage = 1;
584                        else
585                                st->stage++;
586                        break;
587                case 4:
588                        if (++st->busyLoop > 100) {
589                                st->busyLoop = 0;
590                        }
591                        init_lightning(mi);
592                        break;
593        }
594}
595
596void
597release_lightning(ModeInfo * mi)
598{
599        if (Helga != NULL) {
600                (void) free((void *) Helga);
601                Helga = (Storm *) NULL;
602        }
603}
604
605void
606refresh_lightning(ModeInfo * mi)
607{
608        /* Do nothing, it will refresh by itself */
609}
610
611#endif /* MODE_lightning */
Note: See TracBrowser for help on using the repository browser.