diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 5fdc3cbf5..f90ba4184 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -638,6 +638,9 @@ MwIniImporter::MwIniImporter() "Blood:Texture Name 1", "Blood:Texture Name 2", + // werewolf (Bloodmoon) + "General:Werewolf FOV", + 0 }; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eb2f23529..78ff96532 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -256,7 +256,7 @@ namespace MWGui MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); + fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "Camera"))) + ")"); MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 815671266..4e367b3b1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -274,13 +275,15 @@ NpcAnimation::~NpcAnimation() mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, + bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) : Animation(ptr, parentNode, resourceSystem), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), + mFirstPersonFieldOfView(firstPersonFieldOfView), mSoundsDisabled(disableSounds), mAccurateAiming(false), mAimingFactor(0.f) @@ -336,6 +339,37 @@ public: osg::ref_ptr mDepth; }; +/// Overrides Field of View to given value for rendering the subgraph. +/// Must be added as cull callback. +class OverrideFieldOfViewCallback : public osg::NodeCallback +{ +public: + OverrideFieldOfViewCallback(float fov) + : mFov(fov) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + osg::RefMatrix* projectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + float fov, aspect, zNear, zFar; + if (projectionMatrix->getPerspective(fov, aspect, zNear, zFar)) + { + fov = mFov; + projectionMatrix->makePerspective(fov, aspect, zNear, zFar); + cv->pushProjectionMatrix(projectionMatrix); + traverse(node, nv); + cv->popProjectionMatrix(); + } + else + traverse(node, nv); + } + +private: + float mFov; +}; + void NpcAnimation::setRenderBin() { if (mViewMode == VM_FirstPerson) @@ -445,6 +479,7 @@ void NpcAnimation::updateNpcBase() else { mObjectRoot->setNodeMask(Mask_FirstPerson); + mObjectRoot->addCullCallback(new OverrideFieldOfViewCallback(mFirstPersonFieldOfView)); if(isWerewolf) addAnimSource(smodel); else diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 2289703c8..c5fc62f9c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -61,6 +61,8 @@ private: int mPartPriorities[ESM::PRT_Count]; osg::Vec3f mFirstPersonOffset; + // Field of view to use when rendering first person meshes + float mFirstPersonFieldOfView; boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; @@ -102,7 +104,7 @@ public: * @param viewMode */ NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener = false, - bool disableSounds = false, ViewMode viewMode=VM_Normal); + bool disableSounds = false, ViewMode viewMode=VM_Normal, float firstPersonFieldOfView=55.f); virtual ~NpcAnimation(); virtual void enableHeadAnimation(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f4e7ca684..4b208fa94 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -136,6 +136,8 @@ namespace MWRender , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) + , mFieldOfViewOverride(0.f) + , mFieldOfViewOverridden(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); @@ -205,7 +207,8 @@ namespace MWRender mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); + mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); @@ -727,7 +730,8 @@ namespace MWRender void RenderingManager::renderPlayer(const MWWorld::Ptr &player) { - mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0)); + mPlayerAnimation.reset(new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, false, NpcAnimation::VM_Normal, + mFirstPersonFieldOfView)); mCamera->setAnimation(mPlayerAnimation.get()); mCamera->attachTo(player); @@ -769,7 +773,10 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); - mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); + float fov = mFieldOfView; + if (mFieldOfViewOverridden) + fov = mFieldOfViewOverride; + mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() @@ -808,9 +815,9 @@ namespace MWRender { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { - if (it->first == "General" && it->second == "field of view") + if (it->first == "Camera" && it->second == "field of view") { - mFieldOfView = Settings::Manager::getFloat("field of view", "General"); + mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); updateProjectionMatrix(); } else if (it->first == "Camera" && it->second == "viewing distance") @@ -912,4 +919,23 @@ namespace MWRender mCamera->setCameraDistance(-factor/120.f*10, true, true); } + void RenderingManager::overrideFieldOfView(float val) + { + if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) + { + mFieldOfViewOverridden = true; + mFieldOfViewOverride = val; + updateProjectionMatrix(); + } + } + + void RenderingManager::resetFieldOfView() + { + if (mFieldOfViewOverridden == true) + { + mFieldOfViewOverridden = false; + updateProjectionMatrix(); + } + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 936f7cb99..7b1c8529f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -170,6 +170,11 @@ namespace MWRender void togglePlayerLooking(bool enable); void changeVanityModeScale(float factor); + /// temporarily override the field of view with given value. + void overrideFieldOfView(float val); + /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. + void resetFieldOfView(); + private: void updateProjectionMatrix(); void updateTextureFiltering(); @@ -208,7 +213,10 @@ namespace MWRender float mNearClip; float mViewDistance; + float mFieldOfViewOverride; + bool mFieldOfViewOverridden; float mFieldOfView; + float mFirstPersonFieldOfView; void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0cb2e980d..2436225b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1565,8 +1565,20 @@ namespace MWWorld mPlayer->setLastKnownExteriorPosition(pos.asVec3()); } - if (player.getClass().getNpcStats(player).isWerewolf()) - MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); + bool isWerewolf = player.getClass().getNpcStats(player).isWerewolf(); + bool isFirstPerson = mRendering->getCamera()->isFirstPerson(); + if (isWerewolf && isFirstPerson) + { + float werewolfFov = mFallback.getFallbackFloat("General_Werewolf_FOV"); + if (werewolfFov != 0) + mRendering->overrideFieldOfView(werewolfFov); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(true); + } + else + { + mRendering->resetFieldOfView(); + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(false); + } // Sink the camera while sneaking bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 22d36de2b..6d2424aa5 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -280,7 +280,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7d0292c5b..6de42fd4e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -23,6 +23,14 @@ small feature culling = true # can dramatically affect performance, see documentation for details. viewing distance = 6666.0 +# Camera field of view in degrees (e.g. 30.0 to 110.0). +# Does not affect the player's hands in the first person camera. +field of view = 55.0 + +# Field of view for first person meshes (i.e. the player's hands) +# Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. +first person field of view = 55.0 + [Cells] # Adjacent exterior cells loaded (>0). Caution: this setting can @@ -99,9 +107,6 @@ show effect duration = false # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). anisotropy = 4 -# Camera field of view in degrees (e.g. 30.0 to 110.0). -field of view = 55.0 - # File format for screenshots. (jpg, png, tga, and possibly more). screenshot format = png