#include "sky.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/fallback.hpp" #include "renderconst.hpp" #include "renderingmanager.hpp" using namespace MWRender; using namespace Ogre; BillboardObject::BillboardObject( const String& textureName, const float initialSize, const Vector3& position, SceneNode* rootNode, const std::string& material) { SceneManager* sceneMgr = rootNode->getCreator(); Vector3 finalPosition = position.normalisedCopy() * 1000.f; static unsigned int bodyCount=0; mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("billboard", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); mEntity = sceneMgr->createEntity("billboard"); mEntity->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); mEntity->setVisibilityFlags(RV_Sky); mEntity->setCastShadows(false); mNode = rootNode->createChildSceneNode(); mNode->setPosition(finalPosition); mNode->attachObject(mEntity); mNode->setScale(Ogre::Vector3(450.f*initialSize)); mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-position.normalisedCopy())); sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); bodyCount++; } BillboardObject::BillboardObject() { } void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) { } void BillboardObject::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) { setVisibility(mVisibility); setColour(mColour); } void BillboardObject::setVisible(const bool visible) { mEntity->setVisible(visible); } void BillboardObject::setSize(const float size) { mNode->setScale(450.f*size, 450.f*size, 450.f*size); } void BillboardObject::setVisibility(const float visibility) { mVisibility = visibility; Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); for (int i=0; igetNumTechniques(); ++i) { Ogre::Technique* t = m->getTechnique(i); if (t->getNumPasses ()) t->getPass(0)->setDiffuse (0,0,0, visibility); } } void BillboardObject::setPosition(const Vector3& pPosition) { Vector3 normalised = pPosition.normalisedCopy(); Vector3 finalPosition = normalised * 1000.f; mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-normalised)); mNode->setPosition(finalPosition); } Vector3 BillboardObject::getPosition() const { return mNode->getPosition(); } void BillboardObject::setVisibilityFlags(int flags) { mEntity->setVisibilityFlags(flags); } void BillboardObject::setColour(const ColourValue& pColour) { mColour = pColour; Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); for (int i=0; igetNumTechniques(); ++i) { Ogre::Technique* t = m->getTechnique(i); if (t->getNumPasses ()) t->getPass(0)->setSelfIllumination (pColour); } } void BillboardObject::setRenderQueue(unsigned int id) { mEntity->setRenderQueueGroup(id); } SceneNode* BillboardObject::getNode() { return mNode; } Moon::Moon( const String& textureName, const float initialSize, const Vector3& position, SceneNode* rootNode, const std::string& material) : BillboardObject(textureName, initialSize, position, rootNode, material) { setVisibility(1.0); mPhase = Moon::Phase_Full; } void Moon::setType(const Moon::Type& type) { mType = type; } void Moon::setPhase(const Moon::Phase& phase) { // Colour texture Ogre::String textureName = "textures\\tx_"; if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; if (phase == Moon::Phase_New) textureName += "new"; else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; else if (phase == Moon::Phase_Full) textureName += "full"; textureName += ".dds"; if (mType == Moon::Type_Secunda) sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); else sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); mPhase = phase; } Moon::Phase Moon::getPhase() const { return mPhase; } unsigned int Moon::getPhaseInt() const { if (mPhase == Moon::Phase_New) return 0; else if (mPhase == Moon::Phase_WaxingCrescent) return 1; else if (mPhase == Moon::Phase_WaningCrescent) return 1; else if (mPhase == Moon::Phase_WaxingHalf) return 2; else if (mPhase == Moon::Phase_WaningHalf) return 2; else if (mPhase == Moon::Phase_WaxingGibbous) return 3; else if (mPhase == Moon::Phase_WaningGibbous) return 3; else if (mPhase == Moon::Phase_Full) return 4; return 0; } SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) : mHour(0.0f) , mDay(0) , mMonth(0) , mSun(NULL) , mSunGlare(NULL) , mMasser(NULL) , mSecunda(NULL) , mCamera(pCamera) , mRootNode(NULL) , mSceneMgr(NULL) , mAtmosphereDay(NULL) , mAtmosphereNight(NULL) , mCloudNode(NULL) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) , mGlareFade(0.0f) , mGlare(0.0f) , mEnabled(true) , mSunEnabled(true) , mMasserEnabled(true) , mSecundaEnabled(true) , mCreated(false) , mCloudAnimationTimer(0.f) , mMoonRed(false) , mParticleNode(NULL) , mRainEnabled(false) , mRainTimer(0) , mRainSpeed(0) , mRainFrequency(1) , mStormDirection(0,-1,0) , mIsStorm(false) { mSceneMgr = root->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); } void SkyManager::create() { assert(!mCreated); sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance().setSharedParameter ("cloudOpacity", sh::makeProperty(new sh::FloatValue(1))); sh::Factory::getInstance().setSharedParameter ("cloudColour", sh::makeProperty(new sh::Vector3(1,1,1))); sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance().setSharedParameter ("nightFade", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); // Create light used for thunderstorm mLightning = mSceneMgr->createLight(); mLightning->setType (Ogre::Light::LT_DIRECTIONAL); mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); mSun->setRenderQueue(RQG_SkiesEarly+4); mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); Ogre::AxisAlignedBox aabInf = Ogre::AxisAlignedBox::BOX_INFINITE; // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); NifOgre::ObjectScenePtr objects; if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("meshes\\sky_night_02.nif")) objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_02.nif"); else objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) { Entity* night1_ent = objects->mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); night1_ent->getMesh()->_setBounds (aabInf); for (unsigned int j=0; jgetNumSubEntities(); ++j) { std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); std::string textureName = sh::retrieveValue( sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); night1_ent->getSubEntity(j)->setMaterialName(matName); } } mObjects.push_back(objects); // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < objects->mEntities.size();i++) { Entity* atmosphere_ent = objects->mEntities[i]; atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions atmosphere_ent->getMesh()->_setBounds (aabInf); } mObjects.push_back(objects); // Clouds mCloudNode = mRootNode->createChildSceneNode(); objects = NifOgre::Loader::createObjects(mCloudNode, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < objects->mEntities.size();i++) { Entity* clouds_ent = objects->mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); clouds_ent->setCastShadows(false); // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions clouds_ent->getMesh()->_setBounds (aabInf); } mObjects.push_back(objects); mCreated = true; } SkyManager::~SkyManager() { clearRain(); delete mSun; delete mSunGlare; delete mMasser; delete mSecunda; } int SkyManager::getMasserPhase() const { if (!mCreated) return 0; return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { if (!mCreated) return 0; return mSecunda->getPhaseInt(); } void SkyManager::clearRain() { for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) { it->second.setNull(); Ogre::SceneNode* parent = it->first->getParentSceneNode(); mSceneMgr->destroySceneNode(it->first); mSceneMgr->destroySceneNode(parent); mRainModels.erase(it++); } } 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::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); for (unsigned int i=0; imEntities.size(); ++i) { objects->mEntities[i]->setRenderQueueGroup(RQG_Alpha); objects->mEntities[i]->setVisibilityFlags(RV_Sky); } for (unsigned int i=0; imParticles.size(); ++i) { objects->mParticles[i]->setRenderQueueGroup(RQG_Alpha); objects->mParticles[i]->setVisibilityFlags(RV_Sky); } mRainModels[offsetNode] = objects; } } } void SkyManager::update(float duration) { if (!mEnabled) return; const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); if (!mParticle.isNull()) { for (unsigned int i=0; imControllers.size(); ++i) mParticle->mControllers[i].update(); if (mIsStorm) mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); } if (mIsStorm) mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); else mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); updateRain(duration); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed; sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full if (mGlareFade > mGlare) { mGlareFade -= duration*10; if (mGlareFade < mGlare) mGlareFade = mGlare; } else if (mGlareFade < mGlare) { mGlareFade += duration*10; if (mGlareFade > mGlare) mGlareFade = mGlare; } // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*6; mSunGlare->setSize(val * mGlareFade); } mSunGlare->setVisible(mSunEnabled); mSun->setVisible(mSunEnabled); mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } 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; } void SkyManager::setMoonColour (bool red) { mMoonRed = red; } void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { if (!mCreated) return; mRainEffect = weather.mRainEffect; mRainEnabled = !mRainEffect.empty(); mRainFrequency = weather.mRainFrequency; mRainSpeed = weather.mRainSpeed; mIsStorm = weather.mIsStorm; if (mCurrentParticleEffect != weather.mParticleEffect) { mCurrentParticleEffect = weather.mParticleEffect; if (mCurrentParticleEffect.empty()) { mParticle.setNull(); } else { if (!mParticleNode) { mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(); mParticleNode->setInheritOrientation(false); } mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); for(size_t i = 0; i < mParticle->mParticles.size(); ++i) { ParticleSystem* particle = mParticle->mParticles[i]; particle->setRenderQueueGroup(RQG_Alpha); particle->setVisibilityFlags(RV_Sky); } for (size_t i = 0; i < mParticle->mControllers.size(); ++i) { if (mParticle->mControllers[i].getSource().isNull()) mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); } } } if (mClouds != weather.mCloudTexture) { sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", Misc::ResourceHelpers::correctTexturePath(weather.mCloudTexture)); mClouds = weather.mCloudTexture; } if (mNextClouds != weather.mNextCloudTexture) { sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", Misc::ResourceHelpers::correctTexturePath(weather.mNextCloudTexture)); mNextClouds = weather.mNextCloudTexture; } if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", sh::makeProperty(new sh::FloatValue(weather.mCloudBlendFactor))); } if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; sh::Factory::getInstance().setSharedParameter ("cloudOpacity", sh::makeProperty(new sh::FloatValue(weather.mCloudOpacity))); } if (mCloudColour != weather.mSunColor) { ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7, weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7, weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7); sh::Factory::getInstance().setSharedParameter ("cloudColour", sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); mCloudColour = weather.mSunColor; } if (mSkyColour != weather.mSkyColor) { mSkyColour = weather.mSkyColor; sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4( weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); } if (mFogColour != weather.mFogColor) { mFogColour = weather.mFogColor; sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); } mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) { if (weather.mNightFade == 0) mAtmosphereNight->setVisible(false); else { mAtmosphereNight->setVisible(true); sh::Factory::getInstance().setSharedParameter ("nightFade", sh::makeProperty(new sh::FloatValue(weather.mNightFade))); mStarsOpacity = weather.mNightFade; } } float strength; float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); if (timeofday_angle <= 0.44) strength = timeofday_angle/0.44f; else strength = 1.f; mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); mSun->setVisibility(weather.mGlareView * strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); } void SkyManager::setGlare(const float glare) { mGlare = glare; } Vector3 SkyManager::getRealSunPos() { if (!mCreated) return Vector3(0,0,0); return mSun->getNode()->getPosition() + mCamera->getRealPosition(); } void SkyManager::sunEnable() { mSunEnabled = true; } void SkyManager::sunDisable() { mSunEnabled = false; } void SkyManager::setStormDirection(const Vector3 &direction) { mStormDirection = direction; } void SkyManager::setSunDirection(const Vector3& direction, bool is_moon) { if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); float height = direction.z; float fade = is_moon ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } void SkyManager::setMasserDirection(const Vector3& direction) { if (!mCreated) return; mMasser->setPosition(direction); } void SkyManager::setSecundaDirection(const Vector3& direction) { if (!mCreated) return; mSecunda->setPosition(direction); } void SkyManager::masserEnable() { mMasserEnabled = true; } void SkyManager::secundaEnable() { mSecundaEnabled = true; } void SkyManager::masserDisable() { mMasserEnabled = false; } void SkyManager::secundaDisable() { mSecundaEnabled = false; } void SkyManager::setLightningStrength(const float factor) { if (!mCreated) return; if (factor > 0.f) { mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); mLightning->setVisible(true); } else mLightning->setVisible(false); } void SkyManager::setLightningEnabled(bool enabled) { /// \todo } void SkyManager::setLightningDirection(const Ogre::Vector3& dir) { if (!mCreated) return; mLightning->setDirection (dir); } void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; mMasser->setVisibility(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; mSecunda->setVisibility(fade); } void SkyManager::setHour(double hour) { mHour = hour; } void SkyManager::setDate(int day, int month) { mDay = day; mMonth = month; } Ogre::SceneNode* SkyManager::getSunNode() { if (!mCreated) return 0; return mSun->getNode(); } void SkyManager::setGlareEnabled (bool enabled) { if (!mCreated || !mEnabled) return; mSunGlare->setVisible (mSunEnabled && enabled); }