PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

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