diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0603c18a1..cce2e1b1d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -47,7 +47,7 @@ #include "vismask.hpp" #include "renderbin.hpp" -#define PARTICLE_WIDTH 600.0 +#define RAIN_WIDTH 600.0 namespace { @@ -1344,17 +1344,19 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager, float rangeX, float rangeY) : osg::Drawable::DrawCallback() { mRendering = renderingManager; + mRangeX = rangeX; + mRangeY = rangeY; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { osg::Vec3 cameraPos = mRendering->getCameraPosition(); osg::Vec3 cameraOffset = osg::Vec3( - PARTICLE_WIDTH - fmod(cameraPos.x(), PARTICLE_WIDTH / 2), - PARTICLE_WIDTH - fmod(cameraPos.y(), PARTICLE_WIDTH / 2), + mRangeX - fmod(cameraPos.x(), mRangeX / 2), + mRangeY - fmod(cameraPos.y(), mRangeY / 2), 0); osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; @@ -1362,7 +1364,7 @@ public: for (int xOff = 0; xOff < 3; xOff++) for (int yOff = 0; yOff < 3; yOff++) { - osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * PARTICLE_WIDTH, -1 * yOff * PARTICLE_WIDTH,0); + osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * mRangeX, -1 * yOff * mRangeY,0); for(int i = 0; i < ps->numParticles(); i++) ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); @@ -1376,6 +1378,7 @@ public: protected: MWRender::RenderingManager *mRendering; + float mRangeX, mRangeY; }; void SkyManager::createRain() @@ -1386,7 +1389,7 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering,RAIN_WIDTH,RAIN_WIDTH)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1413,8 +1416,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); // Rain_Diameter - placer->setYRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); + placer->setXRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); // Rain_Diameter + placer->setYRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1493,8 +1496,6 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); - if (mParticleNode) - mParticleNode->setAttitude(quat); mCloudNode->setAttitude(quat); } else @@ -1586,7 +1587,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode = new osg::Group; mParticleNode->addCullCallback(mUnderwaterSwitch); mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); @@ -1603,11 +1604,29 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) - (mParticleEffect->asGroup()->getChild(1)->asGroup()->getChild(0) - ->asGroup()->getChild(2)); + SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); + mParticleEffect->accept(findEmitterVisitor); - ps->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + float rangeX = RAIN_WIDTH; + float rangeY = RAIN_WIDTH; + + if (findEmitterVisitor.mFoundNode) + { + osgParticle::Placer *placer = ((NifOsg::Emitter *) findEmitterVisitor.mFoundNode)->getPlacer(); + + if (placer && strcmp(placer->className(),"BoxPlacer") == 0) + { + rangeX = ((osgParticle::BoxPlacer *) placer)->getXRange().maximum; + rangeY = ((osgParticle::BoxPlacer *) placer)->getYRange().maximum; + } + } + + + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); + + if (findPSVisitor.mFoundNode) + ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(mRendering,rangeX,rangeY)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 37c999563..fdcd27e5a 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -177,7 +177,7 @@ namespace MWRender osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; - osg::ref_ptr mParticleNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; osg::ref_ptr mUnderwaterSwitch; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 62360b9d6..547b71034 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -250,6 +250,11 @@ void Emitter::setPlacer(osgParticle::Placer *placer) mPlacer = placer; } +osgParticle::Placer *Emitter::getPlacer() +{ + return mPlacer; +} + void Emitter::setCounter(osgParticle::Counter *counter) { mCounter = counter; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 7a2377f9d..df93d5ced 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -225,6 +225,7 @@ namespace NifOsg void setShooter(osgParticle::Shooter* shooter); void setPlacer(osgParticle::Placer* placer); + osgParticle::Placer *getPlacer(); void setCounter(osgParticle::Counter* counter); private: diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 74b9be63d..202e6373e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -19,6 +19,14 @@ namespace SceneUtil return false; } + void FindByClassVisitor::apply(osg::Node &node) + { + if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) + mFoundNode = &node; + else + traverse(node); + } + void FindByNameVisitor::apply(osg::Group &group) { if (!checkGroup(group)) diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 209f2d9bd..973f44646 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -20,7 +20,6 @@ namespace SceneUtil } virtual void apply(osg::Group& group); - virtual void apply(osg::MatrixTransform& node); virtual void apply(osg::Geometry& node); @@ -30,6 +29,22 @@ namespace SceneUtil osg::Group* mFoundNode; }; + class FindByClassVisitor : public osg::NodeVisitor + { + public: + FindByClassVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node); + + std::string mNameToFind; + osg::Node* mFoundNode; + }; + // Disable freezeOnCull for all visited particlesystems class DisableFreezeOnCullVisitor : public osg::NodeVisitor {