Warp3DImageModule.cs 36 KB

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