/** * @file llfloaterbvhpreview.cpp * @brief LLFloaterBvhPreview class implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llfloaterbvhpreview.h" #include "llbvhloader.h" #include "lldatapacker.h" #include "lldir.h" #include "llnotificationsutil.h" #include "llfilesystem.h" #include "llapr.h" #include "llstring.h" #include "llagent.h" #include "llagentbenefits.h" #include "llanimationstates.h" #include "llbbox.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldrawable.h" #include "lldrawpoolavatar.h" #include "llrender.h" #include "llface.h" #include "llfocusmgr.h" #include "llkeyframemotion.h" #include "lllineeditor.h" #include "llfloaterperms.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" #include "llviewercamera.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llviewermenufile.h" // upload_new_resource() #include "llvoavatar.h" #include "pipeline.h" #include "lluictrlfactory.h" #include "lltrans.h" const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREVIEW_VPAD = 35; const S32 PREF_BUTTON_HEIGHT = 16 + 35; const S32 PREVIEW_TEXTURE_HEIGHT = 300; const F32 PREVIEW_CAMERA_DISTANCE = 4.f; const F32 MIN_CAMERA_ZOOM = 0.5f; const F32 MAX_CAMERA_ZOOM = 10.f; const F32 BASE_ANIM_TIME_OFFSET = 5.f; std::string STATUS[] = { "E_ST_OK", "E_ST_EOF", "E_ST_NO_CONSTRAINT", "E_ST_NO_FILE", "E_ST_NO_HIER", "E_ST_NO_JOINT", "E_ST_NO_NAME", "E_ST_NO_OFFSET", "E_ST_NO_CHANNELS", "E_ST_NO_ROTATION", "E_ST_NO_AXIS", "E_ST_NO_MOTION", "E_ST_NO_FRAMES", "E_ST_NO_FRAME_TIME", "E_ST_NO_POS", "E_ST_NO_ROT", "E_ST_NO_XLT_FILE", "E_ST_NO_XLT_HEADER", "E_ST_NO_XLT_NAME", "E_ST_NO_XLT_IGNORE", "E_ST_NO_XLT_RELATIVE", "E_ST_NO_XLT_OUTNAME", "E_ST_NO_XLT_MATRIX", "E_ST_NO_XLT_MERGECHILD", "E_ST_NO_XLT_MERGEPARENT", "E_ST_NO_XLT_PRIORITY", "E_ST_NO_XLT_LOOP", "E_ST_NO_XLT_EASEIN", "E_ST_NO_XLT_EASEOUT", "E_ST_NO_XLT_HAND", "E_ST_NO_XLT_EMOTE", "E_ST_BAD_ROOT" }; //----------------------------------------------------------------------------- // LLFloaterBvhPreview() //----------------------------------------------------------------------------- LLFloaterBvhPreview::LLFloaterBvhPreview(const std::string& filename) : LLFloaterNameDesc(filename) { mLastMouseX = 0; mLastMouseY = 0; mIDList["Standing"] = ANIM_AGENT_STAND; mIDList["Walking"] = ANIM_AGENT_FEMALE_WALK; mIDList["Sitting"] = ANIM_AGENT_SIT_FEMALE; mIDList["Flying"] = ANIM_AGENT_HOVER; mIDList["[None]"] = LLUUID::null; mIDList["Aaaaah"] = ANIM_AGENT_EXPRESS_OPEN_MOUTH; mIDList["Afraid"] = ANIM_AGENT_EXPRESS_AFRAID; mIDList["Angry"] = ANIM_AGENT_EXPRESS_ANGER; mIDList["Big Smile"] = ANIM_AGENT_EXPRESS_TOOTHSMILE; mIDList["Bored"] = ANIM_AGENT_EXPRESS_BORED; mIDList["Cry"] = ANIM_AGENT_EXPRESS_CRY; mIDList["Disdain"] = ANIM_AGENT_EXPRESS_DISDAIN; mIDList["Embarrassed"] = ANIM_AGENT_EXPRESS_EMBARRASSED; mIDList["Frown"] = ANIM_AGENT_EXPRESS_FROWN; mIDList["Kiss"] = ANIM_AGENT_EXPRESS_KISS; mIDList["Laugh"] = ANIM_AGENT_EXPRESS_LAUGH; mIDList["Plllppt"] = ANIM_AGENT_EXPRESS_TONGUE_OUT; mIDList["Repulsed"] = ANIM_AGENT_EXPRESS_REPULSED; mIDList["Sad"] = ANIM_AGENT_EXPRESS_SAD; mIDList["Shrug"] = ANIM_AGENT_EXPRESS_SHRUG; mIDList["Smile"] = ANIM_AGENT_EXPRESS_SMILE; mIDList["Surprise"] = ANIM_AGENT_EXPRESS_SURPRISE; mIDList["Wink"] = ANIM_AGENT_EXPRESS_WINK; mIDList["Worry"] = ANIM_AGENT_EXPRESS_WORRY; } //----------------------------------------------------------------------------- // setAnimCallbacks() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::setAnimCallbacks() { getChild("playback_slider")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onSliderMove, this)); getChild("preview_base_anim")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitBaseAnim, this)); getChild("preview_base_anim")->setValue("Standing"); getChild("priority")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitPriority, this)); getChild("loop_check")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoop, this)); getChild("loop_in_point")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoopIn, this)); getChild("loop_in_point")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopIn, this, _1)); getChild("loop_out_point")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoopOut, this)); getChild("loop_out_point")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopOut, this, _1)); getChild("hand_pose_combo")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitHandPose, this)); getChild("emote_combo")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitEmote, this)); getChild("emote_combo")->setValue("[None]"); getChild("ease_in_time")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitEaseIn, this)); getChild("ease_in_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseIn, this, _1)); getChild("ease_out_time")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitEaseOut, this)); getChild("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseOut, this, _1)); } std::map LLFloaterBvhPreview::getJointAliases() { LLPointer av = (LLVOAvatar*)mAnimPreview->getDummyAvatar(); return av->getJointAliases(); } //----------------------------------------------------------------------------- // postBuild() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::postBuild() { LLKeyframeMotion* motionp = NULL; LLBVHLoader* loaderp = NULL; if (!LLFloaterNameDesc::postBuild()) { return false; } getChild("name_form")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitName, this)); childSetAction("ok_btn", onBtnOK, this); setDefaultBtn(); mPreviewRect.set(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD, getRect().getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f); mPlayButton = getChild( "play_btn"); mPlayButton->setClickedCallback(boost::bind(&LLFloaterBvhPreview::onBtnPlay, this)); mPlayButton->setVisible(true); mPauseButton = getChild( "pause_btn"); mPauseButton->setClickedCallback(boost::bind(&LLFloaterBvhPreview::onBtnPause, this)); mPauseButton->setVisible(false); mStopButton = getChild( "stop_btn"); mStopButton->setClickedCallback(boost::bind(&LLFloaterBvhPreview::onBtnStop, this)); getChildView("bad_animation_text")->setVisible(false); mAnimPreview = new LLPreviewAnimation(256, 256); std::string exten = gDirUtilp->getExtension(mFilename); if (exten == "bvh") { // loading a bvh file // now load bvh file S32 file_size; LLAPRFile infile ; infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size); if (!infile.getFileHandle()) { LL_WARNS() << "Can't open BVH file:" << mFilename << LL_ENDL; } else { char* file_buffer; file_buffer = new char[file_size + 1]; if (file_size == infile.read(file_buffer, file_size)) { file_buffer[file_size] = '\0'; LL_INFOS() << "Loading BVH file " << mFilename << LL_ENDL; ELoadStatus load_status = E_ST_OK; S32 line_number = 0; std::map joint_alias_map = getJointAliases(); loaderp = new LLBVHLoader(file_buffer, load_status, line_number, joint_alias_map); std::string status = getString(STATUS[load_status]); if(load_status == E_ST_NO_XLT_FILE) { LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; } else { LL_WARNS() << "ERROR: [line: " << line_number << "] " << status << LL_ENDL; } } infile.close() ; delete[] file_buffer; } } if (loaderp && loaderp->isInitialized() && loaderp->getDuration() <= MAX_ANIM_DURATION) { // generate unique id for this motion mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); // motion will be returned, but it will be in a load-pending state, as this is a new motion // this motion will not request an asset transfer until next update, so we have a chance to // load the keyframe data locally motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); // create data buffer for keyframe initialization S32 buffer_size = loaderp->getOutputSize(); U8* buffer = new(std::nothrow) U8[buffer_size]; if (!buffer) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Bad memory allocation for buffer, size: " << buffer_size << LL_ENDL; } LLDataPackerBinaryBuffer dp(buffer, buffer_size); // pass animation data through memory buffer LL_INFOS("BVH") << "Serializing loaderp" << LL_ENDL; loaderp->serialize(dp); dp.reset(); LL_INFOS("BVH") << "Deserializing motionp" << LL_ENDL; bool success = motionp && motionp->deserialize(dp, mMotionID, false); LL_INFOS("BVH") << "Done" << LL_ENDL; delete []buffer; if (success) { setAnimCallbacks() ; const LLBBoxLocal &pelvis_bbox = motionp->getPelvisBBox(); LLVector3 temp = pelvis_bbox.getCenter(); // only consider XY? //temp.mV[VZ] = 0.f; F32 pelvis_offset = temp.magVec(); temp = pelvis_bbox.getExtent(); //temp.mV[VZ] = 0.f; F32 pelvis_max_displacement = pelvis_offset + (temp.magVec() * 0.5f) + 1.f; F32 camera_zoom = LLViewerCamera::getInstance()->getDefaultFOV() / (2.f * atan(pelvis_max_displacement / PREVIEW_CAMERA_DISTANCE)); mAnimPreview->setZoom(camera_zoom); motionp->setName(getChild("name_form")->getValue().asString()); mAnimPreview->getDummyAvatar()->startMotion(mMotionID); getChild("playback_slider")->setMinValue(0.0); getChild("playback_slider")->setMaxValue(1.0); getChild("loop_check")->setValue(LLSD(motionp->getLoop())); getChild("loop_in_point")->setValue(LLSD(motionp->getLoopIn() / motionp->getDuration() * 100.f)); getChild("loop_out_point")->setValue(LLSD(motionp->getLoopOut() / motionp->getDuration() * 100.f)); getChild("priority")->setValue(LLSD((F32)motionp->getPriority())); getChild("hand_pose_combo")->setValue(LLHandMotion::getHandPoseName(motionp->getHandPose())); getChild("ease_in_time")->setValue(LLSD(motionp->getEaseInDuration())); getChild("ease_out_time")->setValue(LLSD(motionp->getEaseOutDuration())); setEnabled(true); std::string seconds_string; seconds_string = llformat(" - %.2f seconds", motionp->getDuration()); setTitle(mFilename + std::string(seconds_string)); } else { mAnimPreview = NULL; mMotionID.setNull(); getChild("bad_animation_text")->setValue(getString("failed_to_initialize")); } } else { if ( loaderp ) { if (loaderp->getDuration() > MAX_ANIM_DURATION) { LLUIString out_str = getString("anim_too_long"); out_str.setArg("[LENGTH]", llformat("%.1f", loaderp->getDuration())); out_str.setArg("[MAX_LENGTH]", llformat("%.1f", MAX_ANIM_DURATION)); getChild("bad_animation_text")->setValue(out_str.getString()); } else { LLUIString out_str = getString("failed_file_read"); out_str.setArg("[STATUS]", getString(STATUS[loaderp->getStatus()])); getChild("bad_animation_text")->setValue(out_str.getString()); } } //setEnabled(false); mMotionID.setNull(); mAnimPreview = NULL; } refresh(); delete loaderp; return true; } //----------------------------------------------------------------------------- // LLFloaterBvhPreview() //----------------------------------------------------------------------------- LLFloaterBvhPreview::~LLFloaterBvhPreview() { mAnimPreview = NULL; setEnabled(false); } //----------------------------------------------------------------------------- // draw() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::draw() { LLFloater::draw(); LLRect r = getRect(); refresh(); if (mMotionID.notNull() && mAnimPreview) { gGL.color3f(1.f, 1.f, 1.f); gGL.getTexUnit(0)->bind(mAnimPreview); gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 0.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT + PREVIEW_VPAD); } gGL.end(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); if (!avatarp->areAnimationsPaused()) { mAnimPreview->requestUpdate(); } } } //----------------------------------------------------------------------------- // resetMotion() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::resetMotion() { if (!mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); bool paused = avatarp->areAnimationsPaused(); LLKeyframeMotion* motionp = dynamic_cast(avatarp->findMotion(mMotionID)); if( motionp ) { // Set emotion std::string emote = getChild("emote_combo")->getValue().asString(); motionp->setEmote(mIDList[emote]); } LLUUID base_id = mIDList[getChild("preview_base_anim")->getValue().asString()]; avatarp->deactivateAllMotions(); avatarp->startMotion(mMotionID, 0.0f); avatarp->startMotion(base_id, BASE_ANIM_TIME_OFFSET); getChild("playback_slider")->setValue(0.0f); // Set pose std::string handpose = getChild("hand_pose_combo")->getValue().asString(); avatarp->startMotion( ANIM_AGENT_HAND_MOTION, 0.0f ); if( motionp ) { motionp->setHandPose(LLHandMotion::getHandPose(handpose)); } if (paused) { mPauseRequest = avatarp->requestPause(); } else { mPauseRequest = NULL; } } //----------------------------------------------------------------------------- // handleMouseDown() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::handleMouseDown(S32 x, S32 y, MASK mask) { if (mPreviewRect.pointInRect(x, y)) { bringToFront( x, y ); gFocusMgr.setMouseCapture(this); gViewerWindow->hideCursor(); mLastMouseX = x; mLastMouseY = y; return true; } return LLFloater::handleMouseDown(x, y, mask); } //----------------------------------------------------------------------------- // handleMouseUp() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::handleMouseUp(S32 x, S32 y, MASK mask) { gFocusMgr.setMouseCapture(nullptr); gViewerWindow->showCursor(); return LLFloater::handleMouseUp(x, y, mask); } //----------------------------------------------------------------------------- // handleHover() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::handleHover(S32 x, S32 y, MASK mask) { MASK local_mask = mask & ~MASK_ALT; if (mAnimPreview && hasMouseCapture()) { if (local_mask == MASK_PAN) { // pan here mAnimPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); } else if (local_mask == MASK_ORBIT) { F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; mAnimPreview->rotate(yaw_radians, pitch_radians); } else { F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; mAnimPreview->rotate(yaw_radians, 0.f); mAnimPreview->zoom(zoom_amt); } mAnimPreview->requestUpdate(); LLUI::getInstance()->setMousePositionLocal(this, mLastMouseX, mLastMouseY); } if (!mPreviewRect.pointInRect(x, y) || !mAnimPreview) { return LLFloater::handleHover(x, y, mask); } else if (local_mask == MASK_ORBIT) { gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); } else if (local_mask == MASK_PAN) { gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); } else { gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); } return true; } //----------------------------------------------------------------------------- // handleScrollWheel() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) { if (!mAnimPreview) return false; mAnimPreview->zoom((F32)clicks * -0.2f); mAnimPreview->requestUpdate(); return true; } //----------------------------------------------------------------------------- // onMouseCaptureLost() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onMouseCaptureLost() { gViewerWindow->showCursor(); } //----------------------------------------------------------------------------- // onBtnPlay() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnPlay() { if (!getEnabled()) return; if (mMotionID.notNull() && mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); if (!avatarp->isMotionActive(mMotionID)) { resetMotion(); mPauseRequest = NULL; } else if (avatarp->areAnimationsPaused()) { mPauseRequest = NULL; } } } //----------------------------------------------------------------------------- // onBtnPause() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnPause() { if (!getEnabled()) return; if (mMotionID.notNull() && mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); if (avatarp->isMotionActive(mMotionID)) { if (!avatarp->areAnimationsPaused()) { mPauseRequest = avatarp->requestPause(); } } } } //----------------------------------------------------------------------------- // onBtnStop() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnStop() { if (!getEnabled()) return; if (mMotionID.notNull() && mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); resetMotion(); mPauseRequest = avatarp->requestPause(); } } //----------------------------------------------------------------------------- // onSliderMove() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onSliderMove() { if (!getEnabled()) return; if (mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); F32 slider_value = (F32)getChild("playback_slider")->getValue().asReal(); LLUUID base_id = mIDList[getChild("preview_base_anim")->getValue().asString()]; LLMotion* motionp = avatarp->findMotion(mMotionID); F32 duration = motionp->getDuration();// + motionp->getEaseOutDuration(); F32 delta_time = duration * slider_value; avatarp->deactivateAllMotions(); avatarp->startMotion(base_id, delta_time + BASE_ANIM_TIME_OFFSET); avatarp->startMotion(mMotionID, delta_time); mPauseRequest = avatarp->requestPause(); refresh(); } } //----------------------------------------------------------------------------- // onCommitBaseAnim() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitBaseAnim() { if (!getEnabled()) return; if (mAnimPreview) { LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); bool paused = avatarp->areAnimationsPaused(); // stop all other possible base motions avatarp->stopMotion(mIDList["Standing"], true); avatarp->stopMotion(mIDList["Walking"], true); avatarp->stopMotion(mIDList["Sitting"], true); avatarp->stopMotion(mIDList["Flying"], true); resetMotion(); if (!paused) { mPauseRequest = NULL; } } } //----------------------------------------------------------------------------- // onCommitLoop() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitLoop() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (motionp) { motionp->setLoop(getChild("loop_check")->getValue().asBoolean()); motionp->setLoopIn((F32)getChild("loop_in_point")->getValue().asReal() * 0.01f * motionp->getDuration()); motionp->setLoopOut((F32)getChild("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration()); } } //----------------------------------------------------------------------------- // onCommitLoopIn() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitLoopIn() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (motionp) { motionp->setLoopIn((F32)getChild("loop_in_point")->getValue().asReal() / 100.f); resetMotion(); getChild("loop_check")->setValue(LLSD(true)); onCommitLoop(); } } //----------------------------------------------------------------------------- // onCommitLoopOut() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitLoopOut() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (motionp) { motionp->setLoopOut((F32)getChild("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration()); resetMotion(); getChild("loop_check")->setValue(LLSD(true)); onCommitLoop(); } } //----------------------------------------------------------------------------- // onCommitName() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitName() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (motionp) { motionp->setName(getChild("name_form")->getValue().asString()); } doCommit(); } //----------------------------------------------------------------------------- // onCommitHandPose() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitHandPose() { if (!getEnabled()) return; resetMotion(); // sets hand pose } //----------------------------------------------------------------------------- // onCommitEmote() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitEmote() { if (!getEnabled()) return; resetMotion(); // ssts emote } //----------------------------------------------------------------------------- // onCommitPriority() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitPriority() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); motionp->setPriority(llfloor((F32)getChild("priority")->getValue().asReal())); } //----------------------------------------------------------------------------- // onCommitEaseIn() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitEaseIn() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); motionp->setEaseIn((F32)getChild("ease_in_time")->getValue().asReal()); resetMotion(); } //----------------------------------------------------------------------------- // onCommitEaseOut() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitEaseOut() { if (!getEnabled() || !mAnimPreview) return; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); motionp->setEaseOut((F32)getChild("ease_out_time")->getValue().asReal()); resetMotion(); } //----------------------------------------------------------------------------- // validateEaseIn() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::validateEaseIn(const LLSD& data) { if (!getEnabled() || !mAnimPreview) return false; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (!motionp->getLoop()) { F32 new_ease_in = llclamp((F32)getChild("ease_in_time")->getValue().asReal(), 0.f, motionp->getDuration() - motionp->getEaseOutDuration()); getChild("ease_in_time")->setValue(LLSD(new_ease_in)); } return true; } //----------------------------------------------------------------------------- // validateEaseOut() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::validateEaseOut(const LLSD& data) { if (!getEnabled() || !mAnimPreview) return false; LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (!motionp->getLoop()) { F32 new_ease_out = llclamp((F32)getChild("ease_out_time")->getValue().asReal(), 0.f, motionp->getDuration() - motionp->getEaseInDuration()); getChild("ease_out_time")->setValue(LLSD(new_ease_out)); } return true; } //----------------------------------------------------------------------------- // validateLoopIn() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::validateLoopIn(const LLSD& data) { if (!getEnabled()) return false; F32 loop_in_value = (F32)getChild("loop_in_point")->getValue().asReal(); F32 loop_out_value = (F32)getChild("loop_out_point")->getValue().asReal(); if (loop_in_value < 0.f) { loop_in_value = 0.f; } else if (loop_in_value > 100.f) { loop_in_value = 100.f; } else if (loop_in_value > loop_out_value) { loop_in_value = loop_out_value; } getChild("loop_in_point")->setValue(LLSD(loop_in_value)); return true; } //----------------------------------------------------------------------------- // validateLoopOut() //----------------------------------------------------------------------------- bool LLFloaterBvhPreview::validateLoopOut(const LLSD& data) { if (!getEnabled()) return false; F32 loop_out_value = (F32)getChild("loop_out_point")->getValue().asReal(); F32 loop_in_value = (F32)getChild("loop_in_point")->getValue().asReal(); if (loop_out_value < 0.f) { loop_out_value = 0.f; } else if (loop_out_value > 100.f) { loop_out_value = 100.f; } else if (loop_out_value < loop_in_value) { loop_out_value = loop_in_value; } getChild("loop_out_point")->setValue(LLSD(loop_out_value)); return true; } //----------------------------------------------------------------------------- // refresh() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::refresh() { // Are we showing the play button (default) or the pause button? bool show_play = true; if (!mAnimPreview) { getChildView("bad_animation_text")->setVisible(true); // play button visible but disabled mPlayButton->setEnabled(false); mStopButton->setEnabled(false); getChildView("ok_btn")->setEnabled(false); } else { getChildView("bad_animation_text")->setVisible(false); // re-enabled in case previous animation was bad mPlayButton->setEnabled(true); mStopButton->setEnabled(true); LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); if (avatarp->isMotionActive(mMotionID)) { mStopButton->setEnabled(true); LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (!avatarp->areAnimationsPaused()) { // animation is playing if (motionp) { F32 fraction_complete = motionp->getLastUpdateTime() / motionp->getDuration(); getChild("playback_slider")->setValue(fraction_complete); } show_play = false; } } else { // Motion just finished playing mPauseRequest = avatarp->requestPause(); } getChildView("ok_btn")->setEnabled(true); mAnimPreview->requestUpdate(); } mPlayButton->setVisible(show_play); mPauseButton->setVisible(!show_play); } //----------------------------------------------------------------------------- // onBtnOK() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnOK(void* userdata) { LLFloaterBvhPreview* floaterp = (LLFloaterBvhPreview*)userdata; if (!floaterp->getEnabled()) return; if (floaterp->mAnimPreview) { LLKeyframeMotion* motionp = (LLKeyframeMotion*)floaterp->mAnimPreview->getDummyAvatar()->findMotion(floaterp->mMotionID); S32 file_size = motionp->getFileSize(); U8* buffer = new(std::nothrow) U8[file_size]; if (!buffer) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Bad memory allocation for buffer, size: " << file_size << LL_ENDL; } LLDataPackerBinaryBuffer dp(buffer, file_size); if (motionp->serialize(dp)) { LLFileSystem file(motionp->getID(), LLAssetType::AT_ANIMATION, LLFileSystem::APPEND); S32 size = dp.getCurrentSize(); if (file.write((U8*)buffer, size)) { std::string name = floaterp->getChild("name_form")->getValue().asString(); std::string desc = floaterp->getChild("description_form")->getValue().asString(); S32 expected_upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( floaterp->mTransactionID, LLAssetType::AT_ANIMATION, name, desc, 0, LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), expected_upload_cost)); upload_new_resource(assetUploadInfo); } else { LL_WARNS() << "Failure writing animation data." << LL_ENDL; LLNotificationsUtil::add("WriteAnimationFail"); } } delete [] buffer; // clear out cache for motion data floaterp->mAnimPreview->getDummyAvatar()->removeMotion(floaterp->mMotionID); LLKeyframeDataCache::removeKeyframeData(floaterp->mMotionID); } floaterp->closeFloater(false); } //----------------------------------------------------------------------------- // LLPreviewAnimation //----------------------------------------------------------------------------- LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, false) { mNeedsUpdate = true; mCameraDistance = PREVIEW_CAMERA_DISTANCE; mCameraYaw = 0.f; mCameraPitch = 0.f; mCameraZoom = 1.f; mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); mDummyAvatar->mSpecialRenderMode = 1; mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET); // on idle overall apperance update will set skirt to visible, so either // call early or account for mSpecialRenderMode in updateMeshVisibility mDummyAvatar->updateOverallAppearance(); mDummyAvatar->hideHair(); mDummyAvatar->hideSkirt(); // stop extraneous animations mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, true ); mDummyAvatar->stopMotion( ANIM_AGENT_EYE, true ); mDummyAvatar->stopMotion( ANIM_AGENT_BODY_NOISE, true ); mDummyAvatar->stopMotion( ANIM_AGENT_BREATHE_ROT, true ); } //----------------------------------------------------------------------------- // LLPreviewAnimation() //----------------------------------------------------------------------------- LLPreviewAnimation::~LLPreviewAnimation() { mDummyAvatar->markDead(); } //virtual S8 LLPreviewAnimation::getType() const { return LLViewerDynamicTexture::LL_PREVIEW_ANIMATION ; } //----------------------------------------------------------------------------- // update() //----------------------------------------------------------------------------- bool LLPreviewAnimation::render() { mNeedsUpdate = false; LLVOAvatar* avatarp = mDummyAvatar; gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.loadIdentity(); gGL.ortho(0.0f, (F32)mFullWidth, 0.0f, (F32)mFullHeight, -1.0f, 1.0f); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); gGL.loadIdentity(); gUIProgram.bind(); LLGLSUIDefault def; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); gl_rect_2d_simple( mFullWidth, mFullHeight ); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.popMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); gGL.flush(); LLVector3 target_pos = avatarp->mRoot->getWorldPosition(); LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * LLQuaternion(mCameraYaw, LLVector3::z_axis); LLViewerCamera* camera = LLViewerCamera::getInstance(); LLQuaternion av_rot = avatarp->mRoot->getWorldRotation() * camera_rot; camera->setOriginAndLookAt( target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + mCameraOffset) * av_rot), // camera LLVector3::z_axis, // up target_pos + (mCameraOffset * av_rot) ); // point of interest camera->setViewNoBroadcast(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); camera->setAspect((F32) mFullWidth / (F32) mFullHeight); camera->setPerspective(false, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, false); //SJB: Animation is updated in LLVOAvatar::updateCharacter if (avatarp->mDrawable.notNull()) { avatarp->updateLOD(); LLVertexBuffer::unbind(); LLGLDepthTest gls_depth(GL_TRUE); LLFace* face = avatarp->mDrawable->getFace(0); if (face) { LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool(); avatarp->dirtyMesh(); gPipeline.enableLightsPreview(); avatarPoolp->renderAvatars(avatarp); // renders only one avatar } } gGL.color4f(1,1,1,1); return true; } //----------------------------------------------------------------------------- // requestUpdate() //----------------------------------------------------------------------------- void LLPreviewAnimation::requestUpdate() { mNeedsUpdate = true; } //----------------------------------------------------------------------------- // rotate() //----------------------------------------------------------------------------- void LLPreviewAnimation::rotate(F32 yaw_radians, F32 pitch_radians) { mCameraYaw = mCameraYaw + yaw_radians; mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); } //----------------------------------------------------------------------------- // zoom() //----------------------------------------------------------------------------- void LLPreviewAnimation::zoom(F32 zoom_delta) { setZoom(mCameraZoom + zoom_delta); } //----------------------------------------------------------------------------- // setZoom() //----------------------------------------------------------------------------- void LLPreviewAnimation::setZoom(F32 zoom_amt) { mCameraZoom = llclamp(zoom_amt, MIN_CAMERA_ZOOM, MAX_CAMERA_ZOOM); } //----------------------------------------------------------------------------- // pan() //----------------------------------------------------------------------------- void LLPreviewAnimation::pan(F32 right, F32 up) { mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); }