/** * @file llfloaterbvhpreview.cpp * @brief LLFloaterBvhPreview class implementation * * $LicenseInfo:firstyear=2004&license=viewergpl$ * Second Life Viewer Source Code * Copyright (c) 2004-2009, Linden Research, Inc. * * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llfloaterbvhpreview.h" #include "llbvhloader.h" #include "lldatapacker.h" #include "lldir.h" #include "llnotificationsutil.h" #include "llvfile.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 "llvoavatarself.h" #include "pipeline.h" #include "lluictrlfactory.h" #include "hippogridmanager.h" // #include "llinventorymodel.h" // gInventoryModel // 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 PREF_BUTTON_HEIGHT = 16; 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; // struct LLSaveInfo { LLSaveInfo(const LLUUID& item_id, const LLUUID& object_id, const std::string& desc, const LLTransactionID tid) : mItemUUID(item_id), mObjectUUID(object_id), mDesc(desc), mTransactionID(tid) { } LLUUID mItemUUID; LLUUID mObjectUUID; std::string mDesc; LLTransactionID mTransactionID; }; // 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, void* item) : LLFloaterNameDesc(filename, item), mItem(item), // mLastMouseX(0), mLastMouseY(0), mPlayButton(nullptr), mStopButton(nullptr) { 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)); } //----------------------------------------------------------------------------- // postBuild() //----------------------------------------------------------------------------- BOOL LLFloaterBvhPreview::postBuild() { LLRect r; LLKeyframeMotion* motionp = NULL; LLBVHLoader* loaderp = NULL; if (!LLFloaterNameDesc::postBuild()) { return FALSE; } mInWorld = gSavedSettings.getBOOL("PreviewAnimInWorld"); getChild("name_form")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitName, this)); if (gSavedSettings.getBOOL("AscentPowerfulWizard")) { getChild("priority")->setMaxValue(7); } childSetLabelArg("ok_btn", "[UPLOADFEE]", gHippoGridManager->getConnectedGrid()->formatFee(LLAgentBenefitsMgr::current().getAnimationUploadCost())); childSetAction("ok_btn", onBtnOK, this); setDefaultBtn(); if (mInWorld) { r = getRect(); translate(0, 230); reshape(r.getWidth(), r.getHeight() - 230); getChild("bad_animation_text")->setValue(getString("in_world")); getChildView("bad_animation_text")->setVisible(TRUE); } else { getChildView("bad_animation_text")->setVisible(FALSE); } mPreviewRect.set(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT, getRect().getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f); S32 y = mPreviewRect.mTop + BTN_HEIGHT; S32 btn_left = PREVIEW_HPAD; r.set( btn_left, y, btn_left + 32, y - BTN_HEIGHT ); mPlayButton = getChild( "play_btn"); mPlayButton->setClickedCallback(boost::bind(&LLFloaterBvhPreview::onBtnPlay,this)); mPlayButton->setImages(std::string("button_anim_play.tga"), std::string("button_anim_play_selected.tga")); mPlayButton->setImageDisabled(NULL); mPlayButton->setImageDisabledSelected(NULL); mPlayButton->setScaleImage(TRUE); mStopButton = getChild( "stop_btn"); mStopButton->setClickedCallback(boost::bind(&LLFloaterBvhPreview::onBtnStop, this)); mStopButton->setImages(std::string("button_anim_stop.tga"), std::string("button_anim_stop_selected.tga")); mStopButton->setImageDisabled(NULL); mStopButton->setImageDisabledSelected(NULL); mStopButton->setScaleImage(TRUE); r.set(r.mRight + PREVIEW_HPAD, y, getRect().getWidth() - PREVIEW_HPAD, y - BTN_HEIGHT); // moved declaration from below BOOL success = false; // std::string exten = gDirUtilp->getExtension(mFilename); if (exten == "bvh") { // loading a bvh file // now load bvh file S32 file_size; LLAPRFile infile(mFilenameAndPath, LL_APR_RB, &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; loaderp = new LLBVHLoader(file_buffer, load_status, line_number); 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; // moved everything bvh from below if(loaderp && loaderp->isInitialized() && loaderp->getDuration() <= MAX_ANIM_DURATION) { // generate unique id for this motion mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); mAnimPreview = new LLPreviewAnimation(256, 256); // 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 if (mInWorld) motionp = (LLKeyframeMotion*)gAgentAvatarp->createMotion(mMotionID); else motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); // create data buffer for keyframe initialization S32 buffer_size = loaderp->getOutputSize(); U8* buffer = new U8[buffer_size]; LLDataPackerBinaryBuffer dp(buffer, buffer_size); // pass animation data through memory buffer loaderp->serialize(dp); dp.reset(); success = motionp && motionp->deserialize(dp, mMotionID); } else { success = false; 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()); } } if (motionp && mInWorld) { gAgentAvatarp->removeMotion(mMotionID); } //setEnabled(FALSE); mMotionID.setNull(); mAnimPreview = NULL; } // } } // else if(exten == "animatn") { S32 file_size; LLAPRFile raw_animatn(mFilenameAndPath, LL_APR_RB, &file_size); if (!raw_animatn.getFileHandle()) { LL_WARNS() << "Can't open animatn file:" << mFilename << LL_ENDL; } else { char* file_buffer; file_buffer = new char[file_size + 1]; if (file_size == raw_animatn.read(file_buffer, file_size)) { file_buffer[file_size] = '\0'; LL_INFOS() << "Loading animatn file " << mFilename << LL_ENDL; mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); mAnimPreview = new LLPreviewAnimation(256, 256); motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); LLDataPackerBinaryBuffer dp((U8*)file_buffer, file_size); dp.reset(); success = motionp && motionp->deserialize(dp, mMotionID); } raw_animatn.close(); delete[] file_buffer; } } // if (success) { setAnimCallbacks() ; if (!mInWorld) { 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()); if (!mInWorld) 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")); } refresh(); delete loaderp; return TRUE; } //----------------------------------------------------------------------------- // LLFloaterBvhPreview() //----------------------------------------------------------------------------- LLFloaterBvhPreview::~LLFloaterBvhPreview() { if (mInWorld) { LLVOAvatar* avatarp = gAgentAvatarp; if (avatarp) { if (mMotionID.notNull()) { avatarp->stopMotion(mMotionID, TRUE); avatarp->removeMotion(mMotionID); } avatarp->deactivateAllMotions(); avatarp->startMotion(ANIM_AGENT_HEAD_ROT); avatarp->startMotion(ANIM_AGENT_EYE); avatarp->startMotion(ANIM_AGENT_BODY_NOISE); avatarp->startMotion(ANIM_AGENT_BREATHE_ROT); avatarp->startMotion(ANIM_AGENT_HAND_MOTION); avatarp->startMotion(ANIM_AGENT_PELVIS_FIX); avatarp->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET); } } mAnimPreview = NULL; setEnabled(FALSE); } //----------------------------------------------------------------------------- // draw() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::draw() { LLFloater::draw(); LLRect r = getRect(); refresh(); if (mMotionID.notNull() && mAnimPreview && !mInWorld) { gGL.color3f(1.f, 1.f, 1.f); gGL.getTexUnit(0)->bind(mAnimPreview); gGL.begin( LLRender::TRIANGLE_STRIP ); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); gGL.texCoord2f(1.f, 0.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); } gGL.end(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); if (!avatarp->areAnimationsPaused()) { mAnimPreview->requestUpdate(); } } } //----------------------------------------------------------------------------- // resetMotion() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::resetMotion() { LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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 (!mInWorld && 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) { if (!mInWorld) { gFocusMgr.setMouseCapture(FALSE); gViewerWindow->showCursor(); } return LLFloater::handleMouseUp(x, y, mask); } //----------------------------------------------------------------------------- // handleHover() //----------------------------------------------------------------------------- BOOL LLFloaterBvhPreview::handleHover(S32 x, S32 y, MASK mask) { if (mInWorld) return TRUE; 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::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 (mInWorld || !mAnimPreview) return false; mAnimPreview->zoom((F32)clicks * -0.2f); mAnimPreview->requestUpdate(); return TRUE; } //----------------------------------------------------------------------------- // onMouseCaptureLost() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onMouseCaptureLost() { if (!mInWorld) gViewerWindow->showCursor(); } //----------------------------------------------------------------------------- // onBtnPlay() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnPlay() { if (!getEnabled()) return; if (mMotionID.notNull()) { LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; if(!avatarp->isMotionActive(mMotionID)) { resetMotion(); mPauseRequest = NULL; } else if (avatarp->areAnimationsPaused()) { mPauseRequest = NULL; } else //onBtnPause() does this in v3 { mPauseRequest = avatarp->requestPause(); } } } //----------------------------------------------------------------------------- // onBtnStop() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnStop() { if (!getEnabled()) return; if (mMotionID.notNull()) { LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; #if 0 // Singu note: See https://jira.secondlife.com/browse/SH-2590 resetMotion(); mPauseRequest = avatarp->requestPause(); #else // // https://jira.secondlife.com/browse/SH-2590?focusedCommentId=286661&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-286661 // Written by Coaldust Numbers. // Is the motion looping and have we passed the loop in point? if (getChild("loop_check")->getValue().asBoolean() && (F32)getChild("loop_in_point")->getValue().asReal() <= (F32)getChild("playback_slider")->getValue().asReal() * 100.f) { avatarp->stopMotion(mMotionID, FALSE); } else { avatarp->stopMotion(mMotionID, TRUE); } // #endif } } //----------------------------------------------------------------------------- // onSliderMove() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onSliderMove() { if (!getEnabled()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); motionp->setPriority(llfloor((F32)getChild("priority")->getValue().asReal())); } //----------------------------------------------------------------------------- // onCommitEaseIn() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitEaseIn() { if (!getEnabled()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); motionp->setEaseIn((F32)getChild("ease_in_time")->getValue().asReal()); resetMotion(); } //----------------------------------------------------------------------------- // onCommitEaseOut() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onCommitEaseOut() { if (!getEnabled()) return; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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()) return false; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return false; 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()) return false; LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return false; 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 { if (!mInWorld) getChildView("bad_animation_text")->setVisible(FALSE); // re-enabled in case previous animation was bad mPlayButton->setEnabled(TRUE); mStopButton->setEnabled(TRUE); LLVOAvatar* avatarp; if (mInWorld && gAgentAvatarp) avatarp = gAgentAvatarp; else if (mAnimPreview) avatarp = mAnimPreview->getDummyAvatar(); else return; 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); if (!mInWorld) mAnimPreview->requestUpdate(); } if (show_play) mPlayButton->setImages(std::string("button_anim_play.tga"), std::string("button_anim_play_selected.tga")); else mPlayButton->setImages(std::string("button_anim_pause.tga"), std::string("button_anim_pause_selected.tga")); } //----------------------------------------------------------------------------- // onBtnOK() //----------------------------------------------------------------------------- void LLFloaterBvhPreview::onBtnOK(void* userdata) { LLFloaterBvhPreview* floaterp = (LLFloaterBvhPreview*)userdata; if (!floaterp->getEnabled()) return; if ((!floaterp->mInWorld && floaterp->mAnimPreview) || (floaterp->mInWorld && gAgentAvatarp)) { LLKeyframeMotion* motionp; if (floaterp->mInWorld) { motionp = (LLKeyframeMotion*)gAgentAvatarp->findMotion(floaterp->mMotionID); } else { motionp = (LLKeyframeMotion*)floaterp->mAnimPreview->getDummyAvatar()->findMotion(floaterp->mMotionID); } S32 file_size = motionp->getFileSize(); U8* buffer = new U8[file_size]; LLDataPackerBinaryBuffer dp(buffer, file_size); if (motionp->serialize(dp)) { LLVFile file(gVFS, motionp->getID(), LLAssetType::AT_ANIMATION, LLVFile::APPEND); S32 size = dp.getCurrentSize(); file.setMaxSize(size); if (file.write((U8*)buffer, size)) { std::string name = floaterp->getChild("name_form")->getValue().asString(); std::string desc = floaterp->getChild("description_form")->getValue().asString(); LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); void *userdata = NULL; // if(floaterp->mItem) { // Update existing item instead of creating a new one LLViewerInventoryItem* item = (LLViewerInventoryItem*)floaterp->mItem; LLSaveInfo* info = new LLSaveInfo(item->getUUID(), LLUUID::null, desc, floaterp->mTransactionID); gAssetStorage->storeAssetData(floaterp->mTransactionID, LLAssetType::AT_ANIMATION, NULL, info, FALSE); // I guess I will do this now because the floater is closing... LLPointer new_item = new LLViewerInventoryItem(item); new_item->setDescription(desc); new_item->setTransactionID(floaterp->mTransactionID); new_item->setAssetUUID(motionp->getID()); new_item->updateServer(FALSE); gInventory.updateItem(new_item); gInventory.notifyObservers(); } else // { upload_new_resource(floaterp->mTransactionID, // tid LLAssetType::AT_ANIMATION, name, desc, 0, LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), name, callback, expected_upload_cost, userdata); } } else { LL_WARNS() << "Failure writing animation data." << LL_ENDL; LLNotificationsUtil::add("WriteAnimationFail"); } } delete [] buffer; // clear out cache for motion data if (floaterp->mInWorld) { gAgentAvatarp->removeMotion(floaterp->mMotionID); gAgentAvatarp->deactivateAllMotions(); } else { floaterp->mAnimPreview->getDummyAvatar()->removeMotion(floaterp->mMotionID); } LLKeyframeDataCache::removeKeyframeData(floaterp->mMotionID); } floaterp->close(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); 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, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); gGL.loadIdentity(); if (LLGLSLShader::sNoFixedFunction) { 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); LLQuaternion av_rot = avatarp->mRoot->getWorldRotation() * camera_rot; LLViewerCamera::getInstance()->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 LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); mCameraRelPos = LLViewerCamera::getInstance()->getOrigin() - avatarp->mHeadp->getWorldPosition(); //avatarp->setAnimationData("LookAtPoint", (void *)&mCameraRelPos); //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(); 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); }