opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 OpenSimulator 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  
28 using System;
29 using OpenSim.Region.Framework.Interfaces;
30 using OpenSim.Region.Framework.Scenes;
31  
32 namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33 {
34 /// <summary>
35 /// Hydraulic Erosion Brush
36 /// </summary>
37 public class ErodeSphere : ITerrainPaintableEffect
38 {
39 private const double rainHeight = 0.2;
40 private const int rounds = 10;
41 private const NeighbourSystem type = NeighbourSystem.Moore;
42 private const double waterSaturation = 0.30;
43  
44 #region Supporting Functions
45  
46 private static int[] Neighbours(NeighbourSystem neighbourType, int index)
47 {
48 int[] coord = new int[2];
49  
50 index++;
51  
52 switch (neighbourType)
53 {
54 case NeighbourSystem.Moore:
55 switch (index)
56 {
57 case 1:
58 coord[0] = -1;
59 coord[1] = -1;
60 break;
61  
62 case 2:
63 coord[0] = -0;
64 coord[1] = -1;
65 break;
66  
67 case 3:
68 coord[0] = +1;
69 coord[1] = -1;
70 break;
71  
72 case 4:
73 coord[0] = -1;
74 coord[1] = -0;
75 break;
76  
77 case 5:
78 coord[0] = -0;
79 coord[1] = -0;
80 break;
81  
82 case 6:
83 coord[0] = +1;
84 coord[1] = -0;
85 break;
86  
87 case 7:
88 coord[0] = -1;
89 coord[1] = +1;
90 break;
91  
92 case 8:
93 coord[0] = -0;
94 coord[1] = +1;
95 break;
96  
97 case 9:
98 coord[0] = +1;
99 coord[1] = +1;
100 break;
101  
102 default:
103 break;
104 }
105 break;
106  
107 case NeighbourSystem.VonNeumann:
108 switch (index)
109 {
110 case 1:
111 coord[0] = 0;
112 coord[1] = -1;
113 break;
114  
115 case 2:
116 coord[0] = -1;
117 coord[1] = 0;
118 break;
119  
120 case 3:
121 coord[0] = +1;
122 coord[1] = 0;
123 break;
124  
125 case 4:
126 coord[0] = 0;
127 coord[1] = +1;
128 break;
129  
130 case 5:
131 coord[0] = -0;
132 coord[1] = -0;
133 break;
134  
135 default:
136 break;
137 }
138 break;
139 }
140  
141 return coord;
142 }
143  
144 private enum NeighbourSystem
145 {
146 Moore,
147 VonNeumann
148 } ;
149  
150 #endregion
151  
152 #region ITerrainPaintableEffect Members
153  
154 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
155 {
156 strength = TerrainUtil.MetersToSphericalStrength(strength);
157  
158 int x, y;
159 // Using one 'rain' round for this, so skipping a useless loop
160 // Will need to adapt back in for the Flood brush
161  
162 ITerrainChannel water = new TerrainChannel(map.Width, map.Height);
163 ITerrainChannel sediment = new TerrainChannel(map.Width, map.Height);
164  
165 // Fill with rain
166 for (x = 0; x < water.Width; x++)
167 for (y = 0; y < water.Height; y++)
168 water[x, y] = Math.Max(0.0, TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration);
169  
170 for (int i = 0; i < rounds; i++)
171 {
172 // Erode underlying terrain
173 for (x = 0; x < water.Width; x++)
174 {
175 for (y = 0; y < water.Height; y++)
176 {
177 if (mask[x,y])
178 {
179 const double solConst = (1.0 / rounds);
180 double sedDelta = water[x, y] * solConst;
181 map[x, y] -= sedDelta;
182 sediment[x, y] += sedDelta;
183 }
184 }
185 }
186  
187 // Move water
188 for (x = 0; x < water.Width; x++)
189 {
190 for (y = 0; y < water.Height; y++)
191 {
192 if (water[x, y] <= 0)
193 continue;
194  
195 // Step 1. Calculate average of neighbours
196  
197 int neighbours = 0;
198 double altitudeTotal = 0.0;
199 double altitudeMe = map[x, y] + water[x, y];
200  
201 const int NEIGHBOUR_ME = 4;
202 const int NEIGHBOUR_MAX = 9;
203  
204 for (int j = 0; j < NEIGHBOUR_MAX; j++)
205 {
206 if (j != NEIGHBOUR_ME)
207 {
208 int[] coords = Neighbours(type, j);
209  
210 coords[0] += x;
211 coords[1] += y;
212  
213 if (coords[0] > map.Width - 1)
214 continue;
215 if (coords[1] > map.Height - 1)
216 continue;
217 if (coords[0] < 0)
218 continue;
219 if (coords[1] < 0)
220 continue;
221  
222 // Calculate total height of this neighbour
223 double altitudeNeighbour = water[coords[0], coords[1]] + map[coords[0], coords[1]];
224  
225 // If it's greater than me...
226 if (altitudeNeighbour - altitudeMe < 0)
227 {
228 // Add it to our calculations
229 neighbours++;
230 altitudeTotal += altitudeNeighbour;
231 }
232 }
233 }
234  
235 if (neighbours == 0)
236 continue;
237  
238 double altitudeAvg = altitudeTotal / neighbours;
239  
240 // Step 2. Allocate water to neighbours.
241 for (int j = 0; j < NEIGHBOUR_MAX; j++)
242 {
243 if (j != NEIGHBOUR_ME)
244 {
245 int[] coords = Neighbours(type, j);
246  
247 coords[0] += x;
248 coords[1] += y;
249  
250 if (coords[0] > map.Width - 1)
251 continue;
252 if (coords[1] > map.Height - 1)
253 continue;
254 if (coords[0] < 0)
255 continue;
256 if (coords[1] < 0)
257 continue;
258  
259 // Skip if we dont have water to begin with.
260 if (water[x, y] < 0)
261 continue;
262  
263 // Calculate our delta average
264 double altitudeDelta = altitudeMe - altitudeAvg;
265  
266 if (altitudeDelta < 0)
267 continue;
268  
269 // Calculate how much water we can move
270 double waterMin = Math.Min(water[x, y], altitudeDelta);
271 double waterDelta = waterMin * ((water[coords[0], coords[1]] + map[coords[0], coords[1]])
272 / altitudeTotal);
273  
274 double sedimentDelta = sediment[x, y] * (waterDelta / water[x, y]);
275  
276 if (sedimentDelta > 0)
277 {
278 sediment[x, y] -= sedimentDelta;
279 sediment[coords[0], coords[1]] += sedimentDelta;
280 }
281 }
282 }
283 }
284 }
285  
286 // Evaporate
287  
288 for (x = 0; x < water.Width; x++)
289 {
290 for (y = 0; y < water.Height; y++)
291 {
292 water[x, y] *= 1.0 - (rainHeight / rounds);
293  
294 double waterCapacity = waterSaturation * water[x, y];
295  
296 double sedimentDeposit = sediment[x, y] - waterCapacity;
297 if (sedimentDeposit > 0)
298 {
299 if (mask[x,y])
300 {
301 sediment[x, y] -= sedimentDeposit;
302 map[x, y] += sedimentDeposit;
303 }
304 }
305 }
306 }
307 }
308  
309 // Deposit any remainder (should be minimal)
310 for (x = 0; x < water.Width; x++)
311 for (y = 0; y < water.Height; y++)
312 if (mask[x,y] && sediment[x, y] > 0)
313 map[x, y] += sediment[x, y];
314 }
315  
316 #endregion
317 }
318 }