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/llmaniprotate.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/llmaniprotate.cpp')
-rw-r--r-- | linden/indra/newview/llmaniprotate.cpp | 1895 |
1 files changed, 1895 insertions, 0 deletions
diff --git a/linden/indra/newview/llmaniprotate.cpp b/linden/indra/newview/llmaniprotate.cpp new file mode 100644 index 0000000..93cbfe4 --- /dev/null +++ b/linden/indra/newview/llmaniprotate.cpp | |||
@@ -0,0 +1,1895 @@ | |||
1 | /** | ||
2 | * @file llmaniprotate.cpp | ||
3 | * @brief LLManipRotate 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 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llmaniprotate.h" | ||
31 | |||
32 | // library includes | ||
33 | #include "llmath.h" | ||
34 | #include "llgl.h" | ||
35 | #include "v4color.h" | ||
36 | #include "llprimitive.h" | ||
37 | #include "llview.h" | ||
38 | #include "llfontgl.h" | ||
39 | |||
40 | // viewer includes | ||
41 | #include "llagent.h" | ||
42 | #include "llbox.h" | ||
43 | #include "llbutton.h" | ||
44 | #include "llviewercontrol.h" | ||
45 | #include "llcriticaldamp.h" | ||
46 | #include "llhoverview.h" | ||
47 | #include "llfloatertools.h" | ||
48 | #include "llselectmgr.h" | ||
49 | #include "llstatusbar.h" | ||
50 | #include "llui.h" | ||
51 | #include "llvoavatar.h" | ||
52 | #include "llviewborder.h" | ||
53 | #include "llviewercamera.h" | ||
54 | #include "llviewerobject.h" | ||
55 | #include "llviewerobject.h" | ||
56 | #include "llviewerwindow.h" | ||
57 | #include "llworld.h" | ||
58 | #include "pipeline.h" | ||
59 | #include "viewer.h" | ||
60 | #include "lldrawable.h" | ||
61 | #include "llglheaders.h" | ||
62 | |||
63 | const F32 RADIUS_PIXELS = 100.f; // size in screen space | ||
64 | const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS; | ||
65 | const F32 WIDTH_PIXELS = 8; | ||
66 | const S32 CIRCLE_STEPS = 100; | ||
67 | const F32 DELTA = F_TWO_PI / CIRCLE_STEPS; | ||
68 | const F32 SIN_DELTA = sin( DELTA ); | ||
69 | const F32 COS_DELTA = cos( DELTA ); | ||
70 | const F32 MAX_MANIP_SELECT_DISTANCE = 100.f; | ||
71 | const F32 SNAP_ANGLE_INCREMENT = 5.625f; | ||
72 | const F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT; | ||
73 | const F32 SNAP_GUIDE_RADIUS_1 = 2.8f; | ||
74 | const F32 SNAP_GUIDE_RADIUS_2 = 2.4f; | ||
75 | const F32 SNAP_GUIDE_RADIUS_3 = 2.2f; | ||
76 | const F32 SNAP_GUIDE_RADIUS_4 = 2.1f; | ||
77 | const F32 SNAP_GUIDE_RADIUS_5 = 2.05f; | ||
78 | const F32 SNAP_GUIDE_INNER_RADIUS = 2.f; | ||
79 | const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD ); | ||
80 | const F32 SELECTED_MANIPULATOR_SCALE = 1.05f; | ||
81 | const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; | ||
82 | |||
83 | extern void handle_reset_rotation(void*); // in LLViewerWindow | ||
84 | extern void handle_first_tool(void*); | ||
85 | |||
86 | LLManipRotate::LLManipRotate( LLToolComposite* composite ) | ||
87 | : LLManip( "Rotate", composite ), | ||
88 | mRotationCenter(), | ||
89 | mCenterScreen(), | ||
90 | mRotation(), | ||
91 | mMouseDown(), | ||
92 | mMouseCur(), | ||
93 | mRadiusMeters(0.f), | ||
94 | mCenterToCam(), | ||
95 | mCenterToCamNorm(), | ||
96 | mCenterToCamMag(0.f), | ||
97 | mCenterToProfilePlane(), | ||
98 | mCenterToProfilePlaneMag(0.f), | ||
99 | mManipPart( LL_NO_PART ), | ||
100 | mSendUpdateOnMouseUp( FALSE ), | ||
101 | mSmoothRotate( FALSE ), | ||
102 | mCamEdgeOn(FALSE), | ||
103 | mManipulatorScales(1.f, 1.f, 1.f, 1.f) | ||
104 | { } | ||
105 | |||
106 | void LLManipRotate::handleSelect() | ||
107 | { | ||
108 | // *FIX: put this in mouseDown? | ||
109 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
110 | gFloaterTools->setStatusText("Drag colored bands to rotate object"); | ||
111 | } | ||
112 | |||
113 | void LLManipRotate::handleDeselect() | ||
114 | { | ||
115 | mHighlightedPart = LL_NO_PART; | ||
116 | mManipPart = LL_NO_PART; | ||
117 | |||
118 | gFloaterTools->setStatusText(""); | ||
119 | } | ||
120 | |||
121 | void LLManipRotate::render() | ||
122 | { | ||
123 | LLGLSUIDefault gls_ui; | ||
124 | LLGLSNoTexture gls_no_texture; | ||
125 | LLGLDepthTest gls_depth(GL_TRUE); | ||
126 | LLGLEnable gl_blend(GL_BLEND); | ||
127 | LLGLEnable gls_alpha_test(GL_ALPHA_TEST); | ||
128 | |||
129 | // You can rotate if you can move | ||
130 | LLViewerObject* first_object = gSelectMgr->getFirstMoveableObject(TRUE); | ||
131 | if( !first_object ) | ||
132 | { | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | if( !updateVisiblity() ) | ||
137 | { | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | glMatrixMode(GL_MODELVIEW); | ||
142 | glPushMatrix(); | ||
143 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
144 | { | ||
145 | F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom; | ||
146 | glScalef(zoom, zoom, zoom); | ||
147 | } | ||
148 | |||
149 | |||
150 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
151 | |||
152 | LLColor4 highlight_outside( 1.f, 1.f, 0.f, 1.f ); | ||
153 | LLColor4 highlight_inside( 0.7f, 0.7f, 0.f, 0.5f ); | ||
154 | F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS; | ||
155 | |||
156 | glPushMatrix(); | ||
157 | { | ||
158 | // are we in the middle of a constrained drag? | ||
159 | if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z) | ||
160 | { | ||
161 | renderSnapGuides(); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | LLGLEnable cull_face(GL_CULL_FACE); | ||
166 | LLGLDepthTest gls_depth(GL_FALSE); | ||
167 | glPushMatrix(); | ||
168 | { | ||
169 | // Draw "sphere" (intersection of sphere with tangent cone that has apex at camera) | ||
170 | glTranslatef( mCenterToProfilePlane.mV[VX], mCenterToProfilePlane.mV[VY], mCenterToProfilePlane.mV[VZ] ); | ||
171 | glTranslatef( center.mV[VX], center.mV[VY], center.mV[VZ] ); | ||
172 | |||
173 | // Inverse change of basis vectors | ||
174 | LLVector3 forward = mCenterToCamNorm; | ||
175 | LLVector3 left = gAgent.getUpAxis() % forward; | ||
176 | left.normVec(); | ||
177 | LLVector3 up = forward % left; | ||
178 | |||
179 | LLVector4 a(-forward); | ||
180 | a.mV[3] = 0; | ||
181 | LLVector4 b(up); | ||
182 | b.mV[3] = 0; | ||
183 | LLVector4 c(left); | ||
184 | c.mV[3] = 0; | ||
185 | LLMatrix4 mat; | ||
186 | mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f)); | ||
187 | |||
188 | glMultMatrixf( &mat.mMatrix[0][0] ); | ||
189 | |||
190 | glRotatef( -90, 0.f, 1.f, 0.f); | ||
191 | LLColor4 color; | ||
192 | if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL) | ||
193 | { | ||
194 | color.setVec(0.8f, 0.8f, 0.8f, 0.8f); | ||
195 | glScalef(mManipulatorScales.mV[VW], mManipulatorScales.mV[VW], mManipulatorScales.mV[VW]); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | color.setVec( 0.7f, 0.7f, 0.7f, 0.6f ); | ||
200 | } | ||
201 | gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters, CIRCLE_STEPS, color, color); | ||
202 | |||
203 | |||
204 | if (mManipPart == LL_NO_PART) | ||
205 | { | ||
206 | glColor4f( 0.7f, 0.7f, 0.7f, 0.3f ); | ||
207 | gl_circle_2d( 0, 0, mRadiusMeters, CIRCLE_STEPS, TRUE ); | ||
208 | } | ||
209 | |||
210 | GLdouble plane_eqn[] = { 0, 0, 1, 0 }; | ||
211 | glClipPlane( GL_CLIP_PLANE0, plane_eqn ); | ||
212 | } | ||
213 | glPopMatrix(); | ||
214 | } | ||
215 | |||
216 | glTranslatef( center.mV[VX], center.mV[VY], center.mV[VZ] ); | ||
217 | |||
218 | LLQuaternion rot; | ||
219 | F32 angle_radians, x, y, z; | ||
220 | |||
221 | LLVector3 grid_origin; | ||
222 | LLVector3 grid_scale; | ||
223 | LLQuaternion grid_rotation; | ||
224 | |||
225 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
226 | |||
227 | grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); | ||
228 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
229 | |||
230 | |||
231 | if (mManipPart == LL_ROT_Z) | ||
232 | { | ||
233 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
234 | glPushMatrix(); | ||
235 | { | ||
236 | // selected part | ||
237 | glScalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]); | ||
238 | renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f) , LLColor4( 0.f, 0.f, 1.f, 0.3f )); | ||
239 | } | ||
240 | glPopMatrix(); | ||
241 | } | ||
242 | else if (mManipPart == LL_ROT_Y) | ||
243 | { | ||
244 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
245 | glPushMatrix(); | ||
246 | { | ||
247 | glRotatef( 90.f, 1.f, 0.f, 0.f ); | ||
248 | glScalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); | ||
249 | renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f)); | ||
250 | } | ||
251 | glPopMatrix(); | ||
252 | } | ||
253 | else if (mManipPart == LL_ROT_X) | ||
254 | { | ||
255 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
256 | glPushMatrix(); | ||
257 | { | ||
258 | glRotatef( 90.f, 0.f, 1.f, 0.f ); | ||
259 | glScalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); | ||
260 | renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f)); | ||
261 | } | ||
262 | glPopMatrix(); | ||
263 | } | ||
264 | else if (mManipPart == LL_ROT_ROLL) | ||
265 | { | ||
266 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
267 | } | ||
268 | else if (mManipPart == LL_NO_PART) | ||
269 | { | ||
270 | if (mHighlightedPart == LL_NO_PART) | ||
271 | { | ||
272 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
273 | } | ||
274 | |||
275 | LLGLEnable cull_face(GL_CULL_FACE); | ||
276 | LLGLEnable clip_plane0(GL_CLIP_PLANE0); | ||
277 | LLGLDepthTest gls_depth(GL_FALSE); | ||
278 | |||
279 | // First pass: centers. Second pass: sides. | ||
280 | for( S32 i=0; i<2; i++ ) | ||
281 | { | ||
282 | glPushMatrix(); | ||
283 | { | ||
284 | if (mHighlightedPart == LL_ROT_Z) | ||
285 | { | ||
286 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
287 | glScalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]); | ||
288 | // hovering over part | ||
289 | gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f ), LLColor4( 0.f, 0.f, 1.f, 0.5f ), CIRCLE_STEPS, i); | ||
290 | } | ||
291 | else | ||
292 | { | ||
293 | // default | ||
294 | gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 0.8f, 0.8f ), LLColor4( 0.f, 0.f, 0.8f, 0.4f ), CIRCLE_STEPS, i); | ||
295 | } | ||
296 | } | ||
297 | glPopMatrix(); | ||
298 | |||
299 | glPushMatrix(); | ||
300 | { | ||
301 | glRotatef( 90.f, 1.f, 0.f, 0.f ); | ||
302 | if (mHighlightedPart == LL_ROT_Y) | ||
303 | { | ||
304 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
305 | glScalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); | ||
306 | // hovering over part | ||
307 | gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f ), LLColor4( 0.f, 1.f, 0.f, 0.5f ), CIRCLE_STEPS, i); | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | // default | ||
312 | gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.8f, 0.f, 0.8f ), LLColor4( 0.f, 0.8f, 0.f, 0.4f ), CIRCLE_STEPS, i); | ||
313 | } | ||
314 | } | ||
315 | glPopMatrix(); | ||
316 | |||
317 | glPushMatrix(); | ||
318 | { | ||
319 | glRotatef( 90.f, 0.f, 1.f, 0.f ); | ||
320 | if (mHighlightedPart == LL_ROT_X) | ||
321 | { | ||
322 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
323 | glScalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); | ||
324 | |||
325 | // hovering over part | ||
326 | gl_ring( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f ), LLColor4( 1.f, 0.f, 0.f, 0.5f ), CIRCLE_STEPS, i); | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | // default | ||
331 | gl_ring( mRadiusMeters, width_meters, LLColor4( 0.8f, 0.f, 0.f, 0.8f ), LLColor4( 0.8f, 0.f, 0.f, 0.4f ), CIRCLE_STEPS, i); | ||
332 | } | ||
333 | } | ||
334 | glPopMatrix(); | ||
335 | |||
336 | if (mHighlightedPart == LL_ROT_ROLL) | ||
337 | { | ||
338 | mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | glPopMatrix(); | ||
344 | glPopMatrix(); | ||
345 | |||
346 | LLVector3 euler_angles; | ||
347 | LLQuaternion object_rot = first_object->getRotationEdit(); | ||
348 | object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ])); | ||
349 | euler_angles *= RAD_TO_DEG; | ||
350 | euler_angles.mV[VX] = llround(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f); | ||
351 | euler_angles.mV[VY] = llround(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f); | ||
352 | euler_angles.mV[VZ] = llround(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f); | ||
353 | |||
354 | renderXYZ(euler_angles); | ||
355 | } | ||
356 | |||
357 | BOOL LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask) | ||
358 | { | ||
359 | BOOL handled = FALSE; | ||
360 | |||
361 | LLViewerObject* first_object = gSelectMgr->getFirstMoveableObject(TRUE); | ||
362 | if( first_object ) | ||
363 | { | ||
364 | LLViewerObject* hit_obj = gViewerWindow->lastObjectHit(); | ||
365 | if( hit_obj && mHighlightedPart != LL_NO_PART ) | ||
366 | { | ||
367 | handled = handleMouseDownOnPart( x, y, mask ); | ||
368 | } | ||
369 | } | ||
370 | |||
371 | return handled; | ||
372 | } | ||
373 | |||
374 | // Assumes that one of the parts of the manipulator was hit. | ||
375 | BOOL LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) | ||
376 | { | ||
377 | BOOL can_rotate = gSelectMgr->getObjectCount() != 0; | ||
378 | for (LLViewerObject* objectp = gSelectMgr->getFirstObject(); | ||
379 | objectp; | ||
380 | objectp = gSelectMgr->getNextObject()) | ||
381 | { | ||
382 | can_rotate = can_rotate && objectp->permMove() && (objectp->permModify() || gSavedSettings.getBOOL("SelectLinkedSet")); | ||
383 | } | ||
384 | |||
385 | if (!can_rotate) | ||
386 | { | ||
387 | return FALSE; | ||
388 | } | ||
389 | |||
390 | highlightManipulators(x, y); | ||
391 | S32 hit_part = mHighlightedPart; | ||
392 | // we just started a drag, so save initial object positions | ||
393 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE); | ||
394 | |||
395 | // save selection center | ||
396 | mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() ); //gSelectMgr->getSelectionCenterGlobal(); | ||
397 | |||
398 | mManipPart = (EManipPart)hit_part; | ||
399 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
400 | |||
401 | if( mManipPart == LL_ROT_GENERAL) | ||
402 | { | ||
403 | mMouseDown = intersectMouseWithSphere( x, y, center, mRadiusMeters); | ||
404 | } | ||
405 | else | ||
406 | { | ||
407 | // Project onto the plane of the ring | ||
408 | LLVector3 axis = getConstraintAxis(); | ||
409 | |||
410 | F32 axis_onto_cam = llabs( axis * mCenterToCamNorm ); | ||
411 | const F32 AXIS_ONTO_CAM_TOL = cos( 85.f * DEG_TO_RAD ); | ||
412 | if( axis_onto_cam < AXIS_ONTO_CAM_TOL ) | ||
413 | { | ||
414 | LLVector3 up_from_axis = mCenterToCamNorm % axis; | ||
415 | up_from_axis.normVec(); | ||
416 | LLVector3 cur_intersection; | ||
417 | getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam); | ||
418 | cur_intersection -= center; | ||
419 | mMouseDown = projected_vec(cur_intersection, up_from_axis); | ||
420 | F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; | ||
421 | F32 mouse_dist_sqrd = mMouseDown.magVecSquared(); | ||
422 | if (mouse_dist_sqrd > 0.0001f) | ||
423 | { | ||
424 | mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - | ||
425 | mouse_dist_sqrd); | ||
426 | } | ||
427 | LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis); | ||
428 | mMouseDown += mouse_depth * projected_center_to_cam; | ||
429 | |||
430 | } | ||
431 | else | ||
432 | { | ||
433 | mMouseDown = findNearestPointOnRing( x, y, center, axis ) - center; | ||
434 | mMouseDown.normVec(); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | mMouseCur = mMouseDown; | ||
439 | |||
440 | // Route future Mouse messages here preemptively. (Release on mouse up.) | ||
441 | setMouseCapture( TRUE ); | ||
442 | gSelectMgr->enableSilhouette(FALSE); | ||
443 | return TRUE; | ||
444 | } | ||
445 | |||
446 | |||
447 | LLVector3 LLManipRotate::findNearestPointOnRing( S32 x, S32 y, const LLVector3& center, const LLVector3& axis ) | ||
448 | { | ||
449 | // Project the delta onto the ring and rescale it by the radius so that it's _on_ the ring. | ||
450 | LLVector3 proj_onto_ring; | ||
451 | getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis); | ||
452 | proj_onto_ring -= center; | ||
453 | proj_onto_ring.normVec(); | ||
454 | |||
455 | return center + proj_onto_ring * mRadiusMeters; | ||
456 | } | ||
457 | |||
458 | BOOL LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask) | ||
459 | { | ||
460 | // first, perform normal processing in case this was a quick-click | ||
461 | handleHover(x, y, mask); | ||
462 | |||
463 | mManipPart = LL_NO_PART; | ||
464 | |||
465 | // Might have missed last update due to timing. | ||
466 | if (mSendUpdateOnMouseUp) | ||
467 | { | ||
468 | gSelectMgr->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION ); | ||
469 | mSendUpdateOnMouseUp = FALSE; | ||
470 | } | ||
471 | gSelectMgr->enableSilhouette(TRUE); | ||
472 | //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); | ||
473 | |||
474 | gSelectMgr->updateSelectionCenter(); | ||
475 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
476 | |||
477 | return LLManip::handleMouseUp(x, y, mask); | ||
478 | } | ||
479 | |||
480 | |||
481 | BOOL LLManipRotate::handleHover(S32 x, S32 y, MASK mask) | ||
482 | { | ||
483 | if( hasMouseCapture() ) | ||
484 | { | ||
485 | if( gSelectMgr->isEmpty() ) | ||
486 | { | ||
487 | // Somehow the object got deselected while we were dragging it. | ||
488 | setMouseCapture( FALSE ); | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | drag(x, y); | ||
493 | } | ||
494 | |||
495 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (active)" << llendl; | ||
496 | } | ||
497 | else | ||
498 | { | ||
499 | highlightManipulators(x, y); | ||
500 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (inactive)" << llendl; | ||
501 | } | ||
502 | |||
503 | gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE); | ||
504 | return TRUE; | ||
505 | } | ||
506 | |||
507 | |||
508 | LLVector3 LLManipRotate::projectToSphere( F32 x, F32 y, BOOL* on_sphere ) | ||
509 | { | ||
510 | F32 z = 0.f; | ||
511 | F32 dist_squared = x*x + y*y; | ||
512 | |||
513 | *on_sphere = dist_squared <= SQ_RADIUS; | ||
514 | if( *on_sphere ) | ||
515 | { | ||
516 | z = sqrt(SQ_RADIUS - dist_squared); | ||
517 | } | ||
518 | return LLVector3( x, y, z ); | ||
519 | } | ||
520 | |||
521 | extern U32 gFrameCount; | ||
522 | |||
523 | // Freeform rotation | ||
524 | void LLManipRotate::drag( S32 x, S32 y ) | ||
525 | { | ||
526 | static LLTimer update_timer; | ||
527 | F32 elapsed_time = update_timer.getElapsedTimeF32(); | ||
528 | const F32 UPDATE_DELAY = 0.1f; // min time between transmitted updates | ||
529 | BOOL send_rotation_update = FALSE; | ||
530 | BOOL send_position_update = FALSE; | ||
531 | |||
532 | if( !updateVisiblity() ) | ||
533 | { | ||
534 | return; | ||
535 | } | ||
536 | |||
537 | if( mManipPart == LL_ROT_GENERAL ) | ||
538 | { | ||
539 | mRotation = dragUnconstrained(x, y); | ||
540 | } | ||
541 | else | ||
542 | { | ||
543 | mRotation = dragConstrained(x, y); | ||
544 | } | ||
545 | |||
546 | BOOL damped = mSmoothRotate; | ||
547 | mSmoothRotate = FALSE; | ||
548 | |||
549 | LLViewerObject* object; | ||
550 | LLSelectNode* selectNode; | ||
551 | BOOL using_linked_selection = gSavedSettings.getBOOL("SelectLinkedSet"); | ||
552 | |||
553 | for( selectNode = gSelectMgr->getFirstNode(); selectNode != NULL; selectNode = gSelectMgr->getNextNode() ) | ||
554 | { | ||
555 | object = selectNode->getObject(); | ||
556 | |||
557 | // have permission to move and object is root of selection or individually selected | ||
558 | if (object->permMove() && (object->isRootEdit() || selectNode->mIndividualSelection)) | ||
559 | { | ||
560 | if (!object->isRootEdit()) | ||
561 | { | ||
562 | // child objects should not update if parent is selected | ||
563 | LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); | ||
564 | if (editable_root->isSelected()) | ||
565 | { | ||
566 | // we will be moved properly by our parent, so skip | ||
567 | continue; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; | ||
572 | std::vector<LLVector3> child_positions; | ||
573 | std::vector<LLQuaternion> child_rotations; | ||
574 | if (object->isRootEdit() && selectNode->mIndividualSelection) | ||
575 | { | ||
576 | for (U32 i = 0; i < object->mChildList.size(); i++) | ||
577 | { | ||
578 | LLViewerObject* childp = object->mChildList[i]; | ||
579 | child_positions.push_back(childp->getPositionEdit()); | ||
580 | child_rotations.push_back(childp->getRotationEdit()); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | if (object->getParent() && object->mDrawable.notNull()) | ||
585 | { | ||
586 | LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); | ||
587 | invParentRotation.transQuat(); | ||
588 | |||
589 | object->setRotation(new_rot * invParentRotation, damped); | ||
590 | rebuild(object); | ||
591 | } | ||
592 | else | ||
593 | { | ||
594 | object->setRotation(new_rot, damped); | ||
595 | rebuild(object); | ||
596 | } | ||
597 | |||
598 | // don't send updates all the time for sub-objects | ||
599 | if (using_linked_selection && object->getRenderRotation() != new_rot) | ||
600 | { | ||
601 | send_rotation_update = TRUE; | ||
602 | } | ||
603 | |||
604 | // for individually selected roots, we need to counterrotate all the children | ||
605 | if (object->isRootEdit() && selectNode->mIndividualSelection) | ||
606 | { | ||
607 | //RN: must do non-damped updates on these objects so relative rotation appears constant | ||
608 | // instead of having two competing slerps making the child objects appear to "wobble" | ||
609 | for (U32 i = 0; i < object->mChildList.size(); i++) | ||
610 | { | ||
611 | LLViewerObject* childp = object->mChildList[i]; | ||
612 | LLVector3 child_offset = ((child_positions[i] - object->getPositionEdit()) * ~object->getRotationEdit()) - childp->getPosition(); | ||
613 | if (!childp->isSelected() && childp->mDrawable.notNull()) | ||
614 | { | ||
615 | childp->setRotation(child_rotations[i] * ~object->getRotationEdit()); | ||
616 | childp->setPosition((child_positions[i] - object->getPositionEdit()) * ~object->getRotationEdit()); | ||
617 | rebuild(childp); | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | } | ||
623 | |||
624 | // update positions | ||
625 | for( selectNode = gSelectMgr->getFirstNode(); selectNode != NULL; selectNode = gSelectMgr->getNextNode() ) | ||
626 | { | ||
627 | object = selectNode->getObject(); | ||
628 | |||
629 | // to avoid cumulative position changes we calculate the objects new position using its saved position | ||
630 | if (object && object->permMove()) | ||
631 | { | ||
632 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
633 | |||
634 | LLVector3 old_position; | ||
635 | LLVector3 new_position; | ||
636 | |||
637 | if (object->isAttachment() && object->mDrawable.notNull()) | ||
638 | { | ||
639 | // need to work in drawable space to handle selected items from multiple attachments | ||
640 | // (which have no shared frame of reference other than their render positions) | ||
641 | LLXform* parent_xform = object->mDrawable->getXform()->getParent(); | ||
642 | new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); | ||
643 | old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); | ||
644 | } | ||
645 | else | ||
646 | { | ||
647 | new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal ); | ||
648 | old_position = object->getPositionAgent(); | ||
649 | } | ||
650 | |||
651 | new_position = (new_position - center) * mRotation; // new relative rotated position | ||
652 | new_position += center; | ||
653 | |||
654 | if (object->isRootEdit() && !object->isAttachment()) | ||
655 | { | ||
656 | LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); | ||
657 | new_pos_global = gWorldp->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); | ||
658 | new_position = gAgent.getPosAgentFromGlobal(new_pos_global); | ||
659 | } | ||
660 | |||
661 | // for individually selected child objects | ||
662 | if (!object->isRootEdit() && selectNode->mIndividualSelection) | ||
663 | { | ||
664 | LLViewerObject* parentp = (LLViewerObject*)object->getParent(); | ||
665 | if (!parentp->isSelected()) | ||
666 | { | ||
667 | if (object->isAttachment() && object->mDrawable.notNull()) | ||
668 | { | ||
669 | // find position relative to render position of parent | ||
670 | object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); | ||
671 | rebuild(object); | ||
672 | } | ||
673 | else | ||
674 | { | ||
675 | object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); | ||
676 | rebuild(object); | ||
677 | } | ||
678 | } | ||
679 | } | ||
680 | else if (object->isRootEdit()) | ||
681 | { | ||
682 | if (object->isAttachment() && object->mDrawable.notNull()) | ||
683 | { | ||
684 | LLXform* parent_xform = object->mDrawable->getXform()->getParent(); | ||
685 | object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); | ||
686 | rebuild(object); | ||
687 | } | ||
688 | else | ||
689 | { | ||
690 | object->setPositionAgent(new_position); | ||
691 | rebuild(object); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | if (using_linked_selection && object->getPositionAgent() != new_position) | ||
696 | { | ||
697 | send_position_update = TRUE; | ||
698 | } | ||
699 | |||
700 | // for individually selected roots, we need to counter-translate all unselected children | ||
701 | if (object->isRootEdit() && selectNode->mIndividualSelection) | ||
702 | { | ||
703 | // only offset by parent's translation as we've already countered parent's rotation | ||
704 | LLVector3 child_offset; | ||
705 | if (object->isAttachment() && object->mDrawable.notNull()) | ||
706 | { | ||
707 | LLXform* attachment_point_xform = object->mDrawable->getXform()->getParent(); | ||
708 | LLQuaternion parent_rotation = object->getRotation() * attachment_point_xform->getWorldRotation(); | ||
709 | child_offset = LLVector3(old_position - new_position) * ~parent_rotation; | ||
710 | } | ||
711 | else | ||
712 | { | ||
713 | child_offset = LLVector3(old_position - new_position) * ~object->getRenderRotation(); | ||
714 | } | ||
715 | |||
716 | rebuild(object); | ||
717 | for (U32 i = 0; i < object->mChildList.size(); i++) | ||
718 | { | ||
719 | LLViewerObject* childp = object->mChildList[i]; | ||
720 | if (!childp->isSelected() && childp->mDrawable.notNull()) | ||
721 | { | ||
722 | childp->setPosition(childp->getPosition() + child_offset); | ||
723 | rebuild(childp); | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | |||
730 | if ((send_position_update || send_rotation_update) && (elapsed_time > UPDATE_DELAY)) | ||
731 | { | ||
732 | U32 flag = UPD_NONE; | ||
733 | if (send_rotation_update) | ||
734 | { | ||
735 | flag |= UPD_ROTATION; | ||
736 | } | ||
737 | if (send_position_update) | ||
738 | { | ||
739 | flag |= UPD_POSITION; | ||
740 | } | ||
741 | |||
742 | gSelectMgr->sendMultipleUpdate( flag ); | ||
743 | update_timer.reset(); | ||
744 | mSendUpdateOnMouseUp = FALSE; | ||
745 | } | ||
746 | else | ||
747 | { | ||
748 | mSendUpdateOnMouseUp = TRUE; | ||
749 | } | ||
750 | |||
751 | gSelectMgr->updateSelectionCenter(); | ||
752 | |||
753 | // RN: just clear focus so camera doesn't follow spurious object updates | ||
754 | gAgent.clearFocusObject(); | ||
755 | dialog_refresh_all(); | ||
756 | } | ||
757 | |||
758 | void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color) | ||
759 | { | ||
760 | LLGLEnable cull_face(GL_CULL_FACE); | ||
761 | { | ||
762 | gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, FALSE); | ||
763 | gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, TRUE); | ||
764 | } | ||
765 | { | ||
766 | LLGLDepthTest gls_depth(GL_FALSE); | ||
767 | gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, FALSE); | ||
768 | gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, TRUE); | ||
769 | } | ||
770 | } | ||
771 | |||
772 | void LLManipRotate::renderSnapGuides() | ||
773 | { | ||
774 | LLVector3 grid_origin; | ||
775 | LLVector3 grid_scale; | ||
776 | LLQuaternion grid_rotation; | ||
777 | LLVector3 constraint_axis = getConstraintAxis(); | ||
778 | |||
779 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
780 | |||
781 | if (!gSavedSettings.getBOOL("SnapEnabled")) | ||
782 | { | ||
783 | return; | ||
784 | } | ||
785 | |||
786 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
787 | LLVector3 cam_at_axis; | ||
788 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
789 | { | ||
790 | cam_at_axis.setVec(1.f, 0.f, 0.f); | ||
791 | } | ||
792 | else | ||
793 | { | ||
794 | cam_at_axis = center - gAgent.getCameraPositionAgent(); | ||
795 | cam_at_axis.normVec(); | ||
796 | } | ||
797 | |||
798 | LLVector3 world_snap_axis; | ||
799 | LLVector3 test_axis = constraint_axis; | ||
800 | |||
801 | BOOL constrain_to_ref_object = FALSE; | ||
802 | if (gSelectMgr->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject()) | ||
803 | { | ||
804 | test_axis = test_axis * ~grid_rotation; | ||
805 | } | ||
806 | else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT) | ||
807 | { | ||
808 | test_axis = test_axis * ~grid_rotation; | ||
809 | constrain_to_ref_object = TRUE; | ||
810 | } | ||
811 | |||
812 | test_axis.abs(); | ||
813 | |||
814 | // find closest global/reference axis to local constraint axis; | ||
815 | if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ]) | ||
816 | { | ||
817 | world_snap_axis = LLVector3::y_axis; | ||
818 | } | ||
819 | else if (test_axis.mV[VY] > test_axis.mV[VZ]) | ||
820 | { | ||
821 | world_snap_axis = LLVector3::z_axis; | ||
822 | } | ||
823 | else | ||
824 | { | ||
825 | world_snap_axis = LLVector3::x_axis; | ||
826 | } | ||
827 | |||
828 | LLVector3 projected_snap_axis = world_snap_axis; | ||
829 | if (gSelectMgr->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject()) | ||
830 | { | ||
831 | projected_snap_axis = projected_snap_axis * grid_rotation; | ||
832 | } | ||
833 | else if (constrain_to_ref_object) | ||
834 | { | ||
835 | projected_snap_axis = projected_snap_axis * grid_rotation; | ||
836 | } | ||
837 | |||
838 | // project world snap axis onto constraint plane | ||
839 | projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis); | ||
840 | projected_snap_axis.normVec(); | ||
841 | |||
842 | S32 num_rings = mCamEdgeOn ? 2 : 1; | ||
843 | for (S32 ring_num = 0; ring_num < num_rings; ring_num++) | ||
844 | { | ||
845 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
846 | |||
847 | if (mCamEdgeOn) | ||
848 | { | ||
849 | // draw two opposing rings | ||
850 | if (ring_num == 0) | ||
851 | { | ||
852 | center += constraint_axis * mRadiusMeters * 0.5f; | ||
853 | } | ||
854 | else | ||
855 | { | ||
856 | center -= constraint_axis * mRadiusMeters * 0.5f; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | LLGLDepthTest gls_depth(GL_FALSE); | ||
861 | for (S32 pass = 0; pass < 3; pass++) | ||
862 | { | ||
863 | // render snap guide ring | ||
864 | glPushMatrix(); | ||
865 | |||
866 | LLQuaternion snap_guide_rot; | ||
867 | F32 angle_radians, x, y, z; | ||
868 | snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis()); | ||
869 | snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z); | ||
870 | glTranslatef(center.mV[VX], center.mV[VY], center.mV[VZ]); | ||
871 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
872 | |||
873 | LLColor4 line_color = setupSnapGuideRenderPass(pass); | ||
874 | |||
875 | glColor4fv(line_color.mV); | ||
876 | |||
877 | if (mCamEdgeOn) | ||
878 | { | ||
879 | // render an arc | ||
880 | LLVector3 edge_normal = cam_at_axis % constraint_axis; | ||
881 | edge_normal.normVec(); | ||
882 | LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot; | ||
883 | LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot; | ||
884 | |||
885 | F32 end_angle = atan2(y_axis_snap * edge_normal, x_axis_snap * edge_normal); | ||
886 | //F32 start_angle = angle_between((-1.f * LLVector3::x_axis) * snap_guide_rot, edge_normal); | ||
887 | F32 start_angle = end_angle - F_PI; | ||
888 | gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE, start_angle, end_angle); | ||
889 | } | ||
890 | else | ||
891 | { | ||
892 | gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE); | ||
893 | } | ||
894 | glPopMatrix(); | ||
895 | |||
896 | for (S32 i = 0; i < 64; i++) | ||
897 | { | ||
898 | BOOL render_text = TRUE; | ||
899 | F32 deg = 5.625f * (F32)i; | ||
900 | LLVector3 inner_point; | ||
901 | LLVector3 outer_point; | ||
902 | LLVector3 text_point; | ||
903 | LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis); | ||
904 | glBegin(GL_LINES); | ||
905 | { | ||
906 | inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center; | ||
907 | F32 tick_length = 0.f; | ||
908 | if (i % 16 == 0) | ||
909 | { | ||
910 | tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS); | ||
911 | } | ||
912 | else if (i % 8 == 0) | ||
913 | { | ||
914 | tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS); | ||
915 | } | ||
916 | else if (i % 4 == 0) | ||
917 | { | ||
918 | tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS); | ||
919 | } | ||
920 | else if (i % 2 == 0) | ||
921 | { | ||
922 | tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS); | ||
923 | } | ||
924 | else | ||
925 | { | ||
926 | tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS); | ||
927 | } | ||
928 | |||
929 | if (mCamEdgeOn) | ||
930 | { | ||
931 | // don't draw ticks that are on back side of circle | ||
932 | F32 dot = cam_at_axis * (projected_snap_axis * rot); | ||
933 | if (dot > 0.f) | ||
934 | { | ||
935 | outer_point = inner_point; | ||
936 | render_text = FALSE; | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | if (ring_num == 0) | ||
941 | { | ||
942 | outer_point = inner_point + (constraint_axis * tick_length) * rot; | ||
943 | } | ||
944 | else | ||
945 | { | ||
946 | outer_point = inner_point - (constraint_axis * tick_length) * rot; | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | else | ||
951 | { | ||
952 | outer_point = inner_point + (projected_snap_axis * tick_length) * rot; | ||
953 | } | ||
954 | |||
955 | text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot; | ||
956 | |||
957 | glVertex3fv(inner_point.mV); | ||
958 | glVertex3fv(outer_point.mV); | ||
959 | } | ||
960 | glEnd(); | ||
961 | |||
962 | //RN: text rendering does own shadow pass, so only render once | ||
963 | if (pass == 1 && render_text && i % 16 == 0) | ||
964 | { | ||
965 | if (world_snap_axis.mV[VX]) | ||
966 | { | ||
967 | if (i == 0) | ||
968 | { | ||
969 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Forward" : "East", LLColor4::white); | ||
970 | } | ||
971 | else if (i == 16) | ||
972 | { | ||
973 | if (constraint_axis.mV[VZ] > 0.f) | ||
974 | { | ||
975 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Left" : "North", LLColor4::white); | ||
976 | } | ||
977 | else | ||
978 | { | ||
979 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Right" : "South", LLColor4::white); | ||
980 | } | ||
981 | } | ||
982 | else if (i == 32) | ||
983 | { | ||
984 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Back" : "West", LLColor4::white); | ||
985 | } | ||
986 | else | ||
987 | { | ||
988 | if (constraint_axis.mV[VZ] > 0.f) | ||
989 | { | ||
990 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Right" : "South", LLColor4::white); | ||
991 | } | ||
992 | else | ||
993 | { | ||
994 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Left" : "North", LLColor4::white); | ||
995 | } | ||
996 | } | ||
997 | } | ||
998 | else if (world_snap_axis.mV[VY]) | ||
999 | { | ||
1000 | if (i == 0) | ||
1001 | { | ||
1002 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Left" : "North", LLColor4::white); | ||
1003 | } | ||
1004 | else if (i == 16) | ||
1005 | { | ||
1006 | if (constraint_axis.mV[VX] > 0.f) | ||
1007 | { | ||
1008 | renderTickText(text_point, "Up", LLColor4::white); | ||
1009 | } | ||
1010 | else | ||
1011 | { | ||
1012 | renderTickText(text_point, "Down", LLColor4::white); | ||
1013 | } | ||
1014 | } | ||
1015 | else if (i == 32) | ||
1016 | { | ||
1017 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Right" : "South", LLColor4::white); | ||
1018 | } | ||
1019 | else | ||
1020 | { | ||
1021 | if (constraint_axis.mV[VX] > 0.f) | ||
1022 | { | ||
1023 | renderTickText(text_point, "Down", LLColor4::white); | ||
1024 | } | ||
1025 | else | ||
1026 | { | ||
1027 | renderTickText(text_point, "Up", LLColor4::white); | ||
1028 | } | ||
1029 | } | ||
1030 | } | ||
1031 | else if (world_snap_axis.mV[VZ]) | ||
1032 | { | ||
1033 | if (i == 0) | ||
1034 | { | ||
1035 | renderTickText(text_point, "Up", LLColor4::white); | ||
1036 | } | ||
1037 | else if (i == 16) | ||
1038 | { | ||
1039 | if (constraint_axis.mV[VY] > 0.f) | ||
1040 | { | ||
1041 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Forward" : "East", LLColor4::white); | ||
1042 | } | ||
1043 | else | ||
1044 | { | ||
1045 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Back" : "West", LLColor4::white); | ||
1046 | } | ||
1047 | } | ||
1048 | else if (i == 32) | ||
1049 | { | ||
1050 | renderTickText(text_point, "Down", LLColor4::white); | ||
1051 | } | ||
1052 | else | ||
1053 | { | ||
1054 | if (constraint_axis.mV[VY] > 0.f) | ||
1055 | { | ||
1056 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Back" : "West", LLColor4::white); | ||
1057 | } | ||
1058 | else | ||
1059 | { | ||
1060 | renderTickText(text_point, gSelectMgr->selectionIsAttachment() ? "Forward" : "East", LLColor4::white); | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
1064 | } | ||
1065 | glColor4fv(line_color.mV); | ||
1066 | } | ||
1067 | |||
1068 | // now render projected object axis | ||
1069 | if (mInSnapRegime) | ||
1070 | { | ||
1071 | LLVector3 object_axis; | ||
1072 | getObjectAxisClosestToMouse(object_axis); | ||
1073 | |||
1074 | // project onto constraint plane | ||
1075 | LLSelectNode* first_node = gSelectMgr->getFirstMoveableNode(TRUE); | ||
1076 | object_axis = object_axis * first_node->getObject()->getRenderRotation(); | ||
1077 | object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); | ||
1078 | object_axis.normVec(); | ||
1079 | object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center; | ||
1080 | LLVector3 line_start = center; | ||
1081 | |||
1082 | glBegin(GL_LINES); | ||
1083 | { | ||
1084 | glVertex3fv(line_start.mV); | ||
1085 | glVertex3fv(object_axis.mV); | ||
1086 | } | ||
1087 | glEnd(); | ||
1088 | |||
1089 | // draw snap guide arrow | ||
1090 | glBegin(GL_TRIANGLES); | ||
1091 | { | ||
1092 | LLVector3 arrow_dir; | ||
1093 | LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis(); | ||
1094 | arrow_span.normVec(); | ||
1095 | |||
1096 | arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start; | ||
1097 | arrow_dir.normVec(); | ||
1098 | if (ring_num == 1) | ||
1099 | { | ||
1100 | arrow_dir *= -1.f; | ||
1101 | } | ||
1102 | glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV); | ||
1103 | glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV); | ||
1104 | glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV); | ||
1105 | } | ||
1106 | glEnd(); | ||
1107 | |||
1108 | { | ||
1109 | LLGLDepthTest gls_depth(GL_TRUE); | ||
1110 | glBegin(GL_LINES); | ||
1111 | { | ||
1112 | glVertex3fv(line_start.mV); | ||
1113 | glVertex3fv(object_axis.mV); | ||
1114 | } | ||
1115 | glEnd(); | ||
1116 | |||
1117 | // draw snap guide arrow | ||
1118 | glBegin(GL_TRIANGLES); | ||
1119 | { | ||
1120 | LLVector3 arrow_dir; | ||
1121 | LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis(); | ||
1122 | arrow_span.normVec(); | ||
1123 | |||
1124 | arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start; | ||
1125 | arrow_dir.normVec(); | ||
1126 | if (ring_num == 1) | ||
1127 | { | ||
1128 | arrow_dir *= -1.f; | ||
1129 | } | ||
1130 | |||
1131 | glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV); | ||
1132 | glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV); | ||
1133 | glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV); | ||
1134 | } | ||
1135 | glEnd(); | ||
1136 | } | ||
1137 | } | ||
1138 | } | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | // Returns TRUE if center of sphere is visible. Also sets a bunch of member variables that are used later (e.g. mCenterToCam) | ||
1143 | BOOL LLManipRotate::updateVisiblity() | ||
1144 | { | ||
1145 | // Don't want to recalculate the center of the selection during a drag. | ||
1146 | // Due to packet delays, sometimes half the objects in the selection have their | ||
1147 | // new position and half have their old one. This creates subtle errors in the | ||
1148 | // computed center position for that frame. Unfortunately, these errors | ||
1149 | // accumulate. The result is objects seem to "fly apart" during rotations. | ||
1150 | // JC - 03.26.2002 | ||
1151 | if (!hasMouseCapture()) | ||
1152 | { | ||
1153 | mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() );//gSelectMgr->getSelectionCenterGlobal(); | ||
1154 | } | ||
1155 | |||
1156 | BOOL visible = FALSE; | ||
1157 | |||
1158 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
1159 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1160 | { | ||
1161 | mCenterToCam = LLVector3(-1.f / gAgent.getAvatarObject()->mHUDCurZoom, 0.f, 0.f); | ||
1162 | mCenterToCamNorm = mCenterToCam; | ||
1163 | mCenterToCamMag = mCenterToCamNorm.normVec(); | ||
1164 | |||
1165 | mRadiusMeters = RADIUS_PIXELS / (F32) gCamera->getViewHeightInPixels(); | ||
1166 | mRadiusMeters /= gAgent.getAvatarObject()->mHUDCurZoom; | ||
1167 | |||
1168 | mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag; | ||
1169 | mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm; | ||
1170 | |||
1171 | mCenterScreen.set((S32)((0.5f - mRotationCenter.mdV[VY]) / gAgent.getAvatarObject()->mHUDCurZoom * gViewerWindow->getWindowWidth()), | ||
1172 | (S32)((mRotationCenter.mdV[VZ] + 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom * gViewerWindow->getWindowHeight())); | ||
1173 | visible = TRUE; | ||
1174 | } | ||
1175 | else | ||
1176 | { | ||
1177 | visible = gCamera->projectPosAgentToScreen(center, mCenterScreen ); | ||
1178 | if( visible ) | ||
1179 | { | ||
1180 | mCenterToCam = gAgent.getCameraPositionAgent() - center; | ||
1181 | mCenterToCamNorm = mCenterToCam; | ||
1182 | mCenterToCamMag = mCenterToCamNorm.normVec(); | ||
1183 | LLVector3 cameraAtAxis = gCamera->getAtAxis(); | ||
1184 | cameraAtAxis.normVec(); | ||
1185 | |||
1186 | F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis); | ||
1187 | |||
1188 | // Don't drag manip if object too far away | ||
1189 | if (gSavedSettings.getBOOL("LimitSelectDistance")) | ||
1190 | { | ||
1191 | F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance"); | ||
1192 | if (dist_vec(gAgent.getPositionAgent(), center) > max_select_distance) | ||
1193 | { | ||
1194 | visible = FALSE; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | if (mCenterToCamMag > 0.001f) | ||
1199 | { | ||
1200 | F32 fraction_of_fov = RADIUS_PIXELS / (F32) gCamera->getViewHeightInPixels(); | ||
1201 | F32 apparent_angle = fraction_of_fov * gCamera->getView(); // radians | ||
1202 | mRadiusMeters = z_dist * tan(apparent_angle); | ||
1203 | |||
1204 | mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag; | ||
1205 | mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm; | ||
1206 | } | ||
1207 | else | ||
1208 | { | ||
1209 | visible = FALSE; | ||
1210 | } | ||
1211 | } | ||
1212 | } | ||
1213 | |||
1214 | mCamEdgeOn = FALSE; | ||
1215 | F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f; | ||
1216 | if( axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE ) | ||
1217 | { | ||
1218 | mCamEdgeOn = TRUE; | ||
1219 | } | ||
1220 | |||
1221 | return visible; | ||
1222 | } | ||
1223 | |||
1224 | LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y ) | ||
1225 | { | ||
1226 | LLVector3 cam = gAgent.getCameraPositionAgent(); | ||
1227 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
1228 | |||
1229 | mMouseCur = intersectMouseWithSphere( x, y, center, mRadiusMeters); | ||
1230 | |||
1231 | F32 delta_x = (F32)(mCenterScreen.mX - x); | ||
1232 | F32 delta_y = (F32)(mCenterScreen.mY - y); | ||
1233 | |||
1234 | F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y); | ||
1235 | |||
1236 | LLVector3 axis = mMouseDown % mMouseCur; | ||
1237 | axis.normVec(); | ||
1238 | F32 angle = acos(mMouseDown * mMouseCur); | ||
1239 | LLQuaternion sphere_rot( angle, axis ); | ||
1240 | |||
1241 | if (is_approx_zero(1.f - mMouseDown * mMouseCur)) | ||
1242 | { | ||
1243 | return LLQuaternion::DEFAULT; | ||
1244 | } | ||
1245 | else if (dist_from_sphere_center < RADIUS_PIXELS) | ||
1246 | { | ||
1247 | return sphere_rot; | ||
1248 | } | ||
1249 | else | ||
1250 | { | ||
1251 | LLVector3 intersection; | ||
1252 | getMousePointOnPlaneAgent( intersection, x, y, center + mCenterToProfilePlane, mCenterToCamNorm ); | ||
1253 | |||
1254 | // amount dragging in sphere from center to periphery would rotate object | ||
1255 | F32 in_sphere_angle = F_PI_BY_TWO; | ||
1256 | F32 dist_to_tangent_point = mRadiusMeters; | ||
1257 | if( !is_approx_zero( mCenterToProfilePlaneMag ) ) | ||
1258 | { | ||
1259 | dist_to_tangent_point = sqrt( mRadiusMeters * mRadiusMeters - mCenterToProfilePlaneMag * mCenterToProfilePlaneMag ); | ||
1260 | in_sphere_angle = atan2( dist_to_tangent_point, mCenterToProfilePlaneMag ); | ||
1261 | } | ||
1262 | |||
1263 | LLVector3 profile_center_to_intersection = intersection - (center + mCenterToProfilePlane); | ||
1264 | F32 dist_to_intersection = profile_center_to_intersection.normVec(); | ||
1265 | F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) * in_sphere_angle; | ||
1266 | |||
1267 | LLVector3 axis; | ||
1268 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1269 | { | ||
1270 | axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection; | ||
1271 | } | ||
1272 | else | ||
1273 | { | ||
1274 | axis = (cam - center) % profile_center_to_intersection; | ||
1275 | axis.normVec(); | ||
1276 | } | ||
1277 | return sphere_rot * LLQuaternion( angle, axis ); | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | LLVector3 LLManipRotate::getConstraintAxis() | ||
1282 | { | ||
1283 | LLVector3 axis; | ||
1284 | if( LL_ROT_ROLL == mManipPart ) | ||
1285 | { | ||
1286 | axis = mCenterToCamNorm; | ||
1287 | } | ||
1288 | else | ||
1289 | { | ||
1290 | S32 axis_dir = mManipPart - LL_ROT_X; | ||
1291 | if ((axis_dir >= 0) && (axis_dir < 3)) | ||
1292 | { | ||
1293 | axis.mV[axis_dir] = 1.f; | ||
1294 | } | ||
1295 | else | ||
1296 | { | ||
1297 | #ifndef LL_RELEASE_FOR_DOWNLOAD | ||
1298 | llerrs << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl | ||
1299 | #else | ||
1300 | llwarns << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl | ||
1301 | #endif | ||
1302 | axis.mV[0] = 1.f; | ||
1303 | } | ||
1304 | |||
1305 | LLVector3 grid_origin; | ||
1306 | LLVector3 grid_scale; | ||
1307 | LLQuaternion grid_rotation; | ||
1308 | |||
1309 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1310 | |||
1311 | LLSelectNode* first_node = gSelectMgr->getFirstMoveableNode(TRUE); | ||
1312 | if (first_node) | ||
1313 | { | ||
1314 | // *FIX: get agent local attachment grid working | ||
1315 | // Put rotation into frame of first selected root object | ||
1316 | axis = axis * grid_rotation; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | return axis; | ||
1321 | } | ||
1322 | |||
1323 | LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) | ||
1324 | { | ||
1325 | LLSelectNode* first_object_node = gSelectMgr->getFirstMoveableNode(TRUE); | ||
1326 | LLVector3 constraint_axis = getConstraintAxis(); | ||
1327 | LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); | ||
1328 | |||
1329 | F32 angle = 0.f; | ||
1330 | |||
1331 | // build snap axes | ||
1332 | LLVector3 grid_origin; | ||
1333 | LLVector3 grid_scale; | ||
1334 | LLQuaternion grid_rotation; | ||
1335 | |||
1336 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1337 | |||
1338 | LLVector3 axis1; | ||
1339 | LLVector3 axis2; | ||
1340 | |||
1341 | LLVector3 test_axis = constraint_axis; | ||
1342 | if (gSelectMgr->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject()) | ||
1343 | { | ||
1344 | test_axis = test_axis * ~grid_rotation; | ||
1345 | } | ||
1346 | else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT) | ||
1347 | { | ||
1348 | test_axis = test_axis * ~grid_rotation; | ||
1349 | } | ||
1350 | test_axis.abs(); | ||
1351 | |||
1352 | // find closest global axis to constraint axis; | ||
1353 | if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ]) | ||
1354 | { | ||
1355 | axis1 = LLVector3::y_axis; | ||
1356 | } | ||
1357 | else if (test_axis.mV[VY] > test_axis.mV[VZ]) | ||
1358 | { | ||
1359 | axis1 = LLVector3::z_axis; | ||
1360 | } | ||
1361 | else | ||
1362 | { | ||
1363 | axis1 = LLVector3::x_axis; | ||
1364 | } | ||
1365 | |||
1366 | if (gSelectMgr->getSelectType() == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject()) | ||
1367 | { | ||
1368 | axis1 = axis1 * grid_rotation; | ||
1369 | } | ||
1370 | else if (gSelectMgr->getGridMode() == GRID_MODE_REF_OBJECT) | ||
1371 | { | ||
1372 | axis1 = axis1 * grid_rotation; | ||
1373 | } | ||
1374 | |||
1375 | //project axis onto constraint plane | ||
1376 | axis1 -= (axis1 * constraint_axis) * constraint_axis; | ||
1377 | axis1.normVec(); | ||
1378 | |||
1379 | // calculate third and final axis | ||
1380 | axis2 = constraint_axis % axis1; | ||
1381 | |||
1382 | //F32 axis_onto_cam = llabs( constraint_axis * mCenterToCamNorm ); | ||
1383 | if( mCamEdgeOn ) | ||
1384 | { | ||
1385 | // We're looking at the ring edge-on. | ||
1386 | LLVector3 snap_plane_center = (center + (constraint_axis * mRadiusMeters * 0.5f)); | ||
1387 | LLVector3 cam_to_snap_plane; | ||
1388 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1389 | { | ||
1390 | cam_to_snap_plane.setVec(1.f, 0.f, 0.f); | ||
1391 | } | ||
1392 | else | ||
1393 | { | ||
1394 | cam_to_snap_plane = snap_plane_center - gAgent.getCameraPositionAgent(); | ||
1395 | cam_to_snap_plane.normVec(); | ||
1396 | } | ||
1397 | |||
1398 | LLVector3 projected_mouse; | ||
1399 | BOOL hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); | ||
1400 | projected_mouse -= snap_plane_center; | ||
1401 | |||
1402 | S32 snap_plane = 0; | ||
1403 | |||
1404 | F32 dot = cam_to_snap_plane * constraint_axis; | ||
1405 | if (llabs(dot) < 0.01f) | ||
1406 | { | ||
1407 | // looking at ring edge on, project onto view plane and check if mouse is past ring | ||
1408 | getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); | ||
1409 | projected_mouse -= snap_plane_center; | ||
1410 | dot = projected_mouse * constraint_axis; | ||
1411 | if (projected_mouse * constraint_axis > 0) | ||
1412 | { | ||
1413 | snap_plane = 1; | ||
1414 | } | ||
1415 | projected_mouse -= dot * constraint_axis; | ||
1416 | } | ||
1417 | else if (dot > 0.f) | ||
1418 | { | ||
1419 | // look for mouse position outside and in front of snap circle | ||
1420 | if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) | ||
1421 | { | ||
1422 | snap_plane = 1; | ||
1423 | } | ||
1424 | } | ||
1425 | else | ||
1426 | { | ||
1427 | // look for mouse position inside or in back of snap circle | ||
1428 | if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) | ||
1429 | { | ||
1430 | snap_plane = 1; | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | if (snap_plane == 0) | ||
1435 | { | ||
1436 | // try other plane | ||
1437 | snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f)); | ||
1438 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1439 | { | ||
1440 | cam_to_snap_plane.setVec(1.f, 0.f, 0.f); | ||
1441 | } | ||
1442 | else | ||
1443 | { | ||
1444 | cam_to_snap_plane = snap_plane_center - gAgent.getCameraPositionAgent(); | ||
1445 | cam_to_snap_plane.normVec(); | ||
1446 | } | ||
1447 | |||
1448 | hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); | ||
1449 | projected_mouse -= snap_plane_center; | ||
1450 | |||
1451 | dot = cam_to_snap_plane * constraint_axis; | ||
1452 | if (llabs(dot) < 0.01f) | ||
1453 | { | ||
1454 | // looking at ring edge on, project onto view plane and check if mouse is past ring | ||
1455 | getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); | ||
1456 | projected_mouse -= snap_plane_center; | ||
1457 | dot = projected_mouse * constraint_axis; | ||
1458 | if (projected_mouse * constraint_axis < 0) | ||
1459 | { | ||
1460 | snap_plane = 2; | ||
1461 | } | ||
1462 | projected_mouse -= dot * constraint_axis; | ||
1463 | } | ||
1464 | else if (dot < 0.f) | ||
1465 | { | ||
1466 | // look for mouse position outside and in front of snap circle | ||
1467 | if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) | ||
1468 | { | ||
1469 | snap_plane = 2; | ||
1470 | } | ||
1471 | } | ||
1472 | else | ||
1473 | { | ||
1474 | // look for mouse position inside or in back of snap circle | ||
1475 | if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) | ||
1476 | { | ||
1477 | snap_plane = 2; | ||
1478 | } | ||
1479 | } | ||
1480 | } | ||
1481 | |||
1482 | if (snap_plane > 0) | ||
1483 | { | ||
1484 | LLVector3 cam_at_axis; | ||
1485 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1486 | { | ||
1487 | cam_at_axis.setVec(1.f, 0.f, 0.f); | ||
1488 | } | ||
1489 | else | ||
1490 | { | ||
1491 | cam_at_axis = snap_plane_center - gAgent.getCameraPositionAgent(); | ||
1492 | cam_at_axis.normVec(); | ||
1493 | } | ||
1494 | |||
1495 | // first, project mouse onto screen plane at point tangent to rotation radius. | ||
1496 | getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis); | ||
1497 | // project that point onto rotation plane | ||
1498 | projected_mouse -= snap_plane_center; | ||
1499 | projected_mouse -= projected_vec(projected_mouse, constraint_axis); | ||
1500 | |||
1501 | F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec()); | ||
1502 | F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; | ||
1503 | if (llabs(mouse_lateral_dist) > 0.01f) | ||
1504 | { | ||
1505 | mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - | ||
1506 | (mouse_lateral_dist * mouse_lateral_dist)); | ||
1507 | } | ||
1508 | LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis); | ||
1509 | projected_mouse -= mouse_depth * projected_camera_at; | ||
1510 | |||
1511 | if (!mInSnapRegime) | ||
1512 | { | ||
1513 | mSmoothRotate = TRUE; | ||
1514 | } | ||
1515 | mInSnapRegime = TRUE; | ||
1516 | // 0 to 360 deg | ||
1517 | F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); | ||
1518 | |||
1519 | F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); | ||
1520 | //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); | ||
1521 | |||
1522 | LLVector3 object_axis; | ||
1523 | getObjectAxisClosestToMouse(object_axis); | ||
1524 | object_axis = object_axis * first_object_node->mSavedRotation; | ||
1525 | |||
1526 | // project onto constraint plane | ||
1527 | object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); | ||
1528 | object_axis.normVec(); | ||
1529 | |||
1530 | if (relative_mouse_angle < SNAP_ANGLE_DETENTE) | ||
1531 | { | ||
1532 | F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); | ||
1533 | angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); | ||
1534 | } | ||
1535 | else | ||
1536 | { | ||
1537 | angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); | ||
1538 | } | ||
1539 | return LLQuaternion( -angle, constraint_axis ); | ||
1540 | } | ||
1541 | else | ||
1542 | { | ||
1543 | if (mInSnapRegime) | ||
1544 | { | ||
1545 | mSmoothRotate = TRUE; | ||
1546 | } | ||
1547 | mInSnapRegime = FALSE; | ||
1548 | |||
1549 | LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis; | ||
1550 | up_from_axis.normVec(); | ||
1551 | LLVector3 cur_intersection; | ||
1552 | getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam); | ||
1553 | cur_intersection -= center; | ||
1554 | mMouseCur = projected_vec(cur_intersection, up_from_axis); | ||
1555 | F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; | ||
1556 | F32 mouse_dist_sqrd = mMouseCur.magVecSquared(); | ||
1557 | if (mouse_dist_sqrd > 0.0001f) | ||
1558 | { | ||
1559 | mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - | ||
1560 | mouse_dist_sqrd); | ||
1561 | } | ||
1562 | LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, constraint_axis); | ||
1563 | mMouseCur += mouse_depth * projected_center_to_cam; | ||
1564 | |||
1565 | F32 dist = (cur_intersection * up_from_axis) - (mMouseDown * up_from_axis); | ||
1566 | angle = dist / (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * -F_PI_BY_TWO; | ||
1567 | } | ||
1568 | } | ||
1569 | else | ||
1570 | { | ||
1571 | LLVector3 projected_mouse; | ||
1572 | getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis); | ||
1573 | projected_mouse -= center; | ||
1574 | mMouseCur = projected_mouse; | ||
1575 | mMouseCur.normVec(); | ||
1576 | |||
1577 | if (!first_object_node) | ||
1578 | { | ||
1579 | return LLQuaternion::DEFAULT; | ||
1580 | } | ||
1581 | |||
1582 | if (gSavedSettings.getBOOL("SnapEnabled") && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) | ||
1583 | { | ||
1584 | if (!mInSnapRegime) | ||
1585 | { | ||
1586 | mSmoothRotate = TRUE; | ||
1587 | } | ||
1588 | mInSnapRegime = TRUE; | ||
1589 | // 0 to 360 deg | ||
1590 | F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); | ||
1591 | |||
1592 | F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); | ||
1593 | //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); | ||
1594 | |||
1595 | LLVector3 object_axis; | ||
1596 | getObjectAxisClosestToMouse(object_axis); | ||
1597 | object_axis = object_axis * first_object_node->mSavedRotation; | ||
1598 | |||
1599 | // project onto constraint plane | ||
1600 | object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); | ||
1601 | object_axis.normVec(); | ||
1602 | |||
1603 | if (relative_mouse_angle < SNAP_ANGLE_DETENTE) | ||
1604 | { | ||
1605 | F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); | ||
1606 | angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); | ||
1607 | } | ||
1608 | else | ||
1609 | { | ||
1610 | angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); | ||
1611 | } | ||
1612 | return LLQuaternion( -angle, constraint_axis ); | ||
1613 | } | ||
1614 | else | ||
1615 | { | ||
1616 | if (mInSnapRegime) | ||
1617 | { | ||
1618 | mSmoothRotate = TRUE; | ||
1619 | } | ||
1620 | mInSnapRegime = FALSE; | ||
1621 | } | ||
1622 | |||
1623 | angle = acos(mMouseCur * mMouseDown); | ||
1624 | |||
1625 | F32 dir = (mMouseDown % mMouseCur) * constraint_axis; // cross product | ||
1626 | if( dir < 0.f ) | ||
1627 | { | ||
1628 | angle *= -1.f; | ||
1629 | } | ||
1630 | } | ||
1631 | |||
1632 | F32 rot_step = gSavedSettings.getF32("RotationStep"); | ||
1633 | F32 step_size = DEG_TO_RAD * rot_step; | ||
1634 | angle -= fmod(angle, step_size); | ||
1635 | |||
1636 | return LLQuaternion( angle, constraint_axis ); | ||
1637 | } | ||
1638 | |||
1639 | |||
1640 | |||
1641 | LLVector3 LLManipRotate::intersectMouseWithSphere( S32 x, S32 y, const LLVector3& sphere_center, F32 sphere_radius) | ||
1642 | { | ||
1643 | LLVector3 ray_pt; | ||
1644 | LLVector3 ray_dir; | ||
1645 | mouseToRay( x, y, &ray_pt, &ray_dir); | ||
1646 | return intersectRayWithSphere( ray_pt, ray_dir, sphere_center, sphere_radius ); | ||
1647 | } | ||
1648 | |||
1649 | LLVector3 LLManipRotate::intersectRayWithSphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius) | ||
1650 | { | ||
1651 | LLVector3 ray_pt_to_center = sphere_center - ray_pt; | ||
1652 | F32 center_distance = ray_pt_to_center.normVec(); | ||
1653 | |||
1654 | F32 dot = ray_dir * ray_pt_to_center; | ||
1655 | |||
1656 | if (dot == 0.f) | ||
1657 | { | ||
1658 | return LLVector3::zero; | ||
1659 | } | ||
1660 | |||
1661 | // point which ray hits plane centered on sphere origin, facing ray origin | ||
1662 | LLVector3 intersection_sphere_plane = ray_pt + (ray_dir * center_distance / dot); | ||
1663 | // vector from sphere origin to the point, normalized to sphere radius | ||
1664 | LLVector3 sphere_center_to_intersection = (intersection_sphere_plane - sphere_center) / sphere_radius; | ||
1665 | |||
1666 | F32 dist_squared = sphere_center_to_intersection.magVecSquared(); | ||
1667 | LLVector3 result; | ||
1668 | |||
1669 | if (dist_squared > 1.f) | ||
1670 | { | ||
1671 | result = sphere_center_to_intersection; | ||
1672 | result.normVec(); | ||
1673 | } | ||
1674 | else | ||
1675 | { | ||
1676 | result = sphere_center_to_intersection - ray_dir * sqrt(1.f - dist_squared); | ||
1677 | } | ||
1678 | |||
1679 | return result; | ||
1680 | } | ||
1681 | |||
1682 | // Utility function. Should probably be moved to another class. | ||
1683 | void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_dir ) | ||
1684 | { | ||
1685 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1686 | { | ||
1687 | F32 mouse_x = (((F32)x / gViewerWindow->getWindowWidth()) - 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom; | ||
1688 | F32 mouse_y = ((((F32)y) / gViewerWindow->getWindowHeight()) - 0.5f) / gAgent.getAvatarObject()->mHUDCurZoom; | ||
1689 | |||
1690 | *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y); | ||
1691 | *ray_dir = LLVector3(1.f, 0.f, 0.f); | ||
1692 | } | ||
1693 | else | ||
1694 | { | ||
1695 | *ray_pt = gAgent.getCameraPositionAgent(); | ||
1696 | gCamera->projectScreenToPosAgent(x, y, ray_dir); | ||
1697 | *ray_dir -= *ray_pt; | ||
1698 | ray_dir->normVec(); | ||
1699 | } | ||
1700 | } | ||
1701 | |||
1702 | void LLManipRotate::highlightManipulators( S32 x, S32 y ) | ||
1703 | { | ||
1704 | mHighlightedPart = LL_NO_PART; | ||
1705 | |||
1706 | //LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
1707 | LLViewerObject *first_object = gSelectMgr->getFirstMoveableObject(TRUE); | ||
1708 | |||
1709 | if (!first_object) | ||
1710 | { | ||
1711 | return; | ||
1712 | } | ||
1713 | |||
1714 | LLQuaternion object_rot = first_object->getRenderRotation(); | ||
1715 | LLVector3 rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter); | ||
1716 | LLVector3 mouse_dir_x; | ||
1717 | LLVector3 mouse_dir_y; | ||
1718 | LLVector3 mouse_dir_z; | ||
1719 | LLVector3 intersection_roll; | ||
1720 | |||
1721 | LLVector3 grid_origin; | ||
1722 | LLVector3 grid_scale; | ||
1723 | LLQuaternion grid_rotation; | ||
1724 | |||
1725 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1726 | |||
1727 | LLVector3 rot_x_axis = LLVector3::x_axis * grid_rotation; | ||
1728 | LLVector3 rot_y_axis = LLVector3::y_axis * grid_rotation; | ||
1729 | LLVector3 rot_z_axis = LLVector3::z_axis * grid_rotation; | ||
1730 | |||
1731 | F32 proj_rot_x_axis = llabs(rot_x_axis * mCenterToCamNorm); | ||
1732 | F32 proj_rot_y_axis = llabs(rot_y_axis * mCenterToCamNorm); | ||
1733 | F32 proj_rot_z_axis = llabs(rot_z_axis * mCenterToCamNorm); | ||
1734 | |||
1735 | F32 min_select_distance = 0.f; | ||
1736 | F32 cur_select_distance = 0.f; | ||
1737 | |||
1738 | // test x | ||
1739 | getMousePointOnPlaneAgent(mouse_dir_x, x, y, rotation_center, rot_x_axis); | ||
1740 | mouse_dir_x -= rotation_center; | ||
1741 | // push intersection point out when working at obtuse angle to make ring easier to hit | ||
1742 | mouse_dir_x *= 1.f + (1.f - llabs(rot_x_axis * mCenterToCamNorm)) * 0.1f; | ||
1743 | |||
1744 | // test y | ||
1745 | getMousePointOnPlaneAgent(mouse_dir_y, x, y, rotation_center, rot_y_axis); | ||
1746 | mouse_dir_y -= rotation_center; | ||
1747 | mouse_dir_y *= 1.f + (1.f - llabs(rot_y_axis * mCenterToCamNorm)) * 0.1f; | ||
1748 | |||
1749 | // test z | ||
1750 | getMousePointOnPlaneAgent(mouse_dir_z, x, y, rotation_center, rot_z_axis); | ||
1751 | mouse_dir_z -= rotation_center; | ||
1752 | mouse_dir_z *= 1.f + (1.f - llabs(rot_z_axis * mCenterToCamNorm)) * 0.1f; | ||
1753 | |||
1754 | // test roll | ||
1755 | getMousePointOnPlaneAgent(intersection_roll, x, y, rotation_center, mCenterToCamNorm); | ||
1756 | intersection_roll -= rotation_center; | ||
1757 | |||
1758 | F32 dist_x = mouse_dir_x.normVec(); | ||
1759 | F32 dist_y = mouse_dir_y.normVec(); | ||
1760 | F32 dist_z = mouse_dir_z.normVec(); | ||
1761 | |||
1762 | F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWindowHeight(); | ||
1763 | |||
1764 | if (llabs(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) < distance_threshold) | ||
1765 | { | ||
1766 | // selected x | ||
1767 | cur_select_distance = dist_x * mouse_dir_x * mCenterToCamNorm; | ||
1768 | if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) | ||
1769 | { | ||
1770 | min_select_distance = cur_select_distance; | ||
1771 | mHighlightedPart = LL_ROT_X; | ||
1772 | } | ||
1773 | } | ||
1774 | if (llabs(dist_y - mRadiusMeters) * llmax(0.05f, proj_rot_y_axis) < distance_threshold) | ||
1775 | { | ||
1776 | // selected y | ||
1777 | cur_select_distance = dist_y * mouse_dir_y * mCenterToCamNorm; | ||
1778 | if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) | ||
1779 | { | ||
1780 | min_select_distance = cur_select_distance; | ||
1781 | mHighlightedPart = LL_ROT_Y; | ||
1782 | } | ||
1783 | } | ||
1784 | if (llabs(dist_z - mRadiusMeters) * llmax(0.05f, proj_rot_z_axis) < distance_threshold) | ||
1785 | { | ||
1786 | // selected z | ||
1787 | cur_select_distance = dist_z * mouse_dir_z * mCenterToCamNorm; | ||
1788 | if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) | ||
1789 | { | ||
1790 | min_select_distance = cur_select_distance; | ||
1791 | mHighlightedPart = LL_ROT_Z; | ||
1792 | } | ||
1793 | } | ||
1794 | |||
1795 | // test for edge-on intersections | ||
1796 | if (proj_rot_x_axis < 0.05f) | ||
1797 | { | ||
1798 | if ((proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_x_axis) < distance_threshold) && dist_y < mRadiusMeters) || | ||
1799 | (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_x_axis) < distance_threshold) && dist_z < mRadiusMeters)) | ||
1800 | { | ||
1801 | mHighlightedPart = LL_ROT_X; | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | if (proj_rot_y_axis < 0.05f) | ||
1806 | { | ||
1807 | if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_y_axis) < distance_threshold) && dist_x < mRadiusMeters) || | ||
1808 | (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_y_axis) < distance_threshold) && dist_z < mRadiusMeters)) | ||
1809 | { | ||
1810 | mHighlightedPart = LL_ROT_Y; | ||
1811 | } | ||
1812 | } | ||
1813 | |||
1814 | if (proj_rot_z_axis < 0.05f) | ||
1815 | { | ||
1816 | if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_z_axis) < distance_threshold) && dist_x < mRadiusMeters) || | ||
1817 | (proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_z_axis) < distance_threshold) && dist_y < mRadiusMeters)) | ||
1818 | { | ||
1819 | mHighlightedPart = LL_ROT_Z; | ||
1820 | } | ||
1821 | } | ||
1822 | |||
1823 | // test for roll | ||
1824 | if (mHighlightedPart == LL_NO_PART) | ||
1825 | { | ||
1826 | F32 roll_distance = intersection_roll.magVec(); | ||
1827 | F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS; | ||
1828 | |||
1829 | // use larger distance threshold for roll as it is checked only if something else wasn't highlighted | ||
1830 | if (llabs(roll_distance - (mRadiusMeters + (width_meters * 2.f))) < distance_threshold * 2.f) | ||
1831 | { | ||
1832 | mHighlightedPart = LL_ROT_ROLL; | ||
1833 | } | ||
1834 | else if (roll_distance < mRadiusMeters) | ||
1835 | { | ||
1836 | mHighlightedPart = LL_ROT_GENERAL; | ||
1837 | } | ||
1838 | } | ||
1839 | } | ||
1840 | |||
1841 | S32 LLManipRotate::getObjectAxisClosestToMouse(LLVector3& object_axis) | ||
1842 | { | ||
1843 | LLSelectNode* first_object_node = gSelectMgr->getFirstMoveableNode(TRUE); | ||
1844 | |||
1845 | if (!first_object_node) | ||
1846 | { | ||
1847 | object_axis.clearVec(); | ||
1848 | return -1; | ||
1849 | } | ||
1850 | |||
1851 | LLQuaternion obj_rotation = first_object_node->mSavedRotation; | ||
1852 | LLVector3 mouse_down_object = mMouseDown * ~obj_rotation; | ||
1853 | LLVector3 mouse_down_abs = mouse_down_object; | ||
1854 | mouse_down_abs.abs(); | ||
1855 | |||
1856 | S32 axis_index = 0; | ||
1857 | if (mouse_down_abs.mV[VX] > mouse_down_abs.mV[VY] && mouse_down_abs.mV[VX] > mouse_down_abs.mV[VZ]) | ||
1858 | { | ||
1859 | if (mouse_down_object.mV[VX] > 0.f) | ||
1860 | { | ||
1861 | object_axis = LLVector3::x_axis; | ||
1862 | } | ||
1863 | else | ||
1864 | { | ||
1865 | object_axis = LLVector3::x_axis_neg; | ||
1866 | } | ||
1867 | axis_index = VX; | ||
1868 | } | ||
1869 | else if (mouse_down_abs.mV[VY] > mouse_down_abs.mV[VZ]) | ||
1870 | { | ||
1871 | if (mouse_down_object.mV[VY] > 0.f) | ||
1872 | { | ||
1873 | object_axis = LLVector3::y_axis; | ||
1874 | } | ||
1875 | else | ||
1876 | { | ||
1877 | object_axis = LLVector3::y_axis_neg; | ||
1878 | } | ||
1879 | axis_index = VY; | ||
1880 | } | ||
1881 | else | ||
1882 | { | ||
1883 | if (mouse_down_object.mV[VZ] > 0.f) | ||
1884 | { | ||
1885 | object_axis = LLVector3::z_axis; | ||
1886 | } | ||
1887 | else | ||
1888 | { | ||
1889 | object_axis = LLVector3::z_axis_neg; | ||
1890 | } | ||
1891 | axis_index = VZ; | ||
1892 | } | ||
1893 | |||
1894 | return axis_index; | ||
1895 | } | ||