aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerparceloverlay.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerparceloverlay.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewerparceloverlay.cpp')
-rw-r--r--linden/indra/newview/llviewerparceloverlay.cpp869
1 files changed, 869 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerparceloverlay.cpp b/linden/indra/newview/llviewerparceloverlay.cpp
new file mode 100644
index 0000000..91159f0
--- /dev/null
+++ b/linden/indra/newview/llviewerparceloverlay.cpp
@@ -0,0 +1,869 @@
1/**
2 * @file llviewerparceloverlay.cpp
3 * @brief LLViewerParcelOverlay class implementation
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llviewerparceloverlay.h"
31
32// indra includes
33#include "llparcel.h"
34#include "llgl.h"
35#include "v4color.h"
36#include "v2math.h"
37
38// newview includes
39#include "llviewerimage.h"
40#include "llviewercontrol.h"
41#include "llsurface.h"
42#include "llviewerregion.h"
43#include "llagent.h"
44#include "llviewercamera.h"
45#include "llviewerimagelist.h"
46#include "llglheaders.h"
47
48const U8 OVERLAY_IMG_COMPONENTS = 4;
49
50LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters)
51: mRegion( region ),
52 mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ),
53 mDirty( FALSE ),
54 mTimeSinceLastUpdate(),
55 mOverlayTextureIdx(-1),
56 mLineImageID( gViewerArt.getString("propertyline.tga") ),
57 mVertexCount(0),
58 mVertexArray(NULL),
59 mColorArray(NULL)
60// mTexCoordArray(NULL),
61{
62 // Create a texture to hold color information.
63 // 4 components
64 // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges
65 mTexture = new LLImageGL(FALSE);
66 mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS);
67 mTexture->createGLTexture(0, mImageRaw);
68 glActiveTextureARB(GL_TEXTURE0_ARB);
69 mTexture->bind(0);
70 mTexture->setClamp(TRUE, TRUE);
71 mTexture->setMipFilterNearest(TRUE);
72
73 //
74 // Initialize the GL texture with empty data.
75 //
76 // Create the base texture.
77 U8 *raw = mImageRaw->getData();
78 const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS;
79 for (S32 i = 0; i < COUNT; i++)
80 {
81 raw[i] = 0;
82 }
83 mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
84
85 // Create storage for ownership information from simulator
86 // and initialize it.
87 mOwnership = new U8[ mParcelGridsPerEdge * mParcelGridsPerEdge ];
88 for (S32 i = 0; i < mParcelGridsPerEdge * mParcelGridsPerEdge; i++)
89 {
90 mOwnership[i] = PARCEL_PUBLIC;
91 }
92
93 // Make sure the texture matches the ownership information.
94 updateOverlayTexture();
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::isSoundLocal(const LLVector3& pos) const
149{
150 S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
151 S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
152 return PARCEL_SOUND_LOCAL & mOwnership[row * mParcelGridsPerEdge + column];
153}
154
155U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
156{
157 S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
158 S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
159 return ownership(row, column);
160}
161
162F32 LLViewerParcelOverlay::getOwnedRatio() const
163{
164 S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
165 S32 total = 0;
166
167 for (S32 i = 0; i < size; i++)
168 {
169 if ((mOwnership[i] & PARCEL_COLOR_MASK) != PARCEL_PUBLIC)
170 {
171 total++;
172 }
173 }
174
175 return (F32)total / (F32)size;
176
177}
178
179//---------------------------------------------------------------------------
180// MANIPULATORS
181//---------------------------------------------------------------------------
182
183// Color tables for owned land
184// Available = index 0
185// Other = index 1
186// Group = index 2
187// Self = index 3
188
189// Make sure the texture colors match the ownership data.
190// Note: Assumes that the ownership array and
191void LLViewerParcelOverlay::updateOverlayTexture()
192{
193 if (mOverlayTextureIdx < 0 && mDirty)
194 {
195 mOverlayTextureIdx = 0;
196 }
197 if (mOverlayTextureIdx < 0)
198 {
199 return;
200 }
201 // Can do this because gColors are actually stored as LLColor4U
202 const LLColor4U avail = gColors.getColor4U("PropertyColorAvail");
203 const LLColor4U owned = gColors.getColor4U("PropertyColorOther");
204 const LLColor4U group = gColors.getColor4U("PropertyColorGroup");
205 const LLColor4U self = gColors.getColor4U("PropertyColorSelf");
206 const LLColor4U for_sale = gColors.getColor4U("PropertyColorForSale");
207 const LLColor4U auction = gColors.getColor4U("PropertyColorAuction");
208
209 // Create the base texture.
210 U8 *raw = mImageRaw->getData();
211 const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge;
212 S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
213 if (max > COUNT) max = COUNT;
214 S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS;
215 S32 i;
216 for (i = mOverlayTextureIdx; i < max; i++)
217 {
218 U8 ownership = mOwnership[i];
219
220 U8 r,g,b,a;
221
222 // Color stored in low three bits
223 switch( ownership & 0x7 )
224 {
225 case PARCEL_PUBLIC:
226 r = avail.mV[VRED];
227 g = avail.mV[VGREEN];
228 b = avail.mV[VBLUE];
229 a = avail.mV[VALPHA];
230 break;
231 case PARCEL_OWNED:
232 r = owned.mV[VRED];
233 g = owned.mV[VGREEN];
234 b = owned.mV[VBLUE];
235 a = owned.mV[VALPHA];
236 break;
237 case PARCEL_GROUP:
238 r = group.mV[VRED];
239 g = group.mV[VGREEN];
240 b = group.mV[VBLUE];
241 a = group.mV[VALPHA];
242 break;
243 case PARCEL_SELF:
244 r = self.mV[VRED];
245 g = self.mV[VGREEN];
246 b = self.mV[VBLUE];
247 a = self.mV[VALPHA];
248 break;
249 case PARCEL_FOR_SALE:
250 r = for_sale.mV[VRED];
251 g = for_sale.mV[VGREEN];
252 b = for_sale.mV[VBLUE];
253 a = for_sale.mV[VALPHA];
254 break;
255 case PARCEL_AUCTION:
256 r = auction.mV[VRED];
257 g = auction.mV[VGREEN];
258 b = auction.mV[VBLUE];
259 a = auction.mV[VALPHA];
260 break;
261 default:
262 r = self.mV[VRED];
263 g = self.mV[VGREEN];
264 b = self.mV[VBLUE];
265 a = self.mV[VALPHA];
266 break;
267 }
268
269 raw[pixel_index + 0] = r;
270 raw[pixel_index + 1] = g;
271 raw[pixel_index + 2] = b;
272 raw[pixel_index + 3] = a;
273
274 pixel_index += OVERLAY_IMG_COMPONENTS;
275 }
276
277 // Copy data into GL texture from raw data
278 if (i >= COUNT)
279 {
280 mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
281 mOverlayTextureIdx = -1;
282 }
283 else
284 {
285 mOverlayTextureIdx = i;
286 }
287}
288
289
290void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay)
291{
292 // Unpack the message data into the ownership array
293 S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
294 S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS;
295
296 memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size);
297
298 // Force property lines and overlay texture to update
299 setDirty();
300}
301
302
303void LLViewerParcelOverlay::updatePropertyLines()
304{
305 if (!gSavedSettings.getBOOL("ShowPropertyLines"))
306 return;
307
308 S32 row, col;
309
310 // Can do this because gColors are actually stored as LLColor4U
311 const LLColor4U self_coloru = gColors.getColor4U("PropertyColorSelf");
312 const LLColor4U other_coloru = gColors.getColor4U("PropertyColorOther");
313 const LLColor4U group_coloru = gColors.getColor4U("PropertyColorGroup");
314 const LLColor4U for_sale_coloru = gColors.getColor4U("PropertyColorForSale");
315 const LLColor4U auction_coloru = gColors.getColor4U("PropertyColorAuction");
316
317 // Build into dynamic arrays, then copy into static arrays.
318 LLDynamicArray<LLVector3, 256> new_vertex_array;
319 LLDynamicArray<LLColor4U, 256> new_color_array;
320 LLDynamicArray<LLVector2, 256> new_coord_array;
321
322 U8 overlay = 0;
323 BOOL add_edge = FALSE;
324 const F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
325 const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
326
327 for (row = 0; row < GRIDS_PER_EDGE; row++)
328 {
329 for (col = 0; col < GRIDS_PER_EDGE; col++)
330 {
331 overlay = mOwnership[row*GRIDS_PER_EDGE+col];
332
333 F32 left = col*GRID_STEP;
334 F32 right = left+GRID_STEP;
335
336 F32 bottom = row*GRID_STEP;
337 F32 top = bottom+GRID_STEP;
338
339 // West edge
340 if (overlay & PARCEL_WEST_LINE)
341 {
342 switch(overlay & PARCEL_COLOR_MASK)
343 {
344 case PARCEL_SELF:
345 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
346 left, bottom, WEST, self_coloru);
347 break;
348 case PARCEL_GROUP:
349 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
350 left, bottom, WEST, group_coloru);
351 break;
352 case PARCEL_OWNED:
353 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
354 left, bottom, WEST, other_coloru);
355 break;
356 case PARCEL_FOR_SALE:
357 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
358 left, bottom, WEST, for_sale_coloru);
359 break;
360 case PARCEL_AUCTION:
361 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
362 left, bottom, WEST, auction_coloru);
363 break;
364 default:
365 break;
366 }
367 }
368
369 // East edge
370 if (col < GRIDS_PER_EDGE-1)
371 {
372 U8 east_overlay = mOwnership[row*GRIDS_PER_EDGE+col+1];
373 add_edge = east_overlay & PARCEL_WEST_LINE;
374 }
375 else
376 {
377 add_edge = TRUE;
378 }
379
380 if (add_edge)
381 {
382 switch(overlay & PARCEL_COLOR_MASK)
383 {
384 case PARCEL_SELF:
385 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
386 right, bottom, EAST, self_coloru);
387 break;
388 case PARCEL_GROUP:
389 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
390 right, bottom, EAST, group_coloru);
391 break;
392 case PARCEL_OWNED:
393 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
394 right, bottom, EAST, other_coloru);
395 break;
396 case PARCEL_FOR_SALE:
397 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
398 right, bottom, EAST, for_sale_coloru);
399 break;
400 case PARCEL_AUCTION:
401 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
402 right, bottom, EAST, auction_coloru);
403 break;
404 default:
405 break;
406 }
407 }
408
409 // South edge
410 if (overlay & PARCEL_SOUTH_LINE)
411 {
412 switch(overlay & PARCEL_COLOR_MASK)
413 {
414 case PARCEL_SELF:
415 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
416 left, bottom, SOUTH, self_coloru);
417 break;
418 case PARCEL_GROUP:
419 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
420 left, bottom, SOUTH, group_coloru);
421 break;
422 case PARCEL_OWNED:
423 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
424 left, bottom, SOUTH, other_coloru);
425 break;
426 case PARCEL_FOR_SALE:
427 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
428 left, bottom, SOUTH, for_sale_coloru);
429 break;
430 case PARCEL_AUCTION:
431 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
432 left, bottom, SOUTH, auction_coloru);
433 break;
434 default:
435 break;
436 }
437 }
438
439
440 // North edge
441 if (row < GRIDS_PER_EDGE-1)
442 {
443 U8 north_overlay = mOwnership[(row+1)*GRIDS_PER_EDGE+col];
444 add_edge = north_overlay & PARCEL_SOUTH_LINE;
445 }
446 else
447 {
448 add_edge = TRUE;
449 }
450
451 if (add_edge)
452 {
453 switch(overlay & PARCEL_COLOR_MASK)
454 {
455 case PARCEL_SELF:
456 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
457 left, top, NORTH, self_coloru);
458 break;
459 case PARCEL_GROUP:
460 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
461 left, top, NORTH, group_coloru);
462 break;
463 case PARCEL_OWNED:
464 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
465 left, top, NORTH, other_coloru);
466 break;
467 case PARCEL_FOR_SALE:
468 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
469 left, top, NORTH, for_sale_coloru);
470 break;
471 case PARCEL_AUCTION:
472 addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
473 left, top, NORTH, auction_coloru);
474 break;
475 default:
476 break;
477 }
478 }
479 }
480 }
481
482 // Now copy into static arrays for faster rendering.
483 // Attempt to recycle old arrays if possible to avoid memory
484 // shuffling.
485 S32 new_vertex_count = new_vertex_array.count();
486
487 // NOTE: If the new_vertex_count is 0 and wasn't 0 previously
488 // the arrays are still allocated as the arrays aren't set to NULL, etc.
489 // This won't cause any problems, but might waste a few cycles copying over
490 // old data. - jwolk
491 if ( !(mVertexArray && mColorArray && new_vertex_count == mVertexCount) && new_vertex_count > 0 )
492 {
493 // ...need new arrays
494 delete[] mVertexArray;
495 delete[] mColorArray;
496
497 mVertexCount = new_vertex_count;
498
499 mVertexArray = new F32[3 * mVertexCount];
500 mColorArray = new U8 [4 * mVertexCount];
501 }
502
503 // Copy the new data into the arrays
504 S32 i;
505 F32* vertex = mVertexArray;
506 for (i = 0; i < mVertexCount; i++)
507 {
508 const LLVector3& point = new_vertex_array.get(i);
509 *vertex = point.mV[VX];
510 vertex++;
511 *vertex = point.mV[VY];
512 vertex++;
513 *vertex = point.mV[VZ];
514 vertex++;
515 }
516
517 U8* colorp = mColorArray;
518 for (i = 0; i < mVertexCount; i++)
519 {
520 const LLColor4U& color = new_color_array.get(i);
521 *colorp = color.mV[VRED];
522 colorp++;
523 *colorp = color.mV[VGREEN];
524 colorp++;
525 *colorp = color.mV[VBLUE];
526 colorp++;
527 *colorp = color.mV[VALPHA];
528 colorp++;
529 }
530
531 // Everything's clean now
532 mDirty = FALSE;
533}
534
535
536void LLViewerParcelOverlay::addPropertyLine(
537 LLDynamicArray<LLVector3, 256>& vertex_array,
538 LLDynamicArray<LLColor4U, 256>& color_array,
539 LLDynamicArray<LLVector2, 256>& coord_array,
540 const F32 start_x, const F32 start_y,
541 const U32 edge,
542 const LLColor4U& color)
543{
544 LLColor4U underwater( color );
545 underwater.mV[VALPHA] /= 2;
546
547 LLSurface& land = mRegion->getLand();
548
549 F32 dx;
550 F32 dy;
551 F32 tick_dx;
552 F32 tick_dy;
553 //const F32 LINE_WIDTH = 0.125f;
554 const F32 LINE_WIDTH = 0.0625f;
555
556 switch(edge)
557 {
558 case WEST:
559 dx = 0.f;
560 dy = 1.f;
561 tick_dx = LINE_WIDTH;
562 tick_dy = 0.f;
563 break;
564
565 case EAST:
566 dx = 0.f;
567 dy = 1.f;
568 tick_dx = -LINE_WIDTH;
569 tick_dy = 0.f;
570 break;
571
572 case NORTH:
573 dx = 1.f;
574 dy = 0.f;
575 tick_dx = 0.f;
576 tick_dy = -LINE_WIDTH;
577 break;
578
579 case SOUTH:
580 dx = 1.f;
581 dy = 0.f;
582 tick_dx = 0.f;
583 tick_dy = LINE_WIDTH;
584 break;
585
586 default:
587 llerrs << "Invalid edge in addPropertyLine" << llendl;
588 return;
589 }
590
591 F32 outside_x = start_x;
592 F32 outside_y = start_y;
593 F32 outside_z = 0.f;
594 F32 inside_x = start_x + tick_dx;
595 F32 inside_y = start_y + tick_dy;
596 F32 inside_z = 0.f;
597
598 // First part, only one vertex
599 outside_z = land.resolveHeightRegion( outside_x, outside_y );
600
601 if (outside_z > 20.f) color_array.put( color );
602 else color_array.put( underwater );
603
604 vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
605 coord_array.put( LLVector2(outside_x - start_x, 0.f) );
606
607 inside_x += dx * LINE_WIDTH;
608 inside_y += dy * LINE_WIDTH;
609
610 outside_x += dx * LINE_WIDTH;
611 outside_y += dy * LINE_WIDTH;
612
613 // Then the "actual edge"
614 inside_z = land.resolveHeightRegion( inside_x, inside_y );
615 outside_z = land.resolveHeightRegion( outside_x, outside_y );
616
617 if (inside_z > 20.f) color_array.put( color );
618 else color_array.put( underwater );
619
620 if (outside_z > 20.f) color_array.put( color );
621 else color_array.put( underwater );
622
623 vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
624 vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
625
626 coord_array.put( LLVector2(outside_x - start_x, 1.f) );
627 coord_array.put( LLVector2(outside_x - start_x, 0.f) );
628
629 inside_x += dx * (dx - LINE_WIDTH);
630 inside_y += dy * (dy - LINE_WIDTH);
631
632 outside_x += dx * (dx - LINE_WIDTH);
633 outside_y += dy * (dy - LINE_WIDTH);
634
635 // Middle part, full width
636 S32 i;
637 const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
638 for (i = 1; i < GRID_STEP; i++)
639 {
640 inside_z = land.resolveHeightRegion( inside_x, inside_y );
641 outside_z = land.resolveHeightRegion( outside_x, outside_y );
642
643 if (inside_z > 20.f) color_array.put( color );
644 else color_array.put( underwater );
645
646 if (outside_z > 20.f) color_array.put( color );
647 else color_array.put( underwater );
648
649 vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
650 vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
651
652 coord_array.put( LLVector2(outside_x - start_x, 1.f) );
653 coord_array.put( LLVector2(outside_x - start_x, 0.f) );
654
655 inside_x += dx;
656 inside_y += dy;
657
658 outside_x += dx;
659 outside_y += dy;
660 }
661
662 // Extra buffer for edge
663 inside_x -= dx * LINE_WIDTH;
664 inside_y -= dy * LINE_WIDTH;
665
666 outside_x -= dx * LINE_WIDTH;
667 outside_y -= dy * LINE_WIDTH;
668
669 inside_z = land.resolveHeightRegion( inside_x, inside_y );
670 outside_z = land.resolveHeightRegion( outside_x, outside_y );
671
672 if (inside_z > 20.f) color_array.put( color );
673 else color_array.put( underwater );
674
675 if (outside_z > 20.f) color_array.put( color );
676 else color_array.put( underwater );
677
678 vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
679 vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
680
681 coord_array.put( LLVector2(outside_x - start_x, 1.f) );
682 coord_array.put( LLVector2(outside_x - start_x, 0.f) );
683
684 inside_x += dx * LINE_WIDTH;
685 inside_y += dy * LINE_WIDTH;
686
687 outside_x += dx * LINE_WIDTH;
688 outside_y += dy * LINE_WIDTH;
689
690 // Last edge is not drawn to the edge
691 outside_z = land.resolveHeightRegion( outside_x, outside_y );
692
693 if (outside_z > 20.f) color_array.put( color );
694 else color_array.put( underwater );
695
696 vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
697 coord_array.put( LLVector2(outside_x - start_x, 0.f) );
698}
699
700
701void LLViewerParcelOverlay::setDirty()
702{
703 mDirty = TRUE;
704}
705
706void LLViewerParcelOverlay::idleUpdate(bool force_update)
707{
708 if (gGLManager.mIsDisabled)
709 {
710 return;
711 }
712 if (mOverlayTextureIdx >= 0 && (!(mDirty && force_update)))
713 {
714 // We are in the middle of updating the overlay texture
715 updateOverlayTexture();
716 return;
717 }
718 // Only if we're dirty and it's been a while since the last update.
719 if (mDirty)
720 {
721 if (force_update || mTimeSinceLastUpdate.getElapsedTimeF32() > 4.0f)
722 {
723 updateOverlayTexture();
724 updatePropertyLines();
725 mTimeSinceLastUpdate.reset();
726 }
727 }
728}
729
730S32 LLViewerParcelOverlay::renderPropertyLines ()
731{
732 if (!gSavedSettings.getBOOL("ShowPropertyLines"))
733 {
734 return 0;
735 }
736 if (!mVertexArray || !mColorArray)
737 {
738 return 0;
739 }
740
741 LLSurface& land = mRegion->getLand();
742
743 LLGLSUIDefault gls_ui; // called from pipeline
744 LLGLSNoTexture gls_no_texture;
745 LLGLDepthTest mDepthTest(GL_TRUE);
746
747 // JC - This doesn't work.
748 //gGLSUITextureDepth.set();
749 //LLViewerImage* image = gImageList.getImage( mLineImageID );
750 //image->bindTexture();
751
752 // Find camera height off the ground (not from zero)
753 F32 ground_height_at_camera = land.resolveHeightGlobal( gAgent.getCameraPositionGlobal() );
754 F32 camera_z = gCamera->getOrigin().mV[VZ];
755 F32 camera_height = camera_z - ground_height_at_camera;
756
757 camera_height = llclamp(camera_height, 0.f, 100.f);
758
759 // Pull lines toward camera by 1 cm per meter off the ground.
760 const LLVector3& CAMERA_AT = gCamera->getAtAxis();
761 F32 pull_toward_camera_scale = 0.01f * camera_height;
762 LLVector3 pull_toward_camera = CAMERA_AT;
763 pull_toward_camera *= -pull_toward_camera_scale;
764
765 // Always fudge a little vertically.
766 pull_toward_camera.mV[VZ] += 0.01f;
767
768 glMatrixMode( GL_MODELVIEW );
769 glPushMatrix();
770
771 // Move to appropriate region coords
772 LLVector3 origin = mRegion->getOriginAgent();
773 glTranslatef( origin.mV[VX], origin.mV[VY], origin.mV[VZ] );
774
775 glTranslatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY],
776 pull_toward_camera.mV[VZ]);
777
778 // Include +1 because vertices are fenceposts.
779 // *2 because it's a quad strip
780 const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
781 const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3;
782
783 /* JC - Don't do this. Unbinding AGP stalls the draw process,
784 dropping frame rate. Not unbinding AGP causes random crashes
785 on nVidia cards due to binding non-AGP arrays.
786
787 gPipeline.unbindAGP();
788 glEnableClientState(GL_VERTEX_ARRAY);
789 glEnableClientState(GL_COLOR_ARRAY);
790 glVertexPointer(3, GL_FLOAT, 0, mVertexArray );
791 glColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColorArray );
792
793 S32 i;
794 for (i = 0; i < mVertexCount; i += vertex_per_edge)
795 {
796 // Each edge is several vertices
797 glDrawArrays(GL_LINE_STRIP, i, vertex_per_edge);
798 }
799
800 glDisableClientState(GL_COLOR_ARRAY);
801 glDisableClientState(GL_VERTEX_ARRAY);
802 */
803
804 // Stomp the camera into two dimensions
805 LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgent.getCameraPositionGlobal() );
806
807 // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
808 // the camera. The cull plane normal is the camera's at axis.
809 LLVector3 cull_plane_point = gCamera->getAtAxis();
810 cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
811 cull_plane_point += camera_region;
812
813 LLVector3 vertex;
814
815 const S32 BYTES_PER_COLOR = 4;
816 const S32 FLOATS_PER_VERTEX = 3;
817 //const S32 FLOATS_PER_TEX_COORD = 2;
818 S32 i, j;
819 S32 drawn = 0;
820 F32* vertexp;
821 U8* colorp;
822
823 const F32 PROPERTY_LINE_CLIP_DIST = 256.f;
824
825 for (i = 0; i < mVertexCount; i += vertex_per_edge)
826 {
827 colorp = mColorArray + BYTES_PER_COLOR * i;
828 vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
829
830 vertex.mV[VX] = *(vertexp);
831 vertex.mV[VY] = *(vertexp+1);
832 vertex.mV[VZ] = *(vertexp+2);
833
834 if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST*PROPERTY_LINE_CLIP_DIST)
835 {
836 continue;
837 }
838
839 // Destroy vertex, transform to plane-local.
840 vertex -= cull_plane_point;
841
842 // negative dot product means it is in back of the plane
843 if ( vertex * CAMERA_AT < 0.f )
844 {
845 continue;
846 }
847
848 glBegin(GL_TRIANGLE_STRIP);
849
850 for (j = 0; j < vertex_per_edge; j++)
851 {
852 // JC - This doesn't work
853 //glTexCoord2fv(mTexCoordArray + FLOATS_PER_TEX_COORD*offset);
854 glColor4ubv(colorp);
855 glVertex3fv(vertexp);
856
857 colorp += BYTES_PER_COLOR;
858 vertexp += FLOATS_PER_VERTEX;
859 }
860
861 drawn += vertex_per_edge;
862
863 glEnd();
864 }
865
866 glPopMatrix();
867
868 return drawn;
869}