mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-11 07:41:32 +00:00
Merge branch 'sky_shaders' into 'master'
Sky shaders See merge request OpenMW/openmw!1057
This commit is contained in:
commit
b3f84df43c
13 changed files with 3440 additions and 2950 deletions
|
@ -12,6 +12,8 @@
|
||||||
Bug #4602: Robert's Bodies: crash inside createInstance()
|
Bug #4602: Robert's Bodies: crash inside createInstance()
|
||||||
Bug #4700: Editor: Incorrect command implementation
|
Bug #4700: Editor: Incorrect command implementation
|
||||||
Bug #4744: Invisible particles must still be processed
|
Bug #4744: Invisible particles must still be processed
|
||||||
|
Bug #4752: UpdateCellCommand doesn't undo properly
|
||||||
|
Bug #5088: Sky abruptly changes direction during certain weather transitions
|
||||||
Bug #5100: Persuasion doesn't always clamp the resulting disposition
|
Bug #5100: Persuasion doesn't always clamp the resulting disposition
|
||||||
Bug #5120: Scripted object spawning updates physics system
|
Bug #5120: Scripted object spawning updates physics system
|
||||||
Bug #5207: Loose summons can be present in scene
|
Bug #5207: Loose summons can be present in scene
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
||||||
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
||||||
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
||||||
|
Bug #6168: Weather particles flicker for a frame at start of storms
|
||||||
Bug #6172: Some creatures can't open doors
|
Bug #6172: Some creatures can't open doors
|
||||||
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
||||||
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
||||||
|
@ -76,6 +79,7 @@
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
Feature #6032: Reverse-z depth buffer
|
Feature #6032: Reverse-z depth buffer
|
||||||
Feature #6078: First person should not clear depth buffer
|
Feature #6078: First person should not clear depth buffer
|
||||||
|
Feature #6161: Refactor Sky to use shaders and GLES/GL3 friendly
|
||||||
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
||||||
Feature #6199: Support FBO Rendering
|
Feature #6199: Support FBO Rendering
|
||||||
Feature #6249: Alpha testing support for Collada
|
Feature #6249: Alpha testing support for Collada
|
||||||
|
|
|
@ -19,7 +19,7 @@ set(GAME_HEADER
|
||||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
actors objects renderingmanager animation rotatecontroller sky skyutil npcanimation vismask
|
||||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
|
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
|
||||||
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
||||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
|
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,10 +8,7 @@
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osg/Vec4f>
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
namespace osg
|
#include "skyutil.hpp"
|
||||||
{
|
|
||||||
class Camera;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -19,6 +16,7 @@ namespace osg
|
||||||
class Node;
|
class Node;
|
||||||
class Material;
|
class Material;
|
||||||
class PositionAttitudeTransform;
|
class PositionAttitudeTransform;
|
||||||
|
class Camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace osgParticle
|
namespace osgParticle
|
||||||
|
@ -45,80 +43,6 @@ namespace MWRender
|
||||||
class AlphaFader;
|
class AlphaFader;
|
||||||
class UnderwaterSwitchCallback;
|
class UnderwaterSwitchCallback;
|
||||||
|
|
||||||
struct WeatherResult
|
|
||||||
{
|
|
||||||
std::string mCloudTexture;
|
|
||||||
std::string mNextCloudTexture;
|
|
||||||
float mCloudBlendFactor;
|
|
||||||
|
|
||||||
osg::Vec4f mFogColor;
|
|
||||||
|
|
||||||
osg::Vec4f mAmbientColor;
|
|
||||||
|
|
||||||
osg::Vec4f mSkyColor;
|
|
||||||
|
|
||||||
// sun light color
|
|
||||||
osg::Vec4f mSunColor;
|
|
||||||
|
|
||||||
// alpha is the sun transparency
|
|
||||||
osg::Vec4f mSunDiscColor;
|
|
||||||
|
|
||||||
float mFogDepth;
|
|
||||||
|
|
||||||
float mDLFogFactor;
|
|
||||||
float mDLFogOffset;
|
|
||||||
|
|
||||||
float mWindSpeed;
|
|
||||||
float mBaseWindSpeed;
|
|
||||||
float mCurrentWindSpeed;
|
|
||||||
float mNextWindSpeed;
|
|
||||||
|
|
||||||
float mCloudSpeed;
|
|
||||||
|
|
||||||
float mGlareView;
|
|
||||||
|
|
||||||
bool mNight; // use night skybox
|
|
||||||
float mNightFade; // fading factor for night skybox
|
|
||||||
|
|
||||||
bool mIsStorm;
|
|
||||||
|
|
||||||
std::string mAmbientLoopSoundID;
|
|
||||||
float mAmbientSoundVolume;
|
|
||||||
|
|
||||||
std::string mParticleEffect;
|
|
||||||
std::string mRainEffect;
|
|
||||||
float mPrecipitationAlpha;
|
|
||||||
|
|
||||||
float mRainDiameter;
|
|
||||||
float mRainMinHeight;
|
|
||||||
float mRainMaxHeight;
|
|
||||||
float mRainSpeed;
|
|
||||||
float mRainEntranceSpeed;
|
|
||||||
int mRainMaxRaindrops;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MoonState
|
|
||||||
{
|
|
||||||
enum class Phase
|
|
||||||
{
|
|
||||||
Full = 0,
|
|
||||||
WaningGibbous,
|
|
||||||
ThirdQuarter,
|
|
||||||
WaningCrescent,
|
|
||||||
New,
|
|
||||||
WaxingCrescent,
|
|
||||||
FirstQuarter,
|
|
||||||
WaxingGibbous,
|
|
||||||
Unspecified
|
|
||||||
};
|
|
||||||
|
|
||||||
float mRotationFromHorizon;
|
|
||||||
float mRotationFromNorth;
|
|
||||||
Phase mPhase;
|
|
||||||
float mShadowBlend;
|
|
||||||
float mMoonAlpha;
|
|
||||||
};
|
|
||||||
|
|
||||||
///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered
|
///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered
|
||||||
/// relative to the camera (e.g. weather particle effects)
|
/// relative to the camera (e.g. weather particle effects)
|
||||||
class SkyManager
|
class SkyManager
|
||||||
|
@ -162,7 +86,7 @@ namespace MWRender
|
||||||
|
|
||||||
void setRainSpeed(float speed);
|
void setRainSpeed(float speed);
|
||||||
|
|
||||||
void setStormDirection(const osg::Vec3f& direction);
|
void setStormParticleDirection(const osg::Vec3f& direction);
|
||||||
|
|
||||||
void setSunDirection(const osg::Vec3f& direction);
|
void setSunDirection(const osg::Vec3f& direction);
|
||||||
|
|
||||||
|
@ -203,12 +127,12 @@ namespace MWRender
|
||||||
osg::ref_ptr<osg::Node> mParticleEffect;
|
osg::ref_ptr<osg::Node> mParticleEffect;
|
||||||
osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch;
|
osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch;
|
||||||
|
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mCloudNode;
|
osg::ref_ptr<osg::Group> mCloudNode;
|
||||||
|
|
||||||
osg::ref_ptr<CloudUpdater> mCloudUpdater;
|
osg::ref_ptr<CloudUpdater> mCloudUpdater;
|
||||||
osg::ref_ptr<CloudUpdater> mCloudUpdater2;
|
osg::ref_ptr<CloudUpdater> mNextCloudUpdater;
|
||||||
osg::ref_ptr<osg::Node> mCloudMesh;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mCloudMesh;
|
||||||
osg::ref_ptr<osg::Node> mCloudMesh2;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mNextCloudMesh;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> mAtmosphereDay;
|
osg::ref_ptr<osg::Node> mAtmosphereDay;
|
||||||
|
|
||||||
|
@ -239,7 +163,10 @@ namespace MWRender
|
||||||
|
|
||||||
float mRainTimer;
|
float mRainTimer;
|
||||||
|
|
||||||
|
// particle system rotation is independent of cloud rotation internally
|
||||||
|
osg::Vec3f mStormParticleDirection;
|
||||||
osg::Vec3f mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
|
osg::Vec3f mNextStormDirection;
|
||||||
|
|
||||||
// remember some settings so we don't have to apply them again if they didn't change
|
// remember some settings so we don't have to apply them again if they didn't change
|
||||||
std::string mClouds;
|
std::string mClouds;
|
||||||
|
@ -275,4 +202,4 @@ namespace MWRender
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // GAME_RENDER_SKY_H
|
#endif
|
||||||
|
|
1142
apps/openmw/mwrender/skyutil.cpp
Normal file
1142
apps/openmw/mwrender/skyutil.cpp
Normal file
File diff suppressed because it is too large
Load diff
343
apps/openmw/mwrender/skyutil.hpp
Normal file
343
apps/openmw/mwrender/skyutil.hpp
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
#ifndef OPENMW_MWRENDER_SKYUTIL_H
|
||||||
|
#define OPENMW_MWRENDER_SKYUTIL_H
|
||||||
|
|
||||||
|
#include <osg/Vec4f>
|
||||||
|
#include <osg/Matrixf>
|
||||||
|
#include <osg/Texture2D>
|
||||||
|
#include <osg/Transform>
|
||||||
|
#include <osg/Material>
|
||||||
|
|
||||||
|
#include <osgParticle/Shooter>
|
||||||
|
#include <osgParticle/ConstantRateCounter>
|
||||||
|
|
||||||
|
#include <components/sceneutil/statesetupdater.hpp>
|
||||||
|
#include <components/sceneutil/nodecallback.hpp>
|
||||||
|
|
||||||
|
namespace Resource
|
||||||
|
{
|
||||||
|
class ImageManager;
|
||||||
|
class SceneManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
struct MoonUpdater;
|
||||||
|
class SunUpdater;
|
||||||
|
class SunFlashCallback;
|
||||||
|
class SunGlareCallback;
|
||||||
|
|
||||||
|
struct WeatherResult
|
||||||
|
{
|
||||||
|
std::string mCloudTexture;
|
||||||
|
std::string mNextCloudTexture;
|
||||||
|
float mCloudBlendFactor;
|
||||||
|
|
||||||
|
osg::Vec4f mFogColor;
|
||||||
|
|
||||||
|
osg::Vec4f mAmbientColor;
|
||||||
|
|
||||||
|
osg::Vec4f mSkyColor;
|
||||||
|
|
||||||
|
// sun light color
|
||||||
|
osg::Vec4f mSunColor;
|
||||||
|
|
||||||
|
// alpha is the sun transparency
|
||||||
|
osg::Vec4f mSunDiscColor;
|
||||||
|
|
||||||
|
float mFogDepth;
|
||||||
|
|
||||||
|
float mDLFogFactor;
|
||||||
|
float mDLFogOffset;
|
||||||
|
|
||||||
|
float mWindSpeed;
|
||||||
|
float mBaseWindSpeed;
|
||||||
|
float mCurrentWindSpeed;
|
||||||
|
float mNextWindSpeed;
|
||||||
|
|
||||||
|
float mCloudSpeed;
|
||||||
|
|
||||||
|
float mGlareView;
|
||||||
|
|
||||||
|
bool mNight; // use night skybox
|
||||||
|
float mNightFade; // fading factor for night skybox
|
||||||
|
|
||||||
|
bool mIsStorm;
|
||||||
|
|
||||||
|
std::string mAmbientLoopSoundID;
|
||||||
|
float mAmbientSoundVolume;
|
||||||
|
|
||||||
|
std::string mParticleEffect;
|
||||||
|
std::string mRainEffect;
|
||||||
|
float mPrecipitationAlpha;
|
||||||
|
|
||||||
|
float mRainDiameter;
|
||||||
|
float mRainMinHeight;
|
||||||
|
float mRainMaxHeight;
|
||||||
|
float mRainSpeed;
|
||||||
|
float mRainEntranceSpeed;
|
||||||
|
int mRainMaxRaindrops;
|
||||||
|
|
||||||
|
osg::Vec3f mStormDirection;
|
||||||
|
osg::Vec3f mNextStormDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MoonState
|
||||||
|
{
|
||||||
|
enum class Phase
|
||||||
|
{
|
||||||
|
Full,
|
||||||
|
WaningGibbous,
|
||||||
|
ThirdQuarter,
|
||||||
|
WaningCrescent,
|
||||||
|
New,
|
||||||
|
WaxingCrescent,
|
||||||
|
FirstQuarter,
|
||||||
|
WaxingGibbous,
|
||||||
|
Unspecified
|
||||||
|
};
|
||||||
|
|
||||||
|
float mRotationFromHorizon;
|
||||||
|
float mRotationFromNorth;
|
||||||
|
Phase mPhase;
|
||||||
|
float mShadowBlend;
|
||||||
|
float mMoonAlpha;
|
||||||
|
};
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Material> createAlphaTrackingUnlitMaterial();
|
||||||
|
osg::ref_ptr<osg::Material> createUnlitMaterial();
|
||||||
|
|
||||||
|
class OcclusionCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OcclusionCallback(osg::ref_ptr<osg::OcclusionQueryNode> oqnVisible, osg::ref_ptr<osg::OcclusionQueryNode> oqnTotal);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float getVisibleRatio (osg::Camera* camera);
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryVisiblePixels;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryTotalPixels;
|
||||||
|
|
||||||
|
std::map<osg::observer_ptr<osg::Camera>, float> mLastRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AtmosphereUpdater : public SceneUtil::StateSetUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setEmissionColor(const osg::Vec4f& emissionColor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setDefaults(osg::StateSet* stateset) override;
|
||||||
|
void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::Vec4f mEmissionColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AtmosphereNightUpdater : public SceneUtil::StateSetUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AtmosphereNightUpdater(Resource::ImageManager* imageManager, bool forceShaders);
|
||||||
|
|
||||||
|
void setFade(float fade);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setDefaults(osg::StateSet* stateset) override;
|
||||||
|
|
||||||
|
void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::Vec4f mColor;
|
||||||
|
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||||
|
bool mForceShaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CloudUpdater : public SceneUtil::StateSetUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CloudUpdater(bool forceShaders);
|
||||||
|
|
||||||
|
void setTexture(osg::ref_ptr<osg::Texture2D> texture);
|
||||||
|
|
||||||
|
void setEmissionColor(const osg::Vec4f& emissionColor);
|
||||||
|
void setOpacity(float opacity);
|
||||||
|
void setTextureCoord(float timer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setDefaults(osg::StateSet *stateset) override;
|
||||||
|
void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||||
|
osg::Vec4f mEmissionColor;
|
||||||
|
float mOpacity;
|
||||||
|
bool mForceShaders;
|
||||||
|
osg::Matrixf mTexMat;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Transform that removes the eyepoint of the modelview matrix,
|
||||||
|
/// i.e. its children are positioned relative to the camera.
|
||||||
|
class CameraRelativeTransform : public osg::Transform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CameraRelativeTransform();
|
||||||
|
|
||||||
|
CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
|
META_Node(MWRender, CameraRelativeTransform)
|
||||||
|
|
||||||
|
const osg::Vec3f& getLastViewPoint() const;
|
||||||
|
|
||||||
|
bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const override;
|
||||||
|
|
||||||
|
osg::BoundingSphere computeBound() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// viewPoint for the current frame
|
||||||
|
mutable osg::Vec3f mViewPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Hides the node subgraph if the eye point is below water.
|
||||||
|
/// @note Must be added as cull callback.
|
||||||
|
/// @note Meant to be used on a node that is child of a CameraRelativeTransform.
|
||||||
|
/// The current view point must be retrieved by the CameraRelativeTransform since we can't get it anymore once we are in camera-relative space.
|
||||||
|
class UnderwaterSwitchCallback : public SceneUtil::NodeCallback<UnderwaterSwitchCallback>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnderwaterSwitchCallback(CameraRelativeTransform* cameraRelativeTransform);
|
||||||
|
bool isUnderwater();
|
||||||
|
|
||||||
|
void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
void setWaterLevel(float waterLevel);
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::ref_ptr<CameraRelativeTransform> mCameraRelativeTransform;
|
||||||
|
bool mEnabled;
|
||||||
|
float mWaterLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A base class for the sun and moons.
|
||||||
|
class CelestialBody
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets, unsigned int visibleMask=~0u);
|
||||||
|
|
||||||
|
virtual ~CelestialBody() = default;
|
||||||
|
|
||||||
|
virtual void adjustTransparency(const float ratio) = 0;
|
||||||
|
|
||||||
|
void setVisible(bool visible);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned int mVisibleMask;
|
||||||
|
static const float mDistance;
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform;
|
||||||
|
osg::ref_ptr<osg::Geometry> mGeom;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sun : public CelestialBody
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sun(osg::Group* parentNode, Resource::ImageManager& imageManager);
|
||||||
|
|
||||||
|
~Sun();
|
||||||
|
|
||||||
|
void setColor(const osg::Vec4f& color);
|
||||||
|
void adjustTransparency(const float ratio) override;
|
||||||
|
|
||||||
|
void setDirection(const osg::Vec3f& direction);
|
||||||
|
void setGlareTimeOfDayFade(float val);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels.
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> createOcclusionQueryNode(osg::Group* parent, bool queryVisible);
|
||||||
|
|
||||||
|
void createSunFlash(Resource::ImageManager& imageManager);
|
||||||
|
void destroySunFlash();
|
||||||
|
|
||||||
|
void createSunGlare();
|
||||||
|
void destroySunGlare();
|
||||||
|
|
||||||
|
osg::ref_ptr<SunUpdater> mUpdater;
|
||||||
|
osg::ref_ptr<osg::Node> mSunFlashNode;
|
||||||
|
osg::ref_ptr<osg::Node> mSunGlareNode;
|
||||||
|
osg::ref_ptr<SunFlashCallback> mSunFlashCallback;
|
||||||
|
osg::ref_ptr<SunGlareCallback> mSunGlareCallback;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryVisiblePixels;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryTotalPixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Moon : public CelestialBody
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_Masser = 0,
|
||||||
|
Type_Secunda
|
||||||
|
};
|
||||||
|
|
||||||
|
Moon(osg::Group* parentNode, Resource::SceneManager& sceneManager, float scaleFactor, Type type);
|
||||||
|
|
||||||
|
~Moon();
|
||||||
|
|
||||||
|
void adjustTransparency(const float ratio) override;
|
||||||
|
void setState(const MoonState state);
|
||||||
|
void setAtmosphereColor(const osg::Vec4f& color);
|
||||||
|
void setColor(const osg::Vec4f& color);
|
||||||
|
|
||||||
|
unsigned int getPhaseInt() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type mType;
|
||||||
|
MoonState::Phase mPhase;
|
||||||
|
osg::ref_ptr<MoonUpdater> mUpdater;
|
||||||
|
|
||||||
|
void setPhase(const MoonState::Phase& phase);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RainCounter : public osgParticle::ConstantRateCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int numParticlesToCreate(double dt) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RainShooter : public osgParticle::Shooter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RainShooter();
|
||||||
|
|
||||||
|
osg::Object* cloneType() const override;
|
||||||
|
|
||||||
|
osg::Object* clone(const osg::CopyOp &) const override;
|
||||||
|
|
||||||
|
void shoot(osgParticle::Particle* particle) const override;
|
||||||
|
|
||||||
|
void setVelocity(const osg::Vec3f& velocity);
|
||||||
|
void setAngle(float angle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::Vec3f mVelocity;
|
||||||
|
float mAngle;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModVertexAlphaVisitor : public osg::NodeVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum MeshType
|
||||||
|
{
|
||||||
|
Atmosphere,
|
||||||
|
Stars,
|
||||||
|
Clouds
|
||||||
|
};
|
||||||
|
|
||||||
|
ModVertexAlphaVisitor(MeshType type);
|
||||||
|
|
||||||
|
void apply(osg::Geometry& geometry) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MeshType mType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,8 +22,6 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
using namespace MWWorld;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static const int invalidWeatherID = -1;
|
static const int invalidWeatherID = -1;
|
||||||
|
@ -38,11 +36,27 @@ namespace
|
||||||
{
|
{
|
||||||
return x * (1-factor) + y * factor;
|
return x * (1-factor) + y * factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec3f calculateStormDirection(const std::string& particleEffect)
|
||||||
|
{
|
||||||
|
osg::Vec3f stormDirection = MWWorld::Weather::defaultDirection();
|
||||||
|
if (particleEffect == "meshes\\ashcloud.nif" || particleEffect == "meshes\\blightcloud.nif")
|
||||||
|
{
|
||||||
|
osg::Vec3f playerPos = MWMechanics::getPlayer().getRefData().getPosition().asVec3();
|
||||||
|
playerPos.z() = 0;
|
||||||
|
osg::Vec3f redMountainPos = osg::Vec3f(25000.f, 70000.f, 0.f);
|
||||||
|
stormDirection = (playerPos - redMountainPos);
|
||||||
|
stormDirection.normalize();
|
||||||
|
}
|
||||||
|
return stormDirection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
namespace MWWorld
|
||||||
T TimeOfDayInterpolator<T>::getValue(const float gameHour, const TimeOfDaySettings& timeSettings, const std::string& prefix) const
|
|
||||||
{
|
{
|
||||||
|
template <typename T>
|
||||||
|
T TimeOfDayInterpolator<T>::getValue(const float gameHour, const TimeOfDaySettings& timeSettings, const std::string& prefix) const
|
||||||
|
{
|
||||||
WeatherSetting setting = timeSettings.getSetting(prefix);
|
WeatherSetting setting = timeSettings.getSetting(prefix);
|
||||||
float preSunriseTime = setting.mPreSunriseTime;
|
float preSunriseTime = setting.mPreSunriseTime;
|
||||||
float postSunriseTime = setting.mPostSunriseTime;
|
float postSunriseTime = setting.mPostSunriseTime;
|
||||||
|
@ -107,14 +121,18 @@ T TimeOfDayInterpolator<T>::getValue(const float gameHour, const TimeOfDaySettin
|
||||||
}
|
}
|
||||||
// shut up compiler
|
// shut up compiler
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template class MWWorld::TimeOfDayInterpolator<float>;
|
||||||
|
template class MWWorld::TimeOfDayInterpolator<osg::Vec4f>;
|
||||||
|
|
||||||
|
osg::Vec3f Weather::defaultDirection()
|
||||||
|
{
|
||||||
|
static const osg::Vec3f direction = osg::Vec3f(0.f, 1.f, 0.f);
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
template class MWWorld::TimeOfDayInterpolator<float>;
|
Weather::Weather(const std::string& name,
|
||||||
template class MWWorld::TimeOfDayInterpolator<osg::Vec4f>;
|
|
||||||
|
|
||||||
Weather::Weather(const std::string& name,
|
|
||||||
float stormWindSpeed,
|
float stormWindSpeed,
|
||||||
float rainSpeed,
|
float rainSpeed,
|
||||||
float dlFactor,
|
float dlFactor,
|
||||||
|
@ -155,6 +173,7 @@ Weather::Weather(const std::string& name,
|
||||||
, mRainMaxHeight(Fallback::Map::getFloat("Weather_" + name + "_Rain_Height_Max"))
|
, mRainMaxHeight(Fallback::Map::getFloat("Weather_" + name + "_Rain_Height_Max"))
|
||||||
, mParticleEffect(particleEffect)
|
, mParticleEffect(particleEffect)
|
||||||
, mRainEffect(Fallback::Map::getBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "")
|
, mRainEffect(Fallback::Map::getBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "")
|
||||||
|
, mStormDirection(Weather::defaultDirection())
|
||||||
, mTransitionDelta(Fallback::Map::getFloat("Weather_" + name + "_Transition_Delta"))
|
, mTransitionDelta(Fallback::Map::getFloat("Weather_" + name + "_Transition_Delta"))
|
||||||
, mCloudsMaximumPercent(Fallback::Map::getFloat("Weather_" + name + "_Clouds_Maximum_Percent"))
|
, mCloudsMaximumPercent(Fallback::Map::getFloat("Weather_" + name + "_Clouds_Maximum_Percent"))
|
||||||
, mThunderFrequency(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Frequency"))
|
, mThunderFrequency(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Frequency"))
|
||||||
|
@ -162,7 +181,7 @@ Weather::Weather(const std::string& name,
|
||||||
, mThunderSoundID()
|
, mThunderSoundID()
|
||||||
, mFlashDecrement(Fallback::Map::getFloat("Weather_" + name + "_Flash_Decrement"))
|
, mFlashDecrement(Fallback::Map::getFloat("Weather_" + name + "_Flash_Decrement"))
|
||||||
, mFlashBrightness(0.0f)
|
, mFlashBrightness(0.0f)
|
||||||
{
|
{
|
||||||
mDL.FogFactor = dlFactor;
|
mDL.FogFactor = dlFactor;
|
||||||
mDL.FogOffset = dlOffset;
|
mDL.FogOffset = dlOffset;
|
||||||
mThunderSoundID[0] = Fallback::Map::getString("Weather_" + name + "_Thunder_Sound_ID_0");
|
mThunderSoundID[0] = Fallback::Map::getString("Weather_" + name + "_Thunder_Sound_ID_0");
|
||||||
|
@ -183,23 +202,23 @@ Weather::Weather(const std::string& name,
|
||||||
|
|
||||||
if (Misc::StringUtils::ciEqual(mAmbientLoopSoundID, "None"))
|
if (Misc::StringUtils::ciEqual(mAmbientLoopSoundID, "None"))
|
||||||
mAmbientLoopSoundID.clear();
|
mAmbientLoopSoundID.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Weather::transitionDelta() const
|
float Weather::transitionDelta() const
|
||||||
{
|
{
|
||||||
// Transition Delta describes how quickly transitioning to the weather in question will take, in Hz. Note that the
|
// Transition Delta describes how quickly transitioning to the weather in question will take, in Hz. Note that the
|
||||||
// measurement is in real time, not in-game time.
|
// measurement is in real time, not in-game time.
|
||||||
return mTransitionDelta;
|
return mTransitionDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Weather::cloudBlendFactor(const float transitionRatio) const
|
float Weather::cloudBlendFactor(const float transitionRatio) const
|
||||||
{
|
{
|
||||||
// Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next.
|
// Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next.
|
||||||
return transitionRatio / mCloudsMaximumPercent;
|
return transitionRatio / mCloudsMaximumPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Weather::calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused)
|
float Weather::calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused)
|
||||||
{
|
{
|
||||||
// When paused, the flash brightness remains the same and no new strikes can occur.
|
// When paused, the flash brightness remains the same and no new strikes can occur.
|
||||||
if(!isPaused)
|
if(!isPaused)
|
||||||
{
|
{
|
||||||
|
@ -220,28 +239,28 @@ float Weather::calculateThunder(const float transitionRatio, const float elapsed
|
||||||
}
|
}
|
||||||
|
|
||||||
return mFlashBrightness;
|
return mFlashBrightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Weather::flashDecrement(const float elapsedSeconds)
|
inline void Weather::flashDecrement(const float elapsedSeconds)
|
||||||
{
|
{
|
||||||
// The Flash Decrement is measured in whole units per second. This means that if the flash brightness was
|
// The Flash Decrement is measured in whole units per second. This means that if the flash brightness was
|
||||||
// currently 1.0, then it should take approximately 0.25 seconds to decay to 0.0 (the minimum).
|
// currently 1.0, then it should take approximately 0.25 seconds to decay to 0.0 (the minimum).
|
||||||
float decrement = mFlashDecrement * elapsedSeconds;
|
float decrement = mFlashDecrement * elapsedSeconds;
|
||||||
mFlashBrightness = decrement > mFlashBrightness ? 0.0f : mFlashBrightness - decrement;
|
mFlashBrightness = decrement > mFlashBrightness ? 0.0f : mFlashBrightness - decrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float Weather::thunderChance(const float transitionRatio, const float elapsedSeconds) const
|
inline float Weather::thunderChance(const float transitionRatio, const float elapsedSeconds) const
|
||||||
{
|
{
|
||||||
// This formula is reversed from the observation that with Thunder Frequency set to 1, there are roughly 10 strikes
|
// This formula is reversed from the observation that with Thunder Frequency set to 1, there are roughly 10 strikes
|
||||||
// per minute. It doesn't appear to be tied to in game time as Timescale doesn't affect it. Various values of
|
// per minute. It doesn't appear to be tied to in game time as Timescale doesn't affect it. Various values of
|
||||||
// Thunder Frequency seem to change the average number of strikes in a linear fashion.. During a transition, it appears to
|
// Thunder Frequency seem to change the average number of strikes in a linear fashion.. During a transition, it appears to
|
||||||
// scaled based on how far past it is past the Thunder Threshold.
|
// scaled based on how far past it is past the Thunder Threshold.
|
||||||
float scaleFactor = (transitionRatio - mThunderThreshold) / (1.0f - mThunderThreshold);
|
float scaleFactor = (transitionRatio - mThunderThreshold) / (1.0f - mThunderThreshold);
|
||||||
return ((mThunderFrequency * 10.0f) / 60.0f) * elapsedSeconds * scaleFactor;
|
return ((mThunderFrequency * 10.0f) / 60.0f) * elapsedSeconds * scaleFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Weather::lightningAndThunder(void)
|
inline void Weather::lightningAndThunder(void)
|
||||||
{
|
{
|
||||||
// Morrowind seems to vary the intensity of the brightness based on which of the four sound IDs it selects.
|
// Morrowind seems to vary the intensity of the brightness based on which of the four sound IDs it selects.
|
||||||
// They appear to go from 0 (brightest, closest) to 3 (faintest, farthest). The value of 0.25 per distance
|
// They appear to go from 0 (brightest, closest) to 3 (faintest, farthest). The value of 0.25 per distance
|
||||||
// was derived by setting the Flash Decrement to 0.1 and measuring how long each value took to decay to 0.
|
// was derived by setting the Flash Decrement to 0.1 and measuring how long each value took to decay to 0.
|
||||||
|
@ -250,12 +269,12 @@ inline void Weather::lightningAndThunder(void)
|
||||||
// Flash brightness appears additive, since if multiple strikes occur, it takes longer for it to decay to 0.
|
// Flash brightness appears additive, since if multiple strikes occur, it takes longer for it to decay to 0.
|
||||||
mFlashBrightness += 1 - (distance * 0.25f);
|
mFlashBrightness += 1 - (distance * 0.25f);
|
||||||
MWBase::Environment::get().getSoundManager()->playSound(mThunderSoundID[distance], 1.0, 1.0);
|
MWBase::Environment::get().getSoundManager()->playSound(mThunderSoundID[distance], 1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionWeather::RegionWeather(const ESM::Region& region)
|
RegionWeather::RegionWeather(const ESM::Region& region)
|
||||||
: mWeather(invalidWeatherID)
|
: mWeather(invalidWeatherID)
|
||||||
, mChances()
|
, mChances()
|
||||||
{
|
{
|
||||||
mChances.reserve(10);
|
mChances.reserve(10);
|
||||||
mChances.push_back(region.mData.mClear);
|
mChances.push_back(region.mData.mClear);
|
||||||
mChances.push_back(region.mData.mCloudy);
|
mChances.push_back(region.mData.mCloudy);
|
||||||
|
@ -267,16 +286,16 @@ RegionWeather::RegionWeather(const ESM::Region& region)
|
||||||
mChances.push_back(region.mData.mBlight);
|
mChances.push_back(region.mData.mBlight);
|
||||||
mChances.push_back(region.mData.mA);
|
mChances.push_back(region.mData.mA);
|
||||||
mChances.push_back(region.mData.mB);
|
mChances.push_back(region.mData.mB);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionWeather::RegionWeather(const ESM::RegionWeatherState& state)
|
RegionWeather::RegionWeather(const ESM::RegionWeatherState& state)
|
||||||
: mWeather(state.mWeather)
|
: mWeather(state.mWeather)
|
||||||
, mChances(state.mChances)
|
, mChances(state.mChances)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionWeather::operator ESM::RegionWeatherState() const
|
RegionWeather::operator ESM::RegionWeatherState() const
|
||||||
{
|
{
|
||||||
ESM::RegionWeatherState state =
|
ESM::RegionWeatherState state =
|
||||||
{
|
{
|
||||||
mWeather,
|
mWeather,
|
||||||
|
@ -284,10 +303,10 @@ RegionWeather::operator ESM::RegionWeatherState() const
|
||||||
};
|
};
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionWeather::setChances(const std::vector<char>& chances)
|
void RegionWeather::setChances(const std::vector<char>& chances)
|
||||||
{
|
{
|
||||||
if(mChances.size() < chances.size())
|
if(mChances.size() < chances.size())
|
||||||
{
|
{
|
||||||
mChances.reserve(chances.size());
|
mChances.reserve(chances.size());
|
||||||
|
@ -305,15 +324,15 @@ void RegionWeather::setChances(const std::vector<char>& chances)
|
||||||
{
|
{
|
||||||
chooseNewWeather();
|
chooseNewWeather();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionWeather::setWeather(int weatherID)
|
void RegionWeather::setWeather(int weatherID)
|
||||||
{
|
{
|
||||||
mWeather = weatherID;
|
mWeather = weatherID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegionWeather::getWeather()
|
int RegionWeather::getWeather()
|
||||||
{
|
{
|
||||||
// If the region weather was already set (by ChangeWeather, or by a previous call) then just return that value.
|
// If the region weather was already set (by ChangeWeather, or by a previous call) then just return that value.
|
||||||
// Note that the region weather will be expired periodically when the weather update timer expires.
|
// Note that the region weather will be expired periodically when the weather update timer expires.
|
||||||
if(mWeather == invalidWeatherID)
|
if(mWeather == invalidWeatherID)
|
||||||
|
@ -322,10 +341,10 @@ int RegionWeather::getWeather()
|
||||||
}
|
}
|
||||||
|
|
||||||
return mWeather;
|
return mWeather;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionWeather::chooseNewWeather()
|
void RegionWeather::chooseNewWeather()
|
||||||
{
|
{
|
||||||
// All probabilities must add to 100 (responsibility of the user).
|
// All probabilities must add to 100 (responsibility of the user).
|
||||||
// If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30
|
// If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30
|
||||||
// and 70% will be greater than 30 (in theory).
|
// and 70% will be greater than 30 (in theory).
|
||||||
|
@ -344,9 +363,9 @@ void RegionWeather::chooseNewWeather()
|
||||||
|
|
||||||
// if we hit this path then the chances don't add to 100, choose a default weather instead
|
// if we hit this path then the chances don't add to 100, choose a default weather instead
|
||||||
mWeather = 0;
|
mWeather = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MoonModel::MoonModel(const std::string& name)
|
MoonModel::MoonModel(const std::string& name)
|
||||||
: mFadeInStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Start"))
|
: mFadeInStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Start"))
|
||||||
, mFadeInFinish(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Finish"))
|
, mFadeInFinish(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Finish"))
|
||||||
, mFadeOutStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_Out_Start"))
|
, mFadeOutStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_Out_Start"))
|
||||||
|
@ -357,14 +376,14 @@ MoonModel::MoonModel(const std::string& name)
|
||||||
, mFadeStartAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_Start_Angle"))
|
, mFadeStartAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_Start_Angle"))
|
||||||
, mFadeEndAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_End_Angle"))
|
, mFadeEndAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_End_Angle"))
|
||||||
, mMoonShadowEarlyFadeAngle(Fallback::Map::getFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle"))
|
, mMoonShadowEarlyFadeAngle(Fallback::Map::getFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle"))
|
||||||
{
|
{
|
||||||
// Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably
|
// Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably
|
||||||
// complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering.
|
// complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering.
|
||||||
mSpeed = std::min(mSpeed, 180.0f / 23.0f);
|
mSpeed = std::min(mSpeed, 180.0f / 23.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const
|
MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const
|
||||||
{
|
{
|
||||||
float rotationFromHorizon = angle(gameTime);
|
float rotationFromHorizon = angle(gameTime);
|
||||||
MWRender::MoonState state =
|
MWRender::MoonState state =
|
||||||
{
|
{
|
||||||
|
@ -376,10 +395,10 @@ MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const
|
||||||
};
|
};
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::angle(const TimeStamp& gameTime) const
|
inline float MoonModel::angle(const TimeStamp& gameTime) const
|
||||||
{
|
{
|
||||||
// Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the
|
// Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the
|
||||||
// opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise.
|
// opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise.
|
||||||
|
|
||||||
|
@ -415,10 +434,10 @@ inline float MoonModel::angle(const TimeStamp& gameTime) const
|
||||||
}
|
}
|
||||||
|
|
||||||
return moonRiseAngleToday;
|
return moonRiseAngleToday;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::moonRiseHour(unsigned int daysPassed) const
|
inline float MoonModel::moonRiseHour(unsigned int daysPassed) const
|
||||||
{
|
{
|
||||||
// This arises from the start date of 16 Last Seed, 427
|
// This arises from the start date of 16 Last Seed, 427
|
||||||
// TODO: Find an alternate formula that doesn't rely on this day being fixed.
|
// TODO: Find an alternate formula that doesn't rely on this day being fixed.
|
||||||
static const unsigned int startDay = 16;
|
static const unsigned int startDay = 16;
|
||||||
|
@ -429,18 +448,18 @@ inline float MoonModel::moonRiseHour(unsigned int daysPassed) const
|
||||||
// know if doing so would cause the moon rise to be postponed until the next day (which happens when
|
// know if doing so would cause the moon rise to be postponed until the next day (which happens when
|
||||||
// the moon rise hour is >= 24 in Morrowind).
|
// the moon rise hour is >= 24 in Morrowind).
|
||||||
return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f);
|
return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::rotation(float hours) const
|
inline float MoonModel::rotation(float hours) const
|
||||||
{
|
{
|
||||||
// 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph.
|
// 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph.
|
||||||
// Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure
|
// Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure
|
||||||
// of whole rotations that could be completed in a day.
|
// of whole rotations that could be completed in a day.
|
||||||
return 15.0f * mSpeed * hours;
|
return 15.0f * mSpeed * hours;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWRender::MoonState::Phase MoonModel::phase(const TimeStamp& gameTime) const
|
MWRender::MoonState::Phase MoonModel::phase(const TimeStamp& gameTime) const
|
||||||
{
|
{
|
||||||
// Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle.
|
// Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle.
|
||||||
|
|
||||||
// If the moon didn't rise yet today, use yesterday's moon phase.
|
// If the moon didn't rise yet today, use yesterday's moon phase.
|
||||||
|
@ -448,10 +467,10 @@ MWRender::MoonState::Phase MoonModel::phase(const TimeStamp& gameTime) const
|
||||||
return static_cast<MWRender::MoonState::Phase>((gameTime.getDay() / 3) % 8);
|
return static_cast<MWRender::MoonState::Phase>((gameTime.getDay() / 3) % 8);
|
||||||
else
|
else
|
||||||
return static_cast<MWRender::MoonState::Phase>(((gameTime.getDay() + 1) / 3) % 8);
|
return static_cast<MWRender::MoonState::Phase>(((gameTime.getDay() + 1) / 3) % 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::shadowBlend(float angle) const
|
inline float MoonModel::shadowBlend(float angle) const
|
||||||
{
|
{
|
||||||
// The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk
|
// The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk
|
||||||
// that is roughly the color of the sky, to a textured surface.
|
// that is roughly the color of the sky, to a textured surface.
|
||||||
// Depending on the current angle, the following values describe the ratio between the textured moon
|
// Depending on the current angle, the following values describe the ratio between the textured moon
|
||||||
|
@ -471,10 +490,10 @@ inline float MoonModel::shadowBlend(float angle) const
|
||||||
return (fadeEndAngle2 - angle) / fadeAngle;
|
return (fadeEndAngle2 - angle) / fadeAngle;
|
||||||
else
|
else
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::hourlyAlpha(float gameHour) const
|
inline float MoonModel::hourlyAlpha(float gameHour) const
|
||||||
{
|
{
|
||||||
// The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon
|
// The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon
|
||||||
// appears and disappears.
|
// appears and disappears.
|
||||||
// Depending on the current hour, the following values describe how transparent the moon is.
|
// Depending on the current hour, the following values describe how transparent the moon is.
|
||||||
|
@ -490,10 +509,10 @@ inline float MoonModel::hourlyAlpha(float gameHour) const
|
||||||
return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart);
|
return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart);
|
||||||
else
|
else
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float MoonModel::earlyMoonShadowAlpha(float angle) const
|
inline float MoonModel::earlyMoonShadowAlpha(float angle) const
|
||||||
{
|
{
|
||||||
// The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle.
|
// The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle.
|
||||||
// Depending on the current angle, the following values describe how transparent the moon is.
|
// Depending on the current angle, the following values describe how transparent the moon is.
|
||||||
// 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1
|
// 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1
|
||||||
|
@ -511,9 +530,9 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const
|
||||||
return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle;
|
return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle;
|
||||||
else
|
else
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, MWWorld::ESMStore& store)
|
WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, MWWorld::ESMStore& store)
|
||||||
: mStore(store)
|
: mStore(store)
|
||||||
, mRendering(rendering)
|
, mRendering(rendering)
|
||||||
, mSunriseTime(Fallback::Map::getFloat("Weather_Sunrise_Time"))
|
, mSunriseTime(Fallback::Map::getFloat("Weather_Sunrise_Time"))
|
||||||
|
@ -536,7 +555,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, MWWorld::E
|
||||||
, mNextWindSpeed(0.f)
|
, mNextWindSpeed(0.f)
|
||||||
, mIsStorm(false)
|
, mIsStorm(false)
|
||||||
, mPrecipitation(false)
|
, mPrecipitation(false)
|
||||||
, mStormDirection(0,1,0)
|
, mStormDirection(Weather::defaultDirection())
|
||||||
, mCurrentRegion()
|
, mCurrentRegion()
|
||||||
, mTimePassed(0)
|
, mTimePassed(0)
|
||||||
, mFastForward(false)
|
, mFastForward(false)
|
||||||
|
@ -550,7 +569,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, MWWorld::E
|
||||||
, mResult()
|
, mResult()
|
||||||
, mAmbientSound(nullptr)
|
, mAmbientSound(nullptr)
|
||||||
, mPlayingSoundID()
|
, mPlayingSoundID()
|
||||||
{
|
{
|
||||||
mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration;
|
mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration;
|
||||||
mTimeSettings.mNightEnd = mSunriseTime;
|
mTimeSettings.mNightEnd = mSunriseTime;
|
||||||
mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration;
|
mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration;
|
||||||
|
@ -597,15 +616,15 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, MWWorld::E
|
||||||
}
|
}
|
||||||
|
|
||||||
forceWeather(0);
|
forceWeather(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherManager::~WeatherManager()
|
WeatherManager::~WeatherManager()
|
||||||
{
|
{
|
||||||
stopSounds();
|
stopSounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::changeWeather(const std::string& regionID, const unsigned int weatherID)
|
void WeatherManager::changeWeather(const std::string& regionID, const unsigned int weatherID)
|
||||||
{
|
{
|
||||||
// In Morrowind, this seems to have the following behavior, when applied to the current region:
|
// In Morrowind, this seems to have the following behavior, when applied to the current region:
|
||||||
// - When there is no transition in progress, start transitioning to the new weather.
|
// - When there is no transition in progress, start transitioning to the new weather.
|
||||||
// - If there is a transition in progress, queue up the transition and process it when the current one completes.
|
// - If there is a transition in progress, queue up the transition and process it when the current one completes.
|
||||||
|
@ -624,10 +643,10 @@ void WeatherManager::changeWeather(const std::string& regionID, const unsigned i
|
||||||
regionalWeatherChanged(it->first, it->second);
|
regionalWeatherChanged(it->first, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::modRegion(const std::string& regionID, const std::vector<char>& chances)
|
void WeatherManager::modRegion(const std::string& regionID, const std::vector<char>& chances)
|
||||||
{
|
{
|
||||||
// Sets the region's probability for various weather patterns. Note that this appears to be saved permanently.
|
// Sets the region's probability for various weather patterns. Note that this appears to be saved permanently.
|
||||||
// In Morrowind, this seems to have the following behavior when applied to the current region:
|
// In Morrowind, this seems to have the following behavior when applied to the current region:
|
||||||
// - If the region supports the current weather, no change in current weather occurs.
|
// - If the region supports the current weather, no change in current weather occurs.
|
||||||
|
@ -643,10 +662,10 @@ void WeatherManager::modRegion(const std::string& regionID, const std::vector<ch
|
||||||
it->second.setChances(chances);
|
it->second.setChances(chances);
|
||||||
regionalWeatherChanged(it->first, it->second);
|
regionalWeatherChanged(it->first, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::playerTeleported(const std::string& playerRegion, bool isExterior)
|
void WeatherManager::playerTeleported(const std::string& playerRegion, bool isExterior)
|
||||||
{
|
{
|
||||||
// If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to
|
// If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to
|
||||||
// be changed immediately, and any transitions for the previous region discarded.
|
// be changed immediately, and any transitions for the previous region discarded.
|
||||||
{
|
{
|
||||||
|
@ -657,10 +676,10 @@ void WeatherManager::playerTeleported(const std::string& playerRegion, bool isEx
|
||||||
forceWeather(it->second.getWeather());
|
forceWeather(it->second.getWeather());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float WeatherManager::calculateWindSpeed(int weatherId, float currentSpeed)
|
float WeatherManager::calculateWindSpeed(int weatherId, float currentSpeed)
|
||||||
{
|
{
|
||||||
float targetSpeed = std::min(8.0f * mWeatherSettings[weatherId].mWindSpeed, 70.f);
|
float targetSpeed = std::min(8.0f * mWeatherSettings[weatherId].mWindSpeed, 70.f);
|
||||||
if (currentSpeed == 0.f)
|
if (currentSpeed == 0.f)
|
||||||
currentSpeed = targetSpeed;
|
currentSpeed = targetSpeed;
|
||||||
|
@ -672,10 +691,10 @@ float WeatherManager::calculateWindSpeed(int weatherId, float currentSpeed)
|
||||||
currentSpeed = updatedSpeed;
|
currentSpeed = updatedSpeed;
|
||||||
|
|
||||||
return currentSpeed;
|
return currentSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::update(float duration, bool paused, const TimeStamp& time, bool isExterior)
|
void WeatherManager::update(float duration, bool paused, const TimeStamp& time, bool isExterior)
|
||||||
{
|
{
|
||||||
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
||||||
|
|
||||||
if(!paused || mFastForward)
|
if(!paused || mFastForward)
|
||||||
|
@ -727,20 +746,8 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time,
|
||||||
mPrecipitation = !(mResult.mParticleEffect.empty() && mResult.mRainEffect.empty())
|
mPrecipitation = !(mResult.mParticleEffect.empty() && mResult.mRainEffect.empty())
|
||||||
&& mResult.mParticleEffect != "meshes\\ashcloud.nif";
|
&& mResult.mParticleEffect != "meshes\\ashcloud.nif";
|
||||||
|
|
||||||
if (mIsStorm)
|
mStormDirection = calculateStormDirection(mResult.mParticleEffect);
|
||||||
{
|
mRendering.getSkyManager()->setStormParticleDirection(mStormDirection);
|
||||||
osg::Vec3f stormDirection(0, 1, 0);
|
|
||||||
if (mResult.mParticleEffect == "meshes\\ashcloud.nif" || mResult.mParticleEffect == "meshes\\blightcloud.nif")
|
|
||||||
{
|
|
||||||
osg::Vec3f playerPos (MWMechanics::getPlayer().getRefData().getPosition().asVec3());
|
|
||||||
playerPos.z() = 0;
|
|
||||||
osg::Vec3f redMountainPos (25000, 70000, 0);
|
|
||||||
stormDirection = (playerPos - redMountainPos);
|
|
||||||
stormDirection.normalize();
|
|
||||||
}
|
|
||||||
mStormDirection = stormDirection;
|
|
||||||
mRendering.getSkyManager()->setStormDirection(mStormDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable sun during night
|
// disable sun during night
|
||||||
if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime)
|
if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime)
|
||||||
|
@ -817,58 +824,58 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time,
|
||||||
}
|
}
|
||||||
else if (mAmbientSound)
|
else if (mAmbientSound)
|
||||||
mAmbientSound->setVolume(mResult.mAmbientSoundVolume);
|
mAmbientSound->setVolume(mResult.mAmbientSoundVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::stopSounds()
|
void WeatherManager::stopSounds()
|
||||||
{
|
{
|
||||||
if (mAmbientSound)
|
if (mAmbientSound)
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound);
|
MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound);
|
||||||
mAmbientSound = nullptr;
|
mAmbientSound = nullptr;
|
||||||
mPlayingSoundID.clear();
|
mPlayingSoundID.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
float WeatherManager::getWindSpeed() const
|
float WeatherManager::getWindSpeed() const
|
||||||
{
|
{
|
||||||
return mWindSpeed;
|
return mWindSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WeatherManager::isInStorm() const
|
bool WeatherManager::isInStorm() const
|
||||||
{
|
{
|
||||||
return mIsStorm;
|
return mIsStorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f WeatherManager::getStormDirection() const
|
osg::Vec3f WeatherManager::getStormDirection() const
|
||||||
{
|
{
|
||||||
return mStormDirection;
|
return mStormDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::advanceTime(double hours, bool incremental)
|
void WeatherManager::advanceTime(double hours, bool incremental)
|
||||||
{
|
{
|
||||||
// In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are
|
// In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are
|
||||||
// immediately applied, regardless of whatever transition time might have been remaining.
|
// immediately applied, regardless of whatever transition time might have been remaining.
|
||||||
mTimePassed += hours;
|
mTimePassed += hours;
|
||||||
mFastForward = !incremental ? true : mFastForward;
|
mFastForward = !incremental ? true : mFastForward;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int WeatherManager::getWeatherID() const
|
unsigned int WeatherManager::getWeatherID() const
|
||||||
{
|
{
|
||||||
return mCurrentWeather;
|
return mCurrentWeather;
|
||||||
}
|
}
|
||||||
|
|
||||||
NightDayMode WeatherManager::getNightDayMode() const
|
NightDayMode WeatherManager::getNightDayMode() const
|
||||||
{
|
{
|
||||||
return mNightDayMode;
|
return mNightDayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WeatherManager::useTorches(float hour) const
|
bool WeatherManager::useTorches(float hour) const
|
||||||
{
|
{
|
||||||
bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart;
|
bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart;
|
||||||
|
|
||||||
return isDark && !mPrecipitation;
|
return isDark && !mPrecipitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
||||||
{
|
{
|
||||||
ESM::WeatherState state;
|
ESM::WeatherState state;
|
||||||
state.mCurrentRegion = mCurrentRegion;
|
state.mCurrentRegion = mCurrentRegion;
|
||||||
state.mTimePassed = mTimePassed;
|
state.mTimePassed = mTimePassed;
|
||||||
|
@ -888,10 +895,10 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
||||||
writer.startRecord(ESM::REC_WTHR);
|
writer.startRecord(ESM::REC_WTHR);
|
||||||
state.save(writer);
|
state.save(writer);
|
||||||
writer.endRecord(ESM::REC_WTHR);
|
writer.endRecord(ESM::REC_WTHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
||||||
{
|
{
|
||||||
if(ESM::REC_WTHR == type)
|
if(ESM::REC_WTHR == type)
|
||||||
{
|
{
|
||||||
static const int oldestCompatibleSaveFormat = 2;
|
static const int oldestCompatibleSaveFormat = 2;
|
||||||
|
@ -932,10 +939,10 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::clear()
|
void WeatherManager::clear()
|
||||||
{
|
{
|
||||||
stopSounds();
|
stopSounds();
|
||||||
|
|
||||||
mCurrentRegion = "";
|
mCurrentRegion = "";
|
||||||
|
@ -944,30 +951,30 @@ void WeatherManager::clear()
|
||||||
forceWeather(0);
|
forceWeather(0);
|
||||||
mRegions.clear();
|
mRegions.clear();
|
||||||
importRegions();
|
importRegions();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::addWeather(const std::string& name,
|
inline void WeatherManager::addWeather(const std::string& name,
|
||||||
float dlFactor, float dlOffset,
|
float dlFactor, float dlOffset,
|
||||||
const std::string& particleEffect)
|
const std::string& particleEffect)
|
||||||
{
|
{
|
||||||
static const float fStromWindSpeed = mStore.get<ESM::GameSetting>().find("fStromWindSpeed")->mValue.getFloat();
|
static const float fStromWindSpeed = mStore.get<ESM::GameSetting>().find("fStromWindSpeed")->mValue.getFloat();
|
||||||
|
|
||||||
Weather weather(name, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect);
|
Weather weather(name, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect);
|
||||||
|
|
||||||
mWeatherSettings.push_back(weather);
|
mWeatherSettings.push_back(weather);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::importRegions()
|
inline void WeatherManager::importRegions()
|
||||||
{
|
{
|
||||||
for(const ESM::Region& region : mStore.get<ESM::Region>())
|
for(const ESM::Region& region : mStore.get<ESM::Region>())
|
||||||
{
|
{
|
||||||
std::string regionID = Misc::StringUtils::lowerCase(region.mId);
|
std::string regionID = Misc::StringUtils::lowerCase(region.mId);
|
||||||
mRegions.insert(std::make_pair(regionID, RegionWeather(region)));
|
mRegions.insert(std::make_pair(regionID, RegionWeather(region)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region)
|
inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region)
|
||||||
{
|
{
|
||||||
// If the region is current, then add a weather transition for it.
|
// If the region is current, then add a weather transition for it.
|
||||||
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
||||||
if(player.isInCell())
|
if(player.isInCell())
|
||||||
|
@ -977,10 +984,10 @@ inline void WeatherManager::regionalWeatherChanged(const std::string& regionID,
|
||||||
addWeatherTransition(region.getWeather());
|
addWeatherTransition(region.getWeather());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool WeatherManager::updateWeatherTime()
|
inline bool WeatherManager::updateWeatherTime()
|
||||||
{
|
{
|
||||||
mWeatherUpdateTime -= mTimePassed;
|
mWeatherUpdateTime -= mTimePassed;
|
||||||
mTimePassed = 0.0f;
|
mTimePassed = 0.0f;
|
||||||
if(mWeatherUpdateTime <= 0.0f)
|
if(mWeatherUpdateTime <= 0.0f)
|
||||||
|
@ -998,10 +1005,10 @@ inline bool WeatherManager::updateWeatherTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion)
|
inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion)
|
||||||
{
|
{
|
||||||
if(!playerRegion.empty() && playerRegion != mCurrentRegion)
|
if(!playerRegion.empty() && playerRegion != mCurrentRegion)
|
||||||
{
|
{
|
||||||
mCurrentRegion = playerRegion;
|
mCurrentRegion = playerRegion;
|
||||||
|
@ -1010,10 +1017,10 @@ inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeconds)
|
inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeconds)
|
||||||
{
|
{
|
||||||
// When a player chooses to train, wait, or serves jail time, any transitions will be fast forwarded to the last
|
// When a player chooses to train, wait, or serves jail time, any transitions will be fast forwarded to the last
|
||||||
// weather type set, regardless of the remaining transition time.
|
// weather type set, regardless of the remaining transition time.
|
||||||
if(!mFastForward && inTransition())
|
if(!mFastForward && inTransition())
|
||||||
|
@ -1054,23 +1061,23 @@ inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeco
|
||||||
mQueuedWeather = invalidWeatherID;
|
mQueuedWeather = invalidWeatherID;
|
||||||
mFastForward = false;
|
mFastForward = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::forceWeather(const int weatherID)
|
inline void WeatherManager::forceWeather(const int weatherID)
|
||||||
{
|
{
|
||||||
mTransitionFactor = 0.0f;
|
mTransitionFactor = 0.0f;
|
||||||
mCurrentWeather = weatherID;
|
mCurrentWeather = weatherID;
|
||||||
mNextWeather = invalidWeatherID;
|
mNextWeather = invalidWeatherID;
|
||||||
mQueuedWeather = invalidWeatherID;
|
mQueuedWeather = invalidWeatherID;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool WeatherManager::inTransition()
|
inline bool WeatherManager::inTransition()
|
||||||
{
|
{
|
||||||
return mNextWeather != invalidWeatherID;
|
return mNextWeather != invalidWeatherID;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::addWeatherTransition(const int weatherID)
|
inline void WeatherManager::addWeatherTransition(const int weatherID)
|
||||||
{
|
{
|
||||||
// In order to work like ChangeWeather expects, this method begins transitioning to the new weather immediately if
|
// In order to work like ChangeWeather expects, this method begins transitioning to the new weather immediately if
|
||||||
// no transition is in progress, otherwise it queues it to be transitioned.
|
// no transition is in progress, otherwise it queues it to be transitioned.
|
||||||
|
|
||||||
|
@ -1085,12 +1092,12 @@ inline void WeatherManager::addWeatherTransition(const int weatherID)
|
||||||
{
|
{
|
||||||
mQueuedWeather = weatherID;
|
mQueuedWeather = weatherID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::calculateWeatherResult(const float gameHour,
|
inline void WeatherManager::calculateWeatherResult(const float gameHour,
|
||||||
const float elapsedSeconds,
|
const float elapsedSeconds,
|
||||||
const bool isPaused)
|
const bool isPaused)
|
||||||
{
|
{
|
||||||
float flash = 0.0f;
|
float flash = 0.0f;
|
||||||
if(!inTransition())
|
if(!inTransition())
|
||||||
{
|
{
|
||||||
|
@ -1113,10 +1120,10 @@ inline void WeatherManager::calculateWeatherResult(const float gameHour,
|
||||||
mResult.mFogColor += flashColor;
|
mResult.mFogColor += flashColor;
|
||||||
mResult.mAmbientColor += flashColor;
|
mResult.mAmbientColor += flashColor;
|
||||||
mResult.mSunColor += flashColor;
|
mResult.mSunColor += flashColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::calculateResult(const int weatherID, const float gameHour)
|
inline void WeatherManager::calculateResult(const int weatherID, const float gameHour)
|
||||||
{
|
{
|
||||||
const Weather& current = mWeatherSettings[weatherID];
|
const Weather& current = mWeatherSettings[weatherID];
|
||||||
|
|
||||||
mResult.mCloudTexture = current.mCloudTexture;
|
mResult.mCloudTexture = current.mCloudTexture;
|
||||||
|
@ -1190,15 +1197,19 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
|
||||||
else
|
else
|
||||||
mResult.mSunDiscColor.a() = 1;
|
mResult.mSunDiscColor.a() = 1;
|
||||||
|
|
||||||
}
|
mResult.mStormDirection = calculateStormDirection(mResult.mParticleEffect);
|
||||||
|
}
|
||||||
|
|
||||||
inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour)
|
inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour)
|
||||||
{
|
{
|
||||||
calculateResult(mCurrentWeather, gameHour);
|
calculateResult(mCurrentWeather, gameHour);
|
||||||
const MWRender::WeatherResult current = mResult;
|
const MWRender::WeatherResult current = mResult;
|
||||||
calculateResult(mNextWeather, gameHour);
|
calculateResult(mNextWeather, gameHour);
|
||||||
const MWRender::WeatherResult other = mResult;
|
const MWRender::WeatherResult other = mResult;
|
||||||
|
|
||||||
|
mResult.mStormDirection = current.mStormDirection;
|
||||||
|
mResult.mNextStormDirection = other.mStormDirection;
|
||||||
|
|
||||||
mResult.mCloudTexture = current.mCloudTexture;
|
mResult.mCloudTexture = current.mCloudTexture;
|
||||||
mResult.mNextCloudTexture = other.mCloudTexture;
|
mResult.mNextCloudTexture = other.mCloudTexture;
|
||||||
mResult.mCloudBlendFactor = mWeatherSettings[mNextWeather].cloudBlendFactor(factor);
|
mResult.mCloudBlendFactor = mWeatherSettings[mNextWeather].cloudBlendFactor(factor);
|
||||||
|
@ -1225,7 +1236,7 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const
|
||||||
mResult.mNight = current.mNight;
|
mResult.mNight = current.mNight;
|
||||||
|
|
||||||
float threshold = mWeatherSettings[mNextWeather].mRainThreshold;
|
float threshold = mWeatherSettings[mNextWeather].mRainThreshold;
|
||||||
if (threshold <= 0)
|
if (threshold <= 0.f)
|
||||||
threshold = 0.5f;
|
threshold = 0.5f;
|
||||||
|
|
||||||
if(factor < threshold)
|
if(factor < threshold)
|
||||||
|
@ -1235,7 +1246,7 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const
|
||||||
mResult.mRainEffect = current.mRainEffect;
|
mResult.mRainEffect = current.mRainEffect;
|
||||||
mResult.mRainSpeed = current.mRainSpeed;
|
mResult.mRainSpeed = current.mRainSpeed;
|
||||||
mResult.mRainEntranceSpeed = current.mRainEntranceSpeed;
|
mResult.mRainEntranceSpeed = current.mRainEntranceSpeed;
|
||||||
mResult.mAmbientSoundVolume = 1 - factor / threshold;
|
mResult.mAmbientSoundVolume = 1.f - factor / threshold;
|
||||||
mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume;
|
mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume;
|
||||||
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
||||||
mResult.mRainDiameter = current.mRainDiameter;
|
mResult.mRainDiameter = current.mRainDiameter;
|
||||||
|
@ -1259,5 +1270,6 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const
|
||||||
mResult.mRainMaxHeight = other.mRainMaxHeight;
|
mResult.mRainMaxHeight = other.mRainMaxHeight;
|
||||||
mResult.mRainMaxRaindrops = other.mRainMaxRaindrops;
|
mResult.mRainMaxRaindrops = other.mRainMaxRaindrops;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,8 @@ namespace MWWorld
|
||||||
class Weather
|
class Weather
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static osg::Vec3f defaultDirection();
|
||||||
|
|
||||||
Weather(const std::string& name,
|
Weather(const std::string& name,
|
||||||
float stormWindSpeed,
|
float stormWindSpeed,
|
||||||
float rainSpeed,
|
float rainSpeed,
|
||||||
|
@ -189,6 +191,8 @@ namespace MWWorld
|
||||||
|
|
||||||
std::string mRainEffect;
|
std::string mRainEffect;
|
||||||
|
|
||||||
|
osg::Vec3f mStormDirection;
|
||||||
|
|
||||||
// Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
|
// Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
|
||||||
// is broken in the vanilla game and was disabled.
|
// is broken in the vanilla game and was disabled.
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,14 @@ namespace Shader
|
||||||
// We could fall back to a texture size uniform if EXT_gpu_shader4 is missing
|
// We could fall back to a texture size uniform if EXT_gpu_shader4 is missing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simpleLighting = false;
|
||||||
|
node.getUserValue("simpleLighting", simpleLighting);
|
||||||
|
if (simpleLighting)
|
||||||
|
{
|
||||||
|
defineMap["forcePPL"] = "1";
|
||||||
|
defineMap["endLight"] = "0";
|
||||||
|
}
|
||||||
|
|
||||||
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST))
|
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST))
|
||||||
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
||||||
// This disables the deprecated fixed-function alpha test
|
// This disables the deprecated fixed-function alpha test
|
||||||
|
|
|
@ -36,6 +36,9 @@ set(SHADER_FILES
|
||||||
gui_fragment.glsl
|
gui_fragment.glsl
|
||||||
debug_vertex.glsl
|
debug_vertex.glsl
|
||||||
debug_fragment.glsl
|
debug_fragment.glsl
|
||||||
|
sky_vertex.glsl
|
||||||
|
sky_fragment.glsl
|
||||||
|
skypasses.glsl
|
||||||
)
|
)
|
||||||
|
|
||||||
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}")
|
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}")
|
||||||
|
|
87
files/shaders/sky_fragment.glsl
Normal file
87
files/shaders/sky_fragment.glsl
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
#include "skypasses.glsl"
|
||||||
|
|
||||||
|
uniform int pass;
|
||||||
|
uniform sampler2D diffuseMap;
|
||||||
|
uniform sampler2D maskMap; // PASS_MOON
|
||||||
|
uniform float opacity; // PASS_CLOUDS, PASS_ATMOSPHERE_NIGHT
|
||||||
|
uniform vec4 moonBlend; // PASS_MOON
|
||||||
|
uniform vec4 atmosphereFade; // PASS_MOON
|
||||||
|
|
||||||
|
varying vec2 diffuseMapUV;
|
||||||
|
varying vec4 passColor;
|
||||||
|
|
||||||
|
void paintAtmosphere(inout vec4 color)
|
||||||
|
{
|
||||||
|
color = gl_FrontMaterial.emission;
|
||||||
|
color.a *= passColor.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintAtmosphereNight(inout vec4 color)
|
||||||
|
{
|
||||||
|
color = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
color.a *= passColor.a * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintClouds(inout vec4 color)
|
||||||
|
{
|
||||||
|
color = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
color.a *= passColor.a * opacity;
|
||||||
|
color.xyz = clamp(color.xyz * gl_FrontMaterial.emission.xyz, 0.0, 1.0);
|
||||||
|
|
||||||
|
// ease transition between clear color and atmosphere/clouds
|
||||||
|
color = mix(vec4(gl_Fog.color.xyz, color.a), color, passColor.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintMoon(inout vec4 color)
|
||||||
|
{
|
||||||
|
vec4 phase = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
vec4 mask = texture2D(maskMap, diffuseMapUV);
|
||||||
|
|
||||||
|
vec4 blendedLayer = phase * moonBlend;
|
||||||
|
color = vec4(blendedLayer.xyz + atmosphereFade.xyz, atmosphereFade.a * mask.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintSun(inout vec4 color)
|
||||||
|
{
|
||||||
|
color = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
color.a *= gl_FrontMaterial.diffuse.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintSunflashQuery(inout vec4 color)
|
||||||
|
{
|
||||||
|
const float threshold = 0.8;
|
||||||
|
|
||||||
|
color = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
if (color.a <= threshold)
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintSunglare(inout vec4 color)
|
||||||
|
{
|
||||||
|
color = gl_FrontMaterial.emission;
|
||||||
|
color.a = gl_FrontMaterial.diffuse.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = vec4(0.0);
|
||||||
|
|
||||||
|
if (pass == PASS_ATMOSPHERE)
|
||||||
|
paintAtmosphere(color);
|
||||||
|
else if (pass == PASS_ATMOSPHERE_NIGHT)
|
||||||
|
paintAtmosphereNight(color);
|
||||||
|
else if (pass == PASS_CLOUDS)
|
||||||
|
paintClouds(color);
|
||||||
|
else if (pass == PASS_MOON)
|
||||||
|
paintMoon(color);
|
||||||
|
else if (pass == PASS_SUN)
|
||||||
|
paintSun(color);
|
||||||
|
else if (pass == PASS_SUNFLASH_QUERY)
|
||||||
|
paintSunflashQuery(color);
|
||||||
|
else if (pass == PASS_SUNGLARE)
|
||||||
|
paintSunglare(color);
|
||||||
|
|
||||||
|
gl_FragData[0] = color;
|
||||||
|
}
|
20
files/shaders/sky_vertex.glsl
Normal file
20
files/shaders/sky_vertex.glsl
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
#include "skypasses.glsl"
|
||||||
|
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform int pass;
|
||||||
|
|
||||||
|
varying vec4 passColor;
|
||||||
|
varying vec2 diffuseMapUV;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||||
|
passColor = gl_Color;
|
||||||
|
|
||||||
|
if (pass == PASS_CLOUDS)
|
||||||
|
diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
|
||||||
|
else
|
||||||
|
diffuseMapUV = gl_MultiTexCoord0.xy;
|
||||||
|
}
|
7
files/shaders/skypasses.glsl
Normal file
7
files/shaders/skypasses.glsl
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#define PASS_ATMOSPHERE 0
|
||||||
|
#define PASS_ATMOSPHERE_NIGHT 1
|
||||||
|
#define PASS_CLOUDS 2
|
||||||
|
#define PASS_MOON 3
|
||||||
|
#define PASS_SUN 4
|
||||||
|
#define PASS_SUNFLASH_QUERY 5
|
||||||
|
#define PASS_SUNGLARE 6
|
Loading…
Reference in a new issue