// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "std3d.h"
# include "nel/3d/cloud_scape.h"
# include "nel/3d/driver.h"
# include "nel/3d/scissor.h"
# include "nel/3d/viewport.h"
// ------------------------------------------------------------------------------------------------
using namespace NLMISC ;
namespace NL3D
{
// ------------------------------------------------------------------------------------------------
# define SQR(x) (x)*(x)
# define MAX_DIST 400.0f
# define MAX_CLOUDS 256
// QUEUE_SIZE must be at least 2*MAX_CLOUDS
# define QUEUE_SIZE 512
static const double MAX_CLOUDS_ANIM_DELTA_TIME = 0.075 ; // maximum delta time handled by cloud animation, delta t above that are clamped
static const double MIN_CLOUDS_ANIM_DELTA_TIME = 0.005 ; // minimum delta time handled by clouds animation
static const double MAX_TIME_FOR_CLOUD_ANIM = 0.02 ; // max number of second spent for cloud render before we check if too slow
static const double MAX_FRAME_PERCENT_FOR_CLOUD_RENDERING = 20 / 100 ; // at most 20 % of the frame for cloud render
// ------------------------------------------------------------------------------------------------
// SCloudTexture3D
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
SCloudTexture3D : : SCloudTexture3D ( )
{
Mem = NULL ;
Mem2 = NULL ;
MemBuffer = NULL ;
ToLightRGB . initUnlit ( ) ;
ToLightRGB . setShader ( CMaterial : : Normal ) ;
ToLightRGB . setZFunc ( CMaterial : : always ) ;
ToLightRGB . setZWrite ( false ) ;
ToLightRGB . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
ToLightRGB . texEnvArg0RGB ( 0 , CMaterial : : Diffuse , CMaterial : : SrcColor ) ;
ToLightRGB . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
ToLightRGB . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
ToLightRGB . setBlend ( true ) ;
ToLightRGB . setBlendFunc ( CMaterial : : invsrcalpha , CMaterial : : srcalpha ) ;
ToLightRGB . setColor ( CRGBA ( 0 , 0 , 0 , 255 ) ) ;
ToLightAlpha . initUnlit ( ) ;
ToLightAlpha . setShader ( CMaterial : : Normal ) ;
ToLightAlpha . setZFunc ( CMaterial : : always ) ;
ToLightAlpha . setZWrite ( false ) ;
ToLightAlpha . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
ToLightAlpha . texEnvArg0RGB ( 0 , CMaterial : : Diffuse , CMaterial : : SrcColor ) ;
ToLightAlpha . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
ToLightAlpha . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : InvSrcAlpha ) ;
ToLightAlpha . setColor ( CRGBA ( 0 , 0 , 0 , 255 ) ) ;
ToBill . initUnlit ( ) ;
ToBill . setZFunc ( CMaterial : : always ) ;
ToBill . setZWrite ( false ) ;
ToBill . setDoubleSided ( true ) ;
ToBill . texEnvOpRGB ( 0 , CMaterial : : Add ) ;
ToBill . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
ToBill . texEnvArg1RGB ( 0 , CMaterial : : Diffuse , CMaterial : : SrcColor ) ;
ToBill . setColor ( CRGBA ( 80 , 80 , 80 , 255 ) ) ;
ToBill . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
ToBill . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
ToBill . texEnvOpRGB ( 1 , CMaterial : : Modulate ) ;
ToBill . texEnvArg0RGB ( 1 , CMaterial : : Previous , CMaterial : : SrcColor ) ;
ToBill . texEnvArg1RGB ( 1 , CMaterial : : Previous , CMaterial : : SrcAlpha ) ;
ToBill . texEnvOpAlpha ( 1 , CMaterial : : Replace ) ;
ToBill . texEnvArg0Alpha ( 1 , CMaterial : : Previous , CMaterial : : SrcAlpha ) ;
ToBill . setBlendFunc ( CMaterial : : one , CMaterial : : invsrcalpha ) ;
ToBill . setBlend ( true ) ;
MatCopy . initUnlit ( ) ;
MatCopy . setShader ( CMaterial : : Normal ) ;
MatCopy . setZFunc ( CMaterial : : always ) ;
MatCopy . setZWrite ( false ) ;
MatCopy . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
MatCopy . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
MatCopy . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
MatCopy . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
MatCopy . setBlend ( false ) ;
MatCopy . setColor ( CRGBA ( 255 , 255 , 255 , 255 ) ) ;
}
// ------------------------------------------------------------------------------------------------
void SCloudTexture3D : : init ( uint32 nWidth , uint32 nHeight , uint32 nDepth )
{
if ( Mem ! = NULL )
return ;
Width = raiseToNextPowerOf2 ( nWidth ) ;
Height = raiseToNextPowerOf2 ( nHeight ) ;
Depth = raiseToNextPowerOf2 ( nDepth ) ;
uint32 vdpo2 = getPowerOf2 ( Depth ) ;
NbW = 1 < < ( vdpo2 / 2 ) ;
if ( ( vdpo2 & 1 ) ! = 0 )
NbH = 2 < < ( vdpo2 / 2 ) ;
else
NbH = 1 < < ( vdpo2 / 2 ) ;
Mem = new uint8 [ 4 * NbW * Width * NbH * Height ] ;
Mem2 = new uint8 [ 4 * NbW * Width * NbH * Height ] ;
MemBuffer = new uint8 [ 4 * Width * Height ] ;
Tex = new CTextureMem ( Mem , 4 * NbW * Width * NbH * Height , true , false , NbW * Width , NbH * Height , CBitmap : : RGBA ) ;
Tex2 = new CTextureMem ( Mem2 , 4 * NbW * Width * NbH * Height , true , false , NbW * Width , NbH * Height , CBitmap : : RGBA ) ;
TexBuffer = new CTextureMem ( MemBuffer , 4 * Width * Height , true , false , Width , Height , CBitmap : : RGBA ) ;
Tex - > setWrapS ( ITexture : : Clamp ) ;
Tex - > setWrapT ( ITexture : : Clamp ) ;
Tex - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
Tex - > setReleasable ( false ) ;
Tex - > setRenderTarget ( true ) ;
Tex - > generate ( ) ;
Tex2 - > setWrapS ( ITexture : : Clamp ) ;
Tex2 - > setWrapT ( ITexture : : Clamp ) ;
Tex2 - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
Tex2 - > setReleasable ( false ) ;
Tex2 - > setRenderTarget ( true ) ;
Tex2 - > generate ( ) ;
TexBuffer - > setWrapS ( ITexture : : Clamp ) ;
TexBuffer - > setWrapT ( ITexture : : Clamp ) ;
TexBuffer - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
TexBuffer - > setReleasable ( false ) ;
TexBuffer - > setRenderTarget ( true ) ;
TexBuffer - > generate ( ) ;
ToLightRGB . setTexture ( 0 , Tex ) ;
ToLightAlpha . setTexture ( 0 , Tex ) ;
ToBill . setTexture ( 0 , Tex2 ) ;
ToBill . setTexture ( 1 , Tex2 ) ;
MatCopy . setTexture ( 0 , TexBuffer ) ;
}
// ------------------------------------------------------------------------------------------------
// SCloudTextureClamp
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
SCloudTextureClamp : : SCloudTextureClamp ( )
{
Mem = NULL ;
ToClamp . initUnlit ( ) ;
ToClamp . setShader ( CMaterial : : Normal ) ;
ToClamp . texEnvOpAlpha ( 0 , CMaterial : : Add ) ;
ToClamp . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
ToClamp . texEnvArg1Alpha ( 0 , CMaterial : : Diffuse , CMaterial : : SrcAlpha ) ;
ToClamp . setColor ( CRGBA ( 255 , 255 , 255 , 255 ) ) ;
ToClamp . setBlend ( true ) ;
ToClamp . setBlendFunc ( CMaterial : : one , CMaterial : : one ) ;
ToClamp . setZFunc ( CMaterial : : always ) ;
ToClamp . setZWrite ( false ) ;
}
// ------------------------------------------------------------------------------------------------
void SCloudTextureClamp : : init ( uint32 nWidth , uint32 nHeight , uint32 nDepth , const std : : string & filename )
{
if ( Mem ! = NULL )
return ;
Width = raiseToNextPowerOf2 ( nWidth ) ;
Height = raiseToNextPowerOf2 ( nHeight ) ;
Depth = raiseToNextPowerOf2 ( nDepth ) ;
uint32 vdpo2 = getPowerOf2 ( Depth ) ;
NbW = 1 < < ( vdpo2 / 2 ) ;
if ( ( vdpo2 & 1 ) ! = 0 )
NbH = 2 < < ( vdpo2 / 2 ) ;
else
NbH = 1 < < ( vdpo2 / 2 ) ;
Mem = new uint8 [ NbW * Width * NbH * Height ] ;
uint32 i , j ;
if ( filename . empty ( ) )
{
// No filename so init with default
for ( i = 0 ; i < NbW ; + + i )
{
for ( j = 0 ; j < NbH ; + + j )
{
uint32 d = i + j * NbW ;
uint32 k , l ;
for ( k = 0 ; k < Width ; + + k )
for ( l = 0 ; l < Height ; + + l )
{
float x = k + 0.5f ;
float y = l + 0.5f ;
float z = d + 0.5f ;
float xc = Width / 2.0f ;
float yc = Height / 2.0f ;
float zc = Depth / 2.0f ;
float r = ( x - xc ) * ( x - xc ) / ( Width * Width / 4.0f ) + ( y - yc ) * ( y - yc ) / ( Height * Height / 4.0f )
+ ( z - zc ) * ( z - zc ) / ( Depth * Depth / 4.0f ) ;
uint8 col = 255 ;
if ( r < 1.0f )
{
col = ( uint8 ) ( ( r ) * 223 + 32 ) ;
}
Mem [ i * Width + k + ( j * Height + l ) * NbW * Width ] = col ;
}
}
}
}
else
{
// Load file TODO !
}
Tex = new CTextureMem ( Mem , NbW * Width * NbH * Height , true , false , NbW * Width , NbH * Height , CBitmap : : Alpha ) ;
Tex - > setWrapS ( ITexture : : Repeat ) ;
Tex - > setWrapT ( ITexture : : Repeat ) ;
Tex - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
Tex - > touch ( ) ;
Tex - > setReleasable ( false ) ;
Tex - > generate ( ) ;
ToClamp . setTexture ( 0 , Tex ) ;
}
// ------------------------------------------------------------------------------------------------
// CCloudScape
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
CCloudScape : : CCloudScape ( NL3D : : IDriver * pDriver ) : _Noise3D ( pDriver )
{
_Driver = pDriver ;
// Misc purpose VB
_VertexBuffer . setVertexFormat ( CVertexBuffer : : PositionFlag | CVertexBuffer : : TexCoord0Flag | CVertexBuffer : : TexCoord1Flag ) ;
_VertexBuffer . setNumVertices ( 4 ) ;
_VertexBuffer . setName ( " CloudScape " ) ;
// Material used for cleaning
_MatClear . initUnlit ( ) ;
_MatClear . setDoubleSided ( true ) ;
_MatClear . setZFunc ( CMaterial : : always ) ;
_MatClear . setZWrite ( false ) ;
_MatClear . setBlend ( false ) ;
_MatBill . initUnlit ( ) ;
_MatBill . setShader ( CMaterial : : Normal ) ; // not needed
_MatBill . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
_MatBill . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_MatBill . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
_MatBill . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
_MatBill . texEnvOpRGB ( 1 , CMaterial : : InterpolateDiffuse ) ;
_MatBill . texEnvArg0RGB ( 1 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_MatBill . texEnvArg1RGB ( 1 , CMaterial : : Previous , CMaterial : : SrcColor ) ;
_MatBill . texEnvOpAlpha ( 1 , CMaterial : : InterpolateDiffuse ) ;
_MatBill . texEnvArg0Alpha ( 1 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
_MatBill . texEnvArg1Alpha ( 1 , CMaterial : : Previous , CMaterial : : SrcAlpha ) ;
_MatBill . setBlend ( true ) ;
_MatBill . setBlendFunc ( CMaterial : : one , CMaterial : : invsrcalpha ) ;
_MatBill . setZFunc ( CMaterial : : always ) ;
_MatBill . setZWrite ( false ) ;
_MatBill . setDoubleSided ( true ) ;
_MatBill . setAlphaTest ( true ) ;
_MatBill . setAlphaTestThreshold ( 2.0f / 256.0f ) ;
_LODQualityThreshold = 160.0f ;
_IsIncomingCSS = false ;
_DebugQuad = false ;
_NbHalfCloudToUpdate = 1 ;
_CurrentCloudInProcess = NULL ;
_LastAnimRenderTime = 0 ;
_MaxDeltaTime = 0.1 ; // 100 ms
}
// ------------------------------------------------------------------------------------------------
CCloudScape : : ~ CCloudScape ( )
{
}
// ------------------------------------------------------------------------------------------------
void CCloudScape : : init ( SCloudScapeSetup * pCSS , NL3D : : CCamera * pCamera )
{
_ResetCounter = _Driver - > getResetCounter ( ) ;
_ViewerCam = pCamera ;
_Noise3D . init ( ) ;
_AllClouds . resize ( MAX_CLOUDS , CCloud ( this ) ) ;
_CloudPower . resize ( MAX_CLOUDS ) ;
_ShouldProcessCloud . resize ( MAX_CLOUDS ) ;
// For the moment only one clamp texture (generated)
Tex3DTemp . init ( 64 , 32 , 32 ) ;
TexClamp . init ( 64 , 32 , 32 , " " ) ;
if ( pCSS ! = NULL )
{
_CurrentCSS = * pCSS ;
_NewCSS = * pCSS ;
_OldCSS = * pCSS ;
}
_IsIncomingCSS = false ;
_TimeNewCSS = 60.0 * 60.0 ;
uint32 i ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
{
float newX , newY , newZ , newSizeX , newSizeY , newSizeZ ;
CCloud & c = _AllClouds [ i ] ;
c . setTex3DTemp ( Tex3DTemp ) ;
c . setTexClamp ( TexClamp ) ;
for ( ; ; )
{
bool bRecalc = false ;
newX = MAX_DIST * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
newY = MAX_DIST * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
newZ = 85.0f + 40.0f * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
newSizeX = 60.0f + 10.0f * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
newSizeY = 30.0f + 10.0f * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
newSizeZ = 30.0f + 10.0f * ( 1.0f - 2.0f * ( ( ( float ) rand ( ) ) / RAND_MAX ) ) ;
float f = 0.7f + 0.3f * ( ( float ) rand ( ) ) / RAND_MAX ;
newSizeX * = 1.5f * f ;
newSizeY * = 1.5f * f ;
newSizeZ * = 1.5f * f ;
float d = sqrtf ( SQR ( newX ) + SQR ( newY ) ) ;
if ( d > MAX_DIST ) bRecalc = true ;
for ( uint32 k = 0 ; k < i ; + + k )
{
CCloud & c2 = _AllClouds [ k ] ;
if ( ( fabs ( newX - c2 . getX ( ) ) < ( newSizeX / 2 + c2 . getSizeX ( ) / 2 ) ) & &
( fabs ( newY - c2 . getY ( ) ) < ( newSizeY / 2 + c2 . getSizeY ( ) / 2 ) ) & &
( fabs ( newZ - c2 . getZ ( ) ) < ( newSizeZ / 2 + c2 . getSizeZ ( ) / 2 ) ) )
bRecalc = true ;
}
if ( ! bRecalc ) break ;
}
c . init ( 64 , 32 , 32 , 0.122f , 4 ) ;
c . setX ( newX - newSizeX / 2 ) ;
c . setY ( newY - newSizeY / 2 ) ;
c . setZ ( newZ - newSizeZ / 2 ) ;
c . setSizeX ( newSizeX ) ;
c . setSizeY ( newSizeY ) ;
c . setSizeZ ( newSizeZ ) ;
c . Time = 0 ;
c . FuturTime = _CurrentCSS . NbCloud * 2 * ( 0.04 / _NbHalfCloudToUpdate ) ;
if ( i < _CurrentCSS . NbCloud )
{
_CloudPower [ i ] = 255 ;
_ShouldProcessCloud [ i ] = true ;
}
else
{
_CloudPower [ i ] = 0 ;
_ShouldProcessCloud [ i ] = false ;
}
}
_SortedClouds . resize ( MAX_CLOUDS ) ;
_CloudSchedulerSize = _CurrentCSS . NbCloud ;
_CloudSchedulerLastAdded . resize ( MAX_CLOUDS ) ;
_FrameCounter = 0 ;
_CloudScheduler . clear ( ) ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
_CloudSchedulerLastAdded [ i ] . ValidPos = false ;
if ( _CurrentCSS . NbCloud = = 0 )
{
for ( i = 0 ; i < QUEUE_SIZE ; + + i )
{
SCloudSchedulerEntry cse ;
cse . CloudIndex = - 1 ;
cse . Frame = _FrameCounter ;
cse . Ambient = _CurrentCSS . Ambient ;
cse . Diffuse = _CurrentCSS . Diffuse ;
_CloudScheduler . insert ( _CloudScheduler . end ( ) , cse ) ;
+ + _FrameCounter ;
}
}
else
{
for ( i = 0 ; i < QUEUE_SIZE ; + + i )
{
sint32 nCloudNb ;
nCloudNb = i % _CurrentCSS . NbCloud ;
SCloudSchedulerEntry cse ;
cse . CloudIndex = nCloudNb ;
if ( _CloudSchedulerLastAdded [ nCloudNb ] . ValidPos = = true )
{
SCloudSchedulerEntry & lastCSE = * _CloudSchedulerLastAdded [ nCloudNb ] . Pos ;
sint32 delta = _FrameCounter - lastCSE . Frame ;
lastCSE . DeltaNextCalc = delta ;
}
cse . Frame = _FrameCounter ;
cse . Ambient = _CurrentCSS . Ambient ;
cse . Diffuse = _CurrentCSS . Diffuse ;
cse . Power = _CloudPower [ cse . CloudIndex ] ;
_CloudSchedulerLastAdded [ cse . CloudIndex ] . Pos = _CloudScheduler . insert ( _CloudScheduler . end ( ) , cse ) ;
_CloudSchedulerLastAdded [ cse . CloudIndex ] . ValidPos = true ;
//_CloudSchedulerLastAdded[cse.CloudIndex].Pos = _CloudScheduler.end()-1;
+ + _FrameCounter ;
}
}
_GlobalTime = 0.0f ;
_DTRest = 0.0f ;
_Generate = true ;
_AverageFrameRate . init ( 16 ) ;
for ( i = 0 ; i < 16 ; + + i )
_AverageFrameRate . addValue ( 40.0f / 1000.0f ) ;
_ExtrapolatedPriorities . resize ( MAX_CLOUDS ) ;
for ( i = 0 ; i < QUEUE_SIZE ; + + i )
anim ( 41.0 / 1000.0 , _ViewerCam ) ;
}
// ------------------------------------------------------------------------------------------------
void CCloudScape : : set ( SCloudScapeSetup & css )
{
_IncomingCSS = css ;
_IsIncomingCSS = true ;
}
// ------------------------------------------------------------------------------------------------
void CCloudScape : : anim ( double dt , NL3D : : CCamera * pCamera )
{
double startDate = double ( CTime : : getLocalTime ( ) ) / 1000.0 ;
sint32 i ;
// Disable fog
bool fog = _Driver - > fogEnabled ( ) ;
_Driver - > enableFog ( false ) ;
_ViewerCam = pCamera ;
// update the max delta time
// If rendering was too slow and took too much time of the previous frame, we decrease the max delta time to give clouds less processing time
// Otherwise a cycle occurs, and slow rendering propagate from frame to frame
if ( dt ! = 0 & & _LastAnimRenderTime > MAX_TIME_FOR_CLOUD_ANIM & & ( _LastAnimRenderTime / dt ) > MAX_FRAME_PERCENT_FOR_CLOUD_RENDERING )
{
// if cloud rendering take too much time of previous frame, allocate less time for clouds
// NB : check is only done if clouds rendering is above a given thrheshold, because if only clouds are rendered, then they may take 100% of frame without
// having slow rendering
_MaxDeltaTime = std : : max ( MIN_CLOUDS_ANIM_DELTA_TIME , _MaxDeltaTime / 2 ) ;
}
else
{
// clouds didn't take too much time -> allocate more time for them
_MaxDeltaTime = std : : min ( MAX_CLOUDS_ANIM_DELTA_TIME , _MaxDeltaTime + 0.002 ) ;
}
// 10 fps -> 200 fps
if ( dt > _MaxDeltaTime ) dt = _MaxDeltaTime ;
if ( dt < MIN_CLOUDS_ANIM_DELTA_TIME ) dt = MIN_CLOUDS_ANIM_DELTA_TIME ;
_DeltaTime = dt ;
_GlobalTime + = _DeltaTime ;
_AverageFrameRate . addValue ( ( float ) _DeltaTime ) ;
// Animate the CSS
if ( _TimeNewCSS > _NewCSS . TimeToChange )
{
_CurrentCSS = _NewCSS ;
_OldCSS = _NewCSS ;
if ( _IsIncomingCSS )
{
_IsIncomingCSS = false ;
_NewCSS = _IncomingCSS ;
_TimeNewCSS = 0 ;
if ( _NewCSS . NbCloud > _OldCSS . NbCloud )
for ( i = 0 ; i < ( sint32 ) ( _NewCSS . NbCloud - _OldCSS . NbCloud ) ; + + i )
{
CCloud & c = _AllClouds [ _OldCSS . NbCloud + i ] ;
c . CloudPower = 0 ;
_CloudPower [ _OldCSS . NbCloud + i ] = 0 ;
}
}
}
else
{
float inter = ( float ) ( _TimeNewCSS / _NewCSS . TimeToChange ) ;
_CurrentCSS . WindSpeed = ( _NewCSS . WindSpeed - _OldCSS . WindSpeed ) * inter + _OldCSS . WindSpeed ;
_CurrentCSS . CloudSpeed = ( _NewCSS . CloudSpeed - _OldCSS . CloudSpeed ) * inter + _OldCSS . CloudSpeed ;
_CurrentCSS . Ambient . R = ( uint8 ) ( ( _NewCSS . Ambient . R - _OldCSS . Ambient . R ) * inter + _OldCSS . Ambient . R ) ;
_CurrentCSS . Ambient . G = ( uint8 ) ( ( _NewCSS . Ambient . G - _OldCSS . Ambient . G ) * inter + _OldCSS . Ambient . G ) ;
_CurrentCSS . Ambient . B = ( uint8 ) ( ( _NewCSS . Ambient . B - _OldCSS . Ambient . B ) * inter + _OldCSS . Ambient . B ) ;
_CurrentCSS . Ambient . A = ( uint8 ) ( ( _NewCSS . Ambient . A - _OldCSS . Ambient . A ) * inter + _OldCSS . Ambient . A ) ;
_CurrentCSS . Diffuse . R = ( uint8 ) ( ( _NewCSS . Diffuse . R - _OldCSS . Diffuse . R ) * inter + _OldCSS . Diffuse . R ) ;
_CurrentCSS . Diffuse . G = ( uint8 ) ( ( _NewCSS . Diffuse . G - _OldCSS . Diffuse . G ) * inter + _OldCSS . Diffuse . G ) ;
_CurrentCSS . Diffuse . B = ( uint8 ) ( ( _NewCSS . Diffuse . B - _OldCSS . Diffuse . B ) * inter + _OldCSS . Diffuse . B ) ;
_CurrentCSS . Diffuse . A = ( uint8 ) ( ( _NewCSS . Diffuse . A - _OldCSS . Diffuse . A ) * inter + _OldCSS . Diffuse . A ) ;
if ( _NewCSS . NbCloud > _OldCSS . NbCloud )
{
// Add some clouds
float slice = ( _NewCSS . TimeToChange / 4 ) / ( _NewCSS . NbCloud - _OldCSS . NbCloud ) ;
sint32 diffCloud = _NewCSS . NbCloud - _OldCSS . NbCloud ;
_CurrentCSS . NbCloud = _OldCSS . NbCloud + ( 1 + ( uint32 ) ( _TimeNewCSS / slice ) ) ;
if ( _CurrentCSS . NbCloud > _NewCSS . NbCloud )
_CurrentCSS . NbCloud = _NewCSS . NbCloud ;
for ( i = 0 ; i < diffCloud ; + + i )
{
_ShouldProcessCloud [ _OldCSS . NbCloud + i ] = true ;
if ( _TimeNewCSS < i * slice )
_CloudPower [ _OldCSS . NbCloud + i ] = 1 ;
else if ( _TimeNewCSS > ( i * slice + 3 * _NewCSS . TimeToChange / 4 ) )
_CloudPower [ _OldCSS . NbCloud + i ] = 255 ;
else
_CloudPower [ _OldCSS . NbCloud + i ] = ( uint8 ) ( 255 * ( _TimeNewCSS - i * slice ) / ( 3 * _NewCSS . TimeToChange / 4 ) ) ;
}
}
else
{
// Remove some clouds
sint32 diffCloud = _OldCSS . NbCloud - _NewCSS . NbCloud ;
if ( diffCloud )
{
float slice = ( _NewCSS . TimeToChange / 4 ) / ( float ) diffCloud ;
_CurrentCSS . NbCloud = _OldCSS . NbCloud ;
for ( i = 0 ; i < diffCloud ; + + i )
{
if ( _TimeNewCSS < i * slice )
_CloudPower [ _OldCSS . NbCloud - i - 1 ] = 255 ;
else if ( _TimeNewCSS > ( i * slice + 3 * _NewCSS . TimeToChange / 4 ) )
_CloudPower [ _OldCSS . NbCloud - i - 1 ] = 0 ;
else
_CloudPower [ _OldCSS . NbCloud - i - 1 ] = ( uint8 ) ( 255 - 255 * ( _TimeNewCSS - i * slice ) / ( 3 * _NewCSS . TimeToChange / 4 ) ) ;
}
}
}
}
// Make the right number of half cloud
_DTRest + = dt ;
while ( _DTRest > ( 0.04 / _NbHalfCloudToUpdate ) )
{
makeHalfCloud ( ) ;
_DTRest - = 0.04 / _NbHalfCloudToUpdate ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
{
CCloud & c = _AllClouds [ i ] ;
c . Time + = 0.04 / _NbHalfCloudToUpdate ;
}
_TimeNewCSS + = 0.04 / _NbHalfCloudToUpdate ;
}
// Backup fog
_Driver - > enableFog ( fog ) ;
// Has the driver been reseted ?
if ( _ResetCounter ! = _Driver - > getResetCounter ( ) )
{
/* Yes. Force the rebuild of all the clouds not setuped in VRAM */
_ResetCounter = _Driver - > getResetCounter ( ) ;
i = 0 ;
while ( i < MAX_CLOUDS )
{
while ( _ShouldProcessCloud [ i ] & &
( ! _AllClouds [ i ] . _TexBill - > setupedIntoDriver ( ) | | ! _AllClouds [ i ] . _TexOldBill - > setupedIntoDriver ( ) ) )
{
// Force a cloudscape rebuild
anim ( 41.0 / 1000.0 , _ViewerCam ) ;
}
i + + ;
}
}
double endDate = double ( CTime : : getLocalTime ( ) ) / 1000.0 ;
_LastAnimRenderTime = endDate - startDate ;
}
// ------------------------------------------------------------------------------------------------
void CCloudScape : : makeHalfCloud ( )
{
CVector Viewer = CVector ( 0 , 0 , 0 ) ; //_ViewerCam->getMatrix().getPos();
if ( _Generate )
{
// Find the next cloud in the list
SCloudSchedulerEntry FrontCSE ;
FrontCSE = _CloudScheduler . front ( ) ;
// Is the cloud do not have another reference in the list add it now because it should be processed
sint32 CloudIndexToAdd = - 1 ;
if ( ( FrontCSE . CloudIndex ! = - 1 ) & &
( _ShouldProcessCloud [ FrontCSE . CloudIndex ] = = true ) & &
( ( _CloudSchedulerLastAdded [ FrontCSE . CloudIndex ] . ValidPos = = false ) | |
( ( _CloudSchedulerLastAdded [ FrontCSE . CloudIndex ] . ValidPos = = true ) & &
( _CloudSchedulerLastAdded [ FrontCSE . CloudIndex ] . Pos = = _CloudScheduler . begin ( ) ) )
) )
{
// It should be added now !
CloudIndexToAdd = FrontCSE . CloudIndex ;
FrontCSE . DeltaNextCalc = QUEUE_SIZE ;
}
else if ( _CurrentCSS . NbCloud ! = 0 )
{
// Choose a Cloud Index To Add at the end of the list
uint32 nPeriodeMax = _CurrentCSS . NbCloud + _CurrentCSS . NbCloud / 10 ;
sint32 Priority = - 10000 ;
uint32 i ;
float sumPrior = 0.0f ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
if ( _ShouldProcessCloud [ i ] )
{
CCloud & rC = _AllClouds [ i ] ;
float ExtrapolatedTime = ( ( 0.04f / _NbHalfCloudToUpdate ) * QUEUE_SIZE * 2 ) ;
float x = rC . getLastX ( ) + ExtrapolatedTime * _CurrentCSS . WindSpeed ;
//float d = sqrtf(SQR(x+rC.getSizeX()/2-Viewer.x)+SQR(rC.getY()+rC.getSizeY()/2-Viewer.y)+
// SQR(rC.getZ()+rC.getSizeZ()/2-Viewer.z));
float d = SQR ( x + rC . getSizeX ( ) / 2 - Viewer . x ) + SQR ( rC . getY ( ) + rC . getSizeY ( ) / 2 - Viewer . y ) +
SQR ( rC . getZ ( ) + rC . getSizeZ ( ) / 2 - Viewer . z ) ;
float d05 = sqrtf ( d ) ;
float d025 = sqrtf ( d05 ) ;
float d075 = d05 * d025 ;
_ExtrapolatedPriorities [ i ] = 1.0f / d075 ;
sumPrior + = _ExtrapolatedPriorities [ i ] ;
}
sint32 sumJeton = 0 ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
if ( _ShouldProcessCloud [ i ] )
{
// Normalize priorities
float factor = ( ( float ) QUEUE_SIZE ) / sumPrior ;
sint32 nbJeton = ( sint32 ) ( 0.5f + ( factor * _ExtrapolatedPriorities [ i ] ) ) ;
if ( nbJeton < 1 )
nbJeton = 1 ;
_ExtrapolatedPriorities [ i ] = ( float ) nbJeton ;
sumJeton + = nbJeton ;
}
if ( sumJeton > QUEUE_SIZE )
{
do
{
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
if ( _ShouldProcessCloud [ i ] )
{
if ( _ExtrapolatedPriorities [ i ] > 1 )
{
_ExtrapolatedPriorities [ i ] - = 1 ;
- - sumJeton ;
if ( sumJeton = = QUEUE_SIZE ) break ;
}
}
}
while ( sumJeton > QUEUE_SIZE ) ;
}
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
if ( _ShouldProcessCloud [ i ] )
{
// Cloud Period
sint32 newPriority = nPeriodeMax ;
// Is there a last entry in array ?
if ( _CloudSchedulerLastAdded [ i ] . ValidPos = = true )
{
SCloudSchedulerEntry & rLastCSE = * _CloudSchedulerLastAdded [ i ] . Pos ;
newPriority = ( sint32 ) ( QUEUE_SIZE / _ExtrapolatedPriorities [ i ] ) ;
newPriority = ( _FrameCounter - rLastCSE . Frame ) - newPriority ;
}
else
{
newPriority = 10000 ;
}
if ( newPriority > Priority )
{
Priority = newPriority ;
CloudIndexToAdd = i ;
}
}
nlassert ( CloudIndexToAdd ! = - 1 ) ;
}
// Ok now we have a good cloud index to add so make the new cloud entry
SCloudSchedulerEntry newCSE ;
newCSE . CloudIndex = CloudIndexToAdd ;
newCSE . Frame = _FrameCounter ;
newCSE . Ambient = _CurrentCSS . Ambient ;
newCSE . Diffuse = _CurrentCSS . Diffuse ;
if ( CloudIndexToAdd ! = - 1 )
{
newCSE . Power = _CloudPower [ CloudIndexToAdd ] ;
// If the cloud where added previously to the list
if ( _CloudSchedulerLastAdded [ CloudIndexToAdd ] . ValidPos = = true )
{
// This means that the cloud were added from a long time ago
SCloudSchedulerEntry & lastCSE = * _CloudSchedulerLastAdded [ CloudIndexToAdd ] . Pos ;
sint32 delta = _FrameCounter - lastCSE . Frame ;
lastCSE . DeltaNextCalc = delta ;
// But the cloud can be removed (if so we have to not process it anymore)
if ( newCSE . Power = = 0 )
_ShouldProcessCloud [ CloudIndexToAdd ] = false ;
}
else
{
// No the cloud do not appear previously in the list... So its a new one
_AllClouds [ CloudIndexToAdd ] . reset ( _ViewerCam ) ;
}
// If the last cloud occurence of the cloud appear at beginning so no more occurence in list
if ( _CloudSchedulerLastAdded [ FrontCSE . CloudIndex ] . Pos = = _CloudScheduler . begin ( ) )
_CloudSchedulerLastAdded [ FrontCSE . CloudIndex ] . ValidPos = false ;
_CloudSchedulerLastAdded [ CloudIndexToAdd ] . Pos = _CloudScheduler . insert ( _CloudScheduler . end ( ) , newCSE ) ;
_CloudSchedulerLastAdded [ CloudIndexToAdd ] . ValidPos = true ;
//_CloudSchedulerLastAdded[CloudIndexToAdd].Pos = _CloudScheduler.end()-1;
}
else
{
_CloudScheduler . insert ( _CloudScheduler . end ( ) , newCSE ) ;
}
_CloudScheduler . pop_front ( ) ;
+ + _FrameCounter ;
// End of scheduling
// Get the cloud to process (this must be the next occurence of front cloud)
std : : list < SCloudSchedulerEntry > : : iterator it = _CloudScheduler . begin ( ) ;
while ( it ! = _CloudScheduler . end ( ) )
{
SCloudSchedulerEntry & rCSE = * it ;
if ( rCSE . CloudIndex = = FrontCSE . CloudIndex )
break ;
+ + it ;
}
SCloudSchedulerEntry CSEToCalc ;
// The cloud is no more present in the list
if ( it = = _CloudScheduler . end ( ) )
{
FrontCSE . DeltaNextCalc = 1 ;
CSEToCalc = FrontCSE ;
}
else
{
CSEToCalc = * it ;
}
// Is the cloud to calc is a real cloud
if ( CSEToCalc . CloudIndex = = - 1 )
{
_CurrentCloudInProcess = NULL ;
}
else
{
_CurrentCloudInProcess = & _AllClouds [ CSEToCalc . CloudIndex ] ;
CCloud & c = * _CurrentCloudInProcess ;
// To go from Front cloud to CSEToCalc cloud we should take the front DeltaNextCalc
_CurrentCloudInProcessFuturTime = ( ( 0.04 / _NbHalfCloudToUpdate ) * FrontCSE . DeltaNextCalc * 2 ) ;
c . setX ( ( float ) ( c . getLastX ( ) + _CurrentCloudInProcessFuturTime * _CurrentCSS . WindSpeed ) ) ;
float d2D = sqrtf ( SQR ( c . getX ( ) + c . getSizeX ( ) / 2 - Viewer . x ) + SQR ( c . getY ( ) + c . getSizeY ( ) / 2 - Viewer . y ) ) ;
if ( d2D > MAX_DIST )
c . CloudDistAtt = 255 ;
else if ( d2D > ( MAX_DIST - 100.0f ) )
c . CloudDistAtt = ( uint8 ) ( 255 * ( ( d2D - ( MAX_DIST - 100.0f ) ) / 100.0f ) ) ;
else
c . CloudDistAtt = 0 ;
c . LastCloudPower = c . CloudPower ;
c . CloudPower = CSEToCalc . Power ;
c . CloudDiffuse = CSEToCalc . Diffuse ;
c . CloudAmbient = CSEToCalc . Ambient ;
c . anim ( _CurrentCloudInProcessFuturTime * _CurrentCSS . CloudSpeed ,
_CurrentCloudInProcessFuturTime * _CurrentCSS . WindSpeed ) ;
c . generate ( _Noise3D ) ;
}
}
else
{
if ( _CurrentCloudInProcess ! = NULL )
{
CCloud & c = * _CurrentCloudInProcess ;
c . Time = 0 ;
c . FuturTime = _CurrentCloudInProcessFuturTime ;
c . light ( ) ;
if ( c . getX ( ) > MAX_DIST )
{
c . setX ( c . getX ( ) - ( 2 * MAX_DIST ) ) ;
c . setLooping ( ) ;
}
float r = sqrtf ( SQR ( c . getSizeX ( ) / 2 ) + SQR ( c . getSizeY ( ) / 2 ) + SQR ( c . getSizeZ ( ) / 2 ) ) ;
float d = sqrtf ( SQR ( c . getX ( ) + c . getSizeX ( ) / 2 - Viewer . x ) + SQR ( c . getY ( ) + c . getSizeY ( ) / 2 - Viewer . y ) +
SQR ( c . getZ ( ) + c . getSizeZ ( ) / 2 - Viewer . z ) ) ;
uint32 lookAtSize = ( uint32 ) ( _LODQualityThreshold * r / d ) ;
lookAtSize = raiseToNextPowerOf2 ( lookAtSize ) ;
if ( lookAtSize > 128 ) lookAtSize = 128 ;
c . genBill ( _ViewerCam , lookAtSize ) ;
}
}
_Generate = ! _Generate ;
}
// ------------------------------------------------------------------------------------------------
void CCloudScape : : render ( )
{
uint32 i , j ;
CVector Viewer = CVector ( 0 , 0 , 0 ) ;
// Disable fog
bool fog = _Driver - > fogEnabled ( ) ;
_Driver - > enableFog ( false ) ;
CMatrix viewMat ;
viewMat = _ViewerCam - > getMatrix ( ) ;
viewMat . setPos ( CVector ( 0 , 0 , 0 ) ) ;
viewMat . invert ( ) ;
CScissor s ;
s . initFullScreen ( ) ;
_Driver - > setupScissor ( s ) ;
CViewport v ;
_Driver - > setupViewport ( v ) ;
CFrustum f = _ViewerCam - > getFrustum ( ) ;
_Driver - > setFrustum ( f . Left , f . Right , f . Bottom , f . Top , f . Near , f . Far , f . Perspective ) ;
_Driver - > setupViewMatrix ( viewMat ) ;
_Driver - > setupModelMatrix ( CMatrix : : Identity ) ;
uint32 nNbCloudToRender = 0 ;
for ( i = 0 ; i < MAX_CLOUDS ; + + i )
{
CCloud & c = _AllClouds [ i ] ;
SSortedCloudEntry & sce = _SortedClouds [ nNbCloudToRender ] ;
sce . Cloud = & c ;
sce . Distance = sqrtf ( SQR ( c . getX ( ) + c . getSizeX ( ) / 2 - Viewer . x ) + SQR ( c . getY ( ) + c . getSizeY ( ) / 2 - Viewer . y ) +
SQR ( c . getZ ( ) + c . getSizeZ ( ) / 2 - Viewer . z ) ) ;
nNbCloudToRender + + ;
}
for ( i = 0 ; i < nNbCloudToRender - 1 ; + + i )
for ( j = i + 1 ; j < nNbCloudToRender ; + + j )
{
if ( _SortedClouds [ i ] . Distance < _SortedClouds [ j ] . Distance )
{
SSortedCloudEntry sceTmp = _SortedClouds [ i ] ;
_SortedClouds [ i ] = _SortedClouds [ j ] ;
_SortedClouds [ j ] = sceTmp ;
}
}
for ( i = 0 ; i < nNbCloudToRender ; + + i )
{
CCloud * pC = _SortedClouds [ i ] . Cloud ;
if ( ( pC - > CloudPower > 0 ) | | ( pC - > LastCloudPower > 0 ) )
pC - > dispBill ( _ViewerCam ) ;
}
// Backup fog
_Driver - > enableFog ( fog ) ;
}
// ------------------------------------------------------------------------------------------------
uint32 CCloudScape : : getMemSize ( )
{
uint32 nMemSize = 0 ;
for ( uint32 i = 0 ; i < MAX_CLOUDS ; + + i )
{
CCloud & c = _AllClouds [ i ] ;
nMemSize + = c . getMemSize ( ) ;
}
return nMemSize ;
}
} // namespace NL3D