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