Warp3DImageModule.cs 33 KB

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