/indra/newview/llhudicon.cpp
C++ | 400 lines | 283 code | 71 blank | 46 comment | 33 complexity | 03d137b78da6bb45059f38993ea17090 MD5 | raw file
Possible License(s): LGPL-2.1
1/**
2 * @file llhudicon.cpp
3 * @brief LLHUDIcon class implementation
4 *
5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
6 * Second Life Viewer Source Code
7 * Copyright (C) 2010, Linden Research, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation;
12 * version 2.1 of the License only.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
24 * $/LicenseInfo$
25 */
26
27#include "llviewerprecompiledheaders.h"
28
29#include "llhudicon.h"
30
31#include "llgl.h"
32#include "llrender.h"
33
34#include "llviewerobject.h"
35#include "lldrawable.h"
36#include "llvector4a.h"
37#include "llviewercamera.h"
38#include "llviewertexture.h"
39#include "llviewerwindow.h"
40
41//-----------------------------------------------------------------------------
42// Local consts
43//-----------------------------------------------------------------------------
44const F32 ANIM_TIME = 0.4f;
45const F32 DIST_START_FADE = 15.f;
46const F32 DIST_END_FADE = 30.f;
47const F32 MAX_VISIBLE_TIME = 15.f;
48const F32 FADE_OUT_TIME = 1.f;
49
50//-----------------------------------------------------------------------------
51// Utility functions
52//-----------------------------------------------------------------------------
53static F32 calc_bouncy_animation(F32 x)
54{
55 return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f;
56}
57
58
59//-----------------------------------------------------------------------------
60// static declarations
61//-----------------------------------------------------------------------------
62LLHUDIcon::icon_instance_t LLHUDIcon::sIconInstances;
63
64LLHUDIcon::LLHUDIcon(const U8 type) :
65 LLHUDObject(type),
66 mImagep(NULL),
67 mPickID(0),
68 mScale(0.1f),
69 mHidden(FALSE)
70{
71 sIconInstances.push_back(this);
72}
73
74LLHUDIcon::~LLHUDIcon()
75{
76 mImagep = NULL;
77}
78
79void LLHUDIcon::renderIcon(BOOL for_select)
80{
81 LLGLSUIDefault texture_state;
82 LLGLDepthTest gls_depth(GL_TRUE);
83 if (for_select)
84 {
85 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
86 }
87
88 if (mHidden)
89 return;
90
91 if (mSourceObject.isNull() || mImagep.isNull())
92 {
93 markDead();
94 return;
95 }
96
97 LLVector3 obj_position = mSourceObject->getRenderPosition();
98
99 // put icon above object, and in front
100 // RN: don't use drawable radius, it's fricking HUGE
101 LLViewerCamera* camera = LLViewerCamera::getInstance();
102 LLVector3 icon_relative_pos = (camera->getUpAxis() * ~mSourceObject->getRenderRotation());
103 icon_relative_pos.abs();
104
105 F32 distance_scale = llmin(mSourceObject->getScale().mV[VX] / icon_relative_pos.mV[VX],
106 mSourceObject->getScale().mV[VY] / icon_relative_pos.mV[VY],
107 mSourceObject->getScale().mV[VZ] / icon_relative_pos.mV[VZ]);
108 F32 up_distance = 0.5f * distance_scale;
109 LLVector3 icon_position = obj_position + (up_distance * camera->getUpAxis()) * 1.2f;
110
111 LLVector3 icon_to_cam = LLViewerCamera::getInstance()->getOrigin() - icon_position;
112 icon_to_cam.normVec();
113
114 icon_position += icon_to_cam * mSourceObject->mDrawable->getRadius() * 1.1f;
115
116 mDistance = dist_vec(icon_position, camera->getOrigin());
117
118 F32 alpha_factor = for_select ? 1.f : clamp_rescale(mDistance, DIST_START_FADE, DIST_END_FADE, 1.f, 0.f);
119
120 LLVector3 x_pixel_vec;
121 LLVector3 y_pixel_vec;
122
123 camera->getPixelVectors(icon_position, y_pixel_vec, x_pixel_vec);
124
125 F32 scale_factor = 1.f;
126 if (mAnimTimer.getElapsedTimeF32() < ANIM_TIME)
127 {
128 scale_factor = llmax(0.f, calc_bouncy_animation(mAnimTimer.getElapsedTimeF32() / ANIM_TIME));
129 }
130
131 F32 time_elapsed = mLifeTimer.getElapsedTimeF32();
132 if (time_elapsed > MAX_VISIBLE_TIME)
133 {
134 markDead();
135 return;
136 }
137
138 if (time_elapsed > MAX_VISIBLE_TIME - FADE_OUT_TIME)
139 {
140 alpha_factor *= clamp_rescale(time_elapsed, MAX_VISIBLE_TIME - FADE_OUT_TIME, MAX_VISIBLE_TIME, 1.f, 0.f);
141 }
142
143 F32 image_aspect = (F32)mImagep->getFullWidth() / (F32)mImagep->getFullHeight() ;
144 LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * x_pixel_vec;
145 LLVector3 y_scale = (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * y_pixel_vec;
146
147 LLVector3 lower_left = icon_position - (x_scale * 0.5f);
148 LLVector3 lower_right = icon_position + (x_scale * 0.5f);
149 LLVector3 upper_left = icon_position - (x_scale * 0.5f) + y_scale;
150 LLVector3 upper_right = icon_position + (x_scale * 0.5f) + y_scale;
151
152 if (for_select)
153 {
154 // set color to unique color id for picking
155 LLColor4U coloru((U8)(mPickID >> 16), (U8)(mPickID >> 8), (U8)mPickID);
156 gGL.color4ubv(coloru.mV);
157 }
158 else
159 {
160 LLColor4 icon_color = LLColor4::white;
161 icon_color.mV[VALPHA] = alpha_factor;
162 gGL.color4fv(icon_color.mV);
163 gGL.getTexUnit(0)->bind(mImagep);
164 }
165
166 gGL.begin(LLRender::QUADS);
167 {
168 gGL.texCoord2f(0.f, 1.f);
169 gGL.vertex3fv(upper_left.mV);
170 gGL.texCoord2f(0.f, 0.f);
171 gGL.vertex3fv(lower_left.mV);
172 gGL.texCoord2f(1.f, 0.f);
173 gGL.vertex3fv(lower_right.mV);
174 gGL.texCoord2f(1.f, 1.f);
175 gGL.vertex3fv(upper_right.mV);
176 }
177 gGL.end();
178}
179
180void LLHUDIcon::setImage(LLViewerTexture* imagep)
181{
182 mImagep = imagep;
183 mImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
184}
185
186void LLHUDIcon::setScale(F32 fraction_of_fov)
187{
188 mScale = fraction_of_fov;
189}
190
191void LLHUDIcon::markDead()
192{
193 if (mSourceObject)
194 {
195 mSourceObject->clearIcon();
196 }
197 LLHUDObject::markDead();
198}
199
200void LLHUDIcon::render()
201{
202 renderIcon(FALSE);
203}
204
205BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection)
206{
207 if (mHidden)
208 return FALSE;
209
210 if (mSourceObject.isNull() || mImagep.isNull())
211 {
212 markDead();
213 return FALSE;
214 }
215
216 LLVector3 obj_position = mSourceObject->getRenderPosition();
217
218 // put icon above object, and in front
219 // RN: don't use drawable radius, it's fricking HUGE
220 LLViewerCamera* camera = LLViewerCamera::getInstance();
221 LLVector3 icon_relative_pos = (camera->getUpAxis() * ~mSourceObject->getRenderRotation());
222 icon_relative_pos.abs();
223
224 F32 distance_scale = llmin(mSourceObject->getScale().mV[VX] / icon_relative_pos.mV[VX],
225 mSourceObject->getScale().mV[VY] / icon_relative_pos.mV[VY],
226 mSourceObject->getScale().mV[VZ] / icon_relative_pos.mV[VZ]);
227 F32 up_distance = 0.5f * distance_scale;
228 LLVector3 icon_position = obj_position + (up_distance * camera->getUpAxis()) * 1.2f;
229
230 LLVector3 icon_to_cam = LLViewerCamera::getInstance()->getOrigin() - icon_position;
231 icon_to_cam.normVec();
232
233 icon_position += icon_to_cam * mSourceObject->mDrawable->getRadius() * 1.1f;
234
235 mDistance = dist_vec(icon_position, camera->getOrigin());
236
237 LLVector3 x_pixel_vec;
238 LLVector3 y_pixel_vec;
239
240 camera->getPixelVectors(icon_position, y_pixel_vec, x_pixel_vec);
241
242 F32 scale_factor = 1.f;
243 if (mAnimTimer.getElapsedTimeF32() < ANIM_TIME)
244 {
245 scale_factor = llmax(0.f, calc_bouncy_animation(mAnimTimer.getElapsedTimeF32() / ANIM_TIME));
246 }
247
248 F32 time_elapsed = mLifeTimer.getElapsedTimeF32();
249 if (time_elapsed > MAX_VISIBLE_TIME)
250 {
251 markDead();
252 return FALSE;
253 }
254
255 F32 image_aspect = (F32)mImagep->getFullWidth() / (F32)mImagep->getFullHeight() ;
256 LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * x_pixel_vec;
257 LLVector3 y_scale = (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * y_pixel_vec;
258
259 LLVector4a x_scalea;
260 LLVector4a icon_positiona;
261 LLVector4a y_scalea;
262
263 x_scalea.load3(x_scale.mV);
264 x_scalea.mul(0.5f);
265 y_scalea.load3(y_scale.mV);
266
267 icon_positiona.load3(icon_position.mV);
268
269 LLVector4a lower_left;
270 lower_left.setSub(icon_positiona, x_scalea);
271 LLVector4a lower_right;
272 lower_right.setAdd(icon_positiona, x_scalea);
273 LLVector4a upper_left;
274 upper_left.setAdd(lower_left, y_scalea);
275 LLVector4a upper_right;
276 upper_right.setAdd(lower_right, y_scalea);
277
278 LLVector4a enda;
279 enda.load3(end.mV);
280 LLVector4a starta;
281 starta.load3(start.mV);
282 LLVector4a dir;
283 dir.setSub(enda, starta);
284
285 F32 a,b,t;
286
287 if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) ||
288 LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t))
289 {
290 if (intersection)
291 {
292 dir.mul(t);
293 starta.add(dir);
294 *intersection = LLVector3(starta.getF32ptr());
295 }
296 return TRUE;
297 }
298
299 return FALSE;
300}
301
302//static
303S32 LLHUDIcon::generatePickIDs(S32 start_id, S32 step_size)
304{
305 S32 cur_id = start_id;
306 icon_instance_t::iterator icon_it;
307
308 for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it)
309 {
310 (*icon_it)->mPickID = cur_id;
311 cur_id += step_size;
312 }
313
314 return cur_id;
315}
316
317//static
318LLHUDIcon* LLHUDIcon::handlePick(S32 pick_id)
319{
320 icon_instance_t::iterator icon_it;
321
322 for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it)
323 {
324 if (pick_id == (*icon_it)->mPickID)
325 {
326 return *icon_it;
327 }
328 }
329
330 return NULL;
331}
332
333//static
334LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector3& start, const LLVector3& end, LLVector3* intersection)
335{
336 icon_instance_t::iterator icon_it;
337
338 LLVector3 local_end = end;
339 LLVector3 position;
340
341 LLHUDIcon* ret = NULL;
342 for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it)
343 {
344 LLHUDIcon* icon = *icon_it;
345 if (icon->lineSegmentIntersect(start, local_end, &position))
346 {
347 ret = icon;
348 if (intersection)
349 {
350 *intersection = position;
351 }
352 local_end = position;
353 }
354 }
355
356 return ret;
357}
358
359
360 //static
361void LLHUDIcon::updateAll()
362{
363 cleanupDeadIcons();
364}
365
366//static
367BOOL LLHUDIcon::iconsNearby()
368{
369 return !sIconInstances.empty();
370}
371
372//static
373void LLHUDIcon::cleanupDeadIcons()
374{
375 icon_instance_t::iterator icon_it;
376
377 icon_instance_t icons_to_erase;
378 for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it)
379 {
380 if ((*icon_it)->mDead)
381 {
382 icons_to_erase.push_back(*icon_it);
383 }
384 }
385
386 for(icon_it = icons_to_erase.begin(); icon_it != icons_to_erase.end(); ++icon_it)
387 {
388 icon_instance_t::iterator found_it = std::find(sIconInstances.begin(), sIconInstances.end(), *icon_it);
389 if (found_it != sIconInstances.end())
390 {
391 sIconInstances.erase(found_it);
392 }
393 }
394}
395
396//static
397S32 LLHUDIcon::getNumInstances()
398{
399 return (S32)sIconInstances.size();
400}