mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 20:53:50 +00:00
initial 3d-person camera support
This commit is contained in:
parent
2a11a28e81
commit
c46eeaa100
10 changed files with 184 additions and 79 deletions
|
@ -67,7 +67,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
mEnvironment.setFrameDuration (evt.timeSinceLastFrame);
|
||||
|
||||
// update input
|
||||
MWBase::Environment::get().getInputManager()->update();
|
||||
MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame);
|
||||
|
||||
// sound
|
||||
if (mUseSound)
|
||||
|
|
|
@ -248,6 +248,8 @@ namespace MWBase
|
|||
|
||||
virtual bool isSwimming(const MWWorld::Ptr &object) = 0;
|
||||
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0;
|
||||
|
||||
virtual void togglePOV() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace MWInput
|
|||
A_ToggleSneak, //Toggles Sneak, add Push-Sneak later
|
||||
A_ToggleWalk, //Toggle Walking/Running
|
||||
A_Crouch,
|
||||
A_TogglePOV,
|
||||
|
||||
A_QuickSave,
|
||||
A_QuickLoad,
|
||||
|
@ -90,6 +91,8 @@ namespace MWInput
|
|||
|
||||
std::map<std::string, bool> mControlSwitch;
|
||||
|
||||
float mPreviewPOVDelay;
|
||||
|
||||
/* InputImpl Methods */
|
||||
public:
|
||||
void adjustMouseRegion(int width, int height)
|
||||
|
@ -340,6 +343,8 @@ private:
|
|||
|
||||
poller.bind(A_Jump, KC_E);
|
||||
poller.bind(A_Crouch, KC_LCONTROL);
|
||||
|
||||
poller.bind(A_TogglePOV, KC_TAB);
|
||||
}
|
||||
|
||||
void setDragDrop(bool dragDrop)
|
||||
|
@ -348,7 +353,7 @@ private:
|
|||
}
|
||||
|
||||
//NOTE: Used to check for movement keys
|
||||
void update ()
|
||||
void update (float duration)
|
||||
{
|
||||
// Tell OIS to handle all input events
|
||||
input.capture();
|
||||
|
@ -400,6 +405,21 @@ private:
|
|||
player.setUpDown (-1);
|
||||
else
|
||||
player.setUpDown (0);
|
||||
|
||||
if (poller.isDown(A_TogglePOV)) {
|
||||
if (mPreviewPOVDelay <= 0.5 &&
|
||||
(mPreviewPOVDelay += duration) > 0.5)
|
||||
{
|
||||
// enable preview mode
|
||||
}
|
||||
} else {
|
||||
if (mPreviewPOVDelay > 0.5) {
|
||||
//disable preview mode
|
||||
} else if (mPreviewPOVDelay > 0.f) {
|
||||
togglePOV();
|
||||
}
|
||||
mPreviewPOVDelay = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,6 +472,11 @@ private:
|
|||
mControlSwitch[sw] = value;
|
||||
}
|
||||
|
||||
void togglePOV()
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->togglePOV();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/***CONSTRUCTOR***/
|
||||
|
@ -470,9 +495,9 @@ private:
|
|||
delete impl;
|
||||
}
|
||||
|
||||
void MWInputManager::update()
|
||||
void MWInputManager::update(float duration)
|
||||
{
|
||||
impl->update();
|
||||
impl->update(duration);
|
||||
}
|
||||
|
||||
void MWInputManager::setDragDrop(bool dragDrop)
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace MWInput
|
|||
OMW::Engine& engine);
|
||||
virtual ~MWInputManager();
|
||||
|
||||
virtual void update();
|
||||
void update(float duration);
|
||||
|
||||
virtual void changeInputMode(bool guiMode);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreRay.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -12,82 +13,119 @@
|
|||
namespace MWRender
|
||||
{
|
||||
Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node)
|
||||
: mCamera (camera),
|
||||
mNode (node),
|
||||
: mCamera(camera),
|
||||
mPlayerNode(node),
|
||||
mCameraNode(mPlayerNode->createChildSceneNode()),
|
||||
mFirstPersonView(true),
|
||||
mVanityModeEnabled(false)
|
||||
{}
|
||||
|
||||
bool Player::setRotation(const Ogre::Vector3 &rot)
|
||||
mVanityMode(false),
|
||||
mPreviewMode(false)
|
||||
{
|
||||
Ogre::SceneNode *sceneNode = mNode;
|
||||
Ogre::Node* yawNode = sceneNode->getChildIterator().getNext();
|
||||
Ogre::Node* pitchNode = yawNode->getChildIterator().getNext();
|
||||
Ogre::SceneNode *pitchNode = mCameraNode->createChildSceneNode();
|
||||
pitchNode->attachObject(mCamera);
|
||||
}
|
||||
|
||||
bool Player::rotate(const Ogre::Vector3 &rot, bool adjust)
|
||||
{
|
||||
bool force = !mVanityMode && !mPreviewMode;
|
||||
Ogre::Vector3 newRot = rot;
|
||||
|
||||
// we are only interested in X and Y rotation
|
||||
rotateCamera(newRot, adjust);
|
||||
|
||||
// Rotate around X axis
|
||||
Ogre::Radian radx(rot.x);
|
||||
if (radx.valueDegrees() > 89.5f) {
|
||||
radx = Ogre::Degree(89.5f);
|
||||
} else if (radx.valueDegrees() < -89.5f) {
|
||||
radx = Ogre::Degree(-89.5f);
|
||||
if (!force || !mFirstPersonView) {
|
||||
moveCamera(400.f, 1600.f);
|
||||
}
|
||||
Ogre::Quaternion xr(radx, Ogre::Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Ogre::Quaternion yr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Y);
|
||||
|
||||
pitchNode->setOrientation(xr);
|
||||
yawNode->setOrientation(yr);
|
||||
|
||||
updateListener();
|
||||
|
||||
return !mVanityModeEnabled;
|
||||
return force;
|
||||
}
|
||||
|
||||
std::string Player::getHandle() const
|
||||
{
|
||||
return mNode->getName();
|
||||
}
|
||||
|
||||
void Player::attachTo(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
ptr.getRefData().setBaseNode(mNode);
|
||||
}
|
||||
|
||||
bool Player::adjustRotation(const Ogre::Vector3 &rot)
|
||||
void Player::rotateCamera(Ogre::Vector3 &rot, bool adjust)
|
||||
{
|
||||
Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode();
|
||||
Ogre::SceneNode *yawNode = pitchNode->getParentSceneNode();
|
||||
|
||||
float f = controlFlip(Ogre::Radian(rot.x).valueDegrees());
|
||||
if (f != 0.0) {
|
||||
pitchNode->pitch(Ogre::Degree(f));
|
||||
if (adjust) {
|
||||
float f =
|
||||
limitPitchAngle(89.5f, Ogre::Radian(rot.x).valueDegrees());
|
||||
|
||||
if (f != 0.0) {
|
||||
pitchNode->pitch(Ogre::Degree(f));
|
||||
}
|
||||
yawNode->yaw(Ogre::Radian(-rot.z));
|
||||
} else {
|
||||
Ogre::Radian radx(rot.x);
|
||||
if (radx.valueDegrees() > 89.5f) {
|
||||
radx = Ogre::Degree(89.5f);
|
||||
} else if (radx.valueDegrees() < -89.5f) {
|
||||
radx = Ogre::Degree(-89.5f);
|
||||
}
|
||||
Ogre::Quaternion xr(radx, Ogre::Vector3::UNIT_X);
|
||||
Ogre::Quaternion yr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Y);
|
||||
|
||||
pitchNode->setOrientation(xr);
|
||||
yawNode->setOrientation(yr);
|
||||
}
|
||||
yawNode->yaw(Ogre::Radian(-rot.z));
|
||||
|
||||
updateListener();
|
||||
|
||||
return !mVanityModeEnabled;
|
||||
}
|
||||
|
||||
float Player::controlFlip(float shift)
|
||||
void Player::moveCamera(float rsq, float hsq)
|
||||
{
|
||||
Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode();
|
||||
Ogre::Quaternion orient = pitchNode->getOrientation();
|
||||
/*
|
||||
Ogre::Quaternion orient =
|
||||
mCamera->getParentSceneNode()->getOrientation();
|
||||
|
||||
float pitchAngle =
|
||||
(2 * Ogre::Degree(Ogre::Math::ASin(orient.x)).valueDegrees());
|
||||
|
||||
if (pitchAngle + shift < 89.5f && pitchAngle + shift > -89.5f) {
|
||||
orient = mCameraNode->getOrientation();
|
||||
float yawAngle =
|
||||
(2 * Ogre::Degree(Ogre::Math::ASin(orient.y)).valueDegrees());
|
||||
|
||||
float tana = Ogre::Math::Tan(Ogre::Degree(pitchAngle));
|
||||
float tansq = tana * tana;
|
||||
|
||||
float r1 = hsq * rsq / (hsq + rsq * tansq);
|
||||
float zsq = r1 * tansq;
|
||||
r1 = Ogre::Math::Sqrt(r1);
|
||||
|
||||
Ogre::Vector3 pos;
|
||||
pos.y = -Ogre::Math::Sqrt(zsq);
|
||||
pos.z = r1 * Ogre::Math::Sin(Ogre::Degree(yawAngle).valueDegrees());
|
||||
pos.x = r1 * Ogre::Math::Cos(Ogre::Degree(yawAngle).valueDegrees());
|
||||
*/
|
||||
Ogre::Vector3 dir = mCamera->getRealDirection();
|
||||
dir.x = -dir.x, dir.y = -dir.y, dir.z = -dir.z;
|
||||
|
||||
Ogre::Ray ray(Ogre::Vector3(0, 0, 0), dir);
|
||||
|
||||
mCameraNode->setPosition(ray.getPoint(800.f));
|
||||
}
|
||||
|
||||
std::string Player::getHandle() const
|
||||
{
|
||||
return mPlayerNode->getName();
|
||||
}
|
||||
|
||||
void Player::attachTo(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
ptr.getRefData().setBaseNode(mPlayerNode);
|
||||
}
|
||||
|
||||
float Player::limitPitchAngle(float limitAbs, float shift)
|
||||
{
|
||||
Ogre::Quaternion orient =
|
||||
mCamera->getParentSceneNode()->getOrientation();
|
||||
|
||||
float pitchAngle =
|
||||
(2 * Ogre::Degree(Ogre::Math::ASin(orient.x)).valueDegrees());
|
||||
|
||||
if (pitchAngle + shift < limitAbs && pitchAngle + shift > -limitAbs) {
|
||||
return shift;
|
||||
}
|
||||
if (pitchAngle > 0) {
|
||||
float f = 89.5f - pitchAngle - shift;
|
||||
float f = limitAbs - pitchAngle - shift;
|
||||
return (f > 0.f) ? f : 0.f;
|
||||
} else if (pitchAngle < 0) {
|
||||
float f = -89.5 - pitchAngle - shift;
|
||||
float f = -limitAbs - pitchAngle - shift;
|
||||
return (f < 0.f) ? f : 0.f;
|
||||
}
|
||||
return 0.f;
|
||||
|
@ -104,4 +142,38 @@ namespace MWRender
|
|||
|
||||
MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir);
|
||||
}
|
||||
|
||||
void Player::update(float duration)
|
||||
{
|
||||
if (mFirstPersonView && !mVanityMode) {
|
||||
return;
|
||||
}
|
||||
if (mVanityMode) {
|
||||
/// \todo adjust rotation constantly
|
||||
} else {
|
||||
/// \todo move camera closer or change view mode if needed
|
||||
}
|
||||
}
|
||||
|
||||
void Player::toggleViewMode()
|
||||
{
|
||||
mFirstPersonView = !mFirstPersonView;
|
||||
if (mFirstPersonView) {
|
||||
mCameraNode->setPosition(0.f, 0.f, 0.f);
|
||||
} else {
|
||||
moveCamera(400.f, 1600.f);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::toggleVanityMode()
|
||||
{
|
||||
/// \todo move camera
|
||||
mVanityMode = !mVanityMode;
|
||||
}
|
||||
|
||||
void Player::togglePreviewMode()
|
||||
{
|
||||
/// \todo move camera
|
||||
mPreviewMode = !mPreviewMode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,16 +22,24 @@ namespace MWRender
|
|||
class Player
|
||||
{
|
||||
Ogre::Camera *mCamera;
|
||||
Ogre::SceneNode* mNode;
|
||||
|
||||
Ogre::SceneNode *mPlayerNode;
|
||||
Ogre::SceneNode *mCameraNode;
|
||||
|
||||
bool mFirstPersonView;
|
||||
bool mVanityModeEnabled;
|
||||
bool mVanityMode;
|
||||
bool mPreviewMode;
|
||||
|
||||
float controlFlip(float shift = 0.f);
|
||||
float mTimeIdle;
|
||||
|
||||
float limitPitchAngle(float limitAbs, float shift = 0.f);
|
||||
|
||||
/// Updates sound manager listener data
|
||||
void updateListener();
|
||||
|
||||
void rotateCamera(Ogre::Vector3 &rot, bool adjust);
|
||||
void moveCamera(float r, float h);
|
||||
|
||||
public:
|
||||
|
||||
Player (Ogre::Camera *camera, Ogre::SceneNode* mNode);
|
||||
|
@ -39,11 +47,7 @@ namespace MWRender
|
|||
/// Set where the player is looking at. Uses Morrowind (euler) angles
|
||||
/// \param rot Rotation angles in radians
|
||||
/// \return true if player object needs to bo rotated physically
|
||||
bool setRotation(const Ogre::Vector3 &rot);
|
||||
|
||||
/// \param rot Rotation angles in radians
|
||||
/// \return true if player object needs to bo rotated physically
|
||||
bool adjustRotation(const Ogre::Vector3 &rot);
|
||||
bool rotate(const Ogre::Vector3 &rot, bool adjust);
|
||||
|
||||
std::string getHandle() const;
|
||||
|
||||
|
@ -52,13 +56,13 @@ namespace MWRender
|
|||
/// several different objects
|
||||
void attachTo(const MWWorld::Ptr &);
|
||||
|
||||
void toggleViewMode() {
|
||||
mFirstPersonView = !mFirstPersonView;
|
||||
}
|
||||
void toggleViewMode();
|
||||
|
||||
void toggleVanityMode() {
|
||||
mVanityModeEnabled = !mVanityModeEnabled;
|
||||
}
|
||||
void toggleVanityMode();
|
||||
|
||||
void togglePreviewMode();
|
||||
|
||||
void update(float duration);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -133,11 +133,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
mObjects.setMwRoot(mMwRoot);
|
||||
mActors.setMwRoot(mMwRoot);
|
||||
|
||||
|
||||
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
||||
playerNode->pitch(Degree(90));
|
||||
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
||||
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
|
||||
cameraPitchNode->attachObject(mRendering.getCamera());
|
||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||
|
||||
mShadows = new Shadows(&mRendering);
|
||||
|
||||
|
@ -147,7 +146,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||
|
||||
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||
|
||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||
mSun = 0;
|
||||
|
||||
mDebugging = new Debugging(mMwRoot, engine);
|
||||
|
@ -259,11 +257,7 @@ RenderingManager::rotateObject(
|
|||
bool force = true;
|
||||
|
||||
if (isPlayer) {
|
||||
if (adjust) {
|
||||
force = mPlayer->adjustRotation(rot);
|
||||
} else {
|
||||
force = mPlayer->setRotation(rot);
|
||||
}
|
||||
force = mPlayer->rotate(rot, adjust);
|
||||
}
|
||||
MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z);
|
||||
|
||||
|
@ -329,6 +323,8 @@ void RenderingManager::update (float duration){
|
|||
);
|
||||
mWater->update(duration);
|
||||
}
|
||||
|
||||
mPlayer->update(duration);
|
||||
}
|
||||
|
||||
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
|
||||
|
|
|
@ -56,6 +56,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
|
|||
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine);
|
||||
virtual ~RenderingManager();
|
||||
|
||||
void togglePOV() {
|
||||
mPlayer->toggleViewMode();
|
||||
}
|
||||
|
||||
void attachCameraTo(const MWWorld::Ptr &ptr);
|
||||
|
||||
SkyManager* getSkyManager();
|
||||
|
|
|
@ -1151,5 +1151,4 @@ namespace MWWorld
|
|||
}
|
||||
return pos.z < cell.water;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -277,6 +277,9 @@ namespace MWWorld
|
|||
virtual bool isSwimming(const MWWorld::Ptr &object);
|
||||
virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos);
|
||||
|
||||
virtual void togglePOV() {
|
||||
mRendering->togglePOV();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue