PageRenderTime 82ms CodeModel.GetById 59ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llviewerparceloverlay.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 996 lines | 739 code | 155 blank | 102 comment | 93 complexity | ddc109ba6019e16abee4ec2382c5426e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewerparceloverlay.cpp
  3. * @brief LLViewerParcelOverlay class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llviewerparceloverlay.h"
  28. // indra includes
  29. #include "llparcel.h"
  30. #include "llfloaterreg.h"
  31. #include "llgl.h"
  32. #include "llrender.h"
  33. #include "v4color.h"
  34. #include "v2math.h"
  35. // newview includes
  36. #include "llagentcamera.h"
  37. #include "llviewertexture.h"
  38. #include "llviewercontrol.h"
  39. #include "llsurface.h"
  40. #include "llviewerregion.h"
  41. #include "llviewercamera.h"
  42. #include "llviewertexturelist.h"
  43. #include "llselectmgr.h"
  44. #include "llfloatertools.h"
  45. #include "llglheaders.h"
  46. #include "pipeline.h"
  47. const U8 OVERLAY_IMG_COMPONENTS = 4;
  48. LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters)
  49. : mRegion( region ),
  50. mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ),
  51. mDirty( FALSE ),
  52. mTimeSinceLastUpdate(),
  53. mOverlayTextureIdx(-1),
  54. mVertexCount(0),
  55. mVertexArray(NULL),
  56. mColorArray(NULL)
  57. // mTexCoordArray(NULL),
  58. {
  59. // Create a texture to hold color information.
  60. // 4 components
  61. // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges
  62. mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS);
  63. mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), FALSE);
  64. mTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
  65. mTexture->setFilteringOption(LLTexUnit::TFO_POINT);
  66. //
  67. // Initialize the GL texture with empty data.
  68. //
  69. // Create the base texture.
  70. U8 *raw = mImageRaw->getData();
  71. const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS;
  72. for (S32 i = 0; i < COUNT; i++)
  73. {
  74. raw[i] = 0;
  75. }
  76. //mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
  77. // Create storage for ownership information from simulator
  78. // and initialize it.
  79. mOwnership = new U8[ mParcelGridsPerEdge * mParcelGridsPerEdge ];
  80. for (S32 i = 0; i < mParcelGridsPerEdge * mParcelGridsPerEdge; i++)
  81. {
  82. mOwnership[i] = PARCEL_PUBLIC;
  83. }
  84. gPipeline.markGLRebuild(this);
  85. }
  86. LLViewerParcelOverlay::~LLViewerParcelOverlay()
  87. {
  88. delete[] mOwnership;
  89. mOwnership = NULL;
  90. delete[] mVertexArray;
  91. mVertexArray = NULL;
  92. delete[] mColorArray;
  93. mColorArray = NULL;
  94. // JC No textures.
  95. // delete mTexCoordArray;
  96. // mTexCoordArray = NULL;
  97. mImageRaw = NULL;
  98. }
  99. //---------------------------------------------------------------------------
  100. // ACCESSORS
  101. //---------------------------------------------------------------------------
  102. BOOL LLViewerParcelOverlay::isOwned(const LLVector3& pos) const
  103. {
  104. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  105. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  106. return (PARCEL_PUBLIC != ownership(row, column));
  107. }
  108. BOOL LLViewerParcelOverlay::isOwnedSelf(const LLVector3& pos) const
  109. {
  110. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  111. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  112. return (PARCEL_SELF == ownership(row, column));
  113. }
  114. BOOL LLViewerParcelOverlay::isOwnedGroup(const LLVector3& pos) const
  115. {
  116. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  117. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  118. return (PARCEL_GROUP == ownership(row, column));
  119. }
  120. BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const
  121. {
  122. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  123. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  124. U8 overlay = ownership(row, column);
  125. return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay);
  126. }
  127. bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) const
  128. {
  129. // boxes are expected to already be axis aligned
  130. for (U32 i = 0; i < boxes.size(); ++i)
  131. {
  132. LLVector3 min = boxes[i].getMinAgent();
  133. LLVector3 max = boxes[i].getMaxAgent();
  134. S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  135. S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  136. S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  137. S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  138. for (S32 row = top; row <= bottom; row++)
  139. {
  140. for (S32 column = left; column <= right; column++)
  141. {
  142. U8 type = ownership(row, column);
  143. if ((PARCEL_SELF == type)
  144. || (PARCEL_GROUP == type))
  145. {
  146. return true;
  147. }
  148. }
  149. }
  150. }
  151. return false;
  152. }
  153. bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes) const
  154. {
  155. // boxes are expected to already be axis aligned
  156. for (U32 i = 0; i < boxes.size(); ++i)
  157. {
  158. LLVector3 min = boxes[i].getMinAgent();
  159. LLVector3 max = boxes[i].getMaxAgent();
  160. S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  161. S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  162. S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  163. S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  164. for (S32 row = top; row <= bottom; row++)
  165. {
  166. for (S32 column = left; column <= right; column++)
  167. {
  168. U8 type = ownership(row, column);
  169. if ((PARCEL_SELF != type))
  170. {
  171. return true;
  172. }
  173. }
  174. }
  175. }
  176. return false;
  177. }
  178. bool LLViewerParcelOverlay::encroachesOnNearbyParcel(const std::vector<LLBBox>& boxes) const
  179. {
  180. // boxes are expected to already be axis aligned
  181. for (U32 i = 0; i < boxes.size(); ++i)
  182. {
  183. LLVector3 min = boxes[i].getMinAgent();
  184. LLVector3 max = boxes[i].getMaxAgent();
  185. // If an object crosses region borders it crosses a parcel
  186. if ( min.mV[VX] < 0
  187. || min.mV[VY] < 0
  188. || max.mV[VX] > REGION_WIDTH_METERS
  189. || max.mV[VY] > REGION_WIDTH_METERS)
  190. {
  191. return true;
  192. }
  193. S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  194. S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  195. S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  196. S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
  197. const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
  198. for (S32 row = bottom; row <= top; row++)
  199. {
  200. for (S32 col = left; col <= right; col++)
  201. {
  202. // This is not the rightmost column
  203. if (col < GRIDS_PER_EDGE-1)
  204. {
  205. U8 east_overlay = mOwnership[row*GRIDS_PER_EDGE+col+1];
  206. // If the column to the east of the current one marks
  207. // the other parcel's west edge and the box extends
  208. // to the west it crosses the parcel border.
  209. if ((east_overlay & PARCEL_WEST_LINE) && col < right)
  210. {
  211. return true;
  212. }
  213. }
  214. // This is not the topmost column
  215. if (row < GRIDS_PER_EDGE-1)
  216. {
  217. U8 north_overlay = mOwnership[(row+1)*GRIDS_PER_EDGE+col];
  218. // If the row to the north of the current one marks
  219. // the other parcel's south edge and the box extends
  220. // to the south it crosses the parcel border.
  221. if ((north_overlay & PARCEL_SOUTH_LINE) && row < top)
  222. {
  223. return true;
  224. }
  225. }
  226. }
  227. }
  228. }
  229. return false;
  230. }
  231. BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
  232. {
  233. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  234. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  235. return PARCEL_SOUND_LOCAL & mOwnership[row * mParcelGridsPerEdge + column];
  236. }
  237. U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
  238. {
  239. S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
  240. S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
  241. return ownership(row, column);
  242. }
  243. F32 LLViewerParcelOverlay::getOwnedRatio() const
  244. {
  245. S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
  246. S32 total = 0;
  247. for (S32 i = 0; i < size; i++)
  248. {
  249. if ((mOwnership[i] & PARCEL_COLOR_MASK) != PARCEL_PUBLIC)
  250. {
  251. total++;
  252. }
  253. }
  254. return (F32)total / (F32)size;
  255. }
  256. //---------------------------------------------------------------------------
  257. // MANIPULATORS
  258. //---------------------------------------------------------------------------
  259. // Color tables for owned land
  260. // Available = index 0
  261. // Other = index 1
  262. // Group = index 2
  263. // Self = index 3
  264. // Make sure the texture colors match the ownership data.
  265. // Note: Assumes that the ownership array and
  266. void LLViewerParcelOverlay::updateOverlayTexture()
  267. {
  268. if (mOverlayTextureIdx < 0 && mDirty)
  269. {
  270. mOverlayTextureIdx = 0;
  271. }
  272. if (mOverlayTextureIdx < 0)
  273. {
  274. return;
  275. }
  276. const LLColor4U avail = LLUIColorTable::instance().getColor("PropertyColorAvail").get();
  277. const LLColor4U owned = LLUIColorTable::instance().getColor("PropertyColorOther").get();
  278. const LLColor4U group = LLUIColorTable::instance().getColor("PropertyColorGroup").get();
  279. const LLColor4U self = LLUIColorTable::instance().getColor("PropertyColorSelf").get();
  280. const LLColor4U for_sale = LLUIColorTable::instance().getColor("PropertyColorForSale").get();
  281. const LLColor4U auction = LLUIColorTable::instance().getColor("PropertyColorAuction").get();
  282. // Create the base texture.
  283. U8 *raw = mImageRaw->getData();
  284. const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge;
  285. S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
  286. if (max > COUNT) max = COUNT;
  287. S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS;
  288. S32 i;
  289. for (i = mOverlayTextureIdx; i < max; i++)
  290. {
  291. U8 ownership = mOwnership[i];
  292. F32 r,g,b,a;
  293. // Color stored in low three bits
  294. switch( ownership & 0x7 )
  295. {
  296. case PARCEL_PUBLIC:
  297. r = avail.mV[VRED];
  298. g = avail.mV[VGREEN];
  299. b = avail.mV[VBLUE];
  300. a = avail.mV[VALPHA];
  301. break;
  302. case PARCEL_OWNED:
  303. r = owned.mV[VRED];
  304. g = owned.mV[VGREEN];
  305. b = owned.mV[VBLUE];
  306. a = owned.mV[VALPHA];
  307. break;
  308. case PARCEL_GROUP:
  309. r = group.mV[VRED];
  310. g = group.mV[VGREEN];
  311. b = group.mV[VBLUE];
  312. a = group.mV[VALPHA];
  313. break;
  314. case PARCEL_SELF:
  315. r = self.mV[VRED];
  316. g = self.mV[VGREEN];
  317. b = self.mV[VBLUE];
  318. a = self.mV[VALPHA];
  319. break;
  320. case PARCEL_FOR_SALE:
  321. r = for_sale.mV[VRED];
  322. g = for_sale.mV[VGREEN];
  323. b = for_sale.mV[VBLUE];
  324. a = for_sale.mV[VALPHA];
  325. break;
  326. case PARCEL_AUCTION:
  327. r = auction.mV[VRED];
  328. g = auction.mV[VGREEN];
  329. b = auction.mV[VBLUE];
  330. a = auction.mV[VALPHA];
  331. break;
  332. default:
  333. r = self.mV[VRED];
  334. g = self.mV[VGREEN];
  335. b = self.mV[VBLUE];
  336. a = self.mV[VALPHA];
  337. break;
  338. }
  339. raw[pixel_index + 0] = (U8)r;
  340. raw[pixel_index + 1] = (U8)g;
  341. raw[pixel_index + 2] = (U8)b;
  342. raw[pixel_index + 3] = (U8)a;
  343. pixel_index += OVERLAY_IMG_COMPONENTS;
  344. }
  345. // Copy data into GL texture from raw data
  346. if (i >= COUNT)
  347. {
  348. if (!mTexture->hasGLTexture())
  349. {
  350. mTexture->createGLTexture(0, mImageRaw);
  351. }
  352. mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
  353. mOverlayTextureIdx = -1;
  354. }
  355. else
  356. {
  357. mOverlayTextureIdx = i;
  358. }
  359. }
  360. void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay)
  361. {
  362. // Unpack the message data into the ownership array
  363. S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
  364. S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS;
  365. memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size); /*Flawfinder: ignore*/
  366. // Force property lines and overlay texture to update
  367. setDirty();
  368. }
  369. void LLViewerParcelOverlay::updatePropertyLines()
  370. {
  371. if (!gSavedSettings.getBOOL("ShowPropertyLines"))
  372. return;
  373. S32 row, col;
  374. const LLColor4U self_coloru = LLUIColorTable::instance().getColor("PropertyColorSelf").get();
  375. const LLColor4U other_coloru = LLUIColorTable::instance().getColor("PropertyColorOther").get();
  376. const LLColor4U group_coloru = LLUIColorTable::instance().getColor("PropertyColorGroup").get();
  377. const LLColor4U for_sale_coloru = LLUIColorTable::instance().getColor("PropertyColorForSale").get();
  378. const LLColor4U auction_coloru = LLUIColorTable::instance().getColor("PropertyColorAuction").get();
  379. // Build into dynamic arrays, then copy into static arrays.
  380. LLDynamicArray<LLVector3, 256> new_vertex_array;
  381. LLDynamicArray<LLColor4U, 256> new_color_array;
  382. LLDynamicArray<LLVector2, 256> new_coord_array;
  383. U8 overlay = 0;
  384. BOOL add_edge = FALSE;
  385. const F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
  386. const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
  387. for (row = 0; row < GRIDS_PER_EDGE; row++)
  388. {
  389. for (col = 0; col < GRIDS_PER_EDGE; col++)
  390. {
  391. overlay = mOwnership[row*GRIDS_PER_EDGE+col];
  392. F32 left = col*GRID_STEP;
  393. F32 right = left+GRID_STEP;
  394. F32 bottom = row*GRID_STEP;
  395. F32 top = bottom+GRID_STEP;
  396. // West edge
  397. if (overlay & PARCEL_WEST_LINE)
  398. {
  399. switch(overlay & PARCEL_COLOR_MASK)
  400. {
  401. case PARCEL_SELF:
  402. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  403. left, bottom, WEST, self_coloru);
  404. break;
  405. case PARCEL_GROUP:
  406. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  407. left, bottom, WEST, group_coloru);
  408. break;
  409. case PARCEL_OWNED:
  410. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  411. left, bottom, WEST, other_coloru);
  412. break;
  413. case PARCEL_FOR_SALE:
  414. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  415. left, bottom, WEST, for_sale_coloru);
  416. break;
  417. case PARCEL_AUCTION:
  418. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  419. left, bottom, WEST, auction_coloru);
  420. break;
  421. default:
  422. break;
  423. }
  424. }
  425. // East edge
  426. if (col < GRIDS_PER_EDGE-1)
  427. {
  428. U8 east_overlay = mOwnership[row*GRIDS_PER_EDGE+col+1];
  429. add_edge = east_overlay & PARCEL_WEST_LINE;
  430. }
  431. else
  432. {
  433. add_edge = TRUE;
  434. }
  435. if (add_edge)
  436. {
  437. switch(overlay & PARCEL_COLOR_MASK)
  438. {
  439. case PARCEL_SELF:
  440. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  441. right, bottom, EAST, self_coloru);
  442. break;
  443. case PARCEL_GROUP:
  444. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  445. right, bottom, EAST, group_coloru);
  446. break;
  447. case PARCEL_OWNED:
  448. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  449. right, bottom, EAST, other_coloru);
  450. break;
  451. case PARCEL_FOR_SALE:
  452. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  453. right, bottom, EAST, for_sale_coloru);
  454. break;
  455. case PARCEL_AUCTION:
  456. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  457. right, bottom, EAST, auction_coloru);
  458. break;
  459. default:
  460. break;
  461. }
  462. }
  463. // South edge
  464. if (overlay & PARCEL_SOUTH_LINE)
  465. {
  466. switch(overlay & PARCEL_COLOR_MASK)
  467. {
  468. case PARCEL_SELF:
  469. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  470. left, bottom, SOUTH, self_coloru);
  471. break;
  472. case PARCEL_GROUP:
  473. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  474. left, bottom, SOUTH, group_coloru);
  475. break;
  476. case PARCEL_OWNED:
  477. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  478. left, bottom, SOUTH, other_coloru);
  479. break;
  480. case PARCEL_FOR_SALE:
  481. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  482. left, bottom, SOUTH, for_sale_coloru);
  483. break;
  484. case PARCEL_AUCTION:
  485. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  486. left, bottom, SOUTH, auction_coloru);
  487. break;
  488. default:
  489. break;
  490. }
  491. }
  492. // North edge
  493. if (row < GRIDS_PER_EDGE-1)
  494. {
  495. U8 north_overlay = mOwnership[(row+1)*GRIDS_PER_EDGE+col];
  496. add_edge = north_overlay & PARCEL_SOUTH_LINE;
  497. }
  498. else
  499. {
  500. add_edge = TRUE;
  501. }
  502. if (add_edge)
  503. {
  504. switch(overlay & PARCEL_COLOR_MASK)
  505. {
  506. case PARCEL_SELF:
  507. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  508. left, top, NORTH, self_coloru);
  509. break;
  510. case PARCEL_GROUP:
  511. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  512. left, top, NORTH, group_coloru);
  513. break;
  514. case PARCEL_OWNED:
  515. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  516. left, top, NORTH, other_coloru);
  517. break;
  518. case PARCEL_FOR_SALE:
  519. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  520. left, top, NORTH, for_sale_coloru);
  521. break;
  522. case PARCEL_AUCTION:
  523. addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
  524. left, top, NORTH, auction_coloru);
  525. break;
  526. default:
  527. break;
  528. }
  529. }
  530. }
  531. }
  532. // Now copy into static arrays for faster rendering.
  533. // Attempt to recycle old arrays if possible to avoid memory
  534. // shuffling.
  535. S32 new_vertex_count = new_vertex_array.count();
  536. if (!(mVertexArray && mColorArray && new_vertex_count == mVertexCount))
  537. {
  538. // ...need new arrays
  539. delete[] mVertexArray;
  540. mVertexArray = NULL;
  541. delete[] mColorArray;
  542. mColorArray = NULL;
  543. mVertexCount = new_vertex_count;
  544. if (new_vertex_count > 0)
  545. {
  546. mVertexArray = new F32[3 * mVertexCount];
  547. mColorArray = new U8 [4 * mVertexCount];
  548. }
  549. }
  550. // Copy the new data into the arrays
  551. S32 i;
  552. F32* vertex = mVertexArray;
  553. for (i = 0; i < mVertexCount; i++)
  554. {
  555. const LLVector3& point = new_vertex_array.get(i);
  556. *vertex = point.mV[VX];
  557. vertex++;
  558. *vertex = point.mV[VY];
  559. vertex++;
  560. *vertex = point.mV[VZ];
  561. vertex++;
  562. }
  563. U8* colorp = mColorArray;
  564. for (i = 0; i < mVertexCount; i++)
  565. {
  566. const LLColor4U& color = new_color_array.get(i);
  567. *colorp = color.mV[VRED];
  568. colorp++;
  569. *colorp = color.mV[VGREEN];
  570. colorp++;
  571. *colorp = color.mV[VBLUE];
  572. colorp++;
  573. *colorp = color.mV[VALPHA];
  574. colorp++;
  575. }
  576. // Everything's clean now
  577. mDirty = FALSE;
  578. }
  579. void LLViewerParcelOverlay::addPropertyLine(
  580. LLDynamicArray<LLVector3, 256>& vertex_array,
  581. LLDynamicArray<LLColor4U, 256>& color_array,
  582. LLDynamicArray<LLVector2, 256>& coord_array,
  583. const F32 start_x, const F32 start_y,
  584. const U32 edge,
  585. const LLColor4U& color)
  586. {
  587. LLColor4U underwater( color );
  588. underwater.mV[VALPHA] /= 2;
  589. LLSurface& land = mRegion->getLand();
  590. F32 dx;
  591. F32 dy;
  592. F32 tick_dx;
  593. F32 tick_dy;
  594. //const F32 LINE_WIDTH = 0.125f;
  595. const F32 LINE_WIDTH = 0.0625f;
  596. switch(edge)
  597. {
  598. case WEST:
  599. dx = 0.f;
  600. dy = 1.f;
  601. tick_dx = LINE_WIDTH;
  602. tick_dy = 0.f;
  603. break;
  604. case EAST:
  605. dx = 0.f;
  606. dy = 1.f;
  607. tick_dx = -LINE_WIDTH;
  608. tick_dy = 0.f;
  609. break;
  610. case NORTH:
  611. dx = 1.f;
  612. dy = 0.f;
  613. tick_dx = 0.f;
  614. tick_dy = -LINE_WIDTH;
  615. break;
  616. case SOUTH:
  617. dx = 1.f;
  618. dy = 0.f;
  619. tick_dx = 0.f;
  620. tick_dy = LINE_WIDTH;
  621. break;
  622. default:
  623. llerrs << "Invalid edge in addPropertyLine" << llendl;
  624. return;
  625. }
  626. F32 outside_x = start_x;
  627. F32 outside_y = start_y;
  628. F32 outside_z = 0.f;
  629. F32 inside_x = start_x + tick_dx;
  630. F32 inside_y = start_y + tick_dy;
  631. F32 inside_z = 0.f;
  632. // First part, only one vertex
  633. outside_z = land.resolveHeightRegion( outside_x, outside_y );
  634. if (outside_z > 20.f) color_array.put( color );
  635. else color_array.put( underwater );
  636. vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
  637. coord_array.put( LLVector2(outside_x - start_x, 0.f) );
  638. inside_x += dx * LINE_WIDTH;
  639. inside_y += dy * LINE_WIDTH;
  640. outside_x += dx * LINE_WIDTH;
  641. outside_y += dy * LINE_WIDTH;
  642. // Then the "actual edge"
  643. inside_z = land.resolveHeightRegion( inside_x, inside_y );
  644. outside_z = land.resolveHeightRegion( outside_x, outside_y );
  645. if (inside_z > 20.f) color_array.put( color );
  646. else color_array.put( underwater );
  647. if (outside_z > 20.f) color_array.put( color );
  648. else color_array.put( underwater );
  649. vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
  650. vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
  651. coord_array.put( LLVector2(outside_x - start_x, 1.f) );
  652. coord_array.put( LLVector2(outside_x - start_x, 0.f) );
  653. inside_x += dx * (dx - LINE_WIDTH);
  654. inside_y += dy * (dy - LINE_WIDTH);
  655. outside_x += dx * (dx - LINE_WIDTH);
  656. outside_y += dy * (dy - LINE_WIDTH);
  657. // Middle part, full width
  658. S32 i;
  659. const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
  660. for (i = 1; i < GRID_STEP; i++)
  661. {
  662. inside_z = land.resolveHeightRegion( inside_x, inside_y );
  663. outside_z = land.resolveHeightRegion( outside_x, outside_y );
  664. if (inside_z > 20.f) color_array.put( color );
  665. else color_array.put( underwater );
  666. if (outside_z > 20.f) color_array.put( color );
  667. else color_array.put( underwater );
  668. vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
  669. vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
  670. coord_array.put( LLVector2(outside_x - start_x, 1.f) );
  671. coord_array.put( LLVector2(outside_x - start_x, 0.f) );
  672. inside_x += dx;
  673. inside_y += dy;
  674. outside_x += dx;
  675. outside_y += dy;
  676. }
  677. // Extra buffer for edge
  678. inside_x -= dx * LINE_WIDTH;
  679. inside_y -= dy * LINE_WIDTH;
  680. outside_x -= dx * LINE_WIDTH;
  681. outside_y -= dy * LINE_WIDTH;
  682. inside_z = land.resolveHeightRegion( inside_x, inside_y );
  683. outside_z = land.resolveHeightRegion( outside_x, outside_y );
  684. if (inside_z > 20.f) color_array.put( color );
  685. else color_array.put( underwater );
  686. if (outside_z > 20.f) color_array.put( color );
  687. else color_array.put( underwater );
  688. vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
  689. vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
  690. coord_array.put( LLVector2(outside_x - start_x, 1.f) );
  691. coord_array.put( LLVector2(outside_x - start_x, 0.f) );
  692. inside_x += dx * LINE_WIDTH;
  693. inside_y += dy * LINE_WIDTH;
  694. outside_x += dx * LINE_WIDTH;
  695. outside_y += dy * LINE_WIDTH;
  696. // Last edge is not drawn to the edge
  697. outside_z = land.resolveHeightRegion( outside_x, outside_y );
  698. if (outside_z > 20.f) color_array.put( color );
  699. else color_array.put( underwater );
  700. vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
  701. coord_array.put( LLVector2(outside_x - start_x, 0.f) );
  702. }
  703. void LLViewerParcelOverlay::setDirty()
  704. {
  705. mDirty = TRUE;
  706. }
  707. void LLViewerParcelOverlay::updateGL()
  708. {
  709. updateOverlayTexture();
  710. }
  711. void LLViewerParcelOverlay::idleUpdate(bool force_update)
  712. {
  713. LLMemType mt_iup(LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY);
  714. if (gGLManager.mIsDisabled)
  715. {
  716. return;
  717. }
  718. if (mOverlayTextureIdx >= 0 && (!(mDirty && force_update)))
  719. {
  720. // We are in the middle of updating the overlay texture
  721. gPipeline.markGLRebuild(this);
  722. return;
  723. }
  724. // Only if we're dirty and it's been a while since the last update.
  725. if (mDirty)
  726. {
  727. if (force_update || mTimeSinceLastUpdate.getElapsedTimeF32() > 4.0f)
  728. {
  729. updateOverlayTexture();
  730. updatePropertyLines();
  731. mTimeSinceLastUpdate.reset();
  732. }
  733. }
  734. }
  735. S32 LLViewerParcelOverlay::renderPropertyLines ()
  736. {
  737. if (!gSavedSettings.getBOOL("ShowPropertyLines"))
  738. {
  739. return 0;
  740. }
  741. if (!mVertexArray || !mColorArray)
  742. {
  743. return 0;
  744. }
  745. LLSurface& land = mRegion->getLand();
  746. LLGLSUIDefault gls_ui; // called from pipeline
  747. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  748. LLGLDepthTest mDepthTest(GL_TRUE);
  749. // Find camera height off the ground (not from zero)
  750. F32 ground_height_at_camera = land.resolveHeightGlobal( gAgentCamera.getCameraPositionGlobal() );
  751. F32 camera_z = LLViewerCamera::getInstance()->getOrigin().mV[VZ];
  752. F32 camera_height = camera_z - ground_height_at_camera;
  753. camera_height = llclamp(camera_height, 0.f, 100.f);
  754. // Pull lines toward camera by 1 cm per meter off the ground.
  755. const LLVector3& CAMERA_AT = LLViewerCamera::getInstance()->getAtAxis();
  756. F32 pull_toward_camera_scale = 0.01f * camera_height;
  757. LLVector3 pull_toward_camera = CAMERA_AT;
  758. pull_toward_camera *= -pull_toward_camera_scale;
  759. // Always fudge a little vertically.
  760. pull_toward_camera.mV[VZ] += 0.01f;
  761. gGL.matrixMode(LLRender::MM_MODELVIEW);
  762. gGL.pushMatrix();
  763. // Move to appropriate region coords
  764. LLVector3 origin = mRegion->getOriginAgent();
  765. gGL.translatef( origin.mV[VX], origin.mV[VY], origin.mV[VZ] );
  766. gGL.translatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY],
  767. pull_toward_camera.mV[VZ]);
  768. // Include +1 because vertices are fenceposts.
  769. // *2 because it's a quad strip
  770. const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
  771. const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3;
  772. // Stomp the camera into two dimensions
  773. LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() );
  774. // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
  775. // the camera. The cull plane normal is the camera's at axis.
  776. LLVector3 cull_plane_point = LLViewerCamera::getInstance()->getAtAxis();
  777. cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
  778. cull_plane_point += camera_region;
  779. LLVector3 vertex;
  780. const S32 BYTES_PER_COLOR = 4;
  781. const S32 FLOATS_PER_VERTEX = 3;
  782. //const S32 FLOATS_PER_TEX_COORD = 2;
  783. S32 i, j;
  784. S32 drawn = 0;
  785. F32* vertexp;
  786. U8* colorp;
  787. bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build");
  788. const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
  789. for (i = 0; i < mVertexCount; i += vertex_per_edge)
  790. {
  791. colorp = mColorArray + BYTES_PER_COLOR * i;
  792. vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
  793. vertex.mV[VX] = *(vertexp);
  794. vertex.mV[VY] = *(vertexp+1);
  795. vertex.mV[VZ] = *(vertexp+2);
  796. if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED)
  797. {
  798. continue;
  799. }
  800. // Destroy vertex, transform to plane-local.
  801. vertex -= cull_plane_point;
  802. // negative dot product means it is in back of the plane
  803. if ( vertex * CAMERA_AT < 0.f )
  804. {
  805. continue;
  806. }
  807. gGL.begin(LLRender::TRIANGLE_STRIP);
  808. for (j = 0; j < vertex_per_edge; j++)
  809. {
  810. gGL.color4ubv(colorp);
  811. gGL.vertex3fv(vertexp);
  812. colorp += BYTES_PER_COLOR;
  813. vertexp += FLOATS_PER_VERTEX;
  814. }
  815. drawn += vertex_per_edge;
  816. gGL.end();
  817. if (render_hidden)
  818. {
  819. LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
  820. colorp = mColorArray + BYTES_PER_COLOR * i;
  821. vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
  822. gGL.begin(LLRender::TRIANGLE_STRIP);
  823. for (j = 0; j < vertex_per_edge; j++)
  824. {
  825. U8 color[4];
  826. color[0] = colorp[0];
  827. color[1] = colorp[1];
  828. color[2] = colorp[2];
  829. color[3] = colorp[3]/4;
  830. gGL.color4ubv(color);
  831. gGL.vertex3fv(vertexp);
  832. colorp += BYTES_PER_COLOR;
  833. vertexp += FLOATS_PER_VERTEX;
  834. }
  835. drawn += vertex_per_edge;
  836. gGL.end();
  837. }
  838. }
  839. gGL.popMatrix();
  840. return drawn;
  841. }