aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden
diff options
context:
space:
mode:
authorJacek Antonelli2010-10-21 22:13:28 -0500
committerMcCabe Maxsted2010-10-23 18:47:52 -0700
commit36c25f06e38e357716ecd31df58d70b92a3d8e0e (patch)
treec47616efa283bf55484a6b59715dc1f3c6c56aa4 /linden
parentMerge remote branch 'jacek/weekly' into weekly (diff)
downloadmeta-impy-36c25f06e38e357716ecd31df58d70b92a3d8e0e.zip
meta-impy-36c25f06e38e357716ecd31df58d70b92a3d8e0e.tar.gz
meta-impy-36c25f06e38e357716ecd31df58d70b92a3d8e0e.tar.bz2
meta-impy-36c25f06e38e357716ecd31df58d70b92a3d8e0e.tar.xz
Prim alignment tool by Qarl, backported by Jacek.
Qarl has given permission to use this code under the terms of the GPL v2 + FLOSS exception and/or the LGPL v2.1.
Diffstat (limited to 'linden')
-rw-r--r--linden/indra/newview/CMakeLists.txt2
-rw-r--r--linden/indra/newview/llfloatertools.cpp6
-rw-r--r--linden/indra/newview/llfloatertools.h1
-rw-r--r--linden/indra/newview/qtoolalign.cpp585
-rw-r--r--linden/indra/newview/qtoolalign.h50
-rw-r--r--linden/indra/newview/skins/default/xui/en-us/floater_tools.xml3
6 files changed, 646 insertions, 1 deletions
diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt
index dfd35bf..1a6ad30 100644
--- a/linden/indra/newview/CMakeLists.txt
+++ b/linden/indra/newview/CMakeLists.txt
@@ -484,6 +484,7 @@ set(viewer_SOURCE_FILES
484 panelradarentry.cpp 484 panelradarentry.cpp
485 pipeline.cpp 485 pipeline.cpp
486 primbackup.cpp 486 primbackup.cpp
487 qtoolalign.cpp
487 rlvhandler.cpp 488 rlvhandler.cpp
488 rlvhelper.cpp 489 rlvhelper.cpp
489 rlvcommon.cpp 490 rlvcommon.cpp
@@ -936,6 +937,7 @@ set(viewer_HEADER_FILES
936 panelradarentry.h 937 panelradarentry.h
937 pipeline.h 938 pipeline.h
938 primbackup.h 939 primbackup.h
940 qtoolalign.h
939 randgauss.h 941 randgauss.h
940 rlvdefines.h 942 rlvdefines.h
941 rlvhandler.h 943 rlvhandler.h
diff --git a/linden/indra/newview/llfloatertools.cpp b/linden/indra/newview/llfloatertools.cpp
index fc72467..daff573 100644
--- a/linden/indra/newview/llfloatertools.cpp
+++ b/linden/indra/newview/llfloatertools.cpp
@@ -84,7 +84,7 @@
84#include "llvograss.h" 84#include "llvograss.h"
85#include "llvotree.h" 85#include "llvotree.h"
86#include "lluictrlfactory.h" 86#include "lluictrlfactory.h"
87 87#include "qtoolalign.h"
88#include "hippoLimits.h" 88#include "hippoLimits.h"
89 89
90// Globals 90// Globals
@@ -273,6 +273,8 @@ BOOL LLFloaterTools::postBuild()
273 childSetCommitCallback("radio stretch",commit_select_tool,LLToolCompScale::getInstance()); 273 childSetCommitCallback("radio stretch",commit_select_tool,LLToolCompScale::getInstance());
274 mRadioSelectFace = getChild<LLCheckBoxCtrl>("radio select face"); 274 mRadioSelectFace = getChild<LLCheckBoxCtrl>("radio select face");
275 childSetCommitCallback("radio select face",commit_select_tool,LLToolFace::getInstance()); 275 childSetCommitCallback("radio select face",commit_select_tool,LLToolFace::getInstance());
276 mRadioAlign = getChild<LLCheckBoxCtrl>("radio align");
277 childSetCommitCallback("radio align",commit_select_tool,QToolAlign::getInstance());
276 mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts"); 278 mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts");
277 childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts")); 279 childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts"));
278 childSetCommitCallback("checkbox edit linked parts",commit_select_component,this); 280 childSetCommitCallback("checkbox edit linked parts",commit_select_component,this);
@@ -698,6 +700,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
698 tool == LLToolCompScale::getInstance() || 700 tool == LLToolCompScale::getInstance() ||
699 tool == LLToolFace::getInstance() || 701 tool == LLToolFace::getInstance() ||
700 tool == LLToolIndividual::getInstance() || 702 tool == LLToolIndividual::getInstance() ||
703 tool == QToolAlign::getInstance() ||
701 tool == LLToolPipette::getInstance(); 704 tool == LLToolPipette::getInstance();
702 705
703 mBtnEdit ->setToggleState( edit_visible ); 706 mBtnEdit ->setToggleState( edit_visible );
@@ -720,6 +723,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
720 mRadioPosition ->set( tool == LLToolCompTranslate::getInstance() ); 723 mRadioPosition ->set( tool == LLToolCompTranslate::getInstance() );
721 mRadioRotate ->set( tool == LLToolCompRotate::getInstance() ); 724 mRadioRotate ->set( tool == LLToolCompRotate::getInstance() );
722 mRadioStretch ->set( tool == LLToolCompScale::getInstance() ); 725 mRadioStretch ->set( tool == LLToolCompScale::getInstance() );
726 mRadioAlign->set( tool == QToolAlign::getInstance() );
723 727
724 if (mComboGridMode) 728 if (mComboGridMode)
725 { 729 {
diff --git a/linden/indra/newview/llfloatertools.h b/linden/indra/newview/llfloatertools.h
index ad5be6c..bbf07ec 100644
--- a/linden/indra/newview/llfloatertools.h
+++ b/linden/indra/newview/llfloatertools.h
@@ -140,6 +140,7 @@ public:
140 LLCheckBoxCtrl *mRadioRotate; 140 LLCheckBoxCtrl *mRadioRotate;
141 LLCheckBoxCtrl *mRadioStretch; 141 LLCheckBoxCtrl *mRadioStretch;
142 LLCheckBoxCtrl *mRadioSelectFace; 142 LLCheckBoxCtrl *mRadioSelectFace;
143 LLCheckBoxCtrl *mRadioAlign;
143 144
144 LLCheckBoxCtrl *mCheckSelectIndividual; 145 LLCheckBoxCtrl *mCheckSelectIndividual;
145 146
diff --git a/linden/indra/newview/qtoolalign.cpp b/linden/indra/newview/qtoolalign.cpp
new file mode 100644
index 0000000..92cab6e
--- /dev/null
+++ b/linden/indra/newview/qtoolalign.cpp
@@ -0,0 +1,585 @@
1/**
2 * @file qtoolalign.cpp
3 * @brief A tool to align objects
4 * @author Karl Stiefvater (Qarl)
5 *
6 * Karl has given permission to use this code under the terms of
7 * the GNU GPL v2 plus FLOSS exception and/or the GNU LGPL v2.1.
8 *
9 * Backported for Viewer 1.X code base by Jacek Antonelli.
10 */
11
12#include "llviewerprecompiledheaders.h"
13
14// File includes
15#include "qtoolalign.h"
16
17// Library includes
18#include "llbbox.h"
19#include "v3math.h"
20
21// Viewer includes
22#include "llagent.h"
23#include "llbox.h"
24#include "llcylinder.h"
25#include "llfloatertools.h"
26#include "llselectmgr.h"
27#include "llviewercamera.h"
28#include "llviewercontrol.h"
29#include "llviewerobject.h"
30#include "llviewerwindow.h"
31
32
33const F32 MANIPULATOR_SIZE = 5.0;
34const F32 MANIPULATOR_SELECT_SIZE = 20.0;
35
36
37
38QToolAlign::QToolAlign()
39: LLTool(std::string("Align"))
40{
41}
42
43
44QToolAlign::~QToolAlign()
45{
46}
47
48
49
50BOOL QToolAlign::handleMouseDown(S32 x, S32 y, MASK mask)
51{
52 if (mHighlightedAxis != -1)
53 {
54 align();
55 }
56 else
57 {
58 gViewerWindow->pickAsync(x, y, mask, pickCallback);
59 }
60
61 return TRUE;
62}
63
64
65
66void QToolAlign::pickCallback(const LLPickInfo& pick_info)
67{
68 LLViewerObject* object = pick_info.getObject();
69
70 if (object)
71 {
72 if (object->isAvatar())
73 {
74 return;
75 }
76
77 if (pick_info.mKeyMask & MASK_SHIFT)
78 {
79 // If object not selected, select it
80 if ( !object->isSelected() )
81 {
82 LLSelectMgr::getInstance()->selectObjectAndFamily(object);
83 }
84 else
85 {
86 LLSelectMgr::getInstance()->deselectObjectAndFamily(object);
87 }
88 }
89 else
90 {
91 LLSelectMgr::getInstance()->deselectAll();
92 LLSelectMgr::getInstance()->selectObjectAndFamily(object);
93 }
94
95 }
96 else
97 {
98 if (!(pick_info.mKeyMask == MASK_SHIFT))
99 {
100 LLSelectMgr::getInstance()->deselectAll();
101 }
102 }
103
104 LLSelectMgr::getInstance()->promoteSelectionToRoot();
105}
106
107
108
109void QToolAlign::handleSelect()
110{
111 // no parts, please
112
113 llwarns << "in select" << llendl;
114 LLSelectMgr::getInstance()->promoteSelectionToRoot();
115}
116
117
118void QToolAlign::handleDeselect()
119{
120}
121
122
123BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y)
124{
125 mHighlightedAxis = -1;
126 mHighlightedDirection = 0;
127
128 LLMatrix4 transform;
129 if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD)
130 {
131 LLVector4 translation(mBBox.getCenterAgent());
132 transform.initRotTrans(mBBox.getRotation(), translation);
133 LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
134 transform *= cfr;
135 LLMatrix4 window_scale;
136 F32 zoom_level = 2.f * gAgent.mHUDCurZoom;
137 window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f),
138 LLQuaternion::DEFAULT,
139 LLVector3::zero);
140 transform *= window_scale;
141 }
142 else
143 {
144 transform.initAll(LLVector3(1.f, 1.f, 1.f), mBBox.getRotation(), mBBox.getCenterAgent());
145
146 LLMatrix4 projection_matrix = LLViewerCamera::getInstance()->getProjection();
147 LLMatrix4 model_matrix = LLViewerCamera::getInstance()->getModelview();
148
149 transform *= model_matrix;
150 transform *= projection_matrix;
151 }
152
153
154 //LLRect world_view_rect = getWorldViewRectScaled();
155 F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f;
156 F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f;
157 LLVector2 manip2d;
158 LLVector2 mousePos((F32)x - half_width, (F32)y - half_height);
159 LLVector2 delta;
160
161 LLVector3 bbox_scale = mBBox.getMaxLocal() - mBBox.getMinLocal();
162
163 for (S32 axis = VX; axis <= VZ; axis++)
164 {
165 for (F32 direction = -1.0; direction <= 1.0; direction += 2.0)
166 {
167 LLVector3 axis_vector = LLVector3(0,0,0);
168 axis_vector.mV[axis] = direction * bbox_scale.mV[axis] / 2.0;
169
170 LLVector4 manipulator_center = LLVector4(axis_vector);
171
172 LLVector4 screen_center = manipulator_center * transform;
173 screen_center /= screen_center.mV[VW];
174
175 manip2d.setVec(screen_center.mV[VX] * half_width, screen_center.mV[VY] * half_height);
176
177 delta = manip2d - mousePos;
178
179 if (delta.magVecSquared() < MANIPULATOR_SELECT_SIZE * MANIPULATOR_SELECT_SIZE)
180 {
181 mHighlightedAxis = axis;
182 mHighlightedDirection = direction;
183 return TRUE;
184 }
185
186 }
187 }
188
189 return FALSE;
190}
191
192
193BOOL QToolAlign::handleHover(S32 x, S32 y, MASK mask)
194{
195 if (mask & MASK_SHIFT)
196 {
197 mForce = FALSE;
198 }
199 else
200 {
201 mForce = TRUE;
202 }
203
204 gViewerWindow->setCursor(UI_CURSOR_ARROW);
205 return findSelectedManipulator(x, y);
206}
207
208
209
210void setup_transforms_bbox(LLBBox bbox)
211{
212 // translate to center
213 LLVector3 center = bbox.getCenterAgent();
214 gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
215
216 // rotate
217 LLQuaternion rotation = bbox.getRotation();
218 F32 angle_radians, x, y, z;
219 rotation.getAngleAxis(&angle_radians, &x, &y, &z);
220 // gGL has no rotate method (despite having translate and scale) presumably because
221 // its authors smoke crack. so we hack.
222 gGL.flush();
223 glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
224
225 // scale
226 LLVector3 scale = bbox.getMaxLocal() - bbox.getMinLocal();
227 gGL.scalef(scale.mV[VX], scale.mV[VY], scale.mV[VZ]);
228}
229
230
231void render_bbox(LLBBox bbox)
232{
233 glMatrixMode(GL_MODELVIEW);
234 gGL.pushMatrix();
235
236 setup_transforms_bbox(bbox);
237
238 gGL.flush();
239 gBox.render();
240
241 gGL.popMatrix();
242}
243
244void render_cone_bbox(LLBBox bbox)
245{
246 glMatrixMode(GL_MODELVIEW);
247 gGL.pushMatrix();
248
249 setup_transforms_bbox(bbox);
250
251 gGL.flush();
252 gCone.render(CONE_LOD_HIGHEST);
253
254 gGL.popMatrix();
255}
256
257
258
259// the selection bbox isn't axis aligned, so we must construct one
260// should this be cached in the selection manager? yes.
261LLBBox get_selection_axis_aligned_bbox()
262{
263 LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
264 LLVector3 position = selection_bbox.getPositionAgent();
265
266 LLBBox axis_aligned_bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3());
267 axis_aligned_bbox.addPointLocal(LLVector3());
268
269 // cycle over the nodes in selection
270 for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin();
271 selection_iter != LLSelectMgr::getInstance()->getSelection()->end();
272 ++selection_iter)
273 {
274 LLSelectNode *select_node = *selection_iter;
275 if (select_node)
276 {
277 LLViewerObject* object = select_node->getObject();
278 if (object)
279 {
280 axis_aligned_bbox.addBBoxAgent(object->getBoundingBoxAgent());
281 }
282 }
283 }
284
285
286 return axis_aligned_bbox;
287}
288
289
290
291void QToolAlign::computeManipulatorSize()
292{
293 if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD)
294 {
295 mManipulatorSize = MANIPULATOR_SIZE / (LLViewerCamera::getInstance()->getViewHeightInPixels() *
296 gAgent.mHUDCurZoom);
297 }
298 else
299 {
300 F32 distance = dist_vec(gAgent.getCameraPositionAgent(), mBBox.getCenterAgent());
301
302 if (distance > 0.001f)
303 {
304 // range != zero
305 F32 fraction_of_fov = MANIPULATOR_SIZE /LLViewerCamera::getInstance()->getViewHeightInPixels();
306 F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians
307 mManipulatorSize = MANIPULATOR_SIZE * distance * tan(apparent_angle);
308 }
309 else
310 {
311 // range == zero
312 mManipulatorSize = MANIPULATOR_SIZE;
313 }
314 }
315}
316
317
318LLColor4 manipulator_color[3] = { LLColor4(0.7f, 0.0f, 0.0f, 0.5f),
319 LLColor4(0.0f, 0.7f, 0.0f, 0.5f),
320 LLColor4(0.0f, 0.0f, 0.7f, 0.5f) };
321
322
323void QToolAlign::renderManipulators()
324{
325 computeManipulatorSize();
326 LLVector3 bbox_center = mBBox.getCenterAgent();
327 LLVector3 bbox_scale = mBBox.getMaxLocal() - mBBox.getMinLocal();
328
329 for (S32 axis = VX; axis <= VZ; axis++)
330 for (F32 direction = -1.0; direction <= 1.0; direction += 2.0)
331 {
332 F32 size = mManipulatorSize;
333 LLColor4 color = manipulator_color[axis];
334
335 if ((axis == mHighlightedAxis) && (direction == mHighlightedDirection))
336 {
337 size *= 2.0;
338 color *= 1.5;
339 }
340
341 S32 arrows = 1;
342 if (mForce)
343 {
344 arrows = 2;
345 }
346
347 for (S32 i = 0; i < arrows; i++)
348 {
349 LLVector3 axis_vector = LLVector3(0,0,0);
350 axis_vector.mV[axis] = direction * (bbox_scale.mV[axis] / 2.0 + i * (size/3.0));
351
352 LLVector3 manipulator_center = bbox_center + axis_vector;
353
354 LLQuaternion manipulator_rotation;
355 manipulator_rotation.shortestArc(LLVector3(0,0,1), -1.0 * axis_vector);
356
357 LLBBox manipulator_bbox = LLBBox(manipulator_center, manipulator_rotation,
358 LLVector3(), LLVector3());
359
360 manipulator_bbox.addPointLocal(LLVector3(-1, -1, -0.75) * size * 0.5);
361 manipulator_bbox.addPointLocal(LLVector3(1, 1, 0.75) * size * 0.5);
362
363 gGL.color4fv(color.mV);
364 // sadly, gCone doesn't use gGL like gBox does (presumably because its author smokes crack) so we
365 // also set the raw GL color. hopefully this won't screw-up later rendering.
366 glColor4fv(color.mV);
367
368 render_cone_bbox(manipulator_bbox);
369 }
370 }
371}
372
373
374void QToolAlign::render()
375{
376 mBBox = get_selection_axis_aligned_bbox();
377
378 // Draw bounding box
379 LLGLSUIDefault gls_ui;
380 LLGLEnable gl_blend(GL_BLEND);
381 LLGLEnable gls_alpha_test(GL_ALPHA_TEST);
382 LLGLDepthTest gls_depth(GL_FALSE);
383 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
384
385 // render box
386 LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.1f );
387 gGL.color4fv( default_normal_color.mV );
388
389 render_bbox(mBBox);
390 renderManipulators();
391}
392
393// only works for our specialized (AABB, position centered) bboxes
394BOOL bbox_overlap(LLBBox bbox1, LLBBox bbox2)
395{
396 const F32 FUDGE = 0.001; // because of stupid SL precision/rounding
397
398 LLVector3 delta = bbox1.getCenterAgent() - bbox2.getCenterAgent();
399
400 LLVector3 half_extent = (bbox1.getExtentLocal() + bbox2.getExtentLocal()) / 2.0;
401
402 return ((fabs(delta.mV[VX]) < half_extent.mV[VX] - FUDGE) &&
403 (fabs(delta.mV[VY]) < half_extent.mV[VY] - FUDGE) &&
404 (fabs(delta.mV[VZ]) < half_extent.mV[VZ] - FUDGE));
405}
406
407
408
409// used to sort bboxes before packing
410class BBoxCompare
411{
412public:
413 BBoxCompare(S32 axis, F32 direction, std::map<LLPointer<LLViewerObject>, LLBBox >& bboxes) :
414 mAxis(axis), mDirection(direction), mBBoxes(bboxes) {}
415
416 BOOL operator() (LLViewerObject* object1, LLViewerObject* object2)
417 {
418 LLVector3 corner1 = mBBoxes[object1].getCenterAgent() -
419 mDirection * mBBoxes[object1].getExtentLocal()/2.0;
420
421 LLVector3 corner2 = mBBoxes[object2].getCenterAgent() -
422 mDirection * mBBoxes[object2].getExtentLocal()/2.0;
423
424
425 return mDirection * corner1.mV[mAxis] < mDirection * corner2.mV[mAxis];
426 }
427
428 S32 mAxis;
429 F32 mDirection;
430 std::map<LLPointer<LLViewerObject>, LLBBox >& mBBoxes;
431};
432
433
434void QToolAlign::align()
435{
436 // no linkset parts, please
437 LLSelectMgr::getInstance()->promoteSelectionToRoot();
438
439 std::vector<LLPointer<LLViewerObject> > objects;
440 std::map<LLPointer<LLViewerObject>, LLBBox > original_bboxes;
441
442 // cycle over the nodes in selection and collect them into an array
443 for (LLObjectSelection::root_iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
444 selection_iter != LLSelectMgr::getInstance()->getSelection()->root_end();
445 ++selection_iter)
446 {
447 LLSelectNode *select_node = *selection_iter;
448 if (select_node)
449 {
450 LLViewerObject* object = select_node->getObject();
451 if (object)
452 {
453 LLVector3 position = object->getPositionAgent();
454
455 LLBBox bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3());
456 bbox.addPointLocal(LLVector3());
457
458 // add the parent's bbox
459 bbox.addBBoxAgent(object->getBoundingBoxAgent());
460 LLViewerObject::const_child_list_t& children = object->getChildren();
461
462 for (LLViewerObject::const_child_list_t::const_iterator i = children.begin();
463 i != children.end(); i++)
464 {
465 // add the child's bbox
466 LLViewerObject* child = *i;
467 bbox.addBBoxAgent(child->getBoundingBoxAgent());
468 }
469
470 objects.push_back(object);
471 original_bboxes[object] = bbox;
472 }
473 }
474 }
475
476 S32 axis = mHighlightedAxis;
477 F32 direction = mHighlightedDirection;
478
479 // sort them into positional order for proper packing
480 BBoxCompare compare(axis, direction, original_bboxes);
481 sort(objects.begin(), objects.end(), compare);
482
483 // storage for their new position after alignment - start with original position first
484 std::map<LLPointer<LLViewerObject>, LLBBox > new_bboxes = original_bboxes;
485
486 // find new positions
487 for (S32 i = 0; i < objects.size(); i++)
488 {
489 LLBBox target_bbox = mBBox;
490 LLVector3 target_corner = target_bbox.getCenterAgent() -
491 direction * target_bbox.getExtentLocal() / 2.0;
492
493 LLViewerObject* object = objects[i];
494
495 LLBBox this_bbox = original_bboxes[object];
496 LLVector3 this_corner = this_bbox.getCenterAgent() -
497 direction * this_bbox.getExtentLocal() / 2.0;
498
499 // for packing, we cycle over several possible positions, taking the smallest that does not overlap
500 F32 smallest = direction * 9999999; // 999999 guarenteed not to be the smallest
501 for (S32 j = 0; j <= i; j++)
502 {
503 // how far must it move?
504 LLVector3 delta = target_corner - this_corner;
505
506 // new position moves only on one axis, please
507 LLVector3 delta_one_axis = LLVector3(0,0,0);
508 delta_one_axis.mV[axis] = delta.mV[axis];
509
510 LLVector3 new_position = this_bbox.getCenterAgent() + delta_one_axis;
511
512 // construct the new bbox
513 LLBBox new_bbox = LLBBox(new_position, LLQuaternion(), LLVector3(), LLVector3());
514 new_bbox.addPointLocal(this_bbox.getExtentLocal() / 2.0);
515 new_bbox.addPointLocal(-1.0 * this_bbox.getExtentLocal() / 2.0);
516
517 // check to see if it overlaps the previously placed objects
518 BOOL overlap = FALSE;
519
520 llwarns << "i=" << i << " j=" << j << llendl;
521
522 if (!mForce) // well, don't check if in force mode
523 {
524 for (S32 k = 0; k < i; k++)
525 {
526 LLViewerObject* other_object = objects[k];
527 LLBBox other_bbox = new_bboxes[other_object];
528
529 BOOL overlaps_this = bbox_overlap(other_bbox, new_bbox);
530
531 if (overlaps_this)
532 {
533 llwarns << "overlap" << new_bbox.getCenterAgent() << other_bbox.getCenterAgent() << llendl;
534 llwarns << "extent" << new_bbox.getExtentLocal() << other_bbox.getExtentLocal() << llendl;
535 }
536
537 overlap = (overlap || overlaps_this);
538 }
539 }
540
541 if (!overlap)
542 {
543 F32 this_value = (new_bbox.getCenterAgent() -
544 direction * new_bbox.getExtentLocal() / 2.0).mV[axis];
545
546 if (direction * this_value < direction * smallest)
547 {
548 smallest = this_value;
549 // store it
550 new_bboxes[object] = new_bbox;
551 }
552 }
553
554 // update target for next time through the loop
555 if (j < objects.size())
556 {
557 LLBBox next_bbox = new_bboxes[objects[j]];
558 target_corner = next_bbox.getCenterAgent() +
559 direction * next_bbox.getExtentLocal() / 2.0;
560 }
561 }
562 }
563
564
565 // now move them
566 for (S32 i = 0; i < objects.size(); i++)
567 {
568 LLViewerObject* object = objects[i];
569
570 LLBBox original_bbox = original_bboxes[object];
571 LLBBox new_bbox = new_bboxes[object];
572
573 LLVector3 delta = new_bbox.getCenterAgent() - original_bbox.getCenterAgent();
574
575 LLVector3 original_position = object->getPositionAgent();
576 LLVector3 new_position = original_position + delta;
577
578 object->setPosition(new_position);
579 }
580
581
582 LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
583}
584
585
diff --git a/linden/indra/newview/qtoolalign.h b/linden/indra/newview/qtoolalign.h
new file mode 100644
index 0000000..b2c18b7
--- /dev/null
+++ b/linden/indra/newview/qtoolalign.h
@@ -0,0 +1,50 @@
1/**
2 * @file qtoolalign.h
3 * @brief A tool to align objects
4 * @author Karl Stiefvater (Qarl)
5 *
6 * Karl has given permission to use this code under the terms of
7 * the GNU GPL v2 plus FLOSS exception and/or the GNU LGPL v2.1.
8 *
9 * Backported for Viewer 1.X code base by Jacek Antonelli.
10 */
11
12#ifndef Q_QTOOLALIGN_H
13#define Q_QTOOLALIGN_H
14
15#include "lltool.h"
16#include "llbbox.h"
17
18class LLViewerObject;
19class LLPickInfo;
20class LLToolSelectRect;
21
22class QToolAlign
23: public LLTool, public LLSingleton<QToolAlign>
24{
25public:
26 QToolAlign();
27 virtual ~QToolAlign();
28
29 virtual void handleSelect();
30 virtual void handleDeselect();
31 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
32 virtual BOOL handleHover(S32 x, S32 y, MASK mask);
33 virtual void render();
34
35 static void pickCallback(const LLPickInfo& pick_info);
36
37private:
38 void align();
39 void computeManipulatorSize();
40 void renderManipulators();
41 BOOL findSelectedManipulator(S32 x, S32 y);
42
43 LLBBox mBBox;
44 F32 mManipulatorSize;
45 S32 mHighlightedAxis;
46 F32 mHighlightedDirection;
47 BOOL mForce;
48};
49
50#endif // Q_QTOOLALIGN_H
diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
index 3e0a5fa..7438329 100644
--- a/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
+++ b/linden/indra/newview/skins/default/xui/en-us/floater_tools.xml
@@ -79,6 +79,9 @@
79 <check_box bottom_delta="-15" follows="left|top" font="SansSerifSmall" height="16" 79 <check_box bottom_delta="-15" follows="left|top" font="SansSerifSmall" height="16"
80 initial_value="false" label="Select faces to texture" left="4" mouse_opaque="true" 80 initial_value="false" label="Select faces to texture" left="4" mouse_opaque="true"
81 name="radio select face" radio_style="true" width="114" /> 81 name="radio select face" radio_style="true" width="114" />
82 <check_box bottom_delta="-15" follows="left|top" font="SansSerifSmall" height="16"
83 initial_value="false" label="Align" left="4" mouse_opaque="true"
84 name="radio align" radio_style="true" width="114" />
82 <check_box bottom_delta="-19" control_name="EditLinkedParts" follows="left|top" 85 <check_box bottom_delta="-19" control_name="EditLinkedParts" follows="left|top"
83 font="SansSerifSmall" height="16" initial_value="false" 86 font="SansSerifSmall" height="16" initial_value="false"
84 label="Edit linked parts" left="4" mouse_opaque="true" 87 label="Edit linked parts" left="4" mouse_opaque="true"