PageRenderTime 294ms CodeModel.GetById 22ms app.highlight 252ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llfloateranimpreview.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1174 lines | 817 code | 188 blank | 169 comment | 94 complexity | 7dbdb6e2799e48363512b9a74cd0f9bb MD5 | raw file
   1/** 
   2 * @file llfloateranimpreview.cpp
   3 * @brief LLFloaterAnimPreview class implementation
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llfloateranimpreview.h"
  30
  31#include "llbvhloader.h"
  32#include "lldatapacker.h"
  33#include "lldir.h"
  34#include "lleconomy.h"
  35#include "llnotificationsutil.h"
  36#include "llvfile.h"
  37#include "llapr.h"
  38#include "llstring.h"
  39
  40#include "llagent.h"
  41#include "llanimationstates.h"
  42#include "llbbox.h"
  43#include "llbutton.h"
  44#include "llcheckboxctrl.h"
  45#include "llcombobox.h"
  46#include "lldrawable.h"
  47#include "lldrawpoolavatar.h"
  48#include "llrender.h"
  49#include "llface.h"
  50#include "llfocusmgr.h"
  51#include "llkeyframemotion.h"
  52#include "lllineeditor.h"
  53#include "llfloaterperms.h"
  54#include "llsliderctrl.h"
  55#include "llspinctrl.h"
  56#include "lltextbox.h"
  57#include "lltoolmgr.h"
  58#include "llui.h"
  59#include "llviewercamera.h"
  60#include "llviewerobjectlist.h"
  61#include "llviewerwindow.h"
  62#include "llviewermenufile.h"	// upload_new_resource()
  63#include "llvoavatar.h"
  64#include "pipeline.h"
  65#include "lluictrlfactory.h"
  66#include "lltrans.h"
  67
  68const S32 PREVIEW_BORDER_WIDTH = 2;
  69const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
  70const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
  71const S32 PREF_BUTTON_HEIGHT = 16;
  72const S32 PREVIEW_TEXTURE_HEIGHT = 300;
  73
  74const F32 PREVIEW_CAMERA_DISTANCE = 4.f;
  75
  76const F32 MIN_CAMERA_ZOOM = 0.5f;
  77const F32 MAX_CAMERA_ZOOM = 10.f;
  78
  79const F32 BASE_ANIM_TIME_OFFSET = 5.f;
  80
  81std::string STATUS[] =
  82{
  83	"E_ST_OK",
  84	"E_ST_EOF",
  85	"E_ST_NO_CONSTRAINT",
  86	"E_ST_NO_FILE",
  87	"E_ST_NO_HIER",
  88	"E_ST_NO_JOINT",
  89	"E_ST_NO_NAME",
  90	"E_ST_NO_OFFSET",
  91	"E_ST_NO_CHANNELS",
  92	"E_ST_NO_ROTATION",
  93	"E_ST_NO_AXIS",
  94	"E_ST_NO_MOTION",
  95	"E_ST_NO_FRAMES",
  96	"E_ST_NO_FRAME_TIME",
  97	"E_ST_NO_POS",
  98	"E_ST_NO_ROT",
  99	"E_ST_NO_XLT_FILE",
 100	"E_ST_NO_XLT_HEADER",
 101	"E_ST_NO_XLT_NAME",
 102	"E_ST_NO_XLT_IGNORE",
 103	"E_ST_NO_XLT_RELATIVE",
 104	"E_ST_NO_XLT_OUTNAME",
 105	"E_ST_NO_XLT_MATRIX",
 106	"E_ST_NO_XLT_MERGECHILD",
 107	"E_ST_NO_XLT_MERGEPARENT",
 108	"E_ST_NO_XLT_PRIORITY",
 109	"E_ST_NO_XLT_LOOP",
 110	"E_ST_NO_XLT_EASEIN",
 111	"E_ST_NO_XLT_EASEOUT",
 112	"E_ST_NO_XLT_HAND",
 113	"E_ST_NO_XLT_EMOTE",
 114"E_ST_BAD_ROOT"
 115};
 116
 117//-----------------------------------------------------------------------------
 118// LLFloaterAnimPreview()
 119//-----------------------------------------------------------------------------
 120LLFloaterAnimPreview::LLFloaterAnimPreview(const std::string& filename) : 
 121	LLFloaterNameDesc(filename)
 122{
 123	mLastMouseX = 0;
 124	mLastMouseY = 0;
 125
 126	mIDList["Standing"] = ANIM_AGENT_STAND;
 127	mIDList["Walking"] = ANIM_AGENT_FEMALE_WALK;
 128	mIDList["Sitting"] = ANIM_AGENT_SIT_FEMALE;
 129	mIDList["Flying"] = ANIM_AGENT_HOVER;
 130
 131	mIDList["[None]"] = LLUUID::null;
 132	mIDList["Aaaaah"] = ANIM_AGENT_EXPRESS_OPEN_MOUTH;
 133	mIDList["Afraid"] = ANIM_AGENT_EXPRESS_AFRAID;
 134	mIDList["Angry"] = ANIM_AGENT_EXPRESS_ANGER;
 135	mIDList["Big Smile"] = ANIM_AGENT_EXPRESS_TOOTHSMILE;
 136	mIDList["Bored"] = ANIM_AGENT_EXPRESS_BORED;
 137	mIDList["Cry"] = ANIM_AGENT_EXPRESS_CRY;
 138	mIDList["Disdain"] = ANIM_AGENT_EXPRESS_DISDAIN;
 139	mIDList["Embarrassed"] = ANIM_AGENT_EXPRESS_EMBARRASSED;
 140	mIDList["Frown"] = ANIM_AGENT_EXPRESS_FROWN;
 141	mIDList["Kiss"] = ANIM_AGENT_EXPRESS_KISS;
 142	mIDList["Laugh"] = ANIM_AGENT_EXPRESS_LAUGH;
 143	mIDList["Plllppt"] = ANIM_AGENT_EXPRESS_TONGUE_OUT;
 144	mIDList["Repulsed"] = ANIM_AGENT_EXPRESS_REPULSED;
 145	mIDList["Sad"] = ANIM_AGENT_EXPRESS_SAD;
 146	mIDList["Shrug"] = ANIM_AGENT_EXPRESS_SHRUG;
 147	mIDList["Smile"] = ANIM_AGENT_EXPRESS_SMILE;
 148	mIDList["Surprise"] = ANIM_AGENT_EXPRESS_SURPRISE;
 149	mIDList["Wink"] = ANIM_AGENT_EXPRESS_WINK;
 150	mIDList["Worry"] = ANIM_AGENT_EXPRESS_WORRY;
 151}
 152
 153//-----------------------------------------------------------------------------
 154// setAnimCallbacks()
 155//-----------------------------------------------------------------------------
 156void LLFloaterAnimPreview::setAnimCallbacks()
 157{
 158	getChild<LLUICtrl>("playback_slider")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onSliderMove, this));
 159	
 160	getChild<LLUICtrl>("preview_base_anim")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitBaseAnim, this));
 161	getChild<LLUICtrl>("preview_base_anim")->setValue("Standing");
 162
 163	getChild<LLUICtrl>("priority")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitPriority, this));
 164	getChild<LLUICtrl>("loop_check")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitLoop, this));
 165	getChild<LLUICtrl>("loop_in_point")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitLoopIn, this));
 166	getChild<LLUICtrl>("loop_in_point")->setValidateBeforeCommit( boost::bind(&LLFloaterAnimPreview::validateLoopIn, this, _1));
 167	getChild<LLUICtrl>("loop_out_point")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitLoopOut, this));
 168	getChild<LLUICtrl>("loop_out_point")->setValidateBeforeCommit( boost::bind(&LLFloaterAnimPreview::validateLoopOut, this, _1));
 169
 170	getChild<LLUICtrl>("hand_pose_combo")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitHandPose, this));
 171	
 172	getChild<LLUICtrl>("emote_combo")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitEmote, this));
 173	getChild<LLUICtrl>("emote_combo")->setValue("[None]");
 174
 175	getChild<LLUICtrl>("ease_in_time")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitEaseIn, this));
 176	getChild<LLUICtrl>("ease_in_time")->setValidateBeforeCommit( boost::bind(&LLFloaterAnimPreview::validateEaseIn, this, _1));
 177	getChild<LLUICtrl>("ease_out_time")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitEaseOut, this));
 178	getChild<LLUICtrl>("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterAnimPreview::validateEaseOut, this, _1));
 179}
 180
 181//-----------------------------------------------------------------------------
 182// postBuild()
 183//-----------------------------------------------------------------------------
 184BOOL LLFloaterAnimPreview::postBuild()
 185{
 186	LLKeyframeMotion* motionp = NULL;
 187	LLBVHLoader* loaderp = NULL;
 188
 189	if (!LLFloaterNameDesc::postBuild())
 190	{
 191		return FALSE;
 192	}
 193
 194	getChild<LLUICtrl>("name_form")->setCommitCallback(boost::bind(&LLFloaterAnimPreview::onCommitName, this));
 195
 196	childSetAction("ok_btn", onBtnOK, this);
 197	setDefaultBtn();
 198
 199	mPreviewRect.set(PREVIEW_HPAD, 
 200		PREVIEW_TEXTURE_HEIGHT,
 201		getRect().getWidth() - PREVIEW_HPAD, 
 202		PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
 203	mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f);
 204
 205	mPlayButton = getChild<LLButton>( "play_btn");
 206	mPlayButton->setClickedCallback(boost::bind(&LLFloaterAnimPreview::onBtnPlay, this));
 207	mPlayButton->setVisible(true);
 208
 209	mPauseButton = getChild<LLButton>( "pause_btn");
 210	mPauseButton->setClickedCallback(boost::bind(&LLFloaterAnimPreview::onBtnPause, this));
 211	mPauseButton->setVisible(false);
 212	
 213	mStopButton = getChild<LLButton>( "stop_btn");
 214	mStopButton->setClickedCallback(boost::bind(&LLFloaterAnimPreview::onBtnStop, this));
 215
 216	getChildView("bad_animation_text")->setVisible(FALSE);
 217
 218	std::string exten = gDirUtilp->getExtension(mFilename);
 219	if (exten == "bvh")
 220	{
 221		// loading a bvh file
 222
 223		// now load bvh file
 224		S32 file_size;
 225		
 226		LLAPRFile infile ;
 227		infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size);
 228		
 229		if (!infile.getFileHandle())
 230		{
 231			llwarns << "Can't open BVH file:" << mFilename << llendl;	
 232		}
 233		else
 234		{
 235			char*	file_buffer;
 236
 237			file_buffer = new char[file_size + 1];
 238
 239			if (file_size == infile.read(file_buffer, file_size))
 240			{
 241				file_buffer[file_size] = '\0';
 242				llinfos << "Loading BVH file " << mFilename << llendl;
 243				ELoadStatus load_status = E_ST_OK;
 244				S32 line_number = 0; 
 245				loaderp = new LLBVHLoader(file_buffer, load_status, line_number);
 246				std::string status = getString(STATUS[load_status]);
 247				
 248				if(load_status == E_ST_NO_XLT_FILE)
 249				{
 250					llwarns << "NOTE: No translation table found." << llendl;
 251				}
 252				else
 253				{
 254					llwarns << "ERROR: [line: " << line_number << "] " << status << llendl;
 255				}
 256			}
 257
 258			infile.close() ;
 259			delete[] file_buffer;
 260		}
 261	}
 262
 263	if (loaderp && loaderp->isInitialized() && loaderp->getDuration() <= MAX_ANIM_DURATION)
 264	{
 265		// generate unique id for this motion
 266		mTransactionID.generate();
 267		mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
 268
 269		mAnimPreview = new LLPreviewAnimation(256, 256);
 270
 271		// motion will be returned, but it will be in a load-pending state, as this is a new motion
 272		// this motion will not request an asset transfer until next update, so we have a chance to 
 273		// load the keyframe data locally
 274		motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID);
 275
 276		// create data buffer for keyframe initialization
 277		S32 buffer_size = loaderp->getOutputSize();
 278		U8* buffer = new U8[buffer_size];
 279
 280		LLDataPackerBinaryBuffer dp(buffer, buffer_size);
 281
 282		// pass animation data through memory buffer
 283		loaderp->serialize(dp);
 284		dp.reset();
 285		BOOL success = motionp && motionp->deserialize(dp);
 286
 287		delete []buffer;
 288
 289		if (success)
 290		{
 291			setAnimCallbacks() ;
 292			
 293			const LLBBoxLocal &pelvis_bbox = motionp->getPelvisBBox();
 294
 295			LLVector3 temp = pelvis_bbox.getCenter();
 296			// only consider XY?
 297			//temp.mV[VZ] = 0.f;
 298			F32 pelvis_offset = temp.magVec();
 299
 300			temp = pelvis_bbox.getExtent();
 301			//temp.mV[VZ] = 0.f;
 302			F32 pelvis_max_displacement = pelvis_offset + (temp.magVec() * 0.5f) + 1.f;
 303			
 304			F32 camera_zoom = LLViewerCamera::getInstance()->getDefaultFOV() / (2.f * atan(pelvis_max_displacement / PREVIEW_CAMERA_DISTANCE));
 305		
 306			mAnimPreview->setZoom(camera_zoom);
 307
 308			motionp->setName(getChild<LLUICtrl>("name_form")->getValue().asString());
 309			mAnimPreview->getDummyAvatar()->startMotion(mMotionID);
 310			
 311			getChild<LLSlider>("playback_slider")->setMinValue(0.0);
 312			getChild<LLSlider>("playback_slider")->setMaxValue(1.0);
 313
 314			getChild<LLUICtrl>("loop_check")->setValue(LLSD(motionp->getLoop()));
 315			getChild<LLUICtrl>("loop_in_point")->setValue(LLSD(motionp->getLoopIn() / motionp->getDuration() * 100.f));
 316			getChild<LLUICtrl>("loop_out_point")->setValue(LLSD(motionp->getLoopOut() / motionp->getDuration() * 100.f));
 317			getChild<LLUICtrl>("priority")->setValue(LLSD((F32)motionp->getPriority()));
 318			getChild<LLUICtrl>("hand_pose_combo")->setValue(LLHandMotion::getHandPoseName(motionp->getHandPose()));
 319			getChild<LLUICtrl>("ease_in_time")->setValue(LLSD(motionp->getEaseInDuration()));
 320			getChild<LLUICtrl>("ease_out_time")->setValue(LLSD(motionp->getEaseOutDuration()));
 321			setEnabled(TRUE);
 322			std::string seconds_string;
 323			seconds_string = llformat(" - %.2f seconds", motionp->getDuration());
 324
 325			setTitle(mFilename + std::string(seconds_string));
 326		}
 327		else
 328		{
 329			mAnimPreview = NULL;
 330			mMotionID.setNull();
 331			getChild<LLUICtrl>("bad_animation_text")->setValue(getString("failed_to_initialize"));
 332		}
 333	}
 334	else
 335	{
 336		if ( loaderp )
 337		{
 338			if (loaderp->getDuration() > MAX_ANIM_DURATION)
 339			{
 340				LLUIString out_str = getString("anim_too_long");
 341				out_str.setArg("[LENGTH]", llformat("%.1f", loaderp->getDuration()));
 342				out_str.setArg("[MAX_LENGTH]", llformat("%.1f", MAX_ANIM_DURATION));
 343				getChild<LLUICtrl>("bad_animation_text")->setValue(out_str.getString());
 344			}
 345			else
 346			{
 347				LLUIString out_str = getString("failed_file_read");
 348				out_str.setArg("[STATUS]", getString(STATUS[loaderp->getStatus()])); 
 349				getChild<LLUICtrl>("bad_animation_text")->setValue(out_str.getString());
 350			}
 351		}
 352
 353		//setEnabled(FALSE);
 354		mMotionID.setNull();
 355		mAnimPreview = NULL;
 356	}
 357
 358	refresh();
 359
 360	delete loaderp;
 361
 362	return TRUE;
 363}
 364
 365//-----------------------------------------------------------------------------
 366// LLFloaterAnimPreview()
 367//-----------------------------------------------------------------------------
 368LLFloaterAnimPreview::~LLFloaterAnimPreview()
 369{
 370	mAnimPreview = NULL;
 371
 372	setEnabled(FALSE);
 373}
 374
 375//-----------------------------------------------------------------------------
 376// draw()
 377//-----------------------------------------------------------------------------
 378void LLFloaterAnimPreview::draw()
 379{
 380	LLFloater::draw();
 381	LLRect r = getRect();
 382
 383	refresh();
 384
 385	if (mMotionID.notNull() && mAnimPreview)
 386	{
 387		gGL.color3f(1.f, 1.f, 1.f);
 388
 389		gGL.getTexUnit(0)->bind(mAnimPreview);
 390
 391		gGL.begin( LLRender::QUADS );
 392		{
 393			gGL.texCoord2f(0.f, 1.f);
 394			gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
 395			gGL.texCoord2f(0.f, 0.f);
 396			gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
 397			gGL.texCoord2f(1.f, 0.f);
 398			gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
 399			gGL.texCoord2f(1.f, 1.f);
 400			gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
 401		}
 402		gGL.end();
 403
 404		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 405
 406		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 407		if (!avatarp->areAnimationsPaused())
 408		{
 409			mAnimPreview->requestUpdate();
 410		}
 411	}
 412}
 413
 414//-----------------------------------------------------------------------------
 415// resetMotion()
 416//-----------------------------------------------------------------------------
 417void LLFloaterAnimPreview::resetMotion()
 418{
 419	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 420	BOOL paused = avatarp->areAnimationsPaused();
 421
 422	// *TODO: Fix awful casting hack
 423	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 424	
 425	// Set emotion
 426	std::string emote = getChild<LLUICtrl>("emote_combo")->getValue().asString();
 427	motionp->setEmote(mIDList[emote]);
 428	
 429	LLUUID base_id = mIDList[getChild<LLUICtrl>("preview_base_anim")->getValue().asString()];
 430	avatarp->deactivateAllMotions();
 431	avatarp->startMotion(mMotionID, 0.0f);
 432	avatarp->startMotion(base_id, BASE_ANIM_TIME_OFFSET);
 433	getChild<LLUICtrl>("playback_slider")->setValue(0.0f);
 434
 435	// Set pose
 436	std::string handpose = getChild<LLUICtrl>("hand_pose_combo")->getValue().asString();
 437	avatarp->startMotion( ANIM_AGENT_HAND_MOTION, 0.0f );
 438	motionp->setHandPose(LLHandMotion::getHandPose(handpose));
 439
 440	if (paused)
 441	{
 442		mPauseRequest = avatarp->requestPause();
 443	}
 444	else
 445	{
 446		mPauseRequest = NULL;	
 447	}
 448}
 449
 450//-----------------------------------------------------------------------------
 451// handleMouseDown()
 452//-----------------------------------------------------------------------------
 453BOOL LLFloaterAnimPreview::handleMouseDown(S32 x, S32 y, MASK mask)
 454{
 455	if (mPreviewRect.pointInRect(x, y))
 456	{
 457		bringToFront( x, y );
 458		gFocusMgr.setMouseCapture(this);
 459		gViewerWindow->hideCursor();
 460		mLastMouseX = x;
 461		mLastMouseY = y;
 462		return TRUE;
 463	}
 464
 465	return LLFloater::handleMouseDown(x, y, mask);
 466}
 467
 468//-----------------------------------------------------------------------------
 469// handleMouseUp()
 470//-----------------------------------------------------------------------------
 471BOOL LLFloaterAnimPreview::handleMouseUp(S32 x, S32 y, MASK mask)
 472{
 473	gFocusMgr.setMouseCapture(FALSE);
 474	gViewerWindow->showCursor();
 475	return LLFloater::handleMouseUp(x, y, mask);
 476}
 477
 478//-----------------------------------------------------------------------------
 479// handleHover()
 480//-----------------------------------------------------------------------------
 481BOOL LLFloaterAnimPreview::handleHover(S32 x, S32 y, MASK mask)
 482{
 483	MASK local_mask = mask & ~MASK_ALT;
 484
 485	if (mAnimPreview && hasMouseCapture())
 486	{
 487		if (local_mask == MASK_PAN)
 488		{
 489			// pan here
 490			mAnimPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
 491		}
 492		else if (local_mask == MASK_ORBIT)
 493		{
 494			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 495			F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
 496			
 497			mAnimPreview->rotate(yaw_radians, pitch_radians);
 498		}
 499		else 
 500		{
 501			F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
 502			F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
 503			
 504			mAnimPreview->rotate(yaw_radians, 0.f);
 505			mAnimPreview->zoom(zoom_amt);
 506		}
 507
 508		mAnimPreview->requestUpdate();
 509
 510		LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY);
 511	}
 512
 513	if (!mPreviewRect.pointInRect(x, y) || !mAnimPreview)
 514	{
 515		return LLFloater::handleHover(x, y, mask);
 516	}
 517	else if (local_mask == MASK_ORBIT)
 518	{
 519		gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA);
 520	}
 521	else if (local_mask == MASK_PAN)
 522	{
 523		gViewerWindow->setCursor(UI_CURSOR_TOOLPAN);
 524	}
 525	else
 526	{
 527		gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN);
 528	}
 529
 530	return TRUE;
 531}
 532
 533//-----------------------------------------------------------------------------
 534// handleScrollWheel()
 535//-----------------------------------------------------------------------------
 536BOOL LLFloaterAnimPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 537{
 538	mAnimPreview->zoom((F32)clicks * -0.2f);
 539	mAnimPreview->requestUpdate();
 540
 541	return TRUE;
 542}
 543
 544//-----------------------------------------------------------------------------
 545// onMouseCaptureLost()
 546//-----------------------------------------------------------------------------
 547void LLFloaterAnimPreview::onMouseCaptureLost()
 548{
 549	gViewerWindow->showCursor();
 550}
 551
 552//-----------------------------------------------------------------------------
 553// onBtnPlay()
 554//-----------------------------------------------------------------------------
 555void LLFloaterAnimPreview::onBtnPlay()
 556{
 557	if (!getEnabled())
 558		return;
 559
 560	if (mMotionID.notNull() && mAnimPreview)
 561	{
 562		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 563		
 564		if (!avatarp->isMotionActive(mMotionID))
 565		{
 566			resetMotion();
 567			mPauseRequest = NULL;
 568		}
 569		else if (avatarp->areAnimationsPaused())
 570		{			
 571			mPauseRequest = NULL;
 572		}
 573	}
 574}
 575
 576//-----------------------------------------------------------------------------
 577// onBtnPause()
 578//-----------------------------------------------------------------------------
 579void LLFloaterAnimPreview::onBtnPause()
 580{
 581	if (!getEnabled())
 582		return;
 583	
 584	if (mMotionID.notNull() && mAnimPreview)
 585	{
 586		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 587
 588		if (avatarp->isMotionActive(mMotionID))
 589		{
 590			if (!avatarp->areAnimationsPaused())
 591			{
 592				mPauseRequest = avatarp->requestPause();
 593			}
 594		}
 595	}
 596}
 597
 598//-----------------------------------------------------------------------------
 599// onBtnStop()
 600//-----------------------------------------------------------------------------
 601void LLFloaterAnimPreview::onBtnStop()
 602{
 603	if (!getEnabled())
 604		return;
 605
 606	if (mMotionID.notNull() && mAnimPreview)
 607	{
 608		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 609		resetMotion();
 610		mPauseRequest = avatarp->requestPause();
 611	}
 612}
 613
 614//-----------------------------------------------------------------------------
 615// onSliderMove()
 616//-----------------------------------------------------------------------------
 617void LLFloaterAnimPreview::onSliderMove()
 618{
 619	if (!getEnabled())
 620		return;
 621
 622	if (mAnimPreview)
 623	{
 624		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 625		F32 slider_value = (F32)getChild<LLUICtrl>("playback_slider")->getValue().asReal();
 626		LLUUID base_id = mIDList[getChild<LLUICtrl>("preview_base_anim")->getValue().asString()];
 627		LLMotion* motionp = avatarp->findMotion(mMotionID);
 628		F32 duration = motionp->getDuration();// + motionp->getEaseOutDuration();
 629		F32 delta_time = duration * slider_value;
 630		avatarp->deactivateAllMotions();
 631		avatarp->startMotion(base_id, delta_time + BASE_ANIM_TIME_OFFSET);
 632		avatarp->startMotion(mMotionID, delta_time);
 633		mPauseRequest = avatarp->requestPause();
 634		refresh();
 635	}
 636
 637}
 638
 639//-----------------------------------------------------------------------------
 640// onCommitBaseAnim()
 641//-----------------------------------------------------------------------------
 642void LLFloaterAnimPreview::onCommitBaseAnim()
 643{
 644	if (!getEnabled())
 645		return;
 646
 647	if (mAnimPreview)
 648	{
 649		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 650
 651		BOOL paused = avatarp->areAnimationsPaused();
 652
 653		// stop all other possible base motions
 654		avatarp->stopMotion(mIDList["Standing"], TRUE);
 655		avatarp->stopMotion(mIDList["Walking"], TRUE);
 656		avatarp->stopMotion(mIDList["Sitting"], TRUE);
 657		avatarp->stopMotion(mIDList["Flying"], TRUE);
 658
 659		resetMotion();
 660
 661		if (!paused)
 662		{
 663			mPauseRequest = NULL;
 664		}
 665	}
 666}
 667
 668//-----------------------------------------------------------------------------
 669// onCommitLoop()
 670//-----------------------------------------------------------------------------
 671void LLFloaterAnimPreview::onCommitLoop()
 672{
 673	if (!getEnabled())
 674		return;
 675	
 676	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 677	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 678
 679	if (motionp)
 680	{
 681		motionp->setLoop(getChild<LLUICtrl>("loop_check")->getValue().asBoolean());
 682		motionp->setLoopIn((F32)getChild<LLUICtrl>("loop_in_point")->getValue().asReal() * 0.01f * motionp->getDuration());
 683		motionp->setLoopOut((F32)getChild<LLUICtrl>("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration());
 684	}
 685}
 686
 687//-----------------------------------------------------------------------------
 688// onCommitLoopIn()
 689//-----------------------------------------------------------------------------
 690void LLFloaterAnimPreview::onCommitLoopIn()
 691{
 692	if (!getEnabled())
 693		return;
 694
 695	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 696	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 697
 698	if (motionp)
 699	{
 700		motionp->setLoopIn((F32)getChild<LLUICtrl>("loop_in_point")->getValue().asReal() / 100.f);
 701		resetMotion();
 702		getChild<LLUICtrl>("loop_check")->setValue(LLSD(TRUE));
 703		onCommitLoop();
 704	}
 705}
 706
 707//-----------------------------------------------------------------------------
 708// onCommitLoopOut()
 709//-----------------------------------------------------------------------------
 710void LLFloaterAnimPreview::onCommitLoopOut()
 711{
 712	if (!getEnabled())
 713		return;
 714
 715	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 716	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 717
 718	if (motionp)
 719	{
 720		motionp->setLoopOut((F32)getChild<LLUICtrl>("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration());
 721		resetMotion();
 722		getChild<LLUICtrl>("loop_check")->setValue(LLSD(TRUE));
 723		onCommitLoop();
 724	}
 725}
 726
 727//-----------------------------------------------------------------------------
 728// onCommitName()
 729//-----------------------------------------------------------------------------
 730void LLFloaterAnimPreview::onCommitName()
 731{
 732	if (!getEnabled())
 733		return;
 734
 735	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 736	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 737
 738	if (motionp)
 739	{
 740		motionp->setName(getChild<LLUICtrl>("name_form")->getValue().asString());
 741	}
 742
 743	doCommit();
 744}
 745
 746//-----------------------------------------------------------------------------
 747// onCommitHandPose()
 748//-----------------------------------------------------------------------------
 749void LLFloaterAnimPreview::onCommitHandPose()
 750{
 751	if (!getEnabled())
 752		return;
 753
 754	resetMotion(); // sets hand pose
 755}
 756
 757//-----------------------------------------------------------------------------
 758// onCommitEmote()
 759//-----------------------------------------------------------------------------
 760void LLFloaterAnimPreview::onCommitEmote()
 761{
 762	if (!getEnabled())
 763		return;
 764
 765	resetMotion(); // ssts emote
 766}
 767
 768//-----------------------------------------------------------------------------
 769// onCommitPriority()
 770//-----------------------------------------------------------------------------
 771void LLFloaterAnimPreview::onCommitPriority()
 772{
 773	if (!getEnabled())
 774		return;
 775
 776	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 777	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 778
 779	motionp->setPriority(llfloor((F32)getChild<LLUICtrl>("priority")->getValue().asReal()));
 780}
 781
 782//-----------------------------------------------------------------------------
 783// onCommitEaseIn()
 784//-----------------------------------------------------------------------------
 785void LLFloaterAnimPreview::onCommitEaseIn()
 786{
 787	if (!getEnabled())
 788		return;
 789
 790	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 791	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 792
 793	motionp->setEaseIn((F32)getChild<LLUICtrl>("ease_in_time")->getValue().asReal());
 794	resetMotion();
 795}
 796
 797//-----------------------------------------------------------------------------
 798// onCommitEaseOut()
 799//-----------------------------------------------------------------------------
 800void LLFloaterAnimPreview::onCommitEaseOut()
 801{
 802	if (!getEnabled())
 803		return;
 804
 805	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 806	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 807
 808	motionp->setEaseOut((F32)getChild<LLUICtrl>("ease_out_time")->getValue().asReal());
 809	resetMotion();
 810}
 811
 812//-----------------------------------------------------------------------------
 813// validateEaseIn()
 814//-----------------------------------------------------------------------------
 815bool LLFloaterAnimPreview::validateEaseIn(const LLSD& data)
 816{
 817	if (!getEnabled())
 818		return false;
 819
 820	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 821	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 822	
 823	if (!motionp->getLoop())
 824	{
 825		F32 new_ease_in = llclamp((F32)getChild<LLUICtrl>("ease_in_time")->getValue().asReal(), 0.f, motionp->getDuration() - motionp->getEaseOutDuration());
 826		getChild<LLUICtrl>("ease_in_time")->setValue(LLSD(new_ease_in));
 827	}
 828	
 829	return true;
 830}
 831
 832//-----------------------------------------------------------------------------
 833// validateEaseOut()
 834//-----------------------------------------------------------------------------
 835bool LLFloaterAnimPreview::validateEaseOut(const LLSD& data)
 836{
 837	if (!getEnabled())
 838		return false;
 839
 840	LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 841	LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 842	
 843	if (!motionp->getLoop())
 844	{
 845		F32 new_ease_out = llclamp((F32)getChild<LLUICtrl>("ease_out_time")->getValue().asReal(), 0.f, motionp->getDuration() - motionp->getEaseInDuration());
 846		getChild<LLUICtrl>("ease_out_time")->setValue(LLSD(new_ease_out));
 847	}
 848
 849	return true;
 850}
 851
 852//-----------------------------------------------------------------------------
 853// validateLoopIn()
 854//-----------------------------------------------------------------------------
 855bool LLFloaterAnimPreview::validateLoopIn(const LLSD& data)
 856{
 857	if (!getEnabled())
 858		return false;
 859
 860	F32 loop_in_value = (F32)getChild<LLUICtrl>("loop_in_point")->getValue().asReal();
 861	F32 loop_out_value = (F32)getChild<LLUICtrl>("loop_out_point")->getValue().asReal();
 862
 863	if (loop_in_value < 0.f)
 864	{
 865		loop_in_value = 0.f;
 866	}
 867	else if (loop_in_value > 100.f)
 868	{
 869		loop_in_value = 100.f;
 870	}
 871	else if (loop_in_value > loop_out_value)
 872	{
 873		loop_in_value = loop_out_value;
 874	}
 875
 876	getChild<LLUICtrl>("loop_in_point")->setValue(LLSD(loop_in_value));
 877	return true;
 878}
 879
 880//-----------------------------------------------------------------------------
 881// validateLoopOut()
 882//-----------------------------------------------------------------------------
 883bool LLFloaterAnimPreview::validateLoopOut(const LLSD& data)
 884{
 885	if (!getEnabled())
 886		return false;
 887
 888	F32 loop_out_value = (F32)getChild<LLUICtrl>("loop_out_point")->getValue().asReal();
 889	F32 loop_in_value = (F32)getChild<LLUICtrl>("loop_in_point")->getValue().asReal();
 890
 891	if (loop_out_value < 0.f)
 892	{
 893		loop_out_value = 0.f;
 894	}
 895	else if (loop_out_value > 100.f)
 896	{
 897		loop_out_value = 100.f;
 898	}
 899	else if (loop_out_value < loop_in_value)
 900	{
 901		loop_out_value = loop_in_value;
 902	}
 903
 904	getChild<LLUICtrl>("loop_out_point")->setValue(LLSD(loop_out_value));
 905	return true;
 906}
 907
 908
 909//-----------------------------------------------------------------------------
 910// refresh()
 911//-----------------------------------------------------------------------------
 912void LLFloaterAnimPreview::refresh()
 913{
 914	// Are we showing the play button (default) or the pause button?
 915	bool show_play = true;
 916	if (!mAnimPreview)
 917	{
 918		getChildView("bad_animation_text")->setVisible(TRUE);
 919		// play button visible but disabled
 920		mPlayButton->setEnabled(FALSE);
 921		mStopButton->setEnabled(FALSE);
 922		getChildView("ok_btn")->setEnabled(FALSE);
 923	}
 924	else
 925	{
 926		getChildView("bad_animation_text")->setVisible(FALSE);
 927		// re-enabled in case previous animation was bad
 928		mPlayButton->setEnabled(TRUE);
 929		mStopButton->setEnabled(TRUE);
 930		LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar();
 931		if (avatarp->isMotionActive(mMotionID))
 932		{
 933			mStopButton->setEnabled(TRUE);
 934			LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
 935			if (!avatarp->areAnimationsPaused())
 936			{
 937				// animation is playing
 938				if (motionp)
 939				{
 940					F32 fraction_complete = motionp->getLastUpdateTime() / motionp->getDuration();
 941					getChild<LLUICtrl>("playback_slider")->setValue(fraction_complete);
 942				}
 943				show_play = false;
 944			}
 945		}
 946		else
 947		{
 948			// Motion just finished playing
 949			mPauseRequest = avatarp->requestPause();
 950		}
 951		getChildView("ok_btn")->setEnabled(TRUE);
 952		mAnimPreview->requestUpdate();
 953	}
 954	mPlayButton->setVisible(show_play);
 955	mPauseButton->setVisible(!show_play);
 956}
 957
 958//-----------------------------------------------------------------------------
 959// onBtnOK()
 960//-----------------------------------------------------------------------------
 961void LLFloaterAnimPreview::onBtnOK(void* userdata)
 962{
 963	LLFloaterAnimPreview* floaterp = (LLFloaterAnimPreview*)userdata;
 964	if (!floaterp->getEnabled()) return;
 965
 966	if (floaterp->mAnimPreview)
 967	{
 968		LLKeyframeMotion* motionp = (LLKeyframeMotion*)floaterp->mAnimPreview->getDummyAvatar()->findMotion(floaterp->mMotionID);
 969
 970		S32 file_size = motionp->getFileSize();
 971		U8* buffer = new U8[file_size];
 972
 973		LLDataPackerBinaryBuffer dp(buffer, file_size);
 974		if (motionp->serialize(dp))
 975		{
 976			LLVFile file(gVFS, motionp->getID(), LLAssetType::AT_ANIMATION, LLVFile::APPEND);
 977
 978			S32 size = dp.getCurrentSize();
 979			file.setMaxSize(size);
 980			if (file.write((U8*)buffer, size))
 981			{
 982				std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString();
 983				std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString();
 984				LLAssetStorage::LLStoreAssetCallback callback = NULL;
 985				S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 986				void *userdata = NULL;
 987				upload_new_resource(floaterp->mTransactionID, // tid
 988						    LLAssetType::AT_ANIMATION,
 989						    name,
 990						    desc,
 991						    0,
 992						    LLFolderType::FT_NONE,
 993						    LLInventoryType::IT_ANIMATION,
 994						    LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
 995						    name,
 996						    callback, expected_upload_cost, userdata);
 997
 998			}
 999			else
1000			{
1001				llwarns << "Failure writing animation data." << llendl;
1002				LLNotificationsUtil::add("WriteAnimationFail");
1003			}
1004		}
1005
1006		delete [] buffer;
1007		// clear out cache for motion data
1008		floaterp->mAnimPreview->getDummyAvatar()->removeMotion(floaterp->mMotionID);
1009		LLKeyframeDataCache::removeKeyframeData(floaterp->mMotionID);
1010	}
1011
1012	floaterp->closeFloater(false);
1013}
1014
1015//-----------------------------------------------------------------------------
1016// LLPreviewAnimation
1017//-----------------------------------------------------------------------------
1018LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE)
1019{
1020	mNeedsUpdate = TRUE;
1021	mCameraDistance = PREVIEW_CAMERA_DISTANCE;
1022	mCameraYaw = 0.f;
1023	mCameraPitch = 0.f;
1024	mCameraZoom = 1.f;
1025
1026	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
1027	mDummyAvatar->createDrawable(&gPipeline);
1028	mDummyAvatar->mIsDummy = TRUE;
1029	mDummyAvatar->mSpecialRenderMode = 1;
1030	mDummyAvatar->setPositionAgent(LLVector3::zero);
1031	mDummyAvatar->slamPosition();
1032	mDummyAvatar->updateJointLODs();
1033	mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
1034	mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);
1035	mDummyAvatar->hideSkirt();
1036
1037	// stop extraneous animations
1038	mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE );
1039	mDummyAvatar->stopMotion( ANIM_AGENT_EYE, TRUE );
1040	mDummyAvatar->stopMotion( ANIM_AGENT_BODY_NOISE, TRUE );
1041	mDummyAvatar->stopMotion( ANIM_AGENT_BREATHE_ROT, TRUE );
1042}
1043
1044//-----------------------------------------------------------------------------
1045// LLPreviewAnimation()
1046//-----------------------------------------------------------------------------
1047LLPreviewAnimation::~LLPreviewAnimation()
1048{
1049	mDummyAvatar->markDead();
1050}
1051
1052//virtual
1053S8 LLPreviewAnimation::getType() const
1054{
1055	return LLViewerDynamicTexture::LL_PREVIEW_ANIMATION ;
1056}
1057
1058//-----------------------------------------------------------------------------
1059// update()
1060//-----------------------------------------------------------------------------
1061BOOL	LLPreviewAnimation::render()
1062{
1063	mNeedsUpdate = FALSE;
1064	LLVOAvatar* avatarp = mDummyAvatar;
1065	
1066	gGL.matrixMode(LLRender::MM_PROJECTION);
1067	gGL.pushMatrix();
1068	gGL.loadIdentity();
1069	gGL.ortho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f);
1070
1071	gGL.matrixMode(LLRender::MM_MODELVIEW);
1072	gGL.pushMatrix();
1073	gGL.loadIdentity();
1074
1075	if (LLGLSLShader::sNoFixedFunction)
1076	{
1077		gUIProgram.bind();
1078	}
1079
1080	LLGLSUIDefault def;
1081	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
1082	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
1083
1084	gl_rect_2d_simple( mFullWidth, mFullHeight );
1085
1086	gGL.matrixMode(LLRender::MM_PROJECTION);
1087	gGL.popMatrix();
1088
1089	gGL.matrixMode(LLRender::MM_MODELVIEW);
1090	gGL.popMatrix();
1091
1092	gGL.flush();
1093
1094	LLVector3 target_pos = avatarp->mRoot.getWorldPosition();
1095
1096	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * 
1097		LLQuaternion(mCameraYaw, LLVector3::z_axis);
1098
1099	LLQuaternion av_rot = avatarp->mRoot.getWorldRotation() * camera_rot;
1100	LLViewerCamera::getInstance()->setOriginAndLookAt(
1101		target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + mCameraOffset) * av_rot),		// camera
1102		LLVector3::z_axis,																	// up
1103		target_pos + (mCameraOffset  * av_rot) );											// point of interest
1104
1105	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
1106	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
1107
1108	mCameraRelPos = LLViewerCamera::getInstance()->getOrigin() - avatarp->mHeadp->getWorldPosition();
1109
1110	//avatarp->setAnimationData("LookAtPoint", (void *)&mCameraRelPos);
1111
1112	//SJB: Animation is updated in LLVOAvatar::updateCharacter
1113	
1114	if (avatarp->mDrawable.notNull())
1115	{
1116		avatarp->updateLOD();
1117		
1118		LLVertexBuffer::unbind();
1119		LLGLDepthTest gls_depth(GL_TRUE);
1120
1121		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool();
1122		avatarp->dirtyMesh();
1123		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
1124	}
1125
1126	gGL.color4f(1,1,1,1);
1127	return TRUE;
1128}
1129
1130//-----------------------------------------------------------------------------
1131// requestUpdate()
1132//-----------------------------------------------------------------------------
1133void LLPreviewAnimation::requestUpdate()
1134{ 
1135	mNeedsUpdate = TRUE; 
1136}
1137
1138//-----------------------------------------------------------------------------
1139// rotate()
1140//-----------------------------------------------------------------------------
1141void LLPreviewAnimation::rotate(F32 yaw_radians, F32 pitch_radians)
1142{
1143	mCameraYaw = mCameraYaw + yaw_radians;
1144
1145	mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f);
1146}
1147
1148//-----------------------------------------------------------------------------
1149// zoom()
1150//-----------------------------------------------------------------------------
1151void LLPreviewAnimation::zoom(F32 zoom_delta)
1152{
1153	setZoom(mCameraZoom + zoom_delta);
1154}
1155
1156//-----------------------------------------------------------------------------
1157// setZoom()
1158//-----------------------------------------------------------------------------
1159void LLPreviewAnimation::setZoom(F32 zoom_amt)
1160{
1161	mCameraZoom	= llclamp(zoom_amt, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM);
1162}
1163
1164//-----------------------------------------------------------------------------
1165// pan()
1166//-----------------------------------------------------------------------------
1167void LLPreviewAnimation::pan(F32 right, F32 up)
1168{
1169	mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
1170	mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
1171}
1172
1173
1174