diff options
author | MW | 2007-06-27 15:28:52 +0000 |
---|---|---|
committer | MW | 2007-06-27 15:28:52 +0000 |
commit | 646bbbc84b8010e0dacbeed5342cdb045f46cc49 (patch) | |
tree | 770b34d19855363c3c113ab9a0af9a56d821d887 /OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs | |
download | opensim-SC-646bbbc84b8010e0dacbeed5342cdb045f46cc49.zip opensim-SC-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.gz opensim-SC-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.bz2 opensim-SC-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.xz |
Some work on restructuring the namespaces / project names. Note this doesn't compile yet as not all the code has been changed to use the new namespaces. Am committing it now for feedback on the namespaces.
Diffstat (limited to 'OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs')
-rw-r--r-- | OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs | 786 |
1 files changed, 786 insertions, 0 deletions
diff --git a/OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs b/OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs new file mode 100644 index 0000000..4f989fa --- /dev/null +++ b/OpenSim/Region/Terrain.BasicTerrain/TerrainEngine.cs | |||
@@ -0,0 +1,786 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://www.openmetaverse.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 | */ | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | using System.Drawing; | ||
32 | using libTerrain; | ||
33 | using OpenJPEGNet; | ||
34 | |||
35 | namespace OpenSim.Terrain | ||
36 | { | ||
37 | public class TerrainCommand | ||
38 | { | ||
39 | public virtual bool run(string[] cmdargs, ref string output) | ||
40 | { | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | public string args; | ||
45 | public string help; | ||
46 | } | ||
47 | |||
48 | public class TerrainEngine | ||
49 | { | ||
50 | /// <summary> | ||
51 | /// Plugin library for scripts | ||
52 | /// </summary> | ||
53 | public FilterHost customFilters = new FilterHost(); | ||
54 | |||
55 | /// <summary> | ||
56 | /// A [normally] 256x256 heightmap | ||
57 | /// </summary> | ||
58 | public Channel heightmap; | ||
59 | |||
60 | /// <summary> | ||
61 | /// A copy of heightmap at the last save point (for reverting) | ||
62 | /// </summary> | ||
63 | public Channel revertmap; | ||
64 | |||
65 | /// <summary> | ||
66 | /// Water heightmap (needs clientside mods to work) | ||
67 | /// </summary> | ||
68 | public Channel watermap; | ||
69 | |||
70 | /// <summary> | ||
71 | /// Whether or not the terrain has been modified since it was last saved and sent to the Physics engine. | ||
72 | /// Counts the number of modifications since the last save. (0 = Untainted) | ||
73 | /// </summary> | ||
74 | public int tainted; | ||
75 | |||
76 | int w, h; | ||
77 | |||
78 | /// <summary> | ||
79 | /// Generate a new TerrainEngine instance and creates a new heightmap | ||
80 | /// </summary> | ||
81 | public TerrainEngine() | ||
82 | { | ||
83 | w = 256; | ||
84 | h = 256; | ||
85 | heightmap = new Channel(w, h); | ||
86 | |||
87 | tainted++; | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Converts the heightmap to a 65536 value 1D floating point array | ||
92 | /// </summary> | ||
93 | /// <returns>A float[65536] array containing the heightmap</returns> | ||
94 | public float[] getHeights1D() | ||
95 | { | ||
96 | float[] heights = new float[w * h]; | ||
97 | int i; | ||
98 | |||
99 | for (i = 0; i < w * h; i++) | ||
100 | { | ||
101 | heights[i] = (float)heightmap.map[i / w, i % w]; | ||
102 | } | ||
103 | |||
104 | return heights; | ||
105 | } | ||
106 | |||
107 | /// <summary> | ||
108 | /// Converts the heightmap to a 256x256 value 2D floating point array. | ||
109 | /// </summary> | ||
110 | /// <returns>An array of 256,256 values containing the heightmap</returns> | ||
111 | public float[,] getHeights2D() | ||
112 | { | ||
113 | float[,] heights = new float[w, h]; | ||
114 | int x, y; | ||
115 | for (x = 0; x < w; x++) | ||
116 | { | ||
117 | for (y = 0; y < h; y++) | ||
118 | { | ||
119 | heights[x, y] = (float)heightmap.map[x, y]; | ||
120 | } | ||
121 | } | ||
122 | return heights; | ||
123 | } | ||
124 | |||
125 | /// <summary> | ||
126 | /// Imports a 1D floating point array into the 2D heightmap array | ||
127 | /// </summary> | ||
128 | /// <param name="heights">The array to import (must have 65536 members)</param> | ||
129 | public void setHeights1D(float[] heights) | ||
130 | { | ||
131 | int i; | ||
132 | for (i = 0; i < w * h; i++) | ||
133 | { | ||
134 | heightmap.map[i / w, i % w] = heights[i]; | ||
135 | } | ||
136 | |||
137 | tainted++; | ||
138 | } | ||
139 | |||
140 | /// <summary> | ||
141 | /// Loads a 2D array of values into the heightmap | ||
142 | /// </summary> | ||
143 | /// <param name="heights">An array of 256,256 float values</param> | ||
144 | public void setHeights2D(float[,] heights) | ||
145 | { | ||
146 | int x, y; | ||
147 | for (x = 0; x < w; x++) | ||
148 | { | ||
149 | for (y = 0; y < h; y++) | ||
150 | { | ||
151 | heightmap.set(x, y, (double)heights[x, y]); | ||
152 | } | ||
153 | } | ||
154 | tainted++; | ||
155 | } | ||
156 | |||
157 | /// <summary> | ||
158 | /// Swaps the two heightmap buffers (the 'revert map' and the heightmap) | ||
159 | /// </summary> | ||
160 | public void swapRevertMaps() | ||
161 | { | ||
162 | Channel backup = heightmap.copy(); | ||
163 | heightmap = revertmap; | ||
164 | revertmap = backup; | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Saves the current heightmap into the revertmap | ||
169 | /// </summary> | ||
170 | public void saveRevertMap() | ||
171 | { | ||
172 | revertmap = heightmap.copy(); | ||
173 | } | ||
174 | |||
175 | /// <summary> | ||
176 | /// Processes a terrain-specific command | ||
177 | /// </summary> | ||
178 | /// <param name="args">Commandline arguments (space seperated)</param> | ||
179 | /// <param name="resultText">Reference that returns error or help text if returning false</param> | ||
180 | /// <returns>If the operation was successful (if not, the error is placed into resultText)</returns> | ||
181 | public bool RunTerrainCmd(string[] args, ref string resultText) | ||
182 | { | ||
183 | string command = args[0]; | ||
184 | |||
185 | try | ||
186 | { | ||
187 | |||
188 | switch (command) | ||
189 | { | ||
190 | case "help": | ||
191 | resultText += "terrain regenerate - rebuilds the sims terrain using a default algorithm\n"; | ||
192 | resultText += "terrain voronoi <points> <blocksize> - generates a worley fractal with X points per block"; | ||
193 | resultText += "terrain seed <seed> - sets the random seed value to <seed>\n"; | ||
194 | resultText += "terrain load <type> <filename> - loads a terrain from disk, type can be 'F32', 'F64', 'RAW' or 'IMG'\n"; | ||
195 | resultText += "terrain save <type> <filename> - saves a terrain to disk, type can be 'F32', 'F64' or 'PNG'\n"; | ||
196 | resultText += "terrain save grdmap <filename> <gradient map> - creates a PNG snapshot of the region using a named gradient map\n"; | ||
197 | resultText += "terrain rescale <min> <max> - rescales a terrain to be between <min> and <max> meters high\n"; | ||
198 | resultText += "terrain erode aerobic <windspeed> <pickupmin> <dropmin> <carry> <rounds> <lowest>\n"; | ||
199 | resultText += "terrain erode thermal <talus> <rounds> <carry>\n"; | ||
200 | resultText += "terrain multiply <val> - multiplies a terrain by <val>\n"; | ||
201 | resultText += "terrain revert - reverts the terrain to the stored original\n"; | ||
202 | resultText += "terrain bake - saves the current terrain into the revert map\n"; | ||
203 | resultText += "terrain csfilter <filename.cs> - loads a new filter from the specified .cs file\n"; | ||
204 | resultText += "terrain jsfilter <filename.js> - loads a new filter from the specified .js file\n"; | ||
205 | foreach (KeyValuePair<string, ITerrainFilter> filter in customFilters.filters) | ||
206 | { | ||
207 | resultText += filter.Value.Help(); | ||
208 | } | ||
209 | |||
210 | return false; | ||
211 | |||
212 | case "revert": | ||
213 | swapRevertMaps(); | ||
214 | saveRevertMap(); | ||
215 | break; | ||
216 | |||
217 | case "bake": | ||
218 | saveRevertMap(); | ||
219 | break; | ||
220 | |||
221 | case "seed": | ||
222 | setSeed(Convert.ToInt32(args[1])); | ||
223 | break; | ||
224 | |||
225 | case "erode": | ||
226 | return consoleErosion(args, ref resultText); | ||
227 | |||
228 | case "voronoi": | ||
229 | double[] c = new double[2]; | ||
230 | c[0] = -1; | ||
231 | c[1] = 1; | ||
232 | heightmap.voronoiDiagram(Convert.ToInt32(args[1]), Convert.ToInt32(args[2]), c); | ||
233 | break; | ||
234 | |||
235 | case "hills": | ||
236 | return consoleHills(args, ref resultText); | ||
237 | |||
238 | case "regenerate": | ||
239 | hills(); | ||
240 | break; | ||
241 | |||
242 | case "rescale": | ||
243 | setRange(Convert.ToSingle(args[1]), Convert.ToSingle(args[2])); | ||
244 | break; | ||
245 | |||
246 | case "multiply": | ||
247 | heightmap *= Convert.ToDouble(args[1]); | ||
248 | break; | ||
249 | |||
250 | case "load": | ||
251 | switch (args[1].ToLower()) | ||
252 | { | ||
253 | case "f32": | ||
254 | loadFromFileF32(args[2]); | ||
255 | break; | ||
256 | |||
257 | case "f64": | ||
258 | loadFromFileF64(args[2]); | ||
259 | break; | ||
260 | |||
261 | case "raw": | ||
262 | loadFromFileSLRAW(args[2]); | ||
263 | break; | ||
264 | |||
265 | case "img": | ||
266 | heightmap.loadImage(args[2]); | ||
267 | return false; | ||
268 | |||
269 | default: | ||
270 | resultText = "Unknown image or data format"; | ||
271 | return false; | ||
272 | } | ||
273 | break; | ||
274 | |||
275 | case "save": | ||
276 | switch (args[1].ToLower()) | ||
277 | { | ||
278 | case "f32": | ||
279 | writeToFileF32(args[2]); | ||
280 | break; | ||
281 | |||
282 | case "f64": | ||
283 | writeToFileF64(args[2]); | ||
284 | break; | ||
285 | |||
286 | case "grdmap": | ||
287 | exportImage(args[2], args[3]); | ||
288 | break; | ||
289 | |||
290 | case "png": | ||
291 | heightmap.saveImage(args[2]); | ||
292 | break; | ||
293 | |||
294 | default: | ||
295 | resultText = "Unknown image or data format"; | ||
296 | return false; | ||
297 | } | ||
298 | break; | ||
299 | |||
300 | case "csfilter": | ||
301 | customFilters.LoadFilterCSharp(args[1]); | ||
302 | break; | ||
303 | case "jsfilter": | ||
304 | customFilters.LoadFilterJScript(args[1]); | ||
305 | break; | ||
306 | |||
307 | default: | ||
308 | // Run any custom registered filters | ||
309 | if (customFilters.filters.ContainsKey(command)) | ||
310 | { | ||
311 | customFilters.filters[command].Filter(heightmap, args); | ||
312 | break; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | resultText = "Unknown terrain command"; | ||
317 | return false; | ||
318 | } | ||
319 | } | ||
320 | return true; | ||
321 | } | ||
322 | catch (Exception e) | ||
323 | { | ||
324 | resultText = "Error running terrain command: " + e.ToString(); | ||
325 | return false; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | private bool consoleErosion(string[] args, ref string resultText) | ||
330 | { | ||
331 | switch (args[1].ToLower()) | ||
332 | { | ||
333 | case "aerobic": | ||
334 | // WindSpeed, PickupMinimum,DropMinimum,Carry,Rounds,Lowest | ||
335 | 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])); | ||
336 | break; | ||
337 | case "thermal": | ||
338 | heightmap.thermalWeathering(Convert.ToDouble(args[2]), Convert.ToInt32(args[3]), Convert.ToDouble(args[4])); | ||
339 | break; | ||
340 | default: | ||
341 | resultText = "Unknown erosion type"; | ||
342 | return false; | ||
343 | } | ||
344 | return true; | ||
345 | } | ||
346 | |||
347 | private bool consoleHills(string[] args, ref string resultText) | ||
348 | { | ||
349 | int count; | ||
350 | double sizeMin; | ||
351 | double sizeRange; | ||
352 | bool island; | ||
353 | bool additive; | ||
354 | bool noisy; | ||
355 | |||
356 | if (args.GetLength(0) > 2) | ||
357 | { | ||
358 | count = Convert.ToInt32(args[2]); | ||
359 | sizeMin = Convert.ToDouble(args[3]); | ||
360 | sizeRange = Convert.ToDouble(args[4]); | ||
361 | island = Convert.ToBoolean(args[5]); | ||
362 | additive = Convert.ToBoolean(args[6]); | ||
363 | noisy = Convert.ToBoolean(args[7]); | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | count = 200; | ||
368 | sizeMin = 20; | ||
369 | sizeRange = 40; | ||
370 | island = true; | ||
371 | additive = true; | ||
372 | noisy = false; | ||
373 | } | ||
374 | |||
375 | switch (args[1].ToLower()) | ||
376 | { | ||
377 | case "blocks": | ||
378 | heightmap.hillsBlocks(count, sizeMin, sizeRange, island, additive, noisy); | ||
379 | break; | ||
380 | case "cones": | ||
381 | heightmap.hillsCones(count, sizeMin, sizeRange, island, additive, noisy); | ||
382 | break; | ||
383 | case "spheres": | ||
384 | heightmap.hillsSpheres(count, sizeMin, sizeRange, island, additive, noisy); | ||
385 | break; | ||
386 | case "squared": | ||
387 | heightmap.hillsSquared(count, sizeMin, sizeRange, island, additive, noisy); | ||
388 | break; | ||
389 | default: | ||
390 | resultText = "Unknown hills type"; | ||
391 | return false; | ||
392 | } | ||
393 | return true; | ||
394 | } | ||
395 | |||
396 | /// <summary> | ||
397 | /// Renormalises the array between min and max | ||
398 | /// </summary> | ||
399 | /// <param name="min">Minimum value of the new array</param> | ||
400 | /// <param name="max">Maximum value of the new array</param> | ||
401 | public void setRange(float min, float max) | ||
402 | { | ||
403 | heightmap.normalise((double)min, (double)max); | ||
404 | tainted++; | ||
405 | } | ||
406 | |||
407 | /// <summary> | ||
408 | /// Loads a file consisting of 256x256 doubles and imports it as an array into the map. | ||
409 | /// </summary> | ||
410 | /// <remarks>TODO: Move this to libTerrain itself</remarks> | ||
411 | /// <param name="filename">The filename of the double array to import</param> | ||
412 | public void loadFromFileF64(string filename) | ||
413 | { | ||
414 | System.IO.FileInfo file = new System.IO.FileInfo(filename); | ||
415 | System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read); | ||
416 | System.IO.BinaryReader bs = new System.IO.BinaryReader(s); | ||
417 | int x, y; | ||
418 | for (x = 0; x < w; x++) | ||
419 | { | ||
420 | for (y = 0; y < h; y++) | ||
421 | { | ||
422 | heightmap.map[x, y] = bs.ReadDouble(); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | bs.Close(); | ||
427 | s.Close(); | ||
428 | |||
429 | tainted++; | ||
430 | } | ||
431 | |||
432 | /// <summary> | ||
433 | /// Loads a file consisting of 256x256 floats and imports it as an array into the map. | ||
434 | /// </summary> | ||
435 | /// <remarks>TODO: Move this to libTerrain itself</remarks> | ||
436 | /// <param name="filename">The filename of the float array to import</param> | ||
437 | public void loadFromFileF32(string filename) | ||
438 | { | ||
439 | System.IO.FileInfo file = new System.IO.FileInfo(filename); | ||
440 | System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read); | ||
441 | System.IO.BinaryReader bs = new System.IO.BinaryReader(s); | ||
442 | int x, y; | ||
443 | for (x = 0; x < w; x++) | ||
444 | { | ||
445 | for (y = 0; y < h; y++) | ||
446 | { | ||
447 | heightmap.map[x, y] = (double)bs.ReadSingle(); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | bs.Close(); | ||
452 | s.Close(); | ||
453 | |||
454 | tainted++; | ||
455 | } | ||
456 | |||
457 | /// <summary> | ||
458 | /// Loads a file formatted in the SL .RAW Format used on the main grid | ||
459 | /// </summary> | ||
460 | /// <remarks>This file format stinks and is best avoided.</remarks> | ||
461 | /// <param name="filename">A path to the .RAW format</param> | ||
462 | public void loadFromFileSLRAW(string filename) | ||
463 | { | ||
464 | System.IO.FileInfo file = new System.IO.FileInfo(filename); | ||
465 | System.IO.FileStream s = file.Open(System.IO.FileMode.Open, System.IO.FileAccess.Read); | ||
466 | System.IO.BinaryReader bs = new System.IO.BinaryReader(s); | ||
467 | int x, y; | ||
468 | for (x = 0; x < w; x++) | ||
469 | { | ||
470 | for (y = 0; y < h; y++) | ||
471 | { | ||
472 | heightmap.map[x, y] = (double)bs.ReadByte() * ((double)bs.ReadByte() / 127.0); | ||
473 | bs.ReadBytes(11); // Advance the stream to next bytes. | ||
474 | } | ||
475 | } | ||
476 | |||
477 | bs.Close(); | ||
478 | s.Close(); | ||
479 | |||
480 | tainted++; | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Writes the current terrain heightmap to disk, in the format of a 65536 entry double[] array. | ||
485 | /// </summary> | ||
486 | /// <param name="filename">The desired output filename</param> | ||
487 | public void writeToFileF64(string filename) | ||
488 | { | ||
489 | System.IO.FileInfo file = new System.IO.FileInfo(filename); | ||
490 | System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write); | ||
491 | System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s); | ||
492 | |||
493 | int x, y; | ||
494 | for (x = 0; x < w; x++) | ||
495 | { | ||
496 | for (y = 0; y < h; y++) | ||
497 | { | ||
498 | bs.Write(heightmap.get(x, y)); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | bs.Close(); | ||
503 | s.Close(); | ||
504 | } | ||
505 | |||
506 | /// <summary> | ||
507 | /// Writes the current terrain heightmap to disk, in the format of a 65536 entry float[] array | ||
508 | /// </summary> | ||
509 | /// <param name="filename">The desired output filename</param> | ||
510 | public void writeToFileF32(string filename) | ||
511 | { | ||
512 | System.IO.FileInfo file = new System.IO.FileInfo(filename); | ||
513 | System.IO.FileStream s = file.Open(System.IO.FileMode.CreateNew, System.IO.FileAccess.Write); | ||
514 | System.IO.BinaryWriter bs = new System.IO.BinaryWriter(s); | ||
515 | |||
516 | int x, y; | ||
517 | for (x = 0; x < w; x++) | ||
518 | { | ||
519 | for (y = 0; y < h; y++) | ||
520 | { | ||
521 | bs.Write((float)heightmap.get(x, y)); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | bs.Close(); | ||
526 | s.Close(); | ||
527 | } | ||
528 | |||
529 | /// <summary> | ||
530 | /// Sets the random seed to be used by procedural functions which involve random numbers. | ||
531 | /// </summary> | ||
532 | /// <param name="val">The desired seed</param> | ||
533 | public void setSeed(int val) | ||
534 | { | ||
535 | heightmap.seed = val; | ||
536 | } | ||
537 | |||
538 | /// <summary> | ||
539 | /// Raises land in a sphere around the specified coordinates | ||
540 | /// </summary> | ||
541 | /// <param name="rx">Center of the sphere on the X axis</param> | ||
542 | /// <param name="ry">Center of the sphere on the Y axis</param> | ||
543 | /// <param name="size">The radius of the sphere</param> | ||
544 | /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param> | ||
545 | public void raise(double rx, double ry, double size, double amount) | ||
546 | { | ||
547 | lock (heightmap) | ||
548 | { | ||
549 | heightmap.raise(rx, ry, size, amount); | ||
550 | } | ||
551 | |||
552 | tainted++; | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// Lowers the land in a sphere around the specified coordinates | ||
557 | /// </summary> | ||
558 | /// <param name="rx">The center of the sphere at the X axis</param> | ||
559 | /// <param name="ry">The center of the sphere at the Y axis</param> | ||
560 | /// <param name="size">The radius of the sphere in meters</param> | ||
561 | /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param> | ||
562 | public void lower(double rx, double ry, double size, double amount) | ||
563 | { | ||
564 | lock (heightmap) | ||
565 | { | ||
566 | heightmap.lower(rx, ry, size, amount); | ||
567 | } | ||
568 | |||
569 | tainted++; | ||
570 | } | ||
571 | |||
572 | /// <summary> | ||
573 | /// Flattens the land under the brush of specified coordinates (spherical mask) | ||
574 | /// </summary> | ||
575 | /// <param name="rx">Center of sphere</param> | ||
576 | /// <param name="ry">Center of sphere</param> | ||
577 | /// <param name="size">Radius of the sphere</param> | ||
578 | /// <param name="amount">Thickness of the mask (0..2 recommended)</param> | ||
579 | public void flatten(double rx, double ry, double size, double amount) | ||
580 | { | ||
581 | lock (heightmap) | ||
582 | { | ||
583 | heightmap.flatten(rx, ry, size, amount); | ||
584 | } | ||
585 | |||
586 | tainted++; | ||
587 | } | ||
588 | |||
589 | /// <summary> | ||
590 | /// Creates noise within the specified bounds | ||
591 | /// </summary> | ||
592 | /// <param name="rx">Center of the bounding sphere</param> | ||
593 | /// <param name="ry">Center of the bounding sphere</param> | ||
594 | /// <param name="size">The radius of the sphere</param> | ||
595 | /// <param name="amount">Strength of the mask (0..2) recommended</param> | ||
596 | public void noise(double rx, double ry, double size, double amount) | ||
597 | { | ||
598 | lock (heightmap) | ||
599 | { | ||
600 | Channel smoothed = new Channel(); | ||
601 | smoothed.noise(); | ||
602 | |||
603 | Channel mask = new Channel(); | ||
604 | mask.raise(rx, ry, size, amount); | ||
605 | |||
606 | heightmap.blend(smoothed, mask); | ||
607 | } | ||
608 | |||
609 | tainted++; | ||
610 | } | ||
611 | |||
612 | /// <summary> | ||
613 | /// Reverts land within the specified bounds | ||
614 | /// </summary> | ||
615 | /// <param name="rx">Center of the bounding sphere</param> | ||
616 | /// <param name="ry">Center of the bounding sphere</param> | ||
617 | /// <param name="size">The radius of the sphere</param> | ||
618 | /// <param name="amount">Strength of the mask (0..2) recommended</param> | ||
619 | public void revert(double rx, double ry, double size, double amount) | ||
620 | { | ||
621 | lock (heightmap) | ||
622 | { | ||
623 | Channel mask = new Channel(); | ||
624 | mask.raise(rx, ry, size, amount); | ||
625 | |||
626 | heightmap.blend(revertmap, mask); | ||
627 | } | ||
628 | |||
629 | tainted++; | ||
630 | } | ||
631 | |||
632 | /// <summary> | ||
633 | /// Smooths land under the brush of specified coordinates (spherical mask) | ||
634 | /// </summary> | ||
635 | /// <param name="rx">Center of the sphere</param> | ||
636 | /// <param name="ry">Center of the sphere</param> | ||
637 | /// <param name="size">Radius of the sphere</param> | ||
638 | /// <param name="amount">Thickness of the mask (0..2 recommended)</param> | ||
639 | public void smooth(double rx, double ry, double size, double amount) | ||
640 | { | ||
641 | lock (heightmap) | ||
642 | { | ||
643 | Channel smoothed = heightmap.copy(); | ||
644 | smoothed.smooth(amount); | ||
645 | |||
646 | Channel mask = new Channel(); | ||
647 | mask.raise(rx,ry,size,amount); | ||
648 | |||
649 | heightmap.blend(smoothed, mask); | ||
650 | } | ||
651 | |||
652 | tainted++; | ||
653 | } | ||
654 | |||
655 | /// <summary> | ||
656 | /// Generates a simple set of hills in the shape of an island | ||
657 | /// </summary> | ||
658 | public void hills() | ||
659 | { | ||
660 | lock (heightmap) | ||
661 | { | ||
662 | heightmap.hillsSpheres(200, 20, 40, true, true, false); | ||
663 | heightmap.normalise(); | ||
664 | heightmap *= 60.0; // Raise to 60m | ||
665 | } | ||
666 | |||
667 | tainted++; | ||
668 | } | ||
669 | |||
670 | /// <summary> | ||
671 | /// Multiplies the heightfield by val | ||
672 | /// </summary> | ||
673 | /// <param name="meep">The heightfield</param> | ||
674 | /// <param name="val">The multiplier</param> | ||
675 | /// <returns></returns> | ||
676 | public static TerrainEngine operator *(TerrainEngine meep, Double val) | ||
677 | { | ||
678 | meep.heightmap *= val; | ||
679 | meep.tainted++; | ||
680 | return meep; | ||
681 | } | ||
682 | |||
683 | /// <summary> | ||
684 | /// Returns the height at the coordinates x,y | ||
685 | /// </summary> | ||
686 | /// <param name="x">X Coordinate</param> | ||
687 | /// <param name="y">Y Coordinate</param> | ||
688 | /// <returns></returns> | ||
689 | public float this[int x, int y] | ||
690 | { | ||
691 | get | ||
692 | { | ||
693 | return (float)heightmap.get(x, y); | ||
694 | } | ||
695 | set | ||
696 | { | ||
697 | tainted++; | ||
698 | heightmap.set(x, y, (double)value); | ||
699 | } | ||
700 | } | ||
701 | |||
702 | /// <summary> | ||
703 | /// Exports the current heightmap to a PNG file | ||
704 | /// </summary> | ||
705 | /// <param name="filename">The destination filename for the image</param> | ||
706 | /// <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> | ||
707 | public void exportImage(string filename, string gradientmap) | ||
708 | { | ||
709 | try | ||
710 | { | ||
711 | Bitmap gradientmapLd = new Bitmap(gradientmap); | ||
712 | |||
713 | int pallete = gradientmapLd.Height; | ||
714 | |||
715 | Bitmap bmp = new Bitmap(heightmap.w, heightmap.h); | ||
716 | Color[] colours = new Color[pallete]; | ||
717 | |||
718 | for (int i = 0; i < pallete; i++) | ||
719 | { | ||
720 | colours[i] = gradientmapLd.GetPixel(0, i); | ||
721 | } | ||
722 | |||
723 | Channel copy = heightmap.copy(); | ||
724 | for (int x = 0; x < copy.w; x++) | ||
725 | { | ||
726 | for (int y = 0; y < copy.h; y++) | ||
727 | { | ||
728 | // 512 is the largest possible height before colours clamp | ||
729 | int colorindex = (int)(Math.Max(Math.Min(1.0, copy.get(x, y) / 512.0), 0.0) * pallete); | ||
730 | bmp.SetPixel(x, y, colours[colorindex]); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png); | ||
735 | } | ||
736 | catch (Exception e) | ||
737 | { | ||
738 | Console.WriteLine("Failed generating terrain map: " + e.ToString()); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | /// <summary> | ||
743 | /// Exports the current heightmap in Jpeg2000 format to a byte[] | ||
744 | /// </summary> | ||
745 | /// <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> | ||
746 | public byte[] exportJpegImage(string gradientmap) | ||
747 | { | ||
748 | byte[] imageData = null; | ||
749 | try | ||
750 | { | ||
751 | Bitmap gradientmapLd = new Bitmap(gradientmap); | ||
752 | |||
753 | int pallete = gradientmapLd.Height; | ||
754 | |||
755 | Bitmap bmp = new Bitmap(heightmap.w, heightmap.h); | ||
756 | Color[] colours = new Color[pallete]; | ||
757 | |||
758 | for (int i = 0; i < pallete; i++) | ||
759 | { | ||
760 | colours[i] = gradientmapLd.GetPixel(0, i); | ||
761 | } | ||
762 | |||
763 | Channel copy = heightmap.copy(); | ||
764 | for (int x = 0; x < copy.w; x++) | ||
765 | { | ||
766 | for (int y = 0; y < copy.h; y++) | ||
767 | { | ||
768 | // 512 is the largest possible height before colours clamp | ||
769 | int colorindex = (int)(Math.Max(Math.Min(1.0, copy.get(copy.h - y, x) / 512.0), 0.0) * pallete); | ||
770 | bmp.SetPixel(x, y, colours[colorindex]); | ||
771 | } | ||
772 | } | ||
773 | |||
774 | //bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png); | ||
775 | imageData = OpenJPEGNet.OpenJPEG.EncodeFromImage(bmp, "map"); | ||
776 | |||
777 | } | ||
778 | catch (Exception e) | ||
779 | { | ||
780 | Console.WriteLine("Failed generating terrain map: " + e.ToString()); | ||
781 | } | ||
782 | |||
783 | return imageData; | ||
784 | } | ||
785 | } | ||
786 | } \ No newline at end of file | ||