Warp3DImageModule.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  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.Drawing;
  30. using System.Drawing.Imaging;
  31. using System.IO;
  32. using System.Reflection;
  33. using System.Runtime;
  34. using CSJ2K;
  35. using Nini.Config;
  36. using log4net;
  37. using Warp3D;
  38. using Mono.Addins;
  39. using OpenSim.Framework;
  40. using OpenSim.Region.Framework.Interfaces;
  41. using OpenSim.Region.Framework.Scenes;
  42. using OpenSim.Region.PhysicsModules.SharedBase;
  43. using OpenSim.Services.Interfaces;
  44. using OpenMetaverse;
  45. using OpenMetaverse.Assets;
  46. using OpenMetaverse.Imaging;
  47. using OpenMetaverse.Rendering;
  48. using OpenMetaverse.StructuredData;
  49. using WarpRenderer = Warp3D.Warp3D;
  50. namespace OpenSim.Region.CoreModules.World.Warp3DMap
  51. {
  52. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "Warp3DImageModule")]
  53. public class Warp3DImageModule : IMapImageGenerator, INonSharedRegionModule
  54. {
  55. private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216);
  56. // private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 128);
  57. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  58. #pragma warning disable 414
  59. private static string LogHeader = "[WARP 3D IMAGE MODULE]";
  60. #pragma warning restore 414
  61. internal Scene m_scene;
  62. private IRendering m_primMesher;
  63. internal IJ2KDecoder m_imgDecoder;
  64. // caches per rendering
  65. private Dictionary<UUID, warp_Texture> m_warpTextures = new Dictionary<UUID, warp_Texture>();
  66. private Dictionary<UUID, int> m_colors = new Dictionary<UUID, int>();
  67. private IConfigSource m_config;
  68. private bool m_drawPrimVolume = true; // true if should render the prims on the tile
  69. private bool m_textureTerrain = true; // true if to create terrain splatting texture
  70. private bool m_textureAverageTerrain = false; // replace terrain textures by their average color
  71. private bool m_texturePrims = true; // true if should texture the rendered prims
  72. private float m_texturePrimSize = 48f; // size of prim before we consider texturing it
  73. private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes
  74. private const float m_cameraHeight = 4096f;
  75. private float m_renderMinHeight = -100f;
  76. private float m_renderMaxHeight = 4096f;
  77. private bool m_Enabled = false;
  78. // private Bitmap lastImage = null;
  79. private DateTime lastImageTime = DateTime.MinValue;
  80. #region Region Module interface
  81. public void Initialise(IConfigSource source)
  82. {
  83. m_config = source;
  84. string[] configSections = new string[] { "Map", "Startup" };
  85. if (Util.GetConfigVarFromSections<string>(
  86. m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule")
  87. return;
  88. m_Enabled = true;
  89. m_drawPrimVolume =
  90. Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume);
  91. m_textureTerrain =
  92. Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain);
  93. m_textureAverageTerrain =
  94. Util.GetConfigVarFromSections<bool>(m_config, "AverageTextureColorOnMapTile", configSections, m_textureAverageTerrain);
  95. if (m_textureAverageTerrain)
  96. m_textureTerrain = true;
  97. m_texturePrims =
  98. Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims);
  99. m_texturePrimSize =
  100. Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize);
  101. m_renderMeshes =
  102. Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes);
  103. m_renderMaxHeight = Util.GetConfigVarFromSections<float>(m_config, "RenderMaxHeight", configSections, m_renderMaxHeight);
  104. m_renderMinHeight = Util.GetConfigVarFromSections<float>(m_config, "RenderMinHeight", configSections, m_renderMinHeight);
  105. /*
  106. m_cameraHeight = Util.GetConfigVarFromSections<float>(m_config, "RenderCameraHeight", configSections, m_cameraHeight);
  107. if (m_cameraHeight < 250f)
  108. m_cameraHeight = 250f;
  109. else if (m_cameraHeight > 4096f)
  110. m_cameraHeight = 4096f;
  111. */
  112. if (m_renderMaxHeight < 100f)
  113. m_renderMaxHeight = 100f;
  114. else if (m_renderMaxHeight > m_cameraHeight - 10f)
  115. m_renderMaxHeight = m_cameraHeight - 10f;
  116. if (m_renderMinHeight < -100f)
  117. m_renderMinHeight = -100f;
  118. else if (m_renderMinHeight > m_renderMaxHeight - 10f)
  119. m_renderMinHeight = m_renderMaxHeight - 10f;
  120. }
  121. public void AddRegion(Scene scene)
  122. {
  123. if (!m_Enabled)
  124. return;
  125. m_scene = scene;
  126. List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
  127. if (renderers.Count > 0)
  128. m_log.Info("[MAPTILE]: Loaded prim mesher " + renderers[0]);
  129. else
  130. m_log.Info("[MAPTILE]: No prim mesher loaded, prim rendering will be disabled");
  131. m_scene.RegisterModuleInterface<IMapImageGenerator>(this);
  132. }
  133. public void RegionLoaded(Scene scene)
  134. {
  135. if (!m_Enabled)
  136. return;
  137. m_imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
  138. }
  139. public void RemoveRegion(Scene scene)
  140. {
  141. }
  142. public void Close()
  143. {
  144. }
  145. public string Name
  146. {
  147. get { return "Warp3DImageModule"; }
  148. }
  149. public Type ReplaceableInterface
  150. {
  151. get { return null; }
  152. }
  153. #endregion
  154. #region IMapImageGenerator Members
  155. private Vector3 cameraPos;
  156. private Vector3 cameraDir;
  157. private int viewWitdh = 256;
  158. private int viewHeight = 256;
  159. private float fov;
  160. private bool orto;
  161. public Bitmap CreateMapTile()
  162. {
  163. List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
  164. if (renderers.Count > 0)
  165. {
  166. m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
  167. }
  168. cameraPos = new Vector3(
  169. (m_scene.RegionInfo.RegionSizeX) * 0.5f,
  170. (m_scene.RegionInfo.RegionSizeY) * 0.5f,
  171. m_cameraHeight);
  172. cameraDir = -Vector3.UnitZ;
  173. viewWitdh = (int)m_scene.RegionInfo.RegionSizeX;
  174. viewHeight = (int)m_scene.RegionInfo.RegionSizeY;
  175. orto = true;
  176. Bitmap tile = GenImage();
  177. // image may be reloaded elsewhere, so no compression format
  178. string filename = "MAP-" + m_scene.RegionInfo.RegionID.ToString() + ".png";
  179. tile.Save(filename, ImageFormat.Png);
  180. m_primMesher = null;
  181. return tile;
  182. }
  183. public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float pfov, int width, int height, bool useTextures)
  184. {
  185. List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
  186. if (renderers.Count > 0)
  187. {
  188. m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
  189. }
  190. cameraPos = camPos;
  191. cameraDir = camDir;
  192. viewWitdh = width;
  193. viewHeight = height;
  194. fov = pfov;
  195. orto = false;
  196. Bitmap tile = GenImage();
  197. m_primMesher = null;
  198. return tile;
  199. }
  200. private Bitmap GenImage()
  201. {
  202. m_colors.Clear();
  203. m_warpTextures.Clear();
  204. WarpRenderer renderer = new WarpRenderer();
  205. if (!renderer.CreateScene(viewWitdh, viewHeight))
  206. return new Bitmap(viewWitdh, viewHeight);
  207. #region Camera
  208. warp_Vector pos = ConvertVector(cameraPos);
  209. warp_Vector lookat = warp_Vector.add(pos, ConvertVector(cameraDir));
  210. if (orto)
  211. renderer.Scene.defaultCamera.setOrthographic(true, viewWitdh, viewHeight);
  212. else
  213. renderer.Scene.defaultCamera.setFov(fov);
  214. renderer.Scene.defaultCamera.setPos(pos);
  215. renderer.Scene.defaultCamera.lookAt(lookat);
  216. #endregion Camera
  217. renderer.Scene.setAmbient(warp_Color.getColor(192, 191, 173));
  218. renderer.Scene.addLight("Light1", new warp_Light(new warp_Vector(0f, 1f, 8f), warp_Color.White, 0, 200, 20));
  219. CreateWater(renderer);
  220. CreateTerrain(renderer);
  221. if (m_drawPrimVolume)
  222. CreateAllPrims(renderer);
  223. renderer.Render();
  224. Bitmap bitmap = renderer.Scene.getImage();
  225. renderer.Scene.destroy();
  226. renderer.Reset();
  227. renderer = null;
  228. m_colors.Clear();
  229. m_warpTextures.Clear();
  230. GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
  231. GC.Collect();
  232. GC.WaitForPendingFinalizers();
  233. GC.Collect();
  234. GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.Default;
  235. return bitmap;
  236. }
  237. public byte[] WriteJpeg2000Image()
  238. {
  239. try
  240. {
  241. using (Bitmap mapbmp = CreateMapTile())
  242. return OpenJPEG.EncodeFromImage(mapbmp, false);
  243. }
  244. catch (Exception e)
  245. {
  246. // JPEG2000 encoder failed
  247. m_log.Error("[WARP 3D IMAGE MODULE]: Failed generating terrain map: ", e);
  248. }
  249. return null;
  250. }
  251. #endregion
  252. #region Rendering Methods
  253. // Add a water plane to the renderer.
  254. private void CreateWater(WarpRenderer renderer)
  255. {
  256. float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
  257. renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f, false);
  258. renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX * 0.5f,
  259. waterHeight,
  260. m_scene.RegionInfo.RegionSizeY * 0.5f);
  261. warp_Material waterMaterial = new warp_Material(ConvertColor(WATER_COLOR));
  262. renderer.Scene.addMaterial("WaterMat", waterMaterial);
  263. renderer.SetObjectMaterial("Water", "WaterMat");
  264. }
  265. // Add a terrain to the renderer.
  266. // Note that we create a 'low resolution' 257x257 vertex terrain rather than trying for
  267. // full resolution. This saves a lot of memory especially for very large regions.
  268. private void CreateTerrain(WarpRenderer renderer)
  269. {
  270. ITerrainChannel terrain = m_scene.Heightmap;
  271. float regionsx = m_scene.RegionInfo.RegionSizeX;
  272. float regionsy = m_scene.RegionInfo.RegionSizeY;
  273. // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding
  274. int bitWidth;
  275. int bitHeight;
  276. const double log2inv = 1.4426950408889634073599246810019;
  277. bitWidth = (int)Math.Ceiling((Math.Log(terrain.Width) * log2inv));
  278. bitHeight = (int)Math.Ceiling((Math.Log(terrain.Height) * log2inv));
  279. if (bitWidth > 8) // more than 256 is very heavy :(
  280. bitWidth = 8;
  281. if (bitHeight > 8)
  282. bitHeight = 8;
  283. int twidth = (int)Math.Pow(2, bitWidth);
  284. int theight = (int)Math.Pow(2, bitHeight);
  285. float diff = regionsx / twidth;
  286. int npointsx = (int)(regionsx / diff);
  287. int npointsy = (int)(regionsy / diff);
  288. float invsx = 1.0f / (npointsx * diff);
  289. float invsy = 1.0f / (npointsy * diff);
  290. npointsx++;
  291. npointsy++;
  292. // Create all the vertices for the terrain
  293. warp_Object obj = new warp_Object();
  294. warp_Vector pos;
  295. float x, y;
  296. float tv;
  297. for (y = 0; y < regionsy; y += diff)
  298. {
  299. tv = y * invsy;
  300. for (x = 0; x < regionsx; x += diff)
  301. {
  302. pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]);
  303. obj.addVertex(new warp_Vertex(pos, x * invsx, tv));
  304. }
  305. pos = ConvertVector(x, y, (float)terrain[(int)(x - diff), (int)y]);
  306. obj.addVertex(new warp_Vertex(pos, 1.0f, tv));
  307. }
  308. int lastY = (int)(y - diff);
  309. for (x = 0; x < regionsx; x += diff)
  310. {
  311. pos = ConvertVector(x, y, (float)terrain[(int)x, lastY]);
  312. obj.addVertex(new warp_Vertex(pos, x * invsx, 1.0f));
  313. }
  314. pos = ConvertVector(x, y, (float)terrain[(int)(x - diff), lastY]);
  315. obj.addVertex(new warp_Vertex(pos, 1.0f, 1.0f));
  316. // create triangles.
  317. int limx = npointsx - 1;
  318. int limy = npointsy - 1;
  319. for (int j = 0; j < limy; j++)
  320. {
  321. for (int i = 0; i < limx; i++)
  322. {
  323. int v = j * npointsx + i;
  324. // Make two triangles for each of the squares in the grid of vertices
  325. obj.addTriangle(
  326. v,
  327. v + 1,
  328. v + npointsx);
  329. obj.addTriangle(
  330. v + npointsx + 1,
  331. v + npointsx,
  332. v + 1);
  333. }
  334. }
  335. renderer.Scene.addObject("Terrain", obj);
  336. UUID[] textureIDs = new UUID[4];
  337. float[] startHeights = new float[4];
  338. float[] heightRanges = new float[4];
  339. OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
  340. textureIDs[0] = regionInfo.TerrainTexture1;
  341. textureIDs[1] = regionInfo.TerrainTexture2;
  342. textureIDs[2] = regionInfo.TerrainTexture3;
  343. textureIDs[3] = regionInfo.TerrainTexture4;
  344. startHeights[0] = (float)regionInfo.Elevation1SW;
  345. startHeights[1] = (float)regionInfo.Elevation1NW;
  346. startHeights[2] = (float)regionInfo.Elevation1SE;
  347. startHeights[3] = (float)regionInfo.Elevation1NE;
  348. heightRanges[0] = (float)regionInfo.Elevation2SW;
  349. heightRanges[1] = (float)regionInfo.Elevation2NW;
  350. heightRanges[2] = (float)regionInfo.Elevation2SE;
  351. heightRanges[3] = (float)regionInfo.Elevation2NE;
  352. warp_Texture texture;
  353. using (Bitmap image = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
  354. m_scene.RegionInfo.WorldLocX, m_scene.RegionInfo.WorldLocY,
  355. m_scene.AssetService, m_imgDecoder, m_textureTerrain, m_textureAverageTerrain,
  356. twidth, twidth))
  357. texture = new warp_Texture(image);
  358. warp_Material material = new warp_Material(texture);
  359. renderer.Scene.addMaterial("TerrainMat", material);
  360. renderer.SetObjectMaterial("Terrain", "TerrainMat");
  361. }
  362. private void CreateAllPrims(WarpRenderer renderer)
  363. {
  364. if (m_primMesher == null)
  365. return;
  366. m_scene.ForEachSOG(
  367. delegate (SceneObjectGroup group)
  368. {
  369. foreach (SceneObjectPart child in group.Parts)
  370. CreatePrim(renderer, child);
  371. }
  372. );
  373. }
  374. private void UVPlanarMap(Vertex v, Vector3 scale, out float tu, out float tv)
  375. {
  376. Vector3 scaledPos = v.Position * scale;
  377. float d = v.Normal.X;
  378. if (d >= 0.5f)
  379. {
  380. tu = 2f * scaledPos.Y;
  381. tv = scaledPos.X * v.Normal.Z - scaledPos.Z * v.Normal.X;
  382. }
  383. else if( d <= -0.5f)
  384. {
  385. tu = -2f * scaledPos.Y;
  386. tv = -scaledPos.X * v.Normal.Z + scaledPos.Z * v.Normal.X;
  387. }
  388. else if (v.Normal.Y > 0f)
  389. {
  390. tu = -2f * scaledPos.X;
  391. tv = scaledPos.Y * v.Normal.Z - scaledPos.Z * v.Normal.Y;
  392. }
  393. else
  394. {
  395. tu = 2f * scaledPos.X;
  396. tv = -scaledPos.Y * v.Normal.Z + scaledPos.Z * v.Normal.Y;
  397. }
  398. tv *= 2f;
  399. }
  400. private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim)
  401. {
  402. if ((PCode)prim.Shape.PCode != PCode.Prim)
  403. return;
  404. Vector3 ppos = prim.GetWorldPosition();
  405. if (ppos.Z < m_renderMinHeight || ppos.Z > m_renderMaxHeight)
  406. return;
  407. warp_Vector primPos = ConvertVector(ppos);
  408. warp_Quaternion primRot = ConvertQuaternion(prim.GetWorldRotation());
  409. warp_Matrix m = warp_Matrix.quaternionMatrix(primRot);
  410. float screenFactor = renderer.Scene.EstimateBoxProjectedArea(primPos, ConvertVector(prim.Scale), m);
  411. if (screenFactor < 0)
  412. return;
  413. const float log2inv = -1.442695f;
  414. int p2 = (int)((float)Math.Log(screenFactor) * log2inv * 0.25 - 1);
  415. if (p2 < 0)
  416. p2 = 0;
  417. else if (p2 > 3)
  418. p2 = 3;
  419. DetailLevel lod = (DetailLevel)(3 - p2);
  420. FacetedMesh renderMesh = null;
  421. Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
  422. if (m_renderMeshes)
  423. {
  424. if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
  425. {
  426. // Try fetchinng the asset
  427. AssetBase sculptAsset = m_scene.AssetService.Get(omvPrim.Sculpt.SculptTexture.ToString());
  428. if (sculptAsset != null)
  429. {
  430. // Is it a mesh?
  431. if (omvPrim.Sculpt.Type == SculptType.Mesh)
  432. {
  433. AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset.Data);
  434. FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, lod, out renderMesh);
  435. meshAsset = null;
  436. }
  437. else // It's sculptie
  438. {
  439. if (m_imgDecoder != null)
  440. {
  441. Image sculpt = m_imgDecoder.DecodeToImage(sculptAsset.Data);
  442. if (sculpt != null)
  443. {
  444. renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, lod);
  445. sculpt.Dispose();
  446. }
  447. }
  448. }
  449. }
  450. else
  451. {
  452. m_log.WarnFormat("[Warp3D] failed to get mesh or sculpt asset {0} of prim {1} at {2}",
  453. omvPrim.Sculpt.SculptTexture.ToString(), prim.Name, prim.GetWorldPosition().ToString());
  454. }
  455. }
  456. }
  457. // If not a mesh or sculptie, try the regular mesher
  458. if (renderMesh == null)
  459. {
  460. renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, lod);
  461. }
  462. if (renderMesh == null)
  463. return;
  464. string primID = prim.UUID.ToString();
  465. // Create the prim faces
  466. // TODO: Implement the useTextures flag behavior
  467. for (int i = 0; i < renderMesh.Faces.Count; i++)
  468. {
  469. Face face = renderMesh.Faces[i];
  470. string meshName = primID + i.ToString();
  471. // Avoid adding duplicate meshes to the scene
  472. if (renderer.Scene.objectData.ContainsKey(meshName))
  473. continue;
  474. warp_Object faceObj = new warp_Object();
  475. Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
  476. Color4 faceColor = teFace.RGBA;
  477. if (faceColor.A == 0)
  478. continue;
  479. string materialName = string.Empty;
  480. if (m_texturePrims)
  481. {
  482. // if(lod > DetailLevel.Low)
  483. {
  484. // materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, lod == DetailLevel.Low);
  485. materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, false, prim);
  486. if (String.IsNullOrEmpty(materialName))
  487. continue;
  488. int c = renderer.Scene.material(materialName).getColor();
  489. if ((c & warp_Color.MASKALPHA) == 0)
  490. continue;
  491. }
  492. }
  493. else
  494. materialName = GetOrCreateMaterial(renderer, faceColor);
  495. if (renderer.Scene.material(materialName).getTexture() == null)
  496. {
  497. // uv map details dont not matter for color;
  498. for (int j = 0; j < face.Vertices.Count; j++)
  499. {
  500. Vertex v = face.Vertices[j];
  501. warp_Vector pos = ConvertVector(v.Position);
  502. warp_Vertex vert = new warp_Vertex(pos, v.TexCoord.X, v.TexCoord.Y);
  503. faceObj.addVertex(vert);
  504. }
  505. }
  506. else
  507. {
  508. float tu;
  509. float tv;
  510. float offsetu = teFace.OffsetU + 0.5f;
  511. float offsetv = teFace.OffsetV + 0.5f;
  512. float scaleu = teFace.RepeatU;
  513. float scalev = teFace.RepeatV;
  514. float rotation = teFace.Rotation;
  515. float rc = 0;
  516. float rs = 0;
  517. if (rotation != 0)
  518. {
  519. rc = (float)Math.Cos(rotation);
  520. rs = (float)Math.Sin(rotation);
  521. }
  522. for (int j = 0; j < face.Vertices.Count; j++)
  523. {
  524. warp_Vertex vert;
  525. Vertex v = face.Vertices[j];
  526. warp_Vector pos = ConvertVector(v.Position);
  527. if(teFace.TexMapType == MappingType.Planar)
  528. UVPlanarMap(v, prim.Scale,out tu, out tv);
  529. else
  530. {
  531. tu = v.TexCoord.X - 0.5f;
  532. tv = 0.5f - v.TexCoord.Y;
  533. }
  534. if (rotation != 0)
  535. {
  536. float tur = tu * rc - tv * rs;
  537. float tvr = tu * rs + tv * rc;
  538. tur *= scaleu;
  539. tur += offsetu;
  540. tvr *= scalev;
  541. tvr += offsetv;
  542. vert = new warp_Vertex(pos, tur, tvr);
  543. }
  544. else
  545. {
  546. tu *= scaleu;
  547. tu += offsetu;
  548. tv *= scalev;
  549. tv += offsetv;
  550. vert = new warp_Vertex(pos, tu, tv);
  551. }
  552. faceObj.addVertex(vert);
  553. }
  554. }
  555. for (int j = 0; j < face.Indices.Count; j += 3)
  556. {
  557. faceObj.addTriangle(
  558. face.Indices[j + 0],
  559. face.Indices[j + 1],
  560. face.Indices[j + 2]);
  561. }
  562. faceObj.scaleSelf(prim.Scale.X, prim.Scale.Z, prim.Scale.Y);
  563. faceObj.transform(m);
  564. faceObj.setPos(primPos);
  565. renderer.Scene.addObject(meshName, faceObj);
  566. renderer.SetObjectMaterial(meshName, materialName);
  567. }
  568. }
  569. private int GetFaceColor(Primitive.TextureEntryFace face)
  570. {
  571. int color;
  572. Color4 ctmp = Color4.White;
  573. if (face.TextureID == UUID.Zero)
  574. return warp_Color.White;
  575. if (!m_colors.TryGetValue(face.TextureID, out color))
  576. {
  577. bool fetched = false;
  578. // Attempt to fetch the texture metadata
  579. string cacheName = "MAPCLR" + face.TextureID.ToString();
  580. AssetBase metadata = m_scene.AssetService.GetCached(cacheName);
  581. if (metadata != null)
  582. {
  583. OSDMap map = null;
  584. try { map = OSDParser.Deserialize(metadata.Data) as OSDMap; } catch { }
  585. if (map != null)
  586. {
  587. ctmp = map["X-RGBA"].AsColor4();
  588. fetched = true;
  589. }
  590. }
  591. if (!fetched)
  592. {
  593. // Fetch the texture, decode and get the average color,
  594. // then save it to a temporary metadata asset
  595. AssetBase textureAsset = m_scene.AssetService.Get(face.TextureID.ToString());
  596. if (textureAsset != null)
  597. {
  598. int width, height;
  599. ctmp = GetAverageColor(textureAsset.FullID, textureAsset.Data, out width, out height);
  600. OSDMap data = new OSDMap { { "X-RGBA", OSD.FromColor4(ctmp) } };
  601. metadata = new AssetBase
  602. {
  603. Data = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)),
  604. Description = "Metadata for texture color" + face.TextureID.ToString(),
  605. Flags = AssetFlags.Collectable,
  606. FullID = UUID.Zero,
  607. ID = cacheName,
  608. Local = true,
  609. Temporary = true,
  610. Name = String.Empty,
  611. Type = (sbyte)AssetType.Unknown
  612. };
  613. m_scene.AssetService.Store(metadata);
  614. }
  615. else
  616. {
  617. ctmp = new Color4(0.5f, 0.5f, 0.5f, 1.0f);
  618. }
  619. }
  620. color = ConvertColor(ctmp);
  621. m_colors[face.TextureID] = color;
  622. }
  623. return color;
  624. }
  625. private string GetOrCreateMaterial(WarpRenderer renderer, Color4 color)
  626. {
  627. string name = color.ToString();
  628. warp_Material material = renderer.Scene.material(name);
  629. if (material != null)
  630. return name;
  631. renderer.AddMaterial(name, ConvertColor(color));
  632. return name;
  633. }
  634. public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID, bool useAverageTextureColor, SceneObjectPart sop)
  635. {
  636. int color = ConvertColor(faceColor);
  637. string idstr = textureID.ToString() + color.ToString();
  638. string materialName = "MAPMAT" + idstr;
  639. if (renderer.Scene.material(materialName) != null)
  640. return materialName;
  641. warp_Material mat = new warp_Material();
  642. warp_Texture texture = GetTexture(textureID, sop);
  643. if (texture != null)
  644. {
  645. if (useAverageTextureColor)
  646. color = warp_Color.multiply(color, texture.averageColor);
  647. else
  648. mat.setTexture(texture);
  649. }
  650. else
  651. color = warp_Color.multiply(color, warp_Color.Grey);
  652. mat.setColor(color);
  653. renderer.Scene.addMaterial(materialName, mat);
  654. return materialName;
  655. }
  656. private warp_Texture GetTexture(UUID id, SceneObjectPart sop)
  657. {
  658. warp_Texture ret = null;
  659. if (id == UUID.Zero)
  660. return ret;
  661. if (m_warpTextures.TryGetValue(id, out ret))
  662. return ret;
  663. AssetBase asset = m_scene.AssetService.Get(id.ToString());
  664. if (asset != null)
  665. {
  666. try
  667. {
  668. using (Bitmap img = (Bitmap)m_imgDecoder.DecodeToImage(asset.Data))
  669. ret = new warp_Texture(img, 8); // reduce textures size to 256x256
  670. }
  671. catch (Exception e)
  672. {
  673. m_log.WarnFormat("[Warp3D]: Failed to decode texture {0} for prim {1} at {2}, exception {3}", id.ToString(), sop.Name, sop.GetWorldPosition().ToString(), e.Message);
  674. }
  675. }
  676. else
  677. m_log.WarnFormat("[Warp3D]: missing texture {0} data for prim {1} at {2}",
  678. id.ToString(), sop.Name, sop.GetWorldPosition().ToString());
  679. m_warpTextures[id] = ret;
  680. return ret;
  681. }
  682. #endregion Rendering Methods
  683. #region Static Helpers
  684. // Note: axis change.
  685. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  686. private static warp_Vector ConvertVector(float x, float y, float z)
  687. {
  688. return new warp_Vector(x, z, y);
  689. }
  690. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  691. private static warp_Vector ConvertVector(Vector3 vector)
  692. {
  693. return new warp_Vector(vector.X, vector.Z, vector.Y);
  694. }
  695. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  696. private static warp_Quaternion ConvertQuaternion(Quaternion quat)
  697. {
  698. return new warp_Quaternion(quat.X, quat.Z, quat.Y, -quat.W);
  699. }
  700. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  701. private static int ConvertColor(Color4 color)
  702. {
  703. int c = warp_Color.getColor((byte)(color.R * 255f), (byte)(color.G * 255f), (byte)(color.B * 255f), (byte)(color.A * 255f));
  704. return c;
  705. }
  706. private static Vector3 SurfaceNormal(Vector3 c1, Vector3 c2, Vector3 c3)
  707. {
  708. Vector3 edge1 = new Vector3(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
  709. Vector3 edge2 = new Vector3(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
  710. Vector3 normal = Vector3.Cross(edge1, edge2);
  711. normal.Normalize();
  712. return normal;
  713. }
  714. public Color4 GetAverageColor(UUID textureID, byte[] j2kData, out int width, out int height)
  715. {
  716. ulong r = 0;
  717. ulong g = 0;
  718. ulong b = 0;
  719. ulong a = 0;
  720. int pixelBytes;
  721. try
  722. {
  723. using (MemoryStream stream = new MemoryStream(j2kData))
  724. using (Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream))
  725. {
  726. width = bitmap.Width;
  727. height = bitmap.Height;
  728. BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
  729. pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
  730. // Sum up the individual channels
  731. unsafe
  732. {
  733. if (pixelBytes == 4)
  734. {
  735. for (int y = 0; y < height; y++)
  736. {
  737. byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
  738. for (int x = 0; x < width; x++)
  739. {
  740. b += row[x * pixelBytes + 0];
  741. g += row[x * pixelBytes + 1];
  742. r += row[x * pixelBytes + 2];
  743. a += row[x * pixelBytes + 3];
  744. }
  745. }
  746. }
  747. else
  748. {
  749. for (int y = 0; y < height; y++)
  750. {
  751. byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
  752. for (int x = 0; x < width; x++)
  753. {
  754. b += row[x * pixelBytes + 0];
  755. g += row[x * pixelBytes + 1];
  756. r += row[x * pixelBytes + 2];
  757. }
  758. }
  759. }
  760. }
  761. }
  762. // Get the averages for each channel
  763. const decimal OO_255 = 1m / 255m;
  764. decimal totalPixels = (decimal)(width * height);
  765. decimal rm = ((decimal)r / totalPixels) * OO_255;
  766. decimal gm = ((decimal)g / totalPixels) * OO_255;
  767. decimal bm = ((decimal)b / totalPixels) * OO_255;
  768. decimal am = ((decimal)a / totalPixels) * OO_255;
  769. if (pixelBytes == 3)
  770. am = 1m;
  771. return new Color4((float)rm, (float)gm, (float)bm, (float)am);
  772. }
  773. catch (Exception ex)
  774. {
  775. m_log.WarnFormat(
  776. "[WARP 3D IMAGE MODULE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}",
  777. textureID, j2kData.Length, ex.Message);
  778. width = 0;
  779. height = 0;
  780. return new Color4(0.5f, 0.5f, 0.5f, 1.0f);
  781. }
  782. }
  783. #endregion Static Helpers
  784. }
  785. public static class ImageUtils
  786. {
  787. /// <summary>
  788. /// Performs bilinear interpolation between four values
  789. /// </summary>
  790. /// <param name="v00">First, or top left value</param>
  791. /// <param name="v01">Second, or top right value</param>
  792. /// <param name="v10">Third, or bottom left value</param>
  793. /// <param name="v11">Fourth, or bottom right value</param>
  794. /// <param name="xPercent">Interpolation value on the X axis, between 0.0 and 1.0</param>
  795. /// <param name="yPercent">Interpolation value on fht Y axis, between 0.0 and 1.0</param>
  796. /// <returns>The bilinearly interpolated result</returns>
  797. public static float Bilinear(float v00, float v01, float v10, float v11, float xPercent, float yPercent)
  798. {
  799. return Utils.Lerp(Utils.Lerp(v00, v01, xPercent), Utils.Lerp(v10, v11, xPercent), yPercent);
  800. }
  801. }
  802. }