1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
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 Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/misc/noise_value.h"
20 #include "nel/misc/fast_floor.h"
31 // 3 level: best quality/speed ratio.
32 #define NL3D_NOISE_LEVEL 3
33 #define NL3D_NOISE_GRID_SIZE_SHIFT 5
34 #define NL3D_NOISE_GRID_SIZE (1<<NL3D_NOISE_GRID_SIZE_SHIFT)
35 static const float NL3D_OO255
= 1.0f
/ 255;
37 // ***************************************************************************
38 // ***************************************************************************
39 // ***************************************************************************
41 // ***************************************************************************
42 /// A static 3D array of random value + other infos for noise
47 // generate a random grid, with same seed.
54 for(uint z
=0; z
<NL3D_NOISE_GRID_SIZE
; z
++)
56 for(uint y
=0; y
<NL3D_NOISE_GRID_SIZE
; y
++)
58 for(uint x
=0; x
<NL3D_NOISE_GRID_SIZE
; x
++)
60 uint id
= x
+ (y
<<NL3D_NOISE_GRID_SIZE_SHIFT
) + (z
<<(NL3D_NOISE_GRID_SIZE_SHIFT
*2));
61 // take higher bits of rand gives better result.
63 _Texture3d
[id
]= v
&255;
70 // sum of sizes must be 1, and each level must be /2.
72 for(i
=0; i
<NL3D_NOISE_LEVEL
; i
++)
74 _Sizes
[i
]= 1.0f
/ (1<<i
);
78 for(i
=0; i
<NL3D_NOISE_LEVEL
; i
++)
84 for(i
=0; i
<NL3D_NOISE_LEVEL
; i
++)
86 _LevelPhase
[i
].x
= frand(NL3D_NOISE_GRID_SIZE
);
87 _LevelPhase
[i
].y
= frand(NL3D_NOISE_GRID_SIZE
);
88 _LevelPhase
[i
].z
= frand(NL3D_NOISE_GRID_SIZE
);
91 _LevelPhase
[0]= CVector::Null
;
94 // x/y/z are use to lookup directly in the grid 3D.
95 static inline float evalNearest(const CVector
&pos
)
97 // compute integer part.
98 sint x
= OptFastFloor(pos
.x
);
99 sint y
= OptFastFloor(pos
.y
);
100 sint z
= OptFastFloor(pos
.z
);
102 uint ux
= x
& (NL3D_NOISE_GRID_SIZE
-1);
103 uint uy
= y
& (NL3D_NOISE_GRID_SIZE
-1);
104 uint uz
= z
& (NL3D_NOISE_GRID_SIZE
-1);
107 float turb
= lookup(ux
,uy
,uz
);
109 return turb
*NL3D_OO255
;
112 // x/y/z are use to lookup directly in the grid 3D.
113 static inline float evalBiLinear(const CVector
&pos
)
115 // compute integer part.
116 sint x
= OptFastFloor(pos
.x
);
117 sint y
= OptFastFloor(pos
.y
);
118 sint z
= OptFastFloor(pos
.z
);
120 uint ux
= x
& (NL3D_NOISE_GRID_SIZE
-1);
121 uint uy
= y
& (NL3D_NOISE_GRID_SIZE
-1);
122 uint uz
= z
& (NL3D_NOISE_GRID_SIZE
-1);
123 uint ux2
= (x
+1)& (NL3D_NOISE_GRID_SIZE
-1);
124 uint uy2
= (y
+1)& (NL3D_NOISE_GRID_SIZE
-1);
125 uint uz2
= (z
+1)& (NL3D_NOISE_GRID_SIZE
-1);
130 easeInEaseOut(dx2
, pos
.x
-x
);
131 easeInEaseOut(dy2
, pos
.y
-y
);
132 easeInEaseOut(dz2
, pos
.z
-z
);
136 // TriLinear in texture3D.
139 turb
+= lookup(ux
,uy
,uz
)* dxdy
*dz
;
140 turb
+= lookup(ux
,uy
,uz2
)* dxdy
*dz2
;
142 turb
+= lookup(ux
,uy2
,uz
)* dxdy2
*dz
;
143 turb
+= lookup(ux
,uy2
,uz2
)* dxdy2
*dz2
;
145 turb
+= lookup(ux2
,uy
,uz
)* dx2dy
*dz
;
146 turb
+= lookup(ux2
,uy
,uz2
)* dx2dy
*dz2
;
147 float dx2dy2
= dx2
*dy2
;
148 turb
+= lookup(ux2
,uy2
,uz
)* dx2dy2
*dz
;
149 turb
+= lookup(ux2
,uy2
,uz2
)* dx2dy2
*dz2
;
152 return turb
*NL3D_OO255
;
156 // get size according to level
157 static inline float getLevelSize(uint level
)
159 return _Sizes
[level
];
162 // get an additional level phase.
163 static inline const CVector
&getLevelPhase(uint level
)
165 return _LevelPhase
[level
];
172 static uint8 _Texture3d
[NL3D_NOISE_GRID_SIZE
*NL3D_NOISE_GRID_SIZE
*NL3D_NOISE_GRID_SIZE
];
173 static float _Sizes
[NL3D_NOISE_LEVEL
];
174 static CVector _LevelPhase
[NL3D_NOISE_LEVEL
];
177 // lookup with no mod.
178 static inline float lookup(uint ux
, uint uy
, uint uz
)
180 uint id
= ux
+ (uy
<<NL3D_NOISE_GRID_SIZE_SHIFT
) + (uz
<<(NL3D_NOISE_GRID_SIZE_SHIFT
*2));
181 return _Texture3d
[id
];
185 static inline void easeInEaseOut(float &y
, float x
)
187 // cubic such that f(0)=0, f'(0)=0, f(1)=1, f'(1)=0.
196 uint8
CRandomGrid3D::_Texture3d
[NL3D_NOISE_GRID_SIZE
*NL3D_NOISE_GRID_SIZE
*NL3D_NOISE_GRID_SIZE
];
197 float CRandomGrid3D::_Sizes
[NL3D_NOISE_LEVEL
];
198 CVector
CRandomGrid3D::_LevelPhase
[NL3D_NOISE_LEVEL
];
200 // just to init the static arrays.
201 static CRandomGrid3D NL3D_RandomGrid3D
;
204 // ***************************************************************************
205 // ***************************************************************************
206 // ***************************************************************************
209 // ***************************************************************************
210 float CNoiseValue::evalRandom(const CVector
&pos
) const
212 return CRandomGrid3D::evalNearest(pos
);
216 // ***************************************************************************
217 float CNoiseValue::noise(const CVector
&pos
) const
222 #if (NL3D_NOISE_LEVEL != 3)
225 for(uint level
=0;level
<NL3D_NOISE_LEVEL
;level
++)
227 // Add the influence of the ith level.
228 turb
+= CRandomGrid3D::getLevelSize(level
) *
229 CRandomGrid3D::evalBiLinear(vd
+ CRandomGrid3D::getLevelPhase(level
) );
230 // Next level at higher frequency
234 // special case. unrolled loop.
235 // level 0 has no phase.
236 turb
= CRandomGrid3D::getLevelSize(0) *
237 CRandomGrid3D::evalBiLinear(pos
);
239 turb
+= CRandomGrid3D::getLevelSize(1) *
240 CRandomGrid3D::evalBiLinear(pos
*2 + CRandomGrid3D::getLevelPhase(1) );
242 turb
+= CRandomGrid3D::getLevelSize(2) *
243 CRandomGrid3D::evalBiLinear(pos
*4 + CRandomGrid3D::getLevelPhase(2) );
251 // ***************************************************************************
252 CNoiseValue::CNoiseValue()
260 // ***************************************************************************
261 CNoiseValue::CNoiseValue(float abs
, float rand
, float freq
)
269 // ***************************************************************************
270 float CNoiseValue::eval(const CVector
&posInWorld
) const
272 // A single cube in the Grid3d correspond to Frequency==1.
273 // So enlarging size of the grid3d do not affect the frequency aspect.
274 return Abs
+ Rand
* noise(posInWorld
*Frequency
);
278 // ***************************************************************************
279 float CNoiseValue::evalOneLevelRandom(const CVector
&posInWorld
) const
281 // A single cube in the Grid3d correspond to Frequency==1.
282 // So enlarging size of the grid3d do not affect the frequency aspect.
283 return Abs
+ Rand
* evalRandom(posInWorld
*Frequency
);
287 // ***************************************************************************
288 void CNoiseValue::serial(IStream
&f
)
290 (void)f
.serialVersion(0);
297 // ***************************************************************************
298 // ***************************************************************************
299 // ***************************************************************************
302 // ***************************************************************************
303 void CNoiseColorGradient::eval(const CVector
&posInWorld
, CRGBAF
&result
) const
305 // test if not null grads.
306 uint nGrads
= (uint
)Gradients
.size();
309 // if only one color, easy
312 result
= Gradients
[0];
317 float f
= NoiseValue
.eval(posInWorld
) * (nGrads
-1);
318 clamp(f
, 0.f
, (float)(nGrads
-1));
319 // look up in table of gradients.
320 uint id
= OptFastFloor(f
);
321 clamp(id
, 0U, nGrads
-2);
325 // interpolate the gradient.
326 result
= Gradients
[id
]*(1-f
) + Gradients
[id
+1]*f
;
330 // ***************************************************************************
331 void CNoiseColorGradient::serial(IStream
&f
)
333 (void)f
.serialVersion(0);
334 f
.serial(NoiseValue
);
335 f
.serialCont(Gradients
);