aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpanelobject.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llpanelobject.cpp
parentREADME.txt (diff)
downloadmeta-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/llpanelobject.cpp')
-rw-r--r--linden/indra/newview/llpanelobject.cpp1698
1 files changed, 1698 insertions, 0 deletions
diff --git a/linden/indra/newview/llpanelobject.cpp b/linden/indra/newview/llpanelobject.cpp
new file mode 100644
index 0000000..54e24e2
--- /dev/null
+++ b/linden/indra/newview/llpanelobject.cpp
@@ -0,0 +1,1698 @@
1/**
2 * @file llpanelobject.cpp
3 * @brief Object editing (position, scale, etc.) in the tools floater
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// file include
31#include "llpanelobject.h"
32
33// linden library includes
34#include "lleconomy.h"
35#include "llerror.h"
36#include "llfontgl.h"
37#include "llpermissionsflags.h"
38#include "llstring.h"
39#include "llvolume.h"
40#include "m3math.h"
41
42// project includes
43#include "llagent.h"
44#include "llbutton.h"
45#include "llcheckboxctrl.h"
46#include "llcolorswatch.h"
47#include "llcombobox.h"
48#include "llfocusmgr.h"
49#include "llmanipscale.h"
50#include "llpanelinventory.h"
51#include "llpreviewscript.h"
52#include "llresmgr.h"
53#include "llselectmgr.h"
54#include "llspinctrl.h"
55#include "lltextbox.h"
56#include "lltool.h"
57#include "lltoolcomp.h"
58#include "lltoolmgr.h"
59#include "llui.h"
60#include "llviewerobject.h"
61#include "llviewerregion.h"
62#include "llviewerwindow.h"
63#include "llvovolume.h"
64#include "llworld.h"
65#include "pipeline.h"
66#include "viewer.h"
67#include "llvieweruictrlfactory.h"
68
69#include "lldrawpool.h"
70
71//
72// Constants
73//
74enum {
75 MI_BOX,
76 MI_CYLINDER,
77 MI_PRISM,
78 MI_SPHERE,
79 MI_TORUS,
80 MI_TUBE,
81 MI_RING,
82 MI_NONE,
83 MI_VOLUME_COUNT
84};
85
86enum {
87 MI_HOLE_SAME,
88 MI_HOLE_CIRCLE,
89 MI_HOLE_SQUARE,
90 MI_HOLE_TRIANGLE,
91 MI_HOLE_COUNT
92};
93
94//XUI:translate (depricated, so very low priority)
95static const LLString LEGACY_FULLBRIGHT_DESC("Fullbright (Legacy)");
96
97BOOL LLPanelObject::postBuild()
98{
99 setMouseOpaque(FALSE);
100
101 //--------------------------------------------------------
102 // Top
103 //--------------------------------------------------------
104
105 // Lock checkbox
106 mCheckLock = gUICtrlFactory->getCheckBoxByName(this,"checkbox locked");
107 childSetCommitCallback("checkbox locked",onCommitLock,this);
108
109 // Physical checkbox
110 mCheckPhysics = gUICtrlFactory->getCheckBoxByName(this,"Physical Checkbox Ctrl");
111 childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this);
112
113 // Temporary checkbox
114 mCheckTemporary = gUICtrlFactory->getCheckBoxByName(this,"Temporary Checkbox Ctrl");
115 childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this);
116
117 // Phantom checkbox
118 mCheckPhantom = gUICtrlFactory->getCheckBoxByName(this,"Phantom Checkbox Ctrl");
119 childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
120
121 // Position
122 mLabelPosition = gUICtrlFactory->getTextBoxByName(this,"label position");
123 mCtrlPosX = gUICtrlFactory->getSpinnerByName(this,"Pos X");
124 childSetCommitCallback("Pos X",onCommitPosition,this);
125 mCtrlPosY = gUICtrlFactory->getSpinnerByName(this,"Pos Y");
126 childSetCommitCallback("Pos Y",onCommitPosition,this);
127 mCtrlPosZ = gUICtrlFactory->getSpinnerByName(this,"Pos Z");
128 childSetCommitCallback("Pos Z",onCommitPosition,this);
129
130 // Scale
131 mLabelSize = gUICtrlFactory->getTextBoxByName(this,"label size");
132 mCtrlScaleX = gUICtrlFactory->getSpinnerByName(this,"Scale X");
133 childSetCommitCallback("Scale X",onCommitScale,this);
134
135 // Scale Y
136 mCtrlScaleY = gUICtrlFactory->getSpinnerByName(this,"Scale Y");
137 childSetCommitCallback("Scale Y",onCommitScale,this);
138
139 // Scale Z
140 mCtrlScaleZ = gUICtrlFactory->getSpinnerByName(this,"Scale Z");
141 childSetCommitCallback("Scale Z",onCommitScale,this);
142
143 // Rotation
144 mLabelRotation = gUICtrlFactory->getTextBoxByName(this,"label rotation");
145 mCtrlRotX = gUICtrlFactory->getSpinnerByName(this,"Rot X");
146 childSetCommitCallback("Rot X",onCommitRotation,this);
147 mCtrlRotY = gUICtrlFactory->getSpinnerByName(this,"Rot Y");
148 childSetCommitCallback("Rot Y",onCommitRotation,this);
149 mCtrlRotZ = gUICtrlFactory->getSpinnerByName(this,"Rot Z");
150 childSetCommitCallback("Rot Z",onCommitRotation,this);
151
152 //--------------------------------------------------------
153
154 // material type popup
155 mLabelMaterial = gUICtrlFactory->getTextBoxByName(this,"label material");
156 mComboMaterial = gUICtrlFactory->getComboBoxByName(this,"material");
157 childSetCommitCallback("material",onCommitMaterial,this);
158 mComboMaterial->removeall();
159 // XUI:translate
160 LLMaterialInfo *minfop;
161 for (minfop = LLMaterialTable::basic.mMaterialInfoList.getFirstData();
162 minfop != NULL;
163 minfop = LLMaterialTable::basic.mMaterialInfoList.getNextData())
164 {
165 if (minfop->mMCode != LL_MCODE_LIGHT)
166 {
167 mComboMaterial->add(minfop->mName);
168 }
169 }
170 mComboMaterialItemCount = mComboMaterial->getItemCount();
171
172 // Base Type
173 mLabelBaseType = gUICtrlFactory->getTextBoxByName(this,"label basetype");
174 mComboBaseType = gUICtrlFactory->getComboBoxByName(this,"comboBaseType");
175 childSetCommitCallback("comboBaseType",onCommitParametric,this);
176
177 // Cut
178 mLabelCut = gUICtrlFactory->getTextBoxByName(this,"text cut");
179 mSpinCutBegin = gUICtrlFactory->getSpinnerByName(this,"cut begin");
180 childSetCommitCallback("cut begin",onCommitParametric,this);
181 mSpinCutBegin->setValidateBeforeCommit( precommitValidate );
182 mSpinCutEnd = gUICtrlFactory->getSpinnerByName(this,"cut end");
183 childSetCommitCallback("cut end",onCommitParametric,this);
184 mSpinCutEnd->setValidateBeforeCommit( &precommitValidate );
185
186 // Hollow / Skew
187 mLabelHollow = gUICtrlFactory->getTextBoxByName(this,"text hollow");
188 mLabelSkew = gUICtrlFactory->getTextBoxByName(this,"text skew");
189 mSpinHollow = gUICtrlFactory->getSpinnerByName(this,"Scale 1");
190 childSetCommitCallback("Scale 1",onCommitParametric,this);
191 mSpinHollow->setValidateBeforeCommit( &precommitValidate );
192 mSpinSkew = gUICtrlFactory->getSpinnerByName(this,"Skew");
193 childSetCommitCallback("Skew",onCommitParametric,this);
194 mSpinSkew->setValidateBeforeCommit( &precommitValidate );
195 mLabelHoleType = gUICtrlFactory->getTextBoxByName(this,"Hollow Shape");
196
197 // Hole Type
198 mComboHoleType = gUICtrlFactory->getComboBoxByName(this,"hole");
199 childSetCommitCallback("hole",onCommitParametric,this);
200
201 // Twist
202 mLabelTwist = gUICtrlFactory->getTextBoxByName(this,"text twist");
203 mSpinTwistBegin = gUICtrlFactory->getSpinnerByName(this,"Twist Begin");
204 childSetCommitCallback("Twist Begin",onCommitParametric,this);
205 mSpinTwistBegin->setValidateBeforeCommit( precommitValidate );
206 mSpinTwist = gUICtrlFactory->getSpinnerByName(this,"Twist End");
207 childSetCommitCallback("Twist End",onCommitParametric,this);
208 mSpinTwist->setValidateBeforeCommit( &precommitValidate );
209
210 // Scale
211 mSpinScaleX = gUICtrlFactory->getSpinnerByName(this,"Taper Scale X");
212 childSetCommitCallback("Taper Scale X",onCommitParametric,this);
213 mSpinScaleX->setValidateBeforeCommit( &precommitValidate );
214 mSpinScaleY = gUICtrlFactory->getSpinnerByName(this,"Taper Scale Y");
215 childSetCommitCallback("Taper Scale Y",onCommitParametric,this);
216 mSpinScaleY->setValidateBeforeCommit( &precommitValidate );
217
218 // Shear
219 mLabelShear = gUICtrlFactory->getTextBoxByName(this,"text topshear");
220 mSpinShearX = gUICtrlFactory->getSpinnerByName(this,"Shear X");
221 childSetCommitCallback("Shear X",onCommitParametric,this);
222 mSpinShearX->setValidateBeforeCommit( &precommitValidate );
223 mSpinShearY = gUICtrlFactory->getSpinnerByName(this,"Shear Y");
224 childSetCommitCallback("Shear Y",onCommitParametric,this);
225 mSpinShearY->setValidateBeforeCommit( &precommitValidate );
226
227 // Path / Profile
228 mCtrlPathBegin = gUICtrlFactory->getSpinnerByName(this,"Path Limit Begin");
229 childSetCommitCallback("Path Limit Begin",onCommitParametric,this);
230 mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate );
231 mCtrlPathEnd = gUICtrlFactory->getSpinnerByName(this,"Path Limit End");
232 childSetCommitCallback("Path Limit End",onCommitParametric,this);
233 mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate );
234
235 // Taper
236 mLabelTaper = gUICtrlFactory->getTextBoxByName(this,"text taper2");
237 mSpinTaperX = gUICtrlFactory->getSpinnerByName(this,"Taper X");
238 childSetCommitCallback("Taper X",onCommitParametric,this);
239 mSpinTaperX->setValidateBeforeCommit( precommitValidate );
240 mSpinTaperY = gUICtrlFactory->getSpinnerByName(this,"Taper Y");
241 childSetCommitCallback("Taper Y",onCommitParametric,this);
242 mSpinTaperY->setValidateBeforeCommit( precommitValidate );
243
244 // Radius Offset / Revolutions
245 mLabelRadiusOffset = gUICtrlFactory->getTextBoxByName(this,"text radius delta");
246 mLabelRevolutions = gUICtrlFactory->getTextBoxByName(this,"text revolutions");
247 mSpinRadiusOffset = gUICtrlFactory->getSpinnerByName(this,"Radius Offset");
248 childSetCommitCallback("Radius Offset",onCommitParametric,this);
249 mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate );
250 mSpinRevolutions = gUICtrlFactory->getSpinnerByName(this,"Revolutions");
251 childSetCommitCallback("Revolutions",onCommitParametric,this);
252 mSpinRevolutions->setValidateBeforeCommit( &precommitValidate );
253
254 // Start with everyone disabled
255 clearCtrls();
256
257 return TRUE;
258}
259
260LLPanelObject::LLPanelObject(const std::string& name)
261: LLPanel(name),
262 mIsPhysical(FALSE),
263 mIsTemporary(FALSE),
264 mIsPhantom(FALSE),
265 mCastShadows(TRUE),
266 mSelectedType(MI_BOX)
267{
268}
269
270
271LLPanelObject::~LLPanelObject()
272{
273 // Children all cleaned up by default view destructor.
274}
275
276void LLPanelObject::getState( )
277{
278 LLViewerObject* objectp = gSelectMgr->getFirstRootObject();
279 LLViewerObject* root_objectp = objectp;
280 if(!objectp)
281 {
282 objectp = gSelectMgr->getFirstObject();
283 // *FIX: shouldn't we just keep the child?
284 if (objectp)
285 {
286 LLViewerObject* parentp = objectp->getSubParent();
287
288 if (parentp)
289 {
290 root_objectp = parentp;
291 }
292 else
293 {
294 root_objectp = objectp;
295 }
296 }
297 }
298
299 LLVOVolume *volobjp = NULL;
300 if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
301 {
302 volobjp = (LLVOVolume *)objectp;
303 }
304
305 if( !objectp )
306 {
307 //forfeit focus
308 if (gFocusMgr.childHasKeyboardFocus(this))
309 {
310 gFocusMgr.setKeyboardFocus(NULL, NULL);
311 }
312
313 // Disable all text input fields
314 clearCtrls();
315 return;
316 }
317
318 // can move or rotate only linked group with move permissions, or sub-object with move and modify perms
319 BOOL enable_move = objectp->permMove() && !objectp->isAttachment() && (objectp->permModify() || gSavedSettings.getBOOL("SelectLinkedSet"));
320 BOOL enable_scale = objectp->permMove() && objectp->permModify();
321 BOOL enable_rotate = objectp->permMove() && ( (objectp->permModify() && !objectp->isAttachment()) || gSavedSettings.getBOOL("SelectLinkedSet"));
322
323 LLVector3 vec;
324 if (enable_move)
325 {
326 vec = objectp->getPositionEdit();
327 mCtrlPosX->set( vec.mV[VX] );
328 mCtrlPosY->set( vec.mV[VY] );
329 mCtrlPosZ->set( vec.mV[VZ] );
330 }
331 else
332 {
333 mCtrlPosX->clear();
334 mCtrlPosY->clear();
335 mCtrlPosZ->clear();
336 }
337
338
339 mLabelPosition->setEnabled( enable_move );
340 mCtrlPosX->setEnabled(enable_move);
341 mCtrlPosY->setEnabled(enable_move);
342 mCtrlPosZ->setEnabled(enable_move);
343
344 if (enable_scale)
345 {
346 vec = objectp->getScale();
347 mCtrlScaleX->set( vec.mV[VX] );
348 mCtrlScaleY->set( vec.mV[VY] );
349 mCtrlScaleZ->set( vec.mV[VZ] );
350 }
351 else
352 {
353 mCtrlScaleX->clear();
354 mCtrlScaleY->clear();
355 mCtrlScaleZ->clear();
356 }
357
358 mLabelSize->setEnabled( enable_scale );
359 mCtrlScaleX->setEnabled( enable_scale );
360 mCtrlScaleY->setEnabled( enable_scale );
361 mCtrlScaleZ->setEnabled( enable_scale );
362
363 LLQuaternion object_rot = objectp->getRotationEdit();
364 object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ]));
365 mCurEulerDegrees *= RAD_TO_DEG;
366 mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
367 mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
368 mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
369
370 if (enable_rotate)
371 {
372 mCtrlRotX->set( mCurEulerDegrees.mV[VX] );
373 mCtrlRotY->set( mCurEulerDegrees.mV[VY] );
374 mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] );
375 }
376 else
377 {
378 mCtrlRotX->clear();
379 mCtrlRotY->clear();
380 mCtrlRotZ->clear();
381 }
382
383 mLabelRotation->setEnabled( enable_rotate );
384 mCtrlRotX->setEnabled( enable_rotate );
385 mCtrlRotY->setEnabled( enable_rotate );
386 mCtrlRotZ->setEnabled( enable_rotate );
387
388 BOOL owners_identical;
389 LLUUID owner_id;
390 LLString owner_name;
391 owners_identical = gSelectMgr->selectGetOwner(owner_id, owner_name);
392
393 // BUG? Check for all objects being editable?
394 S32 roots_selected = gSelectMgr->getRootObjectCount();
395 BOOL editable = root_objectp->permModify();
396 S32 selected_count = gSelectMgr->getObjectCount();
397 BOOL single_volume = (gSelectMgr->selectionAllPCode( LL_PCODE_VOLUME ))
398 && (selected_count == 1);
399
400 // Select Single Message
401 childSetVisible("select_single", FALSE);
402 childSetVisible("edit_object", FALSE);
403 if (!editable || single_volume || selected_count <= 1)
404 {
405 childSetVisible("edit_object", TRUE);
406 childSetEnabled("edit_object", TRUE);
407 }
408 else
409 {
410 childSetVisible("select_single", TRUE);
411 childSetEnabled("select_single", TRUE);
412 }
413 // Lock checkbox - only modifiable if you own the object.
414 BOOL self_owned = (gAgent.getID() == owner_id);
415 mCheckLock->setEnabled( roots_selected > 0 && self_owned );
416
417 // More lock and debit checkbox - get the values
418 BOOL valid;
419 U32 owner_mask_on;
420 U32 owner_mask_off;
421 valid = gSelectMgr->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off);
422
423 if(valid)
424 {
425 if(owner_mask_on & PERM_MOVE)
426 {
427 // owner can move, so not locked
428 mCheckLock->set(FALSE);
429 mCheckLock->setTentative(FALSE);
430 }
431 else if(owner_mask_off & PERM_MOVE)
432 {
433 // owner can't move, so locked
434 mCheckLock->set(TRUE);
435 mCheckLock->setTentative(FALSE);
436 }
437 else
438 {
439 // some locked, some not locked
440 mCheckLock->set(FALSE);
441 mCheckLock->setTentative(TRUE);
442 }
443 }
444
445 BOOL is_flexible = volobjp && volobjp->isFlexible();
446
447 // Physics checkbox
448 mIsPhysical = root_objectp->usePhysics();
449 mCheckPhysics->set( mIsPhysical );
450 mCheckPhysics->setEnabled( roots_selected==1
451 && (editable || gAgent.isGodlike())
452 && !is_flexible);
453
454 mIsTemporary = root_objectp->flagTemporaryOnRez();
455 mCheckTemporary->set( mIsTemporary );
456 mCheckTemporary->setEnabled( roots_selected==1 && editable );
457
458 mIsPhantom = root_objectp->flagPhantom();
459 mCheckPhantom->set( mIsPhantom );
460 mCheckPhantom->setEnabled( roots_selected==1 && editable && !is_flexible );
461
462#if 0 // 1.9.2
463 mCastShadows = root_objectp->flagCastShadows();
464 mCheckCastShadows->set( mCastShadows );
465 mCheckCastShadows->setEnabled( roots_selected==1 && editable );
466#endif
467
468 // Update material part
469 U8 material_code;
470 BOOL material_same = gSelectMgr->selectionGetMaterial(&material_code);
471 if (editable && single_volume && material_same)
472 {
473 mComboMaterial->setEnabled( TRUE );
474 mLabelMaterial->setEnabled( TRUE );
475 if (material_code == LL_MCODE_LIGHT)
476 {
477 if (mComboMaterial->getItemCount() == mComboMaterialItemCount)
478 {
479 mComboMaterial->add(LEGACY_FULLBRIGHT_DESC);
480 }
481 mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC);
482 }
483 else
484 {
485 if (mComboMaterial->getItemCount() != mComboMaterialItemCount)
486 {
487 mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC);
488 }
489 mComboMaterial->setSimple(LLMaterialTable::basic.getName(material_code));
490 }
491 }
492 else
493 {
494 mComboMaterial->setEnabled( FALSE );
495 mLabelMaterial->setEnabled( FALSE );
496 }
497 //----------------------------------------------------------------------------
498
499 S32 selected_item = MI_BOX;
500 S32 selected_hole = MI_HOLE_SAME;
501 BOOL enabled = FALSE;
502 BOOL hole_enabled = FALSE;
503 F32 scale_x=1.f, scale_y=1.f;
504
505 if( !objectp || !objectp->getVolume() || !editable || !single_volume)
506 {
507 // Clear out all geometry fields.
508 mComboBaseType->clear();
509 mSpinHollow->clear();
510 mSpinCutBegin->clear();
511 mSpinCutEnd->clear();
512 mCtrlPathBegin->clear();
513 mCtrlPathEnd->clear();
514 mSpinScaleX->clear();
515 mSpinScaleY->clear();
516 mSpinTwist->clear();
517 mSpinTwistBegin->clear();
518 mComboHoleType->clear();
519 mSpinShearX->clear();
520 mSpinShearY->clear();
521 mSpinTaperX->clear();
522 mSpinTaperY->clear();
523 mSpinRadiusOffset->clear();
524 mSpinRevolutions->clear();
525 mSpinSkew->clear();
526
527 mSelectedType = MI_NONE;
528 }
529 else
530 {
531 // Only allowed to change these parameters for objects
532 // that you have permissions on AND are not attachments.
533 enabled = root_objectp->permModify();
534
535 const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
536
537 // Volume type
538 U8 path = volume_params.getPathParams().getCurveType();
539 U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
540 U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK;
541 U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK;
542
543 // Scale goes first so we can differentiate between a sphere and a torus,
544 // which have the same profile and path types.
545
546 // Scale
547 scale_x = volume_params.getRatioX();
548 scale_y = volume_params.getRatioY();
549
550 BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE);
551 if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE )
552 {
553 selected_item = MI_CYLINDER;
554 }
555 else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE )
556 {
557 selected_item = MI_BOX;
558 }
559 else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI )
560 {
561 selected_item = MI_PRISM;
562 }
563 else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI )
564 {
565 selected_item = MI_PRISM;
566 }
567 else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI )
568 {
569 selected_item = MI_PRISM;
570 }
571 else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen
572 {
573 selected_item = MI_CYLINDER; // reasonable default
574 }
575 else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f)
576 {
577 selected_item = MI_SPHERE;
578 }
579 else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f)
580 {
581 selected_item = MI_TORUS;
582 }
583 else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF)
584 {
585 selected_item = MI_SPHERE;
586 }
587 else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE )
588 {
589 // Spirals aren't supported. Make it into a sphere. JC
590 selected_item = MI_SPHERE;
591 }
592 else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI )
593 {
594 selected_item = MI_RING;
595 }
596 else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f)
597 {
598 selected_item = MI_TUBE;
599 }
600 else
601 {
602 llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl;
603 selected_item = MI_BOX;
604 }
605 mComboBaseType ->setCurrentByIndex( selected_item );
606 mSelectedType = selected_item;
607
608 // Grab S path
609 F32 begin_s = volume_params.getBeginS();
610 F32 end_s = volume_params.getEndS();
611
612 // Compute cut and advanced cut from S and T
613 F32 begin_t = volume_params.getBeginT();
614 F32 end_t = volume_params.getEndT();
615
616 // Hollowness
617 F32 hollow = volume_params.getHollow();
618 mSpinHollow->set( 100.f * hollow );
619
620 // All hollow objects allow a shape to be selected.
621 if (hollow > 0.f)
622 {
623 switch (hole)
624 {
625 case LL_PCODE_HOLE_CIRCLE:
626 selected_hole = MI_HOLE_CIRCLE;
627 break;
628 case LL_PCODE_HOLE_SQUARE:
629 selected_hole = MI_HOLE_SQUARE;
630 break;
631 case LL_PCODE_HOLE_TRIANGLE:
632 selected_hole = MI_HOLE_TRIANGLE;
633 break;
634 case LL_PCODE_HOLE_SAME:
635 default:
636 selected_hole = MI_HOLE_SAME;
637 break;
638 }
639 mComboHoleType->setCurrentByIndex( selected_hole );
640 hole_enabled = enabled;
641 }
642 else
643 {
644 mComboHoleType->setCurrentByIndex( MI_HOLE_SAME );
645 hole_enabled = FALSE;
646 }
647
648 // Cut interpretation varies based on base object type
649 F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end;
650
651 if ( selected_item == MI_SPHERE || selected_item == MI_TORUS ||
652 selected_item == MI_TUBE || selected_item == MI_RING )
653 {
654 cut_begin = begin_t;
655 cut_end = end_t;
656 adv_cut_begin = begin_s;
657 adv_cut_end = end_s;
658 }
659 else
660 {
661 cut_begin = begin_s;
662 cut_end = end_s;
663 adv_cut_begin = begin_t;
664 adv_cut_end = end_t;
665 }
666
667 mSpinCutBegin ->set( cut_begin );
668 mSpinCutEnd ->set( cut_end );
669 mCtrlPathBegin ->set( adv_cut_begin );
670 mCtrlPathEnd ->set( adv_cut_end );
671
672 // Twist
673 F32 twist = volume_params.getTwist();
674 F32 twist_begin = volume_params.getTwistBegin();
675 // Check the path type for conversion.
676 if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
677 {
678 twist *= OBJECT_TWIST_LINEAR_MAX;
679 twist_begin *= OBJECT_TWIST_LINEAR_MAX;
680 }
681 else
682 {
683 twist *= OBJECT_TWIST_MAX;
684 twist_begin *= OBJECT_TWIST_MAX;
685 }
686
687 mSpinTwist ->set( twist );
688 mSpinTwistBegin ->set( twist_begin );
689
690 // Shear
691 F32 shear_x = volume_params.getShearX();
692 F32 shear_y = volume_params.getShearY();
693 mSpinShearX->set( shear_x );
694 mSpinShearY->set( shear_y );
695
696 // Taper
697 F32 taper_x = volume_params.getTaperX();
698 F32 taper_y = volume_params.getTaperY();
699 mSpinTaperX->set( taper_x );
700 mSpinTaperY->set( taper_y );
701
702 // Radius offset.
703 F32 radius_offset = volume_params.getRadiusOffset();
704 // Limit radius offset, based on taper and hole size y.
705 F32 radius_mag = fabs(radius_offset);
706 F32 hole_y_mag = fabs(scale_y);
707 F32 taper_y_mag = fabs(taper_y);
708 // Check to see if the taper effects us.
709 if ( (radius_offset > 0.f && taper_y < 0.f) ||
710 (radius_offset < 0.f && taper_y > 0.f) )
711 {
712 // The taper does not help increase the radius offset range.
713 taper_y_mag = 0.f;
714 }
715 F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
716 // Enforce the maximum magnitude.
717 if (radius_mag > max_radius_mag)
718 {
719 // Check radius offset sign.
720 if (radius_offset < 0.f)
721 {
722 radius_offset = -max_radius_mag;
723 }
724 else
725 {
726 radius_offset = max_radius_mag;
727 }
728 }
729 mSpinRadiusOffset->set( radius_offset);
730
731 // Revolutions
732 F32 revolutions = volume_params.getRevolutions();
733 mSpinRevolutions->set( revolutions );
734
735 // Skew
736 F32 skew = volume_params.getSkew();
737 // Limit skew, based on revolutions hole size x.
738 F32 skew_mag= fabs(skew);
739 F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
740 // Discontinuity; A revolution of 1 allows skews below 0.5.
741 if ( fabs(revolutions - 1.0f) < 0.001)
742 min_skew_mag = 0.0f;
743
744 // Clip skew.
745 if (skew_mag < min_skew_mag)
746 {
747 // Check skew sign.
748 if (skew < 0.0f)
749 {
750 skew = -min_skew_mag;
751 }
752 else
753 {
754 skew = min_skew_mag;
755 }
756 }
757 mSpinSkew->set( skew );
758 }
759
760 // Compute control visibility, label names, and twist range.
761 // Start with defaults.
762 BOOL top_size_x_visible = TRUE;
763 BOOL top_size_y_visible = TRUE;
764 BOOL top_shear_x_visible = TRUE;
765 BOOL top_shear_y_visible = TRUE;
766 BOOL twist_visible = TRUE;
767 BOOL advanced_cut_visible = FALSE;
768 BOOL taper_visible = FALSE;
769 BOOL skew_visible = FALSE;
770 BOOL radius_offset_visible = FALSE;
771 BOOL revolutions_visible = FALSE;
772 F32 twist_min = OBJECT_TWIST_LINEAR_MIN;
773 F32 twist_max = OBJECT_TWIST_LINEAR_MAX;
774 F32 twist_inc = OBJECT_TWIST_LINEAR_INC;
775
776 BOOL advanced_is_dimple = FALSE;
777 BOOL size_is_hole = FALSE;
778
779 // Tune based on overall volume type
780 switch (selected_item)
781 {
782 case MI_SPHERE:
783 top_size_x_visible = FALSE;
784 top_size_y_visible = FALSE;
785 top_shear_x_visible = FALSE;
786 top_shear_y_visible = FALSE;
787 //twist_visible = FALSE;
788 advanced_cut_visible = TRUE;
789 advanced_is_dimple = TRUE;
790 twist_min = OBJECT_TWIST_MIN;
791 twist_max = OBJECT_TWIST_MAX;
792 twist_inc = OBJECT_TWIST_INC;
793 break;
794
795 case MI_TORUS:
796 case MI_TUBE:
797 case MI_RING:
798 //top_size_x_visible = FALSE;
799 //top_size_y_visible = FALSE;
800 size_is_hole = TRUE;
801 skew_visible = TRUE;
802 advanced_cut_visible = TRUE;
803 taper_visible = TRUE;
804 radius_offset_visible = TRUE;
805 revolutions_visible = TRUE;
806 twist_min = OBJECT_TWIST_MIN;
807 twist_max = OBJECT_TWIST_MAX;
808 twist_inc = OBJECT_TWIST_INC;
809
810 break;
811
812 case MI_BOX:
813 case MI_CYLINDER:
814 case MI_PRISM:
815 default:
816 break;
817 }
818
819 // Check if we need to change top size/hole size params.
820 switch (selected_item)
821 {
822 case MI_SPHERE:
823 case MI_TORUS:
824 case MI_TUBE:
825 case MI_RING:
826 mSpinScaleX->set( scale_x );
827 mSpinScaleY->set( scale_y );
828 mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE);
829 mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X);
830 mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE);
831 mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y);
832 break;
833 default:
834 mSpinScaleX->set( 1.f - scale_x );
835 mSpinScaleY->set( 1.f - scale_y );
836 mSpinScaleX->setMinValue(-1.f);
837 mSpinScaleX->setMaxValue(1.f);
838 mSpinScaleY->setMinValue(-1.f);
839 mSpinScaleY->setMaxValue(1.f);
840 break;
841 }
842
843 // Check if we need to limit the hollow based on the hole type.
844 if ( selected_hole == MI_HOLE_SQUARE &&
845 ( selected_item == MI_CYLINDER || selected_item == MI_TORUS ||
846 selected_item == MI_PRISM || selected_item == MI_RING ||
847 selected_item == MI_SPHERE ) )
848 {
849 mSpinHollow->setMinValue(0.f);
850 mSpinHollow->setMaxValue(70.f);
851 }
852 else
853 {
854 mSpinHollow->setMinValue(0.f);
855 mSpinHollow->setMaxValue(95.f);
856 }
857
858 // Update field enablement
859 mLabelBaseType ->setEnabled( enabled );
860 mComboBaseType ->setEnabled( enabled );
861
862 mLabelCut ->setEnabled( enabled );
863 mSpinCutBegin ->setEnabled( enabled );
864 mSpinCutEnd ->setEnabled( enabled );
865
866 mLabelHollow ->setEnabled( enabled );
867 mSpinHollow ->setEnabled( enabled );
868 mLabelHoleType ->setEnabled( hole_enabled );
869 mComboHoleType ->setEnabled( hole_enabled );
870
871 mLabelTwist ->setEnabled( enabled );
872 mSpinTwist ->setEnabled( enabled );
873 mSpinTwistBegin ->setEnabled( enabled );
874
875 mLabelSkew ->setEnabled( enabled );
876 mSpinSkew ->setEnabled( enabled );
877
878 childSetVisible("scale_hole", FALSE);
879 childSetVisible("scale_taper", FALSE);
880 if (top_size_x_visible || top_size_y_visible)
881 {
882 if (size_is_hole)
883 {
884 childSetVisible("scale_hole", TRUE);
885 childSetEnabled("scale_hole", enabled);
886 }
887 else
888 {
889 childSetVisible("scale_taper", TRUE);
890 childSetEnabled("scale_taper", enabled);
891 }
892 }
893
894 mSpinScaleX ->setEnabled( enabled );
895 mSpinScaleY ->setEnabled( enabled );
896
897 mLabelShear ->setEnabled( enabled );
898 mSpinShearX ->setEnabled( enabled );
899 mSpinShearY ->setEnabled( enabled );
900
901 childSetVisible("advanced_cut", FALSE);
902 childSetVisible("advanced_dimple", FALSE);
903 if (advanced_cut_visible)
904 {
905 if (advanced_is_dimple)
906 {
907 childSetVisible("advanced_dimple", TRUE);
908 childSetEnabled("advanced_dimple", enabled);
909 }
910 else
911 {
912 childSetVisible("advanced_cut", TRUE);
913 childSetEnabled("advanced_cut", enabled);
914 }
915 }
916
917 mCtrlPathBegin ->setEnabled( enabled );
918 mCtrlPathEnd ->setEnabled( enabled );
919
920 mLabelTaper ->setEnabled( enabled );
921 mSpinTaperX ->setEnabled( enabled );
922 mSpinTaperY ->setEnabled( enabled );
923
924 mLabelRadiusOffset->setEnabled( enabled );
925 mSpinRadiusOffset ->setEnabled( enabled );
926
927 mLabelRevolutions->setEnabled( enabled );
928 mSpinRevolutions ->setEnabled( enabled );
929
930 // Update field visibility
931 mLabelTwist ->setVisible( twist_visible );
932 mSpinTwist ->setVisible( twist_visible );
933 mSpinTwistBegin ->setVisible( twist_visible );
934 mSpinTwist ->setMinValue( twist_min );
935 mSpinTwist ->setMaxValue( twist_max );
936 mSpinTwist ->setIncrement( twist_inc );
937 mSpinTwistBegin ->setMinValue( twist_min );
938 mSpinTwistBegin ->setMaxValue( twist_max );
939 mSpinTwistBegin ->setIncrement( twist_inc );
940
941 mSpinScaleX ->setVisible( top_size_x_visible );
942 mSpinScaleY ->setVisible( top_size_y_visible );
943
944 mLabelSkew ->setVisible( skew_visible );
945 mSpinSkew ->setVisible( skew_visible );
946
947 mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible );
948 mSpinShearX ->setVisible( top_shear_x_visible );
949 mSpinShearY ->setVisible( top_shear_y_visible );
950
951 mCtrlPathBegin ->setVisible( advanced_cut_visible );
952 mCtrlPathEnd ->setVisible( advanced_cut_visible );
953
954 mLabelTaper ->setVisible( taper_visible );
955 mSpinTaperX ->setVisible( taper_visible );
956 mSpinTaperY ->setVisible( taper_visible );
957
958 mLabelRadiusOffset->setVisible( radius_offset_visible );
959 mSpinRadiusOffset ->setVisible( radius_offset_visible );
960
961 mLabelRevolutions->setVisible( revolutions_visible );
962 mSpinRevolutions ->setVisible( revolutions_visible );
963
964 //----------------------------------------------------------------------------
965
966 mObject = objectp;
967 mRootObject = root_objectp;
968}
969
970// static
971BOOL LLPanelObject::precommitValidate( LLUICtrl* ctrl, void* userdata )
972{
973 // TODO: Richard will fill this in later.
974 return TRUE; // FALSE means that validation failed and new value should not be commited.
975}
976
977void LLPanelObject::sendIsPhysical()
978{
979 BOOL value = mCheckPhysics->get();
980 if( mIsPhysical != value )
981 {
982 gSelectMgr->selectionUpdatePhysics(value);
983 mIsPhysical = value;
984
985 llinfos << "update physics sent" << llendl;
986 }
987 else
988 {
989 llinfos << "update physics not changed" << llendl;
990 }
991}
992
993void LLPanelObject::sendIsTemporary()
994{
995 BOOL value = mCheckTemporary->get();
996 if( mIsTemporary != value )
997 {
998 gSelectMgr->selectionUpdateTemporary(value);
999 mIsTemporary = value;
1000
1001 llinfos << "update temporary sent" << llendl;
1002 }
1003 else
1004 {
1005 llinfos << "update temporary not changed" << llendl;
1006 }
1007}
1008
1009
1010void LLPanelObject::sendIsPhantom()
1011{
1012 BOOL value = mCheckPhantom->get();
1013 if( mIsPhantom != value )
1014 {
1015 gSelectMgr->selectionUpdatePhantom(value);
1016 mIsPhantom = value;
1017
1018 llinfos << "update phantom sent" << llendl;
1019 }
1020 else
1021 {
1022 llinfos << "update phantom not changed" << llendl;
1023 }
1024}
1025
1026void LLPanelObject::sendCastShadows()
1027{
1028 BOOL value = mCheckCastShadows->get();
1029 if( mCastShadows != value )
1030 {
1031 gSelectMgr->selectionUpdateCastShadows(value);
1032 mCastShadows = value;
1033
1034 llinfos << "update cast shadows sent" << llendl;
1035 }
1036 else
1037 {
1038 llinfos << "update cast shadows not changed" << llendl;
1039 }
1040}
1041
1042// static
1043void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata )
1044{
1045 //LLPanelObject* self = (LLPanelObject*) userdata;
1046 LLComboBox* box = (LLComboBox*) ctrl;
1047
1048 if (box)
1049 {
1050 // apply the currently selected material to the object
1051 const LLString& material_name = box->getSimple();
1052 if (material_name != LEGACY_FULLBRIGHT_DESC)
1053 {
1054 U8 material_code = LLMaterialTable::basic.getMCode(material_name.c_str());
1055 gSelectMgr->selectionSetMaterial(material_code);
1056 }
1057 }
1058}
1059
1060// static
1061void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata )
1062{
1063 LLPanelObject* self = (LLPanelObject*) userdata;
1064
1065 if (self->mObject.isNull())
1066 {
1067 return;
1068 }
1069
1070 if (self->mObject->getPCode() != LL_PCODE_VOLUME)
1071 {
1072 // Don't allow modification of non-volume objects.
1073 return;
1074 }
1075
1076 LLVolume *volume = self->mObject->getVolume();
1077 if (!volume)
1078 {
1079 return;
1080 }
1081
1082 LLVolumeParams volume_params;
1083 self->getVolumeParams(volume_params);
1084
1085 // Update the volume, if necessary.
1086 self->mObject->updateVolume(volume_params);
1087
1088 // This was added to make sure thate when changes are made, the UI
1089 // adjusts to present valid options.
1090 // *FIX: only some changes, ie, hollow or primitive type changes,
1091 // require a refresh.
1092 self->refresh();
1093
1094}
1095
1096void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
1097{
1098 // Figure out what type of volume to make
1099 S32 was_selected_type = mSelectedType;
1100 S32 selected_type = mComboBaseType->getCurrentIndex();
1101 U8 profile;
1102 U8 path;
1103 switch ( selected_type )
1104 {
1105 case MI_CYLINDER:
1106 profile = LL_PCODE_PROFILE_CIRCLE;
1107 path = LL_PCODE_PATH_LINE;
1108 break;
1109
1110 case MI_BOX:
1111 profile = LL_PCODE_PROFILE_SQUARE;
1112 path = LL_PCODE_PATH_LINE;
1113 break;
1114
1115 case MI_PRISM:
1116 profile = LL_PCODE_PROFILE_EQUALTRI;
1117 path = LL_PCODE_PATH_LINE;
1118 break;
1119
1120 case MI_SPHERE:
1121 profile = LL_PCODE_PROFILE_CIRCLE_HALF;
1122 path = LL_PCODE_PATH_CIRCLE;
1123 break;
1124
1125 case MI_TORUS:
1126 profile = LL_PCODE_PROFILE_CIRCLE;
1127 path = LL_PCODE_PATH_CIRCLE;
1128 break;
1129
1130 case MI_TUBE:
1131 profile = LL_PCODE_PROFILE_SQUARE;
1132 path = LL_PCODE_PATH_CIRCLE;
1133 break;
1134
1135 case MI_RING:
1136 profile = LL_PCODE_PROFILE_EQUALTRI;
1137 path = LL_PCODE_PATH_CIRCLE;
1138 break;
1139
1140 default:
1141 llwarns << "Unknown base type " << selected_type
1142 << " in getVolumeParams()" << llendl;
1143 // assume a box
1144 selected_type = MI_BOX;
1145 profile = LL_PCODE_PROFILE_SQUARE;
1146 path = LL_PCODE_PATH_LINE;
1147 break;
1148 }
1149
1150 if (path == LL_PCODE_PATH_LINE)
1151 {
1152 LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject);
1153 if (volobjp->isFlexible())
1154 {
1155 path = LL_PCODE_PATH_FLEXIBLE;
1156 }
1157 }
1158
1159 S32 selected_hole = mComboHoleType->getCurrentIndex();
1160 U8 hole;
1161 switch (selected_hole)
1162 {
1163 case MI_HOLE_CIRCLE:
1164 hole = LL_PCODE_HOLE_CIRCLE;
1165 break;
1166 case MI_HOLE_SQUARE:
1167 hole = LL_PCODE_HOLE_SQUARE;
1168 break;
1169 case MI_HOLE_TRIANGLE:
1170 hole = LL_PCODE_HOLE_TRIANGLE;
1171 break;
1172 case MI_HOLE_SAME:
1173 default:
1174 hole = LL_PCODE_HOLE_SAME;
1175 break;
1176 }
1177
1178 volume_params.setType(profile | hole, path);
1179 mSelectedType = selected_type;
1180
1181 // Compute cut start/end
1182 F32 cut_begin = mSpinCutBegin->get();
1183 F32 cut_end = mSpinCutEnd->get();
1184
1185 // Make sure at least OBJECT_CUT_INC of the object survives
1186 if (cut_begin > cut_end - OBJECT_MIN_CUT_INC)
1187 {
1188 cut_begin = cut_end - OBJECT_MIN_CUT_INC;
1189 mSpinCutBegin->set(cut_begin);
1190 }
1191
1192 F32 adv_cut_begin = mCtrlPathBegin->get();
1193 F32 adv_cut_end = mCtrlPathEnd->get();
1194
1195 // Make sure at least OBJECT_CUT_INC of the object survives
1196 if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC)
1197 {
1198 adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC;
1199 mCtrlPathBegin->set(adv_cut_begin);
1200 }
1201
1202 F32 begin_s, end_s;
1203 F32 begin_t, end_t;
1204
1205 if (selected_type == MI_SPHERE || selected_type == MI_TORUS ||
1206 selected_type == MI_TUBE || selected_type == MI_RING)
1207 {
1208 begin_s = adv_cut_begin;
1209 end_s = adv_cut_end;
1210
1211 begin_t = cut_begin;
1212 end_t = cut_end;
1213 }
1214 else
1215 {
1216 begin_s = cut_begin;
1217 end_s = cut_end;
1218
1219 begin_t = adv_cut_begin;
1220 end_t = adv_cut_end;
1221 }
1222
1223 volume_params.setBeginAndEndS(begin_s, end_s);
1224 volume_params.setBeginAndEndT(begin_t, end_t);
1225
1226 // Hollowness
1227 F32 hollow = mSpinHollow->get() / 100.f;
1228
1229 if ( selected_hole == MI_HOLE_SQUARE &&
1230 ( selected_type == MI_CYLINDER || selected_type == MI_TORUS ||
1231 selected_type == MI_PRISM || selected_type == MI_RING ||
1232 selected_type == MI_SPHERE ) )
1233 {
1234 if (hollow > 0.7f) hollow = 0.7f;
1235 }
1236
1237 volume_params.setHollow( hollow );
1238
1239 // Twist Begin,End
1240 F32 twist_begin = mSpinTwistBegin->get();
1241 F32 twist = mSpinTwist->get();
1242 // Check the path type for twist conversion.
1243 if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
1244 {
1245 twist_begin /= OBJECT_TWIST_LINEAR_MAX;
1246 twist /= OBJECT_TWIST_LINEAR_MAX;
1247 }
1248 else
1249 {
1250 twist_begin /= OBJECT_TWIST_MAX;
1251 twist /= OBJECT_TWIST_MAX;
1252 }
1253
1254 volume_params.setTwistBegin(twist_begin);
1255 volume_params.setTwist(twist);
1256
1257 // Scale X,Y
1258 F32 scale_x = mSpinScaleX->get();
1259 F32 scale_y = mSpinScaleY->get();
1260 if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM)
1261 {
1262 scale_x = 1.f - scale_x;
1263 scale_y = 1.f - scale_y;
1264 }
1265
1266 // Skew
1267 F32 skew = mSpinSkew->get();
1268
1269 // Taper X,Y
1270 F32 taper_x = mSpinTaperX->get();
1271 F32 taper_y = mSpinTaperY->get();
1272
1273 // Radius offset
1274 F32 radius_offset = mSpinRadiusOffset->get();
1275
1276 // Revolutions
1277 F32 revolutions = mSpinRevolutions->get();
1278
1279 if ( selected_type == MI_SPHERE )
1280 {
1281 // Snap values to valid sphere parameters.
1282 scale_x = 1.0f;
1283 scale_y = 1.0f;
1284 skew = 0.0f;
1285 taper_x = 0.0f;
1286 taper_y = 0.0f;
1287 radius_offset = 0.0f;
1288 revolutions = 1.0f;
1289 }
1290 else if ( selected_type == MI_TORUS || selected_type == MI_TUBE ||
1291 selected_type == MI_RING )
1292 {
1293 scale_x = llclamp(
1294 scale_x,
1295 OBJECT_MIN_HOLE_SIZE,
1296 OBJECT_MAX_HOLE_SIZE_X);
1297 scale_y = llclamp(
1298 scale_y,
1299 OBJECT_MIN_HOLE_SIZE,
1300 OBJECT_MAX_HOLE_SIZE_Y);
1301
1302 // Limit radius offset, based on taper and hole size y.
1303 F32 radius_mag = fabs(radius_offset);
1304 F32 hole_y_mag = fabs(scale_y);
1305 F32 taper_y_mag = fabs(taper_y);
1306 // Check to see if the taper effects us.
1307 if ( (radius_offset > 0.f && taper_y < 0.f) ||
1308 (radius_offset < 0.f && taper_y > 0.f) )
1309 {
1310 // The taper does not help increase the radius offset range.
1311 taper_y_mag = 0.f;
1312 }
1313 F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
1314 // Enforce the maximum magnitude.
1315 if (radius_mag > max_radius_mag)
1316 {
1317 // Check radius offset sign.
1318 if (radius_offset < 0.f)
1319 {
1320 radius_offset = -max_radius_mag;
1321 }
1322 else
1323 {
1324 radius_offset = max_radius_mag;
1325 }
1326 }
1327
1328 // Check the skew value against the revolutions.
1329 F32 skew_mag= fabs(skew);
1330 F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
1331 // Discontinuity; A revolution of 1 allows skews below 0.5.
1332 if ( fabs(revolutions - 1.0f) < 0.001)
1333 min_skew_mag = 0.0f;
1334
1335 // Clip skew.
1336 if (skew_mag < min_skew_mag)
1337 {
1338 // Check skew sign.
1339 if (skew < 0.0f)
1340 {
1341 skew = -min_skew_mag;
1342 }
1343 else
1344 {
1345 skew = min_skew_mag;
1346 }
1347 }
1348 }
1349
1350 volume_params.setRatio( scale_x, scale_y );
1351 volume_params.setSkew(skew);
1352 volume_params.setTaper( taper_x, taper_y );
1353 volume_params.setRadiusOffset(radius_offset);
1354 volume_params.setRevolutions(revolutions);
1355
1356 // Shear X,Y
1357 F32 shear_x = mSpinShearX->get();
1358 F32 shear_y = mSpinShearY->get();
1359 volume_params.setShear( shear_x, shear_y );
1360}
1361
1362// BUG: Make work with multiple objects
1363void LLPanelObject::sendRotation()
1364{
1365 if (mObject.isNull()) return;
1366
1367 LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
1368 new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION);
1369 new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION);
1370 new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION);
1371
1372 // Note: must compare before conversion to radians
1373 LLVector3 delta = new_rot - mCurEulerDegrees;
1374
1375 if (delta.magVec() >= 0.0005f)
1376 {
1377 mCurEulerDegrees = new_rot;
1378 new_rot *= DEG_TO_RAD;
1379
1380 LLQuaternion rotation;
1381 rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]);
1382
1383 if (mRootObject != mObject)
1384 {
1385 rotation = rotation * ~mRootObject->getRotationRegion();
1386 }
1387
1388 mObject->setRotation(rotation, TRUE );
1389
1390 gSelectMgr->sendMultipleUpdate(UPD_ROTATION);
1391 }
1392}
1393
1394
1395// BUG: Make work with multiple objects
1396void LLPanelObject::sendScale()
1397{
1398 if (mObject.isNull()) return;
1399
1400 LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
1401
1402 LLVector3 delta = newscale - mObject->getScale();
1403 if (delta.magVec() >= 0.0005f)
1404 {
1405 // scale changed by more than 1/2 millimeter
1406
1407 // check to see if we aren't scaling the textures
1408 // (in which case the tex coord's need to be recomputed)
1409 BOOL dont_stretch_textures = !LLManipScale::getStretchTextures();
1410 if (dont_stretch_textures)
1411 {
1412 gSelectMgr->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
1413 }
1414
1415 mObject->setScale(newscale, TRUE);
1416 gSelectMgr->sendMultipleUpdate(UPD_SCALE | UPD_POSITION);
1417
1418 gSelectMgr->adjustTexturesByScale(TRUE, !dont_stretch_textures);
1419// llinfos << "scale sent" << llendl;
1420 }
1421 else
1422 {
1423// llinfos << "scale not changed" << llendl;
1424 }
1425}
1426
1427
1428void LLPanelObject::sendPosition()
1429{
1430 if (mObject.isNull()) return;
1431
1432 LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
1433 LLViewerRegion* regionp = mObject->getRegion();
1434
1435 // Clamp the Z height
1436 const F32 height = newpos.mV[VZ];
1437 const F32 min_height = gWorldp->getMinAllowedZ(mObject);
1438 const F32 max_height = gWorldPointer->getRegionMaxHeight();
1439
1440 if (!mObject->isAttachment())
1441 {
1442 if ( height < min_height)
1443 {
1444 newpos.mV[VZ] = min_height;
1445 mCtrlPosZ->set( min_height );
1446 }
1447 else if ( height > max_height )
1448 {
1449 newpos.mV[VZ] = max_height;
1450 mCtrlPosZ->set( max_height );
1451 }
1452
1453 // Grass is always drawn on the ground, so clamp its position to the ground
1454 if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS)
1455 {
1456 mCtrlPosZ->set(gWorldp->resolveLandHeightAgent(newpos) + 1.f);
1457 }
1458 }
1459
1460 // Make sure new position is in a valid region, so the object
1461 // won't get dumped by the simulator.
1462 LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos);
1463
1464 if ( gWorldPointer->positionRegionValidGlobal(new_pos_global) )
1465 {
1466 // send only if the position is changed, that is, the delta vector is not zero
1467 LLVector3d old_pos_global = mObject->getPositionGlobal();
1468 LLVector3d delta = new_pos_global - old_pos_global;
1469 // moved more than 1/2 millimeter
1470 if (delta.magVec() >= 0.0005f)
1471 {
1472 if (mRootObject != mObject)
1473 {
1474 newpos = newpos - mRootObject->getPositionRegion();
1475 newpos = newpos * ~mRootObject->getRotationRegion();
1476 mObject->setPositionParent(newpos);
1477 }
1478 else
1479 {
1480 mObject->setPositionEdit(newpos);
1481 }
1482 gSelectMgr->sendMultipleUpdate(UPD_POSITION);
1483 //mRootObject->sendPositionUpdate();
1484
1485 gSelectMgr->updateSelectionCenter();
1486
1487// llinfos << "position sent" << llendl;
1488 }
1489 else
1490 {
1491// llinfos << "position not changed" << llendl;
1492 }
1493 }
1494 else
1495 {
1496 // move failed, so we update the UI with the correct values
1497 LLVector3 vec = mRootObject->getPositionRegion();
1498 mCtrlPosX->set(vec.mV[VX]);
1499 mCtrlPosY->set(vec.mV[VY]);
1500 mCtrlPosZ->set(vec.mV[VZ]);
1501 }
1502}
1503
1504
1505void LLPanelObject::refresh()
1506{
1507 getState();
1508 if (mObject.notNull() && mObject->isDead())
1509 {
1510 mObject = NULL;
1511 }
1512
1513 if (mRootObject.notNull() && mRootObject->isDead())
1514 {
1515 mRootObject = NULL;
1516 }
1517}
1518
1519
1520void LLPanelObject::draw()
1521{
1522 const LLColor4 white( 1.0f, 1.0f, 1.0f, 1);
1523 const LLColor4 red( 1.0f, 0.25f, 0.f, 1);
1524 const LLColor4 green( 0.f, 1.0f, 0.f, 1);
1525 const LLColor4 blue( 0.f, 0.5f, 1.0f, 1);
1526
1527 // Tune the colors of the labels
1528 LLTool* tool = gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) );
1529
1530 if (tool == gToolTranslate)
1531 {
1532 mCtrlPosX ->setLabelColor(red);
1533 mCtrlPosY ->setLabelColor(green);
1534 mCtrlPosZ ->setLabelColor(blue);
1535
1536 mCtrlScaleX ->setLabelColor(white);
1537 mCtrlScaleY ->setLabelColor(white);
1538 mCtrlScaleZ ->setLabelColor(white);
1539
1540 mCtrlRotX ->setLabelColor(white);
1541 mCtrlRotY ->setLabelColor(white);
1542 mCtrlRotZ ->setLabelColor(white);
1543 }
1544 else if ( tool == gToolStretch )
1545 {
1546 mCtrlPosX ->setLabelColor(white);
1547 mCtrlPosY ->setLabelColor(white);
1548 mCtrlPosZ ->setLabelColor(white);
1549
1550 mCtrlScaleX ->setLabelColor(red);
1551 mCtrlScaleY ->setLabelColor(green);
1552 mCtrlScaleZ ->setLabelColor(blue);
1553
1554 mCtrlRotX ->setLabelColor(white);
1555 mCtrlRotY ->setLabelColor(white);
1556 mCtrlRotZ ->setLabelColor(white);
1557 }
1558 else if ( tool == gToolRotate )
1559 {
1560 mCtrlPosX ->setLabelColor(white);
1561 mCtrlPosY ->setLabelColor(white);
1562 mCtrlPosZ ->setLabelColor(white);
1563
1564 mCtrlScaleX ->setLabelColor(white);
1565 mCtrlScaleY ->setLabelColor(white);
1566 mCtrlScaleZ ->setLabelColor(white);
1567
1568 mCtrlRotX ->setLabelColor(red);
1569 mCtrlRotY ->setLabelColor(green);
1570 mCtrlRotZ ->setLabelColor(blue);
1571 }
1572 else
1573 {
1574 mCtrlPosX ->setLabelColor(white);
1575 mCtrlPosY ->setLabelColor(white);
1576 mCtrlPosZ ->setLabelColor(white);
1577
1578 mCtrlScaleX ->setLabelColor(white);
1579 mCtrlScaleY ->setLabelColor(white);
1580 mCtrlScaleZ ->setLabelColor(white);
1581
1582 mCtrlRotX ->setLabelColor(white);
1583 mCtrlRotY ->setLabelColor(white);
1584 mCtrlRotZ ->setLabelColor(white);
1585 }
1586
1587 LLPanel::draw();
1588}
1589
1590// virtual
1591void LLPanelObject::clearCtrls()
1592{
1593 LLPanel::clearCtrls();
1594
1595 mCheckLock ->set(FALSE);
1596 mCheckLock ->setEnabled( FALSE );
1597 mCheckPhysics ->set(FALSE);
1598 mCheckPhysics ->setEnabled( FALSE );
1599 mCheckTemporary ->set(FALSE);
1600 mCheckTemporary ->setEnabled( FALSE );
1601 mCheckPhantom ->set(FALSE);
1602 mCheckPhantom ->setEnabled( FALSE );
1603#if 0 // 1.9.2
1604 mCheckCastShadows->set(FALSE);
1605 mCheckCastShadows->setEnabled( FALSE );
1606#endif
1607 mComboMaterial ->setEnabled( FALSE );
1608 mLabelMaterial ->setEnabled( FALSE );
1609 // Disable text labels
1610 mLabelPosition ->setEnabled( FALSE );
1611 mLabelSize ->setEnabled( FALSE );
1612 mLabelRotation ->setEnabled( FALSE );
1613 mLabelBaseType ->setEnabled( FALSE );
1614 mLabelCut ->setEnabled( FALSE );
1615 mLabelHollow ->setEnabled( FALSE );
1616 mLabelHoleType ->setEnabled( FALSE );
1617 mLabelTwist ->setEnabled( FALSE );
1618 mLabelSkew ->setEnabled( FALSE );
1619 mLabelShear ->setEnabled( FALSE );
1620 mLabelTaper ->setEnabled( FALSE );
1621 mLabelRadiusOffset->setEnabled( FALSE );
1622 mLabelRevolutions->setEnabled( FALSE );
1623
1624 childSetVisible("select_single", TRUE);
1625 childSetVisible("edit_object", TRUE);
1626 childSetEnabled("edit_object", FALSE);
1627
1628 childSetEnabled("scale_hole", FALSE);
1629 childSetEnabled("scale_taper", FALSE);
1630 childSetEnabled( "advanced_cut", FALSE );
1631 childSetEnabled( "advanced_dimple", FALSE );
1632}
1633
1634//
1635// Static functions
1636//
1637
1638// static
1639void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data)
1640{
1641 // Checkbox will have toggled itself
1642 LLPanelObject *self = (LLPanelObject *)data;
1643
1644 if(self->mRootObject.isNull()) return;
1645
1646 BOOL new_state = self->mCheckLock->get();
1647
1648 gSelectMgr->setObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY);
1649}
1650
1651// static
1652void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata )
1653{
1654 LLPanelObject* self = (LLPanelObject*) userdata;
1655 self->sendPosition();
1656}
1657
1658// static
1659void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata )
1660{
1661 LLPanelObject* self = (LLPanelObject*) userdata;
1662 self->sendScale();
1663}
1664
1665// static
1666void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata )
1667{
1668 LLPanelObject* self = (LLPanelObject*) userdata;
1669 self->sendRotation();
1670}
1671
1672// static
1673void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata )
1674{
1675 LLPanelObject* self = (LLPanelObject*) userdata;
1676 self->sendIsPhysical();
1677}
1678
1679// static
1680void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata )
1681{
1682 LLPanelObject* self = (LLPanelObject*) userdata;
1683 self->sendIsTemporary();
1684}
1685
1686// static
1687void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata )
1688{
1689 LLPanelObject* self = (LLPanelObject*) userdata;
1690 self->sendIsPhantom();
1691}
1692
1693// static
1694void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata )
1695{
1696 LLPanelObject* self = (LLPanelObject*) userdata;
1697 self->sendCastShadows();
1698}