summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerparceloverlay.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llviewerparceloverlay.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llviewerparceloverlay.cpp')
-rw-r--r--indra/newview/llviewerparceloverlay.cpp850
1 files changed, 850 insertions, 0 deletions
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
new file mode 100644
index 0000000000..2c04c073db
--- /dev/null
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -0,0 +1,850 @@
+/**
+ * @file llviewerparceloverlay.cpp
+ * @brief LLViewerParcelOverlay class implementation
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerparceloverlay.h"
+
+// indra includes
+#include "llparcel.h"
+#include "llgl.h"
+#include "v4color.h"
+#include "v2math.h"
+
+// newview includes
+#include "llviewerimage.h"
+#include "llviewercontrol.h"
+#include "llsurface.h"
+#include "llviewerregion.h"
+#include "llagent.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h"
+#include "llglheaders.h"
+
+const U8 OVERLAY_IMG_COMPONENTS = 4;
+
+LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters)
+: mRegion( region ),
+ mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ),
+ mDirty( FALSE ),
+ mTimeSinceLastUpdate(),
+ mOverlayTextureIdx(-1),
+ mLineImageID( gViewerArt.getString("propertyline.tga") ),
+ mVertexCount(0),
+ mVertexArray(NULL),
+ mColorArray(NULL)
+// mTexCoordArray(NULL),
+{
+ // Create a texture to hold color information.
+ // 4 components
+ // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges
+ mTexture = new LLImageGL(FALSE);
+ mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS);
+ mTexture->createGLTexture(0, mImageRaw);
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ mTexture->bind(0);
+ mTexture->setClamp(TRUE, TRUE);
+ mTexture->setMipFilterNearest(TRUE);
+
+ //
+ // Initialize the GL texture with empty data.
+ //
+ // Create the base texture.
+ U8 *raw = mImageRaw->getData();
+ const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS;
+ for (S32 i = 0; i < COUNT; i++)
+ {
+ raw[i] = 0;
+ }
+ mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
+
+ // Create storage for ownership information from simulator
+ // and initialize it.
+ mOwnership = new U8[ mParcelGridsPerEdge * mParcelGridsPerEdge ];
+ for (S32 i = 0; i < mParcelGridsPerEdge * mParcelGridsPerEdge; i++)
+ {
+ mOwnership[i] = PARCEL_PUBLIC;
+ }
+
+ // Make sure the texture matches the ownership information.
+ updateOverlayTexture();
+}
+
+
+LLViewerParcelOverlay::~LLViewerParcelOverlay()
+{
+ delete[] mOwnership;
+ mOwnership = NULL;
+
+ delete[] mVertexArray;
+ mVertexArray = NULL;
+
+ delete[] mColorArray;
+ mColorArray = NULL;
+
+// JC No textures.
+// delete mTexCoordArray;
+// mTexCoordArray = NULL;
+
+ mImageRaw = NULL;
+}
+
+//---------------------------------------------------------------------------
+// ACCESSORS
+//---------------------------------------------------------------------------
+BOOL LLViewerParcelOverlay::isOwned(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return (PARCEL_PUBLIC != ownership(row, column));
+}
+
+BOOL LLViewerParcelOverlay::isOwnedSelf(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return (PARCEL_SELF == ownership(row, column));
+}
+
+BOOL LLViewerParcelOverlay::isOwnedGroup(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return (PARCEL_GROUP == ownership(row, column));
+}
+
+BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ U8 overlay = ownership(row, column);
+ return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay);
+}
+
+BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return PARCEL_SOUND_LOCAL & mOwnership[row * mParcelGridsPerEdge + column];
+}
+
+U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
+{
+ S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+ S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+ return ownership(row, column);
+}
+
+F32 LLViewerParcelOverlay::getOwnedRatio() const
+{
+ S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
+ S32 total = 0;
+
+ for (S32 i = 0; i < size; i++)
+ {
+ if ((mOwnership[i] & PARCEL_COLOR_MASK) != PARCEL_PUBLIC)
+ {
+ total++;
+ }
+ }
+
+ return (F32)total / (F32)size;
+
+}
+
+//---------------------------------------------------------------------------
+// MANIPULATORS
+//---------------------------------------------------------------------------
+
+// Color tables for owned land
+// Available = index 0
+// Other = index 1
+// Group = index 2
+// Self = index 3
+
+// Make sure the texture colors match the ownership data.
+// Note: Assumes that the ownership array and
+void LLViewerParcelOverlay::updateOverlayTexture()
+{
+ if (mOverlayTextureIdx < 0 && mDirty)
+ {
+ mOverlayTextureIdx = 0;
+ }
+ if (mOverlayTextureIdx < 0)
+ {
+ return;
+ }
+ // Can do this because gColors are actually stored as LLColor4U
+ const LLColor4U avail = gColors.getColor4U("PropertyColorAvail");
+ const LLColor4U owned = gColors.getColor4U("PropertyColorOther");
+ const LLColor4U group = gColors.getColor4U("PropertyColorGroup");
+ const LLColor4U self = gColors.getColor4U("PropertyColorSelf");
+ const LLColor4U for_sale = gColors.getColor4U("PropertyColorForSale");
+ const LLColor4U auction = gColors.getColor4U("PropertyColorAuction");
+
+ // Create the base texture.
+ U8 *raw = mImageRaw->getData();
+ const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge;
+ S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
+ if (max > COUNT) max = COUNT;
+ S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS;
+ S32 i;
+ for (i = mOverlayTextureIdx; i < max; i++)
+ {
+ U8 ownership = mOwnership[i];
+
+ U8 r,g,b,a;
+
+ // Color stored in low three bits
+ switch( ownership & 0x7 )
+ {
+ case PARCEL_PUBLIC:
+ r = avail.mV[VRED];
+ g = avail.mV[VGREEN];
+ b = avail.mV[VBLUE];
+ a = avail.mV[VALPHA];
+ break;
+ case PARCEL_OWNED:
+ r = owned.mV[VRED];
+ g = owned.mV[VGREEN];
+ b = owned.mV[VBLUE];
+ a = owned.mV[VALPHA];
+ break;
+ case PARCEL_GROUP:
+ r = group.mV[VRED];
+ g = group.mV[VGREEN];
+ b = group.mV[VBLUE];
+ a = group.mV[VALPHA];
+ break;
+ case PARCEL_SELF:
+ r = self.mV[VRED];
+ g = self.mV[VGREEN];
+ b = self.mV[VBLUE];
+ a = self.mV[VALPHA];
+ break;
+ case PARCEL_FOR_SALE:
+ r = for_sale.mV[VRED];
+ g = for_sale.mV[VGREEN];
+ b = for_sale.mV[VBLUE];
+ a = for_sale.mV[VALPHA];
+ break;
+ case PARCEL_AUCTION:
+ r = auction.mV[VRED];
+ g = auction.mV[VGREEN];
+ b = auction.mV[VBLUE];
+ a = auction.mV[VALPHA];
+ break;
+ default:
+ r = self.mV[VRED];
+ g = self.mV[VGREEN];
+ b = self.mV[VBLUE];
+ a = self.mV[VALPHA];
+ break;
+ }
+
+ raw[pixel_index + 0] = r;
+ raw[pixel_index + 1] = g;
+ raw[pixel_index + 2] = b;
+ raw[pixel_index + 3] = a;
+
+ pixel_index += OVERLAY_IMG_COMPONENTS;
+ }
+
+ // Copy data into GL texture from raw data
+ if (i >= COUNT)
+ {
+ mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
+ mOverlayTextureIdx = -1;
+ }
+ else
+ {
+ mOverlayTextureIdx = i;
+ }
+}
+
+
+void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay)
+{
+ // Unpack the message data into the ownership array
+ S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
+ S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS;
+
+ memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size);
+
+ // Force property lines and overlay texture to update
+ setDirty();
+}
+
+
+void LLViewerParcelOverlay::updatePropertyLines()
+{
+ if (!gSavedSettings.getBOOL("ShowPropertyLines"))
+ return;
+
+ S32 row, col;
+
+ // Can do this because gColors are actually stored as LLColor4U
+ const LLColor4U self_coloru = gColors.getColor4U("PropertyColorSelf");
+ const LLColor4U other_coloru = gColors.getColor4U("PropertyColorOther");
+ const LLColor4U group_coloru = gColors.getColor4U("PropertyColorGroup");
+ const LLColor4U for_sale_coloru = gColors.getColor4U("PropertyColorForSale");
+ const LLColor4U auction_coloru = gColors.getColor4U("PropertyColorAuction");
+
+ // Build into dynamic arrays, then copy into static arrays.
+ LLDynamicArray<LLVector3, 256> new_vertex_array;
+ LLDynamicArray<LLColor4U, 256> new_color_array;
+ LLDynamicArray<LLVector2, 256> new_coord_array;
+
+ U8 overlay = 0;
+ BOOL add_edge = FALSE;
+ const F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
+ const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
+
+ for (row = 0; row < GRIDS_PER_EDGE; row++)
+ {
+ for (col = 0; col < GRIDS_PER_EDGE; col++)
+ {
+ overlay = mOwnership[row*GRIDS_PER_EDGE+col];
+
+ F32 left = col*GRID_STEP;
+ F32 right = left+GRID_STEP;
+
+ F32 bottom = row*GRID_STEP;
+ F32 top = bottom+GRID_STEP;
+
+ // West edge
+ if (overlay & PARCEL_WEST_LINE)
+ {
+ switch(overlay & PARCEL_COLOR_MASK)
+ {
+ case PARCEL_SELF:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, WEST, self_coloru);
+ break;
+ case PARCEL_GROUP:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, WEST, group_coloru);
+ break;
+ case PARCEL_OWNED:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, WEST, other_coloru);
+ break;
+ case PARCEL_FOR_SALE:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, WEST, for_sale_coloru);
+ break;
+ case PARCEL_AUCTION:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, WEST, auction_coloru);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // East edge
+ if (col < GRIDS_PER_EDGE-1)
+ {
+ U8 east_overlay = mOwnership[row*GRIDS_PER_EDGE+col+1];
+ add_edge = east_overlay & PARCEL_WEST_LINE;
+ }
+ else
+ {
+ add_edge = TRUE;
+ }
+
+ if (add_edge)
+ {
+ switch(overlay & PARCEL_COLOR_MASK)
+ {
+ case PARCEL_SELF:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ right, bottom, EAST, self_coloru);
+ break;
+ case PARCEL_GROUP:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ right, bottom, EAST, group_coloru);
+ break;
+ case PARCEL_OWNED:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ right, bottom, EAST, other_coloru);
+ break;
+ case PARCEL_FOR_SALE:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ right, bottom, EAST, for_sale_coloru);
+ break;
+ case PARCEL_AUCTION:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ right, bottom, EAST, auction_coloru);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // South edge
+ if (overlay & PARCEL_SOUTH_LINE)
+ {
+ switch(overlay & PARCEL_COLOR_MASK)
+ {
+ case PARCEL_SELF:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, SOUTH, self_coloru);
+ break;
+ case PARCEL_GROUP:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, SOUTH, group_coloru);
+ break;
+ case PARCEL_OWNED:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, SOUTH, other_coloru);
+ break;
+ case PARCEL_FOR_SALE:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, SOUTH, for_sale_coloru);
+ break;
+ case PARCEL_AUCTION:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, bottom, SOUTH, auction_coloru);
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ // North edge
+ if (row < GRIDS_PER_EDGE-1)
+ {
+ U8 north_overlay = mOwnership[(row+1)*GRIDS_PER_EDGE+col];
+ add_edge = north_overlay & PARCEL_SOUTH_LINE;
+ }
+ else
+ {
+ add_edge = TRUE;
+ }
+
+ if (add_edge)
+ {
+ switch(overlay & PARCEL_COLOR_MASK)
+ {
+ case PARCEL_SELF:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, top, NORTH, self_coloru);
+ break;
+ case PARCEL_GROUP:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, top, NORTH, group_coloru);
+ break;
+ case PARCEL_OWNED:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, top, NORTH, other_coloru);
+ break;
+ case PARCEL_FOR_SALE:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, top, NORTH, for_sale_coloru);
+ break;
+ case PARCEL_AUCTION:
+ addPropertyLine(new_vertex_array, new_color_array, new_coord_array,
+ left, top, NORTH, auction_coloru);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Now copy into static arrays for faster rendering.
+ // Attempt to recycle old arrays if possible to avoid memory
+ // shuffling.
+ S32 new_vertex_count = new_vertex_array.count();
+
+ // NOTE: If the new_vertex_count is 0 and wasn't 0 previously
+ // the arrays are still allocated as the arrays aren't set to NULL, etc.
+ // This won't cause any problems, but might waste a few cycles copying over
+ // old data. - jwolk
+ if ( !(mVertexArray && mColorArray && new_vertex_count == mVertexCount) && new_vertex_count > 0 )
+ {
+ // ...need new arrays
+ delete[] mVertexArray;
+ delete[] mColorArray;
+
+ mVertexCount = new_vertex_count;
+
+ mVertexArray = new F32[3 * mVertexCount];
+ mColorArray = new U8 [4 * mVertexCount];
+ }
+
+ // Copy the new data into the arrays
+ S32 i;
+ F32* vertex = mVertexArray;
+ for (i = 0; i < mVertexCount; i++)
+ {
+ const LLVector3& point = new_vertex_array.get(i);
+ *vertex = point.mV[VX];
+ vertex++;
+ *vertex = point.mV[VY];
+ vertex++;
+ *vertex = point.mV[VZ];
+ vertex++;
+ }
+
+ U8* colorp = mColorArray;
+ for (i = 0; i < mVertexCount; i++)
+ {
+ const LLColor4U& color = new_color_array.get(i);
+ *colorp = color.mV[VRED];
+ colorp++;
+ *colorp = color.mV[VGREEN];
+ colorp++;
+ *colorp = color.mV[VBLUE];
+ colorp++;
+ *colorp = color.mV[VALPHA];
+ colorp++;
+ }
+
+ // Everything's clean now
+ mDirty = FALSE;
+}
+
+
+void LLViewerParcelOverlay::addPropertyLine(
+ LLDynamicArray<LLVector3, 256>& vertex_array,
+ LLDynamicArray<LLColor4U, 256>& color_array,
+ LLDynamicArray<LLVector2, 256>& coord_array,
+ const F32 start_x, const F32 start_y,
+ const U32 edge,
+ const LLColor4U& color)
+{
+ LLColor4U underwater( color );
+ underwater.mV[VALPHA] /= 2;
+
+ LLSurface& land = mRegion->getLand();
+
+ F32 dx;
+ F32 dy;
+ F32 tick_dx;
+ F32 tick_dy;
+ //const F32 LINE_WIDTH = 0.125f;
+ const F32 LINE_WIDTH = 0.0625f;
+
+ switch(edge)
+ {
+ case WEST:
+ dx = 0.f;
+ dy = 1.f;
+ tick_dx = LINE_WIDTH;
+ tick_dy = 0.f;
+ break;
+
+ case EAST:
+ dx = 0.f;
+ dy = 1.f;
+ tick_dx = -LINE_WIDTH;
+ tick_dy = 0.f;
+ break;
+
+ case NORTH:
+ dx = 1.f;
+ dy = 0.f;
+ tick_dx = 0.f;
+ tick_dy = -LINE_WIDTH;
+ break;
+
+ case SOUTH:
+ dx = 1.f;
+ dy = 0.f;
+ tick_dx = 0.f;
+ tick_dy = LINE_WIDTH;
+ break;
+
+ default:
+ llerrs << "Invalid edge in addPropertyLine" << llendl;
+ return;
+ }
+
+ F32 outside_x = start_x;
+ F32 outside_y = start_y;
+ F32 outside_z = 0.f;
+ F32 inside_x = start_x + tick_dx;
+ F32 inside_y = start_y + tick_dy;
+ F32 inside_z = 0.f;
+
+ // First part, only one vertex
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ if (outside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
+ coord_array.put( LLVector2(outside_x - start_x, 0.f) );
+
+ inside_x += dx * LINE_WIDTH;
+ inside_y += dy * LINE_WIDTH;
+
+ outside_x += dx * LINE_WIDTH;
+ outside_y += dy * LINE_WIDTH;
+
+ // Then the "actual edge"
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ if (inside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ if (outside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
+ vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
+
+ coord_array.put( LLVector2(outside_x - start_x, 1.f) );
+ coord_array.put( LLVector2(outside_x - start_x, 0.f) );
+
+ inside_x += dx * (dx - LINE_WIDTH);
+ inside_y += dy * (dy - LINE_WIDTH);
+
+ outside_x += dx * (dx - LINE_WIDTH);
+ outside_y += dy * (dy - LINE_WIDTH);
+
+ // Middle part, full width
+ S32 i;
+ const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
+ for (i = 1; i < GRID_STEP; i++)
+ {
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ if (inside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ if (outside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
+ vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
+
+ coord_array.put( LLVector2(outside_x - start_x, 1.f) );
+ coord_array.put( LLVector2(outside_x - start_x, 0.f) );
+
+ inside_x += dx;
+ inside_y += dy;
+
+ outside_x += dx;
+ outside_y += dy;
+ }
+
+ // Extra buffer for edge
+ inside_x -= dx * LINE_WIDTH;
+ inside_y -= dy * LINE_WIDTH;
+
+ outside_x -= dx * LINE_WIDTH;
+ outside_y -= dy * LINE_WIDTH;
+
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ if (inside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ if (outside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ vertex_array.put( LLVector3(inside_x, inside_y, inside_z) );
+ vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
+
+ coord_array.put( LLVector2(outside_x - start_x, 1.f) );
+ coord_array.put( LLVector2(outside_x - start_x, 0.f) );
+
+ inside_x += dx * LINE_WIDTH;
+ inside_y += dy * LINE_WIDTH;
+
+ outside_x += dx * LINE_WIDTH;
+ outside_y += dy * LINE_WIDTH;
+
+ // Last edge is not drawn to the edge
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ if (outside_z > 20.f) color_array.put( color );
+ else color_array.put( underwater );
+
+ vertex_array.put( LLVector3(outside_x, outside_y, outside_z) );
+ coord_array.put( LLVector2(outside_x - start_x, 0.f) );
+}
+
+
+void LLViewerParcelOverlay::setDirty()
+{
+ mDirty = TRUE;
+}
+
+void LLViewerParcelOverlay::idleUpdate(bool force_update)
+{
+ if (gGLManager.mIsDisabled)
+ {
+ return;
+ }
+ if (mOverlayTextureIdx >= 0 && (!(mDirty && force_update)))
+ {
+ // We are in the middle of updating the overlay texture
+ updateOverlayTexture();
+ return;
+ }
+ // Only if we're dirty and it's been a while since the last update.
+ if (mDirty)
+ {
+ if (force_update || mTimeSinceLastUpdate.getElapsedTimeF32() > 4.0f)
+ {
+ updateOverlayTexture();
+ updatePropertyLines();
+ mTimeSinceLastUpdate.reset();
+ }
+ }
+}
+
+S32 LLViewerParcelOverlay::renderPropertyLines ()
+{
+ if (!gSavedSettings.getBOOL("ShowPropertyLines"))
+ {
+ return 0;
+ }
+ if (!mVertexArray || !mColorArray)
+ {
+ return 0;
+ }
+
+ LLSurface& land = mRegion->getLand();
+
+ LLGLSUIDefault gls_ui; // called from pipeline
+ LLGLSNoTexture gls_no_texture;
+ LLGLDepthTest mDepthTest(GL_TRUE);
+
+ // JC - This doesn't work.
+ //gGLSUITextureDepth.set();
+ //LLViewerImage* image = gImageList.getImage( mLineImageID );
+ //image->bindTexture();
+
+ // Find camera height off the ground (not from zero)
+ F32 ground_height_at_camera = land.resolveHeightGlobal( gAgent.getCameraPositionGlobal() );
+ F32 camera_z = gCamera->getOrigin().mV[VZ];
+ F32 camera_height = camera_z - ground_height_at_camera;
+
+ camera_height = llclamp(camera_height, 0.f, 100.f);
+
+ // Pull lines toward camera by 1 cm per meter off the ground.
+ const LLVector3& CAMERA_AT = gCamera->getAtAxis();
+ F32 pull_toward_camera_scale = 0.01f * camera_height;
+ LLVector3 pull_toward_camera = CAMERA_AT;
+ pull_toward_camera *= -pull_toward_camera_scale;
+
+ // Always fudge a little vertically.
+ pull_toward_camera.mV[VZ] += 0.01f;
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix();
+
+ // Move to appropriate region coords
+ LLVector3 origin = mRegion->getOriginAgent();
+ glTranslatef( origin.mV[VX], origin.mV[VY], origin.mV[VZ] );
+
+ glTranslatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY],
+ pull_toward_camera.mV[VZ]);
+
+ // Include +1 because vertices are fenceposts.
+ // *2 because it's a quad strip
+ const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
+ const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3;
+
+ /* JC - Don't do this. Unbinding AGP stalls the draw process,
+ dropping frame rate. Not unbinding AGP causes random crashes
+ on nVidia cards due to binding non-AGP arrays.
+
+ gPipeline.unbindAGP();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, mVertexArray );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColorArray );
+
+ S32 i;
+ for (i = 0; i < mVertexCount; i += vertex_per_edge)
+ {
+ // Each edge is several vertices
+ glDrawArrays(GL_LINE_STRIP, i, vertex_per_edge);
+ }
+
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ */
+
+ // Stomp the camera into two dimensions
+ LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgent.getCameraPositionGlobal() );
+
+ // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
+ // the camera. The cull plane normal is the camera's at axis.
+ LLVector3 cull_plane_point = gCamera->getAtAxis();
+ cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
+ cull_plane_point += camera_region;
+
+ LLVector3 vertex;
+
+ const S32 BYTES_PER_COLOR = 4;
+ const S32 FLOATS_PER_VERTEX = 3;
+ //const S32 FLOATS_PER_TEX_COORD = 2;
+ S32 i, j;
+ S32 drawn = 0;
+ F32* vertexp;
+ U8* colorp;
+
+ const F32 PROPERTY_LINE_CLIP_DIST = 256.f;
+
+ for (i = 0; i < mVertexCount; i += vertex_per_edge)
+ {
+ colorp = mColorArray + BYTES_PER_COLOR * i;
+ vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
+
+ vertex.mV[VX] = *(vertexp);
+ vertex.mV[VY] = *(vertexp+1);
+ vertex.mV[VZ] = *(vertexp+2);
+
+ if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST*PROPERTY_LINE_CLIP_DIST)
+ {
+ continue;
+ }
+
+ // Destroy vertex, transform to plane-local.
+ vertex -= cull_plane_point;
+
+ // negative dot product means it is in back of the plane
+ if ( vertex * CAMERA_AT < 0.f )
+ {
+ continue;
+ }
+
+ glBegin(GL_TRIANGLE_STRIP);
+
+ for (j = 0; j < vertex_per_edge; j++)
+ {
+ // JC - This doesn't work
+ //glTexCoord2fv(mTexCoordArray + FLOATS_PER_TEX_COORD*offset);
+ glColor4ubv(colorp);
+ glVertex3fv(vertexp);
+
+ colorp += BYTES_PER_COLOR;
+ vertexp += FLOATS_PER_VERTEX;
+ }
+
+ drawn += vertex_per_edge;
+
+ glEnd();
+ }
+
+ glPopMatrix();
+
+ return drawn;
+}