aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/lltracker.cpp820
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
62const F32 DESTINATION_REACHED_RADIUS = 3.0f;
63const 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
67const F32 DESTINATION_UNVISITED_RADIUS = 12.0f;
68
69const S32 ARROW_OFF_RADIUS_SQRD = 100;
70
71const S32 HUD_ARROW_SIZE = 32;
72
73// static
74LLTracker *LLTracker::sTrackerp = NULL;
75BOOL LLTracker::sCheesyBeacon = FALSE;
76
77LLTracker::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
92LLTracker::~LLTracker()
93{
94 purgeBeaconText();
95}
96
97
98// static
99void LLTracker::stopTracking(void* userdata)
100{
101 BOOL clear_ui = ((BOOL)(intptr_t)userdata);
102 instance()->stopTrackingAll(clear_ui);
103}
104
105
106// static virtual
107void 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
155void 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
286void 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
298void 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
313void 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
329BOOL 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
357LLVector3d 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
387BOOL 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
399const LLString& LLTracker::getTrackedLocationName()
400{
401 return instance()->mTrackedLocationName;
402}
403
404F32 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
421void 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
468void 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
577void 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
597void 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
611void 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
626void 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
638void 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
728void 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
762void 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
812void LLTracker::purgeBeaconText()
813{
814 if(!mBeaconText.isNull())
815 {
816 mBeaconText->markDead();
817 mBeaconText = NULL;
818 }
819}
820