1 // select.h2 //3 // Copyright (C) 2003, 2004 Jason Bevins4 //5 // This library is free software; you can redistribute it and/or modify it6 // under the terms of the GNU Lesser General Public License as published by7 // the Free Software Foundation; either version 2.1 of the License, or (at8 // your option) any later version.9 //10 // This library is distributed in the hope that it will be useful, but WITHOUT11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public13 // License (COPYING.txt) for more details.14 //15 // You should have received a copy of the GNU Lesser General Public License16 // along with this library; if not, write to the Free Software Foundation,17 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18 //19 // The developer's email is jlbezigvins@gmzigail.com (for great email, take20 // off every 'zig'.)21 //22 modulenoise.mod.select;
23 24 private {
25 importnoise.mod.modulebase;
26 importnoise.interp;
27 debugimportstd.stdio;
28 }
29 30 /// @addtogroup libnoise31 /// @{32 33 /// @addtogroup modules34 /// @{35 36 /// @addtogroup selectormodules37 /// @{38 39 /// Default edge-falloff value for the module::Select noise module.40 constdoubleDEFAULT_SELECT_EDGE_FALLOFF = 0.0;
41 42 /// Default lower bound of the selection range for the43 /// module::Select noise module.44 constdoubleDEFAULT_SELECT_LOWER_BOUND = -1.0;
45 46 /// Default upper bound of the selection range for the47 /// module::Select noise module.48 constdoubleDEFAULT_SELECT_UPPER_BOUND = 1.0;
49 50 /// Noise module that outputs the value selected from one of two source51 /// modules chosen by the output value from a control module.52 ///53 /// @image html moduleselect.png54 ///55 /// Unlike most other noise modules, the index value assigned to a source56 /// 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>control60 /// module</i>. The control module determines the value to select. If61 /// the output value from the control module is within a range of values62 /// known as the <i>selection range</i>, this noise module outputs the63 /// value from the source module with an index value of 1. Otherwise,64 /// this noise module outputs the value from the source module with an65 /// 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 the72 /// application code easier to read.73 ///74 /// By default, there is an abrupt transition between the output values75 /// from the two source modules at the selection-range boundary. To76 /// 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 classSelect : Mod81 {
82 83 public:
84 85 /// Constructor.86 ///87 /// The default falloff value at the edge transition is set to88 /// module::DEFAULT_SELECT_EDGE_FALLOFF.89 ///90 /// The default lower bound of the selection range is set to91 /// module::DEFAULT_SELECT_LOWER_BOUND.92 ///93 /// The default upper bound of the selection range is set to94 /// 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(constdoubleedgeFalloff, constdoublelowerBound, constdoubleupperBound)
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 a116 /// call to SetSourceMod() or SetControlMod().117 ///118 /// @throw new ExceptionNoMod See the preconditions for more119 /// information.120 ///121 /// The control module determines the output value to select. If the122 /// output value from the control module is within a range of values123 /// known as the <i>selection range</i>, the GetValue() method outputs124 /// the value from the source module with an index value of 1.125 /// Otherwise, this method outputs the value from the source module126 /// with an index value of 0.127 refconst(Mod) GetControlMod () const128 {
129 if (m_pSourceMod == null || m_pSourceMod[2] == null) {
130 thrownewExceptionNoMod ();
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 either140 /// edge of the selection range.141 ///142 /// By default, there is an abrupt transition between the output143 /// values from the two source modules at the selection-range144 /// boundary.145 doubleGetEdgeFalloff () const146 {
147 returnm_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 the155 /// selection range, the GetValue() method outputs the value from the156 /// source module with an index value of 1. Otherwise, this method157 /// outputs the value from the source module with an index value of 0.158 doubleGetLowerBound () const159 {
160 returnm_lowerBound;
161 }
162 163 overrideintGetSourceModCount () const164 {
165 return3;
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 the173 /// selection range, the GetValue() method outputs the value from the174 /// source module with an index value of 1. Otherwise, this method175 /// outputs the value from the source module with an index value of 0.176 doubleGetUpperBound () const177 {
178 returnm_upperBound;
179 }
180 181 overridedoubleGetValue (doublex, doubley, doublez) const182 {
183 assert (m_pSourceMod[0] !isnull);
184 assert (m_pSourceMod[1] !isnull);
185 assert (m_pSourceMod[2] !isnull);
186 187 doublecontrolValue = m_pSourceMod[2].GetValue (x, y, z);
188 doublealpha;
189 if (m_edgeFalloff > 0.0) {
190 if (controlValue < (m_lowerBound - m_edgeFalloff)) {
191 // The output value from the control module is below the selector192 // threshold; return the output value from the first source module.193 returnm_pSourceMod[0].GetValue (x, y, z);
194 195 } elseif (controlValue < (m_lowerBound + m_edgeFalloff)) {
196 // The output value from the control module is near the lower end of the197 // selector threshold and within the smooth curve. Interpolate between198 // the output values from the first and second source modules.199 doublelowerCurve = (m_lowerBound - m_edgeFalloff);
200 doubleupperCurve = (m_lowerBound + m_edgeFalloff);
201 alpha = SCurve3 (
202 (controlValue - lowerCurve) / (upperCurve - lowerCurve));
203 returnLinearInterp (m_pSourceMod[0].GetValue (x, y, z),
204 m_pSourceMod[1].GetValue (x, y, z),
205 alpha);
206 207 } elseif (controlValue < (m_upperBound - m_edgeFalloff)) {
208 // The output value from the control module is within the selector209 // threshold; return the output value from the second source module.210 returnm_pSourceMod[1].GetValue (x, y, z);
211 212 } elseif (controlValue < (m_upperBound + m_edgeFalloff)) {
213 // The output value from the control module is near the upper end of the214 // selector threshold and within the smooth curve. Interpolate between215 // the output values from the first and second source modules.216 doublelowerCurve = (m_upperBound - m_edgeFalloff);
217 doubleupperCurve = (m_upperBound + m_edgeFalloff);
218 alpha = SCurve3 (
219 (controlValue - lowerCurve) / (upperCurve - lowerCurve));
220 returnLinearInterp (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 returnm_pSourceMod[0].GetValue (x, y, z);
228 }
229 } else {
230 if (controlValue < m_lowerBound || controlValue > m_upperBound) {
231 returnm_pSourceMod[0].GetValue (x, y, z);
232 } else {
233 returnm_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 upper244 /// bound.245 ///246 /// @throw new ExceptionInvalidParam An invalid parameter was247 /// specified; see the preconditions for more information.248 ///249 /// If the output value from the control module is within the250 /// selection range, the GetValue() method outputs the value from the251 /// source module with an index value of 1. Otherwise, this method252 /// outputs the value from the source module with an index value of 0.253 voidSetBounds (doublelowerBound, doubleupperBound)
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 the269 /// output value from the control module is within a range of values270 /// known as the <i>selection range</i>, the GetValue() method outputs271 /// the value from the source module with an index value of 1.272 /// Otherwise, this method outputs the value from the source module273 /// 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 same277 /// 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 this281 /// noise module unless another control module replaces that control282 /// module.283 voidSetControlMod (const(Mod)* controlMod)
284 {
285 assert (m_pSourceMod !isnull);
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 either294 /// edge of the selection range.295 ///296 /// By default, there is an abrupt transition between the values from297 /// 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 edge300 /// falloff value is 0.1, then the GetValue() method outputs:301 /// - the output value from the source module with an index value of 0302 /// if the output value from the control module is less than 0.4303 /// ( = 0.5 - 0.1).304 /// - a linear blend between the two output values from the two source305 /// modules if the output value from the control module is between306 /// 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 1308 /// if the output value from the control module is between 0.6309 /// ( = 0.5 + 0.1) and 0.7 ( = 0.8 - 0.1).310 /// - a linear blend between the output values from the two source311 /// modules if the output value from the control module is between312 /// 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 0314 /// if the output value from the control module is greater than 0.9315 /// ( = 0.8 + 0.1).316 voidSetEdgeFalloff (doubleedgeFalloff)
317 {
318 // Make sure that the edge falloff curves do not overlap.319 doubleboundSize = m_upperBound - m_lowerBound;
320 m_edgeFalloff = (edgeFalloff > boundSize / 2)? boundSize / 2: edgeFalloff;
321 }
322 323 protected:
324 325 /// Edge-falloff value.326 doublem_edgeFalloff;
327 328 /// Lower bound of the selection range.329 doublem_lowerBound;
330 331 /// Upper bound of the selection range.332 doublem_upperBound;
333 334 };
335 336 /// @}337 338 /// @}339 340 /// @}