1
0

TerrainEngine.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  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. */
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Drawing;
  31. using System.Drawing.Imaging;
  32. using System.Globalization;
  33. using System.IO;
  34. using System.Threading;
  35. using libTerrain;
  36. using OpenJPEGNet;
  37. using OpenSim.Framework;
  38. namespace OpenSim.Region.Terrain
  39. {
  40. public class TerrainCommand
  41. {
  42. public virtual bool run(string[] cmdargs, ref string output)
  43. {
  44. return false;
  45. }
  46. public string args;
  47. public string help;
  48. }
  49. public class TerrainEngine
  50. {
  51. public static Mutex fileIOLock = new Mutex();
  52. /// <summary>
  53. /// Plugin library for scripts
  54. /// </summary>
  55. public FilterHost customFilters = new FilterHost();
  56. /// <summary>
  57. /// A [normally] 256x256 heightmap
  58. /// </summary>
  59. public Channel heightmap;
  60. /// <summary>
  61. /// A copy of heightmap at the last save point (for reverting)
  62. /// </summary>
  63. public Channel revertmap;
  64. /// <summary>
  65. /// Water heightmap (needs clientside mods to work)
  66. /// </summary>
  67. public Channel watermap;
  68. /// <summary>
  69. /// Max amount the terrain can be raised from the revert parameters
  70. /// </summary>
  71. public double maxRaise = 500.0;
  72. /// <summary>
  73. /// Min amount the terrain can be lowered from the revert parameters
  74. /// </summary>
  75. public double minLower = 500.0;
  76. /// <summary>
  77. /// The last time the terrain was edited
  78. /// </summary>
  79. public DateTime lastEdit = DateTime.Now;
  80. private int counter = 0;
  81. /// <summary>
  82. /// Whether or not the terrain has been modified since it was last saved and sent to the Physics engine.
  83. /// Counts the number of modifications since the last save. (0 = Untainted)
  84. /// </summary>
  85. public int tainted;
  86. private int w, h;
  87. /// <summary>
  88. /// Used to determine what offset to use when loading singular heightmaps across multiple sims
  89. /// </summary>
  90. private int offsetX;
  91. private int offsetY;
  92. /// <summary>
  93. /// Generate a new TerrainEngine instance and creates a new heightmap
  94. /// </summary>
  95. public TerrainEngine(int X, int Y)
  96. {
  97. w = 256;
  98. h = 256;
  99. heightmap = new Channel(w, h);
  100. revertmap = new Channel(w, h);
  101. watermap = new Channel(w, h);
  102. watermap.Fill(20);
  103. offsetX = X;
  104. offsetY = Y;
  105. tainted++;
  106. }
  107. public bool IsTainted()
  108. {
  109. return (tainted != 0);
  110. }
  111. public bool IsUserStillEditing()
  112. {
  113. TimeSpan gap = DateTime.Now - lastEdit;
  114. if (gap.TotalSeconds <= 4.0)
  115. return true;
  116. return false;
  117. }
  118. public bool IsTainted(int x, int y)
  119. {
  120. return (heightmap.diff[x/16, y/16] != 0);
  121. }
  122. public void ResetTaint()
  123. {
  124. tainted = 0;
  125. heightmap.diff = new int[w/16,h/16];
  126. }
  127. //Testing to see if moving the TerraForming packet handling code into here works well
  128. /// <summary>
  129. /// Modifies terrain using the specified information
  130. /// </summary>
  131. /// <param name="height">The height at which the user started modifying the terrain</param>
  132. /// <param name="seconds">The number of seconds the modify button was pressed</param>
  133. /// <param name="brushsize">The size of the brush used</param>
  134. /// <param name="action">The action to be performed</param>
  135. /// <param name="north">Distance from the north border where the cursor is located</param>
  136. /// <param name="west">Distance from the west border where the cursor is located</param>
  137. public void ModifyTerrain(float height, float seconds, byte brushsize, byte action, float north, float west,
  138. float south, float east,
  139. IClientAPI remoteUser)
  140. {
  141. // Shiny.
  142. double size = (double) (1 << brushsize);
  143. //System.Console.WriteLine("SIZE:" + size.ToString() + " Seconds:" + seconds.ToString());
  144. if (seconds == 1)
  145. {
  146. seconds = 0.0315f;
  147. }
  148. /* Okay, so here's the deal
  149. * This has to handle both when a user draws on the terrain *and* when a user selects
  150. * a selection of AABB on terrain and applies whatever routine the client requests
  151. * There's something currently wrong with the brushsize --> size conversion.. however
  152. * it's workable.. just unpredictable.
  153. *
  154. * North is always higher and East is always higher
  155. * in the AABB representation
  156. *
  157. * Therefore what we're doing is looping from south to north and west to east
  158. * and applying the associated algorithm with the brush.
  159. *
  160. * This works good on the fast ones, but things like smooth take 12 seconds a single click..
  161. * for now, smooth won't be 'selectionated'
  162. *
  163. * If the user draws instead of selects, north will = south, and east will = west.
  164. * if the user selects, then the selection is inclusive
  165. * it'll always affect at least one point on the heightmap.
  166. *
  167. * that means we use the <= operator
  168. *
  169. * Again, libTerrain is yx instead of xy.. so, it's reflected in the function calls
  170. *
  171. */
  172. switch (action)
  173. {
  174. case 0:
  175. // flatten terrain
  176. for (float x = south; x <= north; x++)
  177. {
  178. for (float y = west; y <= east; y++)
  179. {
  180. FlattenTerrain(y, x, size, (double) seconds/5.0);
  181. lastEdit = DateTime.Now;
  182. //remoteUser.SendLayerData((int)(x / 16), (int)(x / 16), GetHeights1D());
  183. }
  184. }
  185. break;
  186. case 1:
  187. // raise terrain
  188. for (float x = south; x <= north; x++)
  189. {
  190. for (float y = west; y <= east; y++)
  191. {
  192. RaiseTerrain(y, x, size, (double) seconds/5.0);
  193. lastEdit = DateTime.Now;
  194. //remoteUser.SendLayerData((int)(x / 16), (int)(x / 16), GetHeights1D());
  195. }
  196. }
  197. break;
  198. case 2:
  199. //lower terrain
  200. for (float x = south; x <= north; x++)
  201. {
  202. for (float y = west; y <= east; y++)
  203. {
  204. LowerTerrain(y, x, size, (double) seconds/5.0);
  205. lastEdit = DateTime.Now;
  206. //remoteUser.SendLayerData((int)(x / 16), (int)(x / 16), GetHeights1D());
  207. }
  208. }
  209. break;
  210. case 3:
  211. // smooth terrain
  212. //
  213. // We're leaving this out of the parcel calculations for now
  214. // because just a single one of these will stall your sim for
  215. // 12 seconds. Looping over the parcel on this one is just stupid
  216. //
  217. //for (float x = south; x <= north; x++)
  218. //{
  219. //for (float y = west; y <= east; y++)
  220. //{
  221. //SmoothTerrain(y, x , size, (double)seconds / 5.0);
  222. //}
  223. //}
  224. SmoothTerrain(west, north, size, (double) seconds/5.0);
  225. break;
  226. case 4:
  227. // noise
  228. for (float x = south; x <= north; x++)
  229. {
  230. for (float y = west; y <= east; y++)
  231. {
  232. NoiseTerrain(y, x, size, (double) seconds/5.0);
  233. lastEdit = DateTime.Now;
  234. }
  235. }
  236. break;
  237. case 5:
  238. // revert
  239. for (float x = south; x <= north; x++)
  240. {
  241. for (float y = west; y <= east; y++)
  242. {
  243. RevertTerrain(y, x, size, (double) seconds/5.0);
  244. lastEdit = DateTime.Now;
  245. }
  246. }
  247. break;
  248. // CLIENT EXTENSIONS GO HERE
  249. case 128:
  250. // erode-thermal
  251. break;
  252. case 129:
  253. // erode-aerobic
  254. break;
  255. case 130:
  256. // erode-hydraulic
  257. break;
  258. }
  259. counter++;
  260. if(counter==2)
  261. {
  262. counter=0;
  263. for (int x = 0; x < 16; x++)
  264. {
  265. for (int y = 0; y < 16; y++)
  266. {
  267. if (IsTainted(x*16, y*16))
  268. {
  269. remoteUser.SendLayerData(x, y, GetHeights1D());
  270. }
  271. }
  272. }
  273. }
  274. lastEdit = DateTime.Now;
  275. return;
  276. }
  277. /// <summary>
  278. /// Checks to make sure the terrain is within baked values +/- maxRaise/minLower
  279. /// </summary>
  280. private void SetTerrainWithinBounds()
  281. {
  282. int x, y;
  283. for (x = 0; x < w; x++)
  284. {
  285. for (y = 0; y < h; y++)
  286. {
  287. if ((heightmap.Get(x, y) > revertmap.Get(x, y) + maxRaise))
  288. {
  289. heightmap.map[x, y] = revertmap.Get(x, y) + maxRaise;
  290. }
  291. if ((heightmap.Get(x, y) > revertmap.Get(x, y) - minLower))
  292. {
  293. heightmap.map[x, y] = revertmap.Get(x, y) - minLower;
  294. }
  295. }
  296. }
  297. }
  298. /// <summary>
  299. /// Converts the heightmap to a 65536 value 1D floating point array
  300. /// </summary>
  301. /// <returns>A float[65536] array containing the heightmap</returns>
  302. public float[] GetHeights1D()
  303. {
  304. float[] heights = new float[w*h];
  305. int i;
  306. for (i = 0; i < w*h; i++)
  307. {
  308. heights[i] = (float) heightmap.map[i%w, i/w];
  309. }
  310. return heights;
  311. }
  312. /// <summary>
  313. /// Converts the heightmap to a 256x256 value 2D floating point array.
  314. /// </summary>
  315. /// <returns>An array of 256,256 values containing the heightmap</returns>
  316. public float[,] GetHeights2D()
  317. {
  318. float[,] heights = new float[w,h];
  319. int x, y;
  320. for (x = 0; x < w; x++)
  321. {
  322. for (y = 0; y < h; y++)
  323. {
  324. heights[x, y] = (float) heightmap.map[x, y];
  325. }
  326. }
  327. return heights;
  328. }
  329. /// <summary>
  330. /// Converts the heightmap to a 256x256 value 2D floating point array. Double precision version.
  331. /// </summary>
  332. /// <returns>An array of 256,256 values containing the heightmap</returns>
  333. public double[,] GetHeights2DD()
  334. {
  335. return heightmap.map;
  336. }
  337. /// <summary>
  338. /// Imports a 1D floating point array into the 2D heightmap array
  339. /// </summary>
  340. /// <param name="heights">The array to import (must have 65536 members)</param>
  341. public void GetHeights1D(float[] heights)
  342. {
  343. int i;
  344. for (i = 0; i < w*h; i++)
  345. {
  346. heightmap.map[i%w, i/w] = heights[i];
  347. }
  348. tainted++;
  349. }
  350. /// <summary>
  351. /// Loads a 2D array of values into the heightmap
  352. /// </summary>
  353. /// <param name="heights">An array of 256,256 float values</param>
  354. public void SetHeights2D(float[,] heights)
  355. {
  356. int x, y;
  357. for (x = 0; x < w; x++)
  358. {
  359. for (y = 0; y < h; y++)
  360. {
  361. heightmap.Set(x, y, (double) heights[x, y]);
  362. }
  363. }
  364. SaveRevertMap();
  365. tainted++;
  366. }
  367. /// <summary>
  368. /// Loads a 2D array of values into the heightmap (Double Precision Version)
  369. /// </summary>
  370. /// <param name="heights">An array of 256,256 float values</param>
  371. public void SetHeights2D(double[,] heights)
  372. {
  373. int x, y;
  374. for (x = 0; x < w; x++)
  375. {
  376. for (y = 0; y < h; y++)
  377. {
  378. heightmap.Set(x, y, heights[x, y]);
  379. }
  380. }
  381. SaveRevertMap();
  382. ResetTaint();
  383. }
  384. /// <summary>
  385. /// Swaps the two heightmap buffers (the 'revert map' and the heightmap)
  386. /// </summary>
  387. public void SwapRevertMaps()
  388. {
  389. Channel backup = heightmap.Copy();
  390. heightmap = revertmap;
  391. revertmap = backup;
  392. }
  393. /// <summary>
  394. /// Saves the current heightmap into the revertmap
  395. /// </summary>
  396. public void SaveRevertMap()
  397. {
  398. revertmap = heightmap.Copy();
  399. }
  400. /// <summary>
  401. /// Processes a terrain-specific command
  402. /// </summary>
  403. /// <param name="args">Commandline arguments (space seperated)</param>
  404. /// <param name="resultText">Reference that returns error or help text if returning false</param>
  405. /// <returns>If the operation was successful (if not, the error is placed into resultText)</returns>
  406. public bool RunTerrainCmd(string[] args, ref string resultText, string simName)
  407. {
  408. string command;
  409. if (args.Length > 0)
  410. {
  411. command = args[0];
  412. }
  413. else
  414. {
  415. command = "help";
  416. }
  417. try
  418. {
  419. switch (command)
  420. {
  421. case "help":
  422. resultText += "terrain regenerate - rebuilds the sims terrain using a default algorithm\n";
  423. resultText +=
  424. "terrain hills <type> <number of hills> <min height> <max height> <island t/f> <additive t/f> <noisy t/f>\n";
  425. resultText += " type should be spheres, blocks, cones, or squared\n";
  426. resultText +=
  427. "terrain voronoi <points> <blocksize> - generates a worley fractal with X points per block";
  428. resultText += "terrain seed <seed> - sets the random seed value to <seed>\n";
  429. resultText +=
  430. "terrain load <type> <filename> - loads a terrain from disk, type can be 'F32', 'F64', 'RAW' or 'IMG'\n";
  431. resultText +=
  432. "terrain save <type> <filename> - saves a terrain to disk, type can be 'F32', 'F64', 'PNG', 'RAW' or 'HIRAW'\n";
  433. resultText +=
  434. "terrain save grdmap <filename> <gradient map> - creates a PNG snapshot of the region using a named gradient map\n";
  435. resultText +=
  436. "terrain rescale <min> <max> - rescales a terrain to be between <min> and <max> meters high\n";
  437. resultText += "terrain fill <val> - fills a terrain at the specified height\n";
  438. resultText +=
  439. "terrain erode aerobic <windspeed> <pickupmin> <dropmin> <carry> <rounds> <lowest t/f> <fluid dynamics t/f>\n";
  440. resultText += "terrain erode thermal <talus> <rounds> <carry>\n";
  441. resultText += "terrain erode hydraulic <rain> <evaporation> <solubility> <frequency> <rounds>\n";
  442. resultText += "terrain multiply <val> - multiplies a terrain by <val>\n";
  443. resultText += "terrain elevate <val> - elevates a terrain by <val>\n";
  444. resultText += "terrain revert - reverts the terrain to the stored original\n";
  445. resultText += "terrain bake - saves the current terrain into the revert map\n";
  446. resultText +=
  447. "terrain csfilter <filename.cs> - loads a new filter from the specified .cs file\n";
  448. resultText +=
  449. "terrain jsfilter <filename.js> - loads a new filter from the specified .js file\n";
  450. foreach (KeyValuePair<string, ITerrainFilter> filter in customFilters.filters)
  451. {
  452. resultText += filter.Value.Help();
  453. }
  454. return false;
  455. case "revert":
  456. SwapRevertMaps();
  457. SaveRevertMap();
  458. break;
  459. case "bake":
  460. SaveRevertMap();
  461. break;
  462. case "seed":
  463. SetSeed(Convert.ToInt32(args[1]));
  464. break;
  465. case "erode":
  466. return ConsoleErosion(args, ref resultText);
  467. case "voronoi":
  468. double[] c = new double[2];
  469. c[0] = -1;
  470. c[1] = 1;
  471. heightmap.VoronoiDiagram(Convert.ToInt32(args[1]), Convert.ToInt32(args[2]), c);
  472. break;
  473. case "hills":
  474. return ConsoleHills(args, ref resultText);
  475. case "regenerate":
  476. SetDefaultTerrain();
  477. break;
  478. case "rescale":
  479. SetRange(Convert.ToSingle(args[1]), Convert.ToSingle(args[2]));
  480. break;
  481. case "elevate":
  482. Elevate(Convert.ToSingle(args[1]));
  483. break;
  484. case "fill":
  485. heightmap.Fill(Convert.ToDouble(args[1]));
  486. tainted++;
  487. break;
  488. case "clip":
  489. heightmap.Clip(Convert.ToDouble(args[1]), Convert.ToDouble(args[2]));
  490. tainted++;
  491. break;
  492. case "smooth":
  493. heightmap.Smooth(Convert.ToDouble(args[1]));
  494. tainted++;
  495. break;
  496. case "add":
  497. heightmap += Convert.ToDouble(args[1]);
  498. tainted++;
  499. break;
  500. case "multiply":
  501. heightmap *= Convert.ToDouble(args[1]);
  502. tainted++;
  503. break;
  504. case "load":
  505. string filenameL = args[2].Replace("%name%", simName);
  506. filenameL = filenameL.Replace("%x%", offsetX.ToString());
  507. filenameL = filenameL.Replace("%y%", offsetY.ToString());
  508. switch (args[1].ToLower())
  509. {
  510. case "f32":
  511. LoadFromFileF32(filenameL);
  512. break;
  513. case "f64":
  514. LoadFromFileF64(filenameL);
  515. break;
  516. case "raw":
  517. LoadFromFileSLRAW(filenameL);
  518. break;
  519. case "img":
  520. heightmap = heightmap.LoadImage(filenameL);
  521. tainted++;
  522. break;
  523. default:
  524. resultText = "Unknown image or data format";
  525. return false;
  526. }
  527. break;
  528. case "load-tile":
  529. switch (args[1].ToLower())
  530. {
  531. case "f32":
  532. LoadFromFileF32(args[2], Convert.ToInt32(args[3]), Convert.ToInt32(args[4]),
  533. Convert.ToInt32(args[5]), Convert.ToInt32(args[6]));
  534. break;
  535. case "raw":
  536. LoadFromFileSLRAW(args[2], Convert.ToInt32(args[3]), Convert.ToInt32(args[4]),
  537. Convert.ToInt32(args[5]), Convert.ToInt32(args[6]));
  538. break;
  539. case "img":
  540. LoadFromFileIMG(args[2], Convert.ToInt32(args[3]), Convert.ToInt32(args[4]),
  541. Convert.ToInt32(args[5]), Convert.ToInt32(args[6]));
  542. break;
  543. default:
  544. resultText = "Unknown or unsupported image or data format";
  545. return false;
  546. }
  547. break;
  548. case "save":
  549. string filename = args[2].Replace("%name%", simName);
  550. filename = filename.Replace("%x%", offsetX.ToString());
  551. filename = filename.Replace("%y%", offsetY.ToString());
  552. switch (args[1].ToLower())
  553. {
  554. case "f32":
  555. WriteToFileF32(filename);
  556. break;
  557. case "f64":
  558. WriteToFileF64(filename);
  559. break;
  560. case "grdmap":
  561. if (args.Length >= 4)
  562. WriteImage(filename, args[3]);
  563. else
  564. WriteImage(filename, "defaultstripe.png");
  565. break;
  566. case "png":
  567. heightmap.SaveImage(filename);
  568. break;
  569. case "raw":
  570. WriteToFileRAW(filename);
  571. break;
  572. case "hiraw":
  573. WriteToFileHiRAW(filename);
  574. break;
  575. default:
  576. resultText = "Unknown image or data format";
  577. return false;
  578. }
  579. break;
  580. case "csfilter":
  581. customFilters.LoadFilterCSharp(args[1]);
  582. break;
  583. case "jsfilter":
  584. customFilters.LoadFilterJScript(args[1]);
  585. break;
  586. default:
  587. // Run any custom registered filters
  588. if (customFilters.filters.ContainsKey(command))
  589. {
  590. customFilters.filters[command].Filter(heightmap, args);
  591. break;
  592. }
  593. else
  594. {
  595. resultText = "Unknown terrain command";
  596. return false;
  597. }
  598. }
  599. return true;
  600. }
  601. catch (Exception e) // SEMI-LEGIT: Catching problems caused by user input or scripts
  602. {
  603. resultText = "Error running terrain command: " + e.ToString();
  604. return false;
  605. }
  606. }
  607. private bool ConsoleErosion(string[] args, ref string resultText)
  608. {
  609. double min = heightmap.FindMin();
  610. double max = heightmap.FindMax();
  611. switch (args[1].ToLower())
  612. {
  613. case "aerobic":
  614. // WindSpeed, PickupMinimum,DropMinimum,Carry,Rounds,Lowest
  615. heightmap.AerobicErosion(Convert.ToDouble(args[2]), Convert.ToDouble(args[3]),
  616. Convert.ToDouble(args[4]), Convert.ToDouble(args[5]),
  617. Convert.ToInt32(args[6]), Convert.ToBoolean(args[7]),
  618. Convert.ToBoolean(args[8]));
  619. break;
  620. case "thermal":
  621. heightmap.ThermalWeathering(Convert.ToDouble(args[2]), Convert.ToInt32(args[3]),
  622. Convert.ToDouble(args[4]));
  623. break;
  624. case "hydraulic":
  625. Channel rainMap = new Channel(w, h);
  626. rainMap.Fill(Convert.ToDouble(args[2]));
  627. heightmap.HydraulicErosion(rainMap, Convert.ToDouble(args[3]), Convert.ToDouble(args[4]),
  628. Convert.ToInt32(args[5]), Convert.ToInt32(args[6]));
  629. break;
  630. default:
  631. resultText = "Unknown erosion type";
  632. return false;
  633. }
  634. heightmap.Normalise(min, max);
  635. tainted++;
  636. return true;
  637. }
  638. private bool ConsoleHills(string[] args, ref string resultText)
  639. {
  640. Random RandomClass = new Random();
  641. SetSeed(RandomClass.Next());
  642. int count;
  643. double sizeMin;
  644. double sizeRange;
  645. bool island;
  646. bool additive;
  647. bool noisy;
  648. if (args.GetLength(0) > 2)
  649. {
  650. int.TryParse(args[2].ToString(), out count);
  651. double.TryParse(args[3].ToString(), NumberStyles.AllowDecimalPoint, Culture.NumberFormatInfo,
  652. out sizeMin);
  653. double.TryParse(args[4].ToString(), NumberStyles.AllowDecimalPoint, Culture.NumberFormatInfo,
  654. out sizeRange);
  655. bool.TryParse(args[5].ToString(), out island);
  656. bool.TryParse(args[6].ToString(), out additive);
  657. bool.TryParse(args[7].ToString(), out noisy);
  658. }
  659. else
  660. {
  661. count = 200;
  662. sizeMin = 20;
  663. sizeRange = 40;
  664. island = true;
  665. additive = true;
  666. noisy = false;
  667. }
  668. switch (args[1].ToLower())
  669. {
  670. case "blocks":
  671. heightmap.HillsBlocks(count, sizeMin, sizeRange, island, additive, noisy);
  672. break;
  673. case "cones":
  674. heightmap.HillsCones(count, sizeMin, sizeRange, island, additive, noisy);
  675. break;
  676. case "spheres":
  677. heightmap.HillsSpheres(count, sizeMin, sizeRange, island, additive, noisy);
  678. break;
  679. case "squared":
  680. heightmap.HillsSquared(count, sizeMin, sizeRange, island, additive, noisy);
  681. break;
  682. default:
  683. resultText = "Unknown hills type";
  684. return false;
  685. }
  686. tainted++;
  687. return true;
  688. }
  689. /// <summary>
  690. /// Renormalises the array between min and max
  691. /// </summary>
  692. /// <param name="min">Minimum value of the new array</param>
  693. /// <param name="max">Maximum value of the new array</param>
  694. public void SetRange(float min, float max)
  695. {
  696. heightmap.Normalise((double) min, (double) max);
  697. tainted++;
  698. }
  699. /// <summary>
  700. /// Adds meters (positive or negative) to terrain height
  701. /// </summary>
  702. /// <param name="meters">Positive or negative value to add to new array</param>
  703. public void Elevate(float meters)
  704. {
  705. heightmap.Elevate((double)meters);
  706. tainted++;
  707. }
  708. /// <summary>
  709. /// Loads a file consisting of 256x256 doubles and imports it as an array into the map.
  710. /// </summary>
  711. /// <remarks>TODO: Move this to libTerrain itself</remarks>
  712. /// <param name="filename">The filename of the double array to import</param>
  713. public void LoadFromFileF64(string filename)
  714. {
  715. FileInfo file = new FileInfo(filename);
  716. FileStream s = file.Open(FileMode.Open, FileAccess.Read);
  717. BinaryReader bs = new BinaryReader(s);
  718. int x, y;
  719. for (y = 0; y < h; y++)
  720. {
  721. for (x = 0; x < h; x++)
  722. {
  723. heightmap.Set(x, y, (double) bs.ReadSingle());
  724. }
  725. }
  726. bs.Close();
  727. s.Close();
  728. tainted++;
  729. }
  730. /// <summary>
  731. /// Loads a file consisting of 256x256 floats and imports it as an array into the map.
  732. /// </summary>
  733. /// <remarks>TODO: Move this to libTerrain itself</remarks>
  734. /// <param name="filename">The filename of the float array to import</param>
  735. public void LoadFromFileF32(string filename)
  736. {
  737. FileInfo file = new FileInfo(filename);
  738. FileStream s = file.Open(FileMode.Open, FileAccess.Read);
  739. BinaryReader bs = new BinaryReader(s);
  740. int x, y;
  741. for (y = 0; y < h; y++)
  742. {
  743. for (x = 0; x < w; x++)
  744. {
  745. heightmap.Set(x, y, (double) bs.ReadSingle());
  746. }
  747. }
  748. bs.Close();
  749. s.Close();
  750. tainted++;
  751. }
  752. /// <summary>
  753. /// Loads a section of a larger heightmap (F32)
  754. /// </summary>
  755. /// <param name="filename">File to load</param>
  756. /// <param name="dimensionX">Size of the file</param>
  757. /// <param name="dimensionY">Size of the file</param>
  758. /// <param name="lowerboundX">Where do the region coords start for this terrain?</param>
  759. /// <param name="lowerboundY">Where do the region coords start for this terrain?</param>
  760. public void LoadFromFileF32(string filename, int dimensionX, int dimensionY, int lowerboundX, int lowerboundY)
  761. {
  762. fileIOLock.WaitOne();
  763. try
  764. {
  765. int sectionToLoadX = ((offsetX - lowerboundX)*w);
  766. int sectionToLoadY = ((offsetY - lowerboundY)*h);
  767. double[,] tempMap = new double[dimensionX,dimensionY];
  768. FileInfo file = new FileInfo(filename);
  769. FileStream s = file.Open(FileMode.Open, FileAccess.Read);
  770. BinaryReader bs = new BinaryReader(s);
  771. int x, y;
  772. for (x = 0; x < dimensionX; x++)
  773. {
  774. for (y = 0; y < dimensionY; y++)
  775. {
  776. tempMap[x, y] = (double) bs.ReadSingle();
  777. }
  778. }
  779. for (y = 0; y < h; y++)
  780. {
  781. for (x = 0; x < w; x++)
  782. {
  783. heightmap.Set(x, y, tempMap[x + sectionToLoadX, y + sectionToLoadY]);
  784. }
  785. }
  786. bs.Close();
  787. s.Close();
  788. tainted++;
  789. }
  790. finally
  791. {
  792. fileIOLock.ReleaseMutex();
  793. }
  794. }
  795. /// <summary>
  796. /// Loads a larger tiled image across a terrain
  797. /// </summary>
  798. /// <param name="filename">Filename to load from (any generic image format should work)</param>
  799. /// <param name="dimensionX">The dimensions of the image</param>
  800. /// <param name="dimensionY">The dimensions of the image</param>
  801. /// <param name="lowerboundX">Where sim coords begin for this patch</param>
  802. /// <param name="lowerboundY">Where sim coords begin for this patch</param>
  803. public void LoadFromFileIMG(string filename, int dimensionX, int dimensionY, int lowerboundX, int lowerboundY)
  804. {
  805. int sectionToLoadX = ((offsetX - lowerboundX)*w);
  806. int sectionToLoadY = ((offsetY - lowerboundY)*h);
  807. double[,] tempMap = new double[dimensionX,dimensionY];
  808. Bitmap lgrBmp = new Bitmap(filename);
  809. int x, y;
  810. for (x = 0; x < dimensionX; x++)
  811. {
  812. for (y = 0; y < dimensionY; y++)
  813. {
  814. tempMap[x, y] = (float) lgrBmp.GetPixel(x, y).GetBrightness();
  815. }
  816. }
  817. for (y = 0; y < h; y++)
  818. {
  819. for (x = 0; x < w; x++)
  820. {
  821. heightmap.Set(x, y, tempMap[x + sectionToLoadX, y + sectionToLoadY]);
  822. }
  823. }
  824. tainted++;
  825. }
  826. /// <summary>
  827. /// Loads a file formatted in the SL .RAW Format used on the main grid
  828. /// </summary>
  829. /// <remarks>This file format stinks and is best avoided.</remarks>
  830. /// <param name="filename">A path to the .RAW format</param>
  831. public void LoadFromFileSLRAW(string filename)
  832. {
  833. FileInfo file = new FileInfo(filename);
  834. FileStream s = file.Open(FileMode.Open, FileAccess.Read);
  835. BinaryReader bs = new BinaryReader(s);
  836. int x, y;
  837. for (y = 0; y < h; y++)
  838. {
  839. for (x = 0; x < w; x++)
  840. {
  841. heightmap.Set(x, y, (double) bs.ReadByte()*((double) bs.ReadByte()/127.0));
  842. bs.ReadBytes(11); // Advance the stream to next bytes.
  843. }
  844. }
  845. bs.Close();
  846. s.Close();
  847. tainted++;
  848. }
  849. /// <summary>
  850. /// Loads a section of a larger heightmap (RAW)
  851. /// </summary>
  852. /// <param name="filename">File to load</param>
  853. /// <param name="dimensionX">Size of the file</param>
  854. /// <param name="dimensionY">Size of the file</param>
  855. /// <param name="lowerboundX">Where do the region coords start for this terrain?</param>
  856. /// <param name="lowerboundY">Where do the region coords start for this terrain?</param>
  857. public void LoadFromFileSLRAW(string filename, int dimensionX, int dimensionY, int lowerboundX, int lowerboundY)
  858. {
  859. // TODO: Mutex fails to release readlock on folder! --> only one file can be loaded into sim
  860. //fileIOLock.WaitOne();
  861. //try
  862. //{
  863. int sectionToLoadX = ((offsetX - lowerboundX)*w);
  864. int sectionToLoadY = ((offsetY - lowerboundY)*h);
  865. double[,] tempMap = new double[dimensionX,dimensionY];
  866. FileInfo file = new FileInfo(filename);
  867. FileStream s = file.Open(FileMode.Open, FileAccess.Read);
  868. BinaryReader bs = new BinaryReader(s);
  869. int x, y;
  870. for (x = 0; x < dimensionX; x++)
  871. {
  872. for (y = 0; y < dimensionY; y++)
  873. {
  874. tempMap[x, y] = (double) bs.ReadByte()*((double) bs.ReadByte()/127.0);
  875. bs.ReadBytes(11); // Advance the stream to next bytes.
  876. }
  877. }
  878. for (y = 0; y < h; y++)
  879. {
  880. for (x = 0; x < w; x++)
  881. {
  882. heightmap.Set(x, y, tempMap[x + sectionToLoadX, y + sectionToLoadY]);
  883. }
  884. }
  885. bs.Close();
  886. s.Close();
  887. tainted++;
  888. //}
  889. //finally
  890. //{
  891. // fileIOLock.ReleaseMutex();
  892. //}
  893. }
  894. /// <summary>
  895. /// Writes the current terrain heightmap to disk, in the format of a 65536 entry double[] array.
  896. /// </summary>
  897. /// <param name="filename">The desired output filename</param>
  898. public void WriteToFileF64(string filename)
  899. {
  900. FileInfo file = new FileInfo(filename);
  901. FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
  902. BinaryWriter bs = new BinaryWriter(s);
  903. int x, y;
  904. for (y = 0; y < h; y++)
  905. {
  906. for (x = 0; x < w; x++)
  907. {
  908. bs.Write(heightmap.Get(x, y));
  909. }
  910. }
  911. bs.Close();
  912. s.Close();
  913. }
  914. /// <summary>
  915. /// Writes the current terrain heightmap to disk, in the format of a 65536 entry float[] array
  916. /// </summary>
  917. /// <param name="filename">The desired output filename</param>
  918. public void WriteToFileF32(string filename)
  919. {
  920. FileInfo file = new FileInfo(filename);
  921. FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
  922. BinaryWriter bs = new BinaryWriter(s);
  923. int x, y;
  924. for (y = 0; y < h; y++)
  925. {
  926. for (x = 0; x < w; x++)
  927. {
  928. bs.Write((float) heightmap.Get(x, y));
  929. }
  930. }
  931. bs.Close();
  932. s.Close();
  933. }
  934. /// <summary>
  935. /// A very fast LL-RAW file output mechanism - lower precision mechanism but wont take 5 minutes to run either.
  936. /// (is also editable in an image application)
  937. /// </summary>
  938. /// <param name="filename">Filename to write to</param>
  939. public void WriteToFileRAW(string filename)
  940. {
  941. FileInfo file = new FileInfo(filename);
  942. FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
  943. BinaryWriter binStream = new BinaryWriter(s);
  944. int x, y;
  945. // Used for the 'green' channel.
  946. byte avgMultiplier = (byte) heightmap.Avg();
  947. byte backupMultiplier = (byte) revertmap.Avg();
  948. // Limit the multiplier so it can represent points >64m.
  949. if (avgMultiplier > 196)
  950. avgMultiplier = 196;
  951. if (backupMultiplier > 196)
  952. backupMultiplier = 196;
  953. // Make sure it's at least one to prevent a div by zero
  954. if (avgMultiplier < 1)
  955. avgMultiplier = 1;
  956. if (backupMultiplier < 1)
  957. backupMultiplier = 1;
  958. for (y = 0; y < h; y++)
  959. {
  960. for (x = 0; x < h; x++)
  961. {
  962. byte red = (byte) (heightmap.Get(x, y)/((double) avgMultiplier/128.0));
  963. byte green = avgMultiplier;
  964. byte blue = (byte) watermap.Get(x, y);
  965. byte alpha1 = 0; // Land Parcels
  966. byte alpha2 = 0; // For Sale Land
  967. byte alpha3 = 0; // Public Edit Object
  968. byte alpha4 = 0; // Public Edit Land
  969. byte alpha5 = 255; // Safe Land
  970. byte alpha6 = 255; // Flying Allowed
  971. byte alpha7 = 255; // Create Landmark
  972. byte alpha8 = 255; // Outside Scripts
  973. byte alpha9 = (byte) (revertmap.Get(x, y)/((double) backupMultiplier/128.0));
  974. byte alpha10 = backupMultiplier;
  975. binStream.Write(red);
  976. binStream.Write(green);
  977. binStream.Write(blue);
  978. binStream.Write(alpha1);
  979. binStream.Write(alpha2);
  980. binStream.Write(alpha3);
  981. binStream.Write(alpha4);
  982. binStream.Write(alpha5);
  983. binStream.Write(alpha6);
  984. binStream.Write(alpha7);
  985. binStream.Write(alpha8);
  986. binStream.Write(alpha9);
  987. binStream.Write(alpha10);
  988. }
  989. }
  990. binStream.Close();
  991. s.Close();
  992. }
  993. /// <summary>
  994. /// Outputs to a LL compatible RAW in the most efficient manner possible
  995. /// </summary>
  996. /// <remarks>Does not calculate the revert map</remarks>
  997. /// <param name="filename">The filename to output to</param>
  998. public void WriteToFileHiRAW(string filename)
  999. {
  1000. FileInfo file = new FileInfo(filename);
  1001. FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
  1002. BinaryWriter binStream = new BinaryWriter(s);
  1003. // Generate a smegging big lookup table to speed the operation up (it needs it)
  1004. double[] lookupHeightTable = new double[65536];
  1005. int i, j, x, y;
  1006. for (i = 0; i < 256; i++)
  1007. {
  1008. for (j = 0; j < 256; j++)
  1009. {
  1010. lookupHeightTable[i + (j*256)] = ((double) i*((double) j/127.0));
  1011. }
  1012. }
  1013. // Output the calculated raw
  1014. for (y = 0; y < h; y++)
  1015. {
  1016. for (x = 0; x < w; x++)
  1017. {
  1018. double t = heightmap.Get(x, y);
  1019. double min = double.MaxValue;
  1020. int index = 0;
  1021. for (i = 0; i < 65536; i++)
  1022. {
  1023. if (Math.Abs(t - lookupHeightTable[i]) < min)
  1024. {
  1025. min = Math.Abs(t - lookupHeightTable[i]);
  1026. index = i;
  1027. }
  1028. }
  1029. byte red = (byte) (index & 0xFF);
  1030. byte green = (byte) ((index >> 8) & 0xFF);
  1031. byte blue = (byte) watermap.Get(x, y);
  1032. byte alpha1 = 0; // Land Parcels
  1033. byte alpha2 = 0; // For Sale Land
  1034. byte alpha3 = 0; // Public Edit Object
  1035. byte alpha4 = 0; // Public Edit Land
  1036. byte alpha5 = 255; // Safe Land
  1037. byte alpha6 = 255; // Flying Allowed
  1038. byte alpha7 = 255; // Create Landmark
  1039. byte alpha8 = 255; // Outside Scripts
  1040. byte alpha9 = red;
  1041. byte alpha10 = green;
  1042. binStream.Write(red);
  1043. binStream.Write(green);
  1044. binStream.Write(blue);
  1045. binStream.Write(alpha1);
  1046. binStream.Write(alpha2);
  1047. binStream.Write(alpha3);
  1048. binStream.Write(alpha4);
  1049. binStream.Write(alpha5);
  1050. binStream.Write(alpha6);
  1051. binStream.Write(alpha7);
  1052. binStream.Write(alpha8);
  1053. binStream.Write(alpha9);
  1054. binStream.Write(alpha10);
  1055. }
  1056. }
  1057. binStream.Close();
  1058. s.Close();
  1059. }
  1060. /// <summary>
  1061. /// Sets the random seed to be used by procedural functions which involve random numbers.
  1062. /// </summary>
  1063. /// <param name="val">The desired seed</param>
  1064. public void SetSeed(int val)
  1065. {
  1066. heightmap.seed = val;
  1067. }
  1068. /// <summary>
  1069. /// Sets a particular heightmap point to a specified value
  1070. /// </summary>
  1071. /// <param name="x">X Coordinate</param>
  1072. /// <param name="y">Y Coordinate</param>
  1073. /// <param name="val">Value</param>
  1074. public void Set(int x, int y, double val)
  1075. {
  1076. lock (heightmap)
  1077. {
  1078. heightmap.Set(x, y, val);
  1079. }
  1080. tainted++;
  1081. }
  1082. /// <summary>
  1083. /// Raises land in a sphere around the specified coordinates
  1084. /// </summary>
  1085. /// <param name="rx">Center of the sphere on the X axis</param>
  1086. /// <param name="ry">Center of the sphere on the Y axis</param>
  1087. /// <param name="size">The radius of the sphere</param>
  1088. /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
  1089. public void RaiseTerrain(double rx, double ry, double size, double amount)
  1090. {
  1091. lock (heightmap)
  1092. {
  1093. heightmap.Raise(rx, ry, size, amount);
  1094. }
  1095. tainted++;
  1096. }
  1097. /// <summary>
  1098. /// Lowers the land in a sphere around the specified coordinates
  1099. /// </summary>
  1100. /// <param name="rx">The center of the sphere at the X axis</param>
  1101. /// <param name="ry">The center of the sphere at the Y axis</param>
  1102. /// <param name="size">The radius of the sphere in meters</param>
  1103. /// <param name="amount">Scale the height of the sphere by this amount (recommended 0..2)</param>
  1104. public void LowerTerrain(double rx, double ry, double size, double amount)
  1105. {
  1106. lock (heightmap)
  1107. {
  1108. heightmap.Lower(rx, ry, size, amount);
  1109. }
  1110. tainted++;
  1111. }
  1112. /// <summary>
  1113. /// Flattens the land under the brush of specified coordinates (spherical mask)
  1114. /// </summary>
  1115. /// <param name="rx">Center of sphere</param>
  1116. /// <param name="ry">Center of sphere</param>
  1117. /// <param name="size">Radius of the sphere</param>
  1118. /// <param name="amount">Thickness of the mask (0..2 recommended)</param>
  1119. public void FlattenTerrain(double rx, double ry, double size, double amount)
  1120. {
  1121. lock (heightmap)
  1122. {
  1123. heightmap.Flatten(rx, ry, size, amount);
  1124. }
  1125. tainted++;
  1126. }
  1127. /// <summary>
  1128. /// Creates noise within the specified bounds
  1129. /// </summary>
  1130. /// <param name="rx">Center of the bounding sphere</param>
  1131. /// <param name="ry">Center of the bounding sphere</param>
  1132. /// <param name="size">The radius of the sphere</param>
  1133. /// <param name="amount">Strength of the mask (0..2) recommended</param>
  1134. public void NoiseTerrain(double rx, double ry, double size, double amount)
  1135. {
  1136. lock (heightmap)
  1137. {
  1138. Channel smoothed = new Channel();
  1139. smoothed.Noise();
  1140. Channel mask = new Channel();
  1141. mask.Raise(rx, ry, size, amount);
  1142. heightmap.Blend(smoothed, mask);
  1143. }
  1144. tainted++;
  1145. }
  1146. /// <summary>
  1147. /// Reverts land within the specified bounds
  1148. /// </summary>
  1149. /// <param name="rx">Center of the bounding sphere</param>
  1150. /// <param name="ry">Center of the bounding sphere</param>
  1151. /// <param name="size">The radius of the sphere</param>
  1152. /// <param name="amount">Strength of the mask (0..2) recommended</param>
  1153. public void RevertTerrain(double rx, double ry, double size, double amount)
  1154. {
  1155. lock (heightmap)
  1156. {
  1157. Channel mask = new Channel();
  1158. mask.Raise(rx, ry, size, amount);
  1159. heightmap.Blend(revertmap, mask);
  1160. }
  1161. tainted++;
  1162. }
  1163. /// <summary>
  1164. /// Smooths land under the brush of specified coordinates (spherical mask)
  1165. /// </summary>
  1166. /// <param name="rx">Center of the sphere</param>
  1167. /// <param name="ry">Center of the sphere</param>
  1168. /// <param name="size">Radius of the sphere</param>
  1169. /// <param name="amount">Thickness of the mask (0..2 recommended)</param>
  1170. public void SmoothTerrain(double rx, double ry, double size, double amount)
  1171. {
  1172. lock (heightmap)
  1173. {
  1174. Channel smoothed = heightmap.Copy();
  1175. smoothed.Smooth(amount);
  1176. Channel mask = new Channel();
  1177. mask.Raise(rx, ry, size, amount);
  1178. heightmap.Blend(smoothed, mask);
  1179. }
  1180. tainted++;
  1181. }
  1182. /// <summary>
  1183. /// Generates a simple set of hills in the shape of an island
  1184. /// </summary>
  1185. public void SetDefaultTerrain()
  1186. {
  1187. lock (heightmap)
  1188. {
  1189. heightmap.HillsSpheres(200, 20, 40, true, true, false);
  1190. heightmap.Normalise();
  1191. heightmap *= 60.0; // Raise to 60m
  1192. heightmap.Clip(0.0, 25.0);
  1193. heightmap.Pertubation(2.5);
  1194. heightmap.Smooth(35.0);
  1195. heightmap.Normalise(0.0, 21.0);
  1196. }
  1197. tainted++;
  1198. }
  1199. /// <summary>
  1200. /// Wrapper to heightmap.get()
  1201. /// </summary>
  1202. /// <param name="x">X coord</param>
  1203. /// <param name="y">Y coord</param>
  1204. /// <returns>Height at specified coordinates</returns>
  1205. public double GetHeight(int x, int y)
  1206. {
  1207. return heightmap.Get(x, y);
  1208. }
  1209. /// <summary>
  1210. /// Multiplies the heightfield by val
  1211. /// </summary>
  1212. /// <param name="meep">The heightfield</param>
  1213. /// <param name="val">The multiplier</param>
  1214. /// <returns></returns>
  1215. public static TerrainEngine operator *(TerrainEngine terrain, Double val)
  1216. {
  1217. terrain.heightmap *= val;
  1218. terrain.tainted++;
  1219. return terrain;
  1220. }
  1221. /// <summary>
  1222. /// Exports the current heightmap to a PNG file
  1223. /// </summary>
  1224. /// <param name="filename">The destination filename for the image</param>
  1225. /// <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>
  1226. public void WriteImage(string filename, string gradientmap)
  1227. {
  1228. try
  1229. {
  1230. Bitmap bmp = TerrainToBitmap(gradientmap);
  1231. bmp.Save(filename, ImageFormat.Png);
  1232. }
  1233. catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
  1234. {
  1235. Console.WriteLine("Failed generating terrain map: " + e.ToString());
  1236. }
  1237. }
  1238. /// <summary>
  1239. /// Exports the current heightmap in Jpeg2000 format to a byte[]
  1240. /// </summary>
  1241. /// <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>
  1242. public byte[] WriteJpegImage(string gradientmap)
  1243. {
  1244. byte[] imageData = null;
  1245. try
  1246. {
  1247. Bitmap bmp = TerrainToBitmap(gradientmap);
  1248. imageData = OpenJPEG.EncodeFromImage(bmp, true);
  1249. }
  1250. catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
  1251. {
  1252. Console.WriteLine("Failed generating terrain map: " + e.ToString());
  1253. }
  1254. return imageData;
  1255. }
  1256. private Bitmap TerrainToBitmap(string gradientmap)
  1257. {
  1258. Bitmap gradientmapLd = new Bitmap(gradientmap);
  1259. int pallete = gradientmapLd.Height;
  1260. Bitmap bmp = new Bitmap(heightmap.w, heightmap.h);
  1261. Color[] colours = new Color[pallete];
  1262. for (int i = 0; i < pallete; i++)
  1263. {
  1264. colours[i] = gradientmapLd.GetPixel(0, i);
  1265. }
  1266. Channel copy = heightmap.Copy();
  1267. for (int y = 0; y < copy.h; y++)
  1268. {
  1269. for (int x = 0; x < copy.w; x++)
  1270. {
  1271. // 512 is the largest possible height before colours clamp
  1272. int colorindex = (int) (Math.Max(Math.Min(1.0, copy.Get(x, y)/512.0), 0.0)*(pallete - 1));
  1273. bmp.SetPixel(x, copy.h - y - 1, colours[colorindex]);
  1274. }
  1275. }
  1276. return bmp;
  1277. }
  1278. }
  1279. }