2013-02-01 22:43:23 +00:00
# include "ripplesimulation.hpp"
2015-02-09 18:28:29 +00:00
# include <stdexcept>
2014-02-19 17:40:29 +00:00
# include <OgreSceneNode.h>
2015-02-09 18:28:29 +00:00
# include <OgreSceneManager.h>
# include <OgreParticleSystem.h>
# include <OgreParticle.h>
2013-02-01 22:43:23 +00:00
# include <extern/shiny/Main/Factory.hpp>
2013-02-27 08:20:42 +00:00
# include "../mwbase/environment.hpp"
# include "../mwbase/world.hpp"
2015-02-09 18:28:29 +00:00
# include "../mwworld/fallback.hpp"
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
# include "renderconst.hpp"
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
namespace MWRender
2013-02-01 22:43:23 +00:00
{
2015-02-09 18:28:29 +00:00
RippleSimulation : : RippleSimulation ( Ogre : : SceneManager * mainSceneManager , const MWWorld : : Fallback * fallback )
: mSceneMgr ( mainSceneManager )
, mParticleSystem ( NULL )
, mSceneNode ( NULL )
{
mRippleLifeTime = fallback - > getFallbackFloat ( " Water_RippleLifetime " ) ;
mRippleRotSpeed = fallback - > getFallbackFloat ( " Water_RippleRotSpeed " ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
// Unknown:
// fallback=Water_RippleScale,0.15, 6.5
// fallback=Water_RippleAlphas,0.7, 0.1, 0.01
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
// Instantiate from ripples.particle file
mParticleSystem = mSceneMgr - > createParticleSystem ( " openmw/Ripples " , " openmw/Ripples " ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
mParticleSystem - > setRenderQueueGroup ( RQG_Ripples ) ;
mParticleSystem - > setVisibilityFlags ( RV_Effects ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
int rippleFrameCount = fallback - > getFallbackInt ( " Water_RippleFrameCount " ) ;
std : : string tex = fallback - > getFallbackString ( " Water_RippleTexture " ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
sh : : MaterialInstance * mat = sh : : Factory : : getInstance ( ) . getMaterialInstance ( " openmw/Ripple " ) ;
mat - > setProperty ( " anim_texture2 " , sh : : makeProperty ( new sh : : StringValue ( std : : string ( " textures \\ water \\ " ) + tex + " .dds "
+ Ogre : : StringConverter : : toString ( rippleFrameCount )
+ " "
+ Ogre : : StringConverter : : toString ( 0.3 ) ) ) ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
// seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better
mParticleSystem - > _update ( 0.f ) ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
mSceneNode = mSceneMgr - > getRootSceneNode ( ) - > createChildSceneNode ( ) ;
mSceneNode - > attachObject ( mParticleSystem ) ;
2013-02-01 22:43:23 +00:00
}
RippleSimulation : : ~ RippleSimulation ( )
{
2015-02-09 18:28:29 +00:00
if ( mParticleSystem )
mSceneMgr - > destroyParticleSystem ( mParticleSystem ) ;
mParticleSystem = NULL ;
2013-02-01 22:43:23 +00:00
2015-02-09 18:28:29 +00:00
if ( mSceneNode )
mSceneMgr - > destroySceneNode ( mSceneNode ) ;
mSceneNode = NULL ;
2013-02-01 22:43:23 +00:00
}
void RippleSimulation : : update ( float dt , Ogre : : Vector2 position )
{
2015-02-09 18:28:29 +00:00
bool newParticle = false ;
2013-02-27 08:20:42 +00:00
for ( std : : vector < Emitter > : : iterator it = mEmitters . begin ( ) ; it ! = mEmitters . end ( ) ; + + it )
2013-02-01 22:43:23 +00:00
{
2014-01-08 17:39:44 +00:00
if ( it - > mPtr = = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) )
2013-02-27 08:20:42 +00:00
{
// fetch a new ptr (to handle cell change etc)
// for non-player actors this is done in updateObjectCell
2014-01-08 17:39:44 +00:00
it - > mPtr = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2013-02-27 08:20:42 +00:00
}
2015-02-09 18:28:29 +00:00
Ogre : : Vector3 currentPos ( it - > mPtr . getRefData ( ) . getPosition ( ) . pos ) ;
currentPos . z = 0 ;
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 ( ) ,
Ogre : : Vector3 ( it - > mPtr . getRefData ( ) . getPosition ( ) . pos ) )
& & ! MWBase : : Environment : : get ( ) . getWorld ( ) - > isSubmerged ( it - > mPtr ) )
2013-02-27 08:20:42 +00:00
{
it - > mLastEmitPosition = currentPos ;
2015-02-09 18:28:29 +00:00
newParticle = true ;
Ogre : : Particle * created = mParticleSystem - > createParticle ( ) ;
if ( ! created )
break ; // TODO: cleanup the oldest particle to make room
# if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0)
Ogre : : Vector3 & position = created - > mPosition ;
Ogre : : Vector3 & direction = created - > mDirection ;
Ogre : : ColourValue & colour = created - > mColour ;
float & totalTimeToLive = created - > mTotalTimeToLive ;
float & timeToLive = created - > mTimeToLive ;
Ogre : : Radian & rotSpeed = created - > mRotationSpeed ;
Ogre : : Radian & rotation = created - > mRotation ;
# else
Ogre : : Vector3 & position = created - > position ;
Ogre : : Vector3 & direction = created - > direction ;
Ogre : : ColourValue & colour = created - > colour ;
float & totalTimeToLive = created - > totalTimeToLive ;
float & timeToLive = created - > timeToLive ;
Ogre : : Radian & rotSpeed = created - > rotationSpeed ;
Ogre : : Radian & rotation = created - > rotation ;
# endif
timeToLive = totalTimeToLive = mRippleLifeTime ;
2015-03-08 00:07:29 +00:00
colour = Ogre : : ColourValue ( 0.f , 0.f , 0.f , 0.7f ) ; // Water_RippleAlphas.x?
2015-02-09 18:28:29 +00:00
direction = Ogre : : Vector3 ( 0 , 0 , 0 ) ;
position = currentPos ;
position . z = 0 ; // Z is set by the Scene Node
rotSpeed = mRippleRotSpeed ;
rotation = Ogre : : Radian ( Ogre : : Math : : RangeRandom ( - Ogre : : Math : : PI , Ogre : : Math : : PI ) ) ;
2015-02-14 15:51:47 +00:00
created - > setDimensions ( mParticleSystem - > getDefaultWidth ( ) , mParticleSystem - > getDefaultHeight ( ) ) ;
2013-02-27 08:20:42 +00:00
}
2013-02-01 22:43:23 +00:00
}
2015-02-09 18:28:29 +00:00
if ( newParticle ) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better
mParticleSystem - > _update ( 0.f ) ;
2013-02-01 22:43:23 +00:00
}
2013-02-27 08:20:42 +00:00
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 ;
}
}
}
2015-02-09 18:28:29 +00:00
void RippleSimulation : : setWaterHeight ( float height )
{
mSceneNode - > setPosition ( 0 , 0 , height ) ;
}
void RippleSimulation : : clear ( )
{
mParticleSystem - > clear ( ) ;
}
2013-02-01 22:43:23 +00:00
}