diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/lltracker.cpp | 820 |
1 files changed, 820 insertions, 0 deletions
diff --git a/linden/indra/newview/lltracker.cpp b/linden/indra/newview/lltracker.cpp new file mode 100644 index 0000000..58ba9b8 --- /dev/null +++ b/linden/indra/newview/lltracker.cpp | |||
@@ -0,0 +1,820 @@ | |||
1 | /** | ||
2 | * @file lltracker.cpp | ||
3 | * @brief Container for objects user is tracking. | ||
4 | * | ||
5 | * Copyright (c) 2003-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 | // library includes | ||
31 | #include "llcoord.h" | ||
32 | #include "lldarray.h" | ||
33 | #include "llfontgl.h" | ||
34 | #include "llgl.h" | ||
35 | #include "llinventory.h" | ||
36 | #include "llmemory.h" | ||
37 | #include "llstring.h" | ||
38 | #include "lluuid.h" | ||
39 | #include "v3math.h" | ||
40 | #include "v3dmath.h" | ||
41 | #include "v4color.h" | ||
42 | |||
43 | // viewer includes | ||
44 | #include "viewer.h" | ||
45 | #include "lltracker.h" | ||
46 | #include "llagent.h" | ||
47 | #include "llcallingcard.h" | ||
48 | #include "llcolorscheme.h" | ||
49 | #include "llcylinder.h" | ||
50 | #include "llfloaterworldmap.h" | ||
51 | #include "llhudtext.h" | ||
52 | #include "llhudview.h" | ||
53 | #include "llinventorymodel.h" | ||
54 | #include "lllandmarklist.h" | ||
55 | #include "llsky.h" | ||
56 | #include "llui.h" | ||
57 | #include "llviewercamera.h" | ||
58 | #include "llviewerinventory.h" | ||
59 | #include "llworld.h" | ||
60 | #include "llworldmapview.h" | ||
61 | |||
62 | const F32 DESTINATION_REACHED_RADIUS = 3.0f; | ||
63 | const F32 DESTINATION_VISITED_RADIUS = 6.0f; | ||
64 | |||
65 | // this last one is useful for when the landmark is | ||
66 | // very close to agent when tracking is turned on | ||
67 | const F32 DESTINATION_UNVISITED_RADIUS = 12.0f; | ||
68 | |||
69 | const S32 ARROW_OFF_RADIUS_SQRD = 100; | ||
70 | |||
71 | const S32 HUD_ARROW_SIZE = 32; | ||
72 | |||
73 | // static | ||
74 | LLTracker *LLTracker::sTrackerp = NULL; | ||
75 | BOOL LLTracker::sCheesyBeacon = FALSE; | ||
76 | |||
77 | LLTracker::LLTracker() | ||
78 | : mTrackingStatus(TRACKING_NOTHING), | ||
79 | mTrackingLocationType(LOCATION_NOTHING), | ||
80 | mHUDArrowCenterX(0), | ||
81 | mHUDArrowCenterY(0), | ||
82 | mToolTip( "" ), | ||
83 | mTrackedLandmarkName(""), | ||
84 | mHasReachedLandmark(FALSE), | ||
85 | mHasLandmarkPosition(FALSE), | ||
86 | mLandmarkHasBeenVisited(FALSE), | ||
87 | mTrackedLocationName( "" ), | ||
88 | mIsTrackingLocation(FALSE) | ||
89 | { } | ||
90 | |||
91 | |||
92 | LLTracker::~LLTracker() | ||
93 | { | ||
94 | purgeBeaconText(); | ||
95 | } | ||
96 | |||
97 | |||
98 | // static | ||
99 | void LLTracker::stopTracking(void* userdata) | ||
100 | { | ||
101 | BOOL clear_ui = ((BOOL)(intptr_t)userdata); | ||
102 | instance()->stopTrackingAll(clear_ui); | ||
103 | } | ||
104 | |||
105 | |||
106 | // static virtual | ||
107 | void LLTracker::drawHUDArrow() | ||
108 | { | ||
109 | /* tracking autopilot destination has been disabled | ||
110 | -- 2004.01.09, Leviathan | ||
111 | // Draw dot for autopilot target | ||
112 | if (gAgent.getAutoPilot()) | ||
113 | { | ||
114 | instance()->drawMarker( gAgent.getAutoPilotTargetGlobal(), gTrackColor ); | ||
115 | return; | ||
116 | } | ||
117 | */ | ||
118 | switch (getTrackingStatus()) | ||
119 | { | ||
120 | case TRACKING_AVATAR: | ||
121 | // Tracked avatar | ||
122 | if(LLAvatarTracker::instance().haveTrackingInfo()) | ||
123 | { | ||
124 | instance()->drawMarker( LLAvatarTracker::instance().getGlobalPos(), gTrackColor ); | ||
125 | } | ||
126 | break; | ||
127 | |||
128 | case TRACKING_LANDMARK: | ||
129 | instance()->drawMarker( getTrackedPositionGlobal(), gTrackColor ); | ||
130 | break; | ||
131 | |||
132 | case TRACKING_LOCATION: | ||
133 | if (!gWorldp) | ||
134 | { | ||
135 | break; | ||
136 | } | ||
137 | // HACK -- try to keep the location just above the terrain | ||
138 | #if 0 | ||
139 | // UNHACKED by CRO - keep location where the location is | ||
140 | instance()->mTrackedPositionGlobal.mdV[VZ] = | ||
141 | 0.9f * instance()->mTrackedPositionGlobal.mdV[VZ] | ||
142 | + 0.1f * (gWorldp->resolveLandHeightGlobal(getTrackedPositionGlobal()) + 1.5f); | ||
143 | #endif | ||
144 | instance()->mTrackedPositionGlobal.mdV[VZ] = llclamp((F32)instance()->mTrackedPositionGlobal.mdV[VZ], gWorldp->resolveLandHeightGlobal(getTrackedPositionGlobal()) + 1.5f, (F32)instance()->getTrackedPositionGlobal().mdV[VZ]); | ||
145 | instance()->drawMarker( getTrackedPositionGlobal(), gTrackColor ); | ||
146 | break; | ||
147 | |||
148 | default: | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | |||
154 | // static | ||
155 | void LLTracker::render3D() | ||
156 | { | ||
157 | if (!gFloaterWorldMap) | ||
158 | { | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | // Arbitary location beacon | ||
163 | if( instance()->mIsTrackingLocation ) | ||
164 | { | ||
165 | if (!instance()->mBeaconText) | ||
166 | { | ||
167 | instance()->mBeaconText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); | ||
168 | instance()->mBeaconText->setDoFade(FALSE); | ||
169 | } | ||
170 | |||
171 | LLVector3d pos_global = instance()->mTrackedPositionGlobal; | ||
172 | // (z-attenuation < 1) means compute "shorter" distance in z-axis, | ||
173 | // so cancel tracking even if avatar is a little above or below. | ||
174 | F32 dist = gFloaterWorldMap->getDistanceToDestination(pos_global, 0.5f); | ||
175 | if (dist < DESTINATION_REACHED_RADIUS) | ||
176 | { | ||
177 | instance()->stopTrackingLocation(); | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | renderBeacon( instance()->mTrackedPositionGlobal, gTrackColor, | ||
182 | instance()->mBeaconText, instance()->mTrackedLocationName ); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | // Landmark beacon | ||
187 | else if( !instance()->mTrackedLandmarkAssetID.isNull() ) | ||
188 | { | ||
189 | if (!instance()->mBeaconText) | ||
190 | { | ||
191 | instance()->mBeaconText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); | ||
192 | instance()->mBeaconText->setDoFade(FALSE); | ||
193 | } | ||
194 | |||
195 | if (instance()->mHasLandmarkPosition) | ||
196 | { | ||
197 | F32 dist = gFloaterWorldMap->getDistanceToDestination(instance()->mTrackedPositionGlobal, 1.0f); | ||
198 | |||
199 | if ( !instance()->mLandmarkHasBeenVisited | ||
200 | && dist < DESTINATION_VISITED_RADIUS ) | ||
201 | { | ||
202 | // its close enough ==> flag as visited | ||
203 | instance()->setLandmarkVisited(); | ||
204 | } | ||
205 | |||
206 | if ( !instance()->mHasReachedLandmark | ||
207 | && dist < DESTINATION_REACHED_RADIUS ) | ||
208 | { | ||
209 | // its VERY CLOSE ==> automatically stop tracking | ||
210 | instance()->stopTrackingLandmark(); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | if ( instance()->mHasReachedLandmark | ||
215 | && dist > DESTINATION_UNVISITED_RADIUS ) | ||
216 | { | ||
217 | // this is so that landmark beacons don't immediately | ||
218 | // disappear when they're created only a few meters | ||
219 | // away, yet disappear when the agent wanders away | ||
220 | // and back again | ||
221 | instance()->mHasReachedLandmark = FALSE; | ||
222 | } | ||
223 | renderBeacon( instance()->mTrackedPositionGlobal, gTrackColor, | ||
224 | instance()->mBeaconText, instance()->mTrackedLandmarkName ); | ||
225 | } | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | // probably just finished downloading the asset | ||
230 | instance()->cacheLandmarkPosition(); | ||
231 | } | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | // Avatar beacon | ||
236 | LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); | ||
237 | if(av_tracker.haveTrackingInfo()) | ||
238 | { | ||
239 | if (!instance()->mBeaconText) | ||
240 | { | ||
241 | instance()->mBeaconText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); | ||
242 | instance()->mBeaconText->setDoFade(FALSE); | ||
243 | } | ||
244 | |||
245 | F32 dist = gFloaterWorldMap->getDistanceToDestination(instance()->mTrackedPositionGlobal, 0.0f); | ||
246 | if (dist < DESTINATION_REACHED_RADIUS) | ||
247 | { | ||
248 | instance()->stopTrackingAvatar(); | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | renderBeacon( av_tracker.getGlobalPos(), gTrackColor, | ||
253 | instance()->mBeaconText, av_tracker.getName() ); | ||
254 | } | ||
255 | } | ||
256 | else | ||
257 | { | ||
258 | BOOL stop_tracking = FALSE; | ||
259 | const LLUUID& avatar_id = av_tracker.getAvatarID(); | ||
260 | if(avatar_id.isNull()) | ||
261 | { | ||
262 | stop_tracking = TRUE; | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | const LLRelationship* buddy = av_tracker.getBuddyInfo(avatar_id); | ||
267 | if(buddy && !buddy->isOnline()) | ||
268 | { | ||
269 | stop_tracking = TRUE; | ||
270 | } | ||
271 | if(!buddy && !gAgent.isGodlike()) | ||
272 | { | ||
273 | stop_tracking = TRUE; | ||
274 | } | ||
275 | } | ||
276 | if(stop_tracking) | ||
277 | { | ||
278 | instance()->stopTrackingAvatar(); | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | |||
285 | // static | ||
286 | void LLTracker::trackAvatar( const LLUUID& avatar_id, const LLString& name ) | ||
287 | { | ||
288 | instance()->stopTrackingLandmark(); | ||
289 | instance()->stopTrackingLocation(); | ||
290 | |||
291 | LLAvatarTracker::instance().track( avatar_id, name ); | ||
292 | instance()->mTrackingStatus = TRACKING_AVATAR; | ||
293 | instance()->mLabel = name; | ||
294 | } | ||
295 | |||
296 | |||
297 | // static | ||
298 | void LLTracker::trackLandmark( const LLUUID& asset_id, const LLUUID& item_id, const LLString& name) | ||
299 | { | ||
300 | instance()->stopTrackingAvatar(); | ||
301 | instance()->stopTrackingLocation(); | ||
302 | |||
303 | instance()->mTrackedLandmarkAssetID = asset_id; | ||
304 | instance()->mTrackedLandmarkItemID = item_id; | ||
305 | instance()->mTrackedLandmarkName = name; | ||
306 | instance()->cacheLandmarkPosition(); | ||
307 | instance()->mTrackingStatus = TRACKING_LANDMARK; | ||
308 | instance()->mLabel = name; | ||
309 | } | ||
310 | |||
311 | |||
312 | // static | ||
313 | void LLTracker::trackLocation(const LLVector3d& pos_global, const LLString& full_name, const LLString& tooltip, ETrackingLocationType location_type) | ||
314 | { | ||
315 | instance()->stopTrackingAvatar(); | ||
316 | instance()->stopTrackingLandmark(); | ||
317 | |||
318 | instance()->mTrackedPositionGlobal = pos_global; | ||
319 | instance()->mTrackedLocationName = full_name; | ||
320 | instance()->mIsTrackingLocation = TRUE; | ||
321 | instance()->mTrackingStatus = TRACKING_LOCATION; | ||
322 | instance()->mTrackingLocationType = location_type; | ||
323 | instance()->mLabel = full_name; | ||
324 | instance()->mToolTip = tooltip; | ||
325 | } | ||
326 | |||
327 | |||
328 | // static | ||
329 | BOOL LLTracker::handleMouseDown(S32 x, S32 y) | ||
330 | { | ||
331 | BOOL eat_mouse_click = FALSE; | ||
332 | // fortunately, we can always compute the tracking arrow center | ||
333 | S32 dist_sqrd = (x - instance()->mHUDArrowCenterX) * (x - instance()->mHUDArrowCenterX) + | ||
334 | (y - instance()->mHUDArrowCenterY) * (y - instance()->mHUDArrowCenterY); | ||
335 | if (dist_sqrd < ARROW_OFF_RADIUS_SQRD) | ||
336 | { | ||
337 | /* tracking autopilot destination has been disabled | ||
338 | -- 2004.01.09, Leviathan | ||
339 | // turn off tracking | ||
340 | if (gAgent.getAutoPilot()) | ||
341 | { | ||
342 | gAgent.stopAutoPilot(TRUE); // TRUE because cancelled by user | ||
343 | eat_mouse_click = TRUE; | ||
344 | } | ||
345 | */ | ||
346 | if (getTrackingStatus()) | ||
347 | { | ||
348 | instance()->stopTrackingAll(); | ||
349 | eat_mouse_click = TRUE; | ||
350 | } | ||
351 | } | ||
352 | return eat_mouse_click; | ||
353 | } | ||
354 | |||
355 | |||
356 | // static | ||
357 | LLVector3d LLTracker::getTrackedPositionGlobal() | ||
358 | { | ||
359 | LLVector3d pos_global; | ||
360 | switch (getTrackingStatus()) | ||
361 | { | ||
362 | case TRACKING_AVATAR: | ||
363 | { | ||
364 | LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); | ||
365 | if (av_tracker.haveTrackingInfo()) | ||
366 | { | ||
367 | pos_global = av_tracker.getGlobalPos(); } | ||
368 | break; | ||
369 | } | ||
370 | case TRACKING_LANDMARK: | ||
371 | if( instance()->mHasLandmarkPosition ) | ||
372 | { | ||
373 | pos_global = instance()->mTrackedPositionGlobal; | ||
374 | } | ||
375 | break; | ||
376 | case TRACKING_LOCATION: | ||
377 | pos_global = instance()->mTrackedPositionGlobal; | ||
378 | break; | ||
379 | default: | ||
380 | break; | ||
381 | } | ||
382 | return pos_global; | ||
383 | } | ||
384 | |||
385 | |||
386 | // static | ||
387 | BOOL LLTracker::hasLandmarkPosition() | ||
388 | { | ||
389 | if (!instance()->mHasLandmarkPosition) | ||
390 | { | ||
391 | // maybe we just received the landmark position info | ||
392 | instance()->cacheLandmarkPosition(); | ||
393 | } | ||
394 | return instance()->mHasLandmarkPosition; | ||
395 | } | ||
396 | |||
397 | |||
398 | // static | ||
399 | const LLString& LLTracker::getTrackedLocationName() | ||
400 | { | ||
401 | return instance()->mTrackedLocationName; | ||
402 | } | ||
403 | |||
404 | F32 pulse_func(F32 t, F32 z) | ||
405 | { | ||
406 | if (!LLTracker::sCheesyBeacon) | ||
407 | { | ||
408 | return 0.f; | ||
409 | } | ||
410 | |||
411 | t *= 3.14159f; | ||
412 | z -= t*64.f - 256.f; | ||
413 | |||
414 | F32 a = cosf(z*3.14159/512.f)*10.0f; | ||
415 | a = llmax(a, 9.9f); | ||
416 | a -= 9.9f; | ||
417 | a *= 10.f; | ||
418 | return a; | ||
419 | } | ||
420 | |||
421 | void draw_shockwave(F32 center_z, F32 t, S32 steps, LLColor4 color) | ||
422 | { | ||
423 | if (!LLTracker::sCheesyBeacon) | ||
424 | { | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | t *= 0.6284f/3.14159f; | ||
429 | |||
430 | t -= (F32) (S32) t; | ||
431 | |||
432 | t = llmax(t, 0.5f); | ||
433 | t -= 0.5f; | ||
434 | t *= 2.0f; | ||
435 | |||
436 | F32 radius = t*16536.f; | ||
437 | |||
438 | // Inexact, but reasonably fast. | ||
439 | F32 delta = F_TWO_PI / steps; | ||
440 | F32 sin_delta = sin( delta ); | ||
441 | F32 cos_delta = cos( delta ); | ||
442 | F32 x = radius; | ||
443 | F32 y = 0.f; | ||
444 | |||
445 | LLColor4 ccol = LLColor4(1,1,1,(1.f-t)*0.25f); | ||
446 | glBegin(GL_TRIANGLE_FAN); | ||
447 | glColor4fv(ccol.mV); | ||
448 | glVertex3f(0.f, 0.f, center_z); | ||
449 | // make sure circle is complete | ||
450 | steps += 1; | ||
451 | |||
452 | color.mV[3] = (1.f-t*t); | ||
453 | |||
454 | glColor4fv(color.mV); | ||
455 | while( steps-- ) | ||
456 | { | ||
457 | // Successive rotations | ||
458 | glVertex3f( x, y, center_z ); | ||
459 | F32 x_new = x * cos_delta - y * sin_delta; | ||
460 | y = x * sin_delta + y * cos_delta; | ||
461 | x = x_new; | ||
462 | } | ||
463 | glEnd(); | ||
464 | } | ||
465 | |||
466 | |||
467 | // static | ||
468 | void LLTracker::renderBeacon(LLVector3d pos_global, | ||
469 | const LLColor4& color, | ||
470 | LLHUDText* hud_textp, | ||
471 | const std::string& label ) | ||
472 | { | ||
473 | sCheesyBeacon = gSavedSettings.getBOOL("CheesyBeacon"); | ||
474 | LLVector3d to_vec = pos_global - gAgent.getCameraPositionGlobal(); | ||
475 | |||
476 | F32 dist = (F32)to_vec.magVec(); | ||
477 | F32 color_frac = 1.f; | ||
478 | if (dist > 0.99f * gCamera->getFar()) | ||
479 | { | ||
480 | color_frac = 0.4f; | ||
481 | // pos_global = gAgent.getCameraPositionGlobal() + 0.99f*(gCamera->getFar()/dist)*to_vec; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | color_frac = 1.f - 0.6f*(dist/gCamera->getFar()); | ||
486 | } | ||
487 | |||
488 | LLColor4 fogged_color = color_frac * color + (1 - color_frac)*gSky.getFogColor(); | ||
489 | |||
490 | F32 FADE_DIST = 3.f; | ||
491 | fogged_color.mV[3] = llmax(0.2f, llmin(0.5f,(dist-FADE_DIST)/FADE_DIST)); | ||
492 | |||
493 | LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(pos_global); | ||
494 | |||
495 | LLGLSTracker gls_tracker; // default - TEXTURE + CULL_FACE + LIGHTING + GL_BLEND + GL_ALPHA_TEST | ||
496 | LLGLDisable cull_face(GL_CULL_FACE); | ||
497 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); | ||
498 | |||
499 | |||
500 | glMatrixMode(GL_MODELVIEW); | ||
501 | glPushMatrix(); | ||
502 | glTranslatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); | ||
503 | |||
504 | draw_shockwave(1024.f, gRenderStartTime.getElapsedTimeF32(), 32, fogged_color); | ||
505 | |||
506 | //glScalef(1.f, 1.f, 1000.f); | ||
507 | glColor4fv(fogged_color.mV); | ||
508 | const U32 BEACON_VERTS = 256; | ||
509 | const F32 step = 1024.0f/BEACON_VERTS; | ||
510 | |||
511 | LLVector3 x_axis = gCamera->getLeftAxis(); | ||
512 | F32 t = gRenderStartTime.getElapsedTimeF32(); | ||
513 | F32 dr = dist/gCamera->getFar(); | ||
514 | |||
515 | for (U32 i = 0; i < BEACON_VERTS; i++) | ||
516 | { | ||
517 | F32 x = x_axis.mV[0]; | ||
518 | F32 y = x_axis.mV[1]; | ||
519 | |||
520 | F32 z = i * step; | ||
521 | F32 z_next = (i+1)*step; | ||
522 | |||
523 | F32 a = pulse_func(t, z); | ||
524 | F32 an = pulse_func(t, z_next); | ||
525 | |||
526 | LLColor4 c_col = fogged_color + LLColor4(a,a,a,a); | ||
527 | LLColor4 col_next = fogged_color + LLColor4(an,an,an,an); | ||
528 | LLColor4 col_edge = fogged_color * LLColor4(a,a,a,0.0f); | ||
529 | LLColor4 col_edge_next = fogged_color * LLColor4(an,an,an,0.0f); | ||
530 | |||
531 | a *= 2.f; | ||
532 | a += 1.0f+dr; | ||
533 | |||
534 | an *= 2.f; | ||
535 | an += 1.0f+dr; | ||
536 | |||
537 | glBegin(GL_TRIANGLE_STRIP); | ||
538 | glColor4fv(col_edge.mV); | ||
539 | glVertex3f(-x*a, -y*a, z); | ||
540 | glColor4fv(col_edge_next.mV); | ||
541 | glVertex3f(-x*an, -y*an, z_next); | ||
542 | |||
543 | glColor4fv(c_col.mV); | ||
544 | glVertex3f(0, 0, z); | ||
545 | glColor4fv(col_next.mV); | ||
546 | glVertex3f(0, 0, z_next); | ||
547 | |||
548 | glColor4fv(col_edge.mV); | ||
549 | glVertex3f(x*a,y*a,z); | ||
550 | glColor4fv(col_edge_next.mV); | ||
551 | glVertex3f(x*an,y*an,z_next); | ||
552 | |||
553 | glEnd(); | ||
554 | } | ||
555 | |||
556 | //gCylinder.render(1000); | ||
557 | glPopMatrix(); | ||
558 | |||
559 | char text[1024]; | ||
560 | sprintf(text, "%.0f m", to_vec.magVec()); | ||
561 | |||
562 | LLWString wstr; | ||
563 | wstr += utf8str_to_wstring(label); | ||
564 | wstr += '\n'; | ||
565 | wstr += utf8str_to_wstring(text); | ||
566 | |||
567 | hud_textp->setFont(LLFontGL::sSansSerif); | ||
568 | hud_textp->setZCompare(FALSE); | ||
569 | hud_textp->setColor(LLColor4(1.f, 1.f, 1.f, llmax(0.2f, llmin(1.f,(dist-FADE_DIST)/FADE_DIST)))); | ||
570 | |||
571 | hud_textp->setString(wstr); | ||
572 | hud_textp->setVertAlignment(LLHUDText::ALIGN_VERT_CENTER); | ||
573 | hud_textp->setPositionAgent(pos_agent); | ||
574 | } | ||
575 | |||
576 | |||
577 | void LLTracker::stopTrackingAll(BOOL clear_ui) | ||
578 | { | ||
579 | switch (mTrackingStatus) | ||
580 | { | ||
581 | case TRACKING_AVATAR : | ||
582 | stopTrackingAvatar(clear_ui); | ||
583 | break; | ||
584 | case TRACKING_LANDMARK : | ||
585 | stopTrackingLandmark(clear_ui); | ||
586 | break; | ||
587 | case TRACKING_LOCATION : | ||
588 | stopTrackingLocation(clear_ui); | ||
589 | break; | ||
590 | default: | ||
591 | mTrackingStatus = TRACKING_NOTHING; | ||
592 | break; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | |||
597 | void LLTracker::stopTrackingAvatar(BOOL clear_ui) | ||
598 | { | ||
599 | LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); | ||
600 | if( !av_tracker.getAvatarID().isNull() ) | ||
601 | { | ||
602 | av_tracker.untrack( av_tracker.getAvatarID() ); | ||
603 | } | ||
604 | |||
605 | purgeBeaconText(); | ||
606 | gFloaterWorldMap->clearAvatarSelection(clear_ui); | ||
607 | mTrackingStatus = TRACKING_NOTHING; | ||
608 | } | ||
609 | |||
610 | |||
611 | void LLTracker::stopTrackingLandmark(BOOL clear_ui) | ||
612 | { | ||
613 | purgeBeaconText(); | ||
614 | mTrackedLandmarkAssetID.setNull(); | ||
615 | mTrackedLandmarkItemID.setNull(); | ||
616 | mTrackedLandmarkName.assign(""); | ||
617 | mTrackedPositionGlobal.zeroVec(); | ||
618 | mHasLandmarkPosition = FALSE; | ||
619 | mHasReachedLandmark = FALSE; | ||
620 | mLandmarkHasBeenVisited = TRUE; | ||
621 | gFloaterWorldMap->clearLandmarkSelection(clear_ui); | ||
622 | mTrackingStatus = TRACKING_NOTHING; | ||
623 | } | ||
624 | |||
625 | |||
626 | void LLTracker::stopTrackingLocation(BOOL clear_ui) | ||
627 | { | ||
628 | purgeBeaconText(); | ||
629 | mTrackedLocationName.assign(""); | ||
630 | mIsTrackingLocation = FALSE; | ||
631 | mTrackedPositionGlobal.zeroVec(); | ||
632 | gFloaterWorldMap->clearLocationSelection(clear_ui); | ||
633 | mTrackingStatus = TRACKING_NOTHING; | ||
634 | mTrackingLocationType = LOCATION_NOTHING; | ||
635 | } | ||
636 | |||
637 | |||
638 | void LLTracker::drawMarker(const LLVector3d& pos_global, const LLColor4& color) | ||
639 | { | ||
640 | if (!gCamera) | ||
641 | { | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | // get position | ||
646 | LLVector3 pos_local = gAgent.getPosAgentFromGlobal(pos_global); | ||
647 | |||
648 | // check in frustum | ||
649 | LLCoordGL screen; | ||
650 | S32 x = 0; | ||
651 | S32 y = 0; | ||
652 | const BOOL CLAMP = TRUE; | ||
653 | |||
654 | if (gCamera->projectPosAgentToScreen(pos_local, screen, CLAMP) | ||
655 | || gCamera->projectPosAgentToScreenEdge(pos_local, screen) ) | ||
656 | { | ||
657 | gHUDView->screenPointToLocal(screen.mX, screen.mY, &x, &y); | ||
658 | |||
659 | // the center of the rendered position of the arrow obeys | ||
660 | // the following rules: | ||
661 | // (1) it lies on an ellipse centered on the target position | ||
662 | // (2) it lies on the line between the target and the window center | ||
663 | // (3) right now the radii of the ellipse are fixed, but eventually | ||
664 | // they will be a function of the target text | ||
665 | // | ||
666 | // from those rules we can compute the position of the | ||
667 | // lower left corner of the image | ||
668 | LLRect rect = gHUDView->getRect(); | ||
669 | S32 x_center = lltrunc(0.5f * (F32)rect.getWidth()); | ||
670 | S32 y_center = lltrunc(0.5f * (F32)rect.getHeight()); | ||
671 | x = x - x_center; // x and y relative to center | ||
672 | y = y - y_center; | ||
673 | F32 dist = sqrt((F32)(x*x + y*y)); | ||
674 | S32 half_arrow_size = lltrunc(0.5f * HUD_ARROW_SIZE); | ||
675 | if (dist > 0.f) | ||
676 | { | ||
677 | const F32 ARROW_ELLIPSE_RADIUS_X = 2 * HUD_ARROW_SIZE; | ||
678 | const F32 ARROW_ELLIPSE_RADIUS_Y = HUD_ARROW_SIZE; | ||
679 | |||
680 | // compute where the arrow should be | ||
681 | F32 x_target = (F32)(x + x_center) - (ARROW_ELLIPSE_RADIUS_X * ((F32)x / dist) ); | ||
682 | F32 y_target = (F32)(y + y_center) - (ARROW_ELLIPSE_RADIUS_Y * ((F32)y / dist) ); | ||
683 | |||
684 | // keep the arrow within the window | ||
685 | F32 x_clamped = llclamp( x_target, (F32)half_arrow_size, (F32)(rect.getWidth() - half_arrow_size)); | ||
686 | F32 y_clamped = llclamp( y_target, (F32)half_arrow_size, (F32)(rect.getHeight() - half_arrow_size)); | ||
687 | |||
688 | F32 slope = (F32)(y) / (F32)(x); | ||
689 | F32 window_ratio = (F32)(rect.getHeight() - HUD_ARROW_SIZE) / (F32)(rect.getWidth() - HUD_ARROW_SIZE); | ||
690 | |||
691 | // if the arrow has been clamped on one axis | ||
692 | // then we need to compute the other axis | ||
693 | if (llabs(slope) > window_ratio) | ||
694 | { | ||
695 | if (y_clamped != (F32)y_target) | ||
696 | { | ||
697 | // clamp by y | ||
698 | x_clamped = (y_clamped - (F32)y_center) / slope + (F32)x_center; | ||
699 | } | ||
700 | } | ||
701 | else if (x_clamped != (F32)x_target) | ||
702 | { | ||
703 | // clamp by x | ||
704 | y_clamped = (x_clamped - (F32)x_center) * slope + (F32)y_center; | ||
705 | } | ||
706 | mHUDArrowCenterX = lltrunc(x_clamped); | ||
707 | mHUDArrowCenterY = lltrunc(y_clamped); | ||
708 | } | ||
709 | else | ||
710 | { | ||
711 | // recycle the old values | ||
712 | x = mHUDArrowCenterX - x_center; | ||
713 | y = mHUDArrowCenterY - y_center; | ||
714 | } | ||
715 | |||
716 | F32 angle = atan2( (F32)y, (F32)x ); | ||
717 | |||
718 | gl_draw_scaled_rotated_image(mHUDArrowCenterX - half_arrow_size, | ||
719 | mHUDArrowCenterY - half_arrow_size, | ||
720 | HUD_ARROW_SIZE, HUD_ARROW_SIZE, | ||
721 | RAD_TO_DEG * angle, | ||
722 | LLWorldMapView::sTrackArrowImage, | ||
723 | color); | ||
724 | } | ||
725 | } | ||
726 | |||
727 | |||
728 | void LLTracker::setLandmarkVisited() | ||
729 | { | ||
730 | // poke the inventory item | ||
731 | if (!mTrackedLandmarkItemID.isNull()) | ||
732 | { | ||
733 | LLInventoryItem* i = gInventory.getItem( mTrackedLandmarkItemID ); | ||
734 | LLViewerInventoryItem* item = (LLViewerInventoryItem*)i; | ||
735 | if ( item | ||
736 | && !(item->getFlags()&LLInventoryItem::II_FLAGS_LANDMARK_VISITED)) | ||
737 | { | ||
738 | U32 flags = item->getFlags(); | ||
739 | flags |= LLInventoryItem::II_FLAGS_LANDMARK_VISITED; | ||
740 | item->setFlags(flags); | ||
741 | LLMessageSystem* msg = gMessageSystem; | ||
742 | msg->newMessage("ChangeInventoryItemFlags"); | ||
743 | msg->nextBlock("AgentData"); | ||
744 | msg->addUUID("AgentID", gAgent.getID()); | ||
745 | msg->addUUID("SessionID", gAgent.getSessionID()); | ||
746 | msg->nextBlock("InventoryData"); | ||
747 | msg->addUUID("ItemID", mTrackedLandmarkItemID); | ||
748 | msg->addU32("Flags", flags); | ||
749 | gAgent.sendReliableMessage(); | ||
750 | |||
751 | LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); | ||
752 | gInventory.accountForUpdate(up); | ||
753 | |||
754 | // need to communicate that the icon needs to change... | ||
755 | gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item->getUUID()); | ||
756 | gInventory.notifyObservers(); | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | |||
761 | |||
762 | void LLTracker::cacheLandmarkPosition() | ||
763 | { | ||
764 | // the landmark asset download may have finished, in which case | ||
765 | // we'll now be able to figure out where we're trying to go | ||
766 | BOOL found_landmark = FALSE; | ||
767 | if( mTrackedLandmarkAssetID == LLFloaterWorldMap::getHomeID()) | ||
768 | { | ||
769 | LLVector3d pos_global; | ||
770 | if ( gAgent.getHomePosGlobal( &mTrackedPositionGlobal )) | ||
771 | { | ||
772 | found_landmark = TRUE; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | llwarns << "LLTracker couldn't find home pos" << llendl; | ||
777 | mTrackedLandmarkAssetID.setNull(); | ||
778 | mTrackedLandmarkItemID.setNull(); | ||
779 | } | ||
780 | } | ||
781 | else | ||
782 | { | ||
783 | LLLandmark* landmark = gLandmarkList.getAsset(mTrackedLandmarkAssetID); | ||
784 | if(landmark && landmark->getGlobalPos(mTrackedPositionGlobal)) | ||
785 | { | ||
786 | found_landmark = TRUE; | ||
787 | |||
788 | // cache the object's visitation status | ||
789 | mLandmarkHasBeenVisited = FALSE; | ||
790 | LLInventoryItem* item = gInventory.getItem(mTrackedLandmarkItemID); | ||
791 | if ( item | ||
792 | && item->getFlags()&LLInventoryItem::II_FLAGS_LANDMARK_VISITED) | ||
793 | { | ||
794 | mLandmarkHasBeenVisited = TRUE; | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | if ( found_landmark && gFloaterWorldMap ) | ||
799 | { | ||
800 | mHasReachedLandmark = FALSE; | ||
801 | F32 dist = gFloaterWorldMap->getDistanceToDestination(mTrackedPositionGlobal, 1.0f); | ||
802 | if ( dist < DESTINATION_UNVISITED_RADIUS ) | ||
803 | { | ||
804 | mHasReachedLandmark = TRUE; | ||
805 | } | ||
806 | mHasLandmarkPosition = TRUE; | ||
807 | } | ||
808 | mHasLandmarkPosition = found_landmark; | ||
809 | } | ||
810 | |||
811 | |||
812 | void LLTracker::purgeBeaconText() | ||
813 | { | ||
814 | if(!mBeaconText.isNull()) | ||
815 | { | ||
816 | mBeaconText->markDead(); | ||
817 | mBeaconText = NULL; | ||
818 | } | ||
819 | } | ||
820 | |||