From 9b0ac4e2998facb18cd7b055d8371893c5588f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Feb 2013 09:20:42 +0100 Subject: [PATCH] NPCs / creatures can now emit ripples --- apps/openmw/mwrender/actors.cpp | 9 ++ apps/openmw/mwrender/actors.hpp | 7 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 127 ++++++++++++---------- apps/openmw/mwrender/renderingmanager.hpp | 9 ++ apps/openmw/mwrender/ripplesimulation.cpp | 89 +++++++++++---- apps/openmw/mwrender/ripplesimulation.hpp | 22 +++- apps/openmw/mwrender/water.cpp | 26 +++-- apps/openmw/mwrender/water.hpp | 12 +- 9 files changed, 205 insertions(+), 98 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 83c07737ce..644d3613bd 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,8 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwrender/renderingmanager.hpp" + #include "animation.hpp" #include "activatoranimation.hpp" #include "creatureanimation.hpp" @@ -72,6 +74,7 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertCreature (const MWWorld::Ptr& ptr) { @@ -79,6 +82,7 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertActivator (const MWWorld::Ptr& ptr) { @@ -90,6 +94,8 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + mRendering->removeWaterRippleEmitter (ptr); + delete mAllActors[ptr]; mAllActors.erase(ptr); @@ -120,6 +126,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) { if(iter->first.getCell() == store) { + mRendering->removeWaterRippleEmitter (iter->first); delete iter->second; mAllActors.erase(iter++); } @@ -172,6 +179,8 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) anim->updatePtr(cur); mAllActors[cur] = anim; } + + mRendering->updateWaterRippleEmitterPtr (old, cur); } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 75a18ba915..bba2d945c2 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -13,6 +13,7 @@ namespace MWWorld namespace MWRender { class Animation; + class RenderingManager; class Actors { @@ -20,13 +21,17 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; + MWRender::RenderingManager* mRendering; Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; public: - Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} + Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) + : mRend(_rend) + , mRendering(rendering) + {} ~Actors(); void setRootNode(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8cf4ff123e..8460d67aae 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -32,7 +32,7 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); mLight->setVisible (false); mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9ef705fde4..943208a66b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,7 +51,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) : mRendering(_rend) , mObjects(mRendering) - , mActors(mRendering) + , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) @@ -136,7 +136,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", sh::makeProperty (new sh::Vector3(0,0,0))); sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); @@ -173,6 +172,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); + mWater = new MWRender::Water(mRendering.getCamera(), this); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -222,15 +223,12 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) void RenderingManager::removeWater () { - if(mWater){ - mWater->setActive(false); - } + mWater->setActive(false); } void RenderingManager::toggleWater() { - if (mWater) - mWater->toggle(); + mWater->toggle(); } void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) @@ -321,6 +319,20 @@ RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr & void RenderingManager::update (float duration, bool paused) { + MWBase::World *world = MWBase::Environment::get().getWorld(); + + // player position + MWWorld::RefData &data = + MWBase::Environment::get() + .getWorld() + ->getPlayer() + .getPlayer() + .getRefData(); + float *_playerPos = data.getPosition().pos; + Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); + + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -343,6 +355,17 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + /* + if (world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)) + { + mFogColour = Ogre::ColourValue(0.18039, 0.23137, 0.25490); + mFogStart = 0; + mFogEnd = 1500; + } + */ + + applyFog(); + if(paused) { return; @@ -358,41 +381,21 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); - - float *fpos = data.getPosition().pos; - - // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - Ogre::SceneNode *node = data.getBaseNode(); //Ogre::Quaternion orient = //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = node->_getDerivedOrientation(); - mLocalMap->updatePlayer(pos, orient); + mLocalMap->updatePlayer(playerPos, orient); - if (mWater) { - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + mWater->updateUnderwater( + world->isUnderwater( + world->getPlayer().getPlayer().getCell(), + cam) + ); - MWBase::World *world = MWBase::Environment::get().getWorld(); - - mWater->updateUnderwater( - world->isUnderwater( - world->getPlayer().getPlayer().getCell(), - cam) - ); - - // MW to ogre coordinates - orig = Ogre::Vector3(orig.x, orig.z, -orig.y); - mWater->update(duration, orig); - } + mWater->update(duration, playerPos); } void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) @@ -416,10 +419,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) || ((store->mCell->isExterior()) && !lands.search(store->mCell->getGridX(),store->mCell->getGridY()) )) // always use water, if the cell does not have land. { - if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), this, store->mCell); - else - mWater->changeCell(store->mCell); + mWater->changeCell(store->mCell); mWater->setActive(true); } else @@ -428,8 +428,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) void RenderingManager::setWaterHeight(const float height) { - if (mWater) - mWater->setHeight(height); + mWater->setHeight(height); } void RenderingManager::skyEnable () @@ -521,24 +520,26 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { + mFogColour = colour; float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); - float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - - mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); - - mRendering.getCamera()->setFarClipDistance ( max / density ); - mRendering.getViewport()->setBackgroundColour (colour); - - if (mWater) - mWater->setViewportBackground (colour); - - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", - sh::makeProperty (new sh::Vector3(colour.r, colour.g, colour.b))); + mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); + mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); + mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density ); } +void RenderingManager::applyFog () +{ + mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); + + mRendering.getViewport()->setBackgroundColour (mFogColour); + + mWater->setViewportBackground (mFogColour); + + sh::Factory::getInstance ().setSharedParameter ("viewportBackground", + sh::makeProperty (new sh::Vector3(mFogColour.r, mFogColour.g, mFogColour.b))); +} void RenderingManager::setAmbientMode() { @@ -826,8 +827,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } - if (mWater) - mWater->processChangedSettings(settings); + mWater->processChangedSettings(settings); if (rebuild) mObjects.rebuildStaticGeometry(); @@ -902,6 +902,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors ); mPlayer->setAnimation(anim); + mWater->removeEmitter (ptr); + mWater->addEmitter (ptr); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) @@ -945,4 +947,19 @@ void RenderingManager::stopVideo() mVideoPlayer->stopVideo (); } +void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) +{ + mWater->addEmitter (ptr, scale, force); +} + +void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr) +{ + mWater->removeEmitter (ptr); +} + +void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mWater->updateEmitterPtr(old, ptr); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5d79f80aa7..02d796fddf 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -163,6 +163,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void skySetMoonColour (bool red); void configureAmbient(MWWorld::CellStore &mCell); + void addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeWaterRippleEmitter (const MWWorld::Ptr& ptr); + void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void requestMap (MWWorld::CellStore* cell); ///< request the local map for a cell @@ -204,6 +208,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList sh::Factory* mFactory; void setAmbientMode(); + void applyFog(); void setMenuTransparency(float val); @@ -234,6 +239,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::SceneNode *mRootNode; + Ogre::ColourValue mFogColour; + float mFogStart; + float mFogEnd; + OEngine::Physic::PhysicEngine* mPhysicsEngine; MWRender::Player *mPlayer; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6c9264b608..47fbc8ddf6 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -7,6 +7,11 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" + namespace MWRender { @@ -21,8 +26,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true), - mLastPos(0,0) + mFirstUpdate(true) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -142,34 +146,39 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); } -void RippleSimulation::addImpulse(Ogre::Vector2 position, float scale, float force) -{ - // don't emit if there wasn't enough movement - /// \todo this should be done somewhere else, otherwise multiple emitters cannot be supported - if ((position - mLastPos).length () <= 2) - return; - - mLastPos = position; - - /// \todo scale, force - mImpulses.push(position); -} - void RippleSimulation::addImpulses() { mRectangle->setVisible(false); mImpulse->setVisible(true); - while (mImpulses.size()) + /// \todo it should be more efficient to render all emitters at once + for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { - Ogre::Vector2 pos = mImpulses.front(); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - mImpulses.pop(); + if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + { + // fetch a new ptr (to handle cell change etc) + // for non-player actors this is done in updateObjectCell + it->mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + } + float* _currentPos = it->mPtr.getRefData().getPosition().pos; + Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - mRenderTargets[1]->update(); + if ( (currentPos - it->mLastEmitPosition).length() > 2 + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + { + it->mLastEmitPosition = currentPos; + + Ogre::Vector2 pos (currentPos.x, currentPos.y); + pos -= mRippleCenter; + pos /= mRippleAreaLength; + float size = mImpulseSize / mRippleAreaLength; + mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); + + // don't render if we are offscreen + if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) + continue; + mRenderTargets[1]->update(); + } } mImpulse->setVisible(false); @@ -216,5 +225,39 @@ void RippleSimulation::swapHeightMaps() mTextures[2] = tmp2; } +void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +{ + Emitter newEmitter; + newEmitter.mPtr = ptr; + newEmitter.mScale = scale; + newEmitter.mForce = force; + newEmitter.mLastEmitPosition = Ogre::Vector3(0,0,0); + mEmitters.push_back (newEmitter); +} + +void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == ptr) + { + mEmitters.erase(it); + return; + } + } +} + +void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == old) + { + it->mPtr = ptr; + return; + } + } +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 2f8cae24fd..7e7eebc1cf 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -4,6 +4,9 @@ #include #include #include +#include + +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -16,6 +19,14 @@ namespace Ogre namespace MWRender { +struct Emitter +{ + MWWorld::Ptr mPtr; + Ogre::Vector3 mLastEmitPosition; + float mScale; + float mForce; +}; + class RippleSimulation { public: @@ -24,9 +35,14 @@ public: void update(float dt, Ogre::Vector2 position); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); private: + std::vector mEmitters; + Ogre::RenderTexture* mRenderTargets[4]; Ogre::TexturePtr mTextures[4]; @@ -34,8 +50,6 @@ private: float mRippleAreaLength; float mImpulseSize; - Ogre::Vector2 mLastPos; - bool mFirstUpdate; Ogre::Camera* mCamera; @@ -51,8 +65,6 @@ private: Ogre::Rectangle2D* mImpulse; - std::queue mImpulses; - void addImpulses(); void heightMapToNormalMap(); void waterSimulation(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7d6ca1a0d0..d112e17b2c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -81,6 +81,7 @@ void CubeReflection::update () PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) : Reflection(sceneManager) , mSky(sky) + , mRenderActive(false) { mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); mSceneMgr->addRenderQueueListener(this); @@ -186,7 +187,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -202,7 +203,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mMaterial = MaterialManager::getSingleton().getByName("Water"); - mTop = cell->mWater; + mTop = 0; mIsUnderwater = false; @@ -216,10 +217,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - if(!(cell->mData.mFlags & cell->Interior)) - { - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); - } mWaterNode->attachObject(mWater); applyRTT(); @@ -397,7 +394,7 @@ void Water::update(float dt, Ogre::Vector3 player) { //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } - mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); + mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); if (mReflection) mReflection->update(); @@ -499,10 +496,19 @@ void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& co } } -void Water::addImpulse (Vector2 position, float scale, float force) +void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { - if (mSimulation) - mSimulation->addImpulse (position, scale, force); + mSimulation->addEmitter (ptr, scale, force); +} + +void Water::removeEmitter (const MWWorld::Ptr& ptr) +{ + mSimulation->removeEmitter (ptr); +} + +void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mSimulation->updateEmitterPtr(old, ptr); } } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index eb7d98f5da..ddf6ef7ab7 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,9 +11,12 @@ #include #include +#include + + #include "renderconst.hpp" -#include +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -138,7 +141,7 @@ namespace MWRender { RippleSimulation* mSimulation; public: - Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); + Water (Ogre::Camera *camera, RenderingManager* rend); ~Water(); void setActive(bool active); @@ -146,7 +149,10 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically using its scene node + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void setViewportBackground(const Ogre::ColourValue& bg);