mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
Implement rain (Feature #41)
This commit is contained in:
parent
4a6dbe6f89
commit
f6a568c995
4 changed files with 139 additions and 4 deletions
|
@ -236,6 +236,10 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera)
|
|||
, mCloudAnimationTimer(0.f)
|
||||
, mMoonRed(false)
|
||||
, mParticleNode(NULL)
|
||||
, mRainEnabled(false)
|
||||
, mRainTimer(0)
|
||||
, mRainSpeed(0)
|
||||
, mRainFrequency(1)
|
||||
{
|
||||
mSceneMgr = root->getCreator();
|
||||
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
|
@ -351,6 +355,7 @@ void SkyManager::create()
|
|||
|
||||
SkyManager::~SkyManager()
|
||||
{
|
||||
clearRain();
|
||||
delete mSun;
|
||||
delete mSunGlare;
|
||||
delete mMasser;
|
||||
|
@ -369,6 +374,66 @@ int SkyManager::getSecundaPhase() const
|
|||
return mSecunda->getPhaseInt();
|
||||
}
|
||||
|
||||
void SkyManager::clearRain()
|
||||
{
|
||||
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::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++);
|
||||
}
|
||||
}
|
||||
|
||||
void SkyManager::updateRain(float dt)
|
||||
{
|
||||
// Move existing rain
|
||||
// Note: if rain gets disabled, we let the existing rain drops finish falling down.
|
||||
float minHeight = 200;
|
||||
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::iterator it = mRainModels.begin(); it != mRainModels.end();)
|
||||
{
|
||||
Ogre::Vector3 pos = it->first->getPosition();
|
||||
pos.z -= mRainSpeed * dt;
|
||||
it->first->setPosition(pos);
|
||||
if (pos.z < -minHeight)
|
||||
{
|
||||
it->second.setNull();
|
||||
Ogre::SceneNode* parent = it->first->getParentSceneNode();
|
||||
mSceneMgr->destroySceneNode(it->first);
|
||||
mSceneMgr->destroySceneNode(parent);
|
||||
mRainModels.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
// Spawn new rain
|
||||
float rainFrequency = mRainFrequency;
|
||||
float startHeight = 700;
|
||||
if (mRainEnabled)
|
||||
{
|
||||
mRainTimer += dt;
|
||||
if (mRainTimer >= 1.f/rainFrequency)
|
||||
{
|
||||
mRainTimer = 0;
|
||||
|
||||
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
|
||||
Ogre::SceneNode* offsetNode = sceneNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight));
|
||||
|
||||
NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect);
|
||||
mRainModels[offsetNode] = objects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkyManager::update(float duration)
|
||||
{
|
||||
if (!mEnabled) return;
|
||||
|
@ -380,6 +445,8 @@ void SkyManager::update(float duration)
|
|||
mParticle->mControllers[i].update();
|
||||
}
|
||||
|
||||
updateRain(duration);
|
||||
|
||||
// UV Scroll the clouds
|
||||
mCloudAnimationTimer += duration * mCloudSpeed;
|
||||
sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
|
||||
|
@ -430,13 +497,22 @@ void SkyManager::enable()
|
|||
if (!mCreated)
|
||||
create();
|
||||
|
||||
if (mParticleNode)
|
||||
mParticleNode->setVisible(true);
|
||||
|
||||
mRootNode->setVisible(true);
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::disable()
|
||||
{
|
||||
if (mParticleNode)
|
||||
mParticleNode->setVisible(false);
|
||||
|
||||
clearRain();
|
||||
|
||||
mRootNode->setVisible(false);
|
||||
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
|
@ -449,6 +525,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
|||
{
|
||||
if (!mCreated) return;
|
||||
|
||||
mRainEffect = weather.mRainEffect;
|
||||
mRainEnabled = !mRainEffect.empty();
|
||||
mRainFrequency = weather.mRainFrequency;
|
||||
mRainSpeed = weather.mRainSpeed;
|
||||
|
||||
if (mCurrentParticleEffect != weather.mParticleEffect)
|
||||
{
|
||||
mCurrentParticleEffect = weather.mParticleEffect;
|
||||
|
@ -461,7 +542,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
|||
{
|
||||
if (!mParticleNode)
|
||||
{
|
||||
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(Ogre::Vector3(0,0,100));
|
||||
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode();
|
||||
mParticleNode->setInheritOrientation(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,8 @@ namespace MWRender
|
|||
|
||||
void sunDisable();
|
||||
|
||||
void setRainSpeed(float speed);
|
||||
|
||||
void setSunDirection(const Ogre::Vector3& direction);
|
||||
|
||||
void setMasserDirection(const Ogre::Vector3& direction);
|
||||
|
@ -176,6 +178,9 @@ namespace MWRender
|
|||
void create();
|
||||
///< no need to call this, automatically done on first enable()
|
||||
|
||||
void updateRain(float dt);
|
||||
void clearRain();
|
||||
|
||||
bool mCreated;
|
||||
|
||||
bool mMoonRed;
|
||||
|
@ -203,6 +208,9 @@ namespace MWRender
|
|||
Ogre::SceneNode* mParticleNode;
|
||||
NifOgre::ObjectScenePtr mParticle;
|
||||
|
||||
std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr> mRainModels;
|
||||
float mRainTimer;
|
||||
|
||||
// remember some settings so we don't have to apply them again if they didnt change
|
||||
Ogre::String mClouds;
|
||||
Ogre::String mNextClouds;
|
||||
|
@ -223,6 +231,11 @@ namespace MWRender
|
|||
float mGlare; // target
|
||||
float mGlareFade; // actual
|
||||
|
||||
bool mRainEnabled;
|
||||
std::string mRainEffect;
|
||||
float mRainSpeed;
|
||||
float mRainFrequency;
|
||||
|
||||
bool mEnabled;
|
||||
bool mSunEnabled;
|
||||
bool mMasserEnabled;
|
||||
|
|
|
@ -59,6 +59,21 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name
|
|||
weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed");
|
||||
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
|
||||
weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture");
|
||||
|
||||
bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip");
|
||||
if (usesPrecip)
|
||||
weather.mRainEffect = "meshes\\raindrop.nif";
|
||||
weather.mRainSpeed = mRainSpeed;
|
||||
weather.mRainFrequency = mFallback->getFallbackFloat("Weather_"+upper+"_Rain_Entrance_Speed");
|
||||
/*
|
||||
Unhandled:
|
||||
Rain Diameter=600 ?
|
||||
Rain Height Min=200 ?
|
||||
Rain Height Max=700 ?
|
||||
Rain Threshold=0.6 ?
|
||||
Max Raindrops=650 ?
|
||||
*/
|
||||
|
||||
size_t offset = weather.mCloudTexture.find(".tga");
|
||||
if (offset != std::string::npos)
|
||||
weather.mCloudTexture.replace(offset, weather.mCloudTexture.length() - offset, ".dds");
|
||||
|
@ -100,7 +115,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
|
|||
mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true),
|
||||
mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0),
|
||||
mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0),
|
||||
mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering)
|
||||
mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering), mIsStorm(false)
|
||||
{
|
||||
//Globals
|
||||
mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0");
|
||||
|
@ -117,6 +132,8 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
|
|||
mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold");
|
||||
mThunderSoundDelay = 0.25;
|
||||
|
||||
mRainSpeed = mFallback->getFallbackFloat("Weather_Precip_Gravity");
|
||||
|
||||
//Some useful values
|
||||
/* TODO: Use pre-sunrise_time, pre-sunset_time,
|
||||
* post-sunrise_time, and post-sunset_time to better
|
||||
|
@ -140,10 +157,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
|
|||
|
||||
Weather thunderstorm;
|
||||
thunderstorm.mRainLoopSoundID = "rain heavy";
|
||||
thunderstorm.mRainEffect = "meshes\\raindrop.nif";
|
||||
setFallbackWeather(thunderstorm,"thunderstorm");
|
||||
|
||||
Weather rain;
|
||||
rain.mRainLoopSoundID = "rain";
|
||||
rain.mRainEffect = "meshes\\raindrop.nif";
|
||||
setFallbackWeather(rain,"rain");
|
||||
|
||||
Weather overcast;
|
||||
|
@ -217,7 +236,11 @@ void WeatherManager::setResult(const String& weatherType)
|
|||
|
||||
mResult.mIsStorm = current.mIsStorm;
|
||||
|
||||
mResult.mRainSpeed = current.mRainSpeed;
|
||||
mResult.mRainFrequency = current.mRainFrequency;
|
||||
|
||||
mResult.mParticleEffect = current.mParticleEffect;
|
||||
mResult.mRainEffect = current.mRainEffect;
|
||||
|
||||
mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1);
|
||||
|
||||
|
@ -324,6 +347,9 @@ void WeatherManager::transition(float factor)
|
|||
|
||||
mResult.mIsStorm = current.mIsStorm;
|
||||
mResult.mParticleEffect = current.mParticleEffect;
|
||||
mResult.mRainEffect = current.mRainEffect;
|
||||
mResult.mRainSpeed = current.mRainSpeed;
|
||||
mResult.mRainFrequency = current.mRainFrequency;
|
||||
}
|
||||
|
||||
void WeatherManager::update(float duration)
|
||||
|
@ -361,6 +387,7 @@ void WeatherManager::update(float duration)
|
|||
setResult(mCurrentWeather);
|
||||
|
||||
mWindSpeed = mResult.mWindSpeed;
|
||||
mIsStorm = mResult.mIsStorm;
|
||||
|
||||
mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor);
|
||||
|
||||
|
@ -499,7 +526,6 @@ void WeatherManager::update(float duration)
|
|||
|
||||
mRendering->getSkyManager()->setWeather(mResult);
|
||||
|
||||
|
||||
// Play sounds
|
||||
if (mNextWeather == "")
|
||||
{
|
||||
|
@ -779,7 +805,7 @@ void WeatherManager::switchToNextWeather(bool instantly)
|
|||
|
||||
bool WeatherManager::isInStorm() const
|
||||
{
|
||||
return mResult.mIsStorm;
|
||||
return mIsStorm;
|
||||
}
|
||||
|
||||
Ogre::Vector3 WeatherManager::getStormDirection() const
|
||||
|
|
|
@ -62,6 +62,10 @@ namespace MWWorld
|
|||
std::string mAmbientLoopSoundID;
|
||||
|
||||
std::string mParticleEffect;
|
||||
|
||||
std::string mRainEffect;
|
||||
float mRainSpeed;
|
||||
float mRainFrequency;
|
||||
};
|
||||
|
||||
|
||||
|
@ -129,8 +133,17 @@ namespace MWWorld
|
|||
// Possible effect on movement speed?
|
||||
bool mIsStorm;
|
||||
|
||||
// How fast does rain travel down?
|
||||
// In Morrowind.ini this is set globally, but we may want to change it per weather later.
|
||||
float mRainSpeed;
|
||||
|
||||
// How often does a new rain mesh spawn?
|
||||
float mRainFrequency;
|
||||
|
||||
std::string mParticleEffect;
|
||||
|
||||
std::string mRainEffect;
|
||||
|
||||
// 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.
|
||||
};
|
||||
|
@ -188,6 +201,7 @@ namespace MWWorld
|
|||
private:
|
||||
float mHour;
|
||||
float mWindSpeed;
|
||||
bool mIsStorm;
|
||||
MWWorld::Fallback* mFallback;
|
||||
void setFallbackWeather(Weather& weather,const std::string& name);
|
||||
MWRender::RenderingManager* mRendering;
|
||||
|
@ -226,6 +240,7 @@ namespace MWWorld
|
|||
typedef std::map<std::string,std::vector<char> > RegionModMap;
|
||||
RegionModMap mRegionMods;
|
||||
|
||||
float mRainSpeed;
|
||||
float mSunriseTime;
|
||||
float mSunsetTime;
|
||||
float mSunriseDuration;
|
||||
|
|
Loading…
Reference in a new issue