|
1
|
|
|
""" |
|
2
|
|
|
This module provides advanced noise generation. |
|
3
|
|
|
|
|
4
|
|
|
Noise is sometimes used for over-world generation, height-maps, and |
|
5
|
|
|
cloud/mist/smoke effects among other things. |
|
6
|
|
|
|
|
7
|
|
|
You can see examples of the available noise algorithms in the libtcod |
|
8
|
|
|
documentation |
|
9
|
|
|
U{here<http://doryen.eptalys.net/data/libtcod/doc/1.5.1/html2/noise.html>}. |
|
10
|
|
|
""" |
|
11
|
|
|
|
|
12
|
|
|
|
|
13
|
|
|
import random as _random |
|
14
|
|
|
|
|
15
|
|
|
from tcod import ffi as _ffi |
|
|
|
|
|
|
16
|
|
|
from tcod import lib as _lib |
|
|
|
|
|
|
17
|
|
|
|
|
18
|
|
|
import tdl as _tdl |
|
19
|
|
|
from . import style as _style |
|
20
|
|
|
|
|
21
|
|
|
_MERSENNE_TWISTER = 1 |
|
22
|
|
|
_CARRY_WITH_MULTIPLY = 2 |
|
23
|
|
|
|
|
24
|
|
|
_MAX_DIMENSIONS = 4 |
|
25
|
|
|
_MAX_OCTAVES = 128 |
|
26
|
|
|
|
|
27
|
|
|
_NOISE_TYPES = {'PERLIN': 1, 'SIMPLEX': 2, 'WAVELET': 4} |
|
28
|
|
|
_NOISE_MODES = {'FLAT': _lib.TCOD_noise_get, |
|
29
|
|
|
'FBM': _lib.TCOD_noise_get_fbm, |
|
30
|
|
|
'TURBULENCE': _lib.TCOD_noise_get_turbulence} |
|
31
|
|
|
|
|
32
|
|
|
class Noise(object): |
|
33
|
|
|
"""An advanced noise generator. |
|
34
|
|
|
""" |
|
35
|
|
|
|
|
36
|
|
|
def __init__(self, algorithm='PERLIN', mode='FLAT', |
|
37
|
|
|
hurst=0.5, lacunarity=2.0, octaves=4.0, seed=None, dimensions=4): |
|
|
|
|
|
|
38
|
|
|
"""Create a new noise generator specifying a noise algorithm and how |
|
39
|
|
|
it's used. |
|
40
|
|
|
|
|
41
|
|
|
@type algorithm: string |
|
42
|
|
|
@param algorithm: The primary noise algorithm to be used. |
|
43
|
|
|
|
|
44
|
|
|
Can be one of 'PERLIN', 'SIMPLEX', 'WAVELET' |
|
45
|
|
|
- 'PERLIN' - |
|
46
|
|
|
A popular noise generator. |
|
47
|
|
|
|
|
48
|
|
|
- 'SIMPLEX' - |
|
49
|
|
|
In theory this is a slightly faster generator with |
|
50
|
|
|
less noticeable directional artifacts. |
|
51
|
|
|
|
|
52
|
|
|
- 'WAVELET' |
|
53
|
|
|
A noise generator designed to reduce aliasing and |
|
54
|
|
|
not lose detail when summed into a fractal |
|
55
|
|
|
(as with the 'FBM' and 'TURBULENCE' modes.) |
|
56
|
|
|
|
|
57
|
|
|
This works faster at higher dimensions. |
|
58
|
|
|
|
|
59
|
|
|
@type mode: string |
|
60
|
|
|
@param mode: A secondary parameter to determine how noise is generated. |
|
61
|
|
|
|
|
62
|
|
|
Can be one of 'FLAT', 'FBM', 'TURBULENCE' |
|
63
|
|
|
- 'FLAT' - |
|
64
|
|
|
Generates the simplest form of noise. |
|
65
|
|
|
This mode does not use the hurst, lacunarity, |
|
66
|
|
|
and octaves parameters. |
|
67
|
|
|
|
|
68
|
|
|
- 'FBM' - |
|
69
|
|
|
Generates fractal brownian motion. |
|
70
|
|
|
|
|
71
|
|
|
- 'TURBULENCE' - |
|
72
|
|
|
Generates detailed noise with smoother and more |
|
73
|
|
|
natural transitions. |
|
74
|
|
|
|
|
75
|
|
|
@type hurst: float |
|
76
|
|
|
@param hurst: The hurst exponent describes the raggedness of the |
|
77
|
|
|
resultant noise, with a higher value leading to a |
|
78
|
|
|
smoother noise. |
|
79
|
|
|
It should be in the 0.0-1.0 range. |
|
80
|
|
|
|
|
81
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
|
82
|
|
|
|
|
83
|
|
|
@type lacunarity: float |
|
84
|
|
|
@param lacunarity: A multiplier that determines how quickly the |
|
85
|
|
|
frequency increases for each successive octave. |
|
86
|
|
|
|
|
87
|
|
|
The frequency of each successive octave is equal to |
|
88
|
|
|
the product of the previous octave's frequency and |
|
89
|
|
|
the lacunarity value. |
|
90
|
|
|
|
|
91
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
|
92
|
|
|
|
|
93
|
|
|
@type octaves: float |
|
94
|
|
|
@param octaves: Controls the amount of detail in the noise. |
|
95
|
|
|
|
|
96
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
|
97
|
|
|
|
|
98
|
|
|
@type seed: object |
|
99
|
|
|
@param seed: You can use any hashable object to be a seed for the |
|
100
|
|
|
noise generator. |
|
101
|
|
|
|
|
102
|
|
|
If None is used then a random seed will be generated. |
|
103
|
|
|
""" |
|
104
|
|
|
if algorithm.upper() not in _NOISE_TYPES: |
|
105
|
|
|
raise _tdl.TDLError('No such noise algorithm as %s' % algorithm) |
|
106
|
|
|
self._algorithm = algorithm.upper() |
|
107
|
|
|
|
|
108
|
|
|
if mode.upper() not in _NOISE_MODES: |
|
109
|
|
|
raise _tdl.TDLError('No such mode as %s' % mode) |
|
110
|
|
|
self._mode = mode.upper() |
|
111
|
|
|
|
|
112
|
|
|
if seed is None: |
|
113
|
|
|
seed = _random.getrandbits(32) |
|
114
|
|
|
else: |
|
115
|
|
|
seed = hash(seed) |
|
116
|
|
|
self._seed = seed |
|
117
|
|
|
# convert values into ctypes to speed up later functions |
|
118
|
|
|
self._dimensions = min(_MAX_DIMENSIONS, int(dimensions)) |
|
119
|
|
|
if self._algorithm == 'WAVELET': |
|
120
|
|
|
self._dimensions = min(self._dimensions, 3) # Wavelet only goes up to 3 |
|
|
|
|
|
|
121
|
|
|
self._random = _lib.TCOD_random_new_from_seed(_MERSENNE_TWISTER, self._seed) |
|
|
|
|
|
|
122
|
|
|
self._hurst = hurst |
|
123
|
|
|
self._lacunarity = lacunarity |
|
124
|
|
|
self._noise = _lib.TCOD_noise_new(self._dimensions, self._hurst, |
|
125
|
|
|
self._lacunarity, self._random) |
|
126
|
|
|
_lib.TCOD_noise_set_type(self._noise, _NOISE_TYPES[self._algorithm]) |
|
127
|
|
|
self._noiseFunc = _NOISE_MODES[self._mode] |
|
|
|
|
|
|
128
|
|
|
self._octaves = octaves |
|
129
|
|
|
self._useOctaves = (self._mode != 'FLAT') |
|
|
|
|
|
|
130
|
|
|
self._arrayType = 'float[%i]' % self._dimensions |
|
|
|
|
|
|
131
|
|
|
#self._cFloatArray = _ctypes.c_float * self._dimensions |
|
132
|
|
|
#self._array = self._cFloatArray() |
|
133
|
|
|
|
|
134
|
|
|
def __copy__(self): |
|
135
|
|
|
# using the pickle method is a convenient way to clone this object |
|
136
|
|
|
return self.__class__(*self.__getstate__()) |
|
137
|
|
|
|
|
138
|
|
|
def __getstate__(self): |
|
139
|
|
|
return (self._algorithm, self._mode, |
|
140
|
|
|
self._hurst, self._lacunarity, self._octaves, |
|
141
|
|
|
self._seed, self._dimensions) |
|
142
|
|
|
|
|
143
|
|
|
def __setstate__(self, state): |
|
144
|
|
|
self.__init__(*state) |
|
145
|
|
|
|
|
146
|
|
|
def get_point(self, *position): |
|
147
|
|
|
"""Return the noise value of a specific position. |
|
148
|
|
|
|
|
149
|
|
|
Example usage: value = noise.getPoint(x, y, z) |
|
150
|
|
|
@type position: floats |
|
151
|
|
|
@param position: |
|
152
|
|
|
|
|
153
|
|
|
@rtype: float |
|
154
|
|
|
@return: Returns the noise value at position. |
|
155
|
|
|
This will be a floating point in the 0.0-1.0 range. |
|
156
|
|
|
""" |
|
157
|
|
|
#array = self._array |
|
158
|
|
|
#for d, pos in enumerate(position): |
|
159
|
|
|
# array[d] = pos |
|
160
|
|
|
#array = self._cFloatArray(*position) |
|
161
|
|
|
array = _ffi.new(self._arrayType, position) |
|
162
|
|
|
if self._useOctaves: |
|
163
|
|
|
return (self._noiseFunc(self._noise, array, self._octaves) + 1) * 0.5 |
|
|
|
|
|
|
164
|
|
|
return (self._noiseFunc(self._noise, array) + 1) * 0.5 |
|
165
|
|
|
|
|
166
|
|
|
|
|
167
|
|
|
__all__ = [_var for _var in locals().keys() if _var[0] != '_'] |
|
168
|
|
|
|
|
169
|
|
|
Noise.getPoint = _style.backport(Noise.get_point) |
|
170
|
|
|
|
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.pyfiles in your module folders. Make sure that you place one file in each sub-folder.