2021-10-23 17:53:38 -07:00
# include "skyutil.hpp"
# include <cmath>
# include <osg/Transform>
# include <osg/Depth>
# include <osg/Geometry>
# include <osg/Material>
# include <osg/TexEnvCombine>
# include <osg/TexMat>
# include <osg/OcclusionQueryNode>
# include <osg/ColorMask>
# include <osg/BlendFunc>
# include <osg/AlphaFunc>
# include <osg/Version>
# include <osg/observer_ptr>
# include <osg/PositionAttitudeTransform>
# include <osgUtil/CullVisitor>
# include <osgParticle/Particle>
# include <components/misc/rng.hpp>
# include <components/resource/scenemanager.hpp>
# include <components/resource/imagemanager.hpp>
2021-11-21 02:25:05 +00:00
# include <components/sceneutil/depth.hpp>
2021-10-23 17:53:38 -07:00
# include <components/fallback/fallback.hpp>
# include <components/sceneutil/statesetupdater.hpp>
# include "../mwbase/environment.hpp"
# include "../mwbase/world.hpp"
# include "../mwworld/weather.hpp"
# include "vismask.hpp"
# include "renderbin.hpp"
namespace
{
enum class Pass
{
Atmosphere ,
Atmosphere_Night ,
Clouds ,
Moon ,
Sun ,
Sunflash_Query ,
Sunglare ,
} ;
osg : : ref_ptr < osg : : Geometry > createTexturedQuad ( int numUvSets = 1 , float scale = 1.f )
{
osg : : ref_ptr < osg : : Geometry > geom = new osg : : Geometry ;
osg : : ref_ptr < osg : : Vec3Array > verts = new osg : : Vec3Array ;
verts - > push_back ( osg : : Vec3f ( - 0.5 * scale , - 0.5 * scale , 0 ) ) ;
verts - > push_back ( osg : : Vec3f ( - 0.5 * scale , 0.5 * scale , 0 ) ) ;
verts - > push_back ( osg : : Vec3f ( 0.5 * scale , 0.5 * scale , 0 ) ) ;
verts - > push_back ( osg : : Vec3f ( 0.5 * scale , - 0.5 * scale , 0 ) ) ;
geom - > setVertexArray ( verts ) ;
osg : : ref_ptr < osg : : Vec2Array > texcoords = new osg : : Vec2Array ;
texcoords - > push_back ( osg : : Vec2f ( 0 , 1 ) ) ;
texcoords - > push_back ( osg : : Vec2f ( 0 , 0 ) ) ;
texcoords - > push_back ( osg : : Vec2f ( 1 , 0 ) ) ;
texcoords - > push_back ( osg : : Vec2f ( 1 , 1 ) ) ;
osg : : ref_ptr < osg : : Vec4Array > colors = new osg : : Vec4Array ;
colors - > push_back ( osg : : Vec4 ( 1.f , 1.f , 1.f , 1.f ) ) ;
geom - > setColorArray ( colors , osg : : Array : : BIND_OVERALL ) ;
for ( int i = 0 ; i < numUvSets ; + + i )
geom - > setTexCoordArray ( i , texcoords , osg : : Array : : BIND_PER_VERTEX ) ;
geom - > addPrimitiveSet ( new osg : : DrawArrays ( osg : : PrimitiveSet : : QUADS , 0 , 4 ) ) ;
return geom ;
}
struct DummyComputeBoundCallback : osg : : Node : : ComputeBoundingSphereCallback
{
osg : : BoundingSphere computeBound ( const osg : : Node & node ) const override
{
return osg : : BoundingSphere ( ) ;
}
} ;
}
namespace MWRender
{
2021-10-30 17:19:58 +00:00
osg : : ref_ptr < osg : : Material > createUnlitMaterial ( osg : : Material : : ColorMode colorMode )
2021-10-23 17:53:38 -07:00
{
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 ) ) ;
2021-10-30 17:19:58 +00:00
mat - > setColorMode ( colorMode ) ;
2021-10-23 17:53:38 -07:00
return mat ;
}
2021-10-30 17:19:58 +00:00
osg : : ref_ptr < osg : : Material > createAlphaTrackingUnlitMaterial ( )
2021-10-23 17:53:38 -07:00
{
2021-10-30 17:19:58 +00:00
return createUnlitMaterial ( osg : : Material : : DIFFUSE ) ;
2021-10-23 17:53:38 -07:00
}
class SunUpdater : public SceneUtil : : StateSetUpdater
{
public :
osg : : Vec4f mColor ;
SunUpdater ( )
: mColor ( 1.f , 1.f , 1.f , 1.f )
{ }
void setDefaults ( osg : : StateSet * stateset ) override
{
2021-10-30 17:19:58 +00:00
stateset - > setAttributeAndModes ( createUnlitMaterial ( ) ) ;
2021-10-23 17:53:38 -07:00
}
void apply ( osg : : StateSet * stateset , osg : : NodeVisitor * ) override
{
osg : : Material * mat = static_cast < osg : : Material * > ( stateset - > getAttribute ( osg : : StateAttribute : : MATERIAL ) ) ;
mat - > setDiffuse ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0 , 0 , 0 , mColor . a ( ) ) ) ;
mat - > setEmission ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( mColor . r ( ) , mColor . g ( ) , mColor . b ( ) , 1 ) ) ;
}
} ;
OcclusionCallback : : OcclusionCallback ( osg : : ref_ptr < osg : : OcclusionQueryNode > oqnVisible , osg : : ref_ptr < osg : : OcclusionQueryNode > oqnTotal )
: mOcclusionQueryVisiblePixels ( oqnVisible )
, mOcclusionQueryTotalPixels ( oqnTotal )
{ }
float OcclusionCallback : : getVisibleRatio ( osg : : Camera * camera )
{
int visible = mOcclusionQueryVisiblePixels - > getQueryGeometry ( ) - > getNumPixels ( camera ) ;
int total = mOcclusionQueryTotalPixels - > getQueryGeometry ( ) - > getNumPixels ( camera ) ;
float visibleRatio = 0.f ;
if ( total > 0 )
visibleRatio = static_cast < float > ( visible ) / static_cast < float > ( total ) ;
float dt = MWBase : : Environment : : get ( ) . getFrameDuration ( ) ;
float lastRatio = mLastRatio [ osg : : observer_ptr < osg : : Camera > ( camera ) ] ;
float change = dt * 10 ;
if ( visibleRatio > lastRatio )
visibleRatio = std : : min ( visibleRatio , lastRatio + change ) ;
else
visibleRatio = std : : max ( visibleRatio , lastRatio - change ) ;
mLastRatio [ osg : : observer_ptr < osg : : Camera > ( camera ) ] = visibleRatio ;
return visibleRatio ;
}
/// SunFlashCallback handles fading/scaling of a node depending on occlusion query result. Must be attached as a cull callback.
class SunFlashCallback : public OcclusionCallback , public SceneUtil : : NodeCallback < SunFlashCallback , osg : : Node * , osgUtil : : CullVisitor * >
{
public :
SunFlashCallback ( osg : : ref_ptr < osg : : OcclusionQueryNode > oqnVisible , osg : : ref_ptr < osg : : OcclusionQueryNode > oqnTotal )
: OcclusionCallback ( oqnVisible , oqnTotal )
, mGlareView ( 1.f )
{ }
void operator ( ) ( osg : : Node * node , osgUtil : : CullVisitor * cv )
{
float visibleRatio = getVisibleRatio ( cv - > getCurrentCamera ( ) ) ;
osg : : ref_ptr < osg : : StateSet > stateset ;
if ( visibleRatio > 0.f )
{
const float fadeThreshold = 0.1 ;
if ( visibleRatio < fadeThreshold )
{
float fade = 1.f - ( fadeThreshold - visibleRatio ) / fadeThreshold ;
2021-10-30 17:19:58 +00:00
osg : : ref_ptr < osg : : Material > mat ( createUnlitMaterial ( ) ) ;
2021-10-23 17:53:38 -07:00
mat - > setDiffuse ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0 , 0 , 0 , fade * mGlareView ) ) ;
stateset = new osg : : StateSet ;
stateset - > setAttributeAndModes ( mat , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
}
else if ( visibleRatio < 1.f )
{
const float threshold = 0.6 ;
visibleRatio = visibleRatio * ( 1.f - threshold ) + threshold ;
}
}
float scale = visibleRatio ;
if ( scale = = 0.f )
{
// no traverse
return ;
}
else if ( scale = = 1.f )
traverse ( node , cv ) ;
else
{
osg : : Matrix modelView = * cv - > getModelViewMatrix ( ) ;
modelView . preMultScale ( osg : : Vec3f ( scale , scale , scale ) ) ;
if ( stateset )
cv - > pushStateSet ( stateset ) ;
cv - > pushModelViewMatrix ( new osg : : RefMatrix ( modelView ) , osg : : Transform : : RELATIVE_RF ) ;
traverse ( node , cv ) ;
cv - > popModelViewMatrix ( ) ;
if ( stateset )
cv - > popStateSet ( ) ;
}
}
void setGlareView ( float value )
{
mGlareView = value ;
}
private :
float mGlareView ;
} ;
/// SunGlareCallback controls a full-screen glare effect depending on occlusion query result and the angle between sun and camera.
/// Must be attached as a cull callback to the node above the glare node.
class SunGlareCallback : public OcclusionCallback , public SceneUtil : : NodeCallback < SunGlareCallback , osg : : Node * , osgUtil : : CullVisitor * >
{
public :
SunGlareCallback ( osg : : ref_ptr < osg : : OcclusionQueryNode > oqnVisible , osg : : ref_ptr < osg : : OcclusionQueryNode > oqnTotal ,
osg : : ref_ptr < osg : : PositionAttitudeTransform > sunTransform )
: OcclusionCallback ( oqnVisible , oqnTotal )
, mSunTransform ( sunTransform )
, mTimeOfDayFade ( 1.f )
, mGlareView ( 1.f )
{
mColor = Fallback : : Map : : getColour ( " Weather_Sun_Glare_Fader_Color " ) ;
mSunGlareFaderMax = Fallback : : Map : : getFloat ( " Weather_Sun_Glare_Fader_Max " ) ;
mSunGlareFaderAngleMax = Fallback : : Map : : getFloat ( " Weather_Sun_Glare_Fader_Angle_Max " ) ;
// Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two,
// then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped,
// so the resulting color looks more orange than red.
mColor * = 2 ;
for ( int i = 0 ; i < 3 ; + + i )
mColor [ i ] = std : : min ( 1.f , mColor [ i ] ) ;
}
void operator ( ) ( osg : : Node * node , osgUtil : : CullVisitor * cv )
{
float angleRadians = getAngleToSunInRadians ( * cv - > getCurrentRenderStage ( ) - > getInitialViewMatrix ( ) ) ;
float visibleRatio = getVisibleRatio ( cv - > getCurrentCamera ( ) ) ;
const float angleMaxRadians = osg : : DegreesToRadians ( mSunGlareFaderAngleMax ) ;
float value = 1.f - std : : min ( 1.f , angleRadians / angleMaxRadians ) ;
float fade = value * mSunGlareFaderMax ;
fade * = mTimeOfDayFade * mGlareView * visibleRatio ;
if ( fade = = 0.f )
{
// no traverse
return ;
}
else
{
osg : : ref_ptr < osg : : StateSet > stateset = new osg : : StateSet ;
2021-10-30 17:19:58 +00:00
osg : : ref_ptr < osg : : Material > mat = createUnlitMaterial ( ) ;
2021-10-23 17:53:38 -07:00
mat - > setDiffuse ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0 , 0 , 0 , fade ) ) ;
mat - > setEmission ( osg : : Material : : FRONT_AND_BACK , mColor ) ;
2021-10-25 15:04:55 -07:00
stateset - > setAttributeAndModes ( mat ) ;
2021-10-23 17:53:38 -07:00
cv - > pushStateSet ( stateset ) ;
traverse ( node , cv ) ;
cv - > popStateSet ( ) ;
}
}
void setTimeOfDayFade ( float val )
{
mTimeOfDayFade = val ;
}
void setGlareView ( float glareView )
{
mGlareView = glareView ;
}
private :
float getAngleToSunInRadians ( const osg : : Matrix & viewMatrix ) const
{
osg : : Vec3d eye , center , up ;
viewMatrix . getLookAt ( eye , center , up ) ;
osg : : Vec3d forward = center - eye ;
osg : : Vec3d sun = mSunTransform - > getPosition ( ) ;
forward . normalize ( ) ;
sun . normalize ( ) ;
float angleRadians = std : : acos ( forward * sun ) ;
return angleRadians ;
}
osg : : ref_ptr < osg : : PositionAttitudeTransform > mSunTransform ;
float mTimeOfDayFade ;
float mGlareView ;
osg : : Vec4f mColor ;
float mSunGlareFaderMax ;
float mSunGlareFaderAngleMax ;
} ;
struct MoonUpdater : SceneUtil : : StateSetUpdater
{
Resource : : ImageManager & mImageManager ;
osg : : ref_ptr < osg : : Texture2D > mPhaseTex ;
osg : : ref_ptr < osg : : Texture2D > mCircleTex ;
float mTransparency ;
float mShadowBlend ;
osg : : Vec4f mAtmosphereColor ;
osg : : Vec4f mMoonColor ;
bool mForceShaders ;
MoonUpdater ( Resource : : ImageManager & imageManager , bool forceShaders )
: mImageManager ( imageManager )
, mPhaseTex ( )
, mCircleTex ( )
, mTransparency ( 1.0f )
, mShadowBlend ( 1.0f )
, mAtmosphereColor ( 1.0f , 1.0f , 1.0f , 1.0f )
, mMoonColor ( 1.0f , 1.0f , 1.0f , 1.0f )
, mForceShaders ( forceShaders )
{ }
void setDefaults ( osg : : StateSet * stateset ) override
{
if ( mForceShaders )
{
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Moon ) ) ) ;
stateset - > setTextureAttributeAndModes ( 0 , mPhaseTex ) ;
stateset - > setTextureAttributeAndModes ( 1 , mCircleTex ) ;
2021-10-23 17:53:38 -07:00
stateset - > setTextureMode ( 0 , GL_TEXTURE_2D , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
stateset - > setTextureMode ( 1 , GL_TEXTURE_2D , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
stateset - > addUniform ( new osg : : Uniform ( " moonBlend " , osg : : Vec4f { } ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " atmosphereFade " , osg : : Vec4f { } ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " diffuseMap " , 0 ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " maskMap " , 1 ) ) ;
2021-10-30 17:19:58 +00:00
stateset - > setAttributeAndModes ( createUnlitMaterial ( ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2021-10-23 17:53:38 -07:00
}
else
{
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 0 , mPhaseTex ) ;
2021-10-23 17:53:38 -07:00
osg : : ref_ptr < osg : : TexEnvCombine > texEnv = new osg : : TexEnvCombine ;
texEnv - > setCombine_RGB ( osg : : TexEnvCombine : : MODULATE ) ;
texEnv - > setSource0_RGB ( osg : : TexEnvCombine : : CONSTANT ) ;
texEnv - > setSource1_RGB ( osg : : TexEnvCombine : : TEXTURE ) ;
texEnv - > setConstantColor ( osg : : Vec4f ( 1.f , 0.f , 0.f , 1.f ) ) ; // mShadowBlend * mMoonColor
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 0 , texEnv ) ;
2021-10-23 17:53:38 -07:00
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 1 , mCircleTex ) ;
2021-10-23 17:53:38 -07:00
osg : : ref_ptr < osg : : TexEnvCombine > texEnv2 = new osg : : TexEnvCombine ;
texEnv2 - > setCombine_RGB ( osg : : TexEnvCombine : : ADD ) ;
texEnv2 - > setCombine_Alpha ( osg : : TexEnvCombine : : MODULATE ) ;
texEnv2 - > setSource0_Alpha ( osg : : TexEnvCombine : : TEXTURE ) ;
texEnv2 - > setSource1_Alpha ( osg : : TexEnvCombine : : CONSTANT ) ;
texEnv2 - > setSource0_RGB ( osg : : TexEnvCombine : : PREVIOUS ) ;
texEnv2 - > setSource1_RGB ( osg : : TexEnvCombine : : CONSTANT ) ;
texEnv2 - > setConstantColor ( osg : : Vec4f ( 0.f , 0.f , 0.f , 1.f ) ) ; // mAtmosphereColor.rgb, mTransparency
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 1 , texEnv2 ) ;
2021-10-30 17:19:58 +00:00
stateset - > setAttributeAndModes ( createUnlitMaterial ( ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2021-10-23 17:53:38 -07:00
}
}
void apply ( osg : : StateSet * stateset , osg : : NodeVisitor * ) override
{
if ( mForceShaders )
{
stateset - > setTextureAttribute ( 0 , mPhaseTex , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
stateset - > setTextureAttribute ( 1 , mCircleTex , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
if ( auto * uMoonBlend = stateset - > getUniform ( " moonBlend " ) )
uMoonBlend - > set ( mMoonColor * mShadowBlend ) ;
if ( auto * uAtmosphereFade = stateset - > getUniform ( " atmosphereFade " ) )
uAtmosphereFade - > set ( osg : : Vec4f ( mAtmosphereColor . x ( ) , mAtmosphereColor . y ( ) , mAtmosphereColor . z ( ) , mTransparency ) ) ;
}
else
{
osg : : TexEnvCombine * texEnv = static_cast < osg : : TexEnvCombine * > ( stateset - > getTextureAttribute ( 0 , osg : : StateAttribute : : TEXENV ) ) ;
texEnv - > setConstantColor ( mMoonColor * mShadowBlend ) ;
osg : : TexEnvCombine * texEnv2 = static_cast < osg : : TexEnvCombine * > ( stateset - > getTextureAttribute ( 1 , osg : : StateAttribute : : TEXENV ) ) ;
texEnv2 - > setConstantColor ( osg : : Vec4f ( mAtmosphereColor . x ( ) , mAtmosphereColor . y ( ) , mAtmosphereColor . z ( ) , mTransparency ) ) ;
}
}
void setTextures ( const std : : string & phaseTex , const std : : string & circleTex )
{
mPhaseTex = new osg : : Texture2D ( mImageManager . getImage ( phaseTex ) ) ;
mPhaseTex - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
mPhaseTex - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
mCircleTex = new osg : : Texture2D ( mImageManager . getImage ( circleTex ) ) ;
mCircleTex - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
mCircleTex - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
reset ( ) ;
}
} ;
class CameraRelativeTransformCullCallback : public SceneUtil : : NodeCallback < CameraRelativeTransformCullCallback , osg : : Node * , osgUtil : : CullVisitor * >
{
public :
void operator ( ) ( osg : : Node * node , osgUtil : : CullVisitor * cv )
{
// XXX have to remove unwanted culling plane of the water reflection camera
// Remove all planes that aren't from the standard frustum
unsigned int numPlanes = 4 ;
if ( cv - > getCullingMode ( ) & osg : : CullSettings : : NEAR_PLANE_CULLING )
+ + numPlanes ;
if ( cv - > getCullingMode ( ) & osg : : CullSettings : : FAR_PLANE_CULLING )
+ + numPlanes ;
unsigned int mask = 0x1 ;
unsigned int resultMask = cv - > getProjectionCullingStack ( ) . back ( ) . getFrustum ( ) . getResultMask ( ) ;
for ( unsigned int i = 0 ; i < cv - > getProjectionCullingStack ( ) . back ( ) . getFrustum ( ) . getPlaneList ( ) . size ( ) ; + + i )
{
if ( i > = numPlanes )
{
// turn off this culling plane
resultMask & = ( ~ mask ) ;
}
mask < < = 1 ;
}
cv - > getProjectionCullingStack ( ) . back ( ) . getFrustum ( ) . setResultMask ( resultMask ) ;
cv - > getCurrentCullingSet ( ) . getFrustum ( ) . setResultMask ( resultMask ) ;
cv - > getProjectionCullingStack ( ) . back ( ) . pushCurrentMask ( ) ;
cv - > getCurrentCullingSet ( ) . pushCurrentMask ( ) ;
traverse ( node , cv ) ;
cv - > getProjectionCullingStack ( ) . back ( ) . popCurrentMask ( ) ;
cv - > getCurrentCullingSet ( ) . popCurrentMask ( ) ;
}
} ;
void AtmosphereUpdater : : setEmissionColor ( const osg : : Vec4f & emissionColor )
{
mEmissionColor = emissionColor ;
}
void AtmosphereUpdater : : setDefaults ( osg : : StateSet * stateset )
{
stateset - > setAttributeAndModes ( createAlphaTrackingUnlitMaterial ( ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Atmosphere ) ) ) ;
2021-10-23 17:53:38 -07:00
}
void AtmosphereUpdater : : apply ( osg : : StateSet * stateset , osg : : NodeVisitor * /*nv*/ )
{
osg : : Material * mat = static_cast < osg : : Material * > ( stateset - > getAttribute ( osg : : StateAttribute : : MATERIAL ) ) ;
mat - > setEmission ( osg : : Material : : FRONT_AND_BACK , mEmissionColor ) ;
}
AtmosphereNightUpdater : : AtmosphereNightUpdater ( Resource : : ImageManager * imageManager , bool forceShaders )
: mColor ( osg : : Vec4f ( 0 , 0 , 0 , 0 ) )
, mTexture ( new osg : : Texture2D ( imageManager - > getWarningImage ( ) ) )
, mForceShaders ( forceShaders )
{ }
void AtmosphereNightUpdater : : setFade ( float fade )
{
mColor . a ( ) = fade ;
}
void AtmosphereNightUpdater : : setDefaults ( osg : : StateSet * stateset )
{
if ( mForceShaders )
{
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " opacity " , 0.f ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Atmosphere_Night ) ) ) ;
2021-10-23 17:53:38 -07:00
}
else
{
osg : : ref_ptr < osg : : TexEnvCombine > texEnv = new osg : : TexEnvCombine ;
texEnv - > setCombine_Alpha ( osg : : TexEnvCombine : : MODULATE ) ;
texEnv - > setSource0_Alpha ( osg : : TexEnvCombine : : PREVIOUS ) ;
texEnv - > setSource1_Alpha ( osg : : TexEnvCombine : : CONSTANT ) ;
texEnv - > setCombine_RGB ( osg : : TexEnvCombine : : REPLACE ) ;
texEnv - > setSource0_RGB ( osg : : TexEnvCombine : : PREVIOUS ) ;
stateset - > setTextureAttributeAndModes ( 1 , mTexture , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
stateset - > setTextureAttributeAndModes ( 1 , texEnv , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
}
}
void AtmosphereNightUpdater : : apply ( osg : : StateSet * stateset , osg : : NodeVisitor * /*nv*/ )
{
if ( mForceShaders )
{
stateset - > getUniform ( " opacity " ) - > set ( mColor . a ( ) ) ;
}
else
{
osg : : TexEnvCombine * texEnv = static_cast < osg : : TexEnvCombine * > ( stateset - > getTextureAttribute ( 1 , osg : : StateAttribute : : TEXENV ) ) ;
texEnv - > setConstantColor ( mColor ) ;
}
}
CloudUpdater : : CloudUpdater ( bool forceShaders )
: mOpacity ( 0.f )
, mForceShaders ( forceShaders )
{ }
void CloudUpdater : : setTexture ( osg : : ref_ptr < osg : : Texture2D > texture )
{
mTexture = texture ;
}
void CloudUpdater : : setEmissionColor ( const osg : : Vec4f & emissionColor )
{
mEmissionColor = emissionColor ;
}
void CloudUpdater : : setOpacity ( float opacity )
{
mOpacity = opacity ;
}
void CloudUpdater : : setTextureCoord ( float timer )
{
mTexMat = osg : : Matrixf : : translate ( osg : : Vec3f ( 0.f , - timer , 0.f ) ) ;
}
void CloudUpdater : : setDefaults ( osg : : StateSet * stateset )
{
stateset - > setAttribute ( createAlphaTrackingUnlitMaterial ( ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
osg : : ref_ptr < osg : : TexMat > texmat = new osg : : TexMat ;
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 0 , texmat ) ;
2021-10-23 17:53:38 -07:00
if ( mForceShaders )
{
stateset - > setTextureAttribute ( 0 , mTexture , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " opacity " , 1.f ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Clouds ) ) ) ;
2021-10-23 17:53:38 -07:00
}
else
{
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 1 , texmat ) ;
2021-10-23 17:53:38 -07:00
// need to set opacity on a separate texture unit, diffuse alpha is used by the vertex colors already
osg : : ref_ptr < osg : : TexEnvCombine > texEnvCombine = new osg : : TexEnvCombine ;
texEnvCombine - > setSource0_RGB ( osg : : TexEnvCombine : : PREVIOUS ) ;
texEnvCombine - > setSource0_Alpha ( osg : : TexEnvCombine : : PREVIOUS ) ;
texEnvCombine - > setSource1_Alpha ( osg : : TexEnvCombine : : CONSTANT ) ;
texEnvCombine - > setConstantColor ( osg : : Vec4f ( 1 , 1 , 1 , 1 ) ) ;
texEnvCombine - > setCombine_Alpha ( osg : : TexEnvCombine : : MODULATE ) ;
texEnvCombine - > setCombine_RGB ( osg : : TexEnvCombine : : REPLACE ) ;
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 1 , texEnvCombine ) ;
2021-10-23 17:53:38 -07:00
stateset - > setTextureMode ( 0 , GL_TEXTURE_2D , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
stateset - > setTextureMode ( 1 , GL_TEXTURE_2D , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
}
}
void CloudUpdater : : apply ( osg : : StateSet * stateset , osg : : NodeVisitor * nv )
{
stateset - > setTextureAttribute ( 0 , mTexture , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
osg : : Material * mat = static_cast < osg : : Material * > ( stateset - > getAttribute ( osg : : StateAttribute : : MATERIAL ) ) ;
mat - > setEmission ( osg : : Material : : FRONT_AND_BACK , mEmissionColor ) ;
osg : : TexMat * texMat = static_cast < osg : : TexMat * > ( stateset - > getTextureAttribute ( 0 , osg : : StateAttribute : : TEXMAT ) ) ;
texMat - > setMatrix ( mTexMat ) ;
if ( mForceShaders )
{
stateset - > getUniform ( " opacity " ) - > set ( mOpacity ) ;
}
else
{
stateset - > setTextureAttribute ( 1 , mTexture , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
osg : : TexEnvCombine * texEnv = static_cast < osg : : TexEnvCombine * > ( stateset - > getTextureAttribute ( 1 , osg : : StateAttribute : : TEXENV ) ) ;
texEnv - > setConstantColor ( osg : : Vec4f ( 1 , 1 , 1 , mOpacity ) ) ;
}
}
CameraRelativeTransform : : CameraRelativeTransform ( )
{
// Culling works in node-local space, not in camera space, so we can't cull this node correctly
// That's not a problem though, children of this node can be culled just fine
// Just make sure you do not place a CameraRelativeTransform deep in the scene graph
setCullingActive ( false ) ;
addCullCallback ( new CameraRelativeTransformCullCallback ) ;
}
CameraRelativeTransform : : CameraRelativeTransform ( const CameraRelativeTransform & copy , const osg : : CopyOp & copyop )
: osg : : Transform ( copy , copyop )
{ }
const osg : : Vec3f & CameraRelativeTransform : : getLastViewPoint ( ) const
{
return mViewPoint ;
}
bool CameraRelativeTransform : : computeLocalToWorldMatrix ( osg : : Matrix & matrix , osg : : NodeVisitor * nv ) const
{
if ( nv - > getVisitorType ( ) = = osg : : NodeVisitor : : CULL_VISITOR )
{
mViewPoint = static_cast < osgUtil : : CullVisitor * > ( nv ) - > getViewPoint ( ) ;
}
if ( _referenceFrame = = RELATIVE_RF )
{
matrix . setTrans ( osg : : Vec3f ( 0.f , 0.f , 0.f ) ) ;
return false ;
}
else // absolute
{
matrix . makeIdentity ( ) ;
return true ;
}
}
osg : : BoundingSphere CameraRelativeTransform : : computeBound ( ) const
{
return osg : : BoundingSphere ( ) ;
}
UnderwaterSwitchCallback : : UnderwaterSwitchCallback ( CameraRelativeTransform * cameraRelativeTransform )
: mCameraRelativeTransform ( cameraRelativeTransform )
, mEnabled ( true )
, mWaterLevel ( 0.f )
{ }
bool UnderwaterSwitchCallback : : isUnderwater ( )
{
osg : : Vec3f viewPoint = mCameraRelativeTransform - > getLastViewPoint ( ) ;
return mEnabled & & viewPoint . z ( ) < mWaterLevel ;
}
void UnderwaterSwitchCallback : : operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
{
if ( isUnderwater ( ) )
return ;
traverse ( node , nv ) ;
}
void UnderwaterSwitchCallback : : setEnabled ( bool enabled )
{
mEnabled = enabled ;
}
void UnderwaterSwitchCallback : : setWaterLevel ( float waterLevel )
{
mWaterLevel = waterLevel ;
}
const float CelestialBody : : mDistance = 1000.0f ;
CelestialBody : : CelestialBody ( osg : : Group * parentNode , float scaleFactor , int numUvSets , unsigned int visibleMask )
: mVisibleMask ( visibleMask )
{
mGeom = createTexturedQuad ( numUvSets ) ;
mGeom - > getOrCreateStateSet ( ) ;
mTransform = new osg : : PositionAttitudeTransform ;
mTransform - > setNodeMask ( mVisibleMask ) ;
mTransform - > setScale ( osg : : Vec3f ( 450 , 450 , 450 ) * scaleFactor ) ;
mTransform - > addChild ( mGeom ) ;
parentNode - > addChild ( mTransform ) ;
}
void CelestialBody : : setVisible ( bool visible )
{
mTransform - > setNodeMask ( visible ? mVisibleMask : 0 ) ;
}
2021-11-22 17:35:00 -08:00
Sun : : Sun ( osg : : Group * parentNode , Resource : : SceneManager & sceneManager )
2021-10-23 17:53:38 -07:00
: CelestialBody ( parentNode , 1.0f , 1 , Mask_Sun )
, mUpdater ( new SunUpdater )
{
mTransform - > addUpdateCallback ( mUpdater ) ;
2021-11-22 17:35:00 -08:00
Resource : : ImageManager & imageManager = * sceneManager . getImageManager ( ) ;
2021-10-23 17:53:38 -07:00
osg : : ref_ptr < osg : : Texture2D > sunTex = new osg : : Texture2D ( imageManager . getImage ( " textures/tx_sun_05.dds " ) ) ;
sunTex - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
sunTex - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
sunTex - > setName ( " diffuseMap " ) ;
2021-10-25 15:04:55 -07:00
mGeom - > getOrCreateStateSet ( ) - > setTextureAttributeAndModes ( 0 , sunTex ) ;
mGeom - > getOrCreateStateSet ( ) - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Sun ) ) ) ;
2021-10-23 17:53:38 -07:00
osg : : ref_ptr < osg : : Group > queryNode = new osg : : Group ;
// Need to render after the world geometry so we can correctly test for occlusions
osg : : StateSet * stateset = queryNode - > getOrCreateStateSet ( ) ;
stateset - > setRenderBinDetails ( RenderBin_OcclusionQuery , " RenderBin " ) ;
stateset - > setNestRenderBins ( false ) ;
// Set up alpha testing on the occlusion testing subgraph, that way we can get the occlusion tested fragments to match the circular shape of the sun
2021-11-22 17:35:00 -08:00
if ( ! sceneManager . getForceShaders ( ) )
{
osg : : ref_ptr < osg : : AlphaFunc > alphaFunc = new osg : : AlphaFunc ;
alphaFunc - > setFunction ( osg : : AlphaFunc : : GREATER , 0.8 ) ;
stateset - > setAttributeAndModes ( alphaFunc ) ;
}
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 0 , sunTex ) ;
stateset - > setAttributeAndModes ( createUnlitMaterial ( ) ) ;
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Sunflash_Query ) ) ) ;
2021-10-23 17:53:38 -07:00
// Disable writing to the color buffer. We are using this geometry for visibility tests only.
osg : : ref_ptr < osg : : ColorMask > colormask = new osg : : ColorMask ( 0 , 0 , 0 , 0 ) ;
2021-10-25 15:04:55 -07:00
stateset - > setAttributeAndModes ( colormask ) ;
2021-10-23 17:53:38 -07:00
mTransform - > addChild ( queryNode ) ;
mOcclusionQueryVisiblePixels = createOcclusionQueryNode ( queryNode , true ) ;
mOcclusionQueryTotalPixels = createOcclusionQueryNode ( queryNode , false ) ;
createSunFlash ( imageManager ) ;
createSunGlare ( ) ;
}
Sun : : ~ Sun ( )
{
mTransform - > removeUpdateCallback ( mUpdater ) ;
destroySunFlash ( ) ;
destroySunGlare ( ) ;
}
void Sun : : setColor ( const osg : : Vec4f & color )
{
mUpdater - > mColor . r ( ) = color . r ( ) ;
mUpdater - > mColor . g ( ) = color . g ( ) ;
mUpdater - > mColor . b ( ) = color . b ( ) ;
}
void Sun : : adjustTransparency ( const float ratio )
{
mUpdater - > mColor . a ( ) = ratio ;
if ( mSunGlareCallback )
mSunGlareCallback - > setGlareView ( ratio ) ;
if ( mSunFlashCallback )
mSunFlashCallback - > setGlareView ( ratio ) ;
}
void Sun : : setDirection ( const osg : : Vec3f & direction )
{
osg : : Vec3f normalizedDirection = direction / direction . length ( ) ;
mTransform - > setPosition ( normalizedDirection * mDistance ) ;
osg : : Quat quat ;
quat . makeRotate ( osg : : Vec3f ( 0.0f , 0.0f , 1.0f ) , normalizedDirection ) ;
mTransform - > setAttitude ( quat ) ;
}
void Sun : : setGlareTimeOfDayFade ( float val )
{
if ( mSunGlareCallback )
mSunGlareCallback - > setTimeOfDayFade ( val ) ;
}
osg : : ref_ptr < osg : : OcclusionQueryNode > Sun : : createOcclusionQueryNode ( osg : : Group * parent , bool queryVisible )
{
osg : : ref_ptr < osg : : OcclusionQueryNode > oqn = new osg : : OcclusionQueryNode ;
oqn - > setQueriesEnabled ( true ) ;
# if OSG_VERSION_GREATER_OR_EQUAL(3, 6, 5)
// With OSG 3.6.5, the method of providing user defined query geometry has been completely replaced
osg : : ref_ptr < osg : : QueryGeometry > queryGeom = new osg : : QueryGeometry ( oqn - > getName ( ) ) ;
# else
osg : : ref_ptr < osg : : QueryGeometry > queryGeom = oqn - > getQueryGeometry ( ) ;
# endif
// Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry,
// so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry
// is only called once.
// Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal.
queryGeom - > setDataVariance ( osg : : Object : : STATIC ) ;
// Set up the query geometry to match the actual sun's rendering shape. osg::OcclusionQueryNode wasn't originally intended to allow this,
// normally it would automatically adjust the query geometry to match the sub graph's bounding box. The below hack is needed to
// circumvent this.
queryGeom - > setVertexArray ( mGeom - > getVertexArray ( ) ) ;
queryGeom - > setTexCoordArray ( 0 , mGeom - > getTexCoordArray ( 0 ) , osg : : Array : : BIND_PER_VERTEX ) ;
queryGeom - > removePrimitiveSet ( 0 , queryGeom - > getNumPrimitiveSets ( ) ) ;
queryGeom - > addPrimitiveSet ( mGeom - > getPrimitiveSet ( 0 ) ) ;
// Hack to disable unwanted awful code inside OcclusionQueryNode::computeBound.
oqn - > setComputeBoundingSphereCallback ( new DummyComputeBoundCallback ) ;
// Still need a proper bounding sphere.
oqn - > setInitialBound ( queryGeom - > getBound ( ) ) ;
# if OSG_VERSION_GREATER_OR_EQUAL(3, 6, 5)
oqn - > setQueryGeometry ( queryGeom . release ( ) ) ;
# endif
osg : : StateSet * queryStateSet = new osg : : StateSet ;
if ( queryVisible )
{
2022-01-04 12:23:37 -08:00
osg : : ref_ptr < osg : : Depth > depth = new SceneUtil : : AutoDepth ( osg : : Depth : : LEQUAL ) ;
2021-10-23 17:53:38 -07:00
// This is a trick to make fragments written by the query always use the maximum depth value,
// without having to retrieve the current far clipping distance.
// We want the sun glare to be "infinitely" far away.
2021-11-21 02:25:05 +00:00
double far = SceneUtil : : AutoDepth : : isReversed ( ) ? 0.0 : 1.0 ;
2021-11-22 17:35:00 -08:00
depth - > setFunction ( osg : : Depth : : LEQUAL ) ;
2021-10-23 17:53:38 -07:00
depth - > setZNear ( far ) ;
depth - > setZFar ( far ) ;
depth - > setWriteMask ( false ) ;
2021-10-25 15:04:55 -07:00
queryStateSet - > setAttributeAndModes ( depth ) ;
2021-10-23 17:53:38 -07:00
}
else
{
queryStateSet - > setMode ( GL_DEPTH_TEST , osg : : StateAttribute : : OFF ) ;
}
oqn - > setQueryStateSet ( queryStateSet ) ;
parent - > addChild ( oqn ) ;
return oqn ;
}
void Sun : : createSunFlash ( Resource : : ImageManager & imageManager )
{
osg : : ref_ptr < osg : : Texture2D > tex = new osg : : Texture2D ( imageManager . getImage ( " textures/tx_sun_flash_grey_05.dds " ) ) ;
tex - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
tex - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
tex - > setName ( " diffuseMap " ) ;
osg : : ref_ptr < osg : : Group > group ( new osg : : Group ) ;
mTransform - > addChild ( group ) ;
const float scale = 2.6f ;
osg : : ref_ptr < osg : : Geometry > geom = createTexturedQuad ( 1 , scale ) ;
group - > addChild ( geom ) ;
osg : : StateSet * stateset = geom - > getOrCreateStateSet ( ) ;
2021-10-25 15:04:55 -07:00
stateset - > setTextureAttributeAndModes ( 0 , tex ) ;
2021-10-23 17:53:38 -07:00
stateset - > setMode ( GL_DEPTH_TEST , osg : : StateAttribute : : OFF ) ;
stateset - > setRenderBinDetails ( RenderBin_SunGlare , " RenderBin " ) ;
stateset - > setNestRenderBins ( false ) ;
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Sun ) ) ) ;
2021-10-23 17:53:38 -07:00
mSunFlashNode = group ;
mSunFlashCallback = new SunFlashCallback ( mOcclusionQueryVisiblePixels , mOcclusionQueryTotalPixels ) ;
mSunFlashNode - > addCullCallback ( mSunFlashCallback ) ;
}
void Sun : : destroySunFlash ( )
{
if ( mSunFlashNode )
{
mSunFlashNode - > removeCullCallback ( mSunFlashCallback ) ;
mSunFlashCallback = nullptr ;
}
}
void Sun : : createSunGlare ( )
{
osg : : ref_ptr < osg : : Camera > camera = new osg : : Camera ;
camera - > setProjectionMatrix ( osg : : Matrix : : identity ( ) ) ;
camera - > setReferenceFrame ( osg : : Transform : : ABSOLUTE_RF ) ; // add to skyRoot instead?
camera - > setViewMatrix ( osg : : Matrix : : identity ( ) ) ;
camera - > setClearMask ( 0 ) ;
camera - > setRenderOrder ( osg : : Camera : : NESTED_RENDER ) ;
camera - > setAllowEventFocus ( false ) ;
2021-11-22 17:35:00 -08:00
camera - > getOrCreateStateSet ( ) - > addUniform ( new osg : : Uniform ( " projectionMatrix " , static_cast < osg : : Matrixf > ( camera - > getProjectionMatrix ( ) ) ) ) ;
SceneUtil : : setCameraClearDepth ( camera ) ;
2021-10-23 17:53:38 -07:00
osg : : ref_ptr < osg : : Geometry > geom = osg : : createTexturedQuadGeometry ( osg : : Vec3f ( - 1 , - 1 , 0 ) , osg : : Vec3f ( 2 , 0 , 0 ) , osg : : Vec3f ( 0 , 2 , 0 ) ) ;
camera - > addChild ( geom ) ;
osg : : StateSet * stateset = geom - > getOrCreateStateSet ( ) ;
stateset - > setRenderBinDetails ( RenderBin_SunGlare , " RenderBin " ) ;
stateset - > setNestRenderBins ( false ) ;
stateset - > setMode ( GL_DEPTH_TEST , osg : : StateAttribute : : OFF ) ;
2021-10-25 15:04:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " pass " , static_cast < int > ( Pass : : Sunglare ) ) ) ;
2021-10-23 17:53:38 -07:00
// set up additive blending
osg : : ref_ptr < osg : : BlendFunc > blendFunc = new osg : : BlendFunc ;
blendFunc - > setSource ( osg : : BlendFunc : : SRC_ALPHA ) ;
blendFunc - > setDestination ( osg : : BlendFunc : : ONE ) ;
2021-10-25 15:04:55 -07:00
stateset - > setAttributeAndModes ( blendFunc ) ;
2021-10-23 17:53:38 -07:00
mSunGlareCallback = new SunGlareCallback ( mOcclusionQueryVisiblePixels , mOcclusionQueryTotalPixels , mTransform ) ;
mSunGlareNode = camera ;
mSunGlareNode - > addCullCallback ( mSunGlareCallback ) ;
mTransform - > addChild ( camera ) ;
}
void Sun : : destroySunGlare ( )
{
if ( mSunGlareNode )
{
mSunGlareNode - > removeCullCallback ( mSunGlareCallback ) ;
mSunGlareCallback = nullptr ;
}
}
Moon : : Moon ( osg : : Group * parentNode , Resource : : SceneManager & sceneManager , float scaleFactor , Type type )
: CelestialBody ( parentNode , scaleFactor , 2 )
, mType ( type )
, mPhase ( MoonState : : Phase : : Unspecified )
, mUpdater ( new MoonUpdater ( * sceneManager . getImageManager ( ) , sceneManager . getForceShaders ( ) ) )
{
setPhase ( MoonState : : Phase : : Full ) ;
setVisible ( true ) ;
mGeom - > addUpdateCallback ( mUpdater ) ;
}
Moon : : ~ Moon ( )
{
mGeom - > removeUpdateCallback ( mUpdater ) ;
}
void Moon : : adjustTransparency ( const float ratio )
{
mUpdater - > mTransparency * = ratio ;
}
void Moon : : setState ( const MoonState state )
{
float radsX = ( ( state . mRotationFromHorizon ) * static_cast < float > ( osg : : PI ) ) / 180.0f ;
float radsZ = ( ( state . mRotationFromNorth ) * static_cast < float > ( osg : : PI ) ) / 180.0f ;
osg : : Quat rotX ( radsX , osg : : Vec3f ( 1.0f , 0.0f , 0.0f ) ) ;
osg : : Quat rotZ ( radsZ , osg : : Vec3f ( 0.0f , 0.0f , 1.0f ) ) ;
osg : : Vec3f direction = rotX * rotZ * osg : : Vec3f ( 0.0f , 1.0f , 0.0f ) ;
mTransform - > setPosition ( direction * mDistance ) ;
// The moon quad is initially oriented facing down, so we need to offset its X-axis
// rotation to rotate it to face the camera when sitting at the horizon.
osg : : Quat attX ( ( - static_cast < float > ( osg : : PI ) / 2.0f ) + radsX , osg : : Vec3f ( 1.0f , 0.0f , 0.0f ) ) ;
mTransform - > setAttitude ( attX * rotZ ) ;
setPhase ( state . mPhase ) ;
mUpdater - > mTransparency = state . mMoonAlpha ;
mUpdater - > mShadowBlend = state . mShadowBlend ;
}
void Moon : : setAtmosphereColor ( const osg : : Vec4f & color )
{
mUpdater - > mAtmosphereColor = color ;
}
void Moon : : setColor ( const osg : : Vec4f & color )
{
mUpdater - > mMoonColor = color ;
}
unsigned int Moon : : getPhaseInt ( ) const
{
switch ( mPhase )
{
case MoonState : : Phase : : New :
return 0 ;
case MoonState : : Phase : : WaxingCrescent :
return 1 ;
case MoonState : : Phase : : WaningCrescent :
return 1 ;
case MoonState : : Phase : : FirstQuarter :
return 2 ;
case MoonState : : Phase : : ThirdQuarter :
return 2 ;
case MoonState : : Phase : : WaxingGibbous :
return 3 ;
case MoonState : : Phase : : WaningGibbous :
return 3 ;
case MoonState : : Phase : : Full :
return 4 ;
default :
return 0 ;
}
}
void Moon : : setPhase ( const MoonState : : Phase & phase )
{
if ( mPhase = = phase )
return ;
mPhase = phase ;
std : : string textureName = " textures/tx_ " ;
if ( mType = = Moon : : Type_Secunda )
textureName + = " secunda_ " ;
else
textureName + = " masser_ " ;
switch ( mPhase )
{
case MoonState : : Phase : : New :
textureName + = " new " ;
break ;
case MoonState : : Phase : : WaxingCrescent :
textureName + = " one_wax " ;
break ;
case MoonState : : Phase : : FirstQuarter :
textureName + = " half_wax " ;
break ;
case MoonState : : Phase : : WaxingGibbous :
textureName + = " three_wax " ;
break ;
case MoonState : : Phase : : WaningCrescent :
textureName + = " one_wan " ;
break ;
case MoonState : : Phase : : ThirdQuarter :
textureName + = " half_wan " ;
break ;
case MoonState : : Phase : : WaningGibbous :
textureName + = " three_wan " ;
break ;
case MoonState : : Phase : : Full :
textureName + = " full " ;
break ;
default :
break ;
}
textureName + = " .dds " ;
if ( mType = = Moon : : Type_Secunda )
mUpdater - > setTextures ( textureName , " textures/tx_mooncircle_full_s.dds " ) ;
else
mUpdater - > setTextures ( textureName , " textures/tx_mooncircle_full_m.dds " ) ;
}
int RainCounter : : numParticlesToCreate ( double dt ) const
{
// limit dt to avoid large particle emissions if there are jumps in the simulation time
// 0.2 seconds is the same cap as used in Engine's frame loop
dt = std : : min ( dt , 0.2 ) ;
return ConstantRateCounter : : numParticlesToCreate ( dt ) ;
}
RainShooter : : RainShooter ( )
: mAngle ( 0.f )
{ }
void RainShooter : : shoot ( osgParticle : : Particle * particle ) const
{
particle - > setVelocity ( mVelocity ) ;
particle - > setAngle ( osg : : Vec3f ( - mAngle , 0 , ( Misc : : Rng : : rollProbability ( ) * 2 - 1 ) * osg : : PI ) ) ;
}
void RainShooter : : setVelocity ( const osg : : Vec3f & velocity )
{
mVelocity = velocity ;
}
void RainShooter : : setAngle ( float angle )
{
mAngle = angle ;
}
osg : : Object * RainShooter : : cloneType ( ) const
{
return new RainShooter ;
}
osg : : Object * RainShooter : : clone ( const osg : : CopyOp & ) const
{
return new RainShooter ( * this ) ;
}
ModVertexAlphaVisitor : : ModVertexAlphaVisitor ( ModVertexAlphaVisitor : : MeshType type )
: osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN )
, mType ( type )
{ }
void ModVertexAlphaVisitor : : apply ( osg : : Geometry & geometry )
{
osg : : ref_ptr < osg : : Vec4Array > colors = new osg : : Vec4Array ( geometry . getVertexArray ( ) - > getNumElements ( ) ) ;
for ( unsigned int i = 0 ; i < colors - > size ( ) ; + + i )
{
float alpha = 1.f ;
switch ( mType )
{
case ModVertexAlphaVisitor : : Atmosphere :
{
// this is a cylinder, so every second vertex belongs to the bottom-most row
alpha = ( i % 2 ) ? 0.f : 1.f ;
break ;
}
case ModVertexAlphaVisitor : : Clouds :
{
if ( i > = 49 & & i < = 64 )
alpha = 0.f ; // bottom-most row
else if ( i > = 33 & & i < = 48 )
alpha = 0.25098 ; // second row
else
alpha = 1.f ;
break ;
}
case ModVertexAlphaVisitor : : Stars :
{
if ( geometry . getColorArray ( ) )
{
osg : : Vec4Array * origColors = static_cast < osg : : Vec4Array * > ( geometry . getColorArray ( ) ) ;
alpha = ( ( * origColors ) [ i ] . x ( ) = = 1.f ) ? 1.f : 0.f ;
}
else
alpha = 1.f ;
break ;
}
}
( * colors ) [ i ] = osg : : Vec4f ( 0.f , 0.f , 0.f , alpha ) ;
}
geometry . setColorArray ( colors , osg : : Array : : BIND_PER_VERTEX ) ;
}
}