From 06ad4408b7aca3dd94abde00d5e427f102e58469 Mon Sep 17 00:00:00 2001 From: Rogerborg Date: Fri, 14 Nov 2008 18:10:47 +0000 Subject: [PATCH] Reducing the optional camera binding to a boolean that binds both ways (rotation to target and vice versa). Thanks to Dorth for suggesting this, which sorts the FPS camera out properly. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1750 dfc29bdd-3216-0410-991c-e03cc46cb475 --- include/ICameraSceneNode.h | 41 +++++++++++---------- source/Irrlicht/CCameraSceneNode.cpp | 53 ++++++++++++++-------------- source/Irrlicht/CCameraSceneNode.h | 23 ++++++++---- source/Irrlicht/CSceneManager.cpp | 4 +-- 4 files changed, 65 insertions(+), 56 deletions(-) diff --git a/include/ICameraSceneNode.h b/include/ICameraSceneNode.h index d6712825..a0f662a8 100644 --- a/include/ICameraSceneNode.h +++ b/include/ICameraSceneNode.h @@ -58,9 +58,18 @@ namespace scene virtual bool OnEvent(const SEvent& event) = 0; //! Sets the look at target of the camera - /** \param pos: Look at target of the camera. */ + /** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's scene node rotation to match the target. + \param pos: Look at target of the camera. */ virtual void setTarget(const core::vector3df& pos) = 0; + //! Sets the rotation of the node. + /** This only modifies the relative rotation of the node. + /** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's target to match the rotation. + \param rotation New rotation of the node in degrees. */ + virtual void setRotation(const core::vector3df& rotation) = 0; + //! Gets the current look at target of the camera /** \return Returns the current look at target of the camera */ virtual const core::vector3df& getTarget() const = 0; @@ -125,27 +134,17 @@ namespace scene return IsOrthogonal; } - //! Determines how the camera's target and its scene node rotation are bound together. - typedef enum _TargetAndRotationBinding - { - //! The target and scene node rotation are independent. - /** This is the default for most cameras. */ - TARGET_AND_ROTATION_INDEPENDENT = 0x10000, + //! Binds the camera scene node's rotation to its target position and vice vera, or unbinds them. + /** When bound, calling setRotation() will update the camera's target position to be along + its +Z axis, and likewise calling setTarget() will update its rotation so that its +Z axis + will point at the target point. FPS camera use this binding by default; other cameras do not. + \param binding true to bind the camera's scene node rotation and targetting, false to unbind them. + @see getTargetAndRotationBinding() */ + virtual void bindTargetAndRotation(bool bound) = 0; - //! The scene node rotation will be updated so that +Z points at the target location. - /** This is the default for FPS camera */ - ROTATION_FOLLOWS_TARGET, - - //! The target position will be updated to be along the node's +Z axis - TARGET_FOLLOWS_ROTATION - - } TargetAndRotationBinding; - - //! Set the binding between the camera's rotation adn target. - virtual void setTargetAndRotationBinding(TargetAndRotationBinding binding) = 0; - - //! Gets the binding between the camera's rotation and target. - virtual TargetAndRotationBinding getTargetAndRotationBinding(void) const = 0; + //! Queries if the camera scene node's rotation and its target position are bound together. + /** @see bindTargetAndRotation() */ + virtual bool getTargetAndRotationBinding(void) const = 0; protected: diff --git a/source/Irrlicht/CCameraSceneNode.cpp b/source/Irrlicht/CCameraSceneNode.cpp index dad838d8..14235b3f 100644 --- a/source/Irrlicht/CCameraSceneNode.cpp +++ b/source/Irrlicht/CCameraSceneNode.cpp @@ -19,7 +19,7 @@ CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 i : ICameraSceneNode(parent, mgr, id, position, core::vector3df(0.0f, 0.0f, 0.0f), core::vector3df(1.0f, 1.0f, 1.0f)), Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f), - InputReceiverEnabled(true) + InputReceiverEnabled(true), TargetAndRotationAreBound(false) { #ifdef _DEBUG setDebugName("CCameraSceneNode"); @@ -110,6 +110,26 @@ bool CCameraSceneNode::OnEvent(const SEvent& event) void CCameraSceneNode::setTarget(const core::vector3df& pos) { Target = pos; + + if(TargetAndRotationAreBound) + { + const core::vector3df toTarget = Target - getAbsolutePosition(); + ISceneNode::setRotation(toTarget.getHorizontalAngle()); + } +} + + +//! Sets the rotation of the node. +/** This only modifies the relative rotation of the node. +/** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) +then calling this will also change the camera's target to match the rotation. +\param rotation New rotation of the node in degrees. */ +void CCameraSceneNode::setRotation(const core::vector3df& rotation) +{ + if(TargetAndRotationAreBound) + Target = getAbsolutePosition() + rotation.rotationToDirection(); + + ISceneNode::setRotation(rotation); } @@ -203,22 +223,6 @@ void CCameraSceneNode::OnRegisterSceneNode() core::vector3df tgtv = Target - pos; tgtv.normalize(); - switch(Binding) - { - case ROTATION_FOLLOWS_TARGET: - setRotation(tgtv.getHorizontalAngle()); - break; - - case TARGET_FOLLOWS_ROTATION: - tgtv = getRotation().rotationToDirection(); // Already normalised - setTarget(pos + tgtv); - break; - - default: - break; - } - - // if upvector and vector to the target are the same, we have a // problem. so solve this problem: core::vector3df up = UpVector; @@ -286,7 +290,7 @@ void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeR out->addFloat("Aspect", Aspect); out->addFloat("ZNear", ZNear); out->addFloat("ZFar", ZFar); - out->addInt("Binding", (int)Binding); + out->addBool("Binding", TargetAndRotationAreBound); } @@ -301,10 +305,7 @@ void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttribute Aspect = in->getAttributeAsFloat("Aspect"); ZNear = in->getAttributeAsFloat("ZNear"); ZFar = in->getAttributeAsFloat("ZFar"); - - Binding = (ICameraSceneNode::TargetAndRotationBinding)in->getAttributeAsInt("Binding"); - if(0 == Binding) - Binding = TARGET_AND_ROTATION_INDEPENDENT; + TargetAndRotationAreBound = in->getAttributeAsBool("Binding"); recalculateProjectionMatrix(); recalculateViewArea(); @@ -312,15 +313,15 @@ void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttribute //! Set the binding between the camera's rotation adn target. -void CCameraSceneNode::setTargetAndRotationBinding(TargetAndRotationBinding binding) +void CCameraSceneNode::bindTargetAndRotation(bool bound) { - Binding = binding; + TargetAndRotationAreBound = bound; } //! Gets the binding between the camera's rotation and target. -ICameraSceneNode::TargetAndRotationBinding CCameraSceneNode::getTargetAndRotationBinding(void) const +bool CCameraSceneNode::getTargetAndRotationBinding(void) const { - return Binding; + return TargetAndRotationAreBound; } diff --git a/source/Irrlicht/CCameraSceneNode.h b/source/Irrlicht/CCameraSceneNode.h index 4a75397a..0a252871 100644 --- a/source/Irrlicht/CCameraSceneNode.h +++ b/source/Irrlicht/CCameraSceneNode.h @@ -47,10 +47,19 @@ namespace scene //! for changing their position, look at target or whatever. virtual bool OnEvent(const SEvent& event); - //! sets the look at target of the camera - //! \param pos: Look at target of the camera. + //! Sets the look at target of the camera + /** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's scene node rotation to match the target. + \param pos: Look at target of the camera. */ virtual void setTarget(const core::vector3df& pos); + //! Sets the rotation of the node. + /** This only modifies the relative rotation of the node. + /** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's target to match the rotation. + \param rotation New rotation of the node in degrees. */ + virtual void setRotation(const core::vector3df& rotation); + //! Gets the current look at target of the camera //! \return Returns the current look at target of the camera virtual const core::vector3df& getTarget() const; @@ -120,11 +129,11 @@ namespace scene //! Returns type of the scene node virtual ESCENE_NODE_TYPE getType() const { return ESNT_CAMERA; } - //! Set the binding between the camera's rotation adn target. - virtual void setTargetAndRotationBinding(TargetAndRotationBinding binding); + //! Binds the camera scene node's rotation to its target position and vice vera, or unbinds them. + virtual void bindTargetAndRotation(bool bound); - //! Gets the binding between the camera's rotation and target. - virtual TargetAndRotationBinding getTargetAndRotationBinding(void) const; + //! Queries if the camera scene node's rotation and its target position are bound together. + virtual bool getTargetAndRotationBinding(void) const; protected: @@ -143,7 +152,7 @@ namespace scene bool InputReceiverEnabled; - TargetAndRotationBinding Binding; + bool TargetAndRotationAreBound; }; } // end namespace diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index f0d2d4cb..80609191 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -667,8 +667,8 @@ ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl, rotateSpeed, moveSpeed, jumpSpeed, keyMapArray, keyMapSize, noVerticalMovement); - // Have the node's rotation follow its target. This is consistent with 1.4.2 and below. - node->setTargetAndRotationBinding(ICameraSceneNode::ROTATION_FOLLOWS_TARGET); + // Bind the node's rotation to its target. This is consistent with 1.4.2 and below. + node->bindTargetAndRotation(true); node->addAnimator(anm); anm->drop();