1 // select.h
2 //
3 // Copyright (C) 2003, 2004 Jason Bevins
4 //
5 // This library is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or (at
8 // your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
13 // License (COPYING.txt) for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 //
19 // The developer's email is jlbezigvins@gmzigail.com (for great email, take
20 // off every 'zig'.)
21 //
22 module noise.mod.select;
23 
24 private {
25   import noise.mod.modulebase;
26   import noise.interp;
27   debug import std.stdio;
28 }
29 
30 /// @addtogroup libnoise
31 /// @{
32 
33 /// @addtogroup modules
34 /// @{
35 
36 /// @addtogroup selectormodules
37 /// @{
38 
39 /// Default edge-falloff value for the module::Select noise module.
40 const double DEFAULT_SELECT_EDGE_FALLOFF = 0.0;
41 
42 /// Default lower bound of the selection range for the
43 /// module::Select noise module.
44 const double DEFAULT_SELECT_LOWER_BOUND = -1.0;
45 
46 /// Default upper bound of the selection range for the
47 /// module::Select noise module.
48 const double DEFAULT_SELECT_UPPER_BOUND = 1.0;
49 
50 /// Noise module that outputs the value selected from one of two source
51 /// modules chosen by the output value from a control module.
52 ///
53 /// @image html moduleselect.png
54 ///
55 /// Unlike most other noise modules, the index value assigned to a source
56 /// module determines its role in the selection operation:
57 /// - Source module 0 (upper left in the diagram) outputs a value.
58 /// - Source module 1 (lower left in the diagram) outputs a value.
59 /// - Source module 2 (bottom of the diagram) is known as the <i>control
60 ///   module</i>.  The control module determines the value to select.  If
61 ///   the output value from the control module is within a range of values
62 ///   known as the <i>selection range</i>, this noise module outputs the
63 ///   value from the source module with an index value of 1.  Otherwise,
64 ///   this noise module outputs the value from the source module with an
65 ///   index value of 0.
66 ///
67 /// To specify the bounds of the selection range, call the SetBounds()
68 /// method.
69 ///
70 /// An application can pass the control module to the SetControlMod()
71 /// method instead of the SetSourceMod() method.  This may make the
72 /// application code easier to read.
73 ///
74 /// By default, there is an abrupt transition between the output values
75 /// from the two source modules at the selection-range boundary.  To
76 /// smooth the transition, pass a non-zero value to the SetEdgeFalloff()
77 /// method.  Higher values result in a smoother transition.
78 ///
79 /// This noise module requires three source modules.
80 class Select : Mod
81 {
82 
83   public:
84 
85     /// Constructor.
86     ///
87     /// The default falloff value at the edge transition is set to
88     /// module::DEFAULT_SELECT_EDGE_FALLOFF.
89     ///
90     /// The default lower bound of the selection range is set to
91     /// module::DEFAULT_SELECT_LOWER_BOUND.
92     ///
93     /// The default upper bound of the selection range is set to
94     /// module::DEFAULT_SELECT_UPPER_BOUND.
95     this()
96     {
97         super(this.GetSourceModCount ());
98         m_edgeFalloff = DEFAULT_SELECT_EDGE_FALLOFF;
99         m_lowerBound = DEFAULT_SELECT_LOWER_BOUND;
100         m_upperBound = DEFAULT_SELECT_UPPER_BOUND;
101     }
102 
103     this(const double edgeFalloff, const double lowerBound, const double upperBound) 
104     {
105         super(this.GetSourceModCount ());
106         m_edgeFalloff = edgeFalloff;
107         m_lowerBound = lowerBound;
108         m_upperBound = upperBound;
109     }
110 
111     /// Returns the control module.
112     ///
113     /// @returns A reference to the control module.
114     ///
115     /// @pre A control module has been added to this noise module via a
116     /// call to SetSourceMod() or SetControlMod().
117     ///
118     /// @throw new ExceptionNoMod See the preconditions for more
119     /// information.
120     ///
121     /// The control module determines the output value to select.  If the
122     /// output value from the control module is within a range of values
123     /// known as the <i>selection range</i>, the GetValue() method outputs
124     /// the value from the source module with an index value of 1.
125     /// Otherwise, this method outputs the value from the source module
126     /// with an index value of 0.
127     ref const(Mod) GetControlMod () const
128     {
129       if (m_pSourceMod == null || m_pSourceMod[2] == null) {
130         throw new ExceptionNoMod ();
131       }
132       return *(m_pSourceMod[2]);
133     }
134 
135     /// Returns the falloff value at the edge transition.
136     ///
137     /// @returns The falloff value at the edge transition.
138     ///
139     /// The falloff value is the width of the edge transition at either
140     /// edge of the selection range.
141     ///
142     /// By default, there is an abrupt transition between the output
143     /// values from the two source modules at the selection-range
144     /// boundary.
145     double GetEdgeFalloff () const
146     {
147       return m_edgeFalloff;
148     }
149 
150     /// Returns the lower bound of the selection range.
151     ///
152     /// @returns The lower bound of the selection range.
153     ///
154     /// If the output value from the control module is within the
155     /// selection range, the GetValue() method outputs the value from the
156     /// source module with an index value of 1.  Otherwise, this method
157     /// outputs the value from the source module with an index value of 0.
158     double GetLowerBound () const
159     {
160       return m_lowerBound;
161     }
162 
163     override int GetSourceModCount () const
164     {
165       return 3;
166     }
167 
168     /// Returns the upper bound of the selection range.
169     ///
170     /// @returns The upper bound of the selection range.
171     ///
172     /// If the output value from the control module is within the
173     /// selection range, the GetValue() method outputs the value from the
174     /// source module with an index value of 1.  Otherwise, this method
175     /// outputs the value from the source module with an index value of 0.
176     double GetUpperBound () const
177     {
178       return m_upperBound;
179     }
180 
181     override double GetValue (double x, double y, double z) const
182     {
183       assert (m_pSourceMod[0] !is null);
184       assert (m_pSourceMod[1] !is null);
185       assert (m_pSourceMod[2] !is null);
186 
187       double controlValue = m_pSourceMod[2].GetValue (x, y, z);
188       double alpha;
189       if (m_edgeFalloff > 0.0) {
190         if (controlValue < (m_lowerBound - m_edgeFalloff)) {
191           // The output value from the control module is below the selector
192           // threshold; return the output value from the first source module.
193           return m_pSourceMod[0].GetValue (x, y, z);
194 
195         } else if (controlValue < (m_lowerBound + m_edgeFalloff)) {
196           // The output value from the control module is near the lower end of the
197           // selector threshold and within the smooth curve. Interpolate between
198           // the output values from the first and second source modules.
199           double lowerCurve = (m_lowerBound - m_edgeFalloff);
200           double upperCurve = (m_lowerBound + m_edgeFalloff);
201           alpha = SCurve3 (
202             (controlValue - lowerCurve) / (upperCurve - lowerCurve));
203           return LinearInterp (m_pSourceMod[0].GetValue (x, y, z),
204             m_pSourceMod[1].GetValue (x, y, z),
205             alpha);
206 
207         } else if (controlValue < (m_upperBound - m_edgeFalloff)) {
208           // The output value from the control module is within the selector
209           // threshold; return the output value from the second source module.
210           return m_pSourceMod[1].GetValue (x, y, z);
211 
212         } else if (controlValue < (m_upperBound + m_edgeFalloff)) {
213           // The output value from the control module is near the upper end of the
214           // selector threshold and within the smooth curve. Interpolate between
215           // the output values from the first and second source modules.
216           double lowerCurve = (m_upperBound - m_edgeFalloff);
217           double upperCurve = (m_upperBound + m_edgeFalloff);
218           alpha = SCurve3 (
219             (controlValue - lowerCurve) / (upperCurve - lowerCurve));
220           return LinearInterp (m_pSourceMod[1].GetValue (x, y, z),
221             m_pSourceMod[0].GetValue (x, y, z),
222             alpha);
223 
224         } else {
225           // Output value from the control module is above the selector threshold;
226           // return the output value from the first source module.
227           return m_pSourceMod[0].GetValue (x, y, z);
228         }
229       } else {
230         if (controlValue < m_lowerBound || controlValue > m_upperBound) {
231           return m_pSourceMod[0].GetValue (x, y, z);
232         } else {
233           return m_pSourceMod[1].GetValue (x, y, z);
234         }
235       }
236     }
237 
238     /// Sets the lower and upper bounds of the selection range.
239     ///
240     /// @param lowerBound The lower bound.
241     /// @param upperBound The upper bound.
242     ///
243     /// @pre The lower bound must be less than or equal to the upper
244     /// bound.
245     ///
246     /// @throw new ExceptionInvalidParam An invalid parameter was
247     /// specified; see the preconditions for more information.
248     ///
249     /// If the output value from the control module is within the
250     /// selection range, the GetValue() method outputs the value from the
251     /// source module with an index value of 1.  Otherwise, this method
252     /// outputs the value from the source module with an index value of 0.
253     void SetBounds (double lowerBound, double upperBound)
254     {
255       assert (lowerBound < upperBound);
256 
257       m_lowerBound = lowerBound;
258       m_upperBound = upperBound;
259 
260       // Make sure that the edge falloff curves do not overlap.
261       SetEdgeFalloff (m_edgeFalloff);
262     }
263 
264     /// Sets the control module.
265     ///
266     /// @param controlMod The control module.
267     ///
268     /// The control module determines the output value to select.  If the
269     /// output value from the control module is within a range of values
270     /// known as the <i>selection range</i>, the GetValue() method outputs
271     /// the value from the source module with an index value of 1.
272     /// Otherwise, this method outputs the value from the source module
273     /// with an index value of 0.
274     ///
275     /// This method assigns the control module an index value of 2.
276     /// Passing the control module to this method produces the same
277     /// results as passing the control module to the SetSourceMod()
278     /// method while assigning that noise module an index value of 2.
279     ///
280     /// This control module must exist throughout the lifetime of this
281     /// noise module unless another control module replaces that control
282     /// module.
283     void SetControlMod (const(Mod)* controlMod)
284     {
285       assert (m_pSourceMod !is null);
286       m_pSourceMod[2] = controlMod;
287     }
288 
289     /// Sets the falloff value at the edge transition.
290     ///
291     /// @param edgeFalloff The falloff value at the edge transition.
292     ///
293     /// The falloff value is the width of the edge transition at either
294     /// edge of the selection range.
295     ///
296     /// By default, there is an abrupt transition between the values from
297     /// the two source modules at the boundaries of the selection range.
298     ///
299     /// For example, if the selection range is 0.5 to 0.8, and the edge
300     /// falloff value is 0.1, then the GetValue() method outputs:
301     /// - the output value from the source module with an index value of 0
302     ///   if the output value from the control module is less than 0.4
303     ///   ( = 0.5 - 0.1).
304     /// - a linear blend between the two output values from the two source
305     ///   modules if the output value from the control module is between
306     ///   0.4 ( = 0.5 - 0.1) and 0.6 ( = 0.5 + 0.1).
307     /// - the output value from the source module with an index value of 1
308     ///   if the output value from the control module is between 0.6
309     ///   ( = 0.5 + 0.1) and 0.7 ( = 0.8 - 0.1).
310     /// - a linear blend between the output values from the two source
311     ///   modules if the output value from the control module is between
312     ///   0.7 ( = 0.8 - 0.1 ) and 0.9 ( = 0.8 + 0.1).
313     /// - the output value from the source module with an index value of 0
314     ///   if the output value from the control module is greater than 0.9
315     ///   ( = 0.8 + 0.1).
316     void SetEdgeFalloff (double edgeFalloff)
317     {
318       // Make sure that the edge falloff curves do not overlap.
319       double boundSize = m_upperBound - m_lowerBound;
320       m_edgeFalloff = (edgeFalloff > boundSize / 2)? boundSize / 2: edgeFalloff;
321     }
322 
323   protected:
324 
325     /// Edge-falloff value.
326     double m_edgeFalloff;
327 
328     /// Lower bound of the selection range.
329     double m_lowerBound;
330 
331     /// Upper bound of the selection range.
332     double m_upperBound;
333 
334 };
335 
336 /// @}
337 
338 /// @}
339 
340 /// @}