4949cb8c430cbeec6ea265817fc4b04e80c12edd
[blender.git] / source / blender / freestyle / intern / system / PseudoNoise.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/freestyle/intern/system/PseudoNoise.cpp
22  *  \ingroup freestyle
23  *  \brief Class to define a pseudo Perlin noise
24  *  \author Fredo Durand
25  *  \date 16/06/2003
26  */
27
28 #include "BLI_math.h"
29 #include "BLI_utildefines.h"
30
31 #include "PseudoNoise.h"
32 #include "RandGen.h"
33
34 static int modf_to_index(Freestyle::real x, unsigned int range)
35 {
36         if (finite(x)) {
37                 Freestyle::real tmp;
38                 int i = abs((int)(modf(x, &tmp) * range));
39                 BLI_assert(i >= 0 && i < range);
40                 return i;
41         }
42         else {
43                 return 0;
44         }
45 }
46
47 namespace Freestyle {
48
49 real PseudoNoise::_values[];
50
51 PseudoNoise::PseudoNoise() {}
52
53 void PseudoNoise::init(long seed)
54 {
55         RandGen::srand48(seed);
56         for (unsigned int i = 0; i < NB_VALUE_NOISE; i++)
57                 _values[i] = -1.0 + 2.0 * RandGen::drand48();
58 }
59
60 real PseudoNoise::linearNoise(real x)
61 {
62         real tmp;
63         int i = modf_to_index(x, NB_VALUE_NOISE);
64         real x1 = _values[i], x2 = _values[(i + 1) % NB_VALUE_NOISE];
65         real t = modf(x * NB_VALUE_NOISE, &tmp);
66         return x1 * (1 - t) + x2 * t;
67 }
68
69 static real LanczosWindowed(real t)
70 {
71         if (fabs(t) > 2)
72                 return 0;
73         if (fabs(t) < M_EPSILON)
74                 return 1.0;
75         return sin(M_PI * t) / (M_PI * t) * sin(M_PI * t / 2.0) / (M_PI * t / 2.0);
76 }
77
78 real PseudoNoise::smoothNoise(real x)
79 {
80         real tmp;
81         int i = modf_to_index(x, NB_VALUE_NOISE);
82         int h = i - 1;
83         if (UNLIKELY(h < 0)) {
84                 h = NB_VALUE_NOISE + h;
85         }
86
87         real x1 = _values[i], x2 = _values[(i + 1) % NB_VALUE_NOISE];
88         real x0 = _values[h], x3 = _values[(i + 2) % NB_VALUE_NOISE];
89
90         real t = modf(x * NB_VALUE_NOISE, &tmp);
91         real y0 = LanczosWindowed(-1 -t);
92         real y1 = LanczosWindowed(-t);
93         real y2 = LanczosWindowed(1 - t);
94         real y3 = LanczosWindowed(2 - t);
95 #if 0
96         cerr << "x0=" << x0 << "  x1=" << x1 << "  x2=" << x2 << "  x3=" << x3 << endl;
97         cerr << "y0=" << y0 << "  y1=" << y1 << "  y2=" << y2 << "  y3=" << y3 << "  :" << endl;
98 #endif
99         return (x0 * y0 + x1 * y1 + x2 * y2 + x3 * y3) / (y0 + y1 + y2 + y3);
100 }
101
102 real PseudoNoise::turbulenceSmooth(real x, unsigned nbOctave)
103 {
104         real y = 0;
105         real k = 1.0;
106         for (unsigned int i = 0; i < nbOctave; i++) {
107                 y = y + k * smoothNoise(x * k);
108                 k = k / 2.0;
109         }
110         return y;
111 }
112
113 real PseudoNoise::turbulenceLinear(real x, unsigned nbOctave)
114 {
115         real y = 0;
116         real k = 1.0;
117         for (unsigned int i = 0; i < nbOctave; i++) {
118                 y = y + k * linearNoise(x * k);
119                 k = k / 2.0;
120         }
121         return y;
122 }
123
124 } /* namespace Freestyle */