summaryrefslogtreecommitdiffstats
path: root/src/Noise/OctavedNoise.h
blob: 166d2c205070f52f3c35a78316d3926e757747b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

// OctavedNoise.h

// Implements the cOctavedNoise class template representing a noise generator that layers several octaves of another noise





#pragma once





template <typename N>
class cOctavedNoise
{
public:
	cOctavedNoise(int a_Seed = 0):
		m_Seed(a_Seed)
	{
	}


	/** Sets a new seed for the generators. Relays the seed to all underlying octaves. */
	void SetSeed(int a_Seed)
	{
		m_Seed = a_Seed;
		for (auto oct: m_Octaves)
		{
			oct->SetSeed(a_Seed);
		}
	}


	/** */
	void AddOctave(NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude)
	{
		m_Octaves.emplace_back(m_Seed, a_Frequency, a_Amplitude);
	}


	/** Fills a 2D array with the values of the noise. */
	void Generate2D(
		NOISE_DATATYPE * a_Array,                        ///< Array to generate into [x + a_SizeX * y]
		int a_SizeX, int a_SizeY,                        ///< Count of the array, in each direction
		NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX,  ///< Noise-space coords of the array in the X direction
		NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY,  ///< Noise-space coords of the array in the Y direction
		NOISE_DATATYPE * a_Workspace                     ///< Workspace that this function can use and trash. Must be valid.
	) const
	{
		// Check that state is alright:
		if (m_Octaves.empty())
		{
			ASSERT(!"Perlin: No octaves to generate!");
			return;
		}

		// Allocate the workspace on the heap, if it wasn't given:
		std::unique_ptr<NOISE_DATATYPE[]> workspaceHeap;
		if (a_Workspace == nullptr)
		{
			workspaceHeap.reset(new NOISE_DATATYPE[a_SizeX * a_SizeY]);
			a_Workspace = workspaceHeap.get();
		}

		// Generate the first octave directly into array:
		const cOctave & FirstOctave = m_Octaves.front();
		int ArrayCount = a_SizeX * a_SizeY;
		FirstOctave.m_Noise.Generate2D(
			a_Workspace, a_SizeX, a_SizeY,
			a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
			a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency
		);
		NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
		for (int i = 0; i < ArrayCount; i++)
		{
			a_Array[i] = a_Workspace[i] * Amplitude;
		}

		// Add each octave:
		for (auto itr = m_Octaves.cbegin() + 1, end = m_Octaves.cend(); itr != end; ++itr)
		{
			// Generate the noise for the octave:
			itr->m_Noise.Generate2D(
				a_Workspace, a_SizeX, a_SizeY,
				a_StartX * itr->m_Frequency, a_EndX * itr->m_Frequency,
				a_StartY * itr->m_Frequency, a_EndY * itr->m_Frequency
			);
			// Add it into the output:
			NOISE_DATATYPE Amplitude = itr->m_Amplitude;
			for (int i = 0; i < ArrayCount; i++)
			{
				a_Array[i] += a_Workspace[i] * Amplitude;
			}
		}  // for itr - m_Octaves[]
	}


	/** Fills a 3D array with the values of the noise. */
	void Generate3D(
		NOISE_DATATYPE * a_Array,                        ///< Array to generate into [x + a_SizeX * y + a_SizeX * a_SizeY * z]
		int a_SizeX, int a_SizeY, int a_SizeZ,           ///< Count of the array, in each direction
		NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX,  ///< Noise-space coords of the array in the X direction
		NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY,  ///< Noise-space coords of the array in the Y direction
		NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ,  ///< Noise-space coords of the array in the Z direction
		NOISE_DATATYPE * a_Workspace = nullptr           ///< Workspace that this function can use and trash, same size as a_Array
	) const
	{
		// Check that state is alright:
		if (m_Octaves.empty())
		{
			ASSERT(!"Perlin: No octaves to generate!");
			return;
		}

		// Allocate the workspace on the heap, if it wasn't given:
		std::unique_ptr<NOISE_DATATYPE[]> workspaceHeap;
		if (a_Workspace == nullptr)
		{
			workspaceHeap.reset(new NOISE_DATATYPE[a_SizeX * a_SizeY * a_SizeZ]);
			a_Workspace = workspaceHeap.get();
		}

		// Generate the first octave directly into array:
		const cOctave & FirstOctave = m_Octaves.front();
		int ArrayCount = a_SizeX * a_SizeY * a_SizeZ;
		FirstOctave.m_Noise.Generate3D(
			a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
			a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
			a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency,
			a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency
		);
		NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
		for (int i = 0; i < ArrayCount; i++)
		{
			a_Array[i] = a_Workspace[i] * Amplitude;
		}

		// Add each octave:
		for (auto itr = m_Octaves.cbegin() + 1, end = m_Octaves.cend(); itr != end; ++itr)
		{
			// Generate the noise for the octave:
			itr->m_Noise.Generate3D(
				a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
				a_StartX * itr->m_Frequency, a_EndX * itr->m_Frequency,
				a_StartY * itr->m_Frequency, a_EndY * itr->m_Frequency,
				a_StartZ * itr->m_Frequency, a_EndZ * itr->m_Frequency
			);
			// Add it into the output:
			NOISE_DATATYPE Amplitude = itr->m_Amplitude;
			for (int i = 0; i < ArrayCount; i++)
			{
				a_Array[i] += a_Workspace[i] * Amplitude;
			}
		}  // for itr - m_Octaves[]
	}

protected:
	/** Stores information and state for one octave of the noise. */
	class cOctave
	{
	public:
		N m_Noise;
		
		/** Coord multiplier. */
		NOISE_DATATYPE m_Frequency;

		/** Value multiplier. */
		NOISE_DATATYPE m_Amplitude;

		cOctave(int a_Seed, NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude) :
			m_Noise(a_Seed),
			m_Frequency(a_Frequency),
			m_Amplitude(a_Amplitude)
		{
		}
	} ;
	typedef std::vector<cOctave> cOctaves;


	/** The seed used by the underlying generators. */
	int m_Seed;

	/** The octaves that compose this noise. */
	cOctaves m_Octaves;
};