phoenix-firestorm/indra/newview/fsmaniprotatejoint.h

176 lines
7.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* @file fsmaniprotatejoint.h
* @brief custom manipulator for rotating joints
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2025 Beq Janus @ Second Life
*
* 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#ifndef FS_MANIP_ROTATE_JOINT_H
#define FS_MANIP_ROTATE_JOINT_H
#include "llselectmgr.h"
#include "llmaniprotate.h"
class LLJoint;
class LLVOAvatar; // for LLVOAvatarSelf, etc.
/// <summary>
/// A set of reference frames for presenting the gimbal within.
/// </summary>
typedef enum E_PoserReferenceFrame
{
POSER_FRAME_BONE = 0, // frame is the bone the gimbal is centered on
POSER_FRAME_WORLD = 1, // frame is world North-South-East-West-Up-Down
POSER_FRAME_AVATAR = 2, // frame is mPelvis rotation
POSER_FRAME_CAMERA = 3, // frame is defined by vector of camera position to bone position
} E_PoserReferenceFrame;
namespace {
const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 85.f * DEG_TO_RAD ); // cos() is not constexpr til c++26
constexpr F32 RADIUS_PIXELS = 100.f; // size in screen space
constexpr S32 CIRCLE_STEPS = 100;
constexpr F32 CIRCLE_STEP_SIZE = 2.0f * F_PI / CIRCLE_STEPS;
constexpr F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
constexpr F32 WIDTH_PIXELS = 8;
constexpr F32 MAX_MANIP_SELECT_DISTANCE = 100.f;
constexpr F32 SNAP_ANGLE_INCREMENT = 5.625f;
constexpr F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT;
constexpr F32 SNAP_GUIDE_RADIUS_1 = 2.8f;
constexpr F32 SNAP_GUIDE_RADIUS_2 = 2.4f;
constexpr F32 SNAP_GUIDE_RADIUS_3 = 2.2f;
constexpr F32 SNAP_GUIDE_RADIUS_4 = 2.1f;
constexpr F32 SNAP_GUIDE_RADIUS_5 = 2.05f;
constexpr F32 SNAP_GUIDE_INNER_RADIUS = 2.f;
constexpr F32 SELECTED_MANIPULATOR_SCALE = 1.05f;
constexpr F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
constexpr S32 VERTICAL_OFFSET = 100;
}
class FSManipRotateJoint : public LLManipRotate
{
// Used for overriding the natural "up" direction of a joint.
// if no override is set then the world up direction is used unless the joint is vertical in which case we pick an arbitrary normal
static std::unordered_map<std::string, LLVector3> sReferenceUpVectors;
struct BoneAxes
{
LLVector3 naturalX;
LLVector3 naturalY;
LLVector3 naturalZ;
};
LLQuaternion computeAlignmentQuat( const BoneAxes& boneAxes ) const;
BoneAxes computeBoneAxes() const;
public:
FSManipRotateJoint(LLToolComposite* composite);
virtual ~FSManipRotateJoint() {}
static std::string getManipPartString(EManipPart part);
/// <summary>
/// Sets the joint we are going to manipulate.
/// </summary>
/// <param name="joint">The joint to interact with.</param>
void setJoint(LLJoint* joint);
/// <summary>
/// Sets the avatar the manip should interact with.
/// </summary>
/// <param name="avatar">The avatar to interact with.</param>
void setAvatar(LLVOAvatar* avatar);
/// <summary>
/// Sets the reference frame for the manipulator.
/// </summary>
/// <param name="avatar">The E_PoserReferenceFrame to use.</param>
void setReferenceFrame(const E_PoserReferenceFrame frame) { mReferenceFrame = frame; };
// Overrides
void handleSelect() override;
bool updateVisiblity() override;
void render() override;
void renderNameXYZ(const LLQuaternion& rot);
bool handleMouseDown(S32 x, S32 y, MASK mask) override;
bool handleMouseUp(S32 x, S32 y, MASK mask) override;
bool handleHover(S32 x, S32 y, MASK mask) override;
void drag(S32 x, S32 y) override;
bool isAlwaysRendered() override { return true; }
void highlightManipulators(S32 x, S32 y) override;
bool handleMouseDownOnPart(S32 x, S32 y, MASK mask) override;
void highlightHoverSpheres(S32 mouseX, S32 mouseY);
protected:
LLQuaternion dragUnconstrained( S32 x, S32 y );
LLQuaternion dragConstrained( S32 x, S32 y );
LLVector3 getConstraintAxis() const { return mConstraintAxis; };
LLVector3 setConstraintAxis();
// Instead of selecting an LLViewerObject, we have a single joint
LLJoint* mJoint = nullptr;
BoneAxes mBoneAxes;
LLQuaternion mNaturalAlignmentQuat;
LLVOAvatar* mAvatar = nullptr;
// We'll store the joint's original rotation for reference
LLQuaternion mSavedJointRot;
LLJoint * mHighlightedJoint = nullptr;
F32 mHighlightedPartDistance = 0.f;
LLVector3 mLastEuler = LLVector3::zero; // last euler angles in degrees
LLVector3 mInitialIntersection; // The initial point on the manipulators sphere (in agent space)
const std::vector<std::string_view> getSelectableJoints(){ return sSelectableJoints; };
private:
bool isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector3& jointWorldPos, F32 jointRadius, F32& outDistanceFromCamera, F32& outDistanceFromCenter) const;
static const std::vector<std::string_view> sSelectableJoints;
// Structure holding parameters needed to render one manipulator ring.
struct RingRenderParams
{
EManipPart part; // e.g. LL_ROT_Z, LL_ROT_Y, LL_ROT_X, etc.
LLVector4 targetScale; // Target scale for mManipulatorScales for this part.
float extraRotateAngle; // Extra rotation angle (in degrees) to apply.
LLVector3 extraRotateAxis; // Axis for the extra rotation.
LLColor4 primaryColor; // Primary ring color.
LLColor4 secondaryColor; // Secondary ring color.
int scaleIndex; // Which component of mManipulatorScales to use (0: X, 1: Y, 2: Z, 3: Roll).
};
static const std::unordered_map<EManipPart, RingRenderParams> sRingParams;
void updateManipulatorScale(EManipPart part, LLVector4& scales);
void renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color);
void renderManipulatorRings(const LLVector3& center, const LLQuaternion& finalAlignment);
void renderCenterCircle(const F32 radius, const LLColor4& normal_color = LLColor4(0.7f,0.7f,0.7f,0.2f), const LLColor4& highlight_color = LLColor4(0.8f,0.8f,0.8f,0.3f)); // <FS:minerjr> add missing f for float
void renderCenterSphere(const F32 radius, const LLColor4& normal_color = LLColor4(0.7f,0.7f,0.7f,0.2f), const LLColor4& highlight_color = LLColor4(0.8f,0.8f,0.8f,0.3f)); // <FS:minerjr> add missing f for float
void renderRingPass(const RingRenderParams& params, float radius, float width, int pass);
void renderAxes(const LLVector3& center, F32 size, const LLQuaternion& rotation);
bool isAvatarJointSafeToUse();
LLQuaternion getSelectedJointWorldRotation();
float mLastAngle = 0.f;
LLVector3 mConstraintAxis;
E_PoserReferenceFrame mReferenceFrame = POSER_FRAME_BONE;
LLQuaternion mLastSetRotation;
};
#endif // FS_MANIP_ROTATE_JOINT_H