/** * @file llpathfindingpathtool.cpp * @brief Implementation of llpathfindingpathtool * @author Stinson@lindenlab.com * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, 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 "llpathfindingpathtool.h" #include <boost/function.hpp> #include <boost/signals2.hpp> #include "llagent.h" #include "llpathfindingmanager.h" #include "llpathinglib.h" #include "llsingleton.h" #include "lltool.h" #include "llviewercamera.h" #include "llviewerregion.h" #include "llviewerwindow.h" #define PATH_TOOL_NAME "PathfindingPathTool" LLPathfindingPathTool::LLPathfindingPathTool() : LLTool(PATH_TOOL_NAME), LLSingleton<LLPathfindingPathTool>(), mFinalPathData(), mTempPathData(), mPathResult(LLPathingLib::LLPL_NO_PATH), mCharacterType(kCharacterTypeNone), mPathEventSignal(), mIsLeftMouseButtonHeld(false), mIsMiddleMouseButtonHeld(false), mIsRightMouseButtonHeld(false) { setCharacterWidth(1.0f); setCharacterType(mCharacterType); } LLPathfindingPathTool::~LLPathfindingPathTool() { } BOOL LLPathfindingPathTool::handleMouseDown(S32 pX, S32 pY, MASK pMask) { BOOL returnVal = FALSE; if (!mIsLeftMouseButtonHeld && !mIsMiddleMouseButtonHeld && !mIsRightMouseButtonHeld) { if (isAnyPathToolModKeys(pMask)) { gViewerWindow->setCursor(isPointAModKeys(pMask) ? UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD : UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD); computeFinalPoints(pX, pY, pMask); mIsLeftMouseButtonHeld = true; setMouseCapture(TRUE); returnVal = TRUE; } else if (!isCameraModKeys(pMask)) { gViewerWindow->setCursor(UI_CURSOR_TOOLNO); mIsLeftMouseButtonHeld = true; setMouseCapture(TRUE); returnVal = TRUE; } } mIsLeftMouseButtonHeld = true; return returnVal; } BOOL LLPathfindingPathTool::handleMouseUp(S32 pX, S32 pY, MASK pMask) { BOOL returnVal = FALSE; if (mIsLeftMouseButtonHeld && !mIsMiddleMouseButtonHeld && !mIsRightMouseButtonHeld) { computeFinalPoints(pX, pY, pMask); setMouseCapture(FALSE); returnVal = TRUE; } mIsLeftMouseButtonHeld = false; return returnVal; } BOOL LLPathfindingPathTool::handleMiddleMouseDown(S32 pX, S32 pY, MASK pMask) { setMouseCapture(TRUE); mIsMiddleMouseButtonHeld = true; gViewerWindow->setCursor(UI_CURSOR_TOOLNO); return TRUE; } BOOL LLPathfindingPathTool::handleMiddleMouseUp(S32 pX, S32 pY, MASK pMask) { if (!mIsLeftMouseButtonHeld && mIsMiddleMouseButtonHeld && !mIsRightMouseButtonHeld) { setMouseCapture(FALSE); } mIsMiddleMouseButtonHeld = false; return TRUE; } BOOL LLPathfindingPathTool::handleRightMouseDown(S32 pX, S32 pY, MASK pMask) { setMouseCapture(TRUE); mIsRightMouseButtonHeld = true; gViewerWindow->setCursor(UI_CURSOR_TOOLNO); return TRUE; } BOOL LLPathfindingPathTool::handleRightMouseUp(S32 pX, S32 pY, MASK pMask) { if (!mIsLeftMouseButtonHeld && !mIsMiddleMouseButtonHeld && mIsRightMouseButtonHeld) { setMouseCapture(FALSE); } mIsRightMouseButtonHeld = false; return TRUE; } BOOL LLPathfindingPathTool::handleDoubleClick(S32 pX, S32 pY, MASK pMask) { return TRUE; } BOOL LLPathfindingPathTool::handleHover(S32 pX, S32 pY, MASK pMask) { BOOL returnVal = FALSE; if (!mIsLeftMouseButtonHeld && !mIsMiddleMouseButtonHeld && !mIsRightMouseButtonHeld && !isAnyPathToolModKeys(pMask)) { gViewerWindow->setCursor(UI_CURSOR_TOOLPATHFINDING); } if (!mIsMiddleMouseButtonHeld && !mIsRightMouseButtonHeld && isAnyPathToolModKeys(pMask)) { gViewerWindow->setCursor(isPointAModKeys(pMask) ? (mIsLeftMouseButtonHeld ? UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD : UI_CURSOR_TOOLPATHFINDING_PATH_START) : (mIsLeftMouseButtonHeld ? UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD : UI_CURSOR_TOOLPATHFINDING_PATH_END)); computeTempPoints(pX, pY, pMask); returnVal = TRUE; } else { clearTemp(); computeFinalPath(); } return returnVal; } BOOL LLPathfindingPathTool::handleKey(KEY pKey, MASK pMask) { // Eat the escape key or else the camera tool will pick up and reset to default view. This, // in turn, will cause some other methods to get called. And one of those methods will reset // the current toolset back to the basic toolset. This means that the pathfinding path toolset // will no longer be active, but typically with pathfinding path elements on screen. return (pKey == KEY_ESCAPE); } LLPathfindingPathTool::EPathStatus LLPathfindingPathTool::getPathStatus() const { EPathStatus status = kPathStatusUnknown; if (LLPathingLib::getInstance() == NULL) { status = kPathStatusNotImplemented; } else if ((gAgent.getRegion() != NULL) && !gAgent.getRegion()->capabilitiesReceived()) { status = kPathStatusUnknown; } else if (!LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion()) { status = kPathStatusNotEnabled; } else if (!hasFinalA() && !hasFinalB()) { status = kPathStatusChooseStartAndEndPoints; } else if (!hasFinalA()) { status = kPathStatusChooseStartPoint; } else if (!hasFinalB()) { status = kPathStatusChooseEndPoint; } else if (mPathResult == LLPathingLib::LLPL_PATH_GENERATED_OK) { status = kPathStatusHasValidPath; } else if (mPathResult == LLPathingLib::LLPL_NO_PATH) { status = kPathStatusHasInvalidPath; } else { status = kPathStatusError; } return status; } F32 LLPathfindingPathTool::getCharacterWidth() const { return mFinalPathData.mCharacterWidth; } void LLPathfindingPathTool::setCharacterWidth(F32 pCharacterWidth) { mFinalPathData.mCharacterWidth = pCharacterWidth; mTempPathData.mCharacterWidth = pCharacterWidth; computeFinalPath(); } LLPathfindingPathTool::ECharacterType LLPathfindingPathTool::getCharacterType() const { return mCharacterType; } void LLPathfindingPathTool::setCharacterType(ECharacterType pCharacterType) { mCharacterType = pCharacterType; LLPathingLib::LLPLCharacterType characterType; switch (pCharacterType) { case kCharacterTypeNone : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_NONE; break; case kCharacterTypeA : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_A; break; case kCharacterTypeB : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_B; break; case kCharacterTypeC : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_C; break; case kCharacterTypeD : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_D; break; default : characterType = LLPathingLib::LLPL_CHARACTER_TYPE_NONE; llassert(0); break; } mFinalPathData.mCharacterType = characterType; mTempPathData.mCharacterType = characterType; computeFinalPath(); } bool LLPathfindingPathTool::isRenderPath() const { return (hasFinalA() || hasFinalB() || hasTempA() || hasTempB()); } void LLPathfindingPathTool::clearPath() { clearFinal(); clearTemp(); computeFinalPath(); } LLPathfindingPathTool::path_event_slot_t LLPathfindingPathTool::registerPathEventListener(path_event_callback_t pPathEventCallback) { return mPathEventSignal.connect(pPathEventCallback); } bool LLPathfindingPathTool::isAnyPathToolModKeys(MASK pMask) const { return ((pMask & (MASK_CONTROL|MASK_SHIFT)) != 0); } bool LLPathfindingPathTool::isPointAModKeys(MASK pMask) const { return ((pMask & MASK_CONTROL) != 0); } bool LLPathfindingPathTool::isPointBModKeys(MASK pMask) const { return ((pMask & MASK_SHIFT) != 0); } bool LLPathfindingPathTool::isCameraModKeys(MASK pMask) const { return ((pMask & MASK_ALT) != 0); } void LLPathfindingPathTool::getRayPoints(S32 pX, S32 pY, LLVector3 &pRayStart, LLVector3 &pRayEnd) const { LLVector3 dv = gViewerWindow->mouseDirectionGlobal(pX, pY); LLVector3 mousePos = LLViewerCamera::getInstance()->getOrigin(); pRayStart = mousePos; pRayEnd = mousePos + dv * 150; } void LLPathfindingPathTool::computeFinalPoints(S32 pX, S32 pY, MASK pMask) { LLVector3 rayStart, rayEnd; getRayPoints(pX, pY, rayStart, rayEnd); if (isPointAModKeys(pMask)) { setFinalA(rayStart, rayEnd); } else if (isPointBModKeys(pMask)) { setFinalB(rayStart, rayEnd); } computeFinalPath(); } void LLPathfindingPathTool::computeTempPoints(S32 pX, S32 pY, MASK pMask) { LLVector3 rayStart, rayEnd; getRayPoints(pX, pY, rayStart, rayEnd); if (isPointAModKeys(pMask)) { setTempA(rayStart, rayEnd); if (hasFinalB()) { setTempB(getFinalBStart(), getFinalBEnd()); } } else if (isPointBModKeys(pMask)) { if (hasFinalA()) { setTempA(getFinalAStart(), getFinalAEnd()); } setTempB(rayStart, rayEnd); } computeTempPath(); } void LLPathfindingPathTool::setFinalA(const LLVector3 &pStartPoint, const LLVector3 &pEndPoint) { mFinalPathData.mStartPointA = pStartPoint; mFinalPathData.mEndPointA = pEndPoint; mFinalPathData.mHasPointA = true; } bool LLPathfindingPathTool::hasFinalA() const { return mFinalPathData.mHasPointA; } const LLVector3 &LLPathfindingPathTool::getFinalAStart() const { return mFinalPathData.mStartPointA; } const LLVector3 &LLPathfindingPathTool::getFinalAEnd() const { return mFinalPathData.mEndPointA; } void LLPathfindingPathTool::setTempA(const LLVector3 &pStartPoint, const LLVector3 &pEndPoint) { mTempPathData.mStartPointA = pStartPoint; mTempPathData.mEndPointA = pEndPoint; mTempPathData.mHasPointA = true; } bool LLPathfindingPathTool::hasTempA() const { return mTempPathData.mHasPointA; } void LLPathfindingPathTool::setFinalB(const LLVector3 &pStartPoint, const LLVector3 &pEndPoint) { mFinalPathData.mStartPointB = pStartPoint; mFinalPathData.mEndPointB = pEndPoint; mFinalPathData.mHasPointB = true; } bool LLPathfindingPathTool::hasFinalB() const { return mFinalPathData.mHasPointB; } const LLVector3 &LLPathfindingPathTool::getFinalBStart() const { return mFinalPathData.mStartPointB; } const LLVector3 &LLPathfindingPathTool::getFinalBEnd() const { return mFinalPathData.mEndPointB; } void LLPathfindingPathTool::setTempB(const LLVector3 &pStartPoint, const LLVector3 &pEndPoint) { mTempPathData.mStartPointB = pStartPoint; mTempPathData.mEndPointB = pEndPoint; mTempPathData.mHasPointB = true; } bool LLPathfindingPathTool::hasTempB() const { return mTempPathData.mHasPointB; } void LLPathfindingPathTool::clearFinal() { mFinalPathData.mHasPointA = false; mFinalPathData.mHasPointB = false; } void LLPathfindingPathTool::clearTemp() { mTempPathData.mHasPointA = false; mTempPathData.mHasPointB = false; } void LLPathfindingPathTool::computeFinalPath() { mPathResult = LLPathingLib::LLPL_NO_PATH; if (LLPathingLib::getInstance() != NULL) { mPathResult = LLPathingLib::getInstance()->generatePath(mFinalPathData); } mPathEventSignal(); } void LLPathfindingPathTool::computeTempPath() { mPathResult = LLPathingLib::LLPL_NO_PATH; if (LLPathingLib::getInstance() != NULL) { mPathResult = LLPathingLib::getInstance()->generatePath(mTempPathData); } mPathEventSignal(); }