1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 21:53:51 +00:00

Water ripples

This commit is contained in:
scrawl 2015-06-16 20:36:48 +02:00
parent 3663511cdb
commit 3da8f6e62e
10 changed files with 355 additions and 14 deletions

View file

@ -22,7 +22,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

View file

@ -114,7 +114,7 @@ namespace MWRender
bool mWireframe; bool mWireframe;
}; };
RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, Resource::ResourceSystem* resourceSystem) RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback)
: mViewer(viewer) : mViewer(viewer)
, mRootNode(rootNode) , mRootNode(rootNode)
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
@ -136,7 +136,7 @@ namespace MWRender
mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem));
mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation())); mWater.reset(new Water(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback));
mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(),
new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain)); new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain));
@ -265,6 +265,8 @@ namespace MWRender
if (store->getCell()->isExterior()) if (store->getCell()->isExterior())
mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY());
mWater->removeCell(store);
} }
void RenderingManager::setSkyEnabled(bool enabled) void RenderingManager::setSkyEnabled(bool enabled)
@ -330,6 +332,7 @@ namespace MWRender
{ {
mEffectManager->update(dt); mEffectManager->update(dt);
mSky->update(dt); mSky->update(dt);
mWater->update(dt);
mCamera->update(dt, paused); mCamera->update(dt, paused);
osg::Vec3f focal, cameraPos; osg::Vec3f focal, cameraPos;
@ -354,6 +357,11 @@ namespace MWRender
mCamera->attachTo(ptr); mCamera->attachTo(ptr);
} }
void RenderingManager::removePlayer(const MWWorld::Ptr &player)
{
mWater->removeEmitter(player);
}
void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot)
{ {
if(ptr == mCamera->getTrackingPtr() && if(ptr == mCamera->getTrackingPtr() &&
@ -378,6 +386,7 @@ namespace MWRender
void RenderingManager::removeObject(const MWWorld::Ptr &ptr) void RenderingManager::removeObject(const MWWorld::Ptr &ptr)
{ {
mObjects->removeObject(ptr); mObjects->removeObject(ptr);
mWater->removeEmitter(ptr);
} }
void RenderingManager::setWaterEnabled(bool enabled) void RenderingManager::setWaterEnabled(bool enabled)
@ -579,7 +588,7 @@ namespace MWRender
void RenderingManager::notifyWorldSpaceChanged() void RenderingManager::notifyWorldSpaceChanged()
{ {
mEffectManager->clear(); mEffectManager->clear();
//mWater->clearRipples(); mWater->clearRipples();
} }
void RenderingManager::clear() void RenderingManager::clear()
@ -613,6 +622,8 @@ namespace MWRender
mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player));
player.getRefData().setBaseNode(mPlayerNode); player.getRefData().setBaseNode(mPlayerNode);
mWater->addEmitter(player);
} }
void RenderingManager::renderPlayer(const MWWorld::Ptr &player) void RenderingManager::renderPlayer(const MWWorld::Ptr &player)
@ -621,8 +632,6 @@ namespace MWRender
mCamera->setAnimation(mPlayerAnimation.get()); mCamera->setAnimation(mPlayerAnimation.get());
mCamera->attachTo(player); mCamera->attachTo(player);
//mWater->removeEmitter(ptr);
//mWater->addEmitter(ptr);
} }
void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
@ -643,6 +652,16 @@ namespace MWRender
} }
} }
void RenderingManager::addWaterRippleEmitter(const MWWorld::Ptr &ptr)
{
mWater->addEmitter(ptr);
}
void RenderingManager::removeWaterRippleEmitter(const MWWorld::Ptr &ptr)
{
mWater->removeEmitter(ptr);
}
void RenderingManager::updateProjectionMatrix() void RenderingManager::updateProjectionMatrix()
{ {
double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); double aspect = mViewer->getCamera()->getViewport()->aspectRatio();

View file

@ -37,6 +37,11 @@ namespace Terrain
class World; class World;
} }
namespace MWWorld
{
class Fallback;
}
namespace MWRender namespace MWRender
{ {
@ -52,7 +57,7 @@ namespace MWRender
class RenderingManager : public MWRender::RenderingInterface class RenderingManager : public MWRender::RenderingInterface
{ {
public: public:
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, Resource::ResourceSystem* resourceSystem); RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback);
~RenderingManager(); ~RenderingManager();
MWRender::Objects& getObjects(); MWRender::Objects& getObjects();
@ -125,8 +130,12 @@ namespace MWRender
Animation* getAnimation(const MWWorld::Ptr& ptr); Animation* getAnimation(const MWWorld::Ptr& ptr);
Animation* getPlayerAnimation(); Animation* getPlayerAnimation();
void addWaterRippleEmitter(const MWWorld::Ptr& ptr);
void removeWaterRippleEmitter(const MWWorld::Ptr& ptr);
void updatePlayerPtr(const MWWorld::Ptr &ptr); void updatePlayerPtr(const MWWorld::Ptr &ptr);
void removePlayer(const MWWorld::Ptr& player);
void setupPlayer(const MWWorld::Ptr& player); void setupPlayer(const MWWorld::Ptr& player);
void renderPlayer(const MWWorld::Ptr& player); void renderPlayer(const MWWorld::Ptr& player);

View file

@ -0,0 +1,202 @@
#include "ripplesimulation.hpp"
#include <iomanip>
#include <osg/Geode>
#include <osg/Texture2D>
#include <osg/Material>
#include <osg/Depth>
#include <osg/PositionAttitudeTransform>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleSystemUpdater>
#include <components/misc/rng.hpp>
#include <components/nifosg/controller.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include "vismask.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/fallback.hpp"
namespace
{
void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node)
{
int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount");
if (rippleFrameCount <= 0)
return;
std::string tex = fallback->getFallbackString("Water_RippleTexture");
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
for (int i=0; i<rippleFrameCount; ++i)
{
std::ostringstream texname;
texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds";
textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT));
}
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures));
controller->setSource(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
node->addUpdateCallback(controller);
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON);
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Material> mat (new osg::Material);
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
mat->setColorMode(osg::Material::DIFFUSE);
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
node->setStateSet(stateset);
}
}
namespace MWRender
{
RippleSimulation::RippleSimulation(osg::Group *parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback)
: mParent(parent)
{
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
mParticleSystem = new osgParticle::ParticleSystem;
geode->addDrawable(mParticleSystem);
mParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
mParticleSystem->setAlignVectorX(osg::Vec3f(1,0,0));
mParticleSystem->setAlignVectorY(osg::Vec3f(0,1,0));
osgParticle::Particle& particleTemplate = mParticleSystem->getDefaultParticleTemplate();
particleTemplate.setSizeRange(osgParticle::rangef(15, 180));
particleTemplate.setColorRange(osgParticle::rangev4(osg::Vec4f(1,1,1,0.7), osg::Vec4f(1,1,1,0.7)));
particleTemplate.setAlphaRange(osgParticle::rangef(1.f, 0.f));
particleTemplate.setAngularVelocity(osg::Vec3f(0,0,fallback->getFallbackFloat("Water_RippleRotSpeed")));
particleTemplate.setLifeTime(fallback->getFallbackFloat("Water_RippleLifetime"));
osg::ref_ptr<osgParticle::ParticleSystemUpdater> updater (new osgParticle::ParticleSystemUpdater);
updater->addParticleSystem(mParticleSystem);
mParticleNode = new osg::PositionAttitudeTransform;
mParticleNode->addChild(updater);
mParticleNode->addChild(geode);
mParticleNode->setNodeMask(Mask_Effect);
createWaterRippleStateSet(resourceSystem, fallback, mParticleNode);
mParent->addChild(mParticleNode);
}
RippleSimulation::~RippleSimulation()
{
mParent->removeChild(mParticleNode);
}
void RippleSimulation::update(float dt)
{
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
{
if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr())
{
// fetch a new ptr (to handle cell change etc)
// for non-player actors this is done in updateObjectCell
it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
}
osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3());
currentPos.z() = 0; // Z is set by the Scene Node
if ( (currentPos - it->mLastEmitPosition).length() > 10
// Only emit when close to the water surface, not above it and not too deep in the water
&& MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3())
&& !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr))
{
it->mLastEmitPosition = currentPos;
if (mParticleSystem->numParticles()-mParticleSystem->numDeadParticles() > 500)
continue; // TODO: remove the oldest particle to make room?
osgParticle::Particle* p = mParticleSystem->createParticle(NULL);
p->setPosition(currentPos);
p->setAngle(osg::Vec3f(0,0, Misc::Rng::rollProbability() * osg::PI * 2 - osg::PI));
}
}
}
void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force)
{
Emitter newEmitter;
newEmitter.mPtr = ptr;
newEmitter.mScale = scale;
newEmitter.mForce = force;
newEmitter.mLastEmitPosition = osg::Vec3f(0,0,0);
mEmitters.push_back (newEmitter);
}
void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr)
{
for (std::vector<Emitter>::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<Emitter>::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it)
{
if (it->mPtr == old)
{
it->mPtr = ptr;
return;
}
}
}
void RippleSimulation::removeCell(const MWWorld::CellStore *store)
{
for (std::vector<Emitter>::iterator it = mEmitters.begin(); it != mEmitters.end();)
{
if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr())
{
it = mEmitters.erase(it);
}
else
++it;
}
}
void RippleSimulation::setWaterHeight(float height)
{
mParticleNode->setPosition(osg::Vec3f(0,0,height));
}
void RippleSimulation::clear()
{
for (int i=0; i<mParticleSystem->numParticles(); ++i)
mParticleSystem->destroyParticle(i);
}
}

View file

@ -0,0 +1,76 @@
#ifndef OPENMW_MWRENDER_RIPPLESIMULATION_H
#define OPENMW_MWRENDER_RIPPLESIMULATION_H
#include <osg/ref_ptr>
#include "../mwworld/ptr.hpp"
namespace osg
{
class Group;
}
namespace osgParticle
{
class ParticleSystem;
}
namespace Resource
{
class ResourceSystem;
}
namespace MWWorld
{
class Fallback;
}
namespace MWRender
{
struct Emitter
{
MWWorld::Ptr mPtr;
osg::Vec3f mLastEmitPosition;
float mScale;
float mForce;
};
class RippleSimulation
{
public:
RippleSimulation(osg::Group* parent, Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback);
~RippleSimulation();
/// @param dt Time since the last frame
void update(float dt);
/// 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);
void removeCell(const MWWorld::CellStore* store);
/// Change the height of the water surface, thus moving all ripples with it
void setWaterHeight(float height);
/// Remove all active ripples
void clear();
private:
osg::ref_ptr<osg::Group> mParent;
Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<osgParticle::ParticleSystem> mParticleSystem;
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
std::vector<Emitter> mEmitters;
float mRippleLifeTime;
float mRippleRotSpeed;
};
}
#endif

View file

@ -18,6 +18,7 @@
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
#include "vismask.hpp" #include "vismask.hpp"
#include "ripplesimulation.hpp"
namespace namespace
{ {
@ -107,13 +108,15 @@ namespace MWRender
// -------------------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------------------
Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico) Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback)
: mParent(parent) : mParent(parent)
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mEnabled(true) , mEnabled(true)
, mToggled(true) , mToggled(true)
, mTop(0) , mTop(0)
{ {
mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback));
osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900);
osg::ref_ptr<osg::Geode> geode (new osg::Geode); osg::ref_ptr<osg::Geode> geode (new osg::Geode);
@ -161,6 +164,11 @@ void Water::setHeight(const float height)
mWaterNode->setPosition(pos); mWaterNode->setPosition(pos);
} }
void Water::update(float dt)
{
mSimulation->update(dt);
}
void Water::updateVisible() void Water::updateVisible()
{ {
mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0);
@ -183,7 +191,6 @@ osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY)
return osg::Vec3f(static_cast<float>(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast<float>(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); return osg::Vec3f(static_cast<float>(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast<float>(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop);
} }
/*
void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force)
{ {
mSimulation->addEmitter (ptr, scale, force); mSimulation->addEmitter (ptr, scale, force);
@ -198,6 +205,15 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
{ {
mSimulation->updateEmitterPtr(old, ptr); mSimulation->updateEmitterPtr(old, ptr);
} }
*/
void Water::removeCell(const MWWorld::CellStore *store)
{
mSimulation->removeCell(store);
}
void Water::clearRipples()
{
mSimulation->clear();
}
} }

View file

@ -21,9 +21,16 @@ namespace Resource
class ResourceSystem; class ResourceSystem;
} }
namespace MWWorld
{
class Fallback;
}
namespace MWRender namespace MWRender
{ {
class RippleSimulation;
/// Water rendering /// Water rendering
class Water class Water
{ {
@ -34,6 +41,8 @@ namespace MWRender
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation; osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation;
std::auto_ptr<RippleSimulation> mSimulation;
bool mEnabled; bool mEnabled;
bool mToggled; bool mToggled;
float mTop; float mTop;
@ -42,7 +51,7 @@ namespace MWRender
void updateVisible(); void updateVisible();
public: public:
Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico); Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback);
~Water(); ~Water();
void setEnabled(bool enabled); void setEnabled(bool enabled);
@ -51,16 +60,19 @@ namespace MWRender
bool isUnderwater(const osg::Vec3f& pos) const; bool isUnderwater(const osg::Vec3f& pos) const;
/*
/// adds an emitter, position will be tracked automatically using its scene node /// 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 addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f);
void removeEmitter (const MWWorld::Ptr& ptr); void removeEmitter (const MWWorld::Ptr& ptr);
void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
*/ void removeCell(const MWWorld::CellStore* store); ///< remove all emitters in this cell
void clearRipples();
void changeCell(const MWWorld::CellStore* store); void changeCell(const MWWorld::CellStore* store);
void setHeight(const float height); void setHeight(const float height);
void update(float dt);
}; };
} }

View file

@ -58,4 +58,5 @@ namespace MWWorld
return osg::Vec4f(boost::lexical_cast<int>(ret[0])/255.f,boost::lexical_cast<int>(ret[1])/255.f,boost::lexical_cast<int>(ret[2])/255.f, 1.f); return osg::Vec4f(boost::lexical_cast<int>(ret[0])/255.f,boost::lexical_cast<int>(ret[1])/255.f,boost::lexical_cast<int>(ret[2])/255.f, 1.f);
} }
} }
} }

View file

@ -39,6 +39,9 @@ namespace
model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
ptr.getClass().insertObjectRendering(ptr, model, rendering); ptr.getClass().insertObjectRendering(ptr, model, rendering);
ptr.getClass().insertObject (ptr, model, physics); ptr.getClass().insertObject (ptr, model, physics);
if (ptr.getClass().isActor())
rendering.addWaterRippleEmitter(ptr);
} }
void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
@ -570,6 +573,8 @@ namespace MWWorld
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
mPhysics->remove(ptr); mPhysics->remove(ptr);
mRendering.removeObject (ptr); mRendering.removeObject (ptr);
if (ptr.getClass().isActor())
mRendering.removeWaterRippleEmitter(ptr);
} }
bool Scene::isCellActive(const CellStore &cell) bool Scene::isCellActive(const CellStore &cell)

View file

@ -161,7 +161,7 @@ namespace MWWorld
{ {
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode);
mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics));
mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback);
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
@ -2064,6 +2064,7 @@ namespace MWWorld
// Remove the old CharacterController // Remove the old CharacterController
MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr());
mPhysics->remove(getPlayerPtr()); mPhysics->remove(getPlayerPtr());
mRendering->removePlayer(getPlayerPtr());
mPlayer->set(player); mPlayer->set(player);
} }