aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs339
1 files changed, 339 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs b/OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs
new file mode 100644
index 0000000..804c642
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Terrain/PaintBrushes/ErodeSphere.cs
@@ -0,0 +1,339 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 THE CONTRIBUTORS 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.
26*
27*/
28using OpenSim.Region.Environment.Interfaces;
29using System;
30
31namespace OpenSim.Region.Environment.Modules.Terrain.PaintBrushes
32{
33 /// <summary>
34 /// Hydraulic Erosion Brush
35 /// </summary>
36 public class ErodeSphere : ITerrainPaintableEffect
37 {
38 NeighbourSystem type = NeighbourSystem.Moore; // Parameter
39
40 double rainHeight = 1.0;
41 int rounds = 10;
42 double waterSaturation = 0.01; // Can carry 1% of water in height
43
44 #region Supporting Functions
45 private enum NeighbourSystem
46 {
47 Moore,
48 VonNeumann
49 } ;
50
51 private int[] Neighbours(NeighbourSystem type, int index)
52 {
53 int[] coord = new int[2];
54
55 index++;
56
57 switch (type)
58 {
59 case NeighbourSystem.Moore:
60 switch (index)
61 {
62 case 1:
63 coord[0] = -1;
64 coord[1] = -1;
65 break;
66
67 case 2:
68 coord[0] = -0;
69 coord[1] = -1;
70 break;
71
72 case 3:
73 coord[0] = +1;
74 coord[1] = -1;
75 break;
76
77 case 4:
78 coord[0] = -1;
79 coord[1] = -0;
80 break;
81
82 case 5:
83 coord[0] = -0;
84 coord[1] = -0;
85 break;
86
87 case 6:
88 coord[0] = +1;
89 coord[1] = -0;
90 break;
91
92 case 7:
93 coord[0] = -1;
94 coord[1] = +1;
95 break;
96
97 case 8:
98 coord[0] = -0;
99 coord[1] = +1;
100 break;
101
102 case 9:
103 coord[0] = +1;
104 coord[1] = +1;
105 break;
106
107 default:
108 break;
109 }
110 break;
111
112 case NeighbourSystem.VonNeumann:
113 switch (index)
114 {
115 case 1:
116 coord[0] = 0;
117 coord[1] = -1;
118 break;
119
120 case 2:
121 coord[0] = -1;
122 coord[1] = 0;
123 break;
124
125 case 3:
126 coord[0] = +1;
127 coord[1] = 0;
128 break;
129
130 case 4:
131 coord[0] = 0;
132 coord[1] = +1;
133 break;
134
135 case 5:
136 coord[0] = -0;
137 coord[1] = -0;
138 break;
139
140 default:
141 break;
142 }
143 break;
144 }
145
146 return coord;
147 }
148
149 private double SphericalFactor(double x, double y, double rx, double ry, double size)
150 {
151 double z = size * size - ((x - rx) * (x - rx) + (y - ry) * (y - ry));
152 return z;
153 }
154
155 private double GetBilinearInterpolate(double x, double y, ITerrainChannel map)
156 {
157 int w = map.Width;
158 int h = map.Height;
159
160 if (x > w - 2.0)
161 x = w - 2.0;
162 if (y > h - 2.0)
163 y = h - 2.0;
164 if (x < 0.0)
165 x = 0.0;
166 if (y < 0.0)
167 y = 0.0;
168
169 int stepSize = 1;
170 double h00 = map[(int)x, (int)y];
171 double h10 = map[(int)x + stepSize, (int)y];
172 double h01 = map[(int)x, (int)y + stepSize];
173 double h11 = map[(int)x + stepSize, (int)y + stepSize];
174 double h1 = h00;
175 double h2 = h10;
176 double h3 = h01;
177 double h4 = h11;
178 double a00 = h1;
179 double a10 = h2 - h1;
180 double a01 = h3 - h1;
181 double a11 = h1 - h2 - h3 + h4;
182 double partialx = x - (int)x;
183 double partialz = y - (int)y;
184 double hi = a00 + (a10 * partialx) + (a01 * partialz) + (a11 * partialx * partialz);
185 return hi;
186 }
187
188 #endregion
189
190 #region ITerrainPaintableEffect Members
191
192 public void PaintEffect(ITerrainChannel map, double rx, double ry, double strength, double duration)
193 {
194 int x, y;
195 // Using one 'rain' round for this, so skipping a useless loop
196 // Will need to adapt back in for the Flood brush
197
198 ITerrainChannel water = new TerrainChannel(map.Width, map.Height);
199 ITerrainChannel sediment = new TerrainChannel(map.Width, map.Height);
200
201 // Fill with rain
202 for (x = 0; x < water.Width; x++)
203 for (y = 0; y < water.Height; y++)
204 water[x, y] = Math.Max(0.0, SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration);
205
206 for (int i = 0; i < rounds; i++)
207 {
208 // Erode underlying terrain
209 for (x = 0; x < water.Width; x++)
210 {
211 for (y = 0; y < water.Height; y++)
212 {
213 double solConst = (1.0 / rounds);
214 double sedDelta = water[x, y] * solConst;
215 map[x, y] -= sedDelta;
216 sediment[x, y] += sedDelta;
217 }
218 }
219
220 // Move water
221 for (x = 0; x < water.Width; x++)
222 {
223 for (y = 0; y < water.Height; y++)
224 {
225 if (water[x, y] <= 0)
226 continue;
227
228 // Step 1. Calculate average of neighbours
229
230 int neighbours = 0;
231 double altitudeTotal = 0.0;
232 double altitudeMe = map[x, y] + water[x, y];
233
234 int NEIGHBOUR_ME = 4;
235
236 int NEIGHBOUR_MAX = type == NeighbourSystem.Moore ? 9 : 5;
237
238 for (int j = 0; j < NEIGHBOUR_MAX; j++)
239 {
240 if (j != NEIGHBOUR_ME)
241 {
242 int[] coords = Neighbours(type, j);
243
244 coords[0] += x;
245 coords[1] += y;
246
247 if (coords[0] > map.Width - 1)
248 continue;
249 if (coords[1] > map.Height - 1)
250 continue;
251 if (coords[0] < 0)
252 continue;
253 if (coords[1] < 0)
254 continue;
255
256 // Calculate total height of this neighbour
257 double altitudeNeighbour = water[coords[0], coords[1]] + map[coords[0], coords[1]];
258
259 // If it's greater than me...
260 if (altitudeNeighbour - altitudeMe > 0)
261 {
262 // Add it to our calculations
263 neighbours++;
264 altitudeTotal += altitudeNeighbour;
265 }
266 }
267 }
268
269 if (neighbours == 0)
270 continue;
271
272 double altitudeAvg = altitudeTotal / neighbours;
273
274 // Step 2. Allocate water to neighbours.
275 for (int j = 0; j < NEIGHBOUR_MAX; j++)
276 {
277 if (j != NEIGHBOUR_ME)
278 {
279 int[] coords = Neighbours(type, j);
280
281 coords[0] += x;
282 coords[1] += y;
283
284 if (coords[0] > map.Width - 1)
285 continue;
286 if (coords[1] > map.Height - 1)
287 continue;
288 if (coords[0] < 0)
289 continue;
290 if (coords[1] < 0)
291 continue;
292
293 // Calculate our delta average
294 double altitudeDelta = altitudeMe - altitudeAvg;
295
296 // Calculate how much water we can move
297 double waterDelta = Math.Min(water[x, y], altitudeDelta)
298 * (water[coords[0], coords[1]] + map[coords[0], coords[1]])
299 / altitudeTotal;
300
301 double sedimentDelta = sediment[x, y] * (waterDelta / water[x, y]);
302
303 if (sedimentDelta > 0)
304 {
305 sediment[x, y] -= sedimentDelta;
306 sediment[coords[0], coords[1]] += sedimentDelta;
307 }
308 }
309 }
310 }
311 }
312
313 // Evaporate
314
315 for (x = 0; x < water.Width; x++)
316 {
317 for (y = 0; y < water.Height; y++)
318 {
319 water[x, y] *= 1.0 - (rainHeight / rounds);
320
321 double waterCapacity = waterSaturation * water[x, y];
322
323 double sedimentDeposit = Math.Max(0, sediment[x, y] - waterCapacity);
324 sediment[x, y] -= sedimentDeposit;
325 map[x, y] += sedimentDeposit;
326 }
327 }
328 }
329
330 // Deposit any remainder (should be minimal)
331 for (x = 0; x < water.Width; x++)
332 for (y = 0; y < water.Height; y++)
333 if (sediment[x, y] > 0)
334 map[x, y] += sediment[x, y];
335 }
336
337 #endregion
338 }
339}