1
0

ViewerEnvironment.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  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 OpenSimulator 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. using System;
  28. using System.Collections.Generic;
  29. using System.Runtime.CompilerServices;
  30. using OpenMetaverse;
  31. using OpenMetaverse.StructuredData;
  32. namespace OpenSim.Framework
  33. {
  34. // legacy lightshare
  35. public class RegionLightShareData
  36. {
  37. public Vector3 waterColor = new(4.0f, 38.0f, 64.0f);
  38. public float waterFogDensityExponent = 4.0f;
  39. public float underwaterFogModifier = 0.25f;
  40. public Vector3 reflectionWaveletScale = new(2.0f, 2.0f, 2.0f);
  41. public float fresnelScale = 0.40f;
  42. public float fresnelOffset = 0.50f;
  43. public float refractScaleAbove = 0.03f;
  44. public float refractScaleBelow = 0.20f;
  45. public float blurMultiplier = 0.040f;
  46. public Vector2 bigWaveDirection = new(1.05f, -0.42f);
  47. public Vector2 littleWaveDirection = new(1.11f, -1.16f);
  48. public UUID normalMapTexture = new("822ded49-9a6c-f61c-cb89-6df54f42cdf4");
  49. public Vector4 horizon = new(0.25f, 0.25f, 0.32f, 0.32f);
  50. public float hazeHorizon = 0.19f;
  51. public Vector4 blueDensity = new(0.12f, 0.22f, 0.38f, 0.38f);
  52. public float hazeDensity = 0.70f;
  53. public float densityMultiplier = 0.18f;
  54. public float distanceMultiplier = 0.8f;
  55. public UInt16 maxAltitude = 1605;
  56. public Vector4 sunMoonColor = new(0.24f, 0.26f, 0.30f, 0.30f);
  57. public float sunMoonPosition = 0.317f;
  58. public Vector4 ambient = new(0.35f, 0.35f, 0.35f, 0.35f);
  59. public float eastAngle = 0.0f;
  60. public float sunGlowFocus = 0.10f;
  61. public float sunGlowSize = 1.75f;
  62. public float sceneGamma = 1.0f;
  63. public float starBrightness = 0.0f;
  64. public Vector4 cloudColor = new(0.41f, 0.41f, 0.41f, 0.41f);
  65. public Vector3 cloudXYDensity = new(1.00f, 0.53f, 1.00f);
  66. public float cloudCoverage = 0.27f;
  67. public float cloudScale = 0.42f;
  68. public Vector3 cloudDetailXYDensity = new(1.00f, 0.53f, 0.12f);
  69. public float cloudScrollX = 0.20f;
  70. public bool cloudScrollXLock = false;
  71. public float cloudScrollY = 0.01f;
  72. public bool cloudScrollYLock = false;
  73. public bool drawClassicClouds = true;
  74. }
  75. public class ViewerEnvironment
  76. {
  77. DayCycle Cycle = new();
  78. public int DayLength = 14400;
  79. public int DayOffset = 57600;
  80. public int Flags = 0;
  81. public float[] Altitudes = new float[3] {1000f, 2000f, 3000f };
  82. //DayHash;
  83. public bool IsLegacy = false;
  84. public string DayCycleName;
  85. public int version = 0;
  86. public void FromWLOSD(OSD osd)
  87. {
  88. OSDArray array = osd as OSDArray;
  89. if(osd != null)
  90. {
  91. Cycle = new DayCycle();
  92. Cycle.FromWLOSD(array);
  93. }
  94. InvalidateCaches();
  95. }
  96. public OSD ToWLOSD(UUID message, UUID region)
  97. {
  98. OSDArray array = new() { null, null, null, null };
  99. array[0] = new OSDMap { {"messageID", message }, { "regionID", region } };
  100. Cycle.ToWLOSD(ref array);
  101. return array;
  102. }
  103. private static Quaternion AzAlToRot(float az, float al)
  104. {
  105. if (Utils.ApproxEqual(al, 0, 1e-3f) || Utils.ApproxEqual(Math.Abs(al), Utils.TWO_PI, 1e-3f))
  106. {
  107. az *= 0.5f;
  108. return new Quaternion(0, 0, MathF.Sin(az), MathF.Cos(az));
  109. }
  110. if (Utils.ApproxEqual(az, 0, 1e-3f) || Utils.ApproxEqual(Math.Abs(az), Utils.TWO_PI, 1e-3f))
  111. {
  112. al *= 0.5f;
  113. return new Quaternion(0, -MathF.Sin(al), 0, MathF.Cos(al));
  114. }
  115. az *= 0.5f;
  116. float sz = MathF.Sin(az);
  117. float cz = MathF.Cos(az);
  118. al *= 0.5f;
  119. float sl = MathF.Sin(al);
  120. float cl = MathF.Cos(al);
  121. Quaternion rot = new(sl * sz, -sl * cz, cl * sz, cl * cz);
  122. rot.Normalize();
  123. return rot;
  124. }
  125. public static void convertFromAngles(SkyData sky, float sun_angle, float east_angle)
  126. {
  127. float az = -east_angle;
  128. float al = sun_angle;
  129. sky.sun_rotation = AzAlToRot(az, al);
  130. sky.moon_rotation = AzAlToRot(az, al + MathF.PI);
  131. }
  132. public static Vector3 Xrot(Quaternion rot)
  133. {
  134. rot.Normalize(); // just in case
  135. return new Vector3(2 * (rot.X * rot.X + rot.W * rot.W) - 1,
  136. 2 * (rot.X * rot.Y + rot.Z * rot.W),
  137. 2 * (rot.X * rot.Z - rot.Y * rot.W));
  138. }
  139. public static void convertToAngles(SkyData sky, out float sun_angle, out float east_angle, out Vector4 lightnorm)
  140. {
  141. Vector3 v = Xrot(sky.sun_rotation);
  142. v.Normalize();
  143. if(v.Z >= 0)
  144. lightnorm = new Vector4(v.Y, v.Z, v.X, 1);
  145. else if (v.Z > -0.12)
  146. {
  147. float m = v.Y * v.Y + v.Z * v.Z;
  148. m = 1.0f / MathF.Sqrt(m);
  149. lightnorm = new Vector4(v.Y * m, 0, v.X * m, 1);
  150. }
  151. else
  152. lightnorm = new Vector4(-v.Y, -v.Z, -v.X, 1);
  153. sun_angle = MathF.Asin(v.Z);
  154. east_angle = -MathF.Atan2(v.Y, v.X);
  155. if (MathF.Abs(east_angle) < 1e-6f)
  156. east_angle = 0;
  157. else if (east_angle < 0)
  158. east_angle = Utils.TWO_PI + east_angle;
  159. // this is just a case on one example daycyles, as wrong as any
  160. /*
  161. if (Utils.ApproxEqual(east_angle, Utils.PI, 1e-4f))
  162. {
  163. east_angle = 0;
  164. sun_angle = Utils.PI - sun_angle;
  165. }
  166. */
  167. if (MathF.Abs(sun_angle) < 1e-6f)
  168. sun_angle = 0;
  169. else if (sun_angle < 0)
  170. sun_angle = Utils.TWO_PI + sun_angle;
  171. }
  172. public void FromLightShare(RegionLightShareData ls)
  173. {
  174. WaterData water = new()
  175. {
  176. waterFogColor = ls.waterColor / 256f,
  177. waterFogDensity = MathF.Pow(2.0f, ls.waterFogDensityExponent),
  178. //water.waterFogDensity = ls.waterFogDensityExponent;
  179. underWaterFogMod = ls.underwaterFogModifier,
  180. normScale = ls.reflectionWaveletScale,
  181. fresnelScale = ls.fresnelScale,
  182. fresnelOffset = ls.fresnelOffset,
  183. scaleAbove = ls.refractScaleAbove,
  184. scaleBelow = ls.refractScaleBelow,
  185. blurMultiplier = ls.blurMultiplier,
  186. wave1Dir = ls.littleWaveDirection,
  187. wave2Dir = ls.bigWaveDirection,
  188. normalMap = ls.normalMapTexture,
  189. Name = "LightshareWater"
  190. };
  191. SkyData sky = new();
  192. convertFromAngles(sky, Utils.TWO_PI * ls.sunMoonPosition, Utils.TWO_PI * ls.eastAngle);
  193. sky.sunlight_color = ls.sunMoonColor * 3.0f;
  194. sky.ambient = new Vector3(ls.ambient.X * 3.0f, ls.ambient.Y * 3.0f, ls.ambient.Z * 3.0f);
  195. sky.blue_horizon = new Vector3(ls.horizon.X * 2.0f, ls.horizon.Y * 2.0f, ls.horizon.Z * 2.0f);
  196. sky.blue_density = new Vector3(ls.blueDensity.X * 2.0f, ls.blueDensity.Y * 2.0f, ls.blueDensity.Z * 2.0f);
  197. sky.haze_horizon = ls.hazeHorizon;
  198. sky.haze_density = ls.hazeDensity;
  199. sky.cloud_shadow = ls.cloudCoverage;
  200. sky.density_multiplier = ls.densityMultiplier / 1000.0f;
  201. sky.distance_multiplier = ls.distanceMultiplier;
  202. sky.max_y = ls.maxAltitude;
  203. sky.cloud_color = new Vector3(ls.cloudColor.X, ls.cloudColor.Y, ls.cloudColor.Z);
  204. sky.cloud_pos_density1 = ls.cloudXYDensity;
  205. sky.cloud_pos_density2 = ls.cloudDetailXYDensity;
  206. sky.cloud_scale = ls.cloudScale;
  207. sky.gamma=ls.sceneGamma;
  208. sky.glow = new Vector3((2f - ls.sunGlowSize) * 20f, 0f, -ls.sunGlowFocus * 5f);
  209. sky.cloud_scroll_rate = new Vector2(ls.cloudScrollX, ls.cloudScrollY);
  210. if (ls.cloudScrollXLock)
  211. sky.cloud_scroll_rate.X = 0;
  212. if (ls.cloudScrollYLock)
  213. sky.cloud_scroll_rate.Y = 0;
  214. sky.star_brightness = ls.starBrightness * 250f;
  215. sky.Name = "LightshareSky";
  216. Cycle = new DayCycle { Name = "Lightshare" };
  217. Cycle.waterframes.Add(water.Name, water);
  218. DayCycle.TrackEntry track = new(-1, water.Name);
  219. Cycle.waterTrack.Add(track);
  220. Cycle.skyframes.Add(sky.Name, sky);
  221. track = new(-1, sky.Name);
  222. Cycle.skyTrack0.Add(track);
  223. InvalidateCaches();
  224. }
  225. public RegionLightShareData ToLightShare()
  226. {
  227. RegionLightShareData ls = new();
  228. DayCycle.TrackEntry te;
  229. if (Cycle.waterTrack.Count > 0)
  230. {
  231. te = Cycle.waterTrack[0];
  232. if (Cycle.waterframes.TryGetValue(te.frameName, out WaterData water))
  233. {
  234. ls.waterColor = water.waterFogColor * 256f;
  235. ls.waterFogDensityExponent = MathF.Sqrt(water.waterFogDensity);
  236. //ls.waterFogDensityExponent = water.waterFogDensity;
  237. ls.underwaterFogModifier = water.underWaterFogMod;
  238. ls.reflectionWaveletScale = water.normScale;
  239. ls.fresnelScale = water.fresnelScale;
  240. ls.fresnelOffset = water.fresnelOffset;
  241. ls.refractScaleAbove = water.scaleAbove;
  242. ls.refractScaleBelow = water.scaleBelow;
  243. ls.blurMultiplier = water.blurMultiplier;
  244. ls.littleWaveDirection = water.wave1Dir;
  245. ls.bigWaveDirection = water.wave2Dir;
  246. ls.normalMapTexture = water.normalMap;
  247. }
  248. }
  249. if (Cycle.skyTrack0.Count > 0)
  250. {
  251. te = Cycle.skyTrack0[0];
  252. if (Cycle.skyframes.TryGetValue(te.frameName, out SkyData sky))
  253. {
  254. convertToAngles(sky, out ls.sunMoonPosition, out ls.eastAngle, out Vector4 _);
  255. ls.sunMoonPosition *= 0.5f / MathF.PI;
  256. ls.eastAngle *= 0.5f / MathF.PI;
  257. ls.sunMoonColor = sky.sunlight_color / 3f;
  258. ls.ambient = new Vector4(sky.ambient.X / 3.0f, sky.ambient.Y / 3.0f, sky.ambient.Z / 3.0f, 1);
  259. ls.horizon = new Vector4(sky.blue_horizon.X / 2.0f, sky.blue_horizon.Y / 2.0f, sky.blue_horizon.Z / 2.0f, 1);
  260. ls.blueDensity = new Vector4(sky.blue_density.X / 2.0f, sky.blue_density.Y / 2.0f, sky.blue_density.Z / 2.0f, 1);
  261. ls.hazeHorizon = sky.haze_horizon;
  262. ls.hazeDensity = sky.haze_density;
  263. ls.cloudCoverage = sky.cloud_shadow;
  264. ls.densityMultiplier = 1000f * sky.density_multiplier;
  265. ls.distanceMultiplier = sky.distance_multiplier;
  266. ls.maxAltitude = (ushort)sky.max_y;
  267. ls.cloudColor = new Vector4(sky.cloud_color.X, sky.cloud_color.Y, sky.cloud_color.Z, 1);
  268. ls.cloudXYDensity = sky.cloud_pos_density1;
  269. ls.cloudDetailXYDensity = sky.cloud_pos_density2;
  270. ls.cloudScale = sky.cloud_scale;
  271. ls.sceneGamma = sky.gamma;
  272. ls.sunGlowSize = (2f - sky.glow.X) / 20f;
  273. ls.sunGlowFocus = -sky.glow.Z / 5f;
  274. ls.cloudScrollX = sky.cloud_scroll_rate.X;
  275. ls.cloudScrollY = sky.cloud_scroll_rate.Y;
  276. ls.cloudScrollXLock = ls.cloudScrollX == 0f;
  277. ls.cloudScrollYLock = ls.cloudScrollY == 0f;
  278. ls.starBrightness = sky.star_brightness / 250f;
  279. }
  280. }
  281. return ls;
  282. }
  283. public void FromOSD(OSD osd)
  284. {
  285. if (osd is not OSDMap map)
  286. return;
  287. OSD otmp;
  288. if (map.TryGetValue("day_cycle", out otmp) && otmp is OSDMap)
  289. {
  290. Cycle = new DayCycle();
  291. Cycle.FromOSD(otmp as OSDMap);
  292. }
  293. Cycle ??= new DayCycle();
  294. if (map.TryGetValue("day_length", out otmp))
  295. DayLength = otmp;
  296. if (map.TryGetValue("day_offset", out otmp))
  297. DayOffset = otmp;
  298. if (map.TryGetValue("flags", out otmp))
  299. Flags = otmp;
  300. if (map.TryGetValue("env_version", out otmp))
  301. version = otmp;
  302. else
  303. ++version;
  304. if (map.TryGetValue("track_altitudes", out otmp) && otmp is OSDArray)
  305. {
  306. OSDArray alt = otmp as OSDArray;
  307. for(int i = 0; i < alt.Count && i < 3; ++i)
  308. Altitudes[i] = alt[i];
  309. SortAltitudes();
  310. }
  311. IsLegacy = false;
  312. InvalidateCaches();
  313. }
  314. public void SortAltitudes()
  315. {
  316. for (int i = 0; i < 2; ++i)
  317. {
  318. float h = Altitudes[i];
  319. for (int j = i + 1; j < 3; ++j)
  320. {
  321. if (h > Altitudes[j])
  322. {
  323. Altitudes[i] = Altitudes[j];
  324. Altitudes[j] = h;
  325. List<DayCycle.TrackEntry> tet = Cycle.skyTracks[i];
  326. Cycle.skyTracks[i] = Cycle.skyTracks[j];
  327. Cycle.skyTracks[j] = tet;
  328. h = Altitudes[i];
  329. }
  330. }
  331. }
  332. }
  333. public bool CycleFromOSD(OSD osd)
  334. {
  335. if (osd is not OSDMap map)
  336. return false;
  337. if (!map.TryGetValue("type", out OSD tmp))
  338. return false;
  339. string type = tmp.AsString();
  340. if (type != "daycycle")
  341. return false;
  342. Cycle = new DayCycle();
  343. Cycle.FromOSD(map);
  344. InvalidateCaches();
  345. return true;
  346. }
  347. public bool FromAssetOSD(string name, OSD osd)
  348. {
  349. if (osd is not OSDMap map)
  350. return false;
  351. if (!map.TryGetValue("type", out OSD tmp))
  352. return false;
  353. string type = tmp.AsString();
  354. bool ok = false;
  355. if (type == "water")
  356. {
  357. Cycle ??= new DayCycle();
  358. ok = Cycle.replaceWaterFromOSD(name, map);
  359. }
  360. else
  361. {
  362. if (type == "daycycle")
  363. {
  364. Cycle = new DayCycle();
  365. Cycle.FromOSD(map);
  366. ok = true;
  367. }
  368. else if(type == "sky")
  369. {
  370. Cycle ??= new DayCycle();
  371. ok = Cycle.replaceSkyFromOSD(name, map);
  372. }
  373. }
  374. if(ok && !string.IsNullOrWhiteSpace(name))
  375. Cycle.Name = name;
  376. InvalidateCaches();
  377. return ok;
  378. }
  379. public OSD ToOSD()
  380. {
  381. return new OSDMap
  382. {
  383. ["day_cycle"] = Cycle.ToOSD(),
  384. ["day_length"] = DayLength,
  385. ["day_offset"] = DayOffset,
  386. ["flags"] = Flags,
  387. ["env_version"] = version,
  388. ["track_altitudes"] = new OSDArray() { Altitudes[0], Altitudes[1], Altitudes[2] }
  389. };
  390. }
  391. public readonly object m_cachedbytesLock = new();
  392. public byte[] m_cachedbytes = null;
  393. public byte[] m_cachedWLbytes = null;
  394. public void InvalidateCaches()
  395. {
  396. lock (m_cachedbytesLock)
  397. {
  398. m_cachedbytes = null;
  399. m_cachedWLbytes = null;
  400. }
  401. }
  402. public byte[] ToCapBytes(UUID regionID, int parcelID)
  403. {
  404. //byte[] ret = m_cachedbytes;
  405. //if(ret != null)
  406. // return ret;
  407. lock (m_cachedbytesLock)
  408. {
  409. byte[] ret = m_cachedbytes;
  410. if (ret == null)
  411. {
  412. OSDMap map = new();
  413. OSDMap cenv = (OSDMap)ToOSD();
  414. cenv["parcel_id"] = parcelID;
  415. cenv["region_id"] = regionID;
  416. map["environment"] = cenv;
  417. map["parcel_id"] = parcelID;
  418. map["success"] = true;
  419. ret = OSDParser.SerializeLLSDXmlToBytes(map);
  420. m_cachedbytes = ret;
  421. }
  422. return ret;
  423. }
  424. }
  425. public byte[] ToCapWLBytes(UUID messageID, UUID regionID)
  426. {
  427. //byte[] ret = m_cachedWLbytes;
  428. //if (ret != null)
  429. // return ret;
  430. lock (m_cachedbytesLock)
  431. {
  432. byte[] ret = m_cachedWLbytes;
  433. if (ret == null)
  434. {
  435. OSD d = ToWLOSD(messageID, regionID);
  436. ret = OSDParser.SerializeLLSDXmlToBytes(d);
  437. m_cachedWLbytes = ret;
  438. }
  439. return ret;
  440. }
  441. }
  442. public static ViewerEnvironment FromOSDString(string s)
  443. {
  444. try
  445. {
  446. OSD eosd = OSDParser.Deserialize(s);
  447. ViewerEnvironment VEnv = new();
  448. VEnv.FromOSD(eosd);
  449. return VEnv;
  450. }
  451. catch
  452. {
  453. }
  454. return null;
  455. }
  456. public static string ToOSDString(ViewerEnvironment VEnv, bool xml = false)
  457. {
  458. try
  459. {
  460. OSD eosd= VEnv.ToOSD();
  461. if(xml)
  462. return OSDParser.SerializeLLSDXmlString(eosd);
  463. else
  464. return OSDParser.SerializeLLSDNotationFull(eosd);
  465. }
  466. catch {}
  467. return String.Empty;
  468. }
  469. public ViewerEnvironment Clone()
  470. {
  471. // im lazy need to proper clone later
  472. OSD osd = ToOSD();
  473. ViewerEnvironment VEnv = new();
  474. VEnv.FromOSD(osd);
  475. return VEnv;
  476. }
  477. public static OSD DefaultToOSD(UUID regionID, int parcel)
  478. {
  479. OSDMap env = new()
  480. {
  481. ["is_default"] = true,
  482. ["region_id"] = regionID,
  483. ["track_altitudes"] = new OSDArray() { 1000f, 2000f, 3000f }
  484. };
  485. if (parcel >= 0)
  486. env["parcel_id"] = parcel;
  487. OSDMap top = new()
  488. {
  489. ["environment"] = env,
  490. ["success"] = true
  491. };
  492. if (parcel >= 0)
  493. top["parcel_id"] = parcel;
  494. return top;
  495. }
  496. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  497. public List<DayCycle.TrackEntry> FindTrack(float altitude)
  498. {
  499. if (altitude < Altitudes[0])
  500. return Cycle.skyTrack0;
  501. int altindx = 1;
  502. for (; altindx < Altitudes.Length; ++altindx)
  503. {
  504. if (Altitudes[altindx] > altitude)
  505. break;
  506. }
  507. List<DayCycle.TrackEntry> track = null;
  508. while (--altindx >= 0)
  509. {
  510. track = Cycle.skyTracks[altindx];
  511. if (track != null && track.Count > 0)
  512. break;
  513. }
  514. return track;
  515. }
  516. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  517. public bool FindSkies(List<DayCycle.TrackEntry> track, float dayfrac, out float skyfrac, out SkyData sky1, out SkyData sky2)
  518. {
  519. sky1 = null;
  520. sky2 = null;
  521. skyfrac = dayfrac;
  522. if (track.Count == 1 || track[0].time < 0)
  523. {
  524. if (!Cycle.skyframes.TryGetValue(track[0].frameName, out sky1) || sky1 == null)
  525. return false;
  526. return true;
  527. }
  528. int i = 0;
  529. while (i < track.Count)
  530. {
  531. if (track[i].time > dayfrac)
  532. break;
  533. ++i;
  534. }
  535. float firstFrac;
  536. float secondFrac;
  537. string first;
  538. string second;
  539. int ntracks = track.Count;
  540. if (i == 0 || i == ntracks)
  541. {
  542. --ntracks;
  543. firstFrac = track[ntracks].time;
  544. first = track[ntracks].frameName;
  545. secondFrac = track[0].time + 1f;
  546. second = track[0].frameName;
  547. }
  548. else
  549. {
  550. secondFrac = track[i].time;
  551. second = track[i].frameName;
  552. --i;
  553. firstFrac = track[i].time;
  554. first = track[i].frameName;
  555. }
  556. if (!Cycle.skyframes.TryGetValue(first, out sky1) || sky1 == null)
  557. firstFrac = -1;
  558. if (!Cycle.skyframes.TryGetValue(second, out sky2) || sky2 == null)
  559. secondFrac = -1;
  560. if (firstFrac < 0)
  561. {
  562. if (secondFrac < 0)
  563. return false;
  564. sky1 = sky2;
  565. sky2 = null;
  566. return true;
  567. }
  568. if (secondFrac < 0 || secondFrac == firstFrac)
  569. {
  570. sky2 = null;
  571. return true;
  572. }
  573. dayfrac -= firstFrac;
  574. secondFrac -= firstFrac;
  575. dayfrac /= secondFrac;
  576. skyfrac = Utils.Clamp(dayfrac, 0, 1f);
  577. return true;
  578. }
  579. public bool getPositions(float altitude, float dayfrac, out Vector3 sundir, out Vector3 moondir,
  580. out Quaternion sunrot, out Quaternion moonrot)
  581. {
  582. sundir = Vector3.Zero;
  583. moondir = Vector3.Zero;
  584. sunrot = Quaternion.Identity;
  585. moonrot = Quaternion.Identity;
  586. List<DayCycle.TrackEntry> track = FindTrack(altitude);
  587. if (track is null || track.Count == 0)
  588. return false;
  589. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  590. return false;
  591. if (sky2 is null)
  592. {
  593. moonrot = sky1.moon_rotation;
  594. moondir = Xrot(moonrot);
  595. sunrot = sky1.sun_rotation;
  596. sundir = Xrot(sunrot);
  597. return true;
  598. }
  599. moonrot = Quaternion.Slerp(sky1.moon_rotation, sky2.moon_rotation, dayfrac);
  600. moondir = Xrot(moonrot);
  601. sunrot = Quaternion.Slerp(sky1.sun_rotation, sky2.sun_rotation, dayfrac);
  602. sundir = Xrot(sunrot);
  603. return true;
  604. }
  605. public bool getPositions_sundir(float altitude, float dayfrac, out Vector3 sundir)
  606. {
  607. sundir = Vector3.Zero;
  608. List<DayCycle.TrackEntry> track = FindTrack(altitude);
  609. if (track is null || track.Count == 0)
  610. return false;
  611. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  612. return false;
  613. if (sky2 is null)
  614. {
  615. sundir = Xrot(sky1.sun_rotation);
  616. return true;
  617. }
  618. Quaternion sunrot = Quaternion.Slerp(sky1.sun_rotation, sky2.sun_rotation, dayfrac);
  619. sundir = Xrot(sunrot);
  620. return true;
  621. }
  622. public bool getPositions_sunrot(float altitude, float dayfrac, out Quaternion sunrot)
  623. {
  624. sunrot = Quaternion.Identity;
  625. List<DayCycle.TrackEntry> track = FindTrack(altitude);
  626. if (track is null || track.Count == 0)
  627. return false;
  628. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  629. return false;
  630. if (sky2 is null)
  631. {
  632. sunrot = sky1.sun_rotation;
  633. return true;
  634. }
  635. sunrot = Quaternion.Slerp(sky1.sun_rotation, sky2.sun_rotation, dayfrac);
  636. return true;
  637. }
  638. public bool getPositions_moondir(float altitude, float dayfrac, out Vector3 moondir)
  639. {
  640. moondir = Vector3.Zero;
  641. List<DayCycle.TrackEntry> track = FindTrack(altitude);
  642. if (track is null || track.Count == 0)
  643. return false;
  644. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  645. return false;
  646. if (sky2 is null)
  647. {
  648. moondir = Xrot(sky1.moon_rotation);
  649. return true;
  650. }
  651. Quaternion moonrot = Quaternion.Slerp(sky1.moon_rotation, sky2.moon_rotation, dayfrac);
  652. moondir = Xrot(moonrot);
  653. return true;
  654. }
  655. public bool getPositions_moonrot(float altitude, float dayfrac, out Quaternion moonrot)
  656. {
  657. moonrot = Quaternion.Identity;
  658. List<DayCycle.TrackEntry> track = FindTrack(altitude);
  659. if (track is null || track.Count == 0)
  660. return false;
  661. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  662. return false;
  663. if (sky2 is null)
  664. {
  665. moonrot = sky1.moon_rotation;
  666. return true;
  667. }
  668. moonrot = Quaternion.Slerp(sky1.moon_rotation, sky2.moon_rotation, dayfrac);
  669. return true;
  670. }
  671. /* not needed for wl viewers
  672. public bool getWLPositions(float altitude, float dayfrac, out Vector3 sundir)
  673. {
  674. sundir = Vector3.Zero;
  675. List<DayCycle.TrackEntry> track = track = FindTrack(altitude);
  676. if (track == null || track.Count == 0)
  677. return false;
  678. if (!FindSkies(track, dayfrac, out dayfrac, out SkyData sky1, out SkyData sky2))
  679. return false;
  680. Quaternion sunrot;
  681. if (sky2 == null)
  682. {
  683. sunrot = sky1.sun_rotation;
  684. sundir = Xrot(sunrot);
  685. return true;
  686. }
  687. sunrot = Quaternion.Slerp(sky1.sun_rotation, sky2.sun_rotation, dayfrac);
  688. sundir = Xrot(sunrot);
  689. return true;
  690. }
  691. */
  692. public void GatherAssets(Dictionary<UUID, sbyte> uuids)
  693. {
  694. Cycle?.GatherAssets(uuids);
  695. }
  696. }
  697. }