aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs')
-rw-r--r--OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs484
1 files changed, 484 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs b/OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
new file mode 100644
index 0000000..aa785b0
--- /dev/null
+++ b/OpenSim/OpenSim.Terrain.BasicTerrain/TerrainEngine.cs
@@ -0,0 +1,484 @@
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', 'RAW' 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 "raw":
174 loadFromFileSLRAW(args[2]);
175 break;
176
177 case "img":
178 resultText = "Error - IMG mode is presently unsupported.";
179 return false;
180
181 default:
182 resultText = "Unknown image or data format";
183 return false;
184 }
185 break;
186
187 case "save":
188 switch (args[1].ToLower())
189 {
190 case "f32":
191 writeToFileF32(args[2]);
192 break;
193
194 case "f64":
195 writeToFileF64(args[2]);
196 break;
197
198 case "grdmap":
199 exportImage(args[2], args[3]);
200 break;
201
202 default:
203 resultText = "Unknown image or data format";
204 return false;
205 }
206 break;
207
208 default:
209 resultText = "Unknown terrain command";
210 return false;
211 }
212 return true;
213 }
214 catch (Exception e)
215 {
216 resultText = "Error running terrain command: " + e.ToString();
217 return false;
218 }
219 }
220
221 /// <summary>
222 /// Renormalises the array between min and max
223 /// </summary>
224 /// <param name="min">Minimum value of the new array</param>
225 /// <param name="max">Maximum value of the new array</param>
226 public void setRange(float min, float max)
227 {
228 heightmap.normalise((double)min, (double)max);
229 tainted++;
230 }
231
232 /// <summary>
233 /// Loads a file consisting of 256x256 doubles and imports it as an array into the map.
234 /// </summary>
235 /// <remarks>TODO: Move this to libTerrain itself</remarks>
236 /// <param name="filename">The filename of the double array to import</param>
237 public void loadFromFileF64(string filename)
238 {
239 System.IO.FileInfo file = new System.IO.FileInfo(filename);
240 System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read);
241 System.IO.BinaryReader bs = new System.IO.BinaryReader(s);
242 int x, y;
243 for (x = 0; x < w; x++)
244 {
245 for (y = 0; y < h; y++)
246 {
247 heightmap.map[x, y] = bs.ReadDouble();
248 }
249 }
250
251 bs.Close();
252 s.Close();
253
254 tainted++;
255 }
256
257 /// <summary>
258 /// Loads a file consisting of 256x256 floats and imports it as an array into the map.
259 /// </summary>
260 /// <remarks>TODO: Move this to libTerrain itself</remarks>
261 /// <param name="filename">The filename of the float array to import</param>
262 public void loadFromFileF32(string filename)
263 {
264 System.IO.FileInfo file = new System.IO.FileInfo(filename);
265 System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read);
266 System.IO.BinaryReader bs = new System.IO.BinaryReader(s);
267 int x, y;
268 for (x = 0; x < w; x++)
269 {
270 for (y = 0; y < h; y++)
271 {
272 heightmap.map[x, y] = (double)bs.ReadSingle();
273 }
274 }
275
276 bs.Close();
277 s.Close();
278
279 tainted++;
280 }
281
282 /// <summary>
283 /// Loads a file formatted in the SL .RAW Format used on the main grid
284 /// </summary>
285 /// <remarks>This file format stinks and is best avoided.</remarks>
286 /// <param name="filename">A path to the .RAW format</param>
287 public void loadFromFileSLRAW(string filename)
288 {
289 System.IO.FileInfo file = new System.IO.FileInfo(filename);
290 System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read);
291 System.IO.BinaryReader bs = new System.IO.BinaryReader(s);
292 int x, y;
293 for (x = 0; x < w; x++)
294 {
295 for (y = 0; y < h; y++)
296 {
297 heightmap.map[x, y] = (double)bs.ReadByte() * ((double)bs.ReadByte() / 127.0);
298 bs.ReadBytes(11); // Advance the stream to next bytes.
299 }
300 }
301
302 bs.Close();
303 s.Close();
304
305 tainted++;
306 }
307
308 /// <summary>
309 /// Writes the current terrain heightmap to disk, in the format of a 65536 entry double[] array.
310 /// </summary>
311 /// <param name="filename">The desired output filename</param>
312 public void writeToFileF64(string filename)
313 {
314 System.IO.FileInfo file = new System.IO.FileInfo(filename);
315 System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);
316 System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s);
317
318 int x, y;
319 for (x = 0; x < w; x++)
320 {
321 for (y = 0; y < h; y++)
322 {
323 bs.Write(heightmap.get(x, y));
324 }
325 }
326
327 bs.Close();
328 s.Close();
329 }
330
331 /// <summary>
332 /// Writes the current terrain heightmap to disk, in the format of a 65536 entry float[] array
333 /// </summary>
334 /// <param name="filename">The desired output filename</param>
335 public void writeToFileF32(string filename)
336 {
337 System.IO.FileInfo file = new System.IO.FileInfo(filename);
338 System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);
339 System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s);
340
341 int x, y;
342 for (x = 0; x < w; x++)
343 {
344 for (y = 0; y < h; y++)
345 {
346 bs.Write((float)heightmap.get(x, y));
347 }
348 }
349
350 bs.Close();
351 s.Close();
352 }
353
354 /// <summary>
355 /// Sets the random seed to be used by procedural functions which involve random numbers.
356 /// </summary>
357 /// <param name="val">The desired seed</param>
358 public void setSeed(int val)
359 {
360 heightmap.seed = val;
361 }
362
363 /// <summary>
364 /// Raises land in a sphere around the specified coordinates
365 /// </summary>
366 /// <param name="rx">Center of the sphere on the X axis</param>
367 /// <param name="ry">Center of the sphere on the Y axis</param>
368 /// <param name="size">The radius of the sphere</param>
369 /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
370 public void raise(double rx, double ry, double size, double amount)
371 {
372 lock (heightmap)
373 {
374 heightmap.raise(rx, ry, size, amount);
375 }
376
377 tainted++;
378 }
379
380 /// <summary>
381 /// Lowers the land in a sphere around the specified coordinates
382 /// </summary>
383 /// <param name="rx">The center of the sphere at the X axis</param>
384 /// <param name="ry">The center of the sphere at the Y axis</param>
385 /// <param name="size">The radius of the sphere in meters</param>
386 /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
387 public void lower(double rx, double ry, double size, double amount)
388 {
389 lock (heightmap)
390 {
391 heightmap.lower(rx, ry, size, amount);
392 }
393
394 tainted++;
395 }
396
397 /// <summary>
398 /// Generates a simple set of hills in the shape of an island
399 /// </summary>
400 public void hills()
401 {
402 lock (heightmap)
403 {
404 heightmap.hillsSpheres(200, 20, 40, true, true, false);
405 heightmap.normalise();
406 heightmap *= 60.0; // Raise to 60m
407 }
408
409 tainted++;
410 }
411
412 /// <summary>
413 /// Multiplies the heightfield by val
414 /// </summary>
415 /// <param name="meep">The heightfield</param>
416 /// <param name="val">The multiplier</param>
417 /// <returns></returns>
418 public static TerrainEngine operator *(TerrainEngine meep, Double val)
419 {
420 meep.heightmap *= val;
421 meep.tainted++;
422 return meep;
423 }
424
425 /// <summary>
426 /// Returns the height at the coordinates x,y
427 /// </summary>
428 /// <param name="x">X Coordinate</param>
429 /// <param name="y">Y Coordinate</param>
430 /// <returns></returns>
431 public float this[int x, int y]
432 {
433 get
434 {
435 return (float)heightmap.get(x, y);
436 }
437 set
438 {
439 tainted++;
440 heightmap.set(x, y, (double)value);
441 }
442 }
443
444 /// <summary>
445 /// Exports the current heightmap to a PNG file
446 /// </summary>
447 /// <param name="filename">The destination filename for the image</param>
448 /// <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>
449 public void exportImage(string filename, string gradientmap)
450 {
451 try
452 {
453 Bitmap gradientmapLd = new Bitmap(gradientmap);
454
455 int pallete = gradientmapLd.Height;
456
457 Bitmap bmp = new Bitmap(heightmap.w, heightmap.h);
458 Color[] colours = new Color[pallete];
459
460 for (int i = 0; i < pallete; i++)
461 {
462 colours[i] = gradientmapLd.GetPixel(0, i);
463 }
464
465 Channel copy = heightmap.copy();
466 for (int x = 0; x < copy.w; x++)
467 {
468 for (int y = 0; y < copy.h; y++)
469 {
470 // 512 is the largest possible height before colours clamp
471 int colorindex = (int)(Math.Max(Math.Min(1.0, copy.get(x, y) / 512.0), 0.0) * pallete);
472 bmp.SetPixel(x, y, colours[colorindex]);
473 }
474 }
475
476 bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
477 }
478 catch (Exception e)
479 {
480 Console.WriteLine("Failed generating terrain map: " + e.ToString());
481 }
482 }
483 }
484} \ No newline at end of file