mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 15:56:42 +00:00 
			
		
		
		
	The InsertFunctor for cells was calling localRotateObject() for all references which set the mChanged flag in RefData to true. Also clean up RefData interface slightly.
		
			
				
	
	
		
			268 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "ripplesimulation.hpp"
 | |
| 
 | |
| #include <OgreTextureManager.h>
 | |
| #include <OgreStringConverter.h>
 | |
| #include <OgreHardwarePixelBuffer.h>
 | |
| #include <OgreRoot.h>
 | |
| #include <OgreRectangle2D.h>
 | |
| #include <OgreSceneNode.h>
 | |
| #include <OgreRenderTexture.h>
 | |
| #include <OgreViewport.h>
 | |
| 
 | |
| #include <extern/shiny/Main/Factory.hpp>
 | |
| 
 | |
| #include "../mwbase/environment.hpp"
 | |
| #include "../mwbase/world.hpp"
 | |
| 
 | |
| namespace MWRender
 | |
| {
 | |
| 
 | |
| 
 | |
| RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager)
 | |
|     : mMainSceneMgr(mainSceneManager),
 | |
|       mTime(0),
 | |
|       mCurrentFrameOffset(0,0),
 | |
|       mPreviousFrameOffset(0,0),
 | |
|       mRippleCenter(0,0),
 | |
|       mTextureSize(512),
 | |
|       mRippleAreaLength(1000),
 | |
|       mImpulseSize(20),
 | |
|       mTexelOffset(0,0),
 | |
|       mFirstUpdate(true),
 | |
|       mRectangle(NULL),
 | |
|       mImpulse(NULL)
 | |
| {
 | |
|     Ogre::AxisAlignedBox aabInf;
 | |
|     aabInf.setInfinite();
 | |
| 
 | |
|     mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
 | |
| 
 | |
|     mCamera = mSceneMgr->createCamera("RippleCamera");
 | |
| 
 | |
|     mRectangle = new Ogre::Rectangle2D(true);
 | |
|     mRectangle->setBoundingBox(aabInf);
 | |
|     mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false);
 | |
|     Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
 | |
|     node->attachObject(mRectangle);
 | |
| 
 | |
|     mImpulse = new Ogre::Rectangle2D(true);
 | |
|     mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false);
 | |
|     mImpulse->setBoundingBox(aabInf);
 | |
|     mImpulse->setMaterial("AddImpulse");
 | |
|     Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
 | |
|     impulseNode->attachObject(mImpulse);
 | |
| 
 | |
|     //float w=0.05;
 | |
|     for (int i=0; i<4; ++i)
 | |
|     {
 | |
|         Ogre::TexturePtr texture;
 | |
|         if (i != 3)
 | |
|             texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i),
 | |
|                 Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
 | |
|         else
 | |
|             texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal",
 | |
|                 Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
 | |
| 
 | |
| 
 | |
|         Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget();
 | |
|         rt->removeAllViewports();
 | |
|         rt->addViewport(mCamera);
 | |
|         rt->setAutoUpdated(false);
 | |
|         rt->getViewport(0)->setClearEveryFrame(false);
 | |
| 
 | |
|         // debug overlay
 | |
|         /*
 | |
|         Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true);
 | |
|         debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false);
 | |
|         w += 0.2;
 | |
|         debugOverlay->setBoundingBox(aabInf);
 | |
|         Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode();
 | |
|         debugNode->attachObject(debugOverlay);
 | |
| 
 | |
|         Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i),
 | |
|             Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
 | |
| 
 | |
|         if (i != 3)
 | |
|             debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i));
 | |
|         else
 | |
|             debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal");
 | |
|         debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false);
 | |
| 
 | |
|         debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i));
 | |
|         */
 | |
| 
 | |
|         mRenderTargets[i] = rt;
 | |
|         mTextures[i] = texture;
 | |
|     }
 | |
| 
 | |
|     sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty<sh::Vector4>(
 | |
|         new sh::Vector4(1.0/512, 1.0/512, 512, 512)));
 | |
|     sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty<sh::Vector3>(
 | |
|          new sh::Vector3(0, 0, 0)));
 | |
|     sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty<sh::FloatValue>(
 | |
|          new sh::FloatValue(mRippleAreaLength)));
 | |
| 
 | |
| }
 | |
| 
 | |
| RippleSimulation::~RippleSimulation()
 | |
| {
 | |
|     delete mRectangle;
 | |
|     delete mImpulse;
 | |
| 
 | |
|     Ogre::Root::getSingleton().destroySceneManager(mSceneMgr);
 | |
| }
 | |
| 
 | |
| void RippleSimulation::update(float dt, Ogre::Vector2 position)
 | |
| {
 | |
|     // try to keep 20 fps
 | |
|     mTime += dt;
 | |
| 
 | |
|     while (mTime >= 1/20.0 || mFirstUpdate)
 | |
|     {
 | |
|         mPreviousFrameOffset = mCurrentFrameOffset;
 | |
| 
 | |
|         mCurrentFrameOffset = position - mRippleCenter;
 | |
|         // add texel offsets from previous frame.
 | |
|         mCurrentFrameOffset += mTexelOffset;
 | |
| 
 | |
|         mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize),
 | |
|                                           std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize));
 | |
| 
 | |
|         // now subtract new offset in order to snap to texels
 | |
|         mCurrentFrameOffset -= mTexelOffset;
 | |
| 
 | |
|         // texture coordinate space
 | |
|         mCurrentFrameOffset /= mRippleAreaLength;
 | |
| 
 | |
|         mRippleCenter = position;
 | |
| 
 | |
|         addImpulses();
 | |
|         waterSimulation();
 | |
|         heightMapToNormalMap();
 | |
| 
 | |
|         swapHeightMaps();
 | |
|         if (!mFirstUpdate)
 | |
|             mTime -= 1/20.0;
 | |
|         else
 | |
|             mFirstUpdate = false;
 | |
|     }
 | |
| 
 | |
|     sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty<sh::Vector3>(
 | |
|          new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0)));
 | |
| }
 | |
| 
 | |
| void RippleSimulation::addImpulses()
 | |
| {
 | |
|     mRectangle->setVisible(false);
 | |
|     mImpulse->setVisible(true);
 | |
| 
 | |
|     /// \todo it should be more efficient to render all emitters at once
 | |
|     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();
 | |
|         }
 | |
|         const float* _currentPos = it->mPtr.getRefData().getPosition().pos;
 | |
|         Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]);
 | |
| 
 | |
|         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);
 | |
|     mRectangle->setVisible(true);
 | |
| }
 | |
| 
 | |
| void RippleSimulation::waterSimulation()
 | |
| {
 | |
|     mRectangle->setMaterial("HeightmapSimulation");
 | |
| 
 | |
|     sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName());
 | |
|     sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName());
 | |
| 
 | |
|     sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty<sh::Vector3>(
 | |
|         new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0)));
 | |
|     sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty<sh::Vector3>(
 | |
|         new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0)));
 | |
| 
 | |
|     mRenderTargets[2]->update();
 | |
| }
 | |
| 
 | |
| void RippleSimulation::heightMapToNormalMap()
 | |
| {
 | |
|     mRectangle->setMaterial("HeightToNormalMap");
 | |
| 
 | |
|     sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName());
 | |
| 
 | |
|     mRenderTargets[TEX_NORMAL]->update();
 | |
| }
 | |
| 
 | |
| void RippleSimulation::swapHeightMaps()
 | |
| {
 | |
|     // 0 -> 1 -> 2 to 2 -> 0 ->1
 | |
|     Ogre::RenderTexture* tmp = mRenderTargets[0];
 | |
|     Ogre::TexturePtr tmp2 = mTextures[0];
 | |
| 
 | |
|     mRenderTargets[0] = mRenderTargets[1];
 | |
|     mTextures[0] = mTextures[1];
 | |
| 
 | |
|     mRenderTargets[1] = mRenderTargets[2];
 | |
|     mTextures[1] = mTextures[2];
 | |
| 
 | |
|     mRenderTargets[2] = tmp;
 | |
|     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<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;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| }
 |