PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenSim/Region/Framework/Scenes/VoxelChannel.cs

https://gitlab.com/N3X15/VoxelSim
C# | 678 lines | 594 code | 56 blank | 28 comment | 81 complexity | 8937d1529fcbaa2c32e4cbf50b70023c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.IO;
  5. using System.Xml;
  6. using System.Xml.Serialization;
  7. using Gif.Components;
  8. using LibNbt;
  9. using LibNbt.Tags;
  10. using OpenMetaverse;
  11. using OpenSim.Framework;
  12. using OpenSim.Region.Framework.Interfaces;
  13. using Math = System.Math;
  14. namespace OpenSim.Region.Framework.Scenes
  15. {
  16. public enum ReplaceMode
  17. {
  18. NONE,
  19. A_ONLY,
  20. B_ONLY
  21. }
  22. public class VoxelChannel:IVoxelChannel
  23. {
  24. // 256x256x256 = 16,777,216 Byte = 16 Megabyte (MB)!
  25. public byte[] Voxels;
  26. public const byte AIR_VOXEL=0x00;
  27. public MaterialMap mMaterials = new MaterialMap();
  28. public Dictionary<string, ITerrainGenerator> TerrainGenerators = new Dictionary<string,ITerrainGenerator>();
  29. public int XScale {get; protected set;}
  30. public int YScale {get; protected set;}
  31. public int ZScale {get; protected set;}
  32. public bool IsSolid(int x,int y,int z)
  33. {
  34. byte v = GetVoxel(x,y,z);
  35. if(v==AIR_VOXEL) return false;
  36. return (mMaterials[v].Flags & MatFlags.Solid)==MatFlags.Solid;
  37. }
  38. public int this[int x,int y,int z]
  39. {
  40. get{
  41. return (int)GetVoxel(x,y,z);
  42. }
  43. set
  44. {
  45. SetVoxel(x,y,z,(byte)value);
  46. }
  47. }
  48. public int Height
  49. {
  50. get{return ZScale;}
  51. }
  52. public int Width
  53. {
  54. get{return XScale;}
  55. }
  56. public int Length
  57. {
  58. get{return YScale;}
  59. }
  60. /// <summary>
  61. /// Constructor.
  62. /// </summary>
  63. /// <param name="x">
  64. /// X size
  65. /// </param>
  66. /// <param name="y">
  67. /// Y size
  68. /// </param>
  69. /// <param name="z">
  70. /// Z size
  71. /// </param>
  72. public VoxelChannel(int x,int y,int z)
  73. {
  74. Voxels = new byte[x*y*z];
  75. XScale=x;
  76. YScale=y;
  77. ZScale=z;
  78. VoxMaterial m = new VoxMaterial();
  79. m.Flags=MatFlags.Solid;
  80. AddMaterial(m);
  81. FillVoxels(new Vector3(0,0,0),new Vector3(x,y,z),AIR_VOXEL);
  82. TerrainGenerators.Add("default", new HillGenerator());
  83. }
  84. public VoxelChannel(uint x,uint y,uint z)
  85. {
  86. Voxels = new byte[x*y*z];
  87. XScale=(int)x;
  88. YScale=(int)y;
  89. ZScale=(int)z;
  90. VoxMaterial m = new VoxMaterial();
  91. m.Flags=MatFlags.Solid;
  92. AddMaterial(m);
  93. FillVoxels(new Vector3(0, 0, 0), new Vector3((int)x, (int)y, (int)z), AIR_VOXEL);
  94. TerrainGenerators.Add("default", new HillGenerator());
  95. }
  96. public void SetVoxel(int x,int y,int z,byte voxel)
  97. {
  98. SetVoxel(new Vector3(x,y,z),voxel);
  99. }
  100. public bool Tainted(int x,int y,int z)
  101. {
  102. // TODO: Implement.
  103. return true;
  104. }
  105. public void AddMaterial(VoxMaterial butts)
  106. {
  107. mMaterials.Add(butts.Name,butts);
  108. }
  109. public void SetVoxel(Vector3 pos, byte v)
  110. {
  111. if(!inGrid(pos)) return;
  112. int x=(int)Math.Round(pos.X);
  113. int y=(int)Math.Round(pos.Y);
  114. int z=(int)Math.Round(pos.Z);
  115. Voxels[y * ZScale + x * ZScale * XScale + z]=v;
  116. }
  117. public IVoxelChannel MakeCopy()
  118. {
  119. VoxelChannel vc = new VoxelChannel(XScale,YScale,ZScale);
  120. vc.Voxels=Voxels;
  121. return vc;
  122. }
  123. public bool inGrid(Vector3 pos)
  124. {
  125. return !(0 > pos.X || XScale < pos.X ||
  126. 0 > pos.Y || YScale < pos.Y ||
  127. 0 > pos.Z || ZScale < pos.Z );
  128. }
  129. public byte GetVoxel(Vector3 pos)
  130. {
  131. if(!inGrid(pos)) return AIR_VOXEL;
  132. int x=(int)Math.Round(pos.X);
  133. int y=(int)Math.Round(pos.Y);
  134. int z=(int)Math.Round(pos.Z);
  135. return Voxels[y * ZScale + x * ZScale * XScale + z];
  136. }
  137. public byte GetVoxel(int x,int y,int z)
  138. {
  139. return GetVoxel(new Vector3(x,y,z));
  140. }
  141. public void MoveVoxel(Vector3 from, Vector3 to)
  142. {
  143. SetVoxel(to,GetVoxel(from));
  144. }
  145. public void FillVoxels(Vector3 min,Vector3 max,byte v)
  146. {
  147. for(int x = (int)Math.Round(min.X);x<(int)Math.Round(max.X);x++)
  148. {
  149. for(int y = (int)Math.Round(min.Y);y<(int)Math.Round(max.Y);y++)
  150. {
  151. for(int z = (int)Math.Round(min.Z);z<(int)Math.Round(max.Z);z++)
  152. {
  153. ///Console.WriteLine("({0},{1},{2}) {3}",x,y,z,v);
  154. SetVoxel(x,y,z,v);
  155. }
  156. }
  157. }
  158. }
  159. static public VoxelChannel AND(VoxelChannel a,VoxelChannel b,ReplaceMode rep)
  160. {
  161. int x,y,z;
  162. for(z=0;z<a.ZScale;z++)
  163. {
  164. for(y=0;y<a.YScale;y++)
  165. {
  166. for(x=0;x<a.XScale;x++)
  167. {
  168. bool As=a.IsSolid(x,y,z);
  169. bool Bs=b.IsSolid(x,y,z);
  170. if(As && Bs)
  171. {
  172. a.SetVoxel(x,y,z,b.GetVoxel(x,y,z));
  173. }
  174. }
  175. }
  176. }
  177. return a;
  178. }
  179. public static VoxelChannel operator+(VoxelChannel a, VoxelChannel b)
  180. {
  181. int x,y,z;
  182. for(z=0;z<a.ZScale;z++)
  183. {
  184. for(y=0;y<a.YScale;y++)
  185. {
  186. for(x=0;x<a.XScale;x++)
  187. {
  188. if(b.IsSolid(x,y,z))
  189. a.SetVoxel(x,y,z,b.GetVoxel(x,y,z));
  190. }
  191. }
  192. }
  193. return a;
  194. }
  195. public static VoxelChannel operator-(VoxelChannel a, VoxelChannel b)
  196. {
  197. int x,y,z;
  198. for(z=0;z<a.ZScale;z++)
  199. {
  200. for(y=0;y<a.YScale;y++)
  201. {
  202. for(x=0;x<a.XScale;x++)
  203. {
  204. if(b.IsSolid(x,y,z))
  205. a.SetVoxel(x,y,z,0x00);
  206. }
  207. }
  208. }
  209. return a;
  210. }
  211. public void Save(string RegionName)
  212. {
  213. SaveToFile("terrain/"+RegionName+".osvox");
  214. }
  215. public void Load(string RegionName)
  216. {
  217. if(!File.Exists("terrain/"+RegionName+".osvox"))
  218. throw new IOException("File not found.");
  219. LoadFromFile("terrain/"+RegionName+".osvox");
  220. }
  221. public double GetHeightAt(int x,int y)
  222. {
  223. double h=0;
  224. for(int z=0;z<ZScale;z++)
  225. {
  226. if(IsSolid(x,y,z))
  227. h=Math.Max(h,z);
  228. }
  229. return h;
  230. }
  231. /// <summary>
  232. /// For the physics subsystem (DEPRECIATED) and mapping.
  233. /// </summary>
  234. /// <returns>
  235. /// A <see cref="System.Single[]"/>
  236. /// </returns>
  237. [Obsolete("Switch to marching tetras")]
  238. public float[] GetFloatsSerialised()
  239. {
  240. /* Basically, get the highest point on each column. */
  241. List<float> sf = new List<float>();
  242. for(int x=0;x<XScale;x++)
  243. {
  244. for(int y=0;y<YScale;y++)
  245. {
  246. float ch = 0;
  247. ch=(float)GetHeightAt(x,y);
  248. sf.Add(ch);
  249. }
  250. }
  251. return sf.ToArray();
  252. }
  253. public void Generate(string method,long seed,long X, long Y)
  254. {
  255. Generate(method,seed,X,Y,new object[]{});
  256. }
  257. public void Generate(string method,long seed,long X, long Y,object[] args)
  258. {
  259. if (!Directory.Exists("terrain"))
  260. Directory.CreateDirectory("terrain");
  261. IVoxelChannel vc = MakeCopy();
  262. if (TerrainGenerators.ContainsKey(method))
  263. {
  264. TerrainGenerators[method].Initialize(mMaterials, seed);
  265. TerrainGenerators[method].Generate(ref vc,X,Y);
  266. Voxels = (vc as VoxelChannel).Voxels;
  267. }
  268. else
  269. {
  270. Console.WriteLine("[TERRAGEN] Terrain generation module \"{0}\" not installed.", method);
  271. return;
  272. }
  273. Image image = new Bitmap(XScale,YScale);
  274. double[,] hm = GetDoubles();
  275. for(int x=0;x<XScale;x++)
  276. {
  277. for(int y=0;y<YScale;y++)
  278. {
  279. int c = (int)(255.0d*(hm[x,y]/256d));
  280. (image as Bitmap).SetPixel(x,255-y,Color.FromArgb(c,c,c));
  281. }
  282. }
  283. image.Save("terrain/GEN.png",System.Drawing.Imaging.ImageFormat.Png);
  284. image.Dispose();
  285. AnimatedGifEncoder e = new AnimatedGifEncoder();
  286. e.Start( "terrain/SLICE.gif" );
  287. e.SetDelay(250);
  288. //-1:no repeat,0:always repeat
  289. e.SetRepeat(0);
  290. for(int x=0;x<XScale;x++)
  291. {
  292. image = new Bitmap(YScale,ZScale);
  293. for(int y=0;y<YScale;y++)
  294. {
  295. //Console.WriteLine();
  296. for(int z=0;z<ZScale;z++)
  297. {
  298. if(IsSolid(x,y,z))
  299. (image as Bitmap).SetPixel(y,ZScale-z-1,Color.FromArgb(255,255,255));
  300. else
  301. (image as Bitmap).SetPixel(y,ZScale-z-1,Color.FromArgb(000,000,000));
  302. }
  303. }
  304. Console.CursorLeft=0;
  305. Console.Write(" * {0}% ({1}/{2}) frames added...",(int)(((float)(x+1)/((float)XScale))*100f),x+1,XScale);
  306. e.AddFrame((Image)image.Clone());
  307. image.Dispose();
  308. }
  309. Console.WriteLine();
  310. e.Finish();
  311. }
  312. public double[,] GetDoubles()
  313. {
  314. return GetDoubles(false);
  315. }
  316. public void ForEachVoxel(Action<byte,int,int,int> a)
  317. {
  318. for(int x=0;x<XScale;x++)
  319. {
  320. for(int y=0;y<YScale;y++)
  321. {
  322. for(int z=0;z<ZScale;z++)
  323. {
  324. a(GetVoxel(x,y,z),x,y,z);
  325. }
  326. }
  327. }
  328. }
  329. public double[,] GetDoubles(bool lowest)
  330. {
  331. double[,] o = new double[XScale,YScale];
  332. for(int x=0;x<XScale;x++)
  333. {
  334. for(int y=0;y<YScale;y++)
  335. {
  336. o[x,y]=0;
  337. for(int z=0;z<ZScale;z++)
  338. {
  339. if(IsSolid(x,y,z))
  340. {
  341. if(o[x,y]<(double)z)
  342. {
  343. o[x,y]=(double)z;
  344. }
  345. } else {
  346. if(lowest) break;
  347. }
  348. }
  349. }
  350. }
  351. return o;
  352. }
  353. // For finding stuck avs/objects
  354. public bool IsInsideTerrain(Vector3 pos)
  355. {
  356. return (IsSolid((int)pos.X,(int)pos.Y,(int)pos.Z));
  357. }
  358. // For fixing stuck avs/objects.
  359. public Vector3 FindNearestAirVoxel(Vector3 subject, bool ForAvatar)
  360. {
  361. Vector3 nearest = new Vector3(0,0,0);
  362. float nd = 10000f;
  363. ForEachVoxel(delegate(byte a,int x,int y,int z){
  364. if(IsSolid(x,y,z)) return;
  365. float d = Vector3.Distance(subject,new Vector3(x,y,z));
  366. if(d<nd)
  367. {
  368. if(ForAvatar)
  369. {
  370. //Avatars need 2m vertical space instead of 1m.
  371. if(z==ZScale-1||IsSolid(x,y,z+1))
  372. return;
  373. }
  374. nd=d;
  375. nearest=new Vector3(x,y,z);
  376. }
  377. });
  378. return nearest;
  379. }
  380. public int[,,] ToMaterialMap()
  381. {
  382. int[,,] map = new int[XScale,YScale,ZScale];
  383. for(int x=0;x<XScale;x++)
  384. for(int y=0;y<YScale;y++)
  385. for(int z=0;z<ZScale;z++)
  386. map[x,y,z]=(int)GetVoxel(x,y,z);
  387. return map;
  388. }
  389. public void ImportHeightmap(float[,] heightmap)
  390. {
  391. int MX=heightmap.GetLength(0);
  392. int MY=heightmap.GetLength(1);
  393. for(int x=0;x<MX;x++)
  394. {
  395. for(int y=0;y < MY;y++)
  396. {
  397. int MZ=Convert.ToInt32(heightmap[x,y]);
  398. for(int z=0;z<MZ;z++)
  399. {
  400. SetVoxel(x,y,z,0x01);
  401. }
  402. }
  403. }
  404. }
  405. public bool[] GetBoolsSerialised()
  406. {
  407. bool[] sb = new bool[XScale*YScale*ZScale];
  408. int i = 0;
  409. for(int z=0;z<ZScale;z++)
  410. {
  411. for(int x=0;x<XScale;x++)
  412. {
  413. for(int y=0;y<YScale;y++)
  414. {
  415. sb[i]=IsSolid(x,y,z);
  416. i++;
  417. }
  418. }
  419. }
  420. return sb;
  421. }
  422. public string SaveToXmlString()
  423. {
  424. XmlWriterSettings settings = new XmlWriterSettings();
  425. settings.Encoding = Util.UTF8;
  426. using (StringWriter sw = new StringWriter())
  427. {
  428. using (XmlWriter writer = XmlWriter.Create(sw, settings))
  429. {
  430. WriteXML(writer);
  431. }
  432. string output = sw.ToString();
  433. return output;
  434. }
  435. }
  436. public byte[] ToBytes()
  437. {
  438. byte[] o = new byte[XScale*YScale*ZScale];
  439. for(int z=0;z<ZScale;z++)
  440. {
  441. for(int x=0;x<XScale;x++)
  442. {
  443. for(int y=0;y<YScale;y++)
  444. {
  445. if(Voxels==null)
  446. {
  447. Console.WriteLine("Voxels == NULL!");
  448. this[x,y,z]=0x00;
  449. }
  450. if(this[x,y,z]==null)
  451. {
  452. this[x,y,z]=0x00;
  453. }
  454. SetChunkBlock(ref o, (byte)this[x, y, z], x, y, z);
  455. }
  456. }
  457. }
  458. return o;
  459. }
  460. public void FromBytes(byte[] b)
  461. {
  462. long rfl=XScale*YScale*ZScale;
  463. if(rfl != b.Length)
  464. throw new IOException("Voxelmap is of size "+b.Length.ToString()+" when it's supposed to be "+rfl.ToString());
  465. int i = 0;
  466. for(int z=0;z<ZScale;z++)
  467. {
  468. for(int x=0;x<XScale;x++)
  469. {
  470. for(int y=0;y<YScale;y++)
  471. {
  472. this[x,y,z]=GetChunkBlock(ref b,x,y,z);
  473. }
  474. }
  475. }
  476. }
  477. private void WriteXML(XmlWriter w)
  478. {
  479. w.WriteStartElement("MaterialMap");
  480. mMaterials.Serialize(ref w);
  481. w.WriteEndElement();
  482. w.WriteStartElement("Voxels");
  483. XmlSerializer vm = new XmlSerializer(typeof(byte[]));
  484. vm.Serialize(w,ToBytes());
  485. w.WriteEndElement();
  486. }
  487. public void LoadFromFile(string file)
  488. {
  489. Console.WriteLine(file);
  490. using(NbtFile rdr = new NbtFile(file))
  491. {
  492. if(rdr.RootTag is NbtCompound)
  493. {
  494. foreach(NbtTag tag in rdr.RootTag.Tags)
  495. {
  496. switch(tag.Name)
  497. {
  498. case "MaterialTable":
  499. NbtCompound c = (NbtCompound)tag;
  500. mMaterials.FromNbt(c);
  501. break;
  502. case "Voxels":
  503. NbtByteArray vba = (NbtByteArray)tag;
  504. FromBytes(vba.Value);
  505. break;
  506. }
  507. }
  508. }
  509. }
  510. }
  511. public void SaveToFile(string file)
  512. {
  513. using(NbtFile rdr = new NbtFile())
  514. {
  515. rdr.RootTag=new NbtCompound("Region");
  516. NbtCompound cMats = new NbtCompound("VoxMaterials");
  517. rdr.RootTag.Tags.Add(mMaterials.ToNBT());
  518. rdr.RootTag.Tags.Add(new NbtByteArray("Voxels",ToBytes()));
  519. rdr.SaveFile(file);
  520. }
  521. }
  522. public void LoadFromXmlString(string data)
  523. {
  524. StringReader sr = new StringReader(data);
  525. XmlTextReader reader = new XmlTextReader(sr);
  526. reader.Read();
  527. ReadXml(reader);
  528. reader.Close();
  529. sr.Close();
  530. }
  531. private void ReadXml(XmlTextReader reader)
  532. {
  533. reader.ReadStartElement("MaterialTable");
  534. mMaterials.Deserialize(reader);
  535. reader.ReadStartElement("Voxels");
  536. VoxelsFromXml(reader);
  537. }
  538. private void VoxelsFromXml(XmlReader xmlReader)
  539. {
  540. XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
  541. byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
  542. int index = 0;
  543. for(int z=0;z<ZScale;z++)
  544. {
  545. for(int x=0;x<XScale;x++)
  546. {
  547. for(int y=0;y<YScale;y++)
  548. {
  549. this[x, y, z] = dataArray[index];
  550. index++;
  551. }
  552. }
  553. }
  554. }
  555. public byte[] GetChunk(int x, int y)
  556. {
  557. NbtFile file = new NbtFile();
  558. NbtCompound c = new NbtCompound("__ROOT__");
  559. c.Tags.Add(new NbtInt("x", x));
  560. c.Tags.Add(new NbtInt("y", y));
  561. c.Tags.Add(new NbtInt("z", 0));
  562. c.Tags.Add(new NbtByteArray("c", GetChunkData(x,y)));
  563. file.RootTag = c;
  564. byte[] endresult;
  565. using (MemoryStream ms = new MemoryStream())
  566. {
  567. file.SaveFile(ms,true);
  568. endresult= ms.ToArray();
  569. }
  570. return endresult;
  571. }
  572. //Each chunk = 64k
  573. public static readonly int CHUNK_SIZE_X = 16;
  574. public static readonly int CHUNK_SIZE_Y = 16;
  575. public static readonly int CHUNK_SIZE_Z = 256;
  576. public byte[] GetChunkData(int X, int Y, int Z=0)
  577. {
  578. byte[] d = new byte[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
  579. for(int x=0;x<CHUNK_SIZE_X;++x)
  580. {
  581. for(int y=0;y<CHUNK_SIZE_Y;++y)
  582. {
  583. for (int z = 0; z < CHUNK_SIZE_Z; ++z)
  584. {
  585. SetChunkBlock(ref d, GetVoxel(x + (X * CHUNK_SIZE_X), y + (Y * CHUNK_SIZE_Y), z), x, y, z);
  586. }
  587. }
  588. }
  589. return d;
  590. }
  591. public bool[] GetSolidsArray()
  592. {
  593. bool[] solids = new bool[Constants.RegionSize * Constants.RegionSize * Constants.RegionSize];
  594. for(int x=0;x<Constants.RegionSize;++x)
  595. {
  596. for(int y=0;y<Constants.RegionSize;++y)
  597. {
  598. for (int z = 0; z < Constants.RegionSize; ++z)
  599. {
  600. solids[y * ZScale + x * ZScale * XScale + z] = IsSolid(x, y, z);
  601. }
  602. }
  603. }
  604. return solids;
  605. }
  606. public void SetChunkBlock(ref byte[] chunk, byte type, int x, int y, int z)
  607. {
  608. chunk[y * ZScale + x * ZScale * XScale + z] = type;
  609. }
  610. public byte GetChunkBlock(ref byte[] chunk, int x, int y, int z)
  611. {
  612. return chunk[y * ZScale + x * ZScale * XScale + z];
  613. }
  614. public void SetTo(byte[, ,] b)
  615. {
  616. for (int x = 0; x < XScale; x++)
  617. for (int y = 0; y < YScale; y++)
  618. for (int z = 0; z < ZScale; z++)
  619. SetVoxel(x, y, z, b[x, y, z]);
  620. }
  621. }
  622. }