diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 51fcb4686..5a4b51504 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -19,6 +19,7 @@ namespace MWRender Camera::Camera (Ogre::Camera *camera) : mCamera(camera), mCameraNode(NULL), + mCameraPosNode(NULL), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -66,12 +67,16 @@ namespace MWRender } Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); - if (!mVanity.enabled && !mPreviewMode) { - mCamera->getParentNode()->setOrientation(xr); - } else { + Ogre::Quaternion orient = xr; + if (mVanity.enabled || mPreviewMode) { Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z); - mCamera->getParentNode()->setOrientation(zr * xr); + orient = zr * xr; } + + if (isFirstPerson()) + mCamera->getParentNode()->setOrientation(orient); + else + mCameraNode->setOrientation(orient); } const std::string &Camera::getHandle() const @@ -79,20 +84,40 @@ namespace MWRender return mTrackingPtr.getRefData().getHandle(); } - void Camera::attachTo(const MWWorld::Ptr &ptr) + Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); + node->setInheritScale(false); + Ogre::SceneNode *posNode = node->createChildSceneNode(); + posNode->setInheritScale(false); if(mCameraNode) { node->setOrientation(mCameraNode->getOrientation()); - node->setPosition(mCameraNode->getPosition()); - node->setScale(mCameraNode->getScale()); + posNode->setPosition(mCameraPosNode->getPosition()); mCameraNode->getCreator()->destroySceneNode(mCameraNode); + mCameraNode->getCreator()->destroySceneNode(mCameraPosNode); } mCameraNode = node; - if(!mCamera->isAttached()) - mCameraNode->attachObject(mCamera); + mCameraPosNode = posNode; + + if (!isFirstPerson()) + { + mCamera->detachFromParent(); + mCameraPosNode->attachObject(mCamera); + } + + return mCameraPosNode; + } + + void Camera::setPosition(const Ogre::Vector3& position) + { + mCameraPosNode->setPosition(position); + } + + void Camera::setPosition(float x, float y, float z) + { + setPosition(Ogre::Vector3(x,y,z)); } void Camera::updateListener() @@ -155,9 +180,9 @@ namespace MWRender processViewChange(); if (mFirstPersonView) { - mCamera->setPosition(0.f, 0.f, 0.f); + setPosition(0.f, 0.f, 0.f); } else { - mCamera->setPosition(0.f, 0.f, mCameraDistance); + setPosition(0.f, 0.f, mCameraDistance); } } @@ -191,14 +216,14 @@ namespace MWRender Ogre::Vector3 rot(0.f, 0.f, 0.f); if (mVanity.enabled) { rot.x = Ogre::Degree(-30.f).valueRadians(); - mMainCam.offset = mCamera->getPosition().z; + mMainCam.offset = mCameraPosNode->getPosition().z; } else { rot.x = getPitch(); offset = mMainCam.offset; } rot.z = getYaw(); - mCamera->setPosition(0.f, 0.f, offset); + setPosition(0.f, 0.f, offset); rotateCamera(rot, false); return true; @@ -215,7 +240,7 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCamera->getPosition().z; + float offset = mCameraPosNode->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; offset = mPreviewCam.offset; @@ -224,7 +249,7 @@ namespace MWRender offset = mMainCam.offset; } - mCamera->setPosition(0.f, 0.f, offset); + setPosition(0.f, 0.f, offset); } void Camera::setSneakOffset(float offset) @@ -283,7 +308,7 @@ namespace MWRender float Camera::getCameraDistance() const { - return mCamera->getPosition().z; + return mCameraPosNode->getPosition().z; } void Camera::setCameraDistance(float dist, bool adjust, bool override) @@ -295,7 +320,7 @@ namespace MWRender Ogre::Vector3 v(0.f, 0.f, dist); if (adjust) { - v += mCamera->getPosition(); + v += mCameraPosNode->getPosition(); } if (v.z >= mFurthest) { v.z = mFurthest; @@ -305,7 +330,7 @@ namespace MWRender v.z = mNearest; mIsNearest = true; } - mCamera->setPosition(v); + setPosition(v); if (override) { if (mVanity.enabled || mPreviewMode) { @@ -322,9 +347,9 @@ namespace MWRender { if (mDistanceAdjusted) { if (mVanity.enabled || mPreviewMode) { - mCamera->setPosition(0, 0, mPreviewCam.offset); + setPosition(0, 0, mPreviewCam.offset); } else if (!mFirstPersonView) { - mCamera->setPosition(0, 0, mCameraDistance); + setPosition(0, 0, mCameraDistance); } } mDistanceAdjusted = false; @@ -355,10 +380,10 @@ namespace MWRender Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera); tag->setInheritOrientation(false); } - else + else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mCameraNode->attachObject(mCamera); + mCameraPosNode->attachObject(mCamera); } rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); } @@ -368,8 +393,7 @@ namespace MWRender mCamera->getParentSceneNode()->needUpdate(true); camera = mCamera->getRealPosition(); - focal = Ogre::Vector3((mCamera->getParentNode()->_getFullTransform() * - Ogre::Vector4(0.0f, 0.0f, 0.0f, 1.0f)).ptr()); + focal = mCameraNode->_getDerivedPosition(); } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index f7b0ae6e8..c542dc96c 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -27,6 +27,7 @@ namespace MWRender Ogre::Camera *mCamera; Ogre::SceneNode *mCameraNode; + Ogre::SceneNode *mCameraPosNode; NpcAnimation *mAnimation; @@ -52,6 +53,9 @@ namespace MWRender /// Updates sound manager listener data void updateListener(); + void setPosition(const Ogre::Vector3& position); + void setPosition(float x, float y, float z); + public: Camera(Ogre::Camera *camera); ~Camera(); @@ -72,7 +76,7 @@ namespace MWRender const std::string &getHandle() const; /// Attach camera to object - void attachTo(const MWWorld::Ptr &); + Ogre::SceneNode* attachTo(const MWWorld::Ptr &); /// @param Force view mode switch, even if currently not allowed by the animation. void toggleViewMode(bool force=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 68d5f515d..f476a7807 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -312,7 +312,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) if(mPlayerAnimation) mPlayerAnimation->updatePtr(ptr); if(mCamera->getHandle() == ptr.getRefData().getHandle()) - mCamera->attachTo(ptr); + attachCameraTo(ptr); } void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) @@ -327,7 +327,7 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) anim->rebuild(); if(mCamera->getHandle() == ptr.getRefData().getHandle()) { - mCamera->attachTo(ptr); + attachCameraTo(ptr); mCamera->setAnimation(anim); } } @@ -869,7 +869,13 @@ void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned i void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) { ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); - mCamera->attachTo(ptr); + attachCameraTo(ptr); +} + +void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) +{ + Ogre::SceneNode* cameraNode = mCamera->attachTo(ptr); + mSkyManager->attachToNode(cameraNode); } void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1c735f056..fa48deafa 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -221,6 +221,8 @@ private: void setAmbientMode(); void applyFog(bool underwater); + void attachCameraTo(const MWWorld::Ptr& ptr); + void setMenuTransparency(float val); bool mSunEnabled; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4620173b5..8e7bd3d89 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -382,9 +382,7 @@ void SkyManager::clearRain() for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) { it->second.setNull(); - Ogre::SceneNode* parent = it->first->getParentSceneNode(); mSceneMgr->destroySceneNode(it->first); - mSceneMgr->destroySceneNode(parent); mRainModels.erase(it++); } } @@ -402,9 +400,7 @@ void SkyManager::updateRain(float dt) if (pos.z < -minHeight) { it->second.setNull(); - Ogre::SceneNode* parent = it->first->getParentSceneNode(); mSceneMgr->destroySceneNode(it->first); - mSceneMgr->destroySceneNode(parent); mRainModels.erase(it++); } else @@ -420,17 +416,20 @@ void SkyManager::updateRain(float dt) { mRainTimer = 0; + // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); - Ogre::SceneNode* sceneNode = mCamera->getParentSceneNode()->createChildSceneNode(); - sceneNode->setInheritOrientation(false); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation float startHeight = 700; - Ogre::SceneNode* offsetNode = sceneNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); + Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); + // Spawn a new rain object for each instance. + // TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions + // about the rain meshes being Quads and their dimensions. + // Or we could clone meshes into one vertex buffer manually. NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect); for (unsigned int i=0; imEntities.size(); ++i) { @@ -562,12 +561,6 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } else { - if (!mParticleNode) - { - mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(); - mParticleNode->setInheritOrientation(false); - } - mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); for(size_t i = 0; i < mParticle->mParticles.size(); ++i) { @@ -783,3 +776,16 @@ void SkyManager::setGlareEnabled (bool enabled) return; mSunGlare->setVisible (mSunEnabled && enabled); } + +void SkyManager::attachToNode(SceneNode *sceneNode) +{ + if (!mParticleNode) + { + mParticleNode = sceneNode->createChildSceneNode(); + mParticleNode->setInheritOrientation(false); + } + else + { + sceneNode->addChild(mParticleNode); + } +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e40eb1dce..0544f17ef 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -116,6 +116,9 @@ namespace MWRender SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); ~SkyManager(); + /// Attach weather particle effects to this scene node (should be the Camera's parent node) + void attachToNode(Ogre::SceneNode* sceneNode); + void update(float duration); void enable();