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/llworldmapview.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 '')
-rw-r--r-- | linden/indra/newview/llworldmapview.cpp | 1962 |
1 files changed, 1962 insertions, 0 deletions
diff --git a/linden/indra/newview/llworldmapview.cpp b/linden/indra/newview/llworldmapview.cpp new file mode 100644 index 0000000..83e10d9 --- /dev/null +++ b/linden/indra/newview/llworldmapview.cpp | |||
@@ -0,0 +1,1962 @@ | |||
1 | /** | ||
2 | * @file llworldmapview.cpp | ||
3 | * @brief LLWorldMapView class implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-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 "llworldmapview.h" | ||
31 | |||
32 | #include "indra_constants.h" | ||
33 | #include "llui.h" | ||
34 | #include "linked_lists.h" | ||
35 | #include "llmath.h" // clampf() | ||
36 | #include "llregionhandle.h" | ||
37 | #include "lleventflags.h" | ||
38 | |||
39 | #include "llagent.h" | ||
40 | #include "llcallingcard.h" | ||
41 | #include "llcolorscheme.h" | ||
42 | #include "llviewercontrol.h" | ||
43 | #include "llcylinder.h" | ||
44 | #include "llfloaterdirectory.h" | ||
45 | #include "llfloatermap.h" | ||
46 | #include "llfloaterworldmap.h" | ||
47 | #include "llfocusmgr.h" | ||
48 | #include "lltextbox.h" | ||
49 | #include "lltextureview.h" | ||
50 | #include "lltracker.h" | ||
51 | #include "llviewercamera.h" | ||
52 | #include "llviewerimage.h" | ||
53 | #include "llviewerimagelist.h" | ||
54 | #include "llviewerparceloverlay.h" | ||
55 | #include "llviewerregion.h" | ||
56 | #include "llviewerwindow.h" | ||
57 | #include "llworld.h" | ||
58 | #include "llworldmap.h" | ||
59 | #include "viewer.h" // Only for constants! | ||
60 | |||
61 | #include "llglheaders.h" | ||
62 | |||
63 | const F32 GODLY_TELEPORT_HEIGHT = 200.f; | ||
64 | const S32 SCROLL_HINT_WIDTH = 65; | ||
65 | const F32 BIG_DOT_RADIUS = 5.f; | ||
66 | BOOL LLWorldMapView::sHandledLastClick = FALSE; | ||
67 | |||
68 | LLPointer<LLViewerImage> LLWorldMapView::sAvatarYouSmallImage = NULL; | ||
69 | LLPointer<LLViewerImage> LLWorldMapView::sAvatarSmallImage = NULL; | ||
70 | LLPointer<LLViewerImage> LLWorldMapView::sAvatarLargeImage = NULL; | ||
71 | |||
72 | LLPointer<LLViewerImage> LLWorldMapView::sTelehubImage = NULL; | ||
73 | LLPointer<LLViewerImage> LLWorldMapView::sInfohubImage = NULL; | ||
74 | LLPointer<LLViewerImage> LLWorldMapView::sHomeImage = NULL; | ||
75 | LLPointer<LLViewerImage> LLWorldMapView::sEventImage = NULL; | ||
76 | LLPointer<LLViewerImage> LLWorldMapView::sEventMatureImage = NULL; | ||
77 | |||
78 | LLPointer<LLViewerImage> LLWorldMapView::sTrackCircleImage = NULL; | ||
79 | LLPointer<LLViewerImage> LLWorldMapView::sTrackArrowImage = NULL; | ||
80 | |||
81 | LLPointer<LLViewerImage> LLWorldMapView::sClassifiedsImage = NULL; | ||
82 | LLPointer<LLViewerImage> LLWorldMapView::sPopularImage = NULL; | ||
83 | LLPointer<LLViewerImage> LLWorldMapView::sForSaleImage = NULL; | ||
84 | |||
85 | F32 LLWorldMapView::sThresholdA = 48.f; | ||
86 | F32 LLWorldMapView::sThresholdB = 96.f; | ||
87 | F32 LLWorldMapView::sPanX = 0.f; | ||
88 | F32 LLWorldMapView::sPanY = 0.f; | ||
89 | F32 LLWorldMapView::sTargetPanX = 0.f; | ||
90 | F32 LLWorldMapView::sTargetPanY = 0.f; | ||
91 | S32 LLWorldMapView::sTrackingArrowX = 0; | ||
92 | S32 LLWorldMapView::sTrackingArrowY = 0; | ||
93 | F32 LLWorldMapView::sPixelsPerMeter = 1.f; | ||
94 | F32 CONE_SIZE = 0.6f; | ||
95 | |||
96 | void LLWorldMapView::initClass() | ||
97 | { | ||
98 | LLUUID image_id; | ||
99 | |||
100 | image_id.set( gViewerArt.getString("map_avatar_you_8.tga") ); | ||
101 | sAvatarYouSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE); | ||
102 | |||
103 | image_id.set( gViewerArt.getString("map_avatar_8.tga") ); | ||
104 | sAvatarSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE); | ||
105 | |||
106 | image_id.set( gViewerArt.getString("map_avatar_16.tga") ); | ||
107 | sAvatarLargeImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE); | ||
108 | |||
109 | image_id.set( gViewerArt.getString("map_home.tga") ); | ||
110 | sHomeImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
111 | |||
112 | image_id.set( gViewerArt.getString("map_telehub.tga") ); | ||
113 | sTelehubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
114 | |||
115 | image_id.set( gViewerArt.getString("map_infohub.tga") ); | ||
116 | sInfohubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
117 | |||
118 | image_id.set( gViewerArt.getString("map_event.tga") ); | ||
119 | sEventImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
120 | |||
121 | image_id.set( gViewerArt.getString("map_event_mature.tga") ); | ||
122 | sEventMatureImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
123 | |||
124 | image_id.set( gViewerArt.getString("map_track_16.tga") ); | ||
125 | sTrackCircleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
126 | |||
127 | image_id.set( gViewerArt.getString("direction_arrow.tga") ); | ||
128 | sTrackArrowImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
129 | // Make sure tracker arrow doesn't wrap | ||
130 | sTrackArrowImage->bindTexture(0); | ||
131 | sTrackArrowImage->setClamp(TRUE, TRUE); | ||
132 | |||
133 | image_id.set( gViewerArt.getString("icon_top_pick.tga") ); | ||
134 | sClassifiedsImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
135 | |||
136 | image_id.set( gViewerArt.getString("icon_popular.tga") ); | ||
137 | sPopularImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
138 | |||
139 | image_id.set( gViewerArt.getString("icon_for_sale.tga") ); | ||
140 | sForSaleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE); | ||
141 | } | ||
142 | |||
143 | // static | ||
144 | void LLWorldMapView::cleanupClass() | ||
145 | { | ||
146 | sAvatarYouSmallImage = NULL; | ||
147 | sAvatarSmallImage = NULL; | ||
148 | sAvatarLargeImage = NULL; | ||
149 | sTelehubImage = NULL; | ||
150 | sInfohubImage = NULL; | ||
151 | sHomeImage = NULL; | ||
152 | sEventImage = NULL; | ||
153 | sEventMatureImage = NULL; | ||
154 | sTrackCircleImage = NULL; | ||
155 | sTrackArrowImage = NULL; | ||
156 | sClassifiedsImage = NULL; | ||
157 | sPopularImage = NULL; | ||
158 | sForSaleImage = NULL; | ||
159 | } | ||
160 | |||
161 | LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) | ||
162 | : LLPanel(name, rect, BORDER_NO), | ||
163 | mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ), | ||
164 | mItemPicked(FALSE), | ||
165 | mPanning( FALSE ), | ||
166 | mMouseDownPanX( 0 ), | ||
167 | mMouseDownPanY( 0 ), | ||
168 | mMouseDownX( 0 ), | ||
169 | mMouseDownY( 0 ), | ||
170 | mSelectIDStart(0), | ||
171 | mAgentCountsUpdateTime(0) | ||
172 | { | ||
173 | sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS; | ||
174 | clearLastClick(); | ||
175 | |||
176 | const S32 DIR_WIDTH = 10; | ||
177 | const S32 DIR_HEIGHT = 10; | ||
178 | LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 ); | ||
179 | |||
180 | mTextBoxNorth = new LLTextBox( "N", major_dir_rect ); | ||
181 | mTextBoxNorth->setDropshadowVisible( TRUE ); | ||
182 | addChild( mTextBoxNorth ); | ||
183 | |||
184 | LLColor4 minor_color( 1.f, 1.f, 1.f, .7f ); | ||
185 | |||
186 | mTextBoxEast = new LLTextBox( "E", major_dir_rect ); | ||
187 | mTextBoxEast->setColor( minor_color ); | ||
188 | addChild( mTextBoxEast ); | ||
189 | |||
190 | mTextBoxWest = new LLTextBox( "W", major_dir_rect ); | ||
191 | mTextBoxWest->setColor( minor_color ); | ||
192 | addChild( mTextBoxWest ); | ||
193 | |||
194 | mTextBoxSouth = new LLTextBox( "S", major_dir_rect ); | ||
195 | mTextBoxSouth->setColor( minor_color ); | ||
196 | addChild( mTextBoxSouth ); | ||
197 | |||
198 | LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 ); | ||
199 | |||
200 | mTextBoxSouthEast = new LLTextBox( "SE", minor_dir_rect ); | ||
201 | mTextBoxSouthEast->setColor( minor_color ); | ||
202 | addChild( mTextBoxSouthEast ); | ||
203 | |||
204 | mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect ); | ||
205 | mTextBoxNorthEast->setColor( minor_color ); | ||
206 | addChild( mTextBoxNorthEast ); | ||
207 | |||
208 | mTextBoxSouthWest = new LLTextBox( "SW", minor_dir_rect ); | ||
209 | mTextBoxSouthWest->setColor( minor_color ); | ||
210 | addChild( mTextBoxSouthWest ); | ||
211 | |||
212 | mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect ); | ||
213 | mTextBoxNorthWest->setColor( minor_color ); | ||
214 | addChild( mTextBoxNorthWest ); | ||
215 | } | ||
216 | |||
217 | |||
218 | LLWorldMapView::~LLWorldMapView() | ||
219 | { | ||
220 | cleanupTextures(); | ||
221 | } | ||
222 | |||
223 | |||
224 | // static | ||
225 | void LLWorldMapView::cleanupTextures() | ||
226 | { | ||
227 | } | ||
228 | |||
229 | |||
230 | // static | ||
231 | void LLWorldMapView::setScale( F32 scale ) | ||
232 | { | ||
233 | if (scale != gMapScale) | ||
234 | { | ||
235 | F32 old_scale = gMapScale; | ||
236 | |||
237 | gMapScale = scale; | ||
238 | if (gMapScale == 0.f) | ||
239 | { | ||
240 | gMapScale = 0.1f; | ||
241 | } | ||
242 | |||
243 | F32 ratio = (scale / old_scale); | ||
244 | sPanX *= ratio; | ||
245 | sPanY *= ratio; | ||
246 | sTargetPanX = sPanX; | ||
247 | sTargetPanY = sPanY; | ||
248 | |||
249 | sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | |||
254 | // static | ||
255 | void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y ) | ||
256 | { | ||
257 | sPanX += delta_x; | ||
258 | sPanY += delta_y; | ||
259 | sTargetPanX = sPanX; | ||
260 | sTargetPanY = sPanY; | ||
261 | } | ||
262 | |||
263 | |||
264 | // static | ||
265 | void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap ) | ||
266 | { | ||
267 | sTargetPanX = (F32)x; | ||
268 | sTargetPanY = (F32)y; | ||
269 | if (snap) | ||
270 | { | ||
271 | sPanX = sTargetPanX; | ||
272 | sPanY = sTargetPanY; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | |||
277 | /////////////////////////////////////////////////////////////////////////////////// | ||
278 | |||
279 | // dumb helper function | ||
280 | BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info) | ||
281 | { | ||
282 | if((region && info) | ||
283 | && (info->mName == region->getName())) | ||
284 | { | ||
285 | return TRUE; | ||
286 | } | ||
287 | return FALSE; | ||
288 | } | ||
289 | |||
290 | void LLWorldMapView::draw() | ||
291 | { | ||
292 | if (!getVisible() || !gWorldPointer) | ||
293 | { | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | LLTextureView::clearDebugImages(); | ||
298 | |||
299 | F64 current_time = LLTimer::getElapsedSeconds(); | ||
300 | |||
301 | if (current_time - mAgentCountsUpdateTime > AGENT_COUNTS_UPDATE_TIME) | ||
302 | { | ||
303 | gWorldMap->sendItemRequest(MAP_ITEM_AGENT_COUNT); | ||
304 | mAgentCountsUpdateTime = current_time; | ||
305 | } | ||
306 | |||
307 | mVisibleRegions.clear(); | ||
308 | |||
309 | // animate pan if necessary | ||
310 | sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); | ||
311 | sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); | ||
312 | |||
313 | LLVector3d pos_global; | ||
314 | LLVector3 pos_map; | ||
315 | |||
316 | const S32 width = mRect.getWidth(); | ||
317 | const S32 height = mRect.getHeight(); | ||
318 | const S32 half_width = width / 2; | ||
319 | const S32 half_height = height / 2; | ||
320 | LLVector3d camera_global = gAgent.getCameraPositionGlobal(); | ||
321 | |||
322 | LLGLEnable scissor_test(GL_SCISSOR_TEST); | ||
323 | LLUI::setScissorRegionLocal(LLRect(0, height, width, 0)); | ||
324 | { | ||
325 | LLGLSNoTexture no_texture; | ||
326 | |||
327 | |||
328 | glMatrixMode(GL_MODELVIEW); | ||
329 | |||
330 | // Clear the background alpha to 0 | ||
331 | glColorMask(FALSE, FALSE, FALSE, TRUE); | ||
332 | glAlphaFunc(GL_GEQUAL, 0.00f); | ||
333 | glBlendFunc(GL_ONE, GL_ZERO); | ||
334 | glColor4f(0.0f, 0.0f, 0.0f, 0.0f); | ||
335 | gl_rect_2d(0, height, width, 0); | ||
336 | } | ||
337 | |||
338 | glAlphaFunc(GL_GEQUAL, 0.01f); | ||
339 | glColorMask(TRUE, TRUE, TRUE, TRUE); | ||
340 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
341 | |||
342 | F32 layer_alpha = 1.f; | ||
343 | |||
344 | // Draw one image per layer | ||
345 | for (U32 layer_idx=0; layer_idx<gWorldMap->mMapLayers[gWorldMap->mCurrentMap].size(); ++layer_idx) | ||
346 | { | ||
347 | if (!gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx].LayerDefined) | ||
348 | { | ||
349 | continue; | ||
350 | } | ||
351 | LLWorldMapLayer *layer = &gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx]; | ||
352 | LLViewerImage *current_image = layer->LayerImage; | ||
353 | #if 1 || LL_RELEASE_FOR_DOWNLOAD | ||
354 | if (current_image->isMissingAsset()) | ||
355 | { | ||
356 | continue; // better to draw nothing than the missing asset image | ||
357 | } | ||
358 | #endif | ||
359 | |||
360 | LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f); | ||
361 | |||
362 | // Find x and y position relative to camera's center. | ||
363 | LLVector3d rel_region_pos = origin_global - camera_global; | ||
364 | S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale); | ||
365 | S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale); | ||
366 | |||
367 | F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1); | ||
368 | F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1); | ||
369 | |||
370 | // When the view isn't panned, 0,0 = center of rectangle | ||
371 | F32 bottom = sPanY + half_height + relative_y; | ||
372 | F32 left = sPanX + half_width + relative_x; | ||
373 | F32 top = bottom + pix_height; | ||
374 | F32 right = left + pix_width; | ||
375 | F32 pixel_area = pix_width*pix_height; | ||
376 | // discard layers that are outside the rectangle | ||
377 | // and discard small layers | ||
378 | if (top < 0.f || | ||
379 | bottom > height || | ||
380 | right < 0.f || | ||
381 | left > width || | ||
382 | (pixel_area < 4*4)) | ||
383 | { | ||
384 | current_image->setBoostLevel(0); | ||
385 | continue; | ||
386 | } | ||
387 | |||
388 | current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER); | ||
389 | current_image->setKnownDrawSize(llround(pix_width), llround(pix_height)); | ||
390 | |||
391 | #if 1 || LL_RELEASE_FOR_DOWNLOAD | ||
392 | if (!current_image->getHasGLTexture()) | ||
393 | { | ||
394 | continue; // better to draw nothing than the default image | ||
395 | } | ||
396 | #endif | ||
397 | |||
398 | LLTextureView::addDebugImage(current_image); | ||
399 | |||
400 | // Draw using the texture. If we don't clamp we get artifact at | ||
401 | // the edge. | ||
402 | LLViewerImage::bindTexture(current_image); | ||
403 | |||
404 | // Draw map image into RGB | ||
405 | //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
406 | glColorMask(TRUE, TRUE, TRUE, FALSE); | ||
407 | glColor4f(1.f, 1.f, 1.f, layer_alpha); | ||
408 | |||
409 | glBegin(GL_QUADS); | ||
410 | glTexCoord2f(0.0f, 1.0f); | ||
411 | glVertex3f(left, top, -1.0f); | ||
412 | glTexCoord2f(0.0f, 0.0f); | ||
413 | glVertex3f(left, bottom, -1.0f); | ||
414 | glTexCoord2f(1.0f, 0.0f); | ||
415 | glVertex3f(right, bottom, -1.0f); | ||
416 | glTexCoord2f(1.0f, 1.0f); | ||
417 | glVertex3f(right, top, -1.0f); | ||
418 | glEnd(); | ||
419 | |||
420 | // draw an alpha of 1 where the sims are visible | ||
421 | glColorMask(FALSE, FALSE, FALSE, TRUE); | ||
422 | glColor4f(1.f, 1.f, 1.f, 1.f); | ||
423 | |||
424 | glBegin(GL_QUADS); | ||
425 | glTexCoord2f(0.0f, 1.0f); | ||
426 | glVertex2f(left, top); | ||
427 | glTexCoord2f(0.0f, 0.0f); | ||
428 | glVertex2f(left, bottom); | ||
429 | glTexCoord2f(1.0f, 0.0f); | ||
430 | glVertex2f(right, bottom); | ||
431 | glTexCoord2f(1.0f, 1.0f); | ||
432 | glVertex2f(right, top); | ||
433 | glEnd(); | ||
434 | } | ||
435 | |||
436 | glAlphaFunc(GL_GEQUAL, 0.01f); | ||
437 | glColorMask(TRUE, TRUE, TRUE, TRUE); | ||
438 | |||
439 | #if 1 | ||
440 | F32 sim_alpha = 1.f; | ||
441 | |||
442 | // Draw one image per region, centered on the camera position. | ||
443 | for (LLWorldMap::sim_info_map_t::iterator it = gWorldMap->mSimInfoMap.begin(); | ||
444 | it != gWorldMap->mSimInfoMap.end(); ++it) | ||
445 | { | ||
446 | U64 handle = (*it).first; | ||
447 | LLSimInfo* info = (*it).second; | ||
448 | |||
449 | if (info->mCurrentImage.isNull()) | ||
450 | { | ||
451 | info->mCurrentImage = gImageList.getImage(info->mMapImageID[gWorldMap->mCurrentMap], MIPMAP_TRUE, FALSE); | ||
452 | } | ||
453 | if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull()) | ||
454 | { | ||
455 | info->mOverlayImage = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE); | ||
456 | info->mOverlayImage->bind(0); | ||
457 | info->mOverlayImage->setClamp(TRUE, TRUE); | ||
458 | } | ||
459 | |||
460 | LLViewerImage* simimage = info->mCurrentImage; | ||
461 | LLViewerImage* overlayimage = info->mOverlayImage; | ||
462 | |||
463 | if (gMapScale < 8.f) | ||
464 | { | ||
465 | simimage->setBoostLevel(0); | ||
466 | if (overlayimage) overlayimage->setBoostLevel(0); | ||
467 | continue; | ||
468 | } | ||
469 | |||
470 | LLVector3d origin_global = from_region_handle(handle); | ||
471 | LLVector3d camera_global = gAgent.getCameraPositionGlobal(); | ||
472 | |||
473 | // Find x and y position relative to camera's center. | ||
474 | LLVector3d rel_region_pos = origin_global - camera_global; | ||
475 | S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale); | ||
476 | S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale); | ||
477 | |||
478 | // When the view isn't panned, 0,0 = center of rectangle | ||
479 | F32 bottom = sPanY + half_height + relative_y; | ||
480 | F32 left = sPanX + half_width + relative_x; | ||
481 | F32 top = bottom + gMapScale ; | ||
482 | F32 right = left + gMapScale ; | ||
483 | |||
484 | // Switch to world map texture (if available for this region) if either: | ||
485 | // 1. Tiles are zoomed out small enough, or | ||
486 | // 2. Sim's texture has not been loaded yet | ||
487 | F32 map_scale_cutoff = SIM_MAP_SCALE; | ||
488 | if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0) | ||
489 | { | ||
490 | map_scale_cutoff = SIM_NULL_MAP_SCALE; | ||
491 | } | ||
492 | |||
493 | info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE); | ||
494 | |||
495 | bool sim_visible = | ||
496 | (gMapScale >= map_scale_cutoff) && | ||
497 | (simimage->getHasGLTexture()); | ||
498 | |||
499 | if (sim_visible) | ||
500 | { | ||
501 | // Fade in | ||
502 | if (info->mAlpha < 0.0f) | ||
503 | info->mAlpha = 1.f; // don't fade initially | ||
504 | else | ||
505 | info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f)); | ||
506 | } | ||
507 | else | ||
508 | { | ||
509 | // Fade out | ||
510 | if (info->mAlpha < 0.0f) | ||
511 | info->mAlpha = 0.f; // don't fade initially | ||
512 | else | ||
513 | info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f)); | ||
514 | } | ||
515 | |||
516 | // discard regions that are outside the rectangle | ||
517 | // and discard small regions | ||
518 | if (top < 0.f || | ||
519 | bottom > height || | ||
520 | right < 0.f || | ||
521 | left > width ) | ||
522 | { | ||
523 | simimage->setBoostLevel(0); | ||
524 | if (overlayimage) overlayimage->setBoostLevel(0); | ||
525 | continue; | ||
526 | } | ||
527 | |||
528 | mVisibleRegions.push_back(handle); | ||
529 | // See if the agents need updating | ||
530 | if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME) | ||
531 | { | ||
532 | gWorldMap->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle); | ||
533 | info->mAgentsUpdateTime = current_time; | ||
534 | } | ||
535 | |||
536 | // Bias the priority escalation for images nearer | ||
537 | LLVector3d center_global = origin_global; | ||
538 | center_global.mdV[VX] += 128.0; | ||
539 | center_global.mdV[VY] += 128.0; | ||
540 | |||
541 | S32 draw_size = llround(gMapScale); | ||
542 | simimage->setBoostLevel(LLViewerImage::BOOST_MAP); | ||
543 | simimage->setKnownDrawSize(draw_size, draw_size); | ||
544 | |||
545 | if (overlayimage) | ||
546 | { | ||
547 | overlayimage->setBoostLevel(LLViewerImage::BOOST_MAP); | ||
548 | overlayimage->setKnownDrawSize(draw_size, draw_size); | ||
549 | } | ||
550 | |||
551 | LLTextureView::addDebugImage(simimage); | ||
552 | |||
553 | if (sim_visible && info->mAlpha > 0.001f) | ||
554 | { | ||
555 | // Draw using the texture. If we don't clamp we get artifact at | ||
556 | // the edge. | ||
557 | LLGLSUIDefault gls_ui; | ||
558 | LLViewerImage::bindTexture(simimage); | ||
559 | |||
560 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
561 | F32 alpha = sim_alpha * info->mAlpha; | ||
562 | glColor4f(1.f, 1.0f, 1.0f, alpha); | ||
563 | |||
564 | glBegin(GL_QUADS); | ||
565 | glTexCoord2f(0.f, 1.f); | ||
566 | glVertex3f(left, top, 0.f); | ||
567 | glTexCoord2f(0.f, 0.f); | ||
568 | glVertex3f(left, bottom, 0.f); | ||
569 | glTexCoord2f(1.f, 0.f); | ||
570 | glVertex3f(right, bottom, 0.f); | ||
571 | glTexCoord2f(1.f, 1.f); | ||
572 | glVertex3f(right, top, 0.f); | ||
573 | glEnd(); | ||
574 | |||
575 | if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->getHasGLTexture()) | ||
576 | { | ||
577 | LLViewerImage::bindTexture(overlayimage); | ||
578 | glColor4f(1.f, 1.f, 1.f, alpha); | ||
579 | glBegin(GL_QUADS); | ||
580 | glTexCoord2f(0.f, 1.f); | ||
581 | glVertex3f(left, top, -0.5f); | ||
582 | glTexCoord2f(0.f, 0.f); | ||
583 | glVertex3f(left, bottom, -0.5f); | ||
584 | glTexCoord2f(1.f, 0.f); | ||
585 | glVertex3f(right, bottom, -0.5f); | ||
586 | glTexCoord2f(1.f, 1.f); | ||
587 | glVertex3f(right, top, -0.5f); | ||
588 | glEnd(); | ||
589 | } | ||
590 | |||
591 | if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0) | ||
592 | { | ||
593 | // draw an alpha of 1 where the sims are visible (except NULL sims) | ||
594 | glBlendFunc(GL_ONE, GL_ZERO); | ||
595 | glColorMask(FALSE, FALSE, FALSE, TRUE); | ||
596 | glColor4f(1.f, 1.f, 1.f, 1.f); | ||
597 | |||
598 | LLGLSNoTexture gls_no_texture; | ||
599 | glBegin(GL_QUADS); | ||
600 | glVertex2f(left, top); | ||
601 | glVertex2f(left, bottom); | ||
602 | glVertex2f(right, bottom); | ||
603 | glVertex2f(right, top); | ||
604 | glEnd(); | ||
605 | |||
606 | glColorMask(TRUE, TRUE, TRUE, TRUE); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | if (info->mAccess == SIM_ACCESS_DOWN) | ||
611 | { | ||
612 | // Draw a transparent red square over down sims | ||
613 | glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA); | ||
614 | glColor4f(0.2f, 0.0f, 0.0f, 0.4f); | ||
615 | |||
616 | LLGLSNoTexture gls_no_texture; | ||
617 | glBegin(GL_QUADS); | ||
618 | glVertex2f(left, top); | ||
619 | glVertex2f(left, bottom); | ||
620 | glVertex2f(right, bottom); | ||
621 | glVertex2f(right, top); | ||
622 | glEnd(); | ||
623 | } | ||
624 | |||
625 | // If this is mature, and you are not, draw a line across it | ||
626 | if (info->mAccess != SIM_ACCESS_DOWN && info->mAccess > gAgent.mAccess) | ||
627 | { | ||
628 | glBlendFunc(GL_DST_ALPHA, GL_ZERO); | ||
629 | |||
630 | LLGLSNoTexture gls_no_texture; | ||
631 | glColor3f(1.f, 0.f, 0.f); | ||
632 | glBegin(GL_LINES); | ||
633 | glVertex2f(left, top); | ||
634 | glVertex2f(right, bottom); | ||
635 | glVertex2f(left, bottom); | ||
636 | glVertex2f(right, top); | ||
637 | glEnd(); | ||
638 | } | ||
639 | |||
640 | // Draw the region name in the lower left corner | ||
641 | LLFontGL* font = LLFontGL::sSansSerifSmall; | ||
642 | |||
643 | char mesg[MAX_STRING]; | ||
644 | if (gMapScale < sThresholdA) | ||
645 | { | ||
646 | mesg[0] = '\0'; | ||
647 | } | ||
648 | else if (gMapScale < sThresholdB) | ||
649 | { | ||
650 | //sprintf(mesg, "%d", info->mAgents); | ||
651 | mesg[0] = '\0'; | ||
652 | } | ||
653 | else | ||
654 | { | ||
655 | //sprintf(mesg, "%d / %s (%s)", | ||
656 | // info->mAgents, | ||
657 | // info->mName.c_str(), | ||
658 | // LLViewerRegion::accessToShortString(info->mAccess) ); | ||
659 | if (info->mAccess == SIM_ACCESS_DOWN) | ||
660 | { | ||
661 | sprintf(mesg, "%s (Offline)", info->mName.c_str()); | ||
662 | } | ||
663 | else | ||
664 | { | ||
665 | sprintf(mesg, "%s", info->mName.c_str()); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (mesg[0] != '\0') | ||
670 | { | ||
671 | font->renderUTF8( | ||
672 | mesg, 0, | ||
673 | llfloor(left + 3), | ||
674 | llfloor(bottom + 2), | ||
675 | LLColor4::white, | ||
676 | LLFontGL::LEFT, | ||
677 | LLFontGL::BASELINE, | ||
678 | LLFontGL::DROP_SHADOW); | ||
679 | } | ||
680 | } | ||
681 | #endif | ||
682 | |||
683 | |||
684 | #if 1 | ||
685 | // Draw background rectangle | ||
686 | LLGLSUIDefault gls_ui; | ||
687 | { | ||
688 | LLGLSNoTexture gls_no_texture; | ||
689 | glAlphaFunc(GL_GEQUAL, 0.0f); | ||
690 | glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); | ||
691 | glColor4fv( mBackgroundColor.mV ); | ||
692 | gl_rect_2d(0, height, width, 0); | ||
693 | } | ||
694 | |||
695 | glAlphaFunc(GL_GEQUAL, 0.01f); | ||
696 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
697 | |||
698 | // Infohubs | ||
699 | // Draw under avatar so you can find yourself. | ||
700 | if (gSavedSettings.getBOOL("MapShowInfohubs")) //(gMapScale >= sThresholdB) | ||
701 | { | ||
702 | S32 infohub_icon_size = (S32)sInfohubImage->getWidth(); | ||
703 | for (U32 infohub=0; infohub<gWorldMap->mInfohubs.size(); ++infohub) | ||
704 | { | ||
705 | LLItemInfo *infohub_info = &gWorldMap->mInfohubs[infohub]; | ||
706 | |||
707 | pos_map = globalPosToView(infohub_info->mPosGlobal); | ||
708 | gl_draw_image(llround(pos_map.mV[VX])-infohub_icon_size/2, | ||
709 | llround(pos_map.mV[VY])-infohub_icon_size/2, | ||
710 | sInfohubImage, | ||
711 | LLColor4::white); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | // Telehubs | ||
716 | // Draw under avatar so you can find yourself. | ||
717 | if (gSavedSettings.getBOOL("MapShowTelehubs")) //(gMapScale >= sThresholdB) | ||
718 | { | ||
719 | S32 telehub_icon_size = (S32)sTelehubImage->getWidth(); | ||
720 | for (U32 telehub=0; telehub<gWorldMap->mTelehubs.size(); ++telehub) | ||
721 | { | ||
722 | LLItemInfo *telehub_info = &gWorldMap->mTelehubs[telehub]; | ||
723 | |||
724 | pos_map = globalPosToView(telehub_info->mPosGlobal); | ||
725 | gl_draw_image(llround(pos_map.mV[VX])-telehub_icon_size/2, | ||
726 | llround(pos_map.mV[VY])-telehub_icon_size/2, | ||
727 | sTelehubImage, | ||
728 | LLColor4::white); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | // Home | ||
733 | // Always Draw | ||
734 | if (1) //(gMapScale >= sThresholdB) | ||
735 | { | ||
736 | S32 home_icon_size = (S32)sHomeImage->getWidth(); | ||
737 | if (gAgent.getHomePosGlobal(&pos_global)) | ||
738 | { | ||
739 | pos_map = globalPosToView(pos_global); | ||
740 | gl_draw_image(llround(pos_map.mV[VX])-home_icon_size/2, | ||
741 | llround(pos_map.mV[VY])-home_icon_size/2, | ||
742 | sHomeImage, | ||
743 | LLColor4::white); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | // Draw all these under the avatar, so you can find yourself | ||
748 | |||
749 | if (gSavedSettings.getBOOL("MapShowLandForSale")) | ||
750 | { | ||
751 | drawGenericItems(gWorldMap->mLandForSale, sForSaleImage); | ||
752 | } | ||
753 | |||
754 | if (gSavedSettings.getBOOL("MapShowClassifieds")) | ||
755 | { | ||
756 | drawGenericItems(gWorldMap->mClassifieds, sClassifiedsImage); | ||
757 | } | ||
758 | |||
759 | if (gSavedSettings.getBOOL("MapShowPopular")) | ||
760 | { | ||
761 | drawGenericItems(gWorldMap->mPopular, sPopularImage); | ||
762 | } | ||
763 | |||
764 | if (gSavedSettings.getBOOL("MapShowEvents")) | ||
765 | { | ||
766 | drawEvents(); | ||
767 | } | ||
768 | |||
769 | // Your avatar. | ||
770 | // Draw avatar position, always, and underneath other avatars | ||
771 | pos_global = gAgent.getPositionGlobal(); | ||
772 | pos_map = globalPosToView(pos_global); | ||
773 | gl_draw_image(llround(pos_map.mV[VX])-8, | ||
774 | llround(pos_map.mV[VY])-8, | ||
775 | sAvatarLargeImage, | ||
776 | LLColor4::white); | ||
777 | |||
778 | if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY]))) | ||
779 | { | ||
780 | drawTracking(pos_global, | ||
781 | lerp(LLColor4::yellow, LLColor4::orange, 0.4f), | ||
782 | TRUE, | ||
783 | "You are here", | ||
784 | "", | ||
785 | llround(LLFontGL::sSansSerifSmall->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking | ||
786 | } | ||
787 | |||
788 | drawFrustum(); | ||
789 | |||
790 | // Draw icons for the avatars in each region. | ||
791 | // Draw after avatar so you can see nearby people. | ||
792 | if (gSavedSettings.getBOOL("MapShowPeople")) | ||
793 | { | ||
794 | drawAgents(); | ||
795 | } | ||
796 | |||
797 | //----------------------------------------------------------------------- | ||
798 | |||
799 | // Always draw tracking information | ||
800 | LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); | ||
801 | if ( LLTracker::TRACKING_AVATAR == tracking_status ) | ||
802 | { | ||
803 | drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor, TRUE, LLTracker::getLabel(), "" ); | ||
804 | } | ||
805 | else if ( LLTracker::TRACKING_LANDMARK == tracking_status | ||
806 | || LLTracker::TRACKING_LOCATION == tracking_status ) | ||
807 | { | ||
808 | // While fetching landmarks, will have 0,0,0 location for a while, | ||
809 | // so don't draw. JC | ||
810 | LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); | ||
811 | if (!pos_global.isExactlyZero()) | ||
812 | { | ||
813 | drawTracking( pos_global, gTrackColor, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() ); | ||
814 | } | ||
815 | } | ||
816 | else if (gWorldMap->mIsTrackingUnknownLocation) | ||
817 | { | ||
818 | if (gWorldMap->mInvalidLocation) | ||
819 | { | ||
820 | // We know this location to be invalid | ||
821 | LLColor4 loading_color(0.0, 0.5, 1.0, 1.0); | ||
822 | drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Invalid Location", ""); | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | double value = fmod(current_time, 2); | ||
827 | value = 0.5 + 0.5*cos(value * 3.14159f); | ||
828 | LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0); | ||
829 | drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Loading...", ""); | ||
830 | } | ||
831 | } | ||
832 | #endif | ||
833 | |||
834 | // turn off the scissor | ||
835 | LLGLDisable no_scissor(GL_SCISSOR_TEST); | ||
836 | |||
837 | updateDirections(); | ||
838 | |||
839 | LLView::draw(); | ||
840 | |||
841 | updateVisibleBlocks(); | ||
842 | } | ||
843 | |||
844 | void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLPointer<LLViewerImage> image) | ||
845 | { | ||
846 | LLWorldMap::item_info_list_t::const_iterator e; | ||
847 | for (e = items.begin(); e != items.end(); ++e) | ||
848 | { | ||
849 | const LLItemInfo& info = *e; | ||
850 | |||
851 | drawGenericItem(info, image); | ||
852 | } | ||
853 | } | ||
854 | |||
855 | void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLPointer<LLViewerImage> image) | ||
856 | { | ||
857 | S32 half_width = image->getWidth()/2; | ||
858 | S32 half_height = image->getHeight()/2; | ||
859 | |||
860 | LLVector3 pos_map = globalPosToView( item.mPosGlobal ); | ||
861 | gl_draw_image(llround(pos_map.mV[VX]) - half_width, | ||
862 | llround(pos_map.mV[VY]) - half_height, | ||
863 | image, | ||
864 | LLColor4::white); | ||
865 | } | ||
866 | |||
867 | void LLWorldMapView::drawAgents() | ||
868 | { | ||
869 | //S32 half_width = sPopularImage->getWidth()/2; | ||
870 | //S32 half_height = sPopularImage->getHeight()/2; | ||
871 | |||
872 | F32 agents_scale = (gMapScale * 0.9f) / 256.f; | ||
873 | |||
874 | for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) | ||
875 | { | ||
876 | U64 handle = *iter; | ||
877 | LLSimInfo* siminfo = gWorldMap->simInfoFromHandle(handle); | ||
878 | if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN)) | ||
879 | { | ||
880 | continue; | ||
881 | } | ||
882 | LLWorldMap::agent_list_map_t::iterator countsiter = gWorldMap->mAgentLocationsMap.find(handle); | ||
883 | if (siminfo && siminfo->mShowAgentLocations && countsiter != gWorldMap->mAgentLocationsMap.end()) | ||
884 | { | ||
885 | // Show Individual agents | ||
886 | LLWorldMap::item_info_list_t& agentcounts = countsiter->second; | ||
887 | S32 sim_agent_count = 0; | ||
888 | for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin(); | ||
889 | iter != agentcounts.end(); ++iter) | ||
890 | { | ||
891 | const LLItemInfo& info = *iter; | ||
892 | LLVector3 pos_map = globalPosToView( info.mPosGlobal ); | ||
893 | S32 agent_count = info.mExtra; | ||
894 | if (agent_count > 0) | ||
895 | { | ||
896 | sim_agent_count += agent_count; | ||
897 | F32 y = 0; | ||
898 | for (S32 cur_agent = 0; cur_agent < agent_count; cur_agent++) | ||
899 | { | ||
900 | gl_draw_image(llround(pos_map.mV[VX]) - 4, | ||
901 | llround(pos_map.mV[VY] + y) - 4, | ||
902 | sAvatarSmallImage, | ||
903 | LLColor4::white ); | ||
904 | // move up a bit | ||
905 | y += 3.f; | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | gWorldMap->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim | ||
910 | } | ||
911 | else | ||
912 | { | ||
913 | // Show agent 'stack' at center of sim | ||
914 | S32 num_agents = gWorldMap->mNumAgents[handle]; | ||
915 | if (num_agents > 0) | ||
916 | { | ||
917 | LLVector3d region_pos = from_region_handle(handle); | ||
918 | region_pos[VX] += REGION_WIDTH_METERS * .5f; | ||
919 | region_pos[VY] += REGION_WIDTH_METERS * .5f; | ||
920 | LLVector3 pos_map = globalPosToView(region_pos); | ||
921 | // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more | ||
922 | S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1; | ||
923 | S32 y = 0; | ||
924 | S32 cur_agent; | ||
925 | for (cur_agent = 0; cur_agent < agent_count; cur_agent++) | ||
926 | { | ||
927 | gl_draw_image( | ||
928 | llround(pos_map.mV[VX]) - 4, | ||
929 | llround(pos_map.mV[VY]) + y - 4, | ||
930 | sAvatarSmallImage, | ||
931 | LLColor4::white ); | ||
932 | // move up a bit | ||
933 | y += 3; | ||
934 | } | ||
935 | } | ||
936 | } | ||
937 | } | ||
938 | } | ||
939 | |||
940 | |||
941 | void LLWorldMapView::drawEvents() | ||
942 | { | ||
943 | BOOL show_mature = gSavedSettings.getBOOL("ShowMatureEvents"); | ||
944 | |||
945 | // Non-selected events | ||
946 | // Draw under avatar so you can find yourself. | ||
947 | LLWorldMap::item_info_list_t::const_iterator e; | ||
948 | for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e) | ||
949 | { | ||
950 | const LLItemInfo& event = *e; | ||
951 | |||
952 | // Draw, but without relative-Z icons | ||
953 | if (!event.mSelected) | ||
954 | { | ||
955 | LLVector3 pos_map = globalPosToView( event.mPosGlobal ); | ||
956 | gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2, | ||
957 | llround(pos_map.mV[VY]) - sEventImage->getHeight()/2, | ||
958 | sEventImage, | ||
959 | LLColor4::white); | ||
960 | } | ||
961 | } | ||
962 | if (show_mature) | ||
963 | { | ||
964 | for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e) | ||
965 | { | ||
966 | const LLItemInfo& event = *e; | ||
967 | |||
968 | // Draw, but without relative-Z icons | ||
969 | if (!event.mSelected) | ||
970 | { | ||
971 | LLVector3 pos_map = globalPosToView( event.mPosGlobal ); | ||
972 | gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2, | ||
973 | llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2, | ||
974 | sEventMatureImage, | ||
975 | LLColor4::white); | ||
976 | } | ||
977 | } | ||
978 | } | ||
979 | |||
980 | // Selected events | ||
981 | // Draw under avatar so you can find yourself. | ||
982 | for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e) | ||
983 | { | ||
984 | const LLItemInfo& event = *e; | ||
985 | |||
986 | // Draw, but without relative-Z icons | ||
987 | if (event.mSelected) | ||
988 | { | ||
989 | LLVector3 pos_map = globalPosToView( event.mPosGlobal ); | ||
990 | gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2, | ||
991 | llround(pos_map.mV[VY]) - sEventImage->getHeight()/2, | ||
992 | sEventImage, | ||
993 | LLColor4::white); | ||
994 | |||
995 | //drawIconName( | ||
996 | // pos_map.mV[VX], | ||
997 | // pos_map.mV[VY], | ||
998 | // gEventColor, | ||
999 | // event.mToolTip.c_str(), | ||
1000 | // event.mName.c_str() ); | ||
1001 | } | ||
1002 | } | ||
1003 | if (show_mature) | ||
1004 | { | ||
1005 | for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e) | ||
1006 | { | ||
1007 | const LLItemInfo& event = *e; | ||
1008 | |||
1009 | // Draw, but without relative-Z icons | ||
1010 | if (event.mSelected) | ||
1011 | { | ||
1012 | LLVector3 pos_map = globalPosToView( event.mPosGlobal ); | ||
1013 | gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2, | ||
1014 | llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2, | ||
1015 | sEventMatureImage, | ||
1016 | LLColor4::white); | ||
1017 | |||
1018 | //drawIconName( | ||
1019 | // pos_map.mV[VX], | ||
1020 | // pos_map.mV[VY], | ||
1021 | // gEventColor, | ||
1022 | // event.mToolTip.c_str(), | ||
1023 | // event.mName.c_str() ); | ||
1024 | } | ||
1025 | } | ||
1026 | } | ||
1027 | } | ||
1028 | |||
1029 | void LLWorldMapView::drawDots() | ||
1030 | { | ||
1031 | |||
1032 | } | ||
1033 | |||
1034 | |||
1035 | void LLWorldMapView::drawFrustum() | ||
1036 | { | ||
1037 | // Draw frustum | ||
1038 | F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS; | ||
1039 | |||
1040 | F32 horiz_fov = gCamera->getView() * gCamera->getAspect(); | ||
1041 | F32 far_clip_meters = gCamera->getFar(); | ||
1042 | F32 far_clip_pixels = far_clip_meters * meters_to_pixels; | ||
1043 | |||
1044 | F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 ); | ||
1045 | F32 half_width_pixels = half_width_meters * meters_to_pixels; | ||
1046 | |||
1047 | F32 ctr_x = mRect.getWidth() * 0.5f + sPanX; | ||
1048 | F32 ctr_y = mRect.getHeight() * 0.5f + sPanY; | ||
1049 | |||
1050 | LLGLSNoTexture gls_no_texture; | ||
1051 | |||
1052 | // Since we don't rotate the map, we have to rotate the frustum. | ||
1053 | glPushMatrix(); | ||
1054 | glTranslatef( ctr_x, ctr_y, 0 ); | ||
1055 | glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f); | ||
1056 | |||
1057 | // Draw triangle with more alpha in far pixels to make it | ||
1058 | // fade out in distance. | ||
1059 | glBegin( GL_TRIANGLES ); | ||
1060 | glColor4f(1.f, 1.f, 1.f, 0.25f); | ||
1061 | glVertex2f( 0, 0 ); | ||
1062 | |||
1063 | glColor4f(1.f, 1.f, 1.f, 0.02f); | ||
1064 | glVertex2f( -half_width_pixels, far_clip_pixels ); | ||
1065 | |||
1066 | glColor4f(1.f, 1.f, 1.f, 0.02f); | ||
1067 | glVertex2f( half_width_pixels, far_clip_pixels ); | ||
1068 | glEnd(); | ||
1069 | glPopMatrix(); | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos ) | ||
1074 | { | ||
1075 | LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal(); | ||
1076 | LLVector3 pos_local; | ||
1077 | pos_local.setVec(relative_pos_global); // convert to floats from doubles | ||
1078 | |||
1079 | pos_local.mV[VX] *= sPixelsPerMeter; | ||
1080 | pos_local.mV[VY] *= sPixelsPerMeter; | ||
1081 | // leave Z component in meters | ||
1082 | |||
1083 | |||
1084 | pos_local.mV[VX] += mRect.getWidth() / 2 + sPanX; | ||
1085 | pos_local.mV[VY] += mRect.getHeight() / 2 + sPanY; | ||
1086 | |||
1087 | return pos_local; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& color, | ||
1092 | BOOL draw_arrow, LLString label, LLString tooltip, S32 vert_offset ) | ||
1093 | { | ||
1094 | LLVector3 pos_local = globalPosToView( pos_global ); | ||
1095 | S32 x = llround( pos_local.mV[VX] ); | ||
1096 | S32 y = llround( pos_local.mV[VY] ); | ||
1097 | LLFontGL* font = LLFontGL::sSansSerifSmall; | ||
1098 | S32 text_x = x; | ||
1099 | S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight()); | ||
1100 | |||
1101 | BOOL is_in_window = true; | ||
1102 | |||
1103 | if( x < 0 | ||
1104 | || y < 0 | ||
1105 | || x >= mRect.getWidth() | ||
1106 | || y >= mRect.getHeight() ) | ||
1107 | { | ||
1108 | if (draw_arrow) | ||
1109 | { | ||
1110 | drawTrackingCircle( mRect, x, y, color, 3, 15 ); | ||
1111 | drawTrackingArrow( mRect, x, y, color ); | ||
1112 | text_x = sTrackingArrowX; | ||
1113 | text_y = sTrackingArrowY; | ||
1114 | } | ||
1115 | is_in_window = false; | ||
1116 | } | ||
1117 | else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION && | ||
1118 | LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING) | ||
1119 | { | ||
1120 | drawTrackingCircle( mRect, x, y, color, 3, 15 ); | ||
1121 | } | ||
1122 | else | ||
1123 | { | ||
1124 | // Draw, but without relative Z | ||
1125 | gl_draw_image(x - sTrackCircleImage->getWidth()/2, | ||
1126 | y - sTrackCircleImage->getHeight()/2, | ||
1127 | sTrackCircleImage, | ||
1128 | color); | ||
1129 | } | ||
1130 | |||
1131 | // clamp text position to on-screen | ||
1132 | const S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2; | ||
1133 | S32 half_text_width = llfloor(font->getWidthF32(label) * 0.5f); | ||
1134 | text_x = llclamp(text_x, half_text_width + TEXT_PADDING, mRect.getWidth() - half_text_width - TEXT_PADDING); | ||
1135 | text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, mRect.getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset); | ||
1136 | |||
1137 | if (label != "") | ||
1138 | { | ||
1139 | font->renderUTF8( | ||
1140 | label, 0, | ||
1141 | text_x, | ||
1142 | text_y, | ||
1143 | LLColor4::white, LLFontGL::HCENTER, | ||
1144 | LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); | ||
1145 | |||
1146 | if (tooltip != "") | ||
1147 | { | ||
1148 | text_y -= (S32)font->getLineHeight(); | ||
1149 | |||
1150 | font->renderUTF8( | ||
1151 | tooltip, 0, | ||
1152 | text_x, | ||
1153 | text_y, | ||
1154 | LLColor4::white, LLFontGL::HCENTER, | ||
1155 | LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); | ||
1156 | } | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | // If you change this, then you need to change LLTracker::getTrackedPositionGlobal() as well | ||
1161 | LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y ) | ||
1162 | { | ||
1163 | x -= llfloor((mRect.getWidth() / 2 + sPanX)); | ||
1164 | y -= llfloor((mRect.getHeight() / 2 + sPanY)); | ||
1165 | |||
1166 | LLVector3 pos_local( (F32)x, (F32)y, 0.f ); | ||
1167 | |||
1168 | pos_local *= ( REGION_WIDTH_METERS / gMapScale ); | ||
1169 | |||
1170 | LLVector3d pos_global; | ||
1171 | pos_global.setVec( pos_local ); | ||
1172 | pos_global += gAgent.getCameraPositionGlobal(); | ||
1173 | if(gAgent.isGodlike()) | ||
1174 | { | ||
1175 | pos_global.mdV[VZ] = GODLY_TELEPORT_HEIGHT; // Godly height should always be 200. | ||
1176 | } | ||
1177 | else | ||
1178 | { | ||
1179 | pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ]; // Want agent's height, not camera's | ||
1180 | } | ||
1181 | |||
1182 | return pos_global; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen ) | ||
1187 | { | ||
1188 | if( !getVisible() || !pointInView( x, y ) ) | ||
1189 | { | ||
1190 | return FALSE; | ||
1191 | } | ||
1192 | |||
1193 | LLVector3d pos_global = viewPosToGlobal(x, y); | ||
1194 | |||
1195 | LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global); | ||
1196 | if (info) | ||
1197 | { | ||
1198 | LLViewerRegion *region = gAgent.getRegion(); | ||
1199 | |||
1200 | std::string message = | ||
1201 | llformat("%s (%s)", | ||
1202 | info->mName.c_str(), | ||
1203 | LLViewerRegion::accessToString(info->mAccess)); | ||
1204 | |||
1205 | if (info->mAccess != SIM_ACCESS_DOWN) | ||
1206 | { | ||
1207 | S32 agent_count = gWorldMap->mNumAgents[info->mHandle]; | ||
1208 | if (region && region->getHandle() == info->mHandle) | ||
1209 | { | ||
1210 | ++agent_count; // Bump by 1 if we're here | ||
1211 | } | ||
1212 | |||
1213 | // We may not have an agent count when the map is really | ||
1214 | // zoomed out, so don't display anything about the count. JC | ||
1215 | if (agent_count > 0) | ||
1216 | { | ||
1217 | message += llformat("\n%d ", agent_count); | ||
1218 | |||
1219 | if (agent_count == 1) | ||
1220 | { | ||
1221 | message += "person"; | ||
1222 | } | ||
1223 | else | ||
1224 | { | ||
1225 | message += "people"; | ||
1226 | } | ||
1227 | } | ||
1228 | } | ||
1229 | msg.assign( message ); | ||
1230 | |||
1231 | // Optionally show region flags | ||
1232 | std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags); | ||
1233 | |||
1234 | if (!region_flags.empty()) | ||
1235 | { | ||
1236 | msg += '\n'; | ||
1237 | msg += region_flags; | ||
1238 | } | ||
1239 | |||
1240 | S32 SLOP = 4; | ||
1241 | localPointToScreen( | ||
1242 | x - SLOP, y - SLOP, | ||
1243 | &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); | ||
1244 | sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; | ||
1245 | sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; | ||
1246 | } | ||
1247 | return TRUE; | ||
1248 | } | ||
1249 | |||
1250 | // Pass relative Z of 0 to draw at same level. | ||
1251 | // static | ||
1252 | void LLWorldMapView::drawAvatar(F32 x_pixels, | ||
1253 | F32 y_pixels, | ||
1254 | const LLColor4& color, | ||
1255 | F32 relative_z, | ||
1256 | F32 dot_radius) | ||
1257 | { | ||
1258 | F32 left = x_pixels - dot_radius; | ||
1259 | F32 right = x_pixels + dot_radius; | ||
1260 | F32 center = (left + right) * 0.5f; | ||
1261 | F32 top = y_pixels + dot_radius; | ||
1262 | F32 bottom = y_pixels - dot_radius; | ||
1263 | |||
1264 | const F32 HEIGHT_THRESHOLD = 7.f; | ||
1265 | |||
1266 | if (relative_z > HEIGHT_THRESHOLD) | ||
1267 | { | ||
1268 | LLGLSNoTexture gls_no_texture; | ||
1269 | glColor4fv( color.mV ); | ||
1270 | LLUI::setLineWidth(1.5f); | ||
1271 | glBegin( GL_LINES ); | ||
1272 | glVertex2f(left, top); | ||
1273 | glVertex2f(right, top); | ||
1274 | glVertex2f(center, top); | ||
1275 | glVertex2f(center, bottom); | ||
1276 | glEnd(); | ||
1277 | LLUI::setLineWidth(1.0f); | ||
1278 | } | ||
1279 | else if (relative_z > -HEIGHT_THRESHOLD) | ||
1280 | { | ||
1281 | gl_draw_image( llround(x_pixels) - sAvatarSmallImage->getWidth()/2, | ||
1282 | llround(y_pixels) - sAvatarSmallImage->getHeight()/2, | ||
1283 | sAvatarSmallImage, | ||
1284 | color); | ||
1285 | } | ||
1286 | else | ||
1287 | { | ||
1288 | LLGLSNoTexture gls_no_texture; | ||
1289 | glColor4fv( color.mV ); | ||
1290 | LLUI::setLineWidth(1.5f); | ||
1291 | glBegin( GL_LINES ); | ||
1292 | glVertex2f(center, top); | ||
1293 | glVertex2f(center, bottom); | ||
1294 | glVertex2f(left, bottom); | ||
1295 | glVertex2f(right, bottom); | ||
1296 | glEnd(); | ||
1297 | LLUI::setLineWidth(1.0f); | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | // Pass relative Z of 0 to draw at same level. | ||
1302 | // static | ||
1303 | void LLWorldMapView::drawTrackingDot( F32 x_pixels, | ||
1304 | F32 y_pixels, | ||
1305 | const LLColor4& color, | ||
1306 | F32 relative_z, | ||
1307 | F32 dot_radius) | ||
1308 | { | ||
1309 | F32 left = x_pixels - dot_radius; | ||
1310 | F32 right = x_pixels + dot_radius; | ||
1311 | F32 center = (left + right) * 0.5f; | ||
1312 | F32 top = y_pixels + dot_radius; | ||
1313 | F32 bottom = y_pixels - dot_radius; | ||
1314 | |||
1315 | const F32 HEIGHT_THRESHOLD = 7.f; | ||
1316 | |||
1317 | if (relative_z > HEIGHT_THRESHOLD) | ||
1318 | { | ||
1319 | LLGLSNoTexture gls_no_texture; | ||
1320 | glColor4fv( color.mV ); | ||
1321 | LLUI::setLineWidth(1.5f); | ||
1322 | glBegin( GL_LINES ); | ||
1323 | glVertex2f(left, top); | ||
1324 | glVertex2f(right, top); | ||
1325 | glVertex2f(center, top); | ||
1326 | glVertex2f(center, bottom); | ||
1327 | glEnd(); | ||
1328 | LLUI::setLineWidth(1.0f); | ||
1329 | } | ||
1330 | else if (relative_z > -HEIGHT_THRESHOLD) | ||
1331 | { | ||
1332 | gl_draw_image( llround(x_pixels) - sAvatarSmallImage->getWidth()/2, | ||
1333 | llround(y_pixels) - sAvatarSmallImage->getHeight()/2, | ||
1334 | sTrackCircleImage, | ||
1335 | color); | ||
1336 | } | ||
1337 | else | ||
1338 | { | ||
1339 | LLGLSNoTexture gls_no_texture; | ||
1340 | glColor4fv( color.mV ); | ||
1341 | LLUI::setLineWidth(1.5f); | ||
1342 | glBegin( GL_LINES ); | ||
1343 | glVertex2f(center, top); | ||
1344 | glVertex2f(center, bottom); | ||
1345 | glVertex2f(left, bottom); | ||
1346 | glVertex2f(right, bottom); | ||
1347 | glEnd(); | ||
1348 | LLUI::setLineWidth(1.0f); | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | |||
1353 | // Pass relative Z of 0 to draw at same level. | ||
1354 | // static | ||
1355 | void LLWorldMapView::drawIconName(F32 x_pixels, | ||
1356 | F32 y_pixels, | ||
1357 | const LLColor4& color, | ||
1358 | const std::string& first_line, | ||
1359 | const std::string& second_line) | ||
1360 | { | ||
1361 | const S32 VERT_PAD = 8; | ||
1362 | S32 text_x = llround(x_pixels); | ||
1363 | S32 text_y = llround(y_pixels | ||
1364 | - BIG_DOT_RADIUS | ||
1365 | - VERT_PAD); | ||
1366 | |||
1367 | // render text | ||
1368 | LLFontGL::sSansSerif->renderUTF8(first_line, 0, | ||
1369 | text_x, | ||
1370 | text_y, | ||
1371 | color, | ||
1372 | LLFontGL::HCENTER, | ||
1373 | LLFontGL::TOP, | ||
1374 | LLFontGL::DROP_SHADOW); | ||
1375 | |||
1376 | text_y -= llround(LLFontGL::sSansSerif->getLineHeight()); | ||
1377 | |||
1378 | // render text | ||
1379 | LLFontGL::sSansSerif->renderUTF8(second_line, 0, | ||
1380 | text_x, | ||
1381 | text_y, | ||
1382 | color, | ||
1383 | LLFontGL::HCENTER, | ||
1384 | LLFontGL::TOP, | ||
1385 | LLFontGL::DROP_SHADOW); | ||
1386 | } | ||
1387 | |||
1388 | |||
1389 | //static | ||
1390 | void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const LLColor4& color, S32 min_thickness, S32 overlap ) | ||
1391 | { | ||
1392 | F32 start_theta = 0.f; | ||
1393 | F32 end_theta = F_TWO_PI; | ||
1394 | F32 x_delta = 0.f; | ||
1395 | F32 y_delta = 0.f; | ||
1396 | |||
1397 | if (x < 0) | ||
1398 | { | ||
1399 | x_delta = 0.f - (F32)x; | ||
1400 | start_theta = F_PI + F_PI_BY_TWO; | ||
1401 | end_theta = F_TWO_PI + F_PI_BY_TWO; | ||
1402 | } | ||
1403 | else if (x > rect.getWidth()) | ||
1404 | { | ||
1405 | x_delta = (F32)(x - rect.getWidth()); | ||
1406 | start_theta = F_PI_BY_TWO; | ||
1407 | end_theta = F_PI + F_PI_BY_TWO; | ||
1408 | } | ||
1409 | |||
1410 | if (y < 0) | ||
1411 | { | ||
1412 | y_delta = 0.f - (F32)y; | ||
1413 | if (x < 0) | ||
1414 | { | ||
1415 | start_theta = 0.f; | ||
1416 | end_theta = F_PI_BY_TWO; | ||
1417 | } | ||
1418 | else if (x > rect.getWidth()) | ||
1419 | { | ||
1420 | start_theta = F_PI_BY_TWO; | ||
1421 | end_theta = F_PI; | ||
1422 | } | ||
1423 | else | ||
1424 | { | ||
1425 | start_theta = 0.f; | ||
1426 | end_theta = F_PI; | ||
1427 | } | ||
1428 | } | ||
1429 | else if (y > rect.getHeight()) | ||
1430 | { | ||
1431 | y_delta = (F32)(y - rect.getHeight()); | ||
1432 | if (x < 0) | ||
1433 | { | ||
1434 | start_theta = F_PI + F_PI_BY_TWO; | ||
1435 | end_theta = F_TWO_PI; | ||
1436 | } | ||
1437 | else if (x > rect.getWidth()) | ||
1438 | { | ||
1439 | start_theta = F_PI; | ||
1440 | end_theta = F_PI + F_PI_BY_TWO; | ||
1441 | } | ||
1442 | else | ||
1443 | { | ||
1444 | start_theta = F_PI; | ||
1445 | end_theta = F_TWO_PI; | ||
1446 | } | ||
1447 | } | ||
1448 | |||
1449 | F32 distance = sqrtf(x_delta * x_delta + y_delta * y_delta); | ||
1450 | |||
1451 | distance = llmax(0.1f, distance); | ||
1452 | |||
1453 | F32 outer_radius = distance + (1.f + (9.f * sqrtf(x_delta * y_delta) / distance)) * (F32)overlap; | ||
1454 | F32 inner_radius = outer_radius - (F32)min_thickness; | ||
1455 | |||
1456 | F32 angle_adjust_x = asin(x_delta / outer_radius); | ||
1457 | F32 angle_adjust_y = asin(y_delta / outer_radius); | ||
1458 | |||
1459 | if (angle_adjust_x) | ||
1460 | { | ||
1461 | if (angle_adjust_y) | ||
1462 | { | ||
1463 | F32 angle_adjust = llmin(angle_adjust_x, angle_adjust_y); | ||
1464 | start_theta += angle_adjust; | ||
1465 | end_theta -= angle_adjust; | ||
1466 | } | ||
1467 | else | ||
1468 | { | ||
1469 | start_theta += angle_adjust_x; | ||
1470 | end_theta -= angle_adjust_x; | ||
1471 | } | ||
1472 | } | ||
1473 | else if (angle_adjust_y) | ||
1474 | { | ||
1475 | start_theta += angle_adjust_y; | ||
1476 | end_theta -= angle_adjust_y; | ||
1477 | } | ||
1478 | |||
1479 | glMatrixMode(GL_MODELVIEW); | ||
1480 | glPushMatrix(); | ||
1481 | glTranslatef((F32)x, (F32)y, 0.f); | ||
1482 | gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color); | ||
1483 | glPopMatrix(); | ||
1484 | |||
1485 | } | ||
1486 | |||
1487 | // static | ||
1488 | void LLWorldMapView::drawTrackingArrow(const LLRect& rect, S32 x, S32 y, | ||
1489 | const LLColor4& color, | ||
1490 | S32 arrow_size) | ||
1491 | { | ||
1492 | F32 x_center = (F32)rect.getWidth() / 2.f; | ||
1493 | F32 y_center = (F32)rect.getHeight() / 2.f; | ||
1494 | |||
1495 | F32 x_clamped = (F32)llclamp( x, 0, rect.getWidth() - arrow_size ); | ||
1496 | F32 y_clamped = (F32)llclamp( y, 0, rect.getHeight() - arrow_size ); | ||
1497 | |||
1498 | F32 slope = (F32)(y - y_center) / (F32)(x - x_center); | ||
1499 | F32 window_ratio = (F32)rect.getHeight() / (F32)rect.getWidth(); | ||
1500 | |||
1501 | if (llabs(slope) > window_ratio && y_clamped != (F32)y) | ||
1502 | { | ||
1503 | // clamp by y | ||
1504 | x_clamped = (y_clamped - y_center) / slope + x_center; | ||
1505 | // adjust for arrow size | ||
1506 | x_clamped = llclamp(x_clamped , 0.f, (F32)(rect.getWidth() - arrow_size) ); | ||
1507 | } | ||
1508 | else if (x_clamped != (F32)x) | ||
1509 | { | ||
1510 | // clamp by x | ||
1511 | y_clamped = (x_clamped - x_center) * slope + y_center; | ||
1512 | // adjust for arrow size | ||
1513 | y_clamped = llclamp( y_clamped, 0.f, (F32)(rect.getHeight() - arrow_size) ); | ||
1514 | } | ||
1515 | |||
1516 | // *FIX: deal with non-square window properly. | ||
1517 | // I do not understand what this comment means -- is it actually | ||
1518 | // broken or is it correctly dealing with non-square | ||
1519 | // windows. Phoenix 2007-01-03. | ||
1520 | S32 half_arrow_size = (S32) (0.5f * arrow_size); | ||
1521 | |||
1522 | F32 angle = atan2( y + half_arrow_size - y_center, x + half_arrow_size - x_center); | ||
1523 | |||
1524 | sTrackingArrowX = llfloor(x_clamped); | ||
1525 | sTrackingArrowY = llfloor(y_clamped); | ||
1526 | |||
1527 | gl_draw_scaled_rotated_image( | ||
1528 | sTrackingArrowX, | ||
1529 | sTrackingArrowY, | ||
1530 | arrow_size, arrow_size, | ||
1531 | RAD_TO_DEG * angle, | ||
1532 | sTrackArrowImage, | ||
1533 | color); | ||
1534 | } | ||
1535 | |||
1536 | void LLWorldMapView::setDirectionPos( LLTextBox* text_box, F32 rotation ) | ||
1537 | { | ||
1538 | // Rotation is in radians. | ||
1539 | // Rotation of 0 means x = 1, y = 0 on the unit circle. | ||
1540 | |||
1541 | |||
1542 | F32 map_half_height = mRect.getHeight() * 0.5f; | ||
1543 | F32 map_half_width = mRect.getWidth() * 0.5f; | ||
1544 | F32 text_half_height = text_box->getRect().getHeight() * 0.5f; | ||
1545 | F32 text_half_width = text_box->getRect().getWidth() * 0.5f; | ||
1546 | F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width ); | ||
1547 | |||
1548 | text_box->setOrigin( | ||
1549 | llround(map_half_width - text_half_width + radius * cos( rotation )), | ||
1550 | llround(map_half_height - text_half_height + radius * sin( rotation )) ); | ||
1551 | } | ||
1552 | |||
1553 | |||
1554 | void LLWorldMapView::updateDirections() | ||
1555 | { | ||
1556 | S32 width = mRect.getWidth(); | ||
1557 | S32 height = mRect.getHeight(); | ||
1558 | |||
1559 | S32 text_height = mTextBoxNorth->getRect().getHeight(); | ||
1560 | S32 text_width = mTextBoxNorth->getRect().getWidth(); | ||
1561 | |||
1562 | const S32 PAD = 2; | ||
1563 | S32 top = height - text_height - PAD; | ||
1564 | S32 left = PAD*2; | ||
1565 | S32 bottom = PAD; | ||
1566 | S32 right = width - text_width - PAD; | ||
1567 | S32 center_x = width/2 - text_width/2; | ||
1568 | S32 center_y = height/2 - text_height/2; | ||
1569 | |||
1570 | mTextBoxNorth->setOrigin( center_x, top ); | ||
1571 | mTextBoxEast->setOrigin( right, center_y ); | ||
1572 | mTextBoxSouth->setOrigin( center_x, bottom ); | ||
1573 | mTextBoxWest->setOrigin( left, center_y ); | ||
1574 | |||
1575 | // These have wider text boxes | ||
1576 | text_width = mTextBoxNorthWest->getRect().getWidth(); | ||
1577 | right = width - text_width - PAD; | ||
1578 | |||
1579 | mTextBoxNorthWest->setOrigin(left, top); | ||
1580 | mTextBoxNorthEast->setOrigin(right, top); | ||
1581 | mTextBoxSouthWest->setOrigin(left, bottom); | ||
1582 | mTextBoxSouthEast->setOrigin(right, bottom); | ||
1583 | |||
1584 | // S32 hint_width = mTextBoxScrollHint->getRect().getWidth(); | ||
1585 | // mTextBoxScrollHint->setOrigin( width - hint_width - text_width - 2 * PAD, | ||
1586 | // PAD * 2 + text_height ); | ||
1587 | } | ||
1588 | |||
1589 | |||
1590 | void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent ) | ||
1591 | { | ||
1592 | LLView::reshape( width, height, called_from_parent ); | ||
1593 | } | ||
1594 | |||
1595 | bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track) | ||
1596 | { | ||
1597 | LLVector3 pos_view = globalPosToView(item.mPosGlobal); | ||
1598 | S32 item_x = llround(pos_view.mV[VX]); | ||
1599 | S32 item_y = llround(pos_view.mV[VY]); | ||
1600 | |||
1601 | if (x < item_x - BIG_DOT_RADIUS) return false; | ||
1602 | if (x > item_x + BIG_DOT_RADIUS) return false; | ||
1603 | if (y < item_y - BIG_DOT_RADIUS) return false; | ||
1604 | if (y > item_y + BIG_DOT_RADIUS) return false; | ||
1605 | |||
1606 | LLSimInfo* sim_info = gWorldMap->simInfoFromHandle(item.mRegionHandle); | ||
1607 | if (sim_info) | ||
1608 | { | ||
1609 | if (track) | ||
1610 | { | ||
1611 | gFloaterWorldMap->trackLocation(item.mPosGlobal); | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | if (track) | ||
1616 | { | ||
1617 | gFloaterWorldMap->trackGenericItem(item); | ||
1618 | } | ||
1619 | |||
1620 | item.mSelected = TRUE; | ||
1621 | *id = item.mID; | ||
1622 | |||
1623 | return true; | ||
1624 | } | ||
1625 | |||
1626 | // Handle a click, which might be on a dot | ||
1627 | void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask, | ||
1628 | S32* hit_type, | ||
1629 | LLUUID* id) | ||
1630 | { | ||
1631 | LLVector3d pos_global = viewPosToGlobal(x, y); | ||
1632 | |||
1633 | // *HACK: Adjust Z values automatically for liaisons & gods so | ||
1634 | // we swoop down when they click on the map. Sadly, the P2P | ||
1635 | // branch does not pay attention to this value; however, the | ||
1636 | // Distributed Messaging branch honors kt. | ||
1637 | if(gAgent.isGodlike()) | ||
1638 | { | ||
1639 | pos_global.mdV[VZ] = 200.0; | ||
1640 | } | ||
1641 | |||
1642 | *hit_type = 0; // hit nothing | ||
1643 | |||
1644 | gWorldMap->mIsTrackingUnknownLocation = FALSE; | ||
1645 | gWorldMap->mIsTrackingDoubleClick = FALSE; | ||
1646 | gWorldMap->mIsTrackingCommit = FALSE; | ||
1647 | |||
1648 | LLWorldMap::item_info_list_t::iterator it; | ||
1649 | |||
1650 | // clear old selected stuff | ||
1651 | for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it) | ||
1652 | { | ||
1653 | (*it).mSelected = FALSE; | ||
1654 | } | ||
1655 | for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it) | ||
1656 | { | ||
1657 | (*it).mSelected = FALSE; | ||
1658 | } | ||
1659 | for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it) | ||
1660 | { | ||
1661 | (*it).mSelected = FALSE; | ||
1662 | } | ||
1663 | for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it) | ||
1664 | { | ||
1665 | (*it).mSelected = FALSE; | ||
1666 | } | ||
1667 | for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it) | ||
1668 | { | ||
1669 | (*it).mSelected = FALSE; | ||
1670 | } | ||
1671 | |||
1672 | // Select event you clicked on | ||
1673 | if (gSavedSettings.getBOOL("MapShowEvents")) | ||
1674 | { | ||
1675 | for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it) | ||
1676 | { | ||
1677 | LLItemInfo& event = *it; | ||
1678 | |||
1679 | if (checkItemHit(x, y, event, id, false)) | ||
1680 | { | ||
1681 | *hit_type = MAP_ITEM_PG_EVENT; | ||
1682 | mItemPicked = TRUE; | ||
1683 | gFloaterWorldMap->trackEvent(event); | ||
1684 | return; | ||
1685 | } | ||
1686 | } | ||
1687 | if (gSavedSettings.getBOOL("ShowMatureEvents")) | ||
1688 | { | ||
1689 | for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it) | ||
1690 | { | ||
1691 | LLItemInfo& event = *it; | ||
1692 | |||
1693 | if (checkItemHit(x, y, event, id, false)) | ||
1694 | { | ||
1695 | *hit_type = MAP_ITEM_MATURE_EVENT; | ||
1696 | mItemPicked = TRUE; | ||
1697 | gFloaterWorldMap->trackEvent(event); | ||
1698 | return; | ||
1699 | } | ||
1700 | } | ||
1701 | } | ||
1702 | } | ||
1703 | |||
1704 | if (gSavedSettings.getBOOL("MapShowPopular")) | ||
1705 | { | ||
1706 | for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it) | ||
1707 | { | ||
1708 | LLItemInfo& popular = *it; | ||
1709 | |||
1710 | if (checkItemHit(x, y, popular, id, true)) | ||
1711 | { | ||
1712 | *hit_type = MAP_ITEM_POPULAR; | ||
1713 | mItemPicked = TRUE; | ||
1714 | return; | ||
1715 | } | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | if (gSavedSettings.getBOOL("MapShowLandForSale")) | ||
1720 | { | ||
1721 | for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it) | ||
1722 | { | ||
1723 | LLItemInfo& land = *it; | ||
1724 | |||
1725 | if (checkItemHit(x, y, land, id, true)) | ||
1726 | { | ||
1727 | *hit_type = MAP_ITEM_LAND_FOR_SALE; | ||
1728 | mItemPicked = TRUE; | ||
1729 | return; | ||
1730 | } | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | if (gSavedSettings.getBOOL("MapShowClassifieds")) | ||
1735 | { | ||
1736 | for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it) | ||
1737 | { | ||
1738 | LLItemInfo& classified = *it; | ||
1739 | |||
1740 | if (checkItemHit(x, y, classified, id, true)) | ||
1741 | { | ||
1742 | *hit_type = MAP_ITEM_CLASSIFIED; | ||
1743 | mItemPicked = TRUE; | ||
1744 | return; | ||
1745 | } | ||
1746 | } | ||
1747 | } | ||
1748 | |||
1749 | // If we get here, we haven't clicked on an icon | ||
1750 | |||
1751 | gFloaterWorldMap->trackLocation(pos_global); | ||
1752 | mItemPicked = FALSE; | ||
1753 | |||
1754 | *id = LLUUID::null; | ||
1755 | return; | ||
1756 | } | ||
1757 | |||
1758 | |||
1759 | BOOL outside_slop(S32 x, S32 y, S32 start_x, S32 start_y) | ||
1760 | { | ||
1761 | S32 dx = x - start_x; | ||
1762 | S32 dy = y - start_y; | ||
1763 | |||
1764 | return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy); | ||
1765 | } | ||
1766 | |||
1767 | BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask ) | ||
1768 | { | ||
1769 | gFocusMgr.setMouseCapture( this, NULL ); | ||
1770 | |||
1771 | mMouseDownPanX = llround(sPanX); | ||
1772 | mMouseDownPanY = llround(sPanY); | ||
1773 | mMouseDownX = x; | ||
1774 | mMouseDownY = y; | ||
1775 | sHandledLastClick = TRUE; | ||
1776 | return TRUE; | ||
1777 | } | ||
1778 | |||
1779 | BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask ) | ||
1780 | { | ||
1781 | if (this == gFocusMgr.getMouseCapture()) | ||
1782 | { | ||
1783 | if (mPanning) | ||
1784 | { | ||
1785 | // restore mouse cursor | ||
1786 | S32 local_x, local_y; | ||
1787 | local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX); | ||
1788 | local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY); | ||
1789 | LLRect clip_rect = mRect; | ||
1790 | clip_rect.stretch(-8); | ||
1791 | clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y); | ||
1792 | LLUI::setCursorPositionLocal(this, local_x, local_y); | ||
1793 | |||
1794 | // finish the pan | ||
1795 | mPanning = FALSE; | ||
1796 | |||
1797 | mMouseDownX = 0; | ||
1798 | mMouseDownY = 0; | ||
1799 | } | ||
1800 | else | ||
1801 | { | ||
1802 | // ignore whether we hit an event or not | ||
1803 | S32 hit_type; | ||
1804 | LLUUID id; | ||
1805 | handleClick(x, y, mask, &hit_type, &id); | ||
1806 | } | ||
1807 | gViewerWindow->showCursor(); | ||
1808 | gFocusMgr.setMouseCapture( NULL, NULL ); | ||
1809 | return TRUE; | ||
1810 | } | ||
1811 | return FALSE; | ||
1812 | } | ||
1813 | |||
1814 | void LLWorldMapView::updateBlock(S32 block_x, S32 block_y) | ||
1815 | { | ||
1816 | S32 offset = block_x | (block_y * MAP_BLOCK_RES); | ||
1817 | if (!gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset]) | ||
1818 | { | ||
1819 | // llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl; | ||
1820 | gWorldMap->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7); | ||
1821 | gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset] = TRUE; | ||
1822 | } | ||
1823 | } | ||
1824 | |||
1825 | void LLWorldMapView::updateVisibleBlocks() | ||
1826 | { | ||
1827 | if (gMapScale < SIM_MAP_SCALE) | ||
1828 | { | ||
1829 | // We don't care what is loaded if we're zoomed out | ||
1830 | return; | ||
1831 | } | ||
1832 | // check if we've loaded the 9 potentially visible zones | ||
1833 | LLVector3d camera_global = gAgent.getCameraPositionGlobal(); | ||
1834 | |||
1835 | // Convert pan to sim coordinates | ||
1836 | S32 world_center_x = S32((-sPanX / gMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS)); | ||
1837 | S32 world_center_y = S32((-sPanY / gMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS)); | ||
1838 | |||
1839 | // Find the corresponding 8x8 block | ||
1840 | S32 world_block_x = world_center_x >> 3; | ||
1841 | S32 world_block_y = world_center_y >> 3; | ||
1842 | |||
1843 | for (S32 block_x = llmax(world_block_x-1, 0); block_x <= llmin(world_block_x+1, MAP_BLOCK_RES-1); ++block_x) | ||
1844 | { | ||
1845 | for (S32 block_y = llmax(world_block_y-1, 0); block_y <= llmin(world_block_y+1, MAP_BLOCK_RES-1); ++block_y) | ||
1846 | { | ||
1847 | updateBlock(block_x, block_y); | ||
1848 | } | ||
1849 | } | ||
1850 | } | ||
1851 | |||
1852 | BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask ) | ||
1853 | { | ||
1854 | if (this == gFocusMgr.getMouseCapture()) | ||
1855 | { | ||
1856 | if (mPanning || outside_slop(x, y, mMouseDownX, mMouseDownY)) | ||
1857 | { | ||
1858 | // just started panning, so hide cursor | ||
1859 | if (!mPanning) | ||
1860 | { | ||
1861 | mPanning = TRUE; | ||
1862 | gViewerWindow->hideCursor(); | ||
1863 | } | ||
1864 | |||
1865 | F32 delta_x = (F32)(gViewerWindow->getCurrentMouseDX()); | ||
1866 | F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY()); | ||
1867 | |||
1868 | // Set pan to value at start of drag + offset | ||
1869 | sPanX += delta_x; | ||
1870 | sPanY += delta_y; | ||
1871 | sTargetPanX = sPanX; | ||
1872 | sTargetPanY = sPanY; | ||
1873 | |||
1874 | gViewerWindow->moveCursorToCenter(); | ||
1875 | } | ||
1876 | |||
1877 | // doesn't matter, cursor should be hidden | ||
1878 | gViewerWindow->setCursor(UI_CURSOR_CROSS ); | ||
1879 | return TRUE; | ||
1880 | } | ||
1881 | else | ||
1882 | { | ||
1883 | // While we're waiting for data from the tracker, we're busy. JC | ||
1884 | LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); | ||
1885 | if (LLTracker::isTracking(NULL) | ||
1886 | && pos_global.isExactlyZero()) | ||
1887 | { | ||
1888 | gViewerWindow->setCursor( UI_CURSOR_WAIT ); | ||
1889 | } | ||
1890 | else | ||
1891 | { | ||
1892 | gViewerWindow->setCursor( UI_CURSOR_CROSS ); | ||
1893 | } | ||
1894 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLWorldMapView" << llendl; | ||
1895 | return TRUE; | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | |||
1900 | BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) | ||
1901 | { | ||
1902 | if( sHandledLastClick ) | ||
1903 | { | ||
1904 | S32 hit_type; | ||
1905 | LLUUID id; | ||
1906 | handleClick(x, y, mask, &hit_type, &id); | ||
1907 | |||
1908 | switch (hit_type) | ||
1909 | { | ||
1910 | case MAP_ITEM_PG_EVENT: | ||
1911 | case MAP_ITEM_MATURE_EVENT: | ||
1912 | { | ||
1913 | gFloaterWorldMap->close(); | ||
1914 | // This is an ungainly hack | ||
1915 | char uuid_str[38]; | ||
1916 | S32 event_id; | ||
1917 | id.toString(uuid_str); | ||
1918 | sscanf(&uuid_str[28], "%X", &event_id); | ||
1919 | LLFloaterDirectory::showEvents(event_id); | ||
1920 | break; | ||
1921 | } | ||
1922 | case MAP_ITEM_POPULAR: | ||
1923 | { | ||
1924 | gFloaterWorldMap->close(); | ||
1925 | LLFloaterDirectory::showPopular(id); | ||
1926 | break; | ||
1927 | } | ||
1928 | case MAP_ITEM_LAND_FOR_SALE: | ||
1929 | { | ||
1930 | gFloaterWorldMap->close(); | ||
1931 | LLFloaterDirectory::showLandForSale(id); | ||
1932 | break; | ||
1933 | } | ||
1934 | case MAP_ITEM_CLASSIFIED: | ||
1935 | { | ||
1936 | gFloaterWorldMap->close(); | ||
1937 | LLFloaterDirectory::showClassified(id); | ||
1938 | break; | ||
1939 | } | ||
1940 | default: | ||
1941 | { | ||
1942 | if (gWorldMap->mIsTrackingUnknownLocation) | ||
1943 | { | ||
1944 | gWorldMap->mIsTrackingDoubleClick = TRUE; | ||
1945 | } | ||
1946 | else | ||
1947 | { | ||
1948 | // Teleport if we got a valid location | ||
1949 | LLVector3d pos_global = viewPosToGlobal(x,y); | ||
1950 | LLSimInfo* sim_info = gWorldMap->simInfoFromPosGlobal(pos_global); | ||
1951 | if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN) | ||
1952 | { | ||
1953 | gAgent.teleportViaLocation( pos_global ); | ||
1954 | } | ||
1955 | } | ||
1956 | } | ||
1957 | }; | ||
1958 | |||
1959 | return TRUE; | ||
1960 | } | ||
1961 | return FALSE; | ||
1962 | } | ||