diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerparceloverlay.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 869 |
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 | |||
48 | const U8 OVERLAY_IMG_COMPONENTS = 4; | ||
49 | |||
50 | LLViewerParcelOverlay::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 | |||
98 | LLViewerParcelOverlay::~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 | //--------------------------------------------------------------------------- | ||
119 | BOOL 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 | |||
126 | BOOL 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 | |||
133 | BOOL 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 | |||
140 | BOOL 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 | |||
148 | BOOL 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 | |||
155 | U8 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 | |||
162 | F32 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 | ||
191 | void 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 | |||
290 | void 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 | |||
303 | void 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 | |||
536 | void 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 | |||
701 | void LLViewerParcelOverlay::setDirty() | ||
702 | { | ||
703 | mDirty = TRUE; | ||
704 | } | ||
705 | |||
706 | void 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 | |||
730 | S32 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 | } | ||