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/llmaniptranslate.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llmaniptranslate.cpp')
-rw-r--r-- | linden/indra/newview/llmaniptranslate.cpp | 2145 |
1 files changed, 2145 insertions, 0 deletions
diff --git a/linden/indra/newview/llmaniptranslate.cpp b/linden/indra/newview/llmaniptranslate.cpp new file mode 100644 index 0000000..fea6092 --- /dev/null +++ b/linden/indra/newview/llmaniptranslate.cpp | |||
@@ -0,0 +1,2145 @@ | |||
1 | /** | ||
2 | * @file llmaniptranslate.cpp | ||
3 | * @brief LLManipTranslate class implementation | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | /** | ||
29 | * Positioning tool | ||
30 | */ | ||
31 | |||
32 | #include "llviewerprecompiledheaders.h" | ||
33 | |||
34 | #include "llmaniptranslate.h" | ||
35 | |||
36 | #include "llgl.h" | ||
37 | |||
38 | #include "llagent.h" | ||
39 | #include "llbbox.h" | ||
40 | #include "llbox.h" | ||
41 | #include "llviewercontrol.h" | ||
42 | #include "llcriticaldamp.h" | ||
43 | #include "llcylinder.h" | ||
44 | #include "lldrawable.h" | ||
45 | #include "llfloatertools.h" | ||
46 | #include "llfontgl.h" | ||
47 | #include "llglheaders.h" | ||
48 | #include "llhudrender.h" | ||
49 | #include "llresmgr.h" | ||
50 | #include "llselectmgr.h" | ||
51 | #include "llsphere.h" | ||
52 | #include "llstatusbar.h" | ||
53 | #include "lltoolmgr.h" | ||
54 | #include "llviewercamera.h" | ||
55 | #include "llviewerjoint.h" | ||
56 | #include "llviewerobject.h" | ||
57 | #include "llviewerwindow.h" | ||
58 | #include "llvoavatar.h" | ||
59 | #include "llworld.h" | ||
60 | #include "viewer.h" | ||
61 | #include "llui.h" | ||
62 | |||
63 | const S32 NUM_AXES = 3; | ||
64 | const S32 MOUSE_DRAG_SLOP = 2; // pixels | ||
65 | const F32 HANDLE_HIDE_ANGLE = 0.15f; // radians | ||
66 | const F32 SELECTED_ARROW_SCALE = 1.3f; | ||
67 | const F32 MANIPULATOR_HOTSPOT_START = 0.2f; | ||
68 | const F32 MANIPULATOR_HOTSPOT_END = 1.2f; | ||
69 | const F32 SNAP_GUIDE_SCREEN_SIZE = 0.7f; | ||
70 | const F32 MIN_PLANE_MANIP_DOT_PRODUCT = 0.25f; | ||
71 | const F32 PLANE_TICK_SIZE = 0.4f; | ||
72 | const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; | ||
73 | const F32 SNAP_ARROW_SCALE = 0.7f; | ||
74 | |||
75 | static GLuint sGridTex = 0; | ||
76 | |||
77 | const LLManip::EManipPart MANIPULATOR_IDS[9] = | ||
78 | { | ||
79 | LLManip::LL_X_ARROW, | ||
80 | LLManip::LL_Y_ARROW, | ||
81 | LLManip::LL_Z_ARROW, | ||
82 | LLManip::LL_X_ARROW, | ||
83 | LLManip::LL_Y_ARROW, | ||
84 | LLManip::LL_Z_ARROW, | ||
85 | LLManip::LL_YZ_PLANE, | ||
86 | LLManip::LL_XZ_PLANE, | ||
87 | LLManip::LL_XY_PLANE | ||
88 | }; | ||
89 | |||
90 | const U32 ARROW_TO_AXIS[4] = | ||
91 | { | ||
92 | VX, | ||
93 | VX, | ||
94 | VY, | ||
95 | VZ | ||
96 | }; | ||
97 | |||
98 | BOOL sort_manip_by_end_z(LLManipTranslate::ManipulatorHandle *new_manip, LLManipTranslate::ManipulatorHandle *test_manip) | ||
99 | { | ||
100 | return (new_manip->mEndPosition.mV[VZ] < test_manip->mEndPosition.mV[VZ]); | ||
101 | } | ||
102 | |||
103 | LLManipTranslate::LLManipTranslate( LLToolComposite* composite ) | ||
104 | : LLManip( "Move", composite ), | ||
105 | mLastHoverMouseX(-1), | ||
106 | mLastHoverMouseY(-1), | ||
107 | mSendUpdateOnMouseUp(FALSE), | ||
108 | mMouseOutsideSlop(FALSE), | ||
109 | mCopyMadeThisDrag(FALSE), | ||
110 | mMouseDownX(-1), | ||
111 | mMouseDownY(-1), | ||
112 | mAxisArrowLength(50), | ||
113 | mConeSize(0), | ||
114 | mArrowLengthMeters(0.f), | ||
115 | mPlaneManipOffsetMeters(0.f), | ||
116 | mManipPart(LL_NO_PART), | ||
117 | mUpdateTimer(), | ||
118 | mSnapOffsetMeters(0.f), | ||
119 | mArrowScales(1.f, 1.f, 1.f), | ||
120 | mPlaneScales(1.f, 1.f, 1.f), | ||
121 | mPlaneManipPositions(1.f, 1.f, 1.f, 1.f) | ||
122 | { | ||
123 | mProjectedManipulators.setInsertBefore(sort_manip_by_end_z); | ||
124 | |||
125 | if (sGridTex == 0) | ||
126 | { | ||
127 | restoreGL(); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | //static | ||
132 | void LLManipTranslate::restoreGL() | ||
133 | { | ||
134 | //generate grid texture | ||
135 | U32 rez = 512; | ||
136 | U32 mip = 0; | ||
137 | |||
138 | GLuint* d = new GLuint[rez*rez]; | ||
139 | LLGLEnable tex2d(GL_TEXTURE_2D); | ||
140 | glGenTextures(1, &sGridTex); | ||
141 | glBindTexture(GL_TEXTURE_2D, sGridTex); | ||
142 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||
143 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
144 | |||
145 | while (rez >= 1) | ||
146 | { | ||
147 | for (U32 i = 0; i < rez*rez; i++) | ||
148 | { | ||
149 | d[i] = 0x00FFFFFF; | ||
150 | } | ||
151 | |||
152 | U32 subcol = 0xFFFFFFFF; | ||
153 | if (rez >= 4) | ||
154 | { //large grain grid | ||
155 | for (U32 i = 0; i < rez; i++) | ||
156 | { | ||
157 | if (rez <= 16) | ||
158 | { | ||
159 | if (rez == 16) | ||
160 | { | ||
161 | subcol = 0xA0FFFFFF; | ||
162 | } | ||
163 | else if (rez == 8) | ||
164 | { | ||
165 | subcol = 0x80FFFFFF; | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | subcol = 0x40FFFFFF; | ||
170 | } | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | subcol = 0xFFFFFFFF; | ||
175 | } | ||
176 | d[i *rez+ 0 ] = subcol; | ||
177 | d[0 *rez+ i ] = subcol; | ||
178 | if (rez >= 32) | ||
179 | { | ||
180 | d[i *rez+ (rez-1)] = subcol; | ||
181 | d[(rez-1) *rez+ i ] = subcol; | ||
182 | } | ||
183 | |||
184 | if (rez >= 64) | ||
185 | { | ||
186 | subcol = 0xFFFFFFFF; | ||
187 | |||
188 | if (i > 0 && i < (rez-1)) | ||
189 | { | ||
190 | d[i *rez+ 1 ] = subcol; | ||
191 | d[i *rez+ (rez-2)] = subcol; | ||
192 | d[1 *rez+ i ] = subcol; | ||
193 | d[(rez-2) *rez+ i ] = subcol; | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | subcol = 0x50A0A0A0; | ||
200 | if (rez >= 128) | ||
201 | { //small grain grid | ||
202 | for (U32 i = 8; i < rez; i+=8) | ||
203 | { | ||
204 | for (U32 j = 2; j < rez-2; j++) | ||
205 | { | ||
206 | d[i *rez+ j] = subcol; | ||
207 | d[j *rez+ i] = subcol; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | if (rez >= 64) | ||
212 | { //medium grain grid | ||
213 | if (rez == 64) | ||
214 | { | ||
215 | subcol = 0x50A0A0A0; | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | subcol = 0xA0D0D0D0; | ||
220 | } | ||
221 | |||
222 | for (U32 i = 32; i < rez; i+=32) | ||
223 | { | ||
224 | U32 pi = i-1; | ||
225 | for (U32 j = 2; j < rez-2; j++) | ||
226 | { | ||
227 | d[i *rez+ j] = subcol; | ||
228 | d[j *rez+ i] = subcol; | ||
229 | |||
230 | if (rez > 128) | ||
231 | { | ||
232 | d[pi *rez+ j] = subcol; | ||
233 | d[j *rez+ pi] = subcol; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | #ifdef LL_WINDOWS | ||
239 | glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, 0, GL_RGBA, GL_UNSIGNED_BYTE, d); | ||
240 | #else | ||
241 | glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d); | ||
242 | #endif | ||
243 | rez = rez >> 1; | ||
244 | mip++; | ||
245 | } | ||
246 | delete [] d; | ||
247 | } | ||
248 | |||
249 | |||
250 | LLManipTranslate::~LLManipTranslate() | ||
251 | { | ||
252 | mProjectedManipulators.deleteAllData(); | ||
253 | } | ||
254 | |||
255 | |||
256 | void LLManipTranslate::handleSelect() | ||
257 | { | ||
258 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
259 | gFloaterTools->setStatusText("Drag to move, shift-drag to copy"); | ||
260 | } | ||
261 | |||
262 | void LLManipTranslate::handleDeselect() | ||
263 | { | ||
264 | mHighlightedPart = LL_NO_PART; | ||
265 | mManipPart = LL_NO_PART; | ||
266 | gFloaterTools->setStatusText(""); | ||
267 | } | ||
268 | |||
269 | BOOL LLManipTranslate::handleMouseDown(S32 x, S32 y, MASK mask) | ||
270 | { | ||
271 | BOOL handled = FALSE; | ||
272 | |||
273 | // didn't click in any UI object, so must have clicked in the world | ||
274 | LLViewerObject* hit_obj = gViewerWindow->lastObjectHit(); | ||
275 | if( hit_obj && | ||
276 | (mHighlightedPart == LL_X_ARROW || | ||
277 | mHighlightedPart == LL_Y_ARROW || | ||
278 | mHighlightedPart == LL_Z_ARROW || | ||
279 | mHighlightedPart == LL_YZ_PLANE || | ||
280 | mHighlightedPart == LL_XZ_PLANE || | ||
281 | mHighlightedPart == LL_XY_PLANE ) ) | ||
282 | { | ||
283 | handled = handleMouseDownOnPart( x, y, mask ); | ||
284 | } | ||
285 | |||
286 | return handled; | ||
287 | } | ||
288 | |||
289 | // Assumes that one of the arrows on an object was hit. | ||
290 | BOOL LLManipTranslate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) | ||
291 | { | ||
292 | BOOL can_move = gSelectMgr->getObjectCount() != 0; | ||
293 | for (LLViewerObject* objectp = gSelectMgr->getFirstObject(); | ||
294 | objectp; | ||
295 | objectp = gSelectMgr->getNextObject()) | ||
296 | { | ||
297 | can_move = can_move && objectp->permMove() && (objectp->permModify() || gSavedSettings.getBOOL("SelectLinkedSet")); | ||
298 | } | ||
299 | |||
300 | if (!can_move) | ||
301 | { | ||
302 | return FALSE; | ||
303 | } | ||
304 | |||
305 | highlightManipulators(x, y); | ||
306 | S32 hit_part = mHighlightedPart; | ||
307 | |||
308 | if( (hit_part != LL_X_ARROW) && | ||
309 | (hit_part != LL_Y_ARROW) && | ||
310 | (hit_part != LL_Z_ARROW) && | ||
311 | (hit_part != LL_YZ_PLANE) && | ||
312 | (hit_part != LL_XZ_PLANE) && | ||
313 | (hit_part != LL_XY_PLANE) ) | ||
314 | { | ||
315 | return TRUE; | ||
316 | } | ||
317 | |||
318 | mHelpTextTimer.reset(); | ||
319 | sNumTimesHelpTextShown++; | ||
320 | |||
321 | gSelectMgr->getGrid(mGridOrigin, mGridRotation, mGridScale); | ||
322 | |||
323 | gSelectMgr->enableSilhouette(FALSE); | ||
324 | |||
325 | // we just started a drag, so save initial object positions | ||
326 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_MOVE); | ||
327 | |||
328 | mManipPart = (EManipPart)hit_part; | ||
329 | mMouseDownX = x; | ||
330 | mMouseDownY = y; | ||
331 | mMouseOutsideSlop = FALSE; | ||
332 | |||
333 | LLVector3 axis; | ||
334 | |||
335 | LLSelectNode *selectNode = gSelectMgr->getFirstMoveableNode(TRUE); | ||
336 | |||
337 | if (!selectNode) | ||
338 | { | ||
339 | // didn't find the object in our selection...oh well | ||
340 | llwarns << "Trying to translate an unselected object" << llendl; | ||
341 | return TRUE; | ||
342 | } | ||
343 | |||
344 | LLViewerObject *selected_object = selectNode->getObject(); | ||
345 | if (!selected_object) | ||
346 | { | ||
347 | // somehow we lost the object! | ||
348 | llwarns << "Translate manip lost the object" << llendl; | ||
349 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
350 | return TRUE; | ||
351 | } | ||
352 | |||
353 | // Compute unit vectors for arrow hit and a plane through that vector | ||
354 | BOOL axis_exists = getManipAxis(selected_object, mManipPart, axis); | ||
355 | getManipNormal(selected_object, mManipPart, mManipNormal); | ||
356 | |||
357 | //LLVector3 select_center_agent = gAgent.getPosAgentFromGlobal(gSelectMgr->getSelectionCenterGlobal()); | ||
358 | // TomY: The above should (?) be identical to the below | ||
359 | LLVector3 select_center_agent = getPivotPoint(); | ||
360 | mSubdivisions = llclamp(getSubdivisionLevel(select_center_agent, axis_exists ? axis : LLVector3::z_axis, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
361 | |||
362 | // if we clicked on a planar manipulator, recenter mouse cursor | ||
363 | if (mManipPart >= LL_YZ_PLANE && mManipPart <= LL_XY_PLANE) | ||
364 | { | ||
365 | LLCoordGL mouse_pos; | ||
366 | gCamera->projectPosAgentToScreen(select_center_agent, mouse_pos); | ||
367 | |||
368 | if (gSavedSettings.getBOOL("SnapToMouseCursor")) | ||
369 | { | ||
370 | LLUI::setCursorPositionScreen(mouse_pos.mX, mouse_pos.mY); | ||
371 | x = mouse_pos.mX; | ||
372 | y = mouse_pos.mY; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | gSelectMgr->updateSelectionCenter(); | ||
377 | LLVector3d object_start_global = gAgent.getPosGlobalFromAgent(getPivotPoint()); | ||
378 | getMousePointOnPlaneGlobal(mDragCursorStartGlobal, x, y, object_start_global, mManipNormal); | ||
379 | mDragSelectionStartGlobal = object_start_global; | ||
380 | mCopyMadeThisDrag = FALSE; | ||
381 | |||
382 | // Route future Mouse messages here preemptively. (Release on mouse up.) | ||
383 | setMouseCapture( TRUE ); | ||
384 | |||
385 | return TRUE; | ||
386 | } | ||
387 | |||
388 | BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) | ||
389 | { | ||
390 | // Translation tool only works if mouse button is down. | ||
391 | // Bail out if mouse not down. | ||
392 | if( !hasMouseCapture() ) | ||
393 | { | ||
394 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (inactive)" << llendl; | ||
395 | // Always show cursor | ||
396 | // gViewerWindow->setCursor(UI_CURSOR_ARROW); | ||
397 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
398 | |||
399 | highlightManipulators(x, y); | ||
400 | return TRUE; | ||
401 | } | ||
402 | |||
403 | // Handle auto-rotation if necessary. | ||
404 | const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD; | ||
405 | const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20; | ||
406 | const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped; | ||
407 | BOOL rotated = FALSE; | ||
408 | |||
409 | // ...build mode moves camera about focus point | ||
410 | if (gSelectMgr->getSelectType() != SELECT_TYPE_HUD) | ||
411 | { | ||
412 | if (x < ROTATE_H_MARGIN) | ||
413 | { | ||
414 | gAgent.cameraOrbitAround(rotate_angle); | ||
415 | rotated = TRUE; | ||
416 | } | ||
417 | else if (x > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN) | ||
418 | { | ||
419 | gAgent.cameraOrbitAround(-rotate_angle); | ||
420 | rotated = TRUE; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | // Suppress processing if mouse hasn't actually moved. | ||
425 | // This may cause problems if the camera moves outside of the | ||
426 | // rotation above. | ||
427 | if( x == mLastHoverMouseX && y == mLastHoverMouseY && !rotated) | ||
428 | { | ||
429 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse unmoved)" << llendl; | ||
430 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
431 | return TRUE; | ||
432 | } | ||
433 | mLastHoverMouseX = x; | ||
434 | mLastHoverMouseY = y; | ||
435 | |||
436 | // Suppress if mouse hasn't moved past the initial slop region | ||
437 | // Reset once we start moving | ||
438 | if( !mMouseOutsideSlop ) | ||
439 | { | ||
440 | if (abs(mMouseDownX - x) < MOUSE_DRAG_SLOP && abs(mMouseDownY - y) < MOUSE_DRAG_SLOP ) | ||
441 | { | ||
442 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse inside slop)" << llendl; | ||
443 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
444 | return TRUE; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | // ...just went outside the slop region | ||
449 | mMouseOutsideSlop = TRUE; | ||
450 | // If holding down shift, leave behind a copy. | ||
451 | if (mask == MASK_COPY) | ||
452 | { | ||
453 | // ...we're trying to make a copy | ||
454 | gSelectMgr->selectDuplicate(LLVector3::zero, FALSE); | ||
455 | mCopyMadeThisDrag = TRUE; | ||
456 | |||
457 | // When we make the copy, we don't want to do any other processing. | ||
458 | // If so, the object will also be moved, and the copy will be offset. | ||
459 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (made copy)" << llendl; | ||
460 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | |||
465 | // Throttle updates to 10 per second. | ||
466 | BOOL send_update = FALSE; | ||
467 | |||
468 | LLVector3 axis_f; | ||
469 | LLVector3d axis_d; | ||
470 | LLViewerObject *object; | ||
471 | |||
472 | // pick the first object to constrain to grid w/ common origin | ||
473 | // this is so we don't screw up groups | ||
474 | LLSelectNode* selectNode = gSelectMgr->getFirstMoveableNode(TRUE); | ||
475 | if (!selectNode) | ||
476 | { | ||
477 | // somehow we lost the object! | ||
478 | llwarns << "Translate manip lost the object" << llendl; | ||
479 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
480 | return TRUE; | ||
481 | } | ||
482 | |||
483 | object = selectNode->getObject(); | ||
484 | if (!object) | ||
485 | { | ||
486 | // somehow we lost the object! | ||
487 | llwarns << "Translate manip lost the object" << llendl; | ||
488 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
489 | return TRUE; | ||
490 | } | ||
491 | |||
492 | // Compute unit vectors for arrow hit and a plane through that vector | ||
493 | BOOL axis_exists = getManipAxis(object, mManipPart, axis_f); // TODO: move this | ||
494 | |||
495 | axis_d.setVec(axis_f); | ||
496 | |||
497 | gSelectMgr->updateSelectionCenter(); | ||
498 | LLVector3d current_pos_global = gAgent.getPosGlobalFromAgent(getPivotPoint()); | ||
499 | |||
500 | mSubdivisions = llclamp(getSubdivisionLevel(getPivotPoint(), axis_f, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
501 | |||
502 | // Project the cursor onto that plane | ||
503 | LLVector3d relative_move; | ||
504 | getMousePointOnPlaneGlobal(relative_move, x, y, current_pos_global, mManipNormal);\ | ||
505 | relative_move -= mDragCursorStartGlobal; | ||
506 | |||
507 | // You can't move more than some distance from your original mousedown point. | ||
508 | if (gSavedSettings.getBOOL("LimitDragDistance")) | ||
509 | { | ||
510 | F32 max_drag_distance = gSavedSettings.getF32("MaxDragDistance"); | ||
511 | |||
512 | if (relative_move.magVecSquared() > max_drag_distance * max_drag_distance) | ||
513 | { | ||
514 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (too far)" << llendl; | ||
515 | gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); | ||
516 | return TRUE; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | F64 axis_magnitude = relative_move * axis_d; // dot product | ||
521 | LLVector3d cursor_point_snap_line; | ||
522 | |||
523 | F64 off_axis_magnitude; | ||
524 | |||
525 | getMousePointOnPlaneGlobal(cursor_point_snap_line, x, y, current_pos_global, mSnapOffsetAxis % axis_f); | ||
526 | off_axis_magnitude = axis_exists ? llabs((cursor_point_snap_line - current_pos_global) * LLVector3d(mSnapOffsetAxis)) : 0.f; | ||
527 | |||
528 | if (gSavedSettings.getBOOL("SnapEnabled")) | ||
529 | { | ||
530 | if (off_axis_magnitude > mSnapOffsetMeters) | ||
531 | { | ||
532 | mInSnapRegime = TRUE; | ||
533 | LLVector3 mouse_down_offset(mDragCursorStartGlobal - mDragSelectionStartGlobal); | ||
534 | LLVector3 cursor_snap_agent = gAgent.getPosAgentFromGlobal(cursor_point_snap_line); | ||
535 | if (!gSavedSettings.getBOOL("SnapToMouseCursor")) | ||
536 | { | ||
537 | cursor_snap_agent -= mouse_down_offset; | ||
538 | } | ||
539 | |||
540 | F32 cursor_grid_dist = (cursor_snap_agent - mGridOrigin) * axis_f; | ||
541 | |||
542 | F32 snap_dist = getMinGridScale() / (2.f * mSubdivisions); | ||
543 | F32 relative_snap_dist = fmodf(llabs(cursor_grid_dist) + snap_dist, getMinGridScale() / mSubdivisions); | ||
544 | if (relative_snap_dist < snap_dist * 2.f) | ||
545 | { | ||
546 | if (cursor_grid_dist > 0.f) | ||
547 | { | ||
548 | cursor_grid_dist -= relative_snap_dist - snap_dist; | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | cursor_grid_dist += relative_snap_dist - snap_dist; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | F32 object_start_on_axis = (gAgent.getPosAgentFromGlobal(mDragSelectionStartGlobal) - mGridOrigin) * axis_f; | ||
557 | axis_magnitude = cursor_grid_dist - object_start_on_axis; | ||
558 | } | ||
559 | else if (mManipPart >= LL_YZ_PLANE && mManipPart <= LL_XY_PLANE) | ||
560 | { | ||
561 | // subtract offset from object center | ||
562 | LLVector3d cursor_point_global; | ||
563 | getMousePointOnPlaneGlobal( cursor_point_global, x, y, current_pos_global, mManipNormal ); | ||
564 | cursor_point_global -= (mDragCursorStartGlobal - mDragSelectionStartGlobal); | ||
565 | |||
566 | // snap to planar grid | ||
567 | LLVector3 cursor_point_agent = gAgent.getPosAgentFromGlobal(cursor_point_global); | ||
568 | LLVector3 camera_plane_projection = gCamera->getAtAxis(); | ||
569 | camera_plane_projection -= projected_vec(camera_plane_projection, mManipNormal); | ||
570 | camera_plane_projection.normVec(); | ||
571 | LLVector3 camera_projected_dir = camera_plane_projection; | ||
572 | camera_plane_projection.rotVec(~mGridRotation); | ||
573 | camera_plane_projection.scaleVec(mGridScale); | ||
574 | camera_plane_projection.abs(); | ||
575 | F32 max_grid_scale; | ||
576 | if (camera_plane_projection.mV[VX] > camera_plane_projection.mV[VY] && | ||
577 | camera_plane_projection.mV[VX] > camera_plane_projection.mV[VZ]) | ||
578 | { | ||
579 | max_grid_scale = mGridScale.mV[VX]; | ||
580 | } | ||
581 | else if (camera_plane_projection.mV[VY] > camera_plane_projection.mV[VZ]) | ||
582 | { | ||
583 | max_grid_scale = mGridScale.mV[VY]; | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | max_grid_scale = mGridScale.mV[VZ]; | ||
588 | } | ||
589 | |||
590 | F32 num_subdivisions = llclamp(getSubdivisionLevel(getPivotPoint(), camera_projected_dir, max_grid_scale), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
591 | |||
592 | F32 grid_scale_a; | ||
593 | F32 grid_scale_b; | ||
594 | LLVector3 cursor_point_grid = (cursor_point_agent - mGridOrigin) * ~mGridRotation; | ||
595 | |||
596 | switch (mManipPart) | ||
597 | { | ||
598 | case LL_YZ_PLANE: | ||
599 | grid_scale_a = mGridScale.mV[VY] / num_subdivisions; | ||
600 | grid_scale_b = mGridScale.mV[VZ] / num_subdivisions; | ||
601 | cursor_point_grid.mV[VY] -= fmod(cursor_point_grid.mV[VY] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; | ||
602 | cursor_point_grid.mV[VZ] -= fmod(cursor_point_grid.mV[VZ] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; | ||
603 | break; | ||
604 | case LL_XZ_PLANE: | ||
605 | grid_scale_a = mGridScale.mV[VX] / num_subdivisions; | ||
606 | grid_scale_b = mGridScale.mV[VZ] / num_subdivisions; | ||
607 | cursor_point_grid.mV[VX] -= fmod(cursor_point_grid.mV[VX] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; | ||
608 | cursor_point_grid.mV[VZ] -= fmod(cursor_point_grid.mV[VZ] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; | ||
609 | break; | ||
610 | case LL_XY_PLANE: | ||
611 | grid_scale_a = mGridScale.mV[VX] / num_subdivisions; | ||
612 | grid_scale_b = mGridScale.mV[VY] / num_subdivisions; | ||
613 | cursor_point_grid.mV[VX] -= fmod(cursor_point_grid.mV[VX] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; | ||
614 | cursor_point_grid.mV[VY] -= fmod(cursor_point_grid.mV[VY] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; | ||
615 | break; | ||
616 | default: | ||
617 | break; | ||
618 | } | ||
619 | cursor_point_agent = (cursor_point_grid * mGridRotation) + mGridOrigin; | ||
620 | relative_move.setVec(cursor_point_agent - gAgent.getPosAgentFromGlobal(mDragSelectionStartGlobal)); | ||
621 | mInSnapRegime = TRUE; | ||
622 | } | ||
623 | else | ||
624 | { | ||
625 | mInSnapRegime = FALSE; | ||
626 | } | ||
627 | } | ||
628 | else | ||
629 | { | ||
630 | mInSnapRegime = FALSE; | ||
631 | } | ||
632 | |||
633 | // Clamp to arrow direction | ||
634 | // *FIX: does this apply anymore? | ||
635 | if (!axis_exists) | ||
636 | { | ||
637 | axis_magnitude = relative_move.normVec(); | ||
638 | axis_d.setVec(relative_move); | ||
639 | axis_d.normVec(); | ||
640 | axis_f.setVec(axis_d); | ||
641 | } | ||
642 | |||
643 | LLVector3d clamped_relative_move = axis_magnitude * axis_d; // scalar multiply | ||
644 | LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply | ||
645 | |||
646 | for(selectNode = gSelectMgr->getFirstNode(); | ||
647 | selectNode; | ||
648 | selectNode = gSelectMgr->getNextNode() ) | ||
649 | { | ||
650 | object = selectNode->getObject(); | ||
651 | |||
652 | // Only apply motion to root objects and objects selected | ||
653 | // as "individual". | ||
654 | if (!object->isRootEdit() && !selectNode->mIndividualSelection) | ||
655 | { | ||
656 | continue; | ||
657 | } | ||
658 | |||
659 | if (!object->isRootEdit()) | ||
660 | { | ||
661 | // child objects should not update if parent is selected | ||
662 | LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); | ||
663 | if (editable_root->isSelected()) | ||
664 | { | ||
665 | // we will be moved properly by our parent, so skip | ||
666 | continue; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | if (object->permMove()) | ||
671 | { | ||
672 | // handle attachments in local space | ||
673 | if (object->isAttachment() && object->mDrawable.notNull()) | ||
674 | { | ||
675 | // calculate local version of relative move | ||
676 | LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); | ||
677 | objWorldRotation.transQuat(); | ||
678 | |||
679 | LLVector3 old_position_local = object->getPosition(); | ||
680 | LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); | ||
681 | |||
682 | // move and clamp root object first, before adjusting children | ||
683 | if (new_position_local != old_position_local) | ||
684 | { | ||
685 | send_update = TRUE; | ||
686 | } | ||
687 | //RN: I forget, but we need to do this because of snapping which doesn't often result | ||
688 | // in position changes even when the mouse moves | ||
689 | object->setPosition(new_position_local); | ||
690 | rebuild(object); | ||
691 | gAgent.getAvatarObject()->clampAttachmentPositions(); | ||
692 | new_position_local = object->getPosition(); | ||
693 | |||
694 | if (selectNode->mIndividualSelection) | ||
695 | { | ||
696 | send_update = FALSE; | ||
697 | LLVector3 child_offset = (old_position_local - new_position_local) * ~object->getRotation(); | ||
698 | |||
699 | // counter-translate child objects if we are moving the root as an individual | ||
700 | for (U32 child_num = 0; child_num < object->mChildList.size(); child_num++) | ||
701 | { | ||
702 | LLViewerObject* childp = object->mChildList[child_num]; | ||
703 | |||
704 | if (!childp->isSelected()) | ||
705 | { | ||
706 | childp->setPosition(childp->getPosition() + child_offset); | ||
707 | rebuild(childp); | ||
708 | } | ||
709 | } | ||
710 | } | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | // compute new position to send to simulators, but don't set it yet. | ||
715 | // We need the old position to know which simulator to send the move message to. | ||
716 | LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; | ||
717 | |||
718 | // Don't let object centers go too far underground | ||
719 | F64 min_height = gWorldp->getMinAllowedZ(object); | ||
720 | if (new_position_global.mdV[VZ] < min_height) | ||
721 | { | ||
722 | new_position_global.mdV[VZ] = min_height; | ||
723 | } | ||
724 | |||
725 | // For safety, cap heights where objects can be dragged | ||
726 | if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) | ||
727 | { | ||
728 | new_position_global.mdV[VZ] = MAX_OBJECT_Z; | ||
729 | } | ||
730 | |||
731 | // Grass is always drawn on the ground, so clamp its position to the ground | ||
732 | if (object->getPCode() == LL_PCODE_LEGACY_GRASS) | ||
733 | { | ||
734 | new_position_global.mdV[VZ] = gWorldp->resolveLandHeightGlobal(new_position_global) + 1.f; | ||
735 | } | ||
736 | |||
737 | if (object->isRootEdit()) | ||
738 | { | ||
739 | new_position_global = gWorldp->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); | ||
740 | } | ||
741 | |||
742 | // PR: Only update if changed | ||
743 | LLVector3d old_position_global = object->getPositionGlobal(); | ||
744 | LLVector3 old_position_agent = object->getPositionAgent(); | ||
745 | LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); | ||
746 | if (object->isRootEdit()) | ||
747 | { | ||
748 | // finally, move parent object after children have calculated new offsets | ||
749 | object->setPositionAgent(new_position_agent); | ||
750 | rebuild(object); | ||
751 | } | ||
752 | else | ||
753 | { | ||
754 | LLViewerObject* root_object = object->getRootEdit(); | ||
755 | new_position_agent -= root_object->getPositionAgent(); | ||
756 | new_position_agent = new_position_agent * ~root_object->getRotation(); | ||
757 | object->setPositionParent(new_position_agent, FALSE); | ||
758 | rebuild(object); | ||
759 | } | ||
760 | |||
761 | if (selectNode->mIndividualSelection) | ||
762 | { | ||
763 | LLVector3 parent_offset = (new_position_agent - old_position_agent) * ~object->getRotation(); | ||
764 | |||
765 | // counter-translate child objects if we are moving the root as an individual | ||
766 | for (U32 child_num = 0; child_num < object->mChildList.size(); child_num++) | ||
767 | { | ||
768 | LLViewerObject* childp = object->mChildList[child_num]; | ||
769 | if (!childp->isSelected()) | ||
770 | { | ||
771 | childp->setPosition(childp->getPosition() - parent_offset); | ||
772 | rebuild(childp); | ||
773 | } | ||
774 | } | ||
775 | send_update = FALSE; | ||
776 | } | ||
777 | else if (old_position_global != new_position_global) | ||
778 | { | ||
779 | send_update = TRUE; | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | } | ||
784 | |||
785 | // Handle throttling to 10 updates per second. | ||
786 | F32 elapsed_time = mUpdateTimer.getElapsedTimeF32(); | ||
787 | const F32 UPDATE_DELAY = 0.1f; // min time between transmitted updates | ||
788 | if (send_update && (elapsed_time > UPDATE_DELAY)) | ||
789 | { | ||
790 | gSelectMgr->sendMultipleUpdate(UPD_POSITION); | ||
791 | mUpdateTimer.reset(); | ||
792 | mSendUpdateOnMouseUp = FALSE; | ||
793 | } | ||
794 | else | ||
795 | { | ||
796 | // ...suppressed update | ||
797 | mSendUpdateOnMouseUp = TRUE; | ||
798 | } | ||
799 | |||
800 | gSelectMgr->updateSelectionCenter(); | ||
801 | gAgent.clearFocusObject(); | ||
802 | //gAgent.setObjectTracking(FALSE); | ||
803 | dialog_refresh_all(); // ??? is this necessary? | ||
804 | |||
805 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (active)" << llendl; | ||
806 | gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); | ||
807 | return TRUE; | ||
808 | } | ||
809 | |||
810 | void LLManipTranslate::highlightManipulators(S32 x, S32 y) | ||
811 | { | ||
812 | mHighlightedPart = LL_NO_PART; | ||
813 | |||
814 | if (!gSelectMgr->getObjectCount()) | ||
815 | { | ||
816 | return; | ||
817 | } | ||
818 | |||
819 | //LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
820 | LLMatrix4 projMatrix = gCamera->getProjection(); | ||
821 | LLMatrix4 modelView = gCamera->getModelview(); | ||
822 | |||
823 | LLVector3 object_position = getPivotPoint(); | ||
824 | |||
825 | LLVector3 grid_origin; | ||
826 | LLVector3 grid_scale; | ||
827 | LLQuaternion grid_rotation; | ||
828 | |||
829 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
830 | |||
831 | LLVector3 relative_camera_dir; | ||
832 | |||
833 | LLMatrix4 transform; | ||
834 | |||
835 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
836 | { | ||
837 | relative_camera_dir = LLVector3(1.f, 0.f, 0.f) * ~grid_rotation; | ||
838 | LLVector4 translation(object_position); | ||
839 | transform.initRotTrans(grid_rotation, translation); | ||
840 | LLMatrix4 cfr(OGL_TO_CFR_ROTATION); | ||
841 | transform *= cfr; | ||
842 | LLMatrix4 window_scale; | ||
843 | F32 zoom_level = 2.f * gAgent.getAvatarObject()->mHUDCurZoom; | ||
844 | window_scale.initAll(LLVector3(zoom_level / gCamera->getAspect(), zoom_level, 0.f), | ||
845 | LLQuaternion::DEFAULT, | ||
846 | LLVector3::zero); | ||
847 | transform *= window_scale; | ||
848 | } | ||
849 | else | ||
850 | { | ||
851 | relative_camera_dir = (object_position - gCamera->getOrigin()) * ~grid_rotation; | ||
852 | relative_camera_dir.normVec(); | ||
853 | |||
854 | transform.initRotTrans(grid_rotation, LLVector4(object_position)); | ||
855 | transform *= modelView; | ||
856 | transform *= projMatrix; | ||
857 | } | ||
858 | |||
859 | mProjectedManipulators.deleteAllData(); | ||
860 | |||
861 | S32 numManips = 0; | ||
862 | |||
863 | // edges | ||
864 | mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 0.f, 0.f, 1.f); | ||
865 | mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 0.f, 0.f, 1.f); | ||
866 | |||
867 | mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 0.f, 1.f); | ||
868 | mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 0.f, 1.f); | ||
869 | |||
870 | mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 1.f); | ||
871 | mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 1.f); | ||
872 | |||
873 | mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 0.f, 0.f, 1.f); | ||
874 | mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 0.f, 0.f, 1.f); | ||
875 | |||
876 | mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 0.f, 1.f); | ||
877 | mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 0.f, 1.f); | ||
878 | |||
879 | mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 1.f); | ||
880 | mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 1.f); | ||
881 | |||
882 | S32 num_arrow_manips = numManips; | ||
883 | |||
884 | // planar manipulators | ||
885 | BOOL planar_manip_yz_visible = FALSE; | ||
886 | BOOL planar_manip_xz_visible = FALSE; | ||
887 | BOOL planar_manip_xy_visible = FALSE; | ||
888 | |||
889 | mManipulatorVertices[numManips] = LLVector4(0.f, mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 1.f); | ||
890 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
891 | mManipulatorVertices[numManips] = LLVector4(0.f, mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 1.f); | ||
892 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
893 | if (llabs(relative_camera_dir.mV[VX]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
894 | { | ||
895 | planar_manip_yz_visible = TRUE; | ||
896 | } | ||
897 | |||
898 | mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 0.f, mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 1.f); | ||
899 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
900 | mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 0.f, mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 1.f); | ||
901 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
902 | if (llabs(relative_camera_dir.mV[VY]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
903 | { | ||
904 | planar_manip_xz_visible = TRUE; | ||
905 | } | ||
906 | |||
907 | mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 0.f, 1.f); | ||
908 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
909 | mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 0.f, 1.f); | ||
910 | mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); | ||
911 | if (llabs(relative_camera_dir.mV[VZ]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
912 | { | ||
913 | planar_manip_xy_visible = TRUE; | ||
914 | } | ||
915 | |||
916 | for (S32 i = 0; i < num_arrow_manips; i+= 2) | ||
917 | { | ||
918 | LLVector4 projected_start = mManipulatorVertices[i] * transform; | ||
919 | projected_start = projected_start * (1.f / projected_start.mV[VW]); | ||
920 | |||
921 | LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; | ||
922 | projected_end = projected_end * (1.f / projected_end.mV[VW]); | ||
923 | |||
924 | ManipulatorHandle* projManipulator = | ||
925 | new ManipulatorHandle(LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), | ||
926 | LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), | ||
927 | MANIPULATOR_IDS[i / 2], | ||
928 | 10.f); // 10 pixel hotspot for arrows | ||
929 | mProjectedManipulators.addDataSorted(projManipulator); | ||
930 | } | ||
931 | |||
932 | if (planar_manip_yz_visible) | ||
933 | { | ||
934 | S32 i = num_arrow_manips; | ||
935 | LLVector4 projected_start = mManipulatorVertices[i] * transform; | ||
936 | projected_start = projected_start * (1.f / projected_start.mV[VW]); | ||
937 | |||
938 | LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; | ||
939 | projected_end = projected_end * (1.f / projected_end.mV[VW]); | ||
940 | |||
941 | ManipulatorHandle* projManipulator = | ||
942 | new ManipulatorHandle(LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), | ||
943 | LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), | ||
944 | MANIPULATOR_IDS[i / 2], | ||
945 | 20.f); // 20 pixels for planar manipulators | ||
946 | mProjectedManipulators.addDataSorted(projManipulator); | ||
947 | } | ||
948 | |||
949 | if (planar_manip_xz_visible) | ||
950 | { | ||
951 | S32 i = num_arrow_manips + 2; | ||
952 | LLVector4 projected_start = mManipulatorVertices[i] * transform; | ||
953 | projected_start = projected_start * (1.f / projected_start.mV[VW]); | ||
954 | |||
955 | LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; | ||
956 | projected_end = projected_end * (1.f / projected_end.mV[VW]); | ||
957 | |||
958 | ManipulatorHandle* projManipulator = | ||
959 | new ManipulatorHandle(LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), | ||
960 | LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), | ||
961 | MANIPULATOR_IDS[i / 2], | ||
962 | 20.f); // 20 pixels for planar manipulators | ||
963 | mProjectedManipulators.addDataSorted(projManipulator); | ||
964 | } | ||
965 | |||
966 | if (planar_manip_xy_visible) | ||
967 | { | ||
968 | S32 i = num_arrow_manips + 4; | ||
969 | LLVector4 projected_start = mManipulatorVertices[i] * transform; | ||
970 | projected_start = projected_start * (1.f / projected_start.mV[VW]); | ||
971 | |||
972 | LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; | ||
973 | projected_end = projected_end * (1.f / projected_end.mV[VW]); | ||
974 | |||
975 | ManipulatorHandle* projManipulator = | ||
976 | new ManipulatorHandle(LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), | ||
977 | LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), | ||
978 | MANIPULATOR_IDS[i / 2], | ||
979 | 20.f); // 20 pixels for planar manipulators | ||
980 | mProjectedManipulators.addDataSorted(projManipulator); | ||
981 | } | ||
982 | |||
983 | LLVector2 manip_start_2d; | ||
984 | LLVector2 manip_end_2d; | ||
985 | LLVector2 manip_dir; | ||
986 | F32 half_width = gViewerWindow->getWindowWidth() / 2.f; | ||
987 | F32 half_height = gViewerWindow->getWindowHeight() / 2.f; | ||
988 | LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); | ||
989 | LLVector2 mouse_delta; | ||
990 | |||
991 | for (ManipulatorHandle* manipulator = mProjectedManipulators.getFirstData(); | ||
992 | manipulator; | ||
993 | manipulator = mProjectedManipulators.getNextData()) | ||
994 | { | ||
995 | manip_start_2d.setVec(manipulator->mStartPosition.mV[VX] * half_width, manipulator->mStartPosition.mV[VY] * half_height); | ||
996 | manip_end_2d.setVec(manipulator->mEndPosition.mV[VX] * half_width, manipulator->mEndPosition.mV[VY] * half_height); | ||
997 | manip_dir = manip_end_2d - manip_start_2d; | ||
998 | |||
999 | mouse_delta = mousePos - manip_start_2d; | ||
1000 | |||
1001 | F32 manip_length = manip_dir.normVec(); | ||
1002 | |||
1003 | F32 mouse_pos_manip = mouse_delta * manip_dir; | ||
1004 | F32 mouse_dist_manip_squared = mouse_delta.magVecSquared() - (mouse_pos_manip * mouse_pos_manip); | ||
1005 | |||
1006 | if (mouse_pos_manip > 0.f && | ||
1007 | mouse_pos_manip < manip_length && | ||
1008 | mouse_dist_manip_squared < manipulator->mHotSpotRadius * manipulator->mHotSpotRadius) | ||
1009 | { | ||
1010 | mHighlightedPart = manipulator->mManipID; | ||
1011 | break; | ||
1012 | } | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | F32 LLManipTranslate::getMinGridScale() | ||
1017 | { | ||
1018 | F32 scale; | ||
1019 | switch (mManipPart) | ||
1020 | { | ||
1021 | case LL_NO_PART: | ||
1022 | default: | ||
1023 | scale = 1.f; | ||
1024 | break; | ||
1025 | case LL_X_ARROW: | ||
1026 | scale = mGridScale.mV[VX]; | ||
1027 | break; | ||
1028 | case LL_Y_ARROW: | ||
1029 | scale = mGridScale.mV[VY]; | ||
1030 | break; | ||
1031 | case LL_Z_ARROW: | ||
1032 | scale = mGridScale.mV[VZ]; | ||
1033 | break; | ||
1034 | case LL_YZ_PLANE: | ||
1035 | scale = llmin(mGridScale.mV[VY], mGridScale.mV[VZ]); | ||
1036 | break; | ||
1037 | case LL_XZ_PLANE: | ||
1038 | scale = llmin(mGridScale.mV[VX], mGridScale.mV[VZ]); | ||
1039 | break; | ||
1040 | case LL_XY_PLANE: | ||
1041 | scale = llmin(mGridScale.mV[VX], mGridScale.mV[VY]); | ||
1042 | break; | ||
1043 | } | ||
1044 | |||
1045 | return scale; | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | BOOL LLManipTranslate::handleMouseUp(S32 x, S32 y, MASK mask) | ||
1050 | { | ||
1051 | // first, perform normal processing in case this was a quick-click | ||
1052 | handleHover(x, y, mask); | ||
1053 | |||
1054 | // make sure arrow colors go back to normal | ||
1055 | mManipPart = LL_NO_PART; | ||
1056 | gSelectMgr->enableSilhouette(TRUE); | ||
1057 | |||
1058 | // Might have missed last update due to UPDATE_DELAY timing. | ||
1059 | if (mSendUpdateOnMouseUp) | ||
1060 | { | ||
1061 | gSelectMgr->sendMultipleUpdate( UPD_POSITION ); | ||
1062 | mSendUpdateOnMouseUp = FALSE; | ||
1063 | } | ||
1064 | |||
1065 | // if (mCopyMadeThisDrag) | ||
1066 | // { | ||
1067 | // gSelectMgr->clearGridObjects(); | ||
1068 | // } | ||
1069 | |||
1070 | mInSnapRegime = FALSE; | ||
1071 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
1072 | //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); | ||
1073 | |||
1074 | return LLManip::handleMouseUp(x, y, mask); | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | void LLManipTranslate::render() | ||
1079 | { | ||
1080 | glMatrixMode(GL_MODELVIEW); | ||
1081 | glPushMatrix(); | ||
1082 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1083 | { | ||
1084 | F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom; | ||
1085 | glScalef(zoom, zoom, zoom); | ||
1086 | } | ||
1087 | { | ||
1088 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); | ||
1089 | renderGuidelines(); | ||
1090 | } | ||
1091 | { | ||
1092 | renderTranslationHandles(); | ||
1093 | renderSnapGuides(); | ||
1094 | } | ||
1095 | glPopMatrix(); | ||
1096 | |||
1097 | renderText(); | ||
1098 | } | ||
1099 | |||
1100 | void LLManipTranslate::renderSnapGuides() | ||
1101 | { | ||
1102 | if (!gSavedSettings.getBOOL("SnapEnabled")) | ||
1103 | { | ||
1104 | return; | ||
1105 | } | ||
1106 | |||
1107 | F32 max_subdivisions = sGridMaxSubdivisionLevel;//(F32)gSavedSettings.getS32("GridSubdivision"); | ||
1108 | F32 line_alpha = gSavedSettings.getF32("GridOpacity"); | ||
1109 | |||
1110 | LLGLSNoTexture gls_no_texture; | ||
1111 | LLGLDepthTest gls_depth(GL_TRUE); | ||
1112 | LLGLDisable gls_cull(GL_CULL_FACE); | ||
1113 | LLVector3 translate_axis; | ||
1114 | |||
1115 | if (mManipPart == LL_NO_PART) | ||
1116 | { | ||
1117 | return; | ||
1118 | } | ||
1119 | |||
1120 | LLSelectNode *first_node = gSelectMgr->getFirstMoveableNode(TRUE); | ||
1121 | if (!first_node) | ||
1122 | { | ||
1123 | return; | ||
1124 | } | ||
1125 | |||
1126 | updateGridSettings(); | ||
1127 | |||
1128 | F32 smallest_grid_unit_scale = getMinGridScale() / max_subdivisions; | ||
1129 | LLVector3 grid_origin; | ||
1130 | LLVector3 grid_scale; | ||
1131 | LLQuaternion grid_rotation; | ||
1132 | |||
1133 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1134 | LLVector3 saved_selection_center = getSavedPivotPoint(); //gSelectMgr->getSavedBBoxOfSelection().getCenterAgent(); | ||
1135 | LLVector3 selection_center = getPivotPoint(); | ||
1136 | |||
1137 | LLViewerObject *first_object = first_node->getObject(); | ||
1138 | |||
1139 | //pick appropriate projection plane for snap rulers according to relative camera position | ||
1140 | if (mManipPart >= LL_X_ARROW && mManipPart <= LL_Z_ARROW) | ||
1141 | { | ||
1142 | getManipAxis(first_object, mManipPart, translate_axis); | ||
1143 | |||
1144 | LLVector3 at_axis_abs; | ||
1145 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1146 | { | ||
1147 | at_axis_abs = LLVector3::x_axis * ~grid_rotation; | ||
1148 | } | ||
1149 | else | ||
1150 | { | ||
1151 | at_axis_abs = saved_selection_center - gCamera->getOrigin(); | ||
1152 | at_axis_abs.normVec(); | ||
1153 | |||
1154 | at_axis_abs = at_axis_abs * ~grid_rotation; | ||
1155 | } | ||
1156 | at_axis_abs.abs(); | ||
1157 | |||
1158 | if (at_axis_abs.mV[VX] > at_axis_abs.mV[VY] && at_axis_abs.mV[VX] > at_axis_abs.mV[VZ]) | ||
1159 | { | ||
1160 | if (mManipPart == LL_Y_ARROW) | ||
1161 | { | ||
1162 | mSnapOffsetAxis = LLVector3::z_axis; | ||
1163 | } | ||
1164 | else if (mManipPart == LL_Z_ARROW) | ||
1165 | { | ||
1166 | mSnapOffsetAxis = LLVector3::y_axis; | ||
1167 | } | ||
1168 | else if (at_axis_abs.mV[VY] > at_axis_abs.mV[VZ]) | ||
1169 | { | ||
1170 | mSnapOffsetAxis = LLVector3::z_axis; | ||
1171 | } | ||
1172 | else | ||
1173 | { | ||
1174 | mSnapOffsetAxis = LLVector3::y_axis; | ||
1175 | } | ||
1176 | } | ||
1177 | else if (at_axis_abs.mV[VY] > at_axis_abs.mV[VZ]) | ||
1178 | { | ||
1179 | if (mManipPart == LL_X_ARROW) | ||
1180 | { | ||
1181 | mSnapOffsetAxis = LLVector3::z_axis; | ||
1182 | } | ||
1183 | else if (mManipPart == LL_Z_ARROW) | ||
1184 | { | ||
1185 | mSnapOffsetAxis = LLVector3::x_axis; | ||
1186 | } | ||
1187 | else if (at_axis_abs.mV[VX] > at_axis_abs.mV[VZ]) | ||
1188 | { | ||
1189 | mSnapOffsetAxis = LLVector3::z_axis; | ||
1190 | } | ||
1191 | else | ||
1192 | { | ||
1193 | mSnapOffsetAxis = LLVector3::x_axis; | ||
1194 | } | ||
1195 | } | ||
1196 | else | ||
1197 | { | ||
1198 | if (mManipPart == LL_X_ARROW) | ||
1199 | { | ||
1200 | mSnapOffsetAxis = LLVector3::y_axis; | ||
1201 | } | ||
1202 | else if (mManipPart == LL_Y_ARROW) | ||
1203 | { | ||
1204 | mSnapOffsetAxis = LLVector3::x_axis; | ||
1205 | } | ||
1206 | else if (at_axis_abs.mV[VX] > at_axis_abs.mV[VY]) | ||
1207 | { | ||
1208 | mSnapOffsetAxis = LLVector3::y_axis; | ||
1209 | } | ||
1210 | else | ||
1211 | { | ||
1212 | mSnapOffsetAxis = LLVector3::x_axis; | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | mSnapOffsetAxis = mSnapOffsetAxis * grid_rotation; | ||
1217 | |||
1218 | F32 guide_size_meters; | ||
1219 | |||
1220 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1221 | { | ||
1222 | guide_size_meters = 1.f / gAgent.getAvatarObject()->mHUDCurZoom; | ||
1223 | mSnapOffsetMeters = mArrowLengthMeters * 1.5f; | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | LLVector3 cam_to_selection = getPivotPoint() - gCamera->getOrigin(); | ||
1228 | F32 current_range = cam_to_selection.normVec(); | ||
1229 | guide_size_meters = SNAP_GUIDE_SCREEN_SIZE * gViewerWindow->getWindowHeight() * current_range / gCamera->getPixelMeterRatio(); | ||
1230 | |||
1231 | F32 fraction_of_fov = mAxisArrowLength / (F32) gCamera->getViewHeightInPixels(); | ||
1232 | F32 apparent_angle = fraction_of_fov * gCamera->getView(); // radians | ||
1233 | F32 offset_at_camera = tan(apparent_angle) * 1.5f; | ||
1234 | F32 range = dist_vec(gAgent.getPosAgentFromGlobal(first_node->mSavedPositionGlobal), gCamera->getOrigin()); | ||
1235 | mSnapOffsetMeters = range * offset_at_camera; | ||
1236 | } | ||
1237 | |||
1238 | LLVector3 tick_start; | ||
1239 | LLVector3 tick_end; | ||
1240 | |||
1241 | // how far away from grid origin is the selection along the axis of translation? | ||
1242 | F32 dist_grid_axis = (selection_center - mGridOrigin) * translate_axis; | ||
1243 | // find distance to nearest smallest grid unit | ||
1244 | F32 offset_nearest_grid_unit = fmodf(dist_grid_axis, smallest_grid_unit_scale); | ||
1245 | // how many smallest grid units are we away from largest grid scale? | ||
1246 | S32 sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() / sGridMinSubdivisionLevel) / smallest_grid_unit_scale); | ||
1247 | S32 num_ticks_per_side = llmax(1, llfloor(0.5f * guide_size_meters / smallest_grid_unit_scale)); | ||
1248 | |||
1249 | LLGLDepthTest gls_depth(GL_FALSE); | ||
1250 | |||
1251 | for (S32 pass = 0; pass < 3; pass++) | ||
1252 | { | ||
1253 | LLColor4 line_color = setupSnapGuideRenderPass(pass); | ||
1254 | |||
1255 | glBegin(GL_LINES); | ||
1256 | { | ||
1257 | LLVector3 line_start = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) + (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit)); | ||
1258 | LLVector3 line_end = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) - (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit)); | ||
1259 | LLVector3 line_mid = (line_start + line_end) * 0.5f; | ||
1260 | |||
1261 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); | ||
1262 | glVertex3fv(line_start.mV); | ||
1263 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); | ||
1264 | glVertex3fv(line_mid.mV); | ||
1265 | glVertex3fv(line_mid.mV); | ||
1266 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); | ||
1267 | glVertex3fv(line_end.mV); | ||
1268 | |||
1269 | line_start.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) + (translate_axis * guide_size_meters * 0.5f)); | ||
1270 | line_end.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) - (translate_axis * guide_size_meters * 0.5f)); | ||
1271 | line_mid = (line_start + line_end) * 0.5f; | ||
1272 | |||
1273 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); | ||
1274 | glVertex3fv(line_start.mV); | ||
1275 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); | ||
1276 | glVertex3fv(line_mid.mV); | ||
1277 | glVertex3fv(line_mid.mV); | ||
1278 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); | ||
1279 | glVertex3fv(line_end.mV); | ||
1280 | |||
1281 | for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++) | ||
1282 | { | ||
1283 | tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit)); | ||
1284 | |||
1285 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
1286 | |||
1287 | if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f) | ||
1288 | { | ||
1289 | continue; | ||
1290 | } | ||
1291 | |||
1292 | // add in off-axis offset | ||
1293 | tick_start += (mSnapOffsetAxis * mSnapOffsetMeters); | ||
1294 | |||
1295 | BOOL is_sub_tick = FALSE; | ||
1296 | F32 tick_scale = 1.f; | ||
1297 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1298 | { | ||
1299 | if (fmodf((F32)(i + sub_div_offset), division_level) == 0.f) | ||
1300 | { | ||
1301 | break; | ||
1302 | } | ||
1303 | tick_scale *= 0.7f; | ||
1304 | is_sub_tick = TRUE; | ||
1305 | } | ||
1306 | |||
1307 | // S32 num_ticks_to_fade = is_sub_tick ? num_ticks_per_side / 2 : num_ticks_per_side; | ||
1308 | // F32 alpha = line_alpha * (1.f - (0.8f * ((F32)llabs(i) / (F32)num_ticks_to_fade))); | ||
1309 | |||
1310 | tick_end = tick_start + (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale); | ||
1311 | |||
1312 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); | ||
1313 | glVertex3fv(tick_start.mV); | ||
1314 | glVertex3fv(tick_end.mV); | ||
1315 | |||
1316 | tick_start = selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) + | ||
1317 | (translate_axis * (getMinGridScale() / (F32)(max_subdivisions) * (F32)i - offset_nearest_grid_unit)); | ||
1318 | tick_end = tick_start - (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale); | ||
1319 | |||
1320 | glVertex3fv(tick_start.mV); | ||
1321 | glVertex3fv(tick_end.mV); | ||
1322 | } | ||
1323 | } | ||
1324 | glEnd(); | ||
1325 | |||
1326 | if (mInSnapRegime) | ||
1327 | { | ||
1328 | LLVector3 line_start = selection_center - mSnapOffsetAxis * mSnapOffsetMeters; | ||
1329 | LLVector3 line_end = selection_center + mSnapOffsetAxis * mSnapOffsetMeters; | ||
1330 | |||
1331 | glBegin(GL_LINES); | ||
1332 | { | ||
1333 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); | ||
1334 | |||
1335 | glVertex3fv(line_start.mV); | ||
1336 | glVertex3fv(line_end.mV); | ||
1337 | } | ||
1338 | glEnd(); | ||
1339 | |||
1340 | // draw snap guide arrow | ||
1341 | glBegin(GL_TRIANGLES); | ||
1342 | { | ||
1343 | glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); | ||
1344 | |||
1345 | LLVector3 arrow_dir; | ||
1346 | LLVector3 arrow_span = translate_axis; | ||
1347 | |||
1348 | arrow_dir = -mSnapOffsetAxis; | ||
1349 | glVertex3fv((line_start + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1350 | glVertex3fv((line_start + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1351 | glVertex3fv((line_start - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1352 | |||
1353 | arrow_dir = mSnapOffsetAxis; | ||
1354 | glVertex3fv((line_end + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1355 | glVertex3fv((line_end + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1356 | glVertex3fv((line_end - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); | ||
1357 | } | ||
1358 | glEnd(); | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() * 32.f) / smallest_grid_unit_scale); | ||
1363 | |||
1364 | LLVector2 screen_translate_axis(llabs(translate_axis * gCamera->getLeftAxis()), llabs(translate_axis * gCamera->getUpAxis())); | ||
1365 | screen_translate_axis.normVec(); | ||
1366 | |||
1367 | S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing); | ||
1368 | |||
1369 | // render tickmark values | ||
1370 | for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++) | ||
1371 | { | ||
1372 | LLVector3 tick_pos = selection_center + (translate_axis * ((smallest_grid_unit_scale * (F32)i) - offset_nearest_grid_unit)); | ||
1373 | F32 alpha = line_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side))); | ||
1374 | |||
1375 | F32 tick_scale = 1.f; | ||
1376 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1377 | { | ||
1378 | if (fmodf((F32)(i + sub_div_offset), division_level) == 0.f) | ||
1379 | { | ||
1380 | break; | ||
1381 | } | ||
1382 | tick_scale *= 0.7f; | ||
1383 | } | ||
1384 | |||
1385 | if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, translate_axis, getMinGridScale(), tick_label_spacing)))) == 0.f) | ||
1386 | { | ||
1387 | F32 snap_offset_meters; | ||
1388 | |||
1389 | if (mSnapOffsetAxis * gCamera->getUpAxis() > 0.f) | ||
1390 | { | ||
1391 | snap_offset_meters = mSnapOffsetMeters; | ||
1392 | } | ||
1393 | else | ||
1394 | { | ||
1395 | snap_offset_meters = -mSnapOffsetMeters; | ||
1396 | } | ||
1397 | LLVector3 text_origin = selection_center + | ||
1398 | (translate_axis * ((smallest_grid_unit_scale * (F32)i) - offset_nearest_grid_unit)) + | ||
1399 | (mSnapOffsetAxis * snap_offset_meters * (1.f + tick_scale)); | ||
1400 | |||
1401 | LLVector3 tick_offset = (tick_pos - mGridOrigin) * ~mGridRotation; | ||
1402 | F32 offset_val = 0.5f * tick_offset.mV[ARROW_TO_AXIS[mManipPart]] / getMinGridScale(); | ||
1403 | EGridMode grid_mode = gSelectMgr->getGridMode(); | ||
1404 | F32 text_highlight = 0.8f; | ||
1405 | if(i - llround(offset_nearest_grid_unit / smallest_grid_unit_scale) == 0 && mInSnapRegime) | ||
1406 | { | ||
1407 | text_highlight = 1.f; | ||
1408 | } | ||
1409 | |||
1410 | if (grid_mode == GRID_MODE_WORLD) | ||
1411 | { | ||
1412 | // rescale units to meters from multiple of grid scale | ||
1413 | offset_val *= 2.f * grid_scale[ARROW_TO_AXIS[mManipPart]]; | ||
1414 | renderTickValue(text_origin, offset_val, "m", LLColor4(text_highlight, text_highlight, text_highlight, alpha)); | ||
1415 | } | ||
1416 | else | ||
1417 | { | ||
1418 | renderTickValue(text_origin, offset_val, "x", LLColor4(text_highlight, text_highlight, text_highlight, alpha)); | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | if (gSelectMgr->getSelectType() != SELECT_TYPE_HUD) | ||
1423 | { | ||
1424 | // render helpful text | ||
1425 | if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText) | ||
1426 | { | ||
1427 | F32 snap_offset_meters_up; | ||
1428 | if (mSnapOffsetAxis * gCamera->getUpAxis() > 0.f) | ||
1429 | { | ||
1430 | snap_offset_meters_up = mSnapOffsetMeters; | ||
1431 | } | ||
1432 | else | ||
1433 | { | ||
1434 | snap_offset_meters_up = -mSnapOffsetMeters; | ||
1435 | } | ||
1436 | |||
1437 | LLVector3 selection_center_start = getSavedPivotPoint();//gSelectMgr->getSavedBBoxOfSelection().getCenterAgent(); | ||
1438 | |||
1439 | LLVector3 help_text_pos = selection_center_start + (snap_offset_meters_up * 3.f * mSnapOffsetAxis); | ||
1440 | const LLFontGL* big_fontp = LLFontGL::sSansSerif; | ||
1441 | |||
1442 | LLGLSTexture gls_texture; | ||
1443 | std::string help_text = "Move mouse cursor over ruler to snap"; | ||
1444 | LLColor4 help_text_color = LLColor4::white; | ||
1445 | help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f); | ||
1446 | hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, gSelectMgr->getSelectType() == SELECT_TYPE_HUD); | ||
1447 | help_text = "to snap to grid"; | ||
1448 | help_text_pos -= gCamera->getUpAxis() * mSnapOffsetMeters * 0.2f; | ||
1449 | hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, gSelectMgr->getSelectType() == SELECT_TYPE_HUD); | ||
1450 | } | ||
1451 | } | ||
1452 | } | ||
1453 | else | ||
1454 | { | ||
1455 | // render gridlines for planar snapping | ||
1456 | |||
1457 | F32 u = 0, v = 0; | ||
1458 | glPushMatrix(); | ||
1459 | |||
1460 | F32 x,y,z,angle_radians; | ||
1461 | grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); | ||
1462 | glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); | ||
1463 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
1464 | |||
1465 | LLVector3 grid_center = selection_center - grid_origin; | ||
1466 | grid_center *= ~grid_rotation; | ||
1467 | |||
1468 | F32 usc = 1; | ||
1469 | F32 vsc = 1; | ||
1470 | |||
1471 | switch (mManipPart) | ||
1472 | { | ||
1473 | case LL_YZ_PLANE: | ||
1474 | u = grid_center.mV[VY]; | ||
1475 | v = grid_center.mV[VZ]; | ||
1476 | usc = grid_scale.mV[VY]; | ||
1477 | vsc = grid_scale.mV[VZ]; | ||
1478 | break; | ||
1479 | case LL_XZ_PLANE: | ||
1480 | u = grid_center.mV[VX]; | ||
1481 | v = grid_center.mV[VZ]; | ||
1482 | usc = grid_scale.mV[VX]; | ||
1483 | vsc = grid_scale.mV[VZ]; | ||
1484 | break; | ||
1485 | case LL_XY_PLANE: | ||
1486 | u = grid_center.mV[VX]; | ||
1487 | v = grid_center.mV[VY]; | ||
1488 | usc = grid_scale.mV[VX]; | ||
1489 | vsc = grid_scale.mV[VY]; | ||
1490 | break; | ||
1491 | default: | ||
1492 | break; | ||
1493 | } | ||
1494 | |||
1495 | F32 sz = mGridSizeMeters; | ||
1496 | F32 tiles = sz; | ||
1497 | glMatrixMode(GL_TEXTURE); | ||
1498 | glPushMatrix(); | ||
1499 | usc = 1.0f/usc; | ||
1500 | vsc = 1.0f/vsc; | ||
1501 | |||
1502 | while (usc > vsc*4.0f) | ||
1503 | { | ||
1504 | usc *= 0.5f; | ||
1505 | } | ||
1506 | while (vsc > usc * 4.0f) | ||
1507 | { | ||
1508 | vsc *= 0.5f; | ||
1509 | } | ||
1510 | |||
1511 | glScalef(usc, vsc, 1.0f); | ||
1512 | glTranslatef(u, v, 0); | ||
1513 | |||
1514 | float a = line_alpha; | ||
1515 | |||
1516 | LLColor4 col = gColors.getColor("SilhouetteChildColor"); | ||
1517 | { | ||
1518 | //draw grid behind objects | ||
1519 | LLGLSTexture tex2d; | ||
1520 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); | ||
1521 | |||
1522 | { | ||
1523 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); | ||
1524 | glBindTexture(GL_TEXTURE_2D, sGridTex); | ||
1525 | glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); | ||
1526 | renderGrid(u,v,tiles,0.9f, 0.9f, 0.9f,a*0.15f); | ||
1527 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
1528 | } | ||
1529 | |||
1530 | { | ||
1531 | LLGLDisable alpha_test(GL_ALPHA_TEST); | ||
1532 | //draw black overlay | ||
1533 | glBindTexture(GL_TEXTURE_2D, 0); | ||
1534 | renderGrid(u,v,tiles,0.0f, 0.0f, 0.0f,a*0.16f); | ||
1535 | |||
1536 | //draw grid top | ||
1537 | glBindTexture(GL_TEXTURE_2D, sGridTex); | ||
1538 | renderGrid(u,v,tiles,1,1,1,a); | ||
1539 | |||
1540 | glPopMatrix(); | ||
1541 | glMatrixMode(GL_MODELVIEW); | ||
1542 | glPopMatrix(); | ||
1543 | |||
1544 | { | ||
1545 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); | ||
1546 | renderGuidelines(); | ||
1547 | } | ||
1548 | |||
1549 | { | ||
1550 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); | ||
1551 | LLGLEnable stipple(GL_LINE_STIPPLE); | ||
1552 | glLineStipple(1, 0x3333); | ||
1553 | |||
1554 | switch (mManipPart) | ||
1555 | { | ||
1556 | case LL_YZ_PLANE: | ||
1557 | renderGuidelines(FALSE, TRUE, TRUE); | ||
1558 | break; | ||
1559 | case LL_XZ_PLANE: | ||
1560 | renderGuidelines(TRUE, FALSE, TRUE); | ||
1561 | break; | ||
1562 | case LL_XY_PLANE: | ||
1563 | renderGuidelines(TRUE, TRUE, FALSE); | ||
1564 | break; | ||
1565 | default: | ||
1566 | break; | ||
1567 | } | ||
1568 | } | ||
1569 | } | ||
1570 | } | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | void LLManipTranslate::renderGrid(F32 x, F32 y, F32 size, F32 r, F32 g, F32 b, F32 a) | ||
1575 | { | ||
1576 | F32 d = size*0.5f; | ||
1577 | |||
1578 | for (F32 xx = -size-d; xx < size+d; xx += d) | ||
1579 | { | ||
1580 | glBegin(GL_TRIANGLE_STRIP); | ||
1581 | for (F32 yy = -size-d; yy < size+d; yy += d) | ||
1582 | { | ||
1583 | float dx, dy, da; | ||
1584 | |||
1585 | dx = xx; dy = yy; | ||
1586 | da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a; | ||
1587 | glTexCoord2f(dx, dy); | ||
1588 | renderGridVert(dx,dy,r,g,b,da); | ||
1589 | |||
1590 | dx = xx+d; dy = yy; | ||
1591 | da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a; | ||
1592 | glTexCoord2f(dx, dy); | ||
1593 | renderGridVert(dx,dy,r,g,b,da); | ||
1594 | |||
1595 | dx = xx; dy = yy+d; | ||
1596 | da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a; | ||
1597 | glTexCoord2f(dx, dy); | ||
1598 | renderGridVert(dx,dy,r,g,b,da); | ||
1599 | |||
1600 | dx = xx+d; dy = yy+d; | ||
1601 | da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a; | ||
1602 | glTexCoord2f(dx, dy); | ||
1603 | renderGridVert(dx,dy,r,g,b,da); | ||
1604 | } | ||
1605 | glEnd(); | ||
1606 | } | ||
1607 | |||
1608 | |||
1609 | } | ||
1610 | |||
1611 | |||
1612 | void LLManipTranslate::renderText() | ||
1613 | { | ||
1614 | if (gSelectMgr->getRootObjectCount() && !gSelectMgr->selectionIsAttachment()) | ||
1615 | { | ||
1616 | LLVector3 pos = getPivotPoint(); | ||
1617 | renderXYZ(pos); | ||
1618 | } | ||
1619 | else | ||
1620 | { | ||
1621 | LLViewerObject* objectp = gSelectMgr->getFirstRootObject(); | ||
1622 | if(!objectp) | ||
1623 | { | ||
1624 | objectp = gSelectMgr->getFirstObject(); | ||
1625 | } | ||
1626 | |||
1627 | if (objectp) | ||
1628 | { | ||
1629 | renderXYZ(objectp->getPositionEdit()); | ||
1630 | } | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | void LLManipTranslate::renderTranslationHandles() | ||
1635 | { | ||
1636 | LLVector3 grid_origin; | ||
1637 | LLVector3 grid_scale; | ||
1638 | LLQuaternion grid_rotation; | ||
1639 | LLGLDepthTest gls_depth(GL_FALSE); | ||
1640 | |||
1641 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1642 | LLVector3 at_axis; | ||
1643 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1644 | { | ||
1645 | at_axis = LLVector3::x_axis * ~grid_rotation; | ||
1646 | } | ||
1647 | else | ||
1648 | { | ||
1649 | at_axis = gCamera->getAtAxis() * ~grid_rotation; | ||
1650 | } | ||
1651 | |||
1652 | if (at_axis.mV[VX] > 0.f) | ||
1653 | { | ||
1654 | mPlaneManipPositions.mV[VX] = 1.f; | ||
1655 | } | ||
1656 | else | ||
1657 | { | ||
1658 | mPlaneManipPositions.mV[VX] = -1.f; | ||
1659 | } | ||
1660 | |||
1661 | if (at_axis.mV[VY] > 0.f) | ||
1662 | { | ||
1663 | mPlaneManipPositions.mV[VY] = 1.f; | ||
1664 | } | ||
1665 | else | ||
1666 | { | ||
1667 | mPlaneManipPositions.mV[VY] = -1.f; | ||
1668 | } | ||
1669 | |||
1670 | if (at_axis.mV[VZ] > 0.f) | ||
1671 | { | ||
1672 | mPlaneManipPositions.mV[VZ] = 1.f; | ||
1673 | } | ||
1674 | else | ||
1675 | { | ||
1676 | mPlaneManipPositions.mV[VZ] = -1.f; | ||
1677 | } | ||
1678 | |||
1679 | LLViewerObject *first_object = gSelectMgr->getFirstMoveableObject(TRUE); | ||
1680 | if (!first_object) return; | ||
1681 | |||
1682 | LLVector3 selection_center = getPivotPoint(); | ||
1683 | |||
1684 | // Drag handles | ||
1685 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1686 | { | ||
1687 | mArrowLengthMeters = mAxisArrowLength / gViewerWindow->getWindowHeight(); | ||
1688 | mArrowLengthMeters /= gAgent.getAvatarObject()->mHUDCurZoom; | ||
1689 | } | ||
1690 | else | ||
1691 | { | ||
1692 | LLVector3 camera_pos_agent = gAgent.getCameraPositionAgent(); | ||
1693 | F32 range = dist_vec(camera_pos_agent, selection_center); | ||
1694 | F32 range_from_agent = dist_vec(gAgent.getPositionAgent(), selection_center); | ||
1695 | |||
1696 | // Don't draw handles if you're too far away | ||
1697 | if (gSavedSettings.getBOOL("LimitSelectDistance")) | ||
1698 | { | ||
1699 | if (range_from_agent > gSavedSettings.getF32("MaxSelectDistance")) | ||
1700 | { | ||
1701 | return; | ||
1702 | } | ||
1703 | } | ||
1704 | |||
1705 | if (range > 0.001f) | ||
1706 | { | ||
1707 | // range != zero | ||
1708 | F32 fraction_of_fov = mAxisArrowLength / (F32) gCamera->getViewHeightInPixels(); | ||
1709 | F32 apparent_angle = fraction_of_fov * gCamera->getView(); // radians | ||
1710 | mArrowLengthMeters = range * tan(apparent_angle); | ||
1711 | } | ||
1712 | else | ||
1713 | { | ||
1714 | // range == zero | ||
1715 | mArrowLengthMeters = 1.0f; | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | mPlaneManipOffsetMeters = mArrowLengthMeters * 1.8f; | ||
1720 | mGridSizeMeters = gSavedSettings.getF32("GridDrawSize"); | ||
1721 | mConeSize = mArrowLengthMeters / 4.f; | ||
1722 | |||
1723 | glMatrixMode(GL_MODELVIEW); | ||
1724 | glPushMatrix(); | ||
1725 | { | ||
1726 | glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); | ||
1727 | |||
1728 | F32 angle_radians, x, y, z; | ||
1729 | grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); | ||
1730 | |||
1731 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
1732 | |||
1733 | LLQuaternion invRotation = grid_rotation; | ||
1734 | invRotation.conjQuat(); | ||
1735 | |||
1736 | LLVector3 relative_camera_dir; | ||
1737 | |||
1738 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1739 | { | ||
1740 | relative_camera_dir = LLVector3::x_axis * invRotation; | ||
1741 | } | ||
1742 | else | ||
1743 | { | ||
1744 | relative_camera_dir = (selection_center - gCamera->getOrigin()) * invRotation; | ||
1745 | } | ||
1746 | relative_camera_dir.normVec(); | ||
1747 | |||
1748 | { | ||
1749 | LLGLSNoTexture gls_ui_no_texture; | ||
1750 | LLGLDisable cull_face(GL_CULL_FACE); | ||
1751 | |||
1752 | LLColor4 color1; | ||
1753 | LLColor4 color2; | ||
1754 | |||
1755 | // update manipulator sizes | ||
1756 | for (S32 index = 0; index < 3; index++) | ||
1757 | { | ||
1758 | if (index == mManipPart - LL_X_ARROW || index == mHighlightedPart - LL_X_ARROW) | ||
1759 | { | ||
1760 | mArrowScales.mV[index] = lerp(mArrowScales.mV[index], SELECTED_ARROW_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1761 | mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1762 | } | ||
1763 | else if (index == mManipPart - LL_YZ_PLANE || index == mHighlightedPart - LL_YZ_PLANE) | ||
1764 | { | ||
1765 | mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1766 | mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], SELECTED_ARROW_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1767 | } | ||
1768 | else | ||
1769 | { | ||
1770 | mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1771 | mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); | ||
1772 | } | ||
1773 | } | ||
1774 | |||
1775 | if ((mManipPart == LL_NO_PART || mManipPart == LL_YZ_PLANE) && llabs(relative_camera_dir.mV[VX]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
1776 | { | ||
1777 | // render YZ plane manipulator | ||
1778 | glPushMatrix(); | ||
1779 | glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]); | ||
1780 | glTranslatef(0.f, mPlaneManipOffsetMeters, mPlaneManipOffsetMeters); | ||
1781 | glScalef(mPlaneScales.mV[VX], mPlaneScales.mV[VX], mPlaneScales.mV[VX]); | ||
1782 | if (mHighlightedPart == LL_YZ_PLANE) | ||
1783 | { | ||
1784 | color1.setVec(0.f, 1.f, 0.f, 1.f); | ||
1785 | color2.setVec(0.f, 0.f, 1.f, 1.f); | ||
1786 | } | ||
1787 | else | ||
1788 | { | ||
1789 | color1.setVec(0.f, 1.f, 0.f, 0.6f); | ||
1790 | color2.setVec(0.f, 0.f, 1.f, 0.6f); | ||
1791 | } | ||
1792 | glBegin(GL_TRIANGLES); | ||
1793 | { | ||
1794 | glColor4fv(color1.mV); | ||
1795 | glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f)); | ||
1796 | glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f)); | ||
1797 | glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1798 | |||
1799 | glColor4fv(color2.mV); | ||
1800 | glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1801 | glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1802 | glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f)); | ||
1803 | } | ||
1804 | glEnd(); | ||
1805 | |||
1806 | LLUI::setLineWidth(3.0f); | ||
1807 | glBegin(GL_LINES); | ||
1808 | { | ||
1809 | glColor4f(0.f, 0.f, 0.f, 0.3f); | ||
1810 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1811 | glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1812 | glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1813 | glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f); | ||
1814 | glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1815 | glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f); | ||
1816 | |||
1817 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1818 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1819 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1820 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f); | ||
1821 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1822 | glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f); | ||
1823 | } | ||
1824 | glEnd(); | ||
1825 | LLUI::setLineWidth(1.0f); | ||
1826 | glPopMatrix(); | ||
1827 | } | ||
1828 | |||
1829 | if ((mManipPart == LL_NO_PART || mManipPart == LL_XZ_PLANE) && llabs(relative_camera_dir.mV[VY]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
1830 | { | ||
1831 | // render XZ plane manipulator | ||
1832 | glPushMatrix(); | ||
1833 | glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]); | ||
1834 | glTranslatef(mPlaneManipOffsetMeters, 0.f, mPlaneManipOffsetMeters); | ||
1835 | glScalef(mPlaneScales.mV[VY], mPlaneScales.mV[VY], mPlaneScales.mV[VY]); | ||
1836 | if (mHighlightedPart == LL_XZ_PLANE) | ||
1837 | { | ||
1838 | color1.setVec(0.f, 0.f, 1.f, 1.f); | ||
1839 | color2.setVec(1.f, 0.f, 0.f, 1.f); | ||
1840 | } | ||
1841 | else | ||
1842 | { | ||
1843 | color1.setVec(0.f, 0.f, 1.f, 0.6f); | ||
1844 | color2.setVec(1.f, 0.f, 0.f, 0.6f); | ||
1845 | } | ||
1846 | |||
1847 | glBegin(GL_TRIANGLES); | ||
1848 | { | ||
1849 | glColor4fv(color1.mV); | ||
1850 | glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1851 | glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1852 | glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f)); | ||
1853 | |||
1854 | glColor4fv(color2.mV); | ||
1855 | glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f)); | ||
1856 | glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f)); | ||
1857 | glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f)); | ||
1858 | } | ||
1859 | glEnd(); | ||
1860 | |||
1861 | LLUI::setLineWidth(3.0f); | ||
1862 | glBegin(GL_LINES); | ||
1863 | { | ||
1864 | glColor4f(0.f, 0.f, 0.f, 0.3f); | ||
1865 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1866 | glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1867 | glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1868 | glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f); | ||
1869 | glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1870 | glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f); | ||
1871 | |||
1872 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f); | ||
1873 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1874 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1875 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f, 0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f); | ||
1876 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, 0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f); | ||
1877 | glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f, 0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f); | ||
1878 | } | ||
1879 | glEnd(); | ||
1880 | LLUI::setLineWidth(1.0f); | ||
1881 | |||
1882 | glPopMatrix(); | ||
1883 | } | ||
1884 | |||
1885 | if ((mManipPart == LL_NO_PART || mManipPart == LL_XY_PLANE) && llabs(relative_camera_dir.mV[VZ]) > MIN_PLANE_MANIP_DOT_PRODUCT) | ||
1886 | { | ||
1887 | // render XY plane manipulator | ||
1888 | glPushMatrix(); | ||
1889 | glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]); | ||
1890 | |||
1891 | /* Y | ||
1892 | ^ | ||
1893 | v1 | ||
1894 | | \ | ||
1895 | |<- v0 | ||
1896 | | /| \ | ||
1897 | v2__v__v3 > X | ||
1898 | */ | ||
1899 | LLVector3 v0,v1,v2,v3; | ||
1900 | #if 0 | ||
1901 | // This should theoretically work but looks off; could be tuned later -SJB | ||
1902 | glTranslatef(-mPlaneManipOffsetMeters, -mPlaneManipOffsetMeters, 0.f); | ||
1903 | v0 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1904 | v1 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.75f), 0.f); | ||
1905 | v2 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1906 | v3 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1907 | #else | ||
1908 | glTranslatef(mPlaneManipOffsetMeters, mPlaneManipOffsetMeters, 0.f); | ||
1909 | v0 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1910 | v1 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), 0.f); | ||
1911 | v2 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1912 | v3 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), 0.f); | ||
1913 | #endif | ||
1914 | glScalef(mPlaneScales.mV[VZ], mPlaneScales.mV[VZ], mPlaneScales.mV[VZ]); | ||
1915 | if (mHighlightedPart == LL_XY_PLANE) | ||
1916 | { | ||
1917 | color1.setVec(1.f, 0.f, 0.f, 1.f); | ||
1918 | color2.setVec(0.f, 1.f, 0.f, 1.f); | ||
1919 | } | ||
1920 | else | ||
1921 | { | ||
1922 | color1.setVec(0.8f, 0.f, 0.f, 0.6f); | ||
1923 | color2.setVec(0.f, 0.8f, 0.f, 0.6f); | ||
1924 | } | ||
1925 | |||
1926 | glBegin(GL_TRIANGLES); | ||
1927 | { | ||
1928 | glColor4fv(color1.mV); | ||
1929 | glVertex3fv(v0.mV); | ||
1930 | glVertex3fv(v1.mV); | ||
1931 | glVertex3fv(v2.mV); | ||
1932 | |||
1933 | glColor4fv(color2.mV); | ||
1934 | glVertex3fv(v2.mV); | ||
1935 | glVertex3fv(v3.mV); | ||
1936 | glVertex3fv(v0.mV); | ||
1937 | } | ||
1938 | glEnd(); | ||
1939 | |||
1940 | LLUI::setLineWidth(3.0f); | ||
1941 | glBegin(GL_LINES); | ||
1942 | { | ||
1943 | glColor4f(0.f, 0.f, 0.f, 0.3f); | ||
1944 | LLVector3 v12 = (v1 + v2) * .5f; | ||
1945 | glVertex3fv(v0.mV); | ||
1946 | glVertex3fv(v12.mV); | ||
1947 | glVertex3fv(v12.mV); | ||
1948 | glVertex3fv((v12 + (v0-v12)*.3f + (v2-v12)*.3f).mV); | ||
1949 | glVertex3fv(v12.mV); | ||
1950 | glVertex3fv((v12 + (v0-v12)*.3f + (v1-v12)*.3f).mV); | ||
1951 | |||
1952 | LLVector3 v23 = (v2 + v3) * .5f; | ||
1953 | glVertex3fv(v0.mV); | ||
1954 | glVertex3fv(v23.mV); | ||
1955 | glVertex3fv(v23.mV); | ||
1956 | glVertex3fv((v23 + (v0-v23)*.3f + (v3-v23)*.3f).mV); | ||
1957 | glVertex3fv(v23.mV); | ||
1958 | glVertex3fv((v23 + (v0-v23)*.3f + (v2-v23)*.3f).mV); | ||
1959 | } | ||
1960 | glEnd(); | ||
1961 | LLUI::setLineWidth(1.0f); | ||
1962 | |||
1963 | glPopMatrix(); | ||
1964 | } | ||
1965 | } | ||
1966 | { | ||
1967 | LLGLSNoTexture gls_ui_no_texture; | ||
1968 | |||
1969 | // Since we draw handles with depth testing off, we need to draw them in the | ||
1970 | // proper depth order. | ||
1971 | |||
1972 | // Copied from LLDrawable::updateGeometry | ||
1973 | LLVector3 pos_agent = first_object->getPositionAgent(); | ||
1974 | LLVector3 camera_agent = gAgent.getCameraPositionAgent(); | ||
1975 | LLVector3 headPos = pos_agent - camera_agent; | ||
1976 | |||
1977 | LLVector3 orientWRTHead = headPos * invRotation; | ||
1978 | |||
1979 | // Find nearest vertex | ||
1980 | U32 nearest = (orientWRTHead.mV[0] < 0.0f ? 1 : 0) + | ||
1981 | (orientWRTHead.mV[1] < 0.0f ? 2 : 0) + | ||
1982 | (orientWRTHead.mV[2] < 0.0f ? 4 : 0); | ||
1983 | |||
1984 | // opposite faces on Linden cubes: | ||
1985 | // 0 & 5 | ||
1986 | // 1 & 3 | ||
1987 | // 2 & 4 | ||
1988 | |||
1989 | // Table of order to draw faces, based on nearest vertex | ||
1990 | static U32 face_list[8][NUM_AXES*2] = { | ||
1991 | { 2,0,1, 4,5,3 }, // v6 F201 F453 | ||
1992 | { 2,0,3, 4,5,1 }, // v7 F203 F451 | ||
1993 | { 4,0,1, 2,5,3 }, // v5 F401 F253 | ||
1994 | { 4,0,3, 2,5,1 }, // v4 F403 F251 | ||
1995 | { 2,5,1, 4,0,3 }, // v2 F251 F403 | ||
1996 | { 2,5,3, 4,0,1 }, // v3 F253 F401 | ||
1997 | { 4,5,1, 2,0,3 }, // v1 F451 F203 | ||
1998 | { 4,5,3, 2,0,1 }, // v0 F453 F201 | ||
1999 | }; | ||
2000 | static const EManipPart which_arrow[6] = { | ||
2001 | LL_Z_ARROW, | ||
2002 | LL_X_ARROW, | ||
2003 | LL_Y_ARROW, | ||
2004 | LL_X_ARROW, | ||
2005 | LL_Y_ARROW, | ||
2006 | LL_Z_ARROW}; | ||
2007 | |||
2008 | // draw arrows for deeper faces first, closer faces last | ||
2009 | LLVector3 camera_axis; | ||
2010 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
2011 | { | ||
2012 | camera_axis = LLVector3::x_axis; | ||
2013 | } | ||
2014 | else | ||
2015 | { | ||
2016 | camera_axis.setVec(gAgent.getCameraPositionAgent() - first_object->getPositionAgent()); | ||
2017 | } | ||
2018 | |||
2019 | for (U32 i = 0; i < NUM_AXES*2; i++) | ||
2020 | { | ||
2021 | U32 face = face_list[nearest][i]; | ||
2022 | |||
2023 | LLVector3 arrow_axis; | ||
2024 | getManipAxis(first_object, which_arrow[face], arrow_axis); | ||
2025 | |||
2026 | if (fabs(angle_between(camera_axis, arrow_axis) - F_PI_BY_TWO) < F_PI_BY_TWO - HANDLE_HIDE_ANGLE) | ||
2027 | { | ||
2028 | renderArrow(which_arrow[face], | ||
2029 | mManipPart, | ||
2030 | (face >= 3) ? -mConeSize : mConeSize, | ||
2031 | (face >= 3) ? -mArrowLengthMeters : mArrowLengthMeters, | ||
2032 | mConeSize, | ||
2033 | FALSE); | ||
2034 | } | ||
2035 | } | ||
2036 | } | ||
2037 | } | ||
2038 | glPopMatrix(); | ||
2039 | } | ||
2040 | |||
2041 | |||
2042 | void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_size, F32 arrow_size, F32 handle_size, BOOL reverse_direction) | ||
2043 | { | ||
2044 | LLGLSNoTexture gls_ui_no_texture; | ||
2045 | LLGLEnable gls_blend(GL_BLEND); | ||
2046 | LLGLEnable gls_color_material(GL_COLOR_MATERIAL); | ||
2047 | |||
2048 | for (S32 pass = 1; pass <= 2; pass++) | ||
2049 | { | ||
2050 | LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, pass == 1 ? GL_LEQUAL : GL_GREATER); | ||
2051 | glPushMatrix(); | ||
2052 | |||
2053 | S32 index = 0; | ||
2054 | |||
2055 | index = ARROW_TO_AXIS[which_arrow]; | ||
2056 | |||
2057 | // assign a color for this arrow | ||
2058 | LLColor4 color; // black | ||
2059 | if (which_arrow == selected_arrow || which_arrow == mHighlightedPart) | ||
2060 | { | ||
2061 | color.mV[index] = (pass == 1) ? 1.f : 0.5f; | ||
2062 | } | ||
2063 | else if (selected_arrow != LL_NO_PART) | ||
2064 | { | ||
2065 | color.mV[VALPHA] = 0.f; | ||
2066 | } | ||
2067 | else | ||
2068 | { | ||
2069 | color.mV[index] = pass == 1 ? .8f : .35f ; // red, green, or blue | ||
2070 | color.mV[VALPHA] = 0.6f; | ||
2071 | } | ||
2072 | glColor4fv( color.mV ); | ||
2073 | |||
2074 | LLVector3 vec; | ||
2075 | |||
2076 | { | ||
2077 | // Stipple looks OK, but not great - SJB | ||
2078 | // LLGLEnable stipple(GL_LINE_STIPPLE); | ||
2079 | // glLineStipple(1, 0x3333); | ||
2080 | |||
2081 | LLUI::setLineWidth(2.0f); | ||
2082 | glBegin(GL_LINES); | ||
2083 | vec.mV[index] = box_size; | ||
2084 | glVertex3f(vec.mV[0], vec.mV[1], vec.mV[2]); | ||
2085 | |||
2086 | vec.mV[index] = arrow_size; | ||
2087 | glVertex3f(vec.mV[0], vec.mV[1], vec.mV[2]); | ||
2088 | glEnd(); | ||
2089 | LLUI::setLineWidth(1.0f); | ||
2090 | } | ||
2091 | |||
2092 | glTranslatef(vec.mV[0], vec.mV[1], vec.mV[2]); | ||
2093 | glScalef(handle_size, handle_size, handle_size); | ||
2094 | |||
2095 | F32 rot = 0.0f; | ||
2096 | LLVector3 axis; | ||
2097 | |||
2098 | switch(which_arrow) | ||
2099 | { | ||
2100 | case LL_X_ARROW: | ||
2101 | rot = reverse_direction ? -90.0f : 90.0f; | ||
2102 | axis.mV[1] = 1.0f; | ||
2103 | break; | ||
2104 | case LL_Y_ARROW: | ||
2105 | rot = reverse_direction ? 90.0f : -90.0f; | ||
2106 | axis.mV[0] = 1.0f; | ||
2107 | break; | ||
2108 | case LL_Z_ARROW: | ||
2109 | rot = reverse_direction ? 180.0f : 0.0f; | ||
2110 | axis.mV[0] = 1.0f; | ||
2111 | break; | ||
2112 | default: | ||
2113 | llerrs << "renderArrow called with bad arrow " << which_arrow << llendl; | ||
2114 | break; | ||
2115 | } | ||
2116 | |||
2117 | glRotatef(rot, axis.mV[0], axis.mV[1], axis.mV[2]); | ||
2118 | glScalef(mArrowScales.mV[index], mArrowScales.mV[index], mArrowScales.mV[index] * 1.5f); | ||
2119 | |||
2120 | gCone.render(CONE_LOD_HIGHEST); | ||
2121 | |||
2122 | glPopMatrix(); | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | void LLManipTranslate::renderGridVert(F32 x_trans, F32 y_trans, F32 r, F32 g, F32 b, F32 alpha) | ||
2127 | { | ||
2128 | glColor4f(r, g, b, alpha); | ||
2129 | switch (mManipPart) | ||
2130 | { | ||
2131 | case LL_YZ_PLANE: | ||
2132 | glVertex3f(0, x_trans, y_trans); | ||
2133 | break; | ||
2134 | case LL_XZ_PLANE: | ||
2135 | glVertex3f(x_trans, 0, y_trans); | ||
2136 | break; | ||
2137 | case LL_XY_PLANE: | ||
2138 | glVertex3f(x_trans, y_trans, 0); | ||
2139 | break; | ||
2140 | default: | ||
2141 | glVertex3f(0,0,0); | ||
2142 | break; | ||
2143 | } | ||
2144 | |||
2145 | } | ||