1 /* -copyright-
2 #-#
3 #-# xsnow: let it snow on your desktop
4 #-# Copyright (C) 1984,1988,1990,1993-1995,2000-2001 Rick Jansen
5 #-# 	      2019,2020,2021 Willem Vermin
6 #-#
7 #-# This program is free software: you can redistribute it and/or modify
8 #-# it under the terms of the GNU General Public License as published by
9 #-# the Free Software Foundation, either version 3 of the License, or
10 #-# (at your option) any later version.
11 #-#
12 #-# This program is distributed in the hope that it will be useful,
13 #-# but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #-# GNU General Public License for more details.
16 #-#
17 #-# You should have received a copy of the GNU General Public License
18 #-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #-#
20 */
21 
22 #include <stdio.h>
23 #include <gtk/gtk.h>
24 #include <stdlib.h>
25 
26 #include "wind.h"
27 #include "utils.h"
28 #include "debug.h"
29 #include "flags.h"
30 #include "windows.h"
31 #include "clocks.h"
32 #include "xsnow.h"
33 
34 #define NOTACTIVE \
35    (Flags.BirdsOnly || !WorkspaceActive())
36 
37 
38 static void   SetWhirl(void);
39 static void   SetWindTimer(void);
40 static int    do_wind(void *);
41 static int    do_newwind(void *);
42 
wind_init()43 void wind_init()
44 {
45    SetWhirl();
46    SetWindTimer();
47    add_to_mainloop(PRIORITY_DEFAULT, time_newwind,        do_newwind );
48    add_to_mainloop(PRIORITY_DEFAULT, time_wind,           do_wind    );
49 }
50 
wind_ui()51 void wind_ui()
52 {
53    UIDO(NoWind, global.Wind = 0; global.NewWind = 0;);
54    UIDO(WhirlFactor, SetWhirl(););
55    UIDO(WindTimer, SetWindTimer(););
56    if(Flags.WindNow)
57    {
58       Flags.WindNow = 0;
59       global.Wind = 2;
60       P("Gust: %d\n",Flags.Changes);
61    }
62 }
63 
draw_wind()64 void draw_wind()
65 {
66    // Nothing to draw
67 }
68 
do_newwind(void * d)69 int do_newwind(void *d)
70 {
71    P("newwind\n");
72    if (Flags.Done)
73       return FALSE;
74    if (NOTACTIVE)
75       return TRUE;
76    //
77    // the speed of newwind is pixels/second
78    // at steady Wind, eventually all flakes get this speed.
79    //
80    if(Flags.NoWind) return TRUE;
81    static double t0 = -1;
82    if (t0<0)
83    {
84       t0 = wallclock();
85       return TRUE;
86    }
87 
88    float r;
89    switch (global.Wind)
90    {
91       case(0):
92       default:
93 	 r = drand48()*global.Whirl;
94 	 global.NewWind += r - global.Whirl/2;
95 	 if(global.NewWind > global.WindMax) global.NewWind = global.WindMax;
96 	 if(global.NewWind < -global.WindMax) global.NewWind = -global.WindMax;
97 	 break;
98       case(1):
99 	 global.NewWind = global.Direction*0.6*global.Whirl;
100 	 break;
101       case(2):
102 	 global.NewWind = global.Direction*1.2*global.Whirl;
103 	 break;
104    }
105    return TRUE;
106    (void)d;
107 }
108 
do_wind(void * d)109 int do_wind(void *d)
110 {
111    P("wind\n");
112    if (Flags.Done)
113       return FALSE;
114    if (NOTACTIVE)
115       return TRUE;
116    if(Flags.NoWind) return TRUE;
117    static int first = 1;
118    static double prevtime;
119 
120    double TNow = wallclock();
121    if (first)
122    {
123       prevtime = TNow;;
124       first    = 0;
125    }
126 
127    // on the average, this function will do something
128    // after WindTimer secs
129 
130    if ((TNow - prevtime) < 2*global.WindTimer*drand48()) return TRUE;
131 
132    prevtime = TNow;
133 
134    if(drand48() > 0.65)  // Now for some of Rick's magic:
135    {
136       if(drand48() > 0.4)
137 	 global.Direction = 1;
138       else
139 	 global.Direction = -1;
140       global.Wind = 2;
141       global.WindTimer = 5;
142       //               next time, this function will be active
143       //               after on average 5 secs
144    }
145    else
146    {
147       if(global.Wind == 2)
148       {
149 	 global.Wind = 1;
150 	 global.WindTimer = 3;
151 	 //                   next time, this function will be active
152 	 //                   after on average 3 secs
153       }
154       else
155       {
156 	 global.Wind = 0;
157 	 global.WindTimer = global.WindTimerStart;
158 	 //                   next time, this function will be active
159 	 //                   after on average WindTimerStart secs
160       }
161    }
162    return TRUE;
163    (void)d;
164 }
165 
SetWhirl()166 void SetWhirl()
167 {
168    global.Whirl = 0.01*Flags.WhirlFactor*WHIRL;
169 }
170 
SetWindTimer()171 void SetWindTimer()
172 {
173    global.WindTimerStart    = Flags.WindTimer;
174    if (global.WindTimerStart < 3)
175       global.WindTimerStart = 3;
176    global.WindTimer         = global.WindTimerStart;
177 }
178