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/llmanipscale.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/llmanipscale.cpp')
-rw-r--r-- | linden/indra/newview/llmanipscale.cpp | 2042 |
1 files changed, 2042 insertions, 0 deletions
diff --git a/linden/indra/newview/llmanipscale.cpp b/linden/indra/newview/llmanipscale.cpp new file mode 100644 index 0000000..f143c5a --- /dev/null +++ b/linden/indra/newview/llmanipscale.cpp | |||
@@ -0,0 +1,2042 @@ | |||
1 | /** | ||
2 | * @file llmanipscale.cpp | ||
3 | * @brief LLManipScale class implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-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 "llmanipscale.h" | ||
31 | |||
32 | // library includes | ||
33 | #include "llmath.h" | ||
34 | #include "v3math.h" | ||
35 | #include "llquaternion.h" | ||
36 | #include "llgl.h" | ||
37 | #include "v4color.h" | ||
38 | #include "llprimitive.h" | ||
39 | |||
40 | // viewer includes | ||
41 | #include "llagent.h" | ||
42 | #include "llbbox.h" | ||
43 | #include "llbox.h" | ||
44 | #include "llviewercontrol.h" | ||
45 | #include "llcriticaldamp.h" | ||
46 | #include "llcylinder.h" | ||
47 | #include "lldrawable.h" | ||
48 | #include "llfloatertools.h" | ||
49 | #include "llglheaders.h" | ||
50 | #include "llselectmgr.h" | ||
51 | #include "llstatusbar.h" | ||
52 | #include "llui.h" | ||
53 | #include "llviewercamera.h" | ||
54 | #include "llviewerobject.h" | ||
55 | #include "llviewerwindow.h" | ||
56 | #include "llhudrender.h" | ||
57 | #include "llworld.h" | ||
58 | #include "v2math.h" | ||
59 | #include "llvoavatar.h" | ||
60 | |||
61 | |||
62 | const F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f; | ||
63 | const F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f; | ||
64 | const F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f; | ||
65 | const F32 SELECTED_MANIPULATOR_SCALE = 1.2f; | ||
66 | const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; | ||
67 | const S32 NUM_MANIPULATORS = 14; | ||
68 | |||
69 | const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = | ||
70 | { | ||
71 | LLManip::LL_CORNER_NNN, | ||
72 | LLManip::LL_CORNER_NNP, | ||
73 | LLManip::LL_CORNER_NPN, | ||
74 | LLManip::LL_CORNER_NPP, | ||
75 | LLManip::LL_CORNER_PNN, | ||
76 | LLManip::LL_CORNER_PNP, | ||
77 | LLManip::LL_CORNER_PPN, | ||
78 | LLManip::LL_CORNER_PPP, | ||
79 | LLManip::LL_FACE_POSZ, | ||
80 | LLManip::LL_FACE_POSX, | ||
81 | LLManip::LL_FACE_POSY, | ||
82 | LLManip::LL_FACE_NEGX, | ||
83 | LLManip::LL_FACE_NEGY, | ||
84 | LLManip::LL_FACE_NEGZ | ||
85 | }; | ||
86 | |||
87 | |||
88 | |||
89 | // static | ||
90 | void LLManipScale::setUniform(BOOL b) | ||
91 | { | ||
92 | gSavedSettings.setBOOL("ScaleUniform", b); | ||
93 | } | ||
94 | |||
95 | // static | ||
96 | void LLManipScale::setShowAxes(BOOL b) | ||
97 | { | ||
98 | gSavedSettings.setBOOL("ScaleShowAxes", b); | ||
99 | } | ||
100 | |||
101 | // static | ||
102 | void LLManipScale::setStretchTextures(BOOL b) | ||
103 | { | ||
104 | gSavedSettings.setBOOL("ScaleStretchTextures", b); | ||
105 | } | ||
106 | |||
107 | // static | ||
108 | BOOL LLManipScale::getUniform() | ||
109 | { | ||
110 | return gSavedSettings.getBOOL("ScaleUniform"); | ||
111 | } | ||
112 | |||
113 | // static | ||
114 | BOOL LLManipScale::getShowAxes() | ||
115 | { | ||
116 | return gSavedSettings.getBOOL("ScaleShowAxes"); | ||
117 | } | ||
118 | |||
119 | // static | ||
120 | BOOL LLManipScale::getStretchTextures() | ||
121 | { | ||
122 | return gSavedSettings.getBOOL("ScaleStretchTextures"); | ||
123 | } | ||
124 | |||
125 | inline void LLManipScale::conditionalHighlight( U32 part, const LLColor4* highlight, const LLColor4* normal ) | ||
126 | { | ||
127 | LLColor4 default_highlight( 1.f, 1.f, 1.f, 1.f ); | ||
128 | LLColor4 default_normal( 0.7f, 0.7f, 0.7f, 0.6f ); | ||
129 | LLColor4 invisible(0.f, 0.f, 0.f, 0.f); | ||
130 | F32 manipulator_scale = 1.f; | ||
131 | |||
132 | for (S32 i = 0; i < NUM_MANIPULATORS; i++) | ||
133 | { | ||
134 | if((U32)MANIPULATOR_IDS[i] == part) | ||
135 | { | ||
136 | manipulator_scale = mManipulatorScales[i]; | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale; | ||
142 | if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part) | ||
143 | { | ||
144 | glColor4fv( invisible.mV ); | ||
145 | } | ||
146 | else if( mHighlightedPart == (S32)part ) | ||
147 | { | ||
148 | glColor4fv( highlight ? highlight->mV : default_highlight.mV ); | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | glColor4fv( normal ? normal->mV : default_normal.mV ); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void LLManipScale::handleSelect() | ||
157 | { | ||
158 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
159 | updateSnapGuides(bbox); | ||
160 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
161 | gFloaterTools->setStatusText("Click and drag to stretch selected side"); | ||
162 | } | ||
163 | |||
164 | void LLManipScale::handleDeselect() | ||
165 | { | ||
166 | mHighlightedPart = LL_NO_PART; | ||
167 | mManipPart = LL_NO_PART; | ||
168 | gFloaterTools->setStatusText(""); | ||
169 | } | ||
170 | |||
171 | BOOL sort_manip_by_z(LLManipScale::ManipulatorHandle *new_manip, LLManipScale::ManipulatorHandle *test_manip) | ||
172 | { | ||
173 | return ((new_manip->mType < test_manip->mType) || (new_manip->mPosition.mV[VZ] < test_manip->mPosition.mV[VZ])); | ||
174 | } | ||
175 | |||
176 | LLManipScale::LLManipScale( LLToolComposite* composite ) | ||
177 | : | ||
178 | LLManip( "Scale", composite ), | ||
179 | mBoxHandleSize( 1.f ), | ||
180 | mScaledBoxHandleSize( 1.f ), | ||
181 | mManipPart( LL_NO_PART ), | ||
182 | mHighlightedPart( LL_NO_PART ), | ||
183 | mLastMouseX( -1 ), | ||
184 | mLastMouseY( -1 ), | ||
185 | mSendUpdateOnMouseUp( FALSE ), | ||
186 | mLastUpdateFlags( 0 ), | ||
187 | mScaleSnapUnit1(1.f), | ||
188 | mScaleSnapUnit2(1.f), | ||
189 | mSnapRegimeOffset(0.f), | ||
190 | mSnapGuideLength(0.f), | ||
191 | mScaleSnapValue(0.f) | ||
192 | { | ||
193 | mProjectedManipulators.setInsertBefore(sort_manip_by_z); | ||
194 | mManipulatorScales = new F32[NUM_MANIPULATORS]; | ||
195 | for (S32 i = 0; i < NUM_MANIPULATORS; i++) | ||
196 | { | ||
197 | mManipulatorScales[i] = 1.f; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | LLManipScale::~LLManipScale() | ||
202 | { | ||
203 | delete []mManipulatorScales; | ||
204 | } | ||
205 | |||
206 | void LLManipScale::render() | ||
207 | { | ||
208 | LLGLSUIDefault gls_ui; | ||
209 | LLGLSNoTexture gls_no_texture; | ||
210 | LLGLDepthTest gls_depth(GL_TRUE); | ||
211 | LLGLEnable gl_blend(GL_BLEND); | ||
212 | LLGLEnable gls_alpha_test(GL_ALPHA_TEST); | ||
213 | |||
214 | if( isSelectionScalable() ) | ||
215 | { | ||
216 | glMatrixMode(GL_MODELVIEW); | ||
217 | glPushMatrix(); | ||
218 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
219 | { | ||
220 | F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom; | ||
221 | glScalef(zoom, zoom, zoom); | ||
222 | } | ||
223 | |||
224 | //////////////////////////////////////////////////////////////////////// | ||
225 | // Calculate size of drag handles | ||
226 | |||
227 | const F32 BOX_HANDLE_BASE_SIZE = 50.0f; // box size in pixels = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR | ||
228 | const F32 BOX_HANDLE_BASE_FACTOR = 0.2f; | ||
229 | |||
230 | LLVector3 center_agent = gAgent.getPosAgentFromGlobal(gSelectMgr->getSelectionCenterGlobal()); | ||
231 | |||
232 | F32 range; | ||
233 | F32 range_from_agent; | ||
234 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
235 | { | ||
236 | mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) gCamera->getViewHeightInPixels(); | ||
237 | mBoxHandleSize /= gAgent.getAvatarObject()->mHUDCurZoom; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | range = dist_vec(gAgent.getCameraPositionAgent(), center_agent); | ||
242 | range_from_agent = dist_vec(gAgent.getPositionAgent(), center_agent); | ||
243 | |||
244 | // Don't draw manip if object too far away | ||
245 | if (gSavedSettings.getBOOL("LimitSelectDistance")) | ||
246 | { | ||
247 | F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance"); | ||
248 | if (range_from_agent > max_select_distance) | ||
249 | { | ||
250 | return; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | if (range > 0.001f) | ||
255 | { | ||
256 | // range != zero | ||
257 | F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) gCamera->getViewHeightInPixels(); | ||
258 | F32 apparent_angle = fraction_of_fov * gCamera->getView(); // radians | ||
259 | mBoxHandleSize = range * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR; | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | // range == zero | ||
264 | mBoxHandleSize = BOX_HANDLE_BASE_FACTOR; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | //////////////////////////////////////////////////////////////////////// | ||
269 | // Draw bounding box | ||
270 | |||
271 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
272 | LLVector3 pos_agent = bbox.getPositionAgent(); | ||
273 | LLQuaternion rot = bbox.getRotation(); | ||
274 | |||
275 | glMatrixMode(GL_MODELVIEW); | ||
276 | glPushMatrix(); | ||
277 | { | ||
278 | glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ]); | ||
279 | |||
280 | F32 angle_radians, x, y, z; | ||
281 | rot.getAngleAxis(&angle_radians, &x, &y, &z); | ||
282 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
283 | |||
284 | |||
285 | { | ||
286 | LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL); | ||
287 | glPolygonOffset( -2.f, -2.f); | ||
288 | |||
289 | // JC - Band-aid until edge stretch working similar to side stretch | ||
290 | // in non-uniform. | ||
291 | // renderEdges( bbox ); | ||
292 | |||
293 | renderCorners( bbox ); | ||
294 | renderFaces( bbox ); | ||
295 | |||
296 | if (mManipPart != LL_NO_PART) | ||
297 | { | ||
298 | renderGuidelinesPart( bbox ); | ||
299 | } | ||
300 | |||
301 | glPolygonOffset( 0.f, 0.f); | ||
302 | } | ||
303 | } | ||
304 | glPopMatrix(); | ||
305 | |||
306 | if (mManipPart != LL_NO_PART) | ||
307 | { | ||
308 | renderSnapGuides(bbox); | ||
309 | } | ||
310 | glPopMatrix(); | ||
311 | |||
312 | renderXYZ(bbox.getExtentLocal()); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | BOOL LLManipScale::handleMouseDown(S32 x, S32 y, MASK mask) | ||
317 | { | ||
318 | BOOL handled = FALSE; | ||
319 | |||
320 | LLViewerObject* hit_obj = gViewerWindow->lastObjectHit(); | ||
321 | if( hit_obj || | ||
322 | (mHighlightedPart != LL_NO_PART) ) | ||
323 | { | ||
324 | handled = handleMouseDownOnPart( x, y, mask ); | ||
325 | } | ||
326 | |||
327 | return handled; | ||
328 | } | ||
329 | |||
330 | // Assumes that one of the arrows on an object was hit. | ||
331 | BOOL LLManipScale::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) | ||
332 | { | ||
333 | BOOL can_scale = gSelectMgr->getObjectCount() != 0; | ||
334 | for (LLViewerObject* objectp = gSelectMgr->getFirstObject(); | ||
335 | objectp; | ||
336 | objectp = gSelectMgr->getNextObject()) | ||
337 | { | ||
338 | can_scale = can_scale && objectp->permModify() && objectp->permMove() && !objectp->isSeat(); | ||
339 | } | ||
340 | |||
341 | if (!can_scale) | ||
342 | { | ||
343 | return FALSE; | ||
344 | } | ||
345 | |||
346 | highlightManipulators(x, y); | ||
347 | S32 hit_part = mHighlightedPart; | ||
348 | |||
349 | gSelectMgr->enableSilhouette(FALSE); | ||
350 | mManipPart = (EManipPart)hit_part; | ||
351 | |||
352 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
353 | LLVector3 box_center_agent = bbox.getCenterAgent(); | ||
354 | LLVector3 box_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ) ); | ||
355 | |||
356 | updateSnapGuides(bbox); | ||
357 | |||
358 | mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent); | ||
359 | mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent); | ||
360 | LLVector3 far_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ) ); | ||
361 | mDragFarHitGlobal = gAgent.getPosGlobalFromAgent(far_corner_agent); | ||
362 | mDragPointGlobal = mDragStartPointGlobal; | ||
363 | |||
364 | // we just started a drag, so save initial object positions, orientations, and scales | ||
365 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE); | ||
366 | // Route future Mouse messages here preemptively. (Release on mouse up.) | ||
367 | setMouseCapture( TRUE ); | ||
368 | |||
369 | mHelpTextTimer.reset(); | ||
370 | sNumTimesHelpTextShown++; | ||
371 | return TRUE; | ||
372 | } | ||
373 | |||
374 | |||
375 | BOOL LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask) | ||
376 | { | ||
377 | // first, perform normal processing in case this was a quick-click | ||
378 | handleHover(x, y, mask); | ||
379 | |||
380 | gSelectMgr->enableSilhouette(TRUE); | ||
381 | mManipPart = LL_NO_PART; | ||
382 | |||
383 | // Might have missed last update due to UPDATE_DELAY timing | ||
384 | if (mSendUpdateOnMouseUp) | ||
385 | { | ||
386 | gSelectMgr->sendMultipleUpdate( mLastUpdateFlags ); | ||
387 | } | ||
388 | |||
389 | //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); | ||
390 | gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); | ||
391 | return LLManip::handleMouseUp(x, y, mask); | ||
392 | } | ||
393 | |||
394 | |||
395 | BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) | ||
396 | { | ||
397 | if( hasMouseCapture() ) | ||
398 | { | ||
399 | if( gSelectMgr->isEmpty() ) | ||
400 | { | ||
401 | // Somehow the object got deselected while we were dragging it. | ||
402 | setMouseCapture( FALSE ); | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | drag( x, y ); | ||
407 | } | ||
408 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (active)" << llendl; | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | mInSnapRegime = FALSE; | ||
413 | // not dragging... | ||
414 | highlightManipulators(x, y); | ||
415 | } | ||
416 | |||
417 | // Patch up textures, if possible. | ||
418 | gSelectMgr->adjustTexturesByScale(TRUE, getStretchTextures()); | ||
419 | |||
420 | gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLSCALE); | ||
421 | return TRUE; | ||
422 | } | ||
423 | |||
424 | void LLManipScale::highlightManipulators(S32 x, S32 y) | ||
425 | { | ||
426 | mHighlightedPart = LL_NO_PART; | ||
427 | |||
428 | // If we have something selected, try to hit its manipulator handles. | ||
429 | // Don't do this with nothing selected, as it kills the framerate. | ||
430 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
431 | |||
432 | if( isSelectionScalable() ) | ||
433 | { | ||
434 | LLMatrix4 transform; | ||
435 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
436 | { | ||
437 | LLVector4 translation(bbox.getPositionAgent()); | ||
438 | transform.initRotTrans(bbox.getRotation(), translation); | ||
439 | LLMatrix4 cfr(OGL_TO_CFR_ROTATION); | ||
440 | transform *= cfr; | ||
441 | LLMatrix4 window_scale; | ||
442 | F32 zoom_level = 2.f * gAgent.getAvatarObject()->mHUDCurZoom; | ||
443 | window_scale.initAll(LLVector3(zoom_level / gCamera->getAspect(), zoom_level, 0.f), | ||
444 | LLQuaternion::DEFAULT, | ||
445 | LLVector3::zero); | ||
446 | transform *= window_scale; | ||
447 | } | ||
448 | else | ||
449 | { | ||
450 | LLMatrix4 projMatrix = gCamera->getProjection(); | ||
451 | LLMatrix4 modelView = gCamera->getModelview(); | ||
452 | transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(), bbox.getPositionAgent()); | ||
453 | |||
454 | transform *= modelView; | ||
455 | transform *= projMatrix; | ||
456 | } | ||
457 | |||
458 | LLVector3 min = bbox.getMinLocal(); | ||
459 | LLVector3 max = bbox.getMaxLocal(); | ||
460 | LLVector3 ctr = bbox.getCenterLocal(); | ||
461 | |||
462 | mProjectedManipulators.deleteAllData(); | ||
463 | |||
464 | S32 numManips = 0; | ||
465 | // corners | ||
466 | mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], min.mV[VZ], 1.f); | ||
467 | mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], max.mV[VZ], 1.f); | ||
468 | mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], min.mV[VZ], 1.f); | ||
469 | mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], max.mV[VZ], 1.f); | ||
470 | mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], min.mV[VZ], 1.f); | ||
471 | mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], max.mV[VZ], 1.f); | ||
472 | mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], min.mV[VZ], 1.f); | ||
473 | mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], max.mV[VZ], 1.f); | ||
474 | |||
475 | // 1-D highlights are applicable iff one object is selected | ||
476 | if( gSelectMgr->getObjectCount() == 1 ) | ||
477 | { | ||
478 | // face centers | ||
479 | mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], max.mV[VZ], 1.f); | ||
480 | mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f); | ||
481 | mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], max.mV[VY], ctr.mV[VZ], 1.f); | ||
482 | mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f); | ||
483 | mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], min.mV[VY], ctr.mV[VZ], 1.f); | ||
484 | mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], min.mV[VZ], 1.f); | ||
485 | } | ||
486 | |||
487 | for (S32 i = 0; i < numManips; i++) | ||
488 | { | ||
489 | LLVector4 projectedVertex = mManipulatorVertices[i] * transform; | ||
490 | projectedVertex = projectedVertex * (1.f / projectedVertex.mV[VW]); | ||
491 | |||
492 | ManipulatorHandle* projManipulator = new ManipulatorHandle(LLVector3(projectedVertex.mV[VX], projectedVertex.mV[VY], | ||
493 | projectedVertex.mV[VZ]), MANIPULATOR_IDS[i], (i < 7) ? SCALE_MANIP_CORNER : SCALE_MANIP_FACE); | ||
494 | mProjectedManipulators.addDataSorted(projManipulator); | ||
495 | } | ||
496 | |||
497 | F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f; | ||
498 | F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f; | ||
499 | LLVector2 manip2d; | ||
500 | LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); | ||
501 | LLVector2 delta; | ||
502 | |||
503 | mHighlightedPart = LL_NO_PART; | ||
504 | |||
505 | for (ManipulatorHandle* manipulator = mProjectedManipulators.getFirstData(); | ||
506 | manipulator; | ||
507 | manipulator = mProjectedManipulators.getNextData()) | ||
508 | { | ||
509 | manip2d.setVec(manipulator->mPosition.mV[VX] * half_width, manipulator->mPosition.mV[VY] * half_height); | ||
510 | |||
511 | delta = manip2d - mousePos; | ||
512 | if (delta.magVecSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED) | ||
513 | { | ||
514 | mHighlightedPart = manipulator->mManipID; | ||
515 | |||
516 | //llinfos << "Tried: " << mHighlightedPart << llendl; | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | |||
522 | for (S32 i = 0; i < NUM_MANIPULATORS; i++) | ||
523 | { | ||
524 | if (mHighlightedPart == MANIPULATOR_IDS[i]) | ||
525 | { | ||
526 | mManipulatorScales[i] = lerp(mManipulatorScales[i], SELECTED_MANIPULATOR_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (inactive)" << llendl; | ||
535 | } | ||
536 | |||
537 | |||
538 | void LLManipScale::renderFaces( const LLBBox& bbox ) | ||
539 | { | ||
540 | // Don't bother to render the drag handles for 1-D scaling if | ||
541 | // more than one object is selected or if it is an attachment | ||
542 | if ( gSelectMgr->getObjectCount() > 1 ) | ||
543 | { | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | // This is a flattened representation of the box as render here | ||
548 | // . | ||
549 | // (+++) (++-) /|\t | ||
550 | // +------------+ | (texture coordinates) | ||
551 | // | | | | ||
552 | // | 1 | (*) --->s | ||
553 | // | +X | | ||
554 | // | | | ||
555 | // (+++) (+-+)| |(+--) (++-) (+++) | ||
556 | // +------------+------------+------------+------------+ | ||
557 | // |0 3|3 7|7 4|4 0| | ||
558 | // | 0 | 4 | 5 | 2 | | ||
559 | // | +Z | -Y | -Z | +Y | | ||
560 | // | | | | | | ||
561 | // |1 2|2 6|6 5|5 1| | ||
562 | // +------------+------------+------------+------------+ | ||
563 | // (-++) (--+)| |(---) (-+-) (-++) | ||
564 | // | 3 | | ||
565 | // | -X | | ||
566 | // | | | ||
567 | // | | | ||
568 | // +------------+ | ||
569 | // (-++) (-+-) | ||
570 | |||
571 | LLColor4 highlight_color( 1.f, 1.f, 1.f, 0.5f); | ||
572 | LLColor4 normal_color( 1.f, 1.f, 1.f, 0.3f); | ||
573 | |||
574 | LLColor4 x_highlight_color( 1.f, 0.2f, 0.2f, 1.0f); | ||
575 | LLColor4 x_normal_color( 0.6f, 0.f, 0.f, 0.4f); | ||
576 | |||
577 | LLColor4 y_highlight_color( 0.2f, 1.f, 0.2f, 1.0f); | ||
578 | LLColor4 y_normal_color( 0.f, 0.6f, 0.f, 0.4f); | ||
579 | |||
580 | LLColor4 z_highlight_color( 0.2f, 0.2f, 1.f, 1.0f); | ||
581 | LLColor4 z_normal_color( 0.f, 0.f, 0.6f, 0.4f); | ||
582 | |||
583 | LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.15f ); | ||
584 | |||
585 | const LLVector3& min = bbox.getMinLocal(); | ||
586 | const LLVector3& max = bbox.getMaxLocal(); | ||
587 | LLVector3 ctr = bbox.getCenterLocal(); | ||
588 | |||
589 | if (mManipPart == LL_NO_PART) | ||
590 | { | ||
591 | glColor4fv( default_normal_color.mV ); | ||
592 | glBegin(GL_QUADS); | ||
593 | { | ||
594 | // Face 0 | ||
595 | glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); | ||
596 | glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); | ||
597 | glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); | ||
598 | glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); | ||
599 | |||
600 | // Face 1 | ||
601 | glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); | ||
602 | glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); | ||
603 | glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); | ||
604 | glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); | ||
605 | |||
606 | // Face 2 | ||
607 | glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); | ||
608 | glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); | ||
609 | glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); | ||
610 | glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); | ||
611 | |||
612 | // Face 3 | ||
613 | glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); | ||
614 | glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); | ||
615 | glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); | ||
616 | glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); | ||
617 | |||
618 | // Face 4 | ||
619 | glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); | ||
620 | glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); | ||
621 | glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); | ||
622 | glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); | ||
623 | |||
624 | // Face 5 | ||
625 | glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); | ||
626 | glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); | ||
627 | glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); | ||
628 | glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); | ||
629 | } | ||
630 | glEnd(); | ||
631 | } | ||
632 | |||
633 | // Find nearest vertex | ||
634 | LLVector3 orientWRTHead = bbox.agentToLocalBasis( bbox.getCenterAgent() - gAgent.getCameraPositionAgent() ); | ||
635 | U32 nearest = | ||
636 | (orientWRTHead.mV[0] < 0.0f ? 1 : 0) + | ||
637 | (orientWRTHead.mV[1] < 0.0f ? 2 : 0) + | ||
638 | (orientWRTHead.mV[2] < 0.0f ? 4 : 0); | ||
639 | |||
640 | // opposite faces on Linden cubes: | ||
641 | // 0 & 5 | ||
642 | // 1 & 3 | ||
643 | // 2 & 4 | ||
644 | |||
645 | // Table of order to draw faces, based on nearest vertex | ||
646 | static U32 face_list[8][6] = { | ||
647 | { 2,0,1, 4,5,3 }, // v6 F201 F453 | ||
648 | { 2,0,3, 4,5,1 }, // v7 F203 F451 | ||
649 | { 4,0,1, 2,5,3 }, // v5 F401 F253 | ||
650 | { 4,0,3, 2,5,1 }, // v4 F403 F251 | ||
651 | { 2,5,1, 4,0,3 }, // v2 F251 F403 | ||
652 | { 2,5,3, 4,0,1 }, // v3 F253 F401 | ||
653 | { 4,5,1, 2,0,3 }, // v1 F451 F203 | ||
654 | { 4,5,3, 2,0,1 } // v0 F453 F201 | ||
655 | }; | ||
656 | |||
657 | { | ||
658 | LLGLDepthTest gls_depth(GL_FALSE); | ||
659 | |||
660 | for (S32 i = 0; i < 6; i++) | ||
661 | { | ||
662 | U32 face = face_list[nearest][i]; | ||
663 | switch( face ) | ||
664 | { | ||
665 | case 0: | ||
666 | conditionalHighlight( LL_FACE_POSZ, &z_highlight_color, &z_normal_color ); | ||
667 | renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) ); | ||
668 | break; | ||
669 | |||
670 | case 1: | ||
671 | conditionalHighlight( LL_FACE_POSX, &x_highlight_color, &x_normal_color ); | ||
672 | renderAxisHandle( ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); | ||
673 | break; | ||
674 | |||
675 | case 2: | ||
676 | conditionalHighlight( LL_FACE_POSY, &y_highlight_color, &y_normal_color ); | ||
677 | renderAxisHandle( ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) ); | ||
678 | break; | ||
679 | |||
680 | case 3: | ||
681 | conditionalHighlight( LL_FACE_NEGX, &x_highlight_color, &x_normal_color ); | ||
682 | renderAxisHandle( ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); | ||
683 | break; | ||
684 | |||
685 | case 4: | ||
686 | conditionalHighlight( LL_FACE_NEGY, &y_highlight_color, &y_normal_color ); | ||
687 | renderAxisHandle( ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) ); | ||
688 | break; | ||
689 | |||
690 | case 5: | ||
691 | conditionalHighlight( LL_FACE_NEGZ, &z_highlight_color, &z_normal_color ); | ||
692 | renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) ); | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | } | ||
697 | } | ||
698 | |||
699 | void LLManipScale::renderEdges( const LLBBox& bbox ) | ||
700 | { | ||
701 | LLVector3 extent = bbox.getExtentLocal(); | ||
702 | F32 edge_width = mBoxHandleSize * .6f; | ||
703 | |||
704 | for( U32 part = LL_EDGE_MIN; part <= LL_EDGE_MAX; part++ ) | ||
705 | { | ||
706 | LLVector3 direction = edgeToUnitVector( part ); | ||
707 | LLVector3 center_to_edge = unitVectorToLocalBBoxExtent( direction, bbox ); | ||
708 | |||
709 | glPushMatrix(); | ||
710 | { | ||
711 | glTranslatef( center_to_edge.mV[0], center_to_edge.mV[1], center_to_edge.mV[2] ); | ||
712 | conditionalHighlight( part ); | ||
713 | glScalef( | ||
714 | direction.mV[0] ? edge_width : extent.mV[VX], | ||
715 | direction.mV[1] ? edge_width : extent.mV[VY], | ||
716 | direction.mV[2] ? edge_width : extent.mV[VZ] ); | ||
717 | gBox.render(); | ||
718 | } | ||
719 | glPopMatrix(); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | |||
724 | void LLManipScale::renderCorners( const LLBBox& bbox ) | ||
725 | { | ||
726 | U32 part = LL_CORNER_NNN; | ||
727 | |||
728 | F32 x_offset = bbox.getMinLocal().mV[VX]; | ||
729 | for( S32 i=0; i < 2; i++ ) | ||
730 | { | ||
731 | F32 y_offset = bbox.getMinLocal().mV[VY]; | ||
732 | for( S32 j=0; j < 2; j++ ) | ||
733 | { | ||
734 | F32 z_offset = bbox.getMinLocal().mV[VZ]; | ||
735 | for( S32 k=0; k < 2; k++ ) | ||
736 | { | ||
737 | conditionalHighlight( part ); | ||
738 | renderBoxHandle( x_offset, y_offset, z_offset ); | ||
739 | part++; | ||
740 | |||
741 | z_offset = bbox.getMaxLocal().mV[VZ]; | ||
742 | |||
743 | } | ||
744 | y_offset = bbox.getMaxLocal().mV[VY]; | ||
745 | } | ||
746 | x_offset = bbox.getMaxLocal().mV[VX]; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | |||
751 | void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z ) | ||
752 | { | ||
753 | LLGLDisable gls_tex(GL_TEXTURE_2D); | ||
754 | |||
755 | glPushMatrix(); | ||
756 | { | ||
757 | glTranslatef( x, y, z ); | ||
758 | glScalef( mScaledBoxHandleSize, mScaledBoxHandleSize, mScaledBoxHandleSize ); | ||
759 | gBox.render(); | ||
760 | } | ||
761 | glPopMatrix(); | ||
762 | } | ||
763 | |||
764 | |||
765 | void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& end ) | ||
766 | { | ||
767 | if( getShowAxes() ) | ||
768 | { | ||
769 | // Draws a single "jacks" style handle: a long, retangular box from start to end. | ||
770 | LLVector3 offset_start = end - start; | ||
771 | offset_start.normVec(); | ||
772 | offset_start = start + mBoxHandleSize * offset_start; | ||
773 | |||
774 | LLVector3 delta = end - offset_start; | ||
775 | LLVector3 pos = offset_start + 0.5f * delta; | ||
776 | |||
777 | glPushMatrix(); | ||
778 | { | ||
779 | glTranslatef( pos.mV[VX], pos.mV[VY], pos.mV[VZ] ); | ||
780 | glScalef( | ||
781 | mBoxHandleSize + llabs(delta.mV[VX]), | ||
782 | mBoxHandleSize + llabs(delta.mV[VY]), | ||
783 | mBoxHandleSize + llabs(delta.mV[VZ])); | ||
784 | gBox.render(); | ||
785 | } | ||
786 | glPopMatrix(); | ||
787 | } | ||
788 | else | ||
789 | { | ||
790 | renderBoxHandle( end.mV[VX], end.mV[VY], end.mV[VZ] ); | ||
791 | } | ||
792 | } | ||
793 | |||
794 | |||
795 | void LLManipScale::drag( S32 x, S32 y ) | ||
796 | { | ||
797 | if( (LL_FACE_MIN <= (S32)mManipPart) | ||
798 | && ((S32)mManipPart <= LL_FACE_MAX) ) | ||
799 | { | ||
800 | dragFace( x, y ); | ||
801 | } | ||
802 | else | ||
803 | if( (LL_CORNER_MIN <= (S32)mManipPart) | ||
804 | && ((S32)mManipPart <= LL_CORNER_MAX) ) | ||
805 | { | ||
806 | dragCorner( x, y ); | ||
807 | } | ||
808 | |||
809 | //gAgent.setObjectTracking(FALSE); | ||
810 | gAgent.clearFocusObject(); | ||
811 | } | ||
812 | |||
813 | // Scale around the | ||
814 | void LLManipScale::dragCorner( S32 x, S32 y ) | ||
815 | { | ||
816 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
817 | |||
818 | // Suppress scale if mouse hasn't moved. | ||
819 | if (x == mLastMouseX && y == mLastMouseY) | ||
820 | { | ||
821 | if (mSendUpdateOnMouseUp) | ||
822 | { | ||
823 | sendUpdates(TRUE,TRUE,TRUE); | ||
824 | } | ||
825 | return; | ||
826 | } | ||
827 | |||
828 | mLastMouseX = x; | ||
829 | mLastMouseY = y; | ||
830 | |||
831 | LLVector3d drag_start_point_global = mDragStartPointGlobal; | ||
832 | LLVector3d drag_start_center_global = mDragStartCenterGlobal; | ||
833 | LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global); | ||
834 | LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global); | ||
835 | |||
836 | LLVector3d drag_start_dir_d; | ||
837 | drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global); | ||
838 | LLVector3 drag_start_dir_f; | ||
839 | drag_start_dir_f.setVec(drag_start_dir_d); | ||
840 | |||
841 | F32 s = 0; | ||
842 | F32 t = 0; | ||
843 | |||
844 | nearestPointOnLineFromMouse(x, y, | ||
845 | drag_start_center_agent, | ||
846 | drag_start_point_agent, | ||
847 | s, t ); | ||
848 | |||
849 | F32 drag_start_dist = dist_vec(drag_start_point_agent, drag_start_center_agent); | ||
850 | |||
851 | if( s <= 0 ) // we only care about intersections in front of the camera | ||
852 | { | ||
853 | return; | ||
854 | } | ||
855 | |||
856 | LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d; | ||
857 | |||
858 | F32 scale_factor = t; | ||
859 | |||
860 | BOOL uniform = LLManipScale::getUniform(); | ||
861 | |||
862 | if( !uniform ) | ||
863 | { | ||
864 | scale_factor = 0.5f + (scale_factor * 0.5f); | ||
865 | } | ||
866 | |||
867 | // check for snapping | ||
868 | LLVector3 drag_center_agent = gAgent.getPosAgentFromGlobal(drag_point_global); | ||
869 | LLVector3 mouse_on_plane1; | ||
870 | getMousePointOnPlaneAgent(mouse_on_plane1, x, y, drag_center_agent, mScalePlaneNormal1); | ||
871 | LLVector3 mouse_on_plane2; | ||
872 | getMousePointOnPlaneAgent(mouse_on_plane2, x, y, drag_center_agent, mScalePlaneNormal2); | ||
873 | LLVector3 mouse_dir_1 = mouse_on_plane1 - mScaleCenter; | ||
874 | LLVector3 mouse_dir_2 = mouse_on_plane2 - mScaleCenter; | ||
875 | LLVector3 mouse_to_scale_line_1 = mouse_dir_1 - projected_vec(mouse_dir_1, mScaleDir); | ||
876 | LLVector3 mouse_to_scale_line_2 = mouse_dir_2 - projected_vec(mouse_dir_2, mScaleDir); | ||
877 | LLVector3 mouse_to_scale_line_dir_1 = mouse_to_scale_line_1; | ||
878 | mouse_to_scale_line_dir_1.normVec(); | ||
879 | if (mouse_to_scale_line_dir_1 * mSnapGuideDir1 < 0.f) | ||
880 | { | ||
881 | // need to keep sign of mouse offset wrt to snap guide direction | ||
882 | mouse_to_scale_line_dir_1 *= -1.f; | ||
883 | } | ||
884 | LLVector3 mouse_to_scale_line_dir_2 = mouse_to_scale_line_2; | ||
885 | mouse_to_scale_line_dir_2.normVec(); | ||
886 | if (mouse_to_scale_line_dir_2 * mSnapGuideDir2 < 0.f) | ||
887 | { | ||
888 | // need to keep sign of mouse offset wrt to snap guide direction | ||
889 | mouse_to_scale_line_dir_2 *= -1.f; | ||
890 | } | ||
891 | |||
892 | F32 snap_dir_dot_mouse_offset1 = mSnapGuideDir1 * mouse_to_scale_line_dir_1; | ||
893 | F32 snap_dir_dot_mouse_offset2 = mSnapGuideDir2 * mouse_to_scale_line_dir_2; | ||
894 | |||
895 | F32 dist_from_scale_line_1 = mouse_to_scale_line_1 * mouse_to_scale_line_dir_1; | ||
896 | F32 dist_from_scale_line_2 = mouse_to_scale_line_2 * mouse_to_scale_line_dir_2; | ||
897 | |||
898 | F32 max_scale = partToMaxScale(mManipPart, bbox); | ||
899 | F32 min_scale = partToMinScale(mManipPart, bbox); | ||
900 | |||
901 | BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled"); | ||
902 | if (snap_enabled && dist_from_scale_line_1 > mSnapRegimeOffset * snap_dir_dot_mouse_offset1) | ||
903 | { | ||
904 | mInSnapRegime = TRUE; | ||
905 | LLVector3 projected_drag_pos = mouse_on_plane1 - (dist_from_scale_line_1 / snap_dir_dot_mouse_offset1) * mSnapGuideDir1; | ||
906 | F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; | ||
907 | |||
908 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
909 | F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions); | ||
910 | F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions); | ||
911 | |||
912 | mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); | ||
913 | |||
914 | scale_factor = mScaleSnapValue / drag_start_dist; | ||
915 | if( !uniform ) | ||
916 | { | ||
917 | scale_factor *= 0.5f; | ||
918 | } | ||
919 | } | ||
920 | else if (snap_enabled && dist_from_scale_line_2 > mSnapRegimeOffset * snap_dir_dot_mouse_offset2) | ||
921 | { | ||
922 | mInSnapRegime = TRUE; | ||
923 | LLVector3 projected_drag_pos = mouse_on_plane2 - (dist_from_scale_line_2 / snap_dir_dot_mouse_offset2) * mSnapGuideDir2; | ||
924 | F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; | ||
925 | |||
926 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
927 | F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions); | ||
928 | F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit2 / cur_subdivisions); | ||
929 | |||
930 | mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); | ||
931 | |||
932 | scale_factor = mScaleSnapValue / drag_start_dist; | ||
933 | if( !uniform ) | ||
934 | { | ||
935 | scale_factor *= 0.5f; | ||
936 | } | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | mInSnapRegime = FALSE; | ||
941 | } | ||
942 | |||
943 | F32 max_scale_factor = MAX_OBJECT_SCALE / MIN_OBJECT_SCALE; | ||
944 | F32 min_scale_factor = MIN_OBJECT_SCALE / MAX_OBJECT_SCALE; | ||
945 | |||
946 | // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale | ||
947 | LLSelectNode* selectNode; | ||
948 | for( selectNode = gSelectMgr->getFirstNode(); selectNode; selectNode = gSelectMgr->getNextNode() ) | ||
949 | { | ||
950 | LLViewerObject* cur = selectNode->getObject(); | ||
951 | if( cur->permModify() && cur->permMove() && !cur->isAvatar() ) | ||
952 | { | ||
953 | const LLVector3& scale = selectNode->mSavedScale; | ||
954 | |||
955 | F32 cur_max_scale_factor = llmin( MAX_OBJECT_SCALE / scale.mV[VX], MAX_OBJECT_SCALE / scale.mV[VY], MAX_OBJECT_SCALE / scale.mV[VZ] ); | ||
956 | max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); | ||
957 | |||
958 | F32 cur_min_scale_factor = llmax( MIN_OBJECT_SCALE / scale.mV[VX], MIN_OBJECT_SCALE / scale.mV[VY], MIN_OBJECT_SCALE / scale.mV[VZ] ); | ||
959 | min_scale_factor = llmax( min_scale_factor, cur_min_scale_factor ); | ||
960 | } | ||
961 | } | ||
962 | |||
963 | scale_factor = llclamp( scale_factor, min_scale_factor, max_scale_factor ); | ||
964 | |||
965 | LLVector3d drag_global = uniform ? mDragStartCenterGlobal : mDragFarHitGlobal; | ||
966 | |||
967 | // do the root objects i.e. (TRUE == cur->isRootEdit()) | ||
968 | for( selectNode = gSelectMgr->getFirstNode(); selectNode; selectNode = gSelectMgr->getNextNode() ) | ||
969 | { | ||
970 | LLViewerObject* cur = selectNode->getObject(); | ||
971 | if( cur->permModify() && cur->permMove() && !cur->isAvatar() && cur->isRootEdit() ) | ||
972 | { | ||
973 | const LLVector3& scale = selectNode->mSavedScale; | ||
974 | cur->setScale( scale_factor * scale ); | ||
975 | |||
976 | LLVector3 delta_pos; | ||
977 | LLVector3 original_pos = cur->getPositionEdit(); | ||
978 | LLVector3d new_pos_global = drag_global + (selectNode->mSavedPositionGlobal - drag_global) * scale_factor; | ||
979 | if (!cur->isAttachment()) | ||
980 | { | ||
981 | new_pos_global = gWorldp->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); | ||
982 | } | ||
983 | cur->setPositionAbsoluteGlobal( new_pos_global ); | ||
984 | rebuild(cur); | ||
985 | |||
986 | delta_pos = cur->getPositionEdit() - original_pos; | ||
987 | |||
988 | if (selectNode->mIndividualSelection) | ||
989 | { | ||
990 | // counter-translate child objects if we are moving the root as an individual | ||
991 | for (U32 child_num = 0; child_num < cur->mChildList.size(); child_num++) | ||
992 | { | ||
993 | LLViewerObject* childp = cur->mChildList[child_num]; | ||
994 | |||
995 | if (cur->isAttachment()) | ||
996 | { | ||
997 | LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit()); | ||
998 | childp->setPosition(child_pos); | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | LLVector3d child_pos_delta(delta_pos); | ||
1003 | // RN: this updates drawable position instantly | ||
1004 | childp->setPositionAbsoluteGlobal(childp->getPositionGlobal() - child_pos_delta); | ||
1005 | } | ||
1006 | rebuild(childp); | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
1010 | } | ||
1011 | // do the child objects i.e. (FALSE == cur->isRootEdit()) | ||
1012 | for( selectNode = gSelectMgr->getFirstNode(); selectNode; selectNode = gSelectMgr->getNextNode() ) | ||
1013 | { | ||
1014 | LLViewerObject*cur = selectNode->getObject(); | ||
1015 | if( cur->permModify() && cur->permMove() && !cur->isAvatar() && !cur->isRootEdit() ) | ||
1016 | { | ||
1017 | const LLVector3& scale = selectNode->mSavedScale; | ||
1018 | cur->setScale( scale_factor * scale, FALSE ); | ||
1019 | |||
1020 | if (!selectNode->mIndividualSelection) | ||
1021 | { | ||
1022 | cur->setPosition(selectNode->mSavedPositionLocal * scale_factor); | ||
1023 | continue; | ||
1024 | } | ||
1025 | |||
1026 | LLVector3d new_pos_global = drag_global + (selectNode->mSavedPositionGlobal - drag_global) * scale_factor; | ||
1027 | cur->setPositionAbsoluteGlobal( new_pos_global ); | ||
1028 | rebuild(cur); | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | |||
1034 | mDragPointGlobal = drag_point_global; | ||
1035 | |||
1036 | sendUpdates( TRUE, TRUE, TRUE ); | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | void LLManipScale::dragFace( S32 x, S32 y ) | ||
1041 | { | ||
1042 | // Suppress scale if mouse hasn't moved. | ||
1043 | if (x == mLastMouseX && y == mLastMouseY) | ||
1044 | { | ||
1045 | if (mSendUpdateOnMouseUp) | ||
1046 | { | ||
1047 | sendUpdates(TRUE,TRUE,FALSE); | ||
1048 | } | ||
1049 | return; | ||
1050 | } | ||
1051 | |||
1052 | mLastMouseX = x; | ||
1053 | mLastMouseY = y; | ||
1054 | |||
1055 | LLVector3d drag_start_point_global = mDragStartPointGlobal; | ||
1056 | LLVector3d drag_start_center_global = mDragStartCenterGlobal; | ||
1057 | LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global); | ||
1058 | LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global); | ||
1059 | |||
1060 | LLVector3d drag_start_dir_d; | ||
1061 | drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global); | ||
1062 | LLVector3 drag_start_dir_f; | ||
1063 | drag_start_dir_f.setVec(drag_start_dir_d); | ||
1064 | |||
1065 | LLBBox bbox = gSelectMgr->getBBoxOfSelection(); | ||
1066 | |||
1067 | F32 s = 0; | ||
1068 | F32 t = 0; | ||
1069 | |||
1070 | nearestPointOnLineFromMouse(x, | ||
1071 | y, | ||
1072 | drag_start_center_agent, | ||
1073 | drag_start_point_agent, | ||
1074 | s, t ); | ||
1075 | |||
1076 | if( s <= 0 ) // we only care about intersections in front of the camera | ||
1077 | { | ||
1078 | return; | ||
1079 | } | ||
1080 | |||
1081 | LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d; | ||
1082 | LLVector3 part_dir_local = partToUnitVector( mManipPart ); | ||
1083 | |||
1084 | // check for snapping | ||
1085 | LLVector3 mouse_on_plane; | ||
1086 | getMousePointOnPlaneAgent(mouse_on_plane, x, y, mScaleCenter, mScalePlaneNormal1 ); | ||
1087 | |||
1088 | LLVector3 mouse_on_scale_line = mScaleCenter + projected_vec(mouse_on_plane - mScaleCenter, mScaleDir); | ||
1089 | LLVector3 drag_delta(mouse_on_scale_line - drag_start_point_agent); | ||
1090 | F32 max_drag_dist = partToMaxScale(mManipPart, bbox); | ||
1091 | F32 min_drag_dist = partToMinScale(mManipPart, bbox); | ||
1092 | |||
1093 | BOOL uniform = LLManipScale::getUniform(); | ||
1094 | if( uniform ) | ||
1095 | { | ||
1096 | drag_delta *= 2.f; | ||
1097 | } | ||
1098 | |||
1099 | LLVector3 scale_center_to_mouse = mouse_on_plane - mScaleCenter; | ||
1100 | F32 dist_from_scale_line = dist_vec(scale_center_to_mouse, (mouse_on_scale_line - mScaleCenter)); | ||
1101 | F32 dist_along_scale_line = scale_center_to_mouse * mScaleDir; | ||
1102 | |||
1103 | BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled"); | ||
1104 | |||
1105 | if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset) | ||
1106 | { | ||
1107 | mInSnapRegime = TRUE; | ||
1108 | |||
1109 | if (dist_along_scale_line > max_drag_dist) | ||
1110 | { | ||
1111 | mScaleSnapValue = max_drag_dist; | ||
1112 | |||
1113 | LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir; | ||
1114 | drag_delta.setVec(clamp_point - drag_start_point_agent); | ||
1115 | } | ||
1116 | else if (dist_along_scale_line < min_drag_dist) | ||
1117 | { | ||
1118 | mScaleSnapValue = min_drag_dist; | ||
1119 | |||
1120 | LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir; | ||
1121 | drag_delta.setVec(clamp_point - drag_start_point_agent); | ||
1122 | } | ||
1123 | else | ||
1124 | { | ||
1125 | F32 drag_dist = scale_center_to_mouse * mScaleDir; | ||
1126 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + mScaleDir * drag_dist, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
1127 | F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions); | ||
1128 | F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions); | ||
1129 | relative_snap_dist -= snap_dist; | ||
1130 | |||
1131 | //make sure that values that the scale is "snapped to" | ||
1132 | //do not exceed/go under the applicable max/mins | ||
1133 | //this causes the box to shift displacements ever so slightly | ||
1134 | //although the "snap value" should go down to 0 | ||
1135 | //see Jira 1027 | ||
1136 | relative_snap_dist = llclamp(relative_snap_dist, | ||
1137 | drag_dist - max_drag_dist, | ||
1138 | drag_dist - min_drag_dist); | ||
1139 | |||
1140 | mScaleSnapValue = drag_dist - relative_snap_dist; | ||
1141 | |||
1142 | if (llabs(relative_snap_dist) < snap_dist) | ||
1143 | { | ||
1144 | LLVector3 drag_correction = relative_snap_dist * mScaleDir; | ||
1145 | if (uniform) | ||
1146 | { | ||
1147 | drag_correction *= 2.f; | ||
1148 | } | ||
1149 | |||
1150 | drag_delta -= drag_correction; | ||
1151 | } | ||
1152 | } | ||
1153 | } | ||
1154 | else | ||
1155 | { | ||
1156 | mInSnapRegime = FALSE; | ||
1157 | } | ||
1158 | |||
1159 | BOOL send_scale_update = FALSE; | ||
1160 | BOOL send_position_update = FALSE; | ||
1161 | |||
1162 | LLVector3 dir_agent; | ||
1163 | if( part_dir_local.mV[VX] ) | ||
1164 | { | ||
1165 | dir_agent = bbox.localToAgentBasis( LLVector3::x_axis ); | ||
1166 | } | ||
1167 | else if( part_dir_local.mV[VY] ) | ||
1168 | { | ||
1169 | dir_agent = bbox.localToAgentBasis( LLVector3::y_axis ); | ||
1170 | } | ||
1171 | else if( part_dir_local.mV[VZ] ) | ||
1172 | { | ||
1173 | dir_agent = bbox.localToAgentBasis( LLVector3::z_axis ); | ||
1174 | } | ||
1175 | stretchFace( | ||
1176 | projected_vec(drag_start_dir_f, dir_agent) + drag_start_center_agent, | ||
1177 | projected_vec(drag_delta, dir_agent)); | ||
1178 | send_position_update = TRUE; | ||
1179 | send_scale_update = TRUE; | ||
1180 | |||
1181 | mDragPointGlobal = drag_point_global; | ||
1182 | |||
1183 | sendUpdates( send_position_update, send_scale_update ); | ||
1184 | } | ||
1185 | |||
1186 | void LLManipScale::sendUpdates( BOOL send_position_update, BOOL send_scale_update, BOOL corner ) | ||
1187 | { | ||
1188 | // Throttle updates to 10 per second. | ||
1189 | static LLTimer update_timer; | ||
1190 | F32 elapsed_time = update_timer.getElapsedTimeF32(); | ||
1191 | const F32 UPDATE_DELAY = 0.1f; // min time between transmitted updates | ||
1192 | |||
1193 | if( send_scale_update || send_position_update ) | ||
1194 | { | ||
1195 | U32 update_flags = UPD_NONE; | ||
1196 | if (send_position_update) update_flags |= UPD_POSITION; | ||
1197 | if (send_scale_update) update_flags |= UPD_SCALE; | ||
1198 | |||
1199 | // BOOL send_type = SEND_INDIVIDUALS; | ||
1200 | if (corner) | ||
1201 | { | ||
1202 | update_flags |= UPD_UNIFORM; | ||
1203 | } | ||
1204 | // keep this up to date for sendonmouseup | ||
1205 | mLastUpdateFlags = update_flags; | ||
1206 | |||
1207 | // enforce minimum update delay and don't stream updates on sub-object selections | ||
1208 | if( elapsed_time > UPDATE_DELAY && gSavedSettings.getBOOL("SelectLinkedSet") ) | ||
1209 | { | ||
1210 | gSelectMgr->sendMultipleUpdate( update_flags ); | ||
1211 | update_timer.reset(); | ||
1212 | mSendUpdateOnMouseUp = FALSE; | ||
1213 | } | ||
1214 | else | ||
1215 | { | ||
1216 | mSendUpdateOnMouseUp = TRUE; | ||
1217 | } | ||
1218 | |||
1219 | gSelectMgr->updateSelectionCenter(); | ||
1220 | dialog_refresh_all(); | ||
1221 | } | ||
1222 | } | ||
1223 | |||
1224 | // Rescales in a single dimension. Either uniform (standard) or one-sided (scale plus translation) | ||
1225 | // depending on mUniform. Handles multiple selection and objects that are not aligned to the bounding box. | ||
1226 | void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVector3& drag_delta_agent ) | ||
1227 | { | ||
1228 | LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal); | ||
1229 | |||
1230 | LLSelectNode *selectNode; | ||
1231 | for( selectNode = gSelectMgr->getFirstNode(); selectNode; selectNode = gSelectMgr->getNextNode() ) | ||
1232 | { | ||
1233 | LLViewerObject*cur = selectNode->getObject(); | ||
1234 | if( cur->permModify() && cur->permMove() && !cur->isAvatar() ) | ||
1235 | { | ||
1236 | LLBBox cur_bbox = cur->getBoundingBoxAgent(); | ||
1237 | LLVector3 start_local = cur_bbox.agentToLocal( drag_start_agent ); | ||
1238 | LLVector3 end_local = cur_bbox.agentToLocal( drag_start_agent + drag_delta_agent); | ||
1239 | LLVector3 start_center_local = cur_bbox.agentToLocal( drag_start_center_agent ); | ||
1240 | LLVector3 axis = nearestAxis( start_local - start_center_local ); | ||
1241 | S32 axis_index = axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2 ); | ||
1242 | |||
1243 | LLVector3 delta_local = end_local - start_local; | ||
1244 | F32 delta_local_mag = delta_local.magVec(); | ||
1245 | LLVector3 dir_local; | ||
1246 | if (delta_local_mag == 0.f) | ||
1247 | { | ||
1248 | dir_local = axis; | ||
1249 | } | ||
1250 | else | ||
1251 | { | ||
1252 | dir_local = delta_local / delta_local_mag; // normalized delta_local | ||
1253 | } | ||
1254 | |||
1255 | F32 denom = axis * dir_local; | ||
1256 | F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters | ||
1257 | F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_OBJECT_SCALE, MAX_OBJECT_SCALE); | ||
1258 | // propagate scale constraint back to position offset | ||
1259 | desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position | ||
1260 | |||
1261 | LLVector3 scale = cur->getScale(); | ||
1262 | scale.mV[axis_index] = desired_scale; | ||
1263 | cur->setScale(scale, FALSE); | ||
1264 | rebuild(cur); | ||
1265 | LLVector3 delta_pos; | ||
1266 | if( !getUniform() ) | ||
1267 | { | ||
1268 | LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size); | ||
1269 | LLVector3d delta_pos_global; | ||
1270 | delta_pos_global.setVec(cur_bbox.localToAgent( delta_pos_local ) - cur_bbox.getCenterAgent()); | ||
1271 | LLVector3 cur_pos = cur->getPositionEdit(); | ||
1272 | |||
1273 | if (cur->isRootEdit() && !cur->isAttachment()) | ||
1274 | { | ||
1275 | LLVector3d new_pos_global = gWorldp->clipToVisibleRegions(selectNode->mSavedPositionGlobal, selectNode->mSavedPositionGlobal + delta_pos_global); | ||
1276 | cur->setPositionGlobal( new_pos_global ); | ||
1277 | } | ||
1278 | else | ||
1279 | { | ||
1280 | LLXform* parent_xform = cur->mDrawable->getXform()->getParent(); | ||
1281 | LLVector3 new_pos_local; | ||
1282 | // this works in attachment point space using world space delta | ||
1283 | if (parent_xform) | ||
1284 | { | ||
1285 | new_pos_local = selectNode->mSavedPositionLocal + (LLVector3(delta_pos_global) * ~parent_xform->getWorldRotation()); | ||
1286 | } | ||
1287 | else | ||
1288 | { | ||
1289 | new_pos_local = selectNode->mSavedPositionLocal + LLVector3(delta_pos_global); | ||
1290 | } | ||
1291 | cur->setPosition(new_pos_local); | ||
1292 | } | ||
1293 | delta_pos = cur->getPositionEdit() - cur_pos; | ||
1294 | } | ||
1295 | if (cur->isRootEdit() && selectNode->mIndividualSelection) | ||
1296 | { | ||
1297 | // counter-translate child objects if we are moving the root as an individual | ||
1298 | for (U32 child_num = 0; child_num < cur->mChildList.size(); child_num++) | ||
1299 | { | ||
1300 | LLViewerObject* childp = cur->mChildList[child_num]; | ||
1301 | if (!getUniform()) | ||
1302 | { | ||
1303 | LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit()); | ||
1304 | childp->setPosition(child_pos); | ||
1305 | rebuild(childp); | ||
1306 | } | ||
1307 | } | ||
1308 | } | ||
1309 | } | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | |||
1314 | void LLManipScale::renderGuidelinesPart( const LLBBox& bbox ) | ||
1315 | { | ||
1316 | LLVector3 guideline_start = bbox.getCenterLocal(); | ||
1317 | |||
1318 | LLVector3 guideline_end = unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ); | ||
1319 | |||
1320 | if (!getUniform()) | ||
1321 | { | ||
1322 | guideline_start = unitVectorToLocalBBoxExtent( -partToUnitVector( mManipPart ), bbox ); | ||
1323 | } | ||
1324 | |||
1325 | guideline_end -= guideline_start; | ||
1326 | guideline_end.normVec(); | ||
1327 | guideline_end *= gWorldPointer->getRegionWidthInMeters(); | ||
1328 | guideline_end += guideline_start; | ||
1329 | |||
1330 | { | ||
1331 | LLGLDepthTest gls_depth(GL_TRUE); | ||
1332 | gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.5f) ); | ||
1333 | } | ||
1334 | { | ||
1335 | LLGLDepthTest gls_depth(GL_FALSE); | ||
1336 | gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.25f) ); | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1340 | void LLManipScale::updateSnapGuides(const LLBBox& bbox) | ||
1341 | { | ||
1342 | LLVector3 grid_origin; | ||
1343 | LLVector3 grid_scale; | ||
1344 | LLQuaternion grid_rotation; | ||
1345 | gSelectMgr->getGrid(grid_origin, grid_rotation, grid_scale); | ||
1346 | |||
1347 | LLVector3 box_corner_agent = bbox.localToAgent(unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox )); | ||
1348 | mScaleCenter = getUniform() ? bbox.getCenterAgent() : bbox.localToAgent(unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox )); | ||
1349 | mScaleDir = box_corner_agent - mScaleCenter; | ||
1350 | mScaleDir.normVec(); | ||
1351 | |||
1352 | if(gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1353 | { | ||
1354 | mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgent.getAvatarObject()->mHUDCurZoom; | ||
1355 | |||
1356 | } | ||
1357 | else | ||
1358 | { | ||
1359 | F32 object_distance = dist_vec(mScaleCenter, gCamera->getOrigin()); | ||
1360 | mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWindowWidth() * object_distance) / gCamera->getPixelMeterRatio(); | ||
1361 | } | ||
1362 | LLVector3 cam_at_axis; | ||
1363 | F32 snap_guide_length; | ||
1364 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1365 | { | ||
1366 | cam_at_axis.setVec(1.f, 0.f, 0.f); | ||
1367 | snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgent.getAvatarObject()->mHUDCurZoom; | ||
1368 | } | ||
1369 | else | ||
1370 | { | ||
1371 | cam_at_axis = gCamera->getAtAxis(); | ||
1372 | F32 manipulator_distance = dist_vec(box_corner_agent, gCamera->getOrigin()); | ||
1373 | snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH * gViewerWindow->getWindowWidth() * manipulator_distance) / gCamera->getPixelMeterRatio(); | ||
1374 | } | ||
1375 | |||
1376 | mSnapGuideLength = snap_guide_length / llmax(0.1f, (llmin(mSnapGuideDir1 * cam_at_axis, mSnapGuideDir2 * cam_at_axis))); | ||
1377 | |||
1378 | LLVector3 off_axis_dir = mScaleDir % cam_at_axis; | ||
1379 | off_axis_dir.normVec(); | ||
1380 | |||
1381 | if( (LL_FACE_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_FACE_MAX) ) | ||
1382 | { | ||
1383 | LLVector3 object_scale = bbox.getMaxLocal(); | ||
1384 | object_scale.scaleVec(off_axis_dir * ~bbox.getRotation()); | ||
1385 | object_scale.abs(); | ||
1386 | if (object_scale.mV[VX] > object_scale.mV[VY] && object_scale.mV[VX] > object_scale.mV[VZ]) | ||
1387 | { | ||
1388 | mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation(); | ||
1389 | } | ||
1390 | else if (object_scale.mV[VY] > object_scale.mV[VZ]) | ||
1391 | { | ||
1392 | mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation(); | ||
1393 | } | ||
1394 | else | ||
1395 | { | ||
1396 | mSnapGuideDir1 = LLVector3::z_axis * bbox.getRotation(); | ||
1397 | } | ||
1398 | |||
1399 | LLVector3 scale_snap = grid_scale; | ||
1400 | mScaleSnapUnit1 = scale_snap.scaleVec(partToUnitVector( mManipPart )).magVec(); | ||
1401 | mScaleSnapUnit2 = mScaleSnapUnit1; | ||
1402 | mSnapGuideDir1 *= mSnapGuideDir1 * gCamera->getUpAxis() > 0.f ? 1.f : -1.f; | ||
1403 | mSnapGuideDir2 = mSnapGuideDir1 * -1.f; | ||
1404 | mSnapDir1 = mScaleDir; | ||
1405 | mSnapDir2 = mScaleDir; | ||
1406 | } | ||
1407 | else if( (LL_CORNER_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_CORNER_MAX) ) | ||
1408 | { | ||
1409 | LLVector3 local_scale_dir = partToUnitVector( mManipPart ); | ||
1410 | LLVector3 local_camera_dir; | ||
1411 | if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD) | ||
1412 | { | ||
1413 | local_camera_dir = LLVector3(-1.f, 0.f, 0.f) * ~bbox.getRotation(); | ||
1414 | } | ||
1415 | else | ||
1416 | { | ||
1417 | local_camera_dir = (gCamera->getOrigin() - bbox.getCenterAgent()) * ~bbox.getRotation(); | ||
1418 | local_camera_dir.normVec(); | ||
1419 | } | ||
1420 | local_scale_dir -= projected_vec(local_scale_dir, local_camera_dir); | ||
1421 | local_scale_dir.normVec(); | ||
1422 | LLVector3 x_axis_proj_camera = LLVector3::x_axis - projected_vec(LLVector3::x_axis, local_camera_dir); | ||
1423 | x_axis_proj_camera.normVec(); | ||
1424 | LLVector3 y_axis_proj_camera = LLVector3::y_axis - projected_vec(LLVector3::y_axis, local_camera_dir); | ||
1425 | y_axis_proj_camera.normVec(); | ||
1426 | LLVector3 z_axis_proj_camera = LLVector3::z_axis - projected_vec(LLVector3::z_axis, local_camera_dir); | ||
1427 | z_axis_proj_camera.normVec(); | ||
1428 | F32 x_axis_proj = llabs(local_scale_dir * x_axis_proj_camera); | ||
1429 | F32 y_axis_proj = llabs(local_scale_dir * y_axis_proj_camera); | ||
1430 | F32 z_axis_proj = llabs(local_scale_dir * z_axis_proj_camera); | ||
1431 | |||
1432 | if (x_axis_proj > y_axis_proj && x_axis_proj > z_axis_proj) | ||
1433 | { | ||
1434 | mSnapGuideDir1 = LLVector3::y_axis; | ||
1435 | mScaleSnapUnit2 = grid_scale.mV[VY]; | ||
1436 | mSnapGuideDir2 = LLVector3::z_axis; | ||
1437 | mScaleSnapUnit1 = grid_scale.mV[VZ]; | ||
1438 | } | ||
1439 | else if (y_axis_proj > z_axis_proj) | ||
1440 | { | ||
1441 | mSnapGuideDir1 = LLVector3::x_axis; | ||
1442 | mScaleSnapUnit2 = grid_scale.mV[VX]; | ||
1443 | mSnapGuideDir2 = LLVector3::z_axis; | ||
1444 | mScaleSnapUnit1 = grid_scale.mV[VZ]; | ||
1445 | } | ||
1446 | else | ||
1447 | { | ||
1448 | mSnapGuideDir1 = LLVector3::x_axis; | ||
1449 | mScaleSnapUnit2 = grid_scale.mV[VX]; | ||
1450 | mSnapGuideDir2 = LLVector3::y_axis; | ||
1451 | mScaleSnapUnit1 = grid_scale.mV[VY]; | ||
1452 | } | ||
1453 | |||
1454 | LLVector3 snap_guide_flip(1.f, 1.f, 1.f); | ||
1455 | switch (mManipPart) | ||
1456 | { | ||
1457 | case LL_CORNER_NNN: | ||
1458 | break; | ||
1459 | case LL_CORNER_NNP: | ||
1460 | snap_guide_flip.setVec(1.f, 1.f, -1.f); | ||
1461 | break; | ||
1462 | case LL_CORNER_NPN: | ||
1463 | snap_guide_flip.setVec(1.f, -1.f, 1.f); | ||
1464 | break; | ||
1465 | case LL_CORNER_NPP: | ||
1466 | snap_guide_flip.setVec(1.f, -1.f, -1.f); | ||
1467 | break; | ||
1468 | case LL_CORNER_PNN: | ||
1469 | snap_guide_flip.setVec(-1.f, 1.f, 1.f); | ||
1470 | break; | ||
1471 | case LL_CORNER_PNP: | ||
1472 | snap_guide_flip.setVec(-1.f, 1.f, -1.f); | ||
1473 | break; | ||
1474 | case LL_CORNER_PPN: | ||
1475 | snap_guide_flip.setVec(-1.f, -1.f, 1.f); | ||
1476 | break; | ||
1477 | case LL_CORNER_PPP: | ||
1478 | snap_guide_flip.setVec(-1.f, -1.f, -1.f); | ||
1479 | break; | ||
1480 | default: | ||
1481 | break; | ||
1482 | } | ||
1483 | mSnapGuideDir1.scaleVec(snap_guide_flip); | ||
1484 | mSnapGuideDir2.scaleVec(snap_guide_flip); | ||
1485 | mSnapGuideDir1.rotVec(bbox.getRotation()); | ||
1486 | mSnapGuideDir2.rotVec(bbox.getRotation()); | ||
1487 | mSnapDir1 = -1.f * mSnapGuideDir2; | ||
1488 | mSnapDir2 = -1.f * mSnapGuideDir1; | ||
1489 | } | ||
1490 | |||
1491 | mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir; | ||
1492 | mScalePlaneNormal1.normVec(); | ||
1493 | |||
1494 | mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir; | ||
1495 | mScalePlaneNormal2.normVec(); | ||
1496 | |||
1497 | mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir); | ||
1498 | mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir); | ||
1499 | } | ||
1500 | |||
1501 | void LLManipScale::renderSnapGuides(const LLBBox& bbox) | ||
1502 | { | ||
1503 | if (!gSavedSettings.getBOOL("SnapEnabled")) | ||
1504 | { | ||
1505 | return; | ||
1506 | } | ||
1507 | |||
1508 | F32 max_subdivisions = sGridMaxSubdivisionLevel; | ||
1509 | F32 grid_alpha = gSavedSettings.getF32("GridOpacity"); | ||
1510 | |||
1511 | F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox); | ||
1512 | LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal); | ||
1513 | |||
1514 | updateGridSettings(); | ||
1515 | |||
1516 | S32 pass; | ||
1517 | for (pass = 0; pass < 3; pass++) | ||
1518 | { | ||
1519 | LLColor4 tick_color = setupSnapGuideRenderPass(pass); | ||
1520 | |||
1521 | glBegin(GL_LINES); | ||
1522 | LLVector3 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset); | ||
1523 | LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f))); | ||
1524 | LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f)); | ||
1525 | |||
1526 | glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f); | ||
1527 | glVertex3fv(line_start.mV); | ||
1528 | glColor4fv(tick_color.mV); | ||
1529 | glVertex3fv(line_mid.mV); | ||
1530 | glVertex3fv(line_mid.mV); | ||
1531 | glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f); | ||
1532 | glVertex3fv(line_end.mV); | ||
1533 | |||
1534 | line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset); | ||
1535 | line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f))); | ||
1536 | line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f)); | ||
1537 | glVertex3fv(line_start.mV); | ||
1538 | glColor4fv(tick_color.mV); | ||
1539 | glVertex3fv(line_mid.mV); | ||
1540 | glVertex3fv(line_mid.mV); | ||
1541 | glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f); | ||
1542 | glVertex3fv(line_end.mV); | ||
1543 | glEnd(); | ||
1544 | } | ||
1545 | |||
1546 | { | ||
1547 | LLGLDepthTest gls_depth(GL_FALSE); | ||
1548 | |||
1549 | F32 dist_grid_axis = (drag_point - mScaleCenter) * mScaleDir; | ||
1550 | // find distance to nearest smallest grid unit | ||
1551 | F32 grid_offset1 = fmodf(dist_grid_axis, mScaleSnapUnit1 / max_subdivisions); | ||
1552 | F32 grid_offset2 = fmodf(dist_grid_axis, mScaleSnapUnit2 / max_subdivisions); | ||
1553 | |||
1554 | // how many smallest grid units are we away from largest grid scale? | ||
1555 | S32 sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 / sGridMinSubdivisionLevel) / (mScaleSnapUnit1 / max_subdivisions)); | ||
1556 | S32 sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 / sGridMinSubdivisionLevel) / (mScaleSnapUnit2 / max_subdivisions)); | ||
1557 | |||
1558 | S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit1 / max_subdivisions))); | ||
1559 | S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit2 / max_subdivisions))); | ||
1560 | F32 dist_scale_units_1 = dist_grid_axis / (mScaleSnapUnit1 / max_subdivisions); | ||
1561 | F32 dist_scale_units_2 = dist_grid_axis / (mScaleSnapUnit2 / max_subdivisions); | ||
1562 | S32 ticks_from_scale_center_1 = lltrunc(dist_scale_units_1); | ||
1563 | S32 ticks_from_scale_center_2 = lltrunc(dist_scale_units_2); | ||
1564 | S32 max_ticks1 = llceil(max_point_on_scale_line / (mScaleSnapUnit1 / max_subdivisions) - dist_scale_units_1); | ||
1565 | S32 max_ticks2 = llceil(max_point_on_scale_line / (mScaleSnapUnit2 / max_subdivisions) - dist_scale_units_2); | ||
1566 | S32 start_tick = 0; | ||
1567 | S32 stop_tick = 0; | ||
1568 | |||
1569 | if (mInSnapRegime) | ||
1570 | { | ||
1571 | // draw snap guide line | ||
1572 | glBegin(GL_LINES); | ||
1573 | LLVector3 snap_line_center = mScaleCenter + (mScaleSnapValue * mScaleDir); | ||
1574 | |||
1575 | LLVector3 snap_line_start = snap_line_center + (mSnapGuideDir1 * mSnapRegimeOffset); | ||
1576 | LLVector3 snap_line_end = snap_line_center + (mSnapGuideDir2 * mSnapRegimeOffset); | ||
1577 | |||
1578 | glColor4f(1.f, 1.f, 1.f, grid_alpha); | ||
1579 | glVertex3fv(snap_line_start.mV); | ||
1580 | glVertex3fv(snap_line_center.mV); | ||
1581 | glVertex3fv(snap_line_center.mV); | ||
1582 | glVertex3fv(snap_line_end.mV); | ||
1583 | glEnd(); | ||
1584 | |||
1585 | // draw snap guide arrow | ||
1586 | glBegin(GL_TRIANGLES); | ||
1587 | { | ||
1588 | //gGLSNoCullFaces.set(); | ||
1589 | glColor4f(1.f, 1.f, 1.f, grid_alpha); | ||
1590 | |||
1591 | LLVector3 arrow_dir; | ||
1592 | LLVector3 arrow_span = mScaleDir; | ||
1593 | |||
1594 | arrow_dir = snap_line_start - snap_line_center; | ||
1595 | arrow_dir.normVec(); | ||
1596 | glVertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV); | ||
1597 | glVertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV); | ||
1598 | glVertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV); | ||
1599 | |||
1600 | arrow_dir = snap_line_end - snap_line_center; | ||
1601 | arrow_dir.normVec(); | ||
1602 | glVertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV); | ||
1603 | glVertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV); | ||
1604 | glVertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV); | ||
1605 | } | ||
1606 | glEnd(); | ||
1607 | } | ||
1608 | |||
1609 | LLVector2 screen_translate_axis(llabs(mScaleDir * gCamera->getLeftAxis()), llabs(mScaleDir * gCamera->getUpAxis())); | ||
1610 | screen_translate_axis.normVec(); | ||
1611 | |||
1612 | S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing); | ||
1613 | |||
1614 | for (pass = 0; pass < 3; pass++) | ||
1615 | { | ||
1616 | LLColor4 tick_color = setupSnapGuideRenderPass(pass); | ||
1617 | |||
1618 | start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1)); | ||
1619 | stop_tick = llmin(max_ticks1, num_ticks_per_side1); | ||
1620 | |||
1621 | glBegin(GL_LINES); | ||
1622 | // draw first row of ticks | ||
1623 | for (S32 i = start_tick; i <= stop_tick; i++) | ||
1624 | { | ||
1625 | F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1))); | ||
1626 | LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1)); | ||
1627 | |||
1628 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
1629 | |||
1630 | if (fmodf((F32)(i + sub_div_offset_1), (max_subdivisions / cur_subdivisions)) != 0.f) | ||
1631 | { | ||
1632 | continue; | ||
1633 | } | ||
1634 | |||
1635 | F32 tick_scale = 1.f; | ||
1636 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1637 | { | ||
1638 | if (fmodf((F32)(i + sub_div_offset_1), division_level) == 0.f) | ||
1639 | { | ||
1640 | break; | ||
1641 | } | ||
1642 | tick_scale *= 0.7f; | ||
1643 | } | ||
1644 | |||
1645 | glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha); | ||
1646 | LLVector3 tick_start = tick_pos + (mSnapGuideDir1 * mSnapRegimeOffset); | ||
1647 | LLVector3 tick_end = tick_start + (mSnapGuideDir1 * mSnapRegimeOffset * tick_scale); | ||
1648 | glVertex3fv(tick_start.mV); | ||
1649 | glVertex3fv(tick_end.mV); | ||
1650 | } | ||
1651 | |||
1652 | // draw opposite row of ticks | ||
1653 | start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2)); | ||
1654 | stop_tick = llmin(max_ticks2, num_ticks_per_side2); | ||
1655 | for (S32 i = start_tick; i <= stop_tick; i++) | ||
1656 | { | ||
1657 | F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2))); | ||
1658 | LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2)); | ||
1659 | |||
1660 | F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); | ||
1661 | |||
1662 | if (fmodf((F32)(i + sub_div_offset_2), (max_subdivisions / cur_subdivisions)) != 0.f) | ||
1663 | { | ||
1664 | continue; | ||
1665 | } | ||
1666 | |||
1667 | F32 tick_scale = 1.f; | ||
1668 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1669 | { | ||
1670 | if (fmodf((F32)(i + sub_div_offset_2), division_level) == 0.f) | ||
1671 | { | ||
1672 | break; | ||
1673 | } | ||
1674 | tick_scale *= 0.7f; | ||
1675 | } | ||
1676 | |||
1677 | glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha); | ||
1678 | LLVector3 tick_start = tick_pos + (mSnapGuideDir2 * mSnapRegimeOffset); | ||
1679 | LLVector3 tick_end = tick_start + (mSnapGuideDir2 * mSnapRegimeOffset * tick_scale); | ||
1680 | glVertex3fv(tick_start.mV); | ||
1681 | glVertex3fv(tick_end.mV); | ||
1682 | } | ||
1683 | glEnd(); | ||
1684 | } | ||
1685 | |||
1686 | // render tick labels | ||
1687 | start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1)); | ||
1688 | stop_tick = llmin(max_ticks1, num_ticks_per_side1); | ||
1689 | |||
1690 | F32 grid_resolution = gSelectMgr->getSelectType() == SELECT_TYPE_HUD ? 0.25f : llmax(gSavedSettings.getF32("GridResolution"), 0.001f); | ||
1691 | S32 label_sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 * 32.f) / (mScaleSnapUnit1 / max_subdivisions)); | ||
1692 | S32 label_sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 * 32.f) / (mScaleSnapUnit2 / max_subdivisions)); | ||
1693 | |||
1694 | for (S32 i = start_tick; i <= stop_tick; i++) | ||
1695 | { | ||
1696 | F32 tick_scale = 1.f; | ||
1697 | F32 alpha = grid_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side1))); | ||
1698 | LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1)); | ||
1699 | |||
1700 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1701 | { | ||
1702 | if (fmodf((F32)(i + label_sub_div_offset_1), division_level) == 0.f) | ||
1703 | { | ||
1704 | break; | ||
1705 | } | ||
1706 | tick_scale *= 0.7f; | ||
1707 | } | ||
1708 | |||
1709 | if (fmodf((F32)(i + label_sub_div_offset_1), (max_subdivisions / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, tick_label_spacing)))) == 0.f) | ||
1710 | { | ||
1711 | LLVector3 text_origin = tick_pos + | ||
1712 | (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale)); | ||
1713 | |||
1714 | EGridMode grid_mode = gSelectMgr->getGridMode(); | ||
1715 | F32 tick_val; | ||
1716 | if (grid_mode == GRID_MODE_WORLD) | ||
1717 | { | ||
1718 | tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 / grid_resolution); | ||
1719 | } | ||
1720 | else | ||
1721 | { | ||
1722 | tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 * 2.f); | ||
1723 | } | ||
1724 | |||
1725 | if (getUniform()) | ||
1726 | { | ||
1727 | tick_val *= 2.f; | ||
1728 | } | ||
1729 | |||
1730 | F32 text_highlight = 0.8f; | ||
1731 | |||
1732 | if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime) | ||
1733 | { | ||
1734 | text_highlight = 1.f; | ||
1735 | } | ||
1736 | |||
1737 | renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? "m" : "x", LLColor4(text_highlight, text_highlight, text_highlight, alpha)); | ||
1738 | } | ||
1739 | } | ||
1740 | |||
1741 | // label ticks on opposite side | ||
1742 | if (mScaleSnapUnit2 != mScaleSnapUnit1) | ||
1743 | { | ||
1744 | start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2)); | ||
1745 | stop_tick = llmin(max_ticks2, num_ticks_per_side2); | ||
1746 | for (S32 i = start_tick; i <= stop_tick; i++) | ||
1747 | { | ||
1748 | F32 tick_scale = 1.f; | ||
1749 | F32 alpha = grid_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side2))); | ||
1750 | LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2)); | ||
1751 | |||
1752 | for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) | ||
1753 | { | ||
1754 | if (fmodf((F32)(i + label_sub_div_offset_2), division_level) == 0.f) | ||
1755 | { | ||
1756 | break; | ||
1757 | } | ||
1758 | tick_scale *= 0.7f; | ||
1759 | } | ||
1760 | |||
1761 | if (fmodf((F32)(i + label_sub_div_offset_2), (max_subdivisions / llmin(max_subdivisions, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, tick_label_spacing)))) == 0.f) | ||
1762 | { | ||
1763 | LLVector3 text_origin = tick_pos + | ||
1764 | (mSnapGuideDir2 * mSnapRegimeOffset * (1.f + tick_scale)); | ||
1765 | |||
1766 | EGridMode grid_mode = gSelectMgr->getGridMode(); | ||
1767 | F32 tick_val; | ||
1768 | if (grid_mode == GRID_MODE_WORLD) | ||
1769 | { | ||
1770 | tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 / grid_resolution); | ||
1771 | } | ||
1772 | else | ||
1773 | { | ||
1774 | tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 * 2.f); | ||
1775 | } | ||
1776 | |||
1777 | if (getUniform()) | ||
1778 | { | ||
1779 | tick_val *= 2.f; | ||
1780 | } | ||
1781 | |||
1782 | F32 text_highlight = 0.8f; | ||
1783 | |||
1784 | if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime) | ||
1785 | { | ||
1786 | text_highlight = 1.f; | ||
1787 | } | ||
1788 | |||
1789 | renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? "m" : "x", LLColor4(text_highlight, text_highlight, text_highlight, alpha)); | ||
1790 | } | ||
1791 | } | ||
1792 | } | ||
1793 | |||
1794 | |||
1795 | // render help text | ||
1796 | if (gSelectMgr->getSelectType() != SELECT_TYPE_HUD) | ||
1797 | { | ||
1798 | if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText) | ||
1799 | { | ||
1800 | LLVector3 selection_center_start = gSelectMgr->getSavedBBoxOfSelection().getCenterAgent(); | ||
1801 | |||
1802 | LLVector3 offset_dir; | ||
1803 | if (mSnapGuideDir1 * gCamera->getAtAxis() > mSnapGuideDir2 * gCamera->getAtAxis()) | ||
1804 | { | ||
1805 | offset_dir = mSnapGuideDir2; | ||
1806 | } | ||
1807 | else | ||
1808 | { | ||
1809 | offset_dir = mSnapGuideDir1; | ||
1810 | } | ||
1811 | |||
1812 | LLVector3 help_text_pos = selection_center_start + (mSnapRegimeOffset * 5.f * offset_dir); | ||
1813 | const LLFontGL* big_fontp = LLFontGL::sSansSerif; | ||
1814 | |||
1815 | std::string help_text = "Move mouse cursor over ruler"; | ||
1816 | LLColor4 help_text_color = LLColor4::white; | ||
1817 | help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, grid_alpha, 0.f); | ||
1818 | 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); | ||
1819 | help_text = "to snap to grid"; | ||
1820 | help_text_pos -= gCamera->getUpAxis() * mSnapRegimeOffset * 0.4f; | ||
1821 | 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); | ||
1822 | } | ||
1823 | } | ||
1824 | } | ||
1825 | } | ||
1826 | |||
1827 | // Returns unit vector in direction of part of an origin-centered cube | ||
1828 | LLVector3 LLManipScale::partToUnitVector( S32 part ) const | ||
1829 | { | ||
1830 | if( (LL_FACE_MIN <= part) && (part <= LL_FACE_MAX) ) | ||
1831 | { | ||
1832 | return faceToUnitVector( part ); | ||
1833 | } | ||
1834 | else | ||
1835 | if( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) ) | ||
1836 | { | ||
1837 | return cornerToUnitVector( part ); | ||
1838 | } | ||
1839 | else | ||
1840 | if( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX ) ) | ||
1841 | { | ||
1842 | return edgeToUnitVector( part ); | ||
1843 | } | ||
1844 | return LLVector3(); | ||
1845 | } | ||
1846 | |||
1847 | |||
1848 | // Returns unit vector in direction of face of an origin-centered cube | ||
1849 | LLVector3 LLManipScale::faceToUnitVector( S32 part ) const | ||
1850 | { | ||
1851 | llassert( (LL_FACE_MIN <= part) && (part <= LL_FACE_MAX) ); | ||
1852 | switch( part ) | ||
1853 | { | ||
1854 | case LL_FACE_POSX: | ||
1855 | return LLVector3( 1.f, 0.f, 0.f ); | ||
1856 | |||
1857 | case LL_FACE_NEGX: | ||
1858 | return LLVector3( -1.f, 0.f, 0.f ); | ||
1859 | |||
1860 | case LL_FACE_POSY: | ||
1861 | return LLVector3( 0.f, 1.f, 0.f ); | ||
1862 | |||
1863 | case LL_FACE_NEGY: | ||
1864 | return LLVector3( 0.f, -1.f, 0.f ); | ||
1865 | |||
1866 | case LL_FACE_POSZ: | ||
1867 | return LLVector3( 0.f, 0.f, 1.f ); | ||
1868 | |||
1869 | case LL_FACE_NEGZ: | ||
1870 | return LLVector3( 0.f, 0.f, -1.f ); | ||
1871 | } | ||
1872 | return LLVector3(); | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | // Returns unit vector in direction of corner of an origin-centered cube | ||
1877 | LLVector3 LLManipScale::cornerToUnitVector( S32 part ) const | ||
1878 | { | ||
1879 | llassert( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) ); | ||
1880 | LLVector3 vec; | ||
1881 | switch(part) | ||
1882 | { | ||
1883 | case LL_CORNER_NNN: | ||
1884 | vec.setVec(-F_SQRT3, -F_SQRT3, -F_SQRT3); | ||
1885 | break; | ||
1886 | case LL_CORNER_NNP: | ||
1887 | vec.setVec(-F_SQRT3, -F_SQRT3, F_SQRT3); | ||
1888 | break; | ||
1889 | case LL_CORNER_NPN: | ||
1890 | vec.setVec(-F_SQRT3, F_SQRT3, -F_SQRT3); | ||
1891 | break; | ||
1892 | case LL_CORNER_NPP: | ||
1893 | vec.setVec(-F_SQRT3, F_SQRT3, F_SQRT3); | ||
1894 | break; | ||
1895 | case LL_CORNER_PNN: | ||
1896 | vec.setVec(F_SQRT3, -F_SQRT3, -F_SQRT3); | ||
1897 | break; | ||
1898 | case LL_CORNER_PNP: | ||
1899 | vec.setVec(F_SQRT3, -F_SQRT3, F_SQRT3); | ||
1900 | break; | ||
1901 | case LL_CORNER_PPN: | ||
1902 | vec.setVec(F_SQRT3, F_SQRT3, -F_SQRT3); | ||
1903 | break; | ||
1904 | case LL_CORNER_PPP: | ||
1905 | vec.setVec(F_SQRT3, F_SQRT3, F_SQRT3); | ||
1906 | break; | ||
1907 | default: | ||
1908 | vec.clearVec(); | ||
1909 | } | ||
1910 | |||
1911 | return vec; | ||
1912 | } | ||
1913 | |||
1914 | // Returns unit vector in direction of edge of an origin-centered cube | ||
1915 | LLVector3 LLManipScale::edgeToUnitVector( S32 part ) const | ||
1916 | { | ||
1917 | llassert( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX) ); | ||
1918 | part -= LL_EDGE_MIN; | ||
1919 | S32 rotation = part >> 2; // Edge between which faces: 0 => XY, 1 => YZ, 2 => ZX | ||
1920 | LLVector3 v; | ||
1921 | v.mV[rotation] = (part & 1) ? F_SQRT2 : -F_SQRT2; | ||
1922 | v.mV[(rotation+1) % 3] = (part & 2) ? F_SQRT2 : -F_SQRT2; | ||
1923 | // v.mV[(rotation+2) % 3] defaults to 0. | ||
1924 | return v; | ||
1925 | } | ||
1926 | |||
1927 | // Non-linear scale of origin-centered unit cube to non-origin-centered, non-symetrical bounding box | ||
1928 | LLVector3 LLManipScale::unitVectorToLocalBBoxExtent( const LLVector3& v, const LLBBox& bbox ) const | ||
1929 | { | ||
1930 | const LLVector3& min = bbox.getMinLocal(); | ||
1931 | const LLVector3& max = bbox.getMaxLocal(); | ||
1932 | LLVector3 ctr = bbox.getCenterLocal(); | ||
1933 | |||
1934 | return LLVector3( | ||
1935 | v.mV[0] ? (v.mV[0]>0 ? max.mV[0] : min.mV[0] ) : ctr.mV[0], | ||
1936 | v.mV[1] ? (v.mV[1]>0 ? max.mV[1] : min.mV[1] ) : ctr.mV[1], | ||
1937 | v.mV[2] ? (v.mV[2]>0 ? max.mV[2] : min.mV[2] ) : ctr.mV[2] ); | ||
1938 | } | ||
1939 | |||
1940 | // returns max allowable scale along a given stretch axis | ||
1941 | F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const | ||
1942 | { | ||
1943 | F32 max_scale_factor = 0.f; | ||
1944 | LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); | ||
1945 | bbox_extents.abs(); | ||
1946 | F32 max_extent = 0.f; | ||
1947 | for (U32 i = VX; i <= VZ; i++) | ||
1948 | { | ||
1949 | if (bbox_extents.mV[i] > max_extent) | ||
1950 | { | ||
1951 | max_extent = bbox_extents.mV[i]; | ||
1952 | } | ||
1953 | } | ||
1954 | max_scale_factor = bbox_extents.magVec() * MAX_OBJECT_SCALE / max_extent; | ||
1955 | |||
1956 | if (getUniform()) | ||
1957 | { | ||
1958 | max_scale_factor *= 0.5f; | ||
1959 | } | ||
1960 | |||
1961 | return max_scale_factor; | ||
1962 | } | ||
1963 | |||
1964 | // returns min allowable scale along a given stretch axis | ||
1965 | F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const | ||
1966 | { | ||
1967 | LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); | ||
1968 | bbox_extents.abs(); | ||
1969 | F32 min_extent = MAX_OBJECT_SCALE; | ||
1970 | for (U32 i = VX; i <= VZ; i++) | ||
1971 | { | ||
1972 | if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) | ||
1973 | { | ||
1974 | min_extent = bbox_extents.mV[i]; | ||
1975 | } | ||
1976 | } | ||
1977 | F32 min_scale_factor = bbox_extents.magVec() * MIN_OBJECT_SCALE / min_extent; | ||
1978 | |||
1979 | if (getUniform()) | ||
1980 | { | ||
1981 | min_scale_factor *= 0.5f; | ||
1982 | } | ||
1983 | |||
1984 | return min_scale_factor; | ||
1985 | } | ||
1986 | |||
1987 | // Returns the axis aligned unit vector closest to v. | ||
1988 | LLVector3 LLManipScale::nearestAxis( const LLVector3& v ) const | ||
1989 | { | ||
1990 | // Note: yes, this is a slow but easy implementation | ||
1991 | // assumes v is normalized | ||
1992 | |||
1993 | F32 coords[][3] = | ||
1994 | { | ||
1995 | { 1.f, 0.f, 0.f }, | ||
1996 | { 0.f, 1.f, 0.f }, | ||
1997 | { 0.f, 0.f, 1.f }, | ||
1998 | {-1.f, 0.f, 0.f }, | ||
1999 | { 0.f,-1.f, 0.f }, | ||
2000 | { 0.f, 0.f,-1.f } | ||
2001 | }; | ||
2002 | |||
2003 | F32 cosine[6]; | ||
2004 | cosine[0] = v * LLVector3( coords[0] ); | ||
2005 | cosine[1] = v * LLVector3( coords[1] ); | ||
2006 | cosine[2] = v * LLVector3( coords[2] ); | ||
2007 | cosine[3] = -cosine[0]; | ||
2008 | cosine[4] = -cosine[1]; | ||
2009 | cosine[5] = -cosine[2]; | ||
2010 | |||
2011 | F32 greatest_cos = cosine[0]; | ||
2012 | S32 greatest_index = 0; | ||
2013 | for( S32 i=1; i<6; i++ ) | ||
2014 | { | ||
2015 | if( greatest_cos < cosine[i] ) | ||
2016 | { | ||
2017 | greatest_cos = cosine[i]; | ||
2018 | greatest_index = i; | ||
2019 | } | ||
2020 | } | ||
2021 | |||
2022 | return LLVector3( coords[greatest_index] ); | ||
2023 | } | ||
2024 | |||
2025 | BOOL LLManipScale::isSelectionScalable() const | ||
2026 | { | ||
2027 | // An selection is scalable if you are allowed to both edit and move | ||
2028 | // everything in it, and it does not have any sitting agents | ||
2029 | BOOL scalable = gSelectMgr->getFirstObject() ? TRUE : FALSE; | ||
2030 | for(LLViewerObject* cur = gSelectMgr->getFirstObject(); | ||
2031 | cur; | ||
2032 | cur = gSelectMgr->getNextObject() ) | ||
2033 | { | ||
2034 | if( !(cur->permModify() && cur->permMove()) | ||
2035 | || cur->isSeat()) | ||
2036 | { | ||
2037 | scalable = FALSE; | ||
2038 | break; | ||
2039 | } | ||
2040 | } | ||
2041 | return scalable; | ||
2042 | } | ||