aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs')
-rw-r--r--OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs453
1 files changed, 453 insertions, 0 deletions
diff --git a/OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs b/OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
new file mode 100644
index 0000000..a0f37f9
--- /dev/null
+++ b/OpenSim-Source/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
@@ -0,0 +1,453 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Drawing;
5using libTerrain;
6
7namespace OpenSim.Terrain
8{
9 public class TerrainEngine
10 {
11 /// <summary>
12 /// A [normally] 256x256 heightmap
13 /// </summary>
14 public Channel heightmap;
15
16 /// <summary>
17 /// Whether or not the terrain has been modified since it was last saved and sent to the Physics engine.
18 /// Counts the number of modifications since the last save. (0 = Untainted)
19 /// </summary>
20 public int tainted;
21
22 int w, h;
23
24 /// <summary>
25 /// Generate a new TerrainEngine instance and creates a new heightmap
26 /// </summary>
27 public TerrainEngine()
28 {
29 w = 256;
30 h = 256;
31 heightmap = new Channel(w, h);
32
33 tainted++;
34 }
35
36 /// <summary>
37 /// Converts the heightmap to a 65536 value 1D floating point array
38 /// </summary>
39 /// <returns>A float[65536] array containing the heightmap</returns>
40 public float[] getHeights1D()
41 {
42 float[] heights = new float[w * h];
43 int i;
44
45 for (i = 0; i < w * h; i++)
46 {
47 heights[i] = (float)heightmap.map[i / w, i % w];
48 }
49
50 return heights;
51 }
52
53 /// <summary>
54 /// Converts the heightmap to a 256x256 value 2D floating point array.
55 /// </summary>
56 /// <returns>An array of 256,256 values containing the heightmap</returns>
57 public float[,] getHeights2D()
58 {
59 float[,] heights = new float[w, h];
60 int x, y;
61 for (x = 0; x < w; x++)
62 {
63 for (y = 0; y < h; y++)
64 {
65 heights[x, y] = (float)heightmap.map[x, y];
66 }
67 }
68 return heights;
69 }
70
71 /// <summary>
72 /// Imports a 1D floating point array into the 2D heightmap array
73 /// </summary>
74 /// <param name="heights">The array to import (must have 65536 members)</param>
75 public void setHeights1D(float[] heights)
76 {
77 int i;
78 for (i = 0; i < w * h; i++)
79 {
80 heightmap.map[i / w, i % w] = heights[i];
81 }
82
83 tainted++;
84 }
85
86 /// <summary>
87 /// Loads a 2D array of values into the heightmap
88 /// </summary>
89 /// <param name="heights">An array of 256,256 float values</param>
90 public void setHeights2D(float[,] heights)
91 {
92 int x, y;
93 for (x = 0; x < w; x++)
94 {
95 for (y = 0; y < h; y++)
96 {
97 heightmap.set(x,y,(double)heights[x,y]);
98 }
99 }
100 tainted++;
101 }
102
103 /// <summary>
104 /// Processes a terrain-specific command
105 /// </summary>
106 /// <param name="args">Commandline arguments (space seperated)</param>
107 /// <param name="resultText">Reference that returns error or help text if returning false</param>
108 /// <returns>If the operation was successful (if not, the error is placed into resultText)</returns>
109 public bool RunTerrainCmd(string[] args, ref string resultText)
110 {
111 string command = args[0];
112
113 try
114 {
115
116 switch (command)
117 {
118 case "help":
119 resultText += "terrain regenerate - rebuilds the sims terrain using a default algorithm\n";
120 resultText += "terrain seed <seed> - sets the random seed value to <seed>\n";
121 resultText += "terrain load <type> <filename> - loads a terrain from disk, type can be 'F32', 'F64' or 'IMG'\n";
122 resultText += "terrain save <type> <filename> - saves a terrain to disk, type can be 'F32' or 'F64'\n";
123 resultText += "terrain save grdmap <filename> <gradient map> - creates a PNG snapshot of the region using a named gradient map\n";
124 resultText += "terrain rescale <min> <max> - rescales a terrain to be between <min> and <max> meters high\n";
125 resultText += "terrain erode aerobic <windspeed> <pickupmin> <dropmin> <carry> <rounds> <lowest>\n";
126 resultText += "terrain erode thermal <talus> <rounds> <carry>\n";
127 resultText += "terrain multiply <val> - multiplies a terrain by <val>\n";
128 return false;
129
130 case "seed":
131 setSeed(Convert.ToInt32(args[1]));
132 break;
133
134 case "erode":
135 switch (args[1].ToLower())
136 {
137 case "aerobic":
138 // WindSpeed, PickupMinimum,DropMinimum,Carry,Rounds,Lowest
139 heightmap.AerobicErosion(Convert.ToDouble(args[2]), Convert.ToDouble(args[3]), Convert.ToDouble(args[4]), Convert.ToDouble(args[5]), Convert.ToInt32(args[6]), Convert.ToBoolean(args[7]));
140 break;
141 case "thermal":
142 heightmap.thermalWeathering(Convert.ToDouble(args[2]), Convert.ToInt32(args[3]), Convert.ToDouble(args[4]));
143 break;
144 default:
145 resultText = "Unknown erosion type";
146 return false;
147 }
148 break;
149
150 case "regenerate":
151 hills();
152 break;
153
154 case "rescale":
155 setRange(Convert.ToSingle(args[1]), Convert.ToSingle(args[2]));
156 break;
157
158 case "multiply":
159 heightmap *= Convert.ToDouble(args[1]);
160 break;
161
162 case "load":
163 switch (args[1].ToLower())
164 {
165 case "f32":
166 loadFromFileF32(args[2]);
167 break;
168
169 case "f64":
170 loadFromFileF64(args[2]);
171 break;
172
173 case "img":
174 resultText = "Error - IMG mode is presently unsupported.";
175 return false;
176
177 default:
178 resultText = "Unknown image or data format";
179 return false;
180 }
181 break;
182
183 case "save":
184 switch (args[1].ToLower())
185 {
186 case "f32":
187 writeToFileF32(args[2]);
188 break;
189
190 case "f64":
191 writeToFileF64(args[2]);
192 break;
193
194 case "grdmap":
195 exportImage(args[2], args[3]);
196 break;
197
198 default:
199 resultText = "Unknown image or data format";
200 return false;
201 }
202 break;
203
204 default:
205 resultText = "Unknown terrain command";
206 return false;
207 }
208 return true;
209 }
210 catch (Exception e)
211 {
212 resultText = "Error running terrain command: " + e.ToString();
213 return false;
214 }
215 }
216
217 /// <summary>
218 /// Renormalises the array between min and max
219 /// </summary>
220 /// <param name="min">Minimum value of the new array</param>
221 /// <param name="max">Maximum value of the new array</param>
222 public void setRange(float min, float max)
223 {
224 heightmap.normalise((double)min, (double)max);
225 tainted++;
226 }
227
228 /// <summary>
229 /// Loads a file consisting of 256x256 doubles and imports it as an array into the map.
230 /// </summary>
231 /// <remarks>TODO: Move this to libTerrain itself</remarks>
232 /// <param name="filename">The filename of the double array to import</param>
233 public void loadFromFileF64(string filename)
234 {
235 System.IO.FileInfo file = new System.IO.FileInfo(filename);
236 System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read);
237 System.IO.BinaryReader bs = new System.IO.BinaryReader(s);
238 int x, y;
239 for (x = 0; x < w; x++)
240 {
241 for (y = 0; y < h; y++)
242 {
243 heightmap.map[x, y] = bs.ReadDouble();
244 }
245 }
246
247 bs.Close();
248 s.Close();
249
250 tainted++;
251 }
252
253 /// <summary>
254 /// Loads a file consisting of 256x256 floats and imports it as an array into the map.
255 /// </summary>
256 /// <remarks>TODO: Move this to libTerrain itself</remarks>
257 /// <param name="filename">The filename of the float array to import</param>
258 public void loadFromFileF32(string filename)
259 {
260 System.IO.FileInfo file = new System.IO.FileInfo(filename);
261 System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read);
262 System.IO.BinaryReader bs = new System.IO.BinaryReader(s);
263 int x, y;
264 for (x = 0; x < w; x++)
265 {
266 for (y = 0; y < h; y++)
267 {
268 heightmap.map[x, y] = (double)bs.ReadSingle();
269 }
270 }
271
272 bs.Close();
273 s.Close();
274
275 tainted++;
276 }
277
278 /// <summary>
279 /// Writes the current terrain heightmap to disk, in the format of a 65536 entry double[] array.
280 /// </summary>
281 /// <param name="filename">The desired output filename</param>
282 public void writeToFileF64(string filename)
283 {
284 System.IO.FileInfo file = new System.IO.FileInfo(filename);
285 System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);
286 System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s);
287
288 int x, y;
289 for (x = 0; x < w; x++)
290 {
291 for (y = 0; y < h; y++)
292 {
293 bs.Write(heightmap.get(x,y));
294 }
295 }
296
297 bs.Close();
298 s.Close();
299 }
300
301 /// <summary>
302 /// Writes the current terrain heightmap to disk, in the format of a 65536 entry float[] array
303 /// </summary>
304 /// <param name="filename">The desired output filename</param>
305 public void writeToFileF32(string filename)
306 {
307 System.IO.FileInfo file = new System.IO.FileInfo(filename);
308 System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);
309 System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s);
310
311 int x, y;
312 for (x = 0; x < w; x++)
313 {
314 for (y = 0; y < h; y++)
315 {
316 bs.Write((float)heightmap.get(x, y));
317 }
318 }
319
320 bs.Close();
321 s.Close();
322 }
323
324 /// <summary>
325 /// Sets the random seed to be used by procedural functions which involve random numbers.
326 /// </summary>
327 /// <param name="val">The desired seed</param>
328 public void setSeed(int val)
329 {
330 heightmap.seed = val;
331 }
332
333 /// <summary>
334 /// Raises land in a sphere around the specified coordinates
335 /// </summary>
336 /// <param name="rx">Center of the sphere on the X axis</param>
337 /// <param name="ry">Center of the sphere on the Y axis</param>
338 /// <param name="size">The radius of the sphere</param>
339 /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
340 public void raise(double rx, double ry, double size, double amount)
341 {
342 lock (heightmap)
343 {
344 heightmap.raise(rx, ry, size, amount);
345 }
346
347 tainted++;
348 }
349
350 /// <summary>
351 /// Lowers the land in a sphere around the specified coordinates
352 /// </summary>
353 /// <param name="rx">The center of the sphere at the X axis</param>
354 /// <param name="ry">The center of the sphere at the Y axis</param>
355 /// <param name="size">The radius of the sphere in meters</param>
356 /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
357 public void lower(double rx, double ry, double size, double amount)
358 {
359 lock (heightmap)
360 {
361 heightmap.lower(rx, ry, size, amount);
362 }
363
364 tainted++;
365 }
366
367 /// <summary>
368 /// Generates a simple set of hills in the shape of an island
369 /// </summary>
370 public void hills()
371 {
372 lock (heightmap)
373 {
374 heightmap.hillsSpheres(200, 20, 40, true, true, false);
375 heightmap.normalise();
376 heightmap *= 60.0; // Raise to 60m
377 }
378
379 tainted++;
380 }
381
382 /// <summary>
383 /// Multiplies the heightfield by val
384 /// </summary>
385 /// <param name="meep">The heightfield</param>
386 /// <param name="val">The multiplier</param>
387 /// <returns></returns>
388 public static TerrainEngine operator *(TerrainEngine meep, Double val) {
389 meep.heightmap *= val;
390 meep.tainted++;
391 return meep;
392 }
393
394 /// <summary>
395 /// Returns the height at the coordinates x,y
396 /// </summary>
397 /// <param name="x">X Coordinate</param>
398 /// <param name="y">Y Coordinate</param>
399 /// <returns></returns>
400 public float this[int x, int y]
401 {
402 get
403 {
404 return (float)heightmap.get(x,y);
405 }
406 set
407 {
408 tainted++;
409 heightmap.set(x,y,(double)value);
410 }
411 }
412
413 /// <summary>
414 /// Exports the current heightmap to a PNG file
415 /// </summary>
416 /// <param name="filename">The destination filename for the image</param>
417 /// <param name="gradientmap">A 1x*height* image which contains the colour gradient to export with. Must be at least 1x2 pixels, 1x256 or more is ideal.</param>
418 public void exportImage(string filename, string gradientmap)
419 {
420 try
421 {
422 Bitmap gradientmapLd = new Bitmap(gradientmap);
423
424 int pallete = gradientmapLd.Width;
425
426 Bitmap bmp = new Bitmap(heightmap.w, heightmap.h);
427 Color[] colours = new Color[pallete];
428
429 for (int i = 0; i < pallete; i++)
430 {
431 colours[i] = gradientmapLd.GetPixel(1, i);
432 }
433
434 Channel copy = heightmap.copy();
435 for (int x = 0; x < copy.w; x++)
436 {
437 for (int y = 0; y < copy.h; y++)
438 {
439 // 512 is the largest possible height before colours clamp
440 int colorindex = (int)(Math.Max(Math.Min(1.0, copy.get(x, y) / 512.0), 0.0) * pallete);
441 bmp.SetPixel(x, y, colours[colorindex]);
442 }
443 }
444
445 bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
446 }
447 catch (Exception e)
448 {
449 Console.WriteLine("Failed generating terrain map: " + e.ToString());
450 }
451 }
452 }
453}