diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index fbffb4976..634173589 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -284,9 +284,25 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mRootNode->setInheritOrientation(false); /// \todo preload all the textures and meshes that are used for sky rendering - - mViewport->setBackgroundColour(ColourValue(0.87, 0.87, 0.87)); + // Create overlay used for thunderstorm + MaterialPtr material = MaterialManager::getSingleton().create( "ThunderMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); + Pass* pass = material->getTechnique(0)->getPass(0); + pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); + mThunderTextureUnit = pass->createTextureUnitState(); + mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); // always black colour + mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f); + OverlayManager& ovm = OverlayManager::getSingleton(); + mThunderOverlay = ovm.create( "ThunderOverlay" ); + OverlayContainer* overlay_panel; + overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "ThunderPanel"); + overlay_panel->_setPosition(0, 0); + overlay_panel->_setDimensions(1, 1); + overlay_panel->setMaterialName( "ThunderMaterial" ); + overlay_panel->show(); + mThunderOverlay->add2D(overlay_panel); + mThunderOverlay->hide(); + mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode); mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode); mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE); @@ -294,22 +310,15 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(0.4, -0.4, 0.5), mRootNode); mMasser->setType(Moon::Type_Masser); mSecunda->setType(Moon::Type_Secunda); - //mMasser->setVisibility(0.2); - //mSecunda->setVisibility(0.2); - mMasser->setVisible(false); - mSecunda->setVisible(false); - + HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); // Stars /// \todo sky_night_02.nif (available in Bloodmoon) - /// \todo how to make a transition between day and night sky? MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1); - - ModVertexAlpha(night1_ent, 2); - + mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight->attachObject(night1_ent); @@ -326,7 +335,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mStarsMaterials[i] = mp; } - // Stars vertex shader + // Stars vertex shader HighLevelGpuProgramPtr vshader3 = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); vshader3->setParameter("profiles", "vs_2_x arbvp1"); @@ -636,3 +645,14 @@ void SkyManager::setSunDirection(const Vector3& direction) mSun->setPosition(direction); mSunGlare->setPosition(direction); } + +void SkyManager::setThunder(const float factor) +{ + if (factor > 0.f) + { + mThunderOverlay->show(); + mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, factor*0.6); + } + else + mThunderOverlay->hide(); +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4a7877d56..ef26ce862 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -19,11 +19,13 @@ namespace Ogre class SceneManager; class Entity; class BillboardSet; + class TextureUnitState; + class Overlay; } namespace MWRender { - class BillboardObject + class BillboardObject { public: BillboardObject( const Ogre::String& textureName, @@ -136,6 +138,8 @@ namespace MWRender void setSunDirection(const Ogre::Vector3& direction); + void setThunder(const float factor); + void setGlare(bool glare); Ogre::Vector3 getRealSunPos(); @@ -168,6 +172,9 @@ namespace MWRender float mStarsOpacity; Ogre::ColourValue mCloudColour; Ogre::ColourValue mSkyColour; + + Ogre::Overlay* mThunderOverlay; + Ogre::TextureUnitState* mThunderTextureUnit; float mRemainingTransitionTime; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 412967126..395fedc2c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -2,19 +2,30 @@ #include "world.hpp" #include "../mwrender/renderingmanager.hpp" +#include "../mwsound/soundmanager.hpp" + +#include +#include using namespace Ogre; using namespace MWWorld; +using namespace MWSound; #define TRANSITION_TIME 10 #define lerp(x, y) (x * (1-factor) + y * factor) -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, World* world) : - mHour(14), mCurrentWeather("clear") +const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; +const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; +const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; +const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; + +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : + mHour(14), mCurrentWeather("clear"), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), + mThunderSoundDelay(0) { mRendering = rendering; - mWorld = world; + mEnvironment = env; #define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f) @@ -22,7 +33,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, World* wor Weather clear; clear.mCloudTexture = "tx_sky_clear.dds"; clear.mCloudsMaximumPercent = 1.0; - clear.mTransitionDelta = 0.15; + clear.mTransitionDelta = 0.015; clear.mSkySunriseColor = clr(118, 141, 164); clear.mSkyDayColor = clr(95, 135, 203); clear.mSkySunsetColor = clr(56, 89, 129); @@ -39,19 +50,18 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, World* wor clear.mSunDayColor = clr(255, 252, 238); clear.mSunSunsetColor = clr(255, 115, 79); clear.mSunNightColor = clr(59, 97, 176); - clear.mSunDiscSunsetColour = clr(255, 189, 157); + clear.mSunDiscSunsetColor = clr(255, 189, 157); clear.mLandFogDayDepth = 0.69; clear.mLandFogNightDepth = 0.69; clear.mWindSpeed = 0.1; clear.mCloudSpeed = 1.25; clear.mGlareView = 1.0; - mWeatherSettings["clear"] = clear; Weather cloudy; cloudy.mCloudTexture = "tx_sky_cloudy.dds"; cloudy.mCloudsMaximumPercent = 1.0; - cloudy.mTransitionDelta = 0.15; + cloudy.mTransitionDelta = 0.015; cloudy.mSkySunriseColor = clr(126, 158, 173); cloudy.mSkyDayColor = clr(117, 160, 215); cloudy.mSkySunsetColor = clr(111, 114, 159); @@ -68,15 +78,42 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, World* wor cloudy.mSunDayColor = clr(255, 236, 221); cloudy.mSunSunsetColor = clr(255, 89, 00); cloudy.mSunNightColor = clr(77, 91, 124); - cloudy.mSunDiscSunsetColour = clr(255, 202, 179); + cloudy.mSunDiscSunsetColor = clr(255, 202, 179); cloudy.mLandFogDayDepth = 0.72; cloudy.mLandFogNightDepth = 0.72; cloudy.mWindSpeed = 0.2; cloudy.mCloudSpeed = 2; cloudy.mGlareView = 1.0; - mWeatherSettings["cloudy"] = cloudy; + Weather thunderstorm; + thunderstorm.mCloudTexture = "tx_sky_thunder.dds"; + thunderstorm.mCloudsMaximumPercent = 0.66; + thunderstorm.mTransitionDelta = 0.03; + thunderstorm.mSkySunriseColor = clr(35, 36, 39); + thunderstorm.mSkyDayColor = clr(97, 104, 115); + thunderstorm.mSkySunsetColor = clr(35, 36, 39); + thunderstorm.mSkyNightColor = clr(19, 20, 22); + thunderstorm.mFogSunriseColor = clr(70, 74, 85); + thunderstorm.mFogDayColor = clr(97, 104, 115); + thunderstorm.mFogSunsetColor = clr(70, 74, 85); + thunderstorm.mFogNightColor = clr(19, 20, 22); + thunderstorm.mAmbientSunriseColor = clr(54, 54, 54); + thunderstorm.mAmbientDayColor = clr(90, 90, 90); + thunderstorm.mAmbientSunsetColor = clr(54, 54, 54); + thunderstorm.mAmbientNightColor = clr(49, 51, 54); + thunderstorm.mSunSunriseColor = clr(91, 99, 122); + thunderstorm.mSunDayColor = clr(138, 144, 155); + thunderstorm.mSunSunsetColor = clr(96, 101, 117); + thunderstorm.mSunNightColor = clr(55, 76, 110); + thunderstorm.mSunDiscSunsetColor = clr(128, 128, 128); + thunderstorm.mLandFogDayDepth = 1; + thunderstorm.mLandFogNightDepth = 1.15; + thunderstorm.mWindSpeed = 0.5; + thunderstorm.mCloudSpeed = 3; + thunderstorm.mGlareView = 0; + mWeatherSettings["thunderstorm"] = thunderstorm; + /* Weather overcast; overcast.mCloudTexture = "tx_sky_overcast.dds"; @@ -84,7 +121,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, World* wor mWeatherSettings["overcast"] = overcast; */ - setWeather("clear", true); + setWeather("thunderstorm", true); } void WeatherManager::setWeather(const String& weather, bool instant) @@ -245,26 +282,90 @@ WeatherResult WeatherManager::transition(float factor) void WeatherManager::update(float duration) { - WeatherResult result; - - if (mNextWeather != "") + if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()) { - mRemainingTransitionTime -= duration; - if (mRemainingTransitionTime < 0) + WeatherResult result; + + if (mNextWeather != "") { - mCurrentWeather = mNextWeather; - mNextWeather = ""; + mRemainingTransitionTime -= duration; + if (mRemainingTransitionTime < 0) + { + mCurrentWeather = mNextWeather; + mNextWeather = ""; + } } - } - - if (mNextWeather != "") - result = transition(1-(mRemainingTransitionTime/TRANSITION_TIME)); - else - result = getResult(mCurrentWeather); - - - if (mWorld->isCellExterior() || mWorld->isCellQuasiExterior()) - { + + if (mNextWeather != "") + result = transition(1-(mRemainingTransitionTime/TRANSITION_TIME)); + else + result = getResult(mCurrentWeather); + + // disable sun during night + if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration + || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) + mRendering->getSkyManager()->sunDisable(); + else + { + // during day, calculate sun angle + float height = 1-std::abs(((mHour-13)/7.f)); + int facing = mHour > 13.f ? 1 : -1; + Vector3 final( + (1-height)*facing, + (1-height)*facing, + height); + mRendering->setSunDirection(final); + + mRendering->getSkyManager()->sunEnable(); + } + + if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + { + if (mThunderFlash > 0) + { + // play the sound after a delay + mThunderSoundDelay -= duration; + if (mThunderSoundDelay <= 0) + { + // pick a random sound + int sound = rand() % 4; + std::string soundname; + if (sound == 0) soundname = WeatherGlobals::mThunderSoundID0; + else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1; + else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2; + else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3; + #include + std::cout << "play sound" << std::endl; + mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); + mThunderSoundDelay = 1000; + } + + mThunderFlash -= duration; + if (mThunderFlash > 0) + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + else + { + srand(time(NULL)); + mThunderChanceNeeded = rand() % 100; + mThunderChance = 0; + mRendering->getSkyManager()->setThunder( 0.f ); + } + } + else + { + // no thunder active + mThunderChance += duration*4; // chance increases by 4 percent every second + if (mThunderChance >= mThunderChanceNeeded) + { + mThunderFlash = WeatherGlobals::mThunderThreshold; + + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + + mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; + } + } + } + mRendering->setAmbientColour(result.mAmbientColor); mRendering->sunEnable(); mRendering->setSunColour(result.mSunColor); @@ -276,24 +377,7 @@ void WeatherManager::update(float duration) { mRendering->sunDisable(); mRendering->skyDisable(); - } - - // disable sun during night - if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration - || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) - mRendering->getSkyManager()->sunDisable(); - else - { - // during day, calculate sun angle - float height = 1-std::abs(((mHour-13)/7.f)); - int facing = mHour > 13.f ? 1 : -1; - Vector3 final( - (1-height)*facing, - (1-height)*facing, - height); - mRendering->setSunDirection(final); - - mRendering->getSkyManager()->sunEnable(); + mRendering->getSkyManager()->setThunder(0.f); } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 61d908054..57a80ed13 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -11,7 +11,7 @@ namespace MWRender namespace MWWorld { - class World; + class Environment; /// Global weather manager properties (according to INI) struct WeatherGlobals @@ -72,8 +72,18 @@ namespace MWWorld static const float mSunsetTime = 18; static const float mSunriseDuration = 2; static const float mSunsetDuration = 2; + + // morrowind sets these per-weather, but since they are only used by 'thunderstorm' + // weather setting anyway, we can just as well set them globally + static const float mThunderFrequency = .4; + static const float mThunderThreshold = 0.6; + static const float mThunderSoundDelay = 0.25; + static const std::string mThunderSoundID0; + static const std::string mThunderSoundID1; + static const std::string mThunderSoundID2; + static const std::string mThunderSoundID3; }; - + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition struct WeatherResult { @@ -142,7 +152,7 @@ namespace MWWorld mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) - Ogre::ColourValue mSunDiscSunsetColour; + Ogre::ColourValue mSunDiscSunsetColor; // Duration of weather transition // the INI value is 0.015, so I suppose this is measured in Morrowind-days? (0.015 days = 36 minutes in Morrowind) @@ -164,7 +174,8 @@ namespace MWWorld // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) Ogre::String mAmbientLoopSoundID; - /// \todo rain, thunder, ashstorm... + // Rain sound effect + Ogre::String mRainLoopSoundID; /// \todo disease chance }; @@ -175,7 +186,7 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*, MWWorld::World*); + WeatherManager(MWRender::RenderingManager*, MWWorld::Environment*); /** * Change the weather setting @@ -201,7 +212,7 @@ namespace MWWorld int mDay, mMonth; MWRender::RenderingManager* mRendering; - MWWorld::World* mWorld; + MWWorld::Environment* mEnvironment; std::map mWeatherSettings; @@ -210,6 +221,11 @@ namespace MWWorld float mRemainingTransitionTime; + float mThunderFlash; + float mThunderChance; + float mThunderChanceNeeded; + float mThunderSoundDelay; + WeatherResult transition(const float factor); WeatherResult getResult(const Ogre::String& weather); }; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 6f5e648d4..bb6498e2a 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -160,7 +160,7 @@ namespace MWWorld mRendering = new MWRender::RenderingManager(renderer, resDir, mPhysEngine, environment); - mWeatherManager = new MWWorld::WeatherManager(mRendering, this); + mWeatherManager = new MWWorld::WeatherManager(mRendering, &environment); boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master));