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 `here |
9
|
|
|
<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
|
|
|
.. deprecated:: 3.2 |
36
|
|
|
This class has been replaced by :any:`tcod.noise.Noise`. |
37
|
|
|
|
38
|
|
|
Args: |
39
|
|
|
algorithm (Text): The primary noise algorithm to be used. |
40
|
|
|
|
41
|
|
|
Can be one of 'PERLIN', 'SIMPLEX', 'WAVELET' |
42
|
|
|
|
43
|
|
|
- 'PERLIN' - |
44
|
|
|
A popular noise generator. |
45
|
|
|
- 'SIMPLEX' - |
46
|
|
|
In theory this is a slightly faster generator with |
47
|
|
|
less noticeable directional artifacts. |
48
|
|
|
- 'WAVELET' - |
49
|
|
|
A noise generator designed to reduce aliasing and |
50
|
|
|
not lose detail when summed into a fractal |
51
|
|
|
(as with the 'FBM' and 'TURBULENCE' modes.) |
52
|
|
|
This works faster at higher dimensions. |
53
|
|
|
|
54
|
|
|
mode (Text): A secondary parameter to determine how noise is generated. |
55
|
|
|
|
56
|
|
|
Can be one of 'FLAT', 'FBM', 'TURBULENCE' |
57
|
|
|
|
58
|
|
|
- 'FLAT' - |
59
|
|
|
Generates the simplest form of noise. |
60
|
|
|
This mode does not use the hurst, lacunarity, |
61
|
|
|
and octaves parameters. |
62
|
|
|
- 'FBM' - |
63
|
|
|
Generates fractal brownian motion. |
64
|
|
|
- 'TURBULENCE' - |
65
|
|
|
Generates detailed noise with smoother and more |
66
|
|
|
natural transitions. |
67
|
|
|
|
68
|
|
|
hurst (float): The hurst exponent. |
69
|
|
|
|
70
|
|
|
This describes the raggedness of the resultant noise, |
71
|
|
|
with a higher value leading to a smoother noise. |
72
|
|
|
It should be in the 0.0-1.0 range. |
73
|
|
|
|
74
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
75
|
|
|
|
76
|
|
|
lacunarity (float): A multiplier that determines how quickly the |
77
|
|
|
frequency increases for each successive octave. |
78
|
|
|
|
79
|
|
|
The frequency of each successive octave is equal to |
80
|
|
|
the product of the previous octave's frequency and |
81
|
|
|
the lacunarity value. |
82
|
|
|
|
83
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
84
|
|
|
|
85
|
|
|
octaves (float): Controls the amount of detail in the noise. |
86
|
|
|
|
87
|
|
|
This is only used in 'FBM' and 'TURBULENCE' modes. |
88
|
|
|
|
89
|
|
|
seed (Hashable): You can use any hashable object to be a seed for the |
90
|
|
|
noise generator. |
91
|
|
|
|
92
|
|
|
If None is used then a random seed will be generated. |
93
|
|
|
""" |
94
|
|
|
|
95
|
|
|
def __init__(self, algorithm='PERLIN', mode='FLAT', |
96
|
|
|
hurst=0.5, lacunarity=2.0, octaves=4.0, seed=None, dimensions=4): |
|
|
|
|
97
|
|
|
if algorithm.upper() not in _NOISE_TYPES: |
98
|
|
|
raise _tdl.TDLError('No such noise algorithm as %s' % algorithm) |
99
|
|
|
self._algorithm = algorithm.upper() |
100
|
|
|
|
101
|
|
|
if mode.upper() not in _NOISE_MODES: |
102
|
|
|
raise _tdl.TDLError('No such mode as %s' % mode) |
103
|
|
|
self._mode = mode.upper() |
104
|
|
|
|
105
|
|
|
if seed is None: |
106
|
|
|
seed = _random.getrandbits(32) |
107
|
|
|
try: |
108
|
|
|
seed = int(seed) |
109
|
|
|
except TypeError: |
110
|
|
|
seed = hash(seed) |
111
|
|
|
self._seed = seed |
112
|
|
|
# convert values into ctypes to speed up later functions |
113
|
|
|
self._dimensions = min(_MAX_DIMENSIONS, int(dimensions)) |
114
|
|
|
if self._algorithm == 'WAVELET': |
115
|
|
|
self._dimensions = min(self._dimensions, 3) # Wavelet only goes up to 3 |
|
|
|
|
116
|
|
|
self._random = _lib.TCOD_random_new_from_seed( |
117
|
|
|
_MERSENNE_TWISTER, |
118
|
|
|
_ffi.cast('uint32_t', self._seed), |
119
|
|
|
) |
120
|
|
|
self._hurst = hurst |
121
|
|
|
self._lacunarity = lacunarity |
122
|
|
|
self._noise = _lib.TCOD_noise_new(self._dimensions, self._hurst, |
123
|
|
|
self._lacunarity, self._random) |
124
|
|
|
_lib.TCOD_noise_set_type(self._noise, _NOISE_TYPES[self._algorithm]) |
125
|
|
|
self._noiseFunc = _NOISE_MODES[self._mode] |
|
|
|
|
126
|
|
|
self._octaves = octaves |
127
|
|
|
self._useOctaves = (self._mode != 'FLAT') |
|
|
|
|
128
|
|
|
self._arrayType = 'float[%i]' % self._dimensions |
|
|
|
|
129
|
|
|
#self._cFloatArray = _ctypes.c_float * self._dimensions |
130
|
|
|
#self._array = self._cFloatArray() |
131
|
|
|
|
132
|
|
|
def __copy__(self): |
133
|
|
|
# using the pickle method is a convenient way to clone this object |
134
|
|
|
return self.__class__(*self.__getstate__()) |
135
|
|
|
|
136
|
|
|
def __getstate__(self): |
137
|
|
|
return (self._algorithm, self._mode, |
138
|
|
|
self._hurst, self._lacunarity, self._octaves, |
139
|
|
|
self._seed, self._dimensions) |
140
|
|
|
|
141
|
|
|
def __setstate__(self, state): |
142
|
|
|
self.__init__(*state) |
143
|
|
|
|
144
|
|
|
def get_point(self, *position): |
145
|
|
|
"""Return the noise value of a specific position. |
146
|
|
|
|
147
|
|
|
Example usage: value = noise.getPoint(x, y, z) |
148
|
|
|
|
149
|
|
|
Args: |
150
|
|
|
position (Tuple[float, ...]): The point to sample at. |
151
|
|
|
|
152
|
|
|
Returns: |
153
|
|
|
float: The noise value at position. |
154
|
|
|
|
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 check looks for lines that are too long. You can specify the maximum line length.