/* This file is part of Caelum. See http://www.ogre3d.org/wiki/index.php/Caelum Copyright (c) 2006-2007 Caelum team. See Contributors.txt for details. Caelum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Caelum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Caelum. If not, see . */ #include "CaelumPrecompiled.h" #include "GroundFog.h" #include "CaelumExceptions.h" #include "InternalUtilities.h" namespace Caelum { const Ogre::String GroundFog::DEFAULT_PASS_NAME = "CaelumGroundFog"; GroundFog::GroundFog( Ogre::SceneManager *sceneMgr, Ogre::SceneNode *caelumRootNode, const Ogre::String &domeMaterialName, const Ogre::String &domeEntityName): mScene(sceneMgr) { Ogre::String uniqueSuffix = InternalUtilities::pointerToString (this); mDomeMaterial.reset(InternalUtilities::checkLoadMaterialClone (domeMaterialName, domeMaterialName + uniqueSuffix)); mDomeParams.setup(mDomeMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()); // Create dome entity, using a prefab sphere. // The prefab sphere has a radius of 50 units. // If this changes in future version of ogre this might break. mDomeEntity.reset (mScene->createEntity (domeEntityName, Ogre::SceneManager::PT_SPHERE)); mDomeEntity->setMaterialName (mDomeMaterial->getName ()); mDomeEntity->setCastShadows (false); mDomeEntity->setRenderQueueGroup (CAELUM_RENDER_QUEUE_GROUND_FOG); sceneMgr->getRenderQueue()->getQueueGroup(CAELUM_RENDER_QUEUE_GROUND_FOG)->setShadowsEnabled(false); // Create dome node mDomeNode.reset (caelumRootNode->createChildSceneNode ()); mDomeNode->attachObject (mDomeEntity.get()); // Initialize default fog parameters mDensity = 0.1; mVerticalDecay = 0.2; mGroundLevel = 5; mFogColour = Ogre::ColourValue::Black; forceUpdate(); } GroundFog::~GroundFog() { // Disable passes. setDensity(0); } GroundFog::PassSet& GroundFog::getPasses() { return mPasses; } const GroundFog::PassSet& GroundFog::getPasses() const { return mPasses; } void GroundFog::findFogPassesByName (const Ogre::String& passName) { Ogre::MaterialManager *matManager = Ogre::MaterialManager::getSingletonPtr(); Ogre::MaterialManager::ResourceMapIterator matIt = matManager->getResourceIterator(); while (matIt.hasMoreElements()) { Ogre::MaterialPtr mat = matIt.getNext(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); while (techIt.hasMoreElements()) { Ogre::Technique *tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); while (passIt.hasMoreElements()) { Ogre::Pass *pass = passIt.getNext(); if (pass->getName() == passName) { mPasses.insert(pass); } } } } forceUpdate(); } void GroundFog::setDensity (Ogre::Real density) { if (Ogre::Math::Abs(mDensity - density) > 0.000001) { for (PassFogParamsVector::const_iterator it = mPassFogParams.begin(), end = mPassFogParams.end(); it != end; ++it) { it->fogDensity.set(it->fpParams, density); } mDensity = density; } updateSkyFogging(); } Ogre::Real GroundFog::getDensity () const { return mDensity; } void GroundFog::setColour (const Ogre::ColourValue &colour) { bool different = Ogre::Math::Abs(mFogColour.r - colour.r) > 0.001 || Ogre::Math::Abs(mFogColour.g - colour.g) > 0.001 || Ogre::Math::Abs(mFogColour.b - colour.b) > 0.001 || Ogre::Math::Abs(mFogColour.a - colour.a) > 0.001; if (different) { for (PassFogParamsVector::const_iterator it = mPassFogParams.begin(), end = mPassFogParams.end(); it != end; ++it) { it->fogColour.set(it->fpParams, colour); } mFogColour = colour; } updateSkyFogging(); } const Ogre::ColourValue GroundFog::getColour () const { return mFogColour; } void GroundFog::setVerticalDecay (Ogre::Real verticalDecay) { if (Ogre::Math::Abs(mVerticalDecay - verticalDecay) > 0.000001) { for (PassFogParamsVector::const_iterator it = mPassFogParams.begin(), end = mPassFogParams.end(); it != end; ++it) { it->fogVerticalDecay.set(it->fpParams, verticalDecay); } mVerticalDecay = verticalDecay; } updateSkyFogging(); } Ogre::Real GroundFog::getVerticalDecay () const { return mVerticalDecay; } void GroundFog::setGroundLevel (Ogre::Real groundLevel) { if (Ogre::Math::Abs(mGroundLevel - groundLevel) > 0.000001) { for (PassFogParamsVector::const_iterator it = mPassFogParams.begin(), end = mPassFogParams.end(); it != end; ++it) { it->fogGroundLevel.set(it->fpParams, groundLevel); } mGroundLevel = groundLevel; } updateSkyFogging(); } Ogre::Real GroundFog::getGroundLevel () const { return mGroundLevel; } void GroundFog::updateSkyFogging() { mDomeParams.fogDensity.set(mDomeParams.fpParams, mDensity); mDomeParams.fogVerticalDecay.set(mDomeParams.fpParams, mVerticalDecay); mDomeParams.fogGroundLevel.set(mDomeParams.fpParams, mGroundLevel); mDomeParams.fogColour.set(mDomeParams.fpParams, mFogColour); } void GroundFog::forceUpdate () { updatePassFogParams(); for (PassFogParamsVector::const_iterator it = mPassFogParams.begin(), end = mPassFogParams.end(); it != end; ++it) { const PassFogParams& params = *it; params.fogDensity.set(params.fpParams, mDensity); params.fogVerticalDecay.set(params.fpParams, mVerticalDecay); params.fogGroundLevel.set(params.fpParams, mGroundLevel); params.fogColour.set(params.fpParams, mFogColour); } updateSkyFogging(); } void GroundFog::updatePassFogParams () { mPassFogParams.clear(); for (PassSet::const_iterator it = mPasses.begin(), end = mPasses.end(); it != end; ++it) { mPassFogParams.push_back(PassFogParams((*it)->getFragmentProgramParameters())); } std::sort(mPassFogParams.begin(), mPassFogParams.end(), PassFogParams::lessThanByParams); std::unique(mPassFogParams.begin(), mPassFogParams.end(), PassFogParams::equalByParams); } void GroundFog::FogParamsBase::setup(Ogre::GpuProgramParametersSharedPtr fpParams) { this->fpParams = fpParams; fogDensity.bind(fpParams, "fogDensity"); fogVerticalDecay.bind(fpParams, "fogVerticalDecay"); fogGroundLevel.bind(fpParams, "fogGroundLevel"); fogColour.bind(fpParams, "fogColour"); } void GroundFog::DomeFogParams::setup(Ogre::GpuProgramParametersSharedPtr fpParams) { FogParamsBase::setup(fpParams); cameraHeight.bind(fpParams, "cameraHeight"); } void GroundFog::notifyCameraChanged (Ogre::Camera *cam) { CameraBoundElement::notifyCameraChanged (cam); // Send camera height to shader. float cameraHeight = cam->getDerivedPosition().dotProduct(mDomeNode->_getDerivedOrientation() * Ogre::Vector3::UNIT_Y); mDomeParams.cameraHeight.set(mDomeParams.fpParams, cameraHeight); } void GroundFog::setFarRadius (Ogre::Real radius) { CameraBoundElement::setFarRadius(radius); // Adjust for radius 50. mDomeNode->setScale(Ogre::Vector3::UNIT_SCALE * radius / 50.0); } }