3 * Copyright (c) 2007,2008 J.C.Wilk
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * The name of J.C.Wilk may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY J.C.WILK ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL J.C.WILK BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * @brief Handles creating noise based on perlin noise.
33 * Code tries to handle basically 2d/3d cases, without much genericness
34 * because it needs to be pretty fast. Originally sped up the code from
35 * about 20 seconds to 8 seconds per Nebula image with the manual loop
38 * @note Tried to optimize a while back with SSE and the works, but because
39 * of the nature of how it's implemented in non-linear fashion it just
40 * wound up complicating the code without actually making it faster.
59 #define TCOD_NOISE_MAX_OCTAVES 4 /**< Default octaves for noise. */
60 #define TCOD_NOISE_DEFAULT_HURST 0.5 /**< Default hurst for noise. */
61 #define TCOD_NOISE_DEFAULT_LACUNARITY 2. /**< Default lacunarity for noise. */
65 * @brief Linearly Interpolates x between a and b.
67 #define LERP(a, b, x) ( a + x * (b - a) )
71 * @brief Structure used for generating noise.
73 typedef struct perlin_data_s
{
74 int ndim
; /**< Dimension of the noise. */
75 unsigned char map
[256]; /**< Randomized map of indexes into buffer */
76 float buffer
[256][3]; /**< Random 256 x 3 buffer */
78 float H
; /**< Not sure. */
79 float lacunarity
; /**< Not sure. */
80 float exponent
[TCOD_NOISE_MAX_OCTAVES
]; /**< Not sure. */
81 } perlin_data_t
; /**< Internal perlin noise data. */
87 /* perlin data handling. */
88 static perlin_data_t
* TCOD_noise_new( int dim
, float hurst
, float lacunarity
);
89 static void TCOD_noise_delete( perlin_data_t
* noise
);
91 static void normalize3( float f
[3] );
92 static void normalize2( float f
[2] );
93 /* noise processing. */
94 static float lattice3( perlin_data_t
*pdata
, int ix
, float fx
,
95 int iy
, float fy
, int iz
, float fz
);
96 static float lattice2( perlin_data_t
*pdata
, int ix
, float fx
, int iy
, float fy
);
97 /* basic perlin noise */
98 static float TCOD_noise_get3( perlin_data_t
* pdata
, float f
[3] );
99 static float TCOD_noise_get2( perlin_data_t
* pdata
, float f
[2] );
101 static float TCOD_noise_turbulence3( perlin_data_t
* noise
, float f
[3], int octaves
);
102 static float TCOD_noise_turbulence2( perlin_data_t
* noise
, float f
[2], int octaves
);
106 * @brief Not sure what it does.
108 static __inline
float lattice3( perlin_data_t
*pdata
, int ix
, float fx
, int iy
, float fy
,
115 nIndex
= pdata
->map
[(nIndex
+ ix
) & 0xFF];
116 nIndex
= pdata
->map
[(nIndex
+ iy
) & 0xFF];
117 nIndex
= pdata
->map
[(nIndex
+ iz
) & 0xFF];
119 value
= pdata
->buffer
[nIndex
][0] * fx
;
120 value
+= pdata
->buffer
[nIndex
][1] * fy
;
121 value
+= pdata
->buffer
[nIndex
][2] * fz
;
128 * @brief Not sure what it does.
130 static float lattice2( perlin_data_t
*pdata
, int ix
, float fx
, int iy
, float fy
)
136 nIndex
= pdata
->map
[(nIndex
+ ix
) & 0xFF];
137 nIndex
= pdata
->map
[(nIndex
+ iy
) & 0xFF];
139 value
= pdata
->buffer
[nIndex
][0] * fx
;
140 value
+= pdata
->buffer
[nIndex
][1] * fy
;
146 #define SWAP(a, b, t) t = a; a = b; b = t /**< Swaps two values. */
147 #define FLOOR(a) ((int)a - (a < 0 && a != (int)a)) /**< Limits to 0. */
148 #define CUBIC(a) ( a * a * (3 - 2*a) ) /**< Does cubic filtering. */
152 * @brief Normalizes a 3d vector.
154 * @param f Vector to normalize.
156 static void normalize3( float f
[3] )
160 magnitude
= 1. / sqrtf(f
[0]*f
[0] + f
[1]*f
[1] + f
[2]*f
[2]);
168 * @brief Normalizes a 2d vector.
170 * @param f Vector to normalize.
172 static void normalize2( float f
[2] )
176 magnitude
= 1. / sqrtf(f
[0]*f
[0] + f
[1]*f
[1]);
183 * @brief Creates a new perlin noise generator.
185 * @param dim Dimension of the noise.
189 static perlin_data_t
* TCOD_noise_new( int dim
, float hurst
, float lacunarity
)
191 perlin_data_t
*pdata
;
196 /* Create the data. */
197 pdata
= calloc(sizeof(perlin_data_t
),1);
200 /* Create the buffer and map. */
202 for(i
=0; i
<256; i
++) {
203 pdata
->map
[i
] = (unsigned char)i
;
204 pdata
->buffer
[i
][0] = RNGF()-0.5;
205 pdata
->buffer
[i
][1] = RNGF()-0.5;
206 pdata
->buffer
[i
][2] = RNGF()-0.5;
207 normalize3(pdata
->buffer
[i
]);
211 for(i
=0; i
<256; i
++) {
212 pdata
->map
[i
] = (unsigned char)i
;
213 pdata
->buffer
[i
][0] = RNGF()-0.5;
214 pdata
->buffer
[i
][1] = RNGF()-0.5;
215 normalize2(pdata
->buffer
[i
]);
224 SWAP(pdata
->map
[i
], pdata
->map
[j
], tmp
);
229 pdata
->lacunarity
= lacunarity
;
230 for(i
=0; i
<TCOD_NOISE_MAX_OCTAVES
; i
++) {
231 /*exponent[i] = powf(f, -H); */
232 pdata
->exponent
[i
] = 1. / f
;
241 * @brief Gets some 3D Perlin noise from the data.
243 * Somewhat optimized for speed, probably can't get optimized much more.
245 * @param pdata Perlin data to use.
246 * @param f Position of the noise to get.
248 static float TCOD_noise_get3( perlin_data_t
* pdata
, float f
[3] )
250 int n
[3] __attribute__ ((aligned (32))); /* Indexes to pass to lattice function */
251 float r
[3] __attribute__ ((aligned (32))); /* Remainders to pass to lattice function */
252 float w
[3] __attribute__ ((aligned (32))); /* Cubic values to pass to interpolation function */
254 float v
[8] __attribute__ ((aligned (32)));
269 * This is the big ugly bit in dire need of optimization
271 v
[0] = lattice3(pdata
, n
[0], r
[0], n
[1], r
[1], n
[2], r
[2]);
272 v
[1] = lattice3(pdata
, n
[0]+1, r
[0]-1, n
[1], r
[1], n
[2], r
[2]);
273 v
[2] = lattice3(pdata
, n
[0], r
[0], n
[1]+1, r
[1]-1, n
[2], r
[2]);
274 v
[3] = lattice3(pdata
, n
[0]+1, r
[0]-1, n
[1]+1, r
[1]-1, n
[2], r
[2]);
275 v
[4] = lattice3(pdata
, n
[0], r
[0], n
[1], r
[1], n
[2]+1, r
[2]-1);
276 v
[5] = lattice3(pdata
, n
[0]+1, r
[0]-1, n
[1], r
[1], n
[2]+1, r
[2]-1);
277 v
[6] = lattice3(pdata
, n
[0], r
[0], n
[1]+1, r
[1]-1, n
[2]+1, r
[2]-1);
278 v
[7] = lattice3(pdata
, n
[0]+1, r
[0]-1, n
[1]+1, r
[1]-1, n
[2]+1, r
[2]-1);
281 LERP(v
[0], v
[1], w
[0]),
282 LERP(v
[2], v
[3], w
[0]),
286 LERP(v
[4], v
[5], w
[0]),
287 LERP(v
[6], v
[7], w
[0]),
293 return CLAMP(-0.99999f
, 0.99999f
, value
);
298 * @brief Gets some 2D Perlin noise from the data.
300 * Somewhat optimized for speed, probably can't get optimized much more.
302 * @param pdata Perlin data to use.
303 * @param f Position of the noise to get.
305 static float TCOD_noise_get2( perlin_data_t
* pdata
, float f
[2] )
307 int n
[2] __attribute__ ((aligned (32))); /* Indexes to pass to lattice function */
308 float r
[2] __attribute__ ((aligned (32))); /* Remainders to pass to lattice function */
309 float w
[2] __attribute__ ((aligned (32))); /* Cubic values to pass to interpolation function */
310 float value
__attribute__ ((aligned (32)));
311 float v
[4] __attribute__ ((aligned (32)));
325 v
[0] = lattice2(pdata
,n
[0], r
[0], n
[1], r
[1]);
326 v
[1] = lattice2(pdata
,n
[0]+1, r
[0]-1, n
[1], r
[1]);
327 v
[2] = lattice2(pdata
,n
[0], r
[0], n
[1]+1, r
[1]-1);
328 v
[3] = lattice2(pdata
,n
[0]+1, r
[0]-1, n
[1]+1, r
[1]-1);
329 value
= LERP(LERP(v
[0], v
[1], w
[0]),
330 LERP(v
[2], v
[3], w
[0]),
333 return CLAMP(-0.99999f
, 0.99999f
, value
);
338 * @brief Gets 3d Turbulence noise for a position.
340 * @param noise Perlin data to generate noise from.
341 * @param f Position of the noise.
342 * @param octaves Octaves to use.
343 * @return The noise level at the position.
345 static float TCOD_noise_turbulence3( perlin_data_t
* noise
, float f
[3], int octaves
)
348 perlin_data_t
*pdata
=(perlin_data_t
*)noise
;
349 /* Initialize locals */
357 /* Inner loop of spectral construction, where the fractal is built */
358 for(i
=0; i
<octaves
; i
++)
360 value
+= ABS(TCOD_noise_get3(noise
,tf
)) * pdata
->exponent
[i
];
361 tf
[0] *= pdata
->lacunarity
;
362 tf
[1] *= pdata
->lacunarity
;
363 tf
[2] *= pdata
->lacunarity
;
366 return CLAMP(-0.99999f
, 0.99999f
, value
);
371 * @brief Gets 2d Turbulence noise for a position.
373 * @param noise Perlin data to generate noise from.
374 * @param f Position of the noise.
375 * @param octaves Octaves to use.
376 * @return The noise level at the position.
378 static float TCOD_noise_turbulence2( perlin_data_t
* noise
, float f
[2], int octaves
)
381 perlin_data_t
*pdata
=(perlin_data_t
*)noise
;
382 /* Initialize locals */
389 /* Inner loop of spectral construction, where the fractal is built */
390 for(i
=0; i
<octaves
; i
++)
392 value
+= ABS(TCOD_noise_get2(noise
,tf
)) * pdata
->exponent
[i
];
393 tf
[0] *= pdata
->lacunarity
;
394 tf
[1] *= pdata
->lacunarity
;
397 return CLAMP(-0.99999f
, 0.99999f
, value
);
402 * @brief Frees some noise data.
404 * @param noise Noise data to free.
406 void TCOD_noise_delete( perlin_data_t
* noise
)
413 * @brief Generates radar interference.
415 * @param w Width to generate.
416 * @param h Height to generate.
417 * @param rug Rugosity of the interference.
418 * @return The map generated.
420 float* noise_genRadarInt( const int w
, const int h
, float rug
)
427 perlin_data_t
* noise
;
431 /* pretty default values */
433 hurst
= TCOD_NOISE_DEFAULT_HURST
;
434 lacunarity
= TCOD_NOISE_DEFAULT_LACUNARITY
;
436 /* create noise and data */
437 noise
= TCOD_noise_new( 2, hurst
, lacunarity
);
438 map
= malloc(sizeof(float)*w
*h
);
440 WARN("Out of memory!");
444 /* Start to create the nebula */
445 for (y
=0; y
<h
; y
++) {
447 f
[1] = rug
* (float)y
/ (float)h
;
448 for (x
=0; x
<w
; x
++) {
450 f
[0] = rug
* (float)x
/ (float)w
;
452 /* Get the 2d noise. */
453 value
= TCOD_noise_get2( noise
, f
);
455 /* Set the value to [0,1]. */
456 map
[y
*w
+ x
] = (value
+ 1.) / 2.;
461 TCOD_noise_delete( noise
);
469 * @brief Generates a 3d nebula map.
471 * @param w Width of the map.
472 * @param h Height of the map.
473 * @param n Number of slices of the map (2d planes).
474 * @param rug Rugosity of the map.
475 * @return The map generated.
477 float* noise_genNebulaMap( const int w
, const int h
, const int n
, float rug
)
484 perlin_data_t
* noise
;
491 /* pretty default values */
493 hurst
= TCOD_NOISE_DEFAULT_HURST
;
494 lacunarity
= TCOD_NOISE_DEFAULT_LACUNARITY
;
495 zoom
= rug
* ((float)h
/768.)*((float)w
/1024.);
497 /* create noise and data */
498 noise
= TCOD_noise_new( 3, hurst
, lacunarity
);
499 nebula
= malloc(sizeof(float)*w
*h
*n
);
500 if (nebula
== NULL
) {
501 WARN("Out of memory!");
505 /* Some debug information and time setting */
507 t
= malloc(sizeof(unsigned int)*n
);
508 DEBUG("Generating Nebula of size %dx%dx%d", w
, h
, n
);
510 /* Start to create the nebula */
512 for (z
=0; z
<n
; z
++) {
514 f
[2] = zoom
* (float)z
/ (float)n
;
516 for (y
=0; y
<h
; y
++) {
518 f
[1] = zoom
* (float)y
/ (float)h
;
520 for (x
=0; x
<w
; x
++) {
522 f
[0] = zoom
* (float)x
/ (float)w
;
524 value
= TCOD_noise_turbulence3( noise
, f
, octaves
);
525 if (max
< value
) max
= value
;
527 nebula
[z
*w
*h
+ y
*w
+ x
] = value
;
531 /* More time magic debug */
532 t
[z
] = SDL_GetTicks();
533 DEBUG(" Layer %d/%d generated in %d ms", z
+1, n
,
534 (z
>0) ? t
[z
] - t
[z
-1] : t
[z
] - s
);
542 nebula
[z
*w
*h
+ y
*w
+ x
] += value
;
545 TCOD_noise_delete( noise
);
548 DEBUG("Nebula Generated in %d ms", SDL_GetTicks() - s
);
554 * @brief Generates tiny nebula puffs
556 * @param w Width of the puff to generate.
557 * @param h Height of the puff to generate.
558 * @param rug Rugosity of the puff.
559 * @return The puff generated.
561 float* noise_genNebulaPuffMap( const int w
, const int h
, float rug
)
569 perlin_data_t
* noise
;
575 /* pretty default values */
577 hurst
= TCOD_NOISE_DEFAULT_HURST
;
578 lacunarity
= TCOD_NOISE_DEFAULT_LACUNARITY
;
581 /* create noise and data */
582 noise
= TCOD_noise_new( 2, hurst
, lacunarity
);
583 nebula
= malloc(sizeof(float)*w
*h
);
584 if (nebula
== NULL
) {
585 WARN("Out of memory!");
589 /* Start to create the nebula */
593 d
= (float)MIN(hw
,hh
);
594 for (y
=0; y
<h
; y
++) {
596 f
[1] = zoom
* (float)y
/ (float)h
;
597 for (x
=0; x
<w
; x
++) {
599 f
[0] = zoom
* (float)x
/ (float)w
;
601 /* Get the 2d noise. */
602 value
= TCOD_noise_turbulence2( noise
, f
, octaves
);
604 /* Make value also depend on distance from center */
605 value
*= (d
- 1. - sqrtf( (float)((x
-hw
)*(x
-hw
) + (y
-hh
)*(y
-hh
)) )) / d
;
609 /* Cap at maximum. */
614 nebula
[y
*w
+ x
] = value
;
619 TCOD_noise_delete( noise
);