llviewerparceloverlay.cpp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. /**
  2. * @file llviewerparceloverlay.cpp
  3. * @brief LLViewerParcelOverlay class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llviewerparceloverlay.h"
  34. #include "llgl.h"
  35. #include "llparcel.h"
  36. #include "llrender.h"
  37. #include "llagent.h"
  38. #include "llfloatertools.h"
  39. #include "llselectmgr.h"
  40. #include "llsurface.h"
  41. #include "llviewercamera.h"
  42. #include "llviewercontrol.h"
  43. #include "llviewerregion.h"
  44. #include "llviewertexturelist.h"
  45. constexpr U8 OVERLAY_IMG_COMPONENTS = 4;
  46. constexpr F32 MAX_COORD = REGION_WIDTH_METERS - 1.f;
  47. constexpr F32 STEP_FACTOR = 1.f / PARCEL_GRID_STEP_METERS;
  48. LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region,
  49. F32 region_width_meters)
  50. : mRegion(region),
  51. mParcelGridsPerEdge(S32(region_width_meters * STEP_FACTOR)),
  52. mRegionSize(S32(region_width_meters)), // Variable region size support
  53. mDirty(false),
  54. mHasCollisions(false),
  55. mTimeSinceLastUpdate(),
  56. mOverlayTextureIdx(-1),
  57. mVertexCount(0),
  58. mVertexArray(NULL),
  59. mColorArray(NULL)
  60. {
  61. // Create a texture to hold color information; 4 components,
  62. // use mipmaps = false, clamped, NEAREST filter, for sharp edges.
  63. mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge,
  64. OVERLAY_IMG_COMPONENTS);
  65. mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), false);
  66. mTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
  67. mTexture->setFilteringOption(LLTexUnit::TFO_POINT);
  68. //
  69. // Initialize the GL texture with empty data.
  70. //
  71. // Create the base texture.
  72. U8* rawp = mImageRaw->getData();
  73. if (rawp)
  74. {
  75. S32 count = mParcelGridsPerEdge * mParcelGridsPerEdge *
  76. OVERLAY_IMG_COMPONENTS;
  77. for (S32 i = 0; i < count; ++i)
  78. {
  79. rawp[i] = 0;
  80. }
  81. mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge,
  82. mParcelGridsPerEdge);
  83. }
  84. // Create storage for ownership information from simulator
  85. // and initialize it.
  86. mOwnership = new (std::nothrow) U8[mParcelGridsPerEdge * mParcelGridsPerEdge];
  87. if (mOwnership)
  88. {
  89. for (S32 i = 0; i < mParcelGridsPerEdge * mParcelGridsPerEdge; ++i)
  90. {
  91. mOwnership[i] = PARCEL_PUBLIC;
  92. }
  93. }
  94. resetCollisionBitmap();
  95. gPipeline.markGLRebuild(this);
  96. LL_DEBUGS("MarkGLRebuild") << "Marked for GL rebuild: " << std::hex
  97. << (intptr_t)this << std::dec << LL_ENDL;
  98. }
  99. LLViewerParcelOverlay::~LLViewerParcelOverlay()
  100. {
  101. delete[] mOwnership;
  102. mOwnership = NULL;
  103. delete[] mVertexArray;
  104. mVertexArray = NULL;
  105. delete[] mColorArray;
  106. mColorArray = NULL;
  107. mImageRaw = NULL;
  108. }
  109. bool LLViewerParcelOverlay::isOwned(const LLVector3& pos) const
  110. {
  111. return ownership(pos.mV[VY] * STEP_FACTOR,
  112. pos.mV[VX] * STEP_FACTOR) != PARCEL_PUBLIC;
  113. }
  114. bool LLViewerParcelOverlay::isOwnedSelf(const LLVector3& pos) const
  115. {
  116. return ownership(pos.mV[VY] * STEP_FACTOR,
  117. pos.mV[VX] * STEP_FACTOR) == PARCEL_SELF;
  118. }
  119. bool LLViewerParcelOverlay::isOwnedGroup(const LLVector3& pos) const
  120. {
  121. return ownership(pos.mV[VY] * STEP_FACTOR,
  122. pos.mV[VX] * STEP_FACTOR) == PARCEL_GROUP;
  123. }
  124. bool LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const
  125. {
  126. U8 overlay = ownership(pos.mV[VY] * STEP_FACTOR, pos.mV[VX] * STEP_FACTOR);
  127. return overlay == PARCEL_OWNED || overlay == PARCEL_FOR_SALE;
  128. }
  129. bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) const
  130. {
  131. // Boxes are expected to already be axis aligned
  132. for (U32 i = 0; i < boxes.size(); ++i)
  133. {
  134. LLVector3 min = boxes[i].getMinAgent();
  135. LLVector3 max = boxes[i].getMaxAgent();
  136. S32 left = S32(llclamp(min.mV[VX] * STEP_FACTOR, 0.f, MAX_COORD));
  137. S32 right = S32(llclamp(max.mV[VX] * STEP_FACTOR, 0.f, MAX_COORD));
  138. S32 top = S32(llclamp(min.mV[VY] * STEP_FACTOR, 0.f, MAX_COORD));
  139. S32 bottom = S32(llclamp(max.mV[VY] * STEP_FACTOR, 0.f, MAX_COORD));
  140. for (S32 row = top; row <= bottom; ++row)
  141. {
  142. for (S32 column = left; column <= right; ++column)
  143. {
  144. U8 type = ownership(row, column);
  145. if (PARCEL_SELF == type || PARCEL_GROUP == type)
  146. {
  147. return true;
  148. }
  149. }
  150. }
  151. }
  152. return false;
  153. }
  154. bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes) const
  155. {
  156. // Boxes are expected to already be axis aligned
  157. for (U32 i = 0; i < boxes.size(); ++i)
  158. {
  159. LLVector3 min = boxes[i].getMinAgent();
  160. LLVector3 max = boxes[i].getMaxAgent();
  161. S32 left = S32(llclamp((min.mV[VX] * STEP_FACTOR), 0.f, MAX_COORD));
  162. S32 right = S32(llclamp((max.mV[VX] * STEP_FACTOR), 0.f, MAX_COORD));
  163. S32 top = S32(llclamp((min.mV[VY] * STEP_FACTOR), 0.f, MAX_COORD));
  164. S32 bottom = S32(llclamp((max.mV[VY] * STEP_FACTOR), 0.f, MAX_COORD));
  165. for (S32 row = top; row <= bottom; ++row)
  166. {
  167. for (S32 column = left; column <= right; ++column)
  168. {
  169. U8 type = ownership(row, column);
  170. if (PARCEL_SELF != type)
  171. {
  172. return true;
  173. }
  174. }
  175. }
  176. }
  177. return false;
  178. }
  179. bool LLViewerParcelOverlay::encroachesOnNearbyParcel(const std::vector<LLBBox>& boxes) const
  180. {
  181. // Boxes are expected to already be axis aligned
  182. for (U32 i = 0; i < boxes.size(); ++i)
  183. {
  184. LLVector3 min = boxes[i].getMinAgent();
  185. LLVector3 max = boxes[i].getMaxAgent();
  186. // If an object crosses region borders it crosses a parcel
  187. if (min.mV[VX] < 0 || 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] * STEP_FACTOR), 0.f, MAX_COORD));
  194. S32 right = S32(llclamp((max.mV[VX] * STEP_FACTOR), 0.f, MAX_COORD));
  195. S32 bottom = S32(llclamp((min.mV[VY] * STEP_FACTOR), 0.f, MAX_COORD));
  196. S32 top = S32(llclamp((max.mV[VY] * STEP_FACTOR), 0.f, MAX_COORD));
  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 =
  206. mOwnership ? mOwnership[row * GRIDS_PER_EDGE + col + 1]
  207. : PARCEL_PUBLIC;
  208. // If the column to the east of the current one marks
  209. // the other parcel's west edge and the box extends
  210. // to the west it crosses the parcel border.
  211. if ((east_overlay & PARCEL_WEST_LINE) && col < right)
  212. {
  213. return true;
  214. }
  215. }
  216. // This is not the topmost column
  217. if (row < GRIDS_PER_EDGE - 1)
  218. {
  219. U8 north_overlay =
  220. mOwnership ? mOwnership[(row + 1) * GRIDS_PER_EDGE + col]
  221. : PARCEL_PUBLIC;
  222. // If the row to the north of the current one marks
  223. // the other parcel's south edge and the box extends
  224. // to the south it crosses the parcel border.
  225. if ((north_overlay & PARCEL_SOUTH_LINE) && row < top)
  226. {
  227. return true;
  228. }
  229. }
  230. }
  231. }
  232. }
  233. return false;
  234. }
  235. U8 LLViewerParcelOverlay::ownership(const LLVector3& pos) const
  236. {
  237. return ownership(pos.mV[VY] * STEP_FACTOR, pos.mV[VX] * STEP_FACTOR);
  238. }
  239. U8 LLViewerParcelOverlay::parcelFlags(S32 row, S32 col, U8 mask) const
  240. {
  241. if (!mOwnership)
  242. {
  243. LL_DEBUGS_ONCE("ParcelOverlay") << "No ownership data for overlay "
  244. << std::hex << (intptr_t)this
  245. << std::dec << llendl;
  246. return mask;
  247. }
  248. if (row < 0 || col < 0 || row >= mParcelGridsPerEdge ||
  249. col >= mParcelGridsPerEdge)
  250. {
  251. LL_DEBUGS_ONCE("ParcelOverlay") << "Out of range coordinates for overlay "
  252. << std::hex << (intptr_t)this
  253. << std::dec << " - row: " << row
  254. << " - col: " << col << llendl;
  255. return mask;
  256. }
  257. return mOwnership[row * mParcelGridsPerEdge + col] & mask;
  258. }
  259. U8 LLViewerParcelOverlay::parcelLineFlags(S32 row, S32 col) const
  260. {
  261. constexpr U8 mask = PARCEL_WEST_LINE | PARCEL_SOUTH_LINE;
  262. return parcelFlags(row, col, mask);
  263. }
  264. bool LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
  265. {
  266. return parcelFlags(S32(pos.mV[VY] * STEP_FACTOR),
  267. S32(pos.mV[VX] * STEP_FACTOR), PARCEL_SOUND_LOCAL);
  268. }
  269. F32 LLViewerParcelOverlay::getOwnedRatio() const
  270. {
  271. S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
  272. S32 total = 0;
  273. if (mOwnership)
  274. {
  275. for (S32 i = 0; i < size; ++i)
  276. {
  277. if ((mOwnership[i] & PARCEL_COLOR_MASK) != PARCEL_PUBLIC)
  278. {
  279. ++total;
  280. }
  281. }
  282. }
  283. return (F32)total / (F32)size;
  284. }
  285. // Color tables for owned land
  286. // Available = index 0
  287. // Other = index 1
  288. // Group = index 2
  289. // Self = index 3
  290. // Make sure the texture colors match the ownership data.
  291. void LLViewerParcelOverlay::updateOverlayTexture()
  292. {
  293. if (mOverlayTextureIdx < 0)
  294. {
  295. if (!mDirty)
  296. {
  297. return;
  298. }
  299. mOverlayTextureIdx = 0;
  300. }
  301. U8* rawp = mImageRaw->getData();
  302. if (!rawp || !mTexture)
  303. {
  304. return;
  305. }
  306. // Can do this because gColors are actually stored as LLColor4U
  307. static LLCachedControl<LLColor4U> color_avail(gColors,
  308. "PropertyColorAvail");
  309. static LLCachedControl<LLColor4U> color_other(gColors,
  310. "PropertyColorOther");
  311. static LLCachedControl<LLColor4U> color_group(gColors,
  312. "PropertyColorGroup");
  313. static LLCachedControl<LLColor4U> color_self(gColors,
  314. "PropertyColorSelf");
  315. static LLCachedControl<LLColor4U> color_for_sale(gColors,
  316. "PropertyColorForSale");
  317. static LLCachedControl<LLColor4U> color_auction(gColors,
  318. "PropertyColorAuction");
  319. // Create the base texture.
  320. LLColor4U color;
  321. S32 count = mParcelGridsPerEdge * mParcelGridsPerEdge;
  322. S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
  323. if (max > count)
  324. {
  325. max = count;
  326. }
  327. S32 pixel_index = mOverlayTextureIdx * OVERLAY_IMG_COMPONENTS;
  328. S32 i;
  329. for (i = mOverlayTextureIdx; i < max; ++i)
  330. {
  331. U8 ownership = mOwnership ? mOwnership[i] : PARCEL_PUBLIC;
  332. // Color stored in low three bits
  333. switch (ownership & 0x7)
  334. {
  335. case PARCEL_PUBLIC:
  336. color = color_avail;
  337. break;
  338. case PARCEL_OWNED:
  339. color = color_other;
  340. break;
  341. case PARCEL_GROUP:
  342. color = color_group;
  343. break;
  344. case PARCEL_FOR_SALE:
  345. color = color_for_sale;
  346. break;
  347. case PARCEL_AUCTION:
  348. color = color_auction;
  349. break;
  350. case PARCEL_SELF:
  351. default:
  352. color = color_self;
  353. break;
  354. }
  355. rawp[pixel_index] = color.mV[VRED];
  356. rawp[pixel_index + 1] = color.mV[VGREEN];
  357. rawp[pixel_index + 2] = color.mV[VBLUE];
  358. rawp[pixel_index + 3] = color.mV[VALPHA];
  359. pixel_index += OVERLAY_IMG_COMPONENTS;
  360. }
  361. // Copy data into GL texture from raw data
  362. if (i >= count)
  363. {
  364. if (!mTexture->hasGLTexture())
  365. {
  366. mTexture->createGLTexture(0, mImageRaw);
  367. }
  368. mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge,
  369. mParcelGridsPerEdge);
  370. mOverlayTextureIdx = -1;
  371. }
  372. else
  373. {
  374. mOverlayTextureIdx = i;
  375. }
  376. }
  377. void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk,
  378. U8* packed_overlay)
  379. {
  380. // Unpack the message data into the ownership array
  381. S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
  382. // Variable region size support
  383. S32 parcel_overlay_chunks = mRegionSize * mRegionSize / (128 * 128);
  384. S32 chunk_size = size / parcel_overlay_chunks;
  385. if (mOwnership)
  386. {
  387. memcpy(mOwnership + chunk * chunk_size, packed_overlay, chunk_size);
  388. }
  389. // Force property lines and overlay texture to update
  390. setDirty();
  391. }
  392. void LLViewerParcelOverlay::updatePropertyLines()
  393. {
  394. static LLCachedControl<bool> show_property_lines(gSavedSettings,
  395. "ShowPropertyLines");
  396. static LLCachedControl<bool> show_parcels(gSavedSettings,
  397. "MinimapShowParcelBorders");
  398. if (!show_property_lines && !show_parcels)
  399. {
  400. return;
  401. }
  402. // Can do this because gColors are actually stored as LLColor4U
  403. static LLCachedControl<LLColor4U> self_coloru(gColors,
  404. "PropertyColorSelf");
  405. static LLCachedControl<LLColor4U> other_coloru(gColors,
  406. "PropertyColorOther");
  407. static LLCachedControl<LLColor4U> group_coloru(gColors,
  408. "PropertyColorGroup");
  409. static LLCachedControl<LLColor4U> for_sale_coloru(gColors,
  410. "PropertyColorForSale");
  411. static LLCachedControl<LLColor4U> auction_coloru(gColors,
  412. "PropertyColorAuction");
  413. LLColor4U color;
  414. // Build into vectors, then copy into static arrays.
  415. std::vector<LLVector3> new_vertex_array;
  416. new_vertex_array.reserve(256);
  417. std::vector<LLColor4U> new_color_array;
  418. new_color_array.reserve(256);
  419. std::vector<LLVector2> new_coord_array;
  420. new_coord_array.reserve(256);
  421. U8 overlay = 0;
  422. bool add_edge = false;
  423. constexpr F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
  424. const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
  425. for (S32 row = 0; row < GRIDS_PER_EDGE; ++row)
  426. {
  427. for (S32 col = 0; col < GRIDS_PER_EDGE; ++col)
  428. {
  429. overlay = mOwnership ? mOwnership[row * GRIDS_PER_EDGE + col]
  430. : PARCEL_PUBLIC;
  431. switch (overlay & PARCEL_COLOR_MASK)
  432. {
  433. case PARCEL_SELF:
  434. color = self_coloru;
  435. break;
  436. case PARCEL_GROUP:
  437. color = group_coloru;
  438. break;
  439. case PARCEL_OWNED:
  440. color = other_coloru;
  441. break;
  442. case PARCEL_FOR_SALE:
  443. color = for_sale_coloru;
  444. break;
  445. case PARCEL_AUCTION:
  446. color = auction_coloru;
  447. break;
  448. default:
  449. continue;
  450. }
  451. F32 left = col * GRID_STEP;
  452. F32 right = left + GRID_STEP;
  453. F32 bottom = row * GRID_STEP;
  454. F32 top = bottom + GRID_STEP;
  455. // West edge
  456. if (overlay & PARCEL_WEST_LINE)
  457. {
  458. addPropertyLine(new_vertex_array, new_color_array,
  459. new_coord_array, left, bottom, WEST, color);
  460. }
  461. // East edge
  462. if (col < GRIDS_PER_EDGE - 1)
  463. {
  464. U8 east_overlay =
  465. mOwnership ? mOwnership[row * GRIDS_PER_EDGE + col + 1]
  466. : PARCEL_PUBLIC;
  467. add_edge = (east_overlay & PARCEL_WEST_LINE) != 0;
  468. }
  469. else
  470. {
  471. add_edge = true;
  472. }
  473. if (add_edge)
  474. {
  475. addPropertyLine(new_vertex_array, new_color_array,
  476. new_coord_array, right, bottom, EAST, color);
  477. }
  478. // South edge
  479. if (overlay & PARCEL_SOUTH_LINE)
  480. {
  481. addPropertyLine(new_vertex_array, new_color_array,
  482. new_coord_array, left, bottom, SOUTH, color);
  483. }
  484. // North edge
  485. if (row < GRIDS_PER_EDGE - 1)
  486. {
  487. U8 north_overlay =
  488. mOwnership ? mOwnership[(row + 1) * GRIDS_PER_EDGE + col]
  489. : PARCEL_PUBLIC;
  490. add_edge = (north_overlay & PARCEL_SOUTH_LINE) != 0;
  491. }
  492. else
  493. {
  494. add_edge = true;
  495. }
  496. if (add_edge)
  497. {
  498. addPropertyLine(new_vertex_array, new_color_array,
  499. new_coord_array, left, top, NORTH, color);
  500. }
  501. }
  502. }
  503. // Now copy into static arrays for faster rendering.
  504. // Attempt to recycle old arrays if possible to avoid memory shuffling.
  505. S32 new_vertex_count = new_vertex_array.size();
  506. if (!(mVertexArray && mColorArray && new_vertex_count == mVertexCount))
  507. {
  508. // ...need new arrays
  509. delete[] mVertexArray;
  510. mVertexArray = NULL;
  511. delete[] mColorArray;
  512. mColorArray = NULL;
  513. mVertexCount = new_vertex_count;
  514. if (new_vertex_count > 0)
  515. {
  516. mVertexArray = new F32[3 * mVertexCount];
  517. mColorArray = new U8[4 * mVertexCount];
  518. }
  519. }
  520. // Copy the new data into the arrays
  521. F32* vertex = mVertexArray;
  522. for (S32 i = 0; i < mVertexCount; ++i)
  523. {
  524. const LLVector3& point = new_vertex_array[i];
  525. *vertex++ = point.mV[VX];
  526. *vertex++ = point.mV[VY];
  527. *vertex++ = point.mV[VZ];
  528. }
  529. U8* colorp = mColorArray;
  530. for (S32 i = 0; i < mVertexCount; ++i)
  531. {
  532. const LLColor4U& color = new_color_array[i];
  533. *colorp++ = color.mV[VRED];
  534. *colorp++ = color.mV[VGREEN];
  535. *colorp++ = color.mV[VBLUE];
  536. *colorp++ = color.mV[VALPHA];
  537. }
  538. // Everything is clean now
  539. mDirty = false;
  540. }
  541. void LLViewerParcelOverlay::addPropertyLine(std::vector<LLVector3>& vertex_array,
  542. std::vector<LLColor4U>& color_array,
  543. std::vector<LLVector2>& coord_array,
  544. F32 start_x, F32 start_y, U32 edge,
  545. const LLColor4U& color)
  546. {
  547. static LLCachedControl<bool> at_surface(gSavedSettings,
  548. "ShowPropLinesAtWaterSurface");
  549. LLColor4U underwater(color);
  550. if (!at_surface)
  551. {
  552. underwater.mV[VALPHA] *= 0.5f;
  553. }
  554. vertex_array.reserve(16);
  555. color_array.reserve(16);
  556. coord_array.reserve(16);
  557. LLSurface& land = mRegion->getLand();
  558. F32 water_height = mRegion->getWaterHeight();
  559. F32 dx;
  560. F32 dy;
  561. F32 tick_dx;
  562. F32 tick_dy;
  563. constexpr F32 LINE_WIDTH = 0.0625f;
  564. switch(edge)
  565. {
  566. case WEST:
  567. dx = 0.f;
  568. dy = 1.f;
  569. tick_dx = LINE_WIDTH;
  570. tick_dy = 0.f;
  571. break;
  572. case EAST:
  573. dx = 0.f;
  574. dy = 1.f;
  575. tick_dx = -LINE_WIDTH;
  576. tick_dy = 0.f;
  577. break;
  578. case NORTH:
  579. dx = 1.f;
  580. dy = 0.f;
  581. tick_dx = 0.f;
  582. tick_dy = -LINE_WIDTH;
  583. break;
  584. case SOUTH:
  585. dx = 1.f;
  586. dy = 0.f;
  587. tick_dx = 0.f;
  588. tick_dy = LINE_WIDTH;
  589. break;
  590. default:
  591. llerrs << "Invalid edge in addPropertyLine" << llendl;
  592. return;
  593. }
  594. F32 outside_x = start_x;
  595. F32 outside_y = start_y;
  596. F32 outside_z = 0.f;
  597. F32 inside_x = start_x + tick_dx;
  598. F32 inside_y = start_y + tick_dy;
  599. F32 inside_z = 0.f;
  600. // First part, only one vertex
  601. outside_z = land.resolveHeightRegion(outside_x, outside_y);
  602. if (outside_z > water_height)
  603. {
  604. color_array.emplace_back(color);
  605. }
  606. else
  607. {
  608. color_array.emplace_back(underwater);
  609. if (at_surface)
  610. {
  611. outside_z = water_height;
  612. }
  613. }
  614. vertex_array.emplace_back(outside_x, outside_y, outside_z);
  615. coord_array.emplace_back(outside_x - start_x, 0.f);
  616. inside_x += dx * LINE_WIDTH;
  617. inside_y += dy * LINE_WIDTH;
  618. outside_x += dx * LINE_WIDTH;
  619. outside_y += dy * LINE_WIDTH;
  620. // Then the "actual edge"
  621. inside_z = land.resolveHeightRegion(inside_x, inside_y);
  622. outside_z = land.resolveHeightRegion(outside_x, outside_y);
  623. if (inside_z > water_height)
  624. {
  625. color_array.emplace_back(color);
  626. }
  627. else
  628. {
  629. color_array.emplace_back(underwater);
  630. if (at_surface)
  631. {
  632. inside_z = water_height;
  633. }
  634. }
  635. if (outside_z > water_height)
  636. {
  637. color_array.emplace_back(color);
  638. }
  639. else
  640. {
  641. color_array.emplace_back(underwater);
  642. if (at_surface)
  643. {
  644. outside_z = water_height;
  645. }
  646. }
  647. vertex_array.emplace_back(inside_x, inside_y, inside_z);
  648. vertex_array.emplace_back(outside_x, outside_y, outside_z);
  649. coord_array.emplace_back(outside_x - start_x, 1.f);
  650. coord_array.emplace_back(outside_x - start_x, 0.f);
  651. inside_x += dx * (dx - LINE_WIDTH);
  652. inside_y += dy * (dy - LINE_WIDTH);
  653. outside_x += dx * (dx - LINE_WIDTH);
  654. outside_y += dy * (dy - LINE_WIDTH);
  655. // Middle part, full width
  656. S32 i;
  657. constexpr S32 GRID_STEP = S32(PARCEL_GRID_STEP_METERS);
  658. for (i = 1; i < GRID_STEP; i++)
  659. {
  660. inside_z = land.resolveHeightRegion(inside_x, inside_y);
  661. outside_z = land.resolveHeightRegion(outside_x, outside_y);
  662. if (inside_z > water_height)
  663. {
  664. color_array.emplace_back(color);
  665. }
  666. else
  667. {
  668. color_array.emplace_back(underwater);
  669. if (at_surface)
  670. {
  671. inside_z = water_height;
  672. }
  673. }
  674. if (outside_z > water_height)
  675. {
  676. color_array.emplace_back(color);
  677. }
  678. else
  679. {
  680. color_array.emplace_back(underwater);
  681. if (at_surface)
  682. {
  683. outside_z = water_height;
  684. }
  685. }
  686. vertex_array.emplace_back(inside_x, inside_y, inside_z);
  687. vertex_array.emplace_back(outside_x, outside_y, outside_z);
  688. coord_array.emplace_back(outside_x - start_x, 1.f);
  689. coord_array.emplace_back(outside_x - start_x, 0.f);
  690. inside_x += dx;
  691. inside_y += dy;
  692. outside_x += dx;
  693. outside_y += dy;
  694. }
  695. // Extra buffer for edge
  696. inside_x -= dx * LINE_WIDTH;
  697. inside_y -= dy * LINE_WIDTH;
  698. outside_x -= dx * LINE_WIDTH;
  699. outside_y -= dy * LINE_WIDTH;
  700. inside_z = land.resolveHeightRegion(inside_x, inside_y);
  701. outside_z = land.resolveHeightRegion(outside_x, outside_y);
  702. if (inside_z > water_height)
  703. {
  704. color_array.emplace_back(color);
  705. }
  706. else
  707. {
  708. color_array.emplace_back(underwater);
  709. if (at_surface)
  710. {
  711. inside_z = water_height;
  712. }
  713. }
  714. if (outside_z > water_height)
  715. {
  716. color_array.emplace_back(color);
  717. }
  718. else
  719. {
  720. color_array.emplace_back(underwater);
  721. if (at_surface)
  722. {
  723. outside_z = water_height;
  724. }
  725. }
  726. vertex_array.emplace_back(inside_x, inside_y, inside_z);
  727. vertex_array.emplace_back(outside_x, outside_y, outside_z);
  728. coord_array.emplace_back(outside_x - start_x, 1.f);
  729. coord_array.emplace_back(outside_x - start_x, 0.f);
  730. inside_x += dx * LINE_WIDTH;
  731. inside_y += dy * LINE_WIDTH;
  732. outside_x += dx * LINE_WIDTH;
  733. outside_y += dy * LINE_WIDTH;
  734. // Last edge is not drawn to the edge
  735. outside_z = land.resolveHeightRegion(outside_x, outside_y);
  736. if (outside_z > water_height)
  737. {
  738. color_array.emplace_back(color);
  739. if (at_surface)
  740. {
  741. inside_z = water_height;
  742. }
  743. }
  744. else
  745. {
  746. color_array.emplace_back(underwater);
  747. if (at_surface)
  748. {
  749. outside_z = water_height;
  750. }
  751. }
  752. vertex_array.emplace_back(outside_x, outside_y, outside_z);
  753. coord_array.emplace_back(outside_x - start_x, 0.f);
  754. }
  755. void LLViewerParcelOverlay::idleUpdate(bool force_update)
  756. {
  757. if (gGLManager.mIsDisabled)
  758. {
  759. return;
  760. }
  761. if (mOverlayTextureIdx >= 0 && !(mDirty && force_update))
  762. {
  763. // We are in the middle of updating the overlay texture
  764. gPipeline.markGLRebuild(this);
  765. LL_DEBUGS("MarkGLRebuild") << "Marked for GL rebuild: " << std::hex
  766. << (intptr_t)this << std::dec << LL_ENDL;
  767. return;
  768. }
  769. // Only if we are dirty and it has been a while since the last update.
  770. if (mDirty)
  771. {
  772. if (force_update || mTimeSinceLastUpdate.getElapsedTimeF32() > 4.f)
  773. {
  774. updateOverlayTexture();
  775. updatePropertyLines();
  776. mTimeSinceLastUpdate.reset();
  777. }
  778. }
  779. }
  780. void LLViewerParcelOverlay::resetCollisionBitmap()
  781. {
  782. mHasCollisions = false;
  783. mCollisionBitmap.clear();
  784. mCollisionBitmap.resize(mParcelGridsPerEdge * mParcelGridsPerEdge, 0);
  785. }
  786. void LLViewerParcelOverlay::readCollisionBitmap(U8* bitmap)
  787. {
  788. for (S32 y = 0; y < mParcelGridsPerEdge; ++y)
  789. {
  790. S32 line_offset = y * mParcelGridsPerEdge;
  791. S32 x = 0;
  792. while (x < mParcelGridsPerEdge)
  793. {
  794. U8 byte = bitmap[(x + line_offset) / 8];
  795. U8 mask = 1;
  796. for (S32 bit = 0; bit < 8; ++bit)
  797. {
  798. if (byte & mask)
  799. {
  800. mCollisionBitmap[x + line_offset] = true;
  801. mHasCollisions = true;
  802. }
  803. mask <<= 1;
  804. ++x;
  805. }
  806. }
  807. }
  808. }
  809. void LLViewerParcelOverlay::renderPropertyLines() const
  810. {
  811. if (!mVertexArray || !mColorArray)
  812. {
  813. return;
  814. }
  815. LLSurface& land = mRegion->getLand();
  816. LLGLSUIDefault gls_ui; // called from pipeline
  817. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  818. LLGLDepthTest mDepthTest(GL_TRUE);
  819. // Find camera height off the ground (not from zero)
  820. F32 ground_height_at_camera =
  821. land.resolveHeightGlobal(gAgent.getCameraPositionGlobal());
  822. F32 camera_z = gViewerCamera.getOrigin().mV[VZ];
  823. F32 camera_height = camera_z - ground_height_at_camera;
  824. camera_height = llclamp(camera_height, 0.f, 100.f);
  825. // Pull lines toward camera by 1 cm per meter off the ground.
  826. const LLVector3& CAMERA_AT = gViewerCamera.getAtAxis();
  827. F32 pull_toward_camera_scale = 0.01f * camera_height;
  828. LLVector3 pull_toward_camera = CAMERA_AT;
  829. pull_toward_camera *= -pull_toward_camera_scale;
  830. // Always fudge a little vertically.
  831. pull_toward_camera.mV[VZ] += 0.01f;
  832. gGL.matrixMode(LLRender::MM_MODELVIEW);
  833. gGL.pushMatrix();
  834. // Move to appropriate region coords
  835. LLVector3 origin = mRegion->getOriginAgent();
  836. gGL.translatef(origin.mV[VX], origin.mV[VY], origin.mV[VZ]);
  837. gGL.translatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY],
  838. pull_toward_camera.mV[VZ]);
  839. // Include +1 because vertices are fenceposts.
  840. // *2 because it is a quad strip
  841. constexpr S32 GRID_STEP = S32(PARCEL_GRID_STEP_METERS);
  842. constexpr S32 vertex_per_edge = 3 + 2 * (GRID_STEP - 1) + 3;
  843. // Stomp the camera into two dimensions
  844. LLVector3 camera_region =
  845. mRegion->getPosRegionFromGlobal(gAgent.getCameraPositionGlobal());
  846. // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
  847. // the camera. The cull plane normal is the camera's at axis.
  848. LLVector3 cull_plane_point = gViewerCamera.getAtAxis();
  849. cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
  850. cull_plane_point += camera_region;
  851. LLVector3 vertex;
  852. constexpr S32 BYTES_PER_COLOR = 4;
  853. constexpr S32 FLOATS_PER_VERTEX = 3;
  854. constexpr F32 PROPERTY_LINE_CLIP_DIST = 256.f;
  855. for (S32 i = 0; i < mVertexCount; i += vertex_per_edge)
  856. {
  857. U8* colorp = mColorArray + BYTES_PER_COLOR * i;
  858. F32* vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
  859. vertex.mV[VX] = *(vertexp);
  860. vertex.mV[VY] = *(vertexp + 1);
  861. vertex.mV[VZ] = *(vertexp + 2);
  862. if (dist_vec_squared2D(vertex, camera_region) >
  863. PROPERTY_LINE_CLIP_DIST * PROPERTY_LINE_CLIP_DIST)
  864. {
  865. continue;
  866. }
  867. // Destroy vertex, transform to plane-local.
  868. vertex -= cull_plane_point;
  869. // Negative dot product means it is in back of the plane
  870. if (vertex * CAMERA_AT < 0.f)
  871. {
  872. continue;
  873. }
  874. gGL.begin(LLRender::TRIANGLE_STRIP);
  875. for (S32 j = 0; j < vertex_per_edge; ++j)
  876. {
  877. gGL.color4ubv(colorp);
  878. gGL.vertex3fv(vertexp);
  879. colorp += BYTES_PER_COLOR;
  880. vertexp += FLOATS_PER_VERTEX;
  881. }
  882. gGL.end();
  883. if (LLSelectMgr::renderHiddenSelection() &&
  884. LLFloaterTools::isVisible())
  885. {
  886. LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
  887. colorp = mColorArray + BYTES_PER_COLOR * i;
  888. vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
  889. gGL.begin(LLRender::TRIANGLE_STRIP);
  890. for (S32 j = 0; j < vertex_per_edge; ++j)
  891. {
  892. U8 color[4];
  893. color[0] = colorp[0];
  894. color[1] = colorp[1];
  895. color[2] = colorp[2];
  896. color[3] = colorp[3] / 4;
  897. gGL.color4ubv(color);
  898. gGL.vertex3fv(vertexp);
  899. colorp += BYTES_PER_COLOR;
  900. vertexp += FLOATS_PER_VERTEX;
  901. }
  902. gGL.end();
  903. }
  904. }
  905. gGL.popMatrix();
  906. stop_glerror();
  907. }
  908. void LLViewerParcelOverlay::renderParcelBorders(F32 scale,
  909. const F32* color) const
  910. {
  911. LLVector3 origin_agent = mRegion->getOriginAgent();
  912. LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent();
  913. F32 region_left = rel_region_pos.mV[0] * scale;
  914. F32 region_bottom = rel_region_pos.mV[1] * scale;
  915. F32 map_parcel_width = PARCEL_GRID_STEP_METERS * scale;
  916. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  917. gGL.lineWidth(1.f);
  918. gGL.color4fv(color);
  919. gGL.begin(LLRender::LINES);
  920. F32 bottom = region_bottom;
  921. S32 line_offset = 0;
  922. for (S32 i = 0; i <= mParcelGridsPerEdge; ++i)
  923. {
  924. F32 left = region_left;
  925. U8 overlay;
  926. for (S32 j = 0; j <= mParcelGridsPerEdge; ++j)
  927. {
  928. bool south_limit = i == mParcelGridsPerEdge;
  929. bool west_limit = j == mParcelGridsPerEdge;
  930. if (south_limit || west_limit)
  931. {
  932. // This is the region boundary (out of mOwnership limits).
  933. overlay = 0;
  934. }
  935. else
  936. {
  937. overlay = mOwnership[line_offset + j];
  938. }
  939. // The property line vertices are three-dimensional, but here we
  940. // only care about the x and y coordinates, as we are drawing on a
  941. // 2D map.
  942. if (!south_limit && (west_limit || (overlay & PARCEL_WEST_LINE)))
  943. {
  944. // We have a left border: draw it
  945. gGL.vertex2f(left, bottom);
  946. gGL.vertex2f(left, bottom + map_parcel_width);
  947. }
  948. if (!west_limit && (south_limit || (overlay & PARCEL_SOUTH_LINE)))
  949. {
  950. // We have a bottom border: draw it
  951. gGL.vertex2f(left, bottom);
  952. gGL.vertex2f(left + map_parcel_width, bottom);
  953. }
  954. left += map_parcel_width;
  955. }
  956. bottom += map_parcel_width;
  957. line_offset += mParcelGridsPerEdge;
  958. }
  959. gGL.end();
  960. }
  961. bool LLViewerParcelOverlay::renderBannedParcels(F32 scale,
  962. const F32* color) const
  963. {
  964. if (!mHasCollisions)
  965. {
  966. // Nothing to render (no banned parcel info received so far). HB
  967. return false;
  968. }
  969. LLVector3 origin_agent = mRegion->getOriginAgent();
  970. LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent();
  971. F32 region_left = rel_region_pos.mV[0] * scale;
  972. F32 region_bottom = rel_region_pos.mV[1] * scale;
  973. F32 map_parcel_width = PARCEL_GRID_STEP_METERS * scale;
  974. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  975. gGL.color4fv(color);
  976. gGL.begin(LLRender::TRIANGLES);
  977. for (S32 y = 0; y < mParcelGridsPerEdge; ++y)
  978. {
  979. S32 line_offset = y * map_parcel_width;
  980. for (S32 x = 0; x < mParcelGridsPerEdge; ++x)
  981. {
  982. if (mCollisionBitmap[x + y * mParcelGridsPerEdge])
  983. {
  984. F32 left = region_left + x * map_parcel_width;
  985. F32 bottom = region_bottom + line_offset;
  986. F32 right = left + map_parcel_width;
  987. F32 top = bottom + map_parcel_width;
  988. gGL.vertex2f(left, top);
  989. gGL.vertex2f(left, bottom);
  990. gGL.vertex2f(right, top);
  991. gGL.vertex2f(right, top);
  992. gGL.vertex2f(left, bottom);
  993. gGL.vertex2f(right, bottom);
  994. }
  995. }
  996. }
  997. gGL.end();
  998. return true;
  999. }