1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "nel/3d/cloud_scape.h"
19 #include "nel/3d/driver.h"
20 #include "nel/3d/scissor.h"
21 #include "nel/3d/viewport.h"
23 // ------------------------------------------------------------------------------------------------
24 using namespace NLMISC
;
33 // ------------------------------------------------------------------------------------------------
34 #define SQR(x) (x)*(x)
36 #define MAX_DIST 400.0f
37 #define MAX_CLOUDS 256
38 // QUEUE_SIZE must be at least 2*MAX_CLOUDS
39 #define QUEUE_SIZE 512
40 static const double MAX_CLOUDS_ANIM_DELTA_TIME
= 0.075; // maximum delta time handled by cloud animation, delta t above that are clamped
41 static const double MIN_CLOUDS_ANIM_DELTA_TIME
= 0.005; // minimum delta time handled by clouds animation
42 static const double MAX_TIME_FOR_CLOUD_ANIM
= 0.02; // max number of second spent for cloud render before we check if too slow
43 static const double MAX_FRAME_PERCENT_FOR_CLOUD_RENDERING
= 20 / 100; // at most 20 % of the frame for cloud render
46 // ------------------------------------------------------------------------------------------------
48 // ------------------------------------------------------------------------------------------------
50 // ------------------------------------------------------------------------------------------------
51 SCloudTexture3D::SCloudTexture3D ()
56 ToLightRGB
.initUnlit();
57 ToLightRGB
.setShader (CMaterial::Normal
);
58 ToLightRGB
.setZFunc (CMaterial::always
);
59 ToLightRGB
.setZWrite (false);
60 ToLightRGB
.texEnvOpRGB (0, CMaterial::Replace
);
61 ToLightRGB
.texEnvArg0RGB (0, CMaterial::Diffuse
, CMaterial::SrcColor
);
62 ToLightRGB
.texEnvOpAlpha (0, CMaterial::Replace
);
63 ToLightRGB
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::SrcAlpha
);
64 ToLightRGB
.setBlend (true);
65 ToLightRGB
.setBlendFunc (CMaterial::invsrcalpha
, CMaterial::srcalpha
);
66 ToLightRGB
.setColor (CRGBA(0,0,0,255));
67 ToLightAlpha
.initUnlit();
68 ToLightAlpha
.setShader (CMaterial::Normal
);
69 ToLightAlpha
.setZFunc (CMaterial::always
);
70 ToLightAlpha
.setZWrite (false);
71 ToLightAlpha
.texEnvOpRGB (0, CMaterial::Replace
);
72 ToLightAlpha
.texEnvArg0RGB (0, CMaterial::Diffuse
, CMaterial::SrcColor
);
73 ToLightAlpha
.texEnvOpAlpha (0, CMaterial::Replace
);
74 ToLightAlpha
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::InvSrcAlpha
);
75 ToLightAlpha
.setColor (CRGBA(0,0,0,255));
78 ToBill
.setZFunc (CMaterial::always
);
79 ToBill
.setZWrite (false);
80 ToBill
.setDoubleSided(true);
82 ToBill
.texEnvOpRGB (0, CMaterial::Add
);
83 ToBill
.texEnvArg0RGB (0, CMaterial::Texture
, CMaterial::SrcColor
);
84 ToBill
.texEnvArg1RGB (0, CMaterial::Diffuse
, CMaterial::SrcColor
);
85 ToBill
.setColor (CRGBA(80,80,80,255));
87 ToBill
.texEnvOpAlpha (0, CMaterial::Replace
);
88 ToBill
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::SrcAlpha
);
90 ToBill
.texEnvOpRGB (1, CMaterial::Modulate
);
91 ToBill
.texEnvArg0RGB (1, CMaterial::Previous
, CMaterial::SrcColor
);
92 ToBill
.texEnvArg1RGB (1, CMaterial::Previous
, CMaterial::SrcAlpha
);
93 ToBill
.texEnvOpAlpha (1, CMaterial::Replace
);
94 ToBill
.texEnvArg0Alpha (1, CMaterial::Previous
, CMaterial::SrcAlpha
);
96 ToBill
.setBlendFunc (CMaterial::one
, CMaterial::invsrcalpha
);
97 ToBill
.setBlend (true);
100 MatCopy
.setShader (CMaterial::Normal
);
101 MatCopy
.setZFunc (CMaterial::always
);
102 MatCopy
.setZWrite (false);
103 MatCopy
.texEnvOpRGB (0, CMaterial::Replace
);
104 MatCopy
.texEnvArg0RGB (0, CMaterial::Texture
, CMaterial::SrcColor
);
105 MatCopy
.texEnvOpAlpha (0, CMaterial::Replace
);
106 MatCopy
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::SrcAlpha
);
107 MatCopy
.setBlend (false);
108 MatCopy
.setColor (CRGBA(255,255,255,255));
111 // ------------------------------------------------------------------------------------------------
112 void SCloudTexture3D::init (uint32 nWidth
, uint32 nHeight
, uint32 nDepth
)
117 Width
= raiseToNextPowerOf2 (nWidth
);
118 Height
= raiseToNextPowerOf2 (nHeight
);
119 Depth
= raiseToNextPowerOf2 (nDepth
);
120 uint32 vdpo2
= getPowerOf2(Depth
);
121 NbW
= 1 << (vdpo2
/ 2);
122 if ((vdpo2
& 1) != 0)
123 NbH
= 2 << (vdpo2
/ 2);
125 NbH
= 1 << (vdpo2
/ 2);
127 Mem
= new uint8
[4*NbW
*Width
*NbH
*Height
];
128 Mem2
= new uint8
[4*NbW
*Width
*NbH
*Height
];
129 MemBuffer
= new uint8
[4*Width
*Height
];
130 Tex
= new CTextureMem (Mem
, 4*NbW
*Width
*NbH
*Height
, true, false, NbW
*Width
, NbH
*Height
, CBitmap::RGBA
);
131 Tex2
= new CTextureMem (Mem2
, 4*NbW
*Width
*NbH
*Height
, true, false, NbW
*Width
, NbH
*Height
, CBitmap::RGBA
);
132 TexBuffer
= new CTextureMem (MemBuffer
, 4*Width
*Height
, true, false, Width
, Height
, CBitmap::RGBA
);
134 Tex
->setWrapS (ITexture::Clamp
);
135 Tex
->setWrapT (ITexture::Clamp
);
136 Tex
->setFilterMode (ITexture::Linear
, ITexture::LinearMipMapOff
);
137 Tex
->setReleasable (false);
138 Tex
->setRenderTarget (true);
140 Tex2
->setWrapS (ITexture::Clamp
);
141 Tex2
->setWrapT (ITexture::Clamp
);
142 Tex2
->setFilterMode (ITexture::Linear
, ITexture::LinearMipMapOff
);
143 Tex2
->setReleasable (false);
144 Tex2
->setRenderTarget (true);
146 TexBuffer
->setWrapS (ITexture::Clamp
);
147 TexBuffer
->setWrapT (ITexture::Clamp
);
148 TexBuffer
->setFilterMode (ITexture::Linear
, ITexture::LinearMipMapOff
);
149 TexBuffer
->setReleasable (false);
150 TexBuffer
->setRenderTarget (true);
151 TexBuffer
->generate ();
153 ToLightRGB
.setTexture (0, Tex
);
154 ToLightAlpha
.setTexture (0, Tex
);
155 ToBill
.setTexture(0, Tex2
);
156 ToBill
.setTexture(1, Tex2
);
157 MatCopy
.setTexture(0, TexBuffer
);
160 // ------------------------------------------------------------------------------------------------
161 // SCloudTextureClamp
162 // ------------------------------------------------------------------------------------------------
164 // ------------------------------------------------------------------------------------------------
165 SCloudTextureClamp::SCloudTextureClamp ()
169 ToClamp
.setShader (CMaterial::Normal
);
170 ToClamp
.texEnvOpAlpha (0, CMaterial::Add
);
171 ToClamp
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::SrcAlpha
);
172 ToClamp
.texEnvArg1Alpha (0, CMaterial::Diffuse
, CMaterial::SrcAlpha
);
173 ToClamp
.setColor (CRGBA(255,255,255,255));
174 ToClamp
.setBlend (true);
175 ToClamp
.setBlendFunc (CMaterial::one
, CMaterial::one
);
176 ToClamp
.setZFunc (CMaterial::always
);
177 ToClamp
.setZWrite (false);
181 // ------------------------------------------------------------------------------------------------
182 void SCloudTextureClamp::init (uint32 nWidth
, uint32 nHeight
, uint32 nDepth
, const std::string
&filename
)
187 Width
= raiseToNextPowerOf2 (nWidth
);
188 Height
= raiseToNextPowerOf2 (nHeight
);
189 Depth
= raiseToNextPowerOf2 (nDepth
);
190 uint32 vdpo2
= getPowerOf2(Depth
);
191 NbW
= 1 << (vdpo2
/ 2);
192 if ((vdpo2
& 1) != 0)
193 NbH
= 2 << (vdpo2
/ 2);
195 NbH
= 1 << (vdpo2
/ 2);
197 Mem
= new uint8
[NbW
*Width
*NbH
*Height
];
200 if (filename
.empty())
202 // No filename so init with default
203 for (i
= 0; i
< NbW
; ++i
)
205 for (j
= 0; j
< NbH
; ++j
)
209 for (k
= 0; k
< Width
; ++k
)
210 for (l
= 0; l
< Height
; ++l
)
215 float xc
= Width
/2.0f
;
216 float yc
= Height
/2.0f
;
217 float zc
= Depth
/2.0f
;
219 float r
= (x
-xc
)*(x
-xc
)/(Width
*Width
/4.0f
) + (y
-yc
)*(y
-yc
)/(Height
*Height
/4.0f
)
220 + (z
-zc
)*(z
-zc
)/(Depth
*Depth
/4.0f
);
225 col
= (uint8
)((r
)*223+32);
227 Mem
[i
*Width
+k
+ (j
*Height
+l
)*NbW
*Width
] = col
;
237 Tex
= new CTextureMem (Mem
, NbW
*Width
*NbH
*Height
, true, false, NbW
*Width
, NbH
*Height
, CBitmap::Alpha
);
238 Tex
->setWrapS (ITexture::Repeat
);
239 Tex
->setWrapT (ITexture::Repeat
);
240 Tex
->setFilterMode (ITexture::Linear
, ITexture::LinearMipMapOff
);
243 Tex
->setReleasable (false);
246 ToClamp
.setTexture(0, Tex
);
251 // ------------------------------------------------------------------------------------------------
253 // ------------------------------------------------------------------------------------------------
255 // ------------------------------------------------------------------------------------------------
256 CCloudScape::CCloudScape (NL3D::IDriver
*pDriver
) : _Noise3D (pDriver
)
260 _VertexBuffer
.setVertexFormat (CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
| CVertexBuffer::TexCoord1Flag
);
261 _VertexBuffer
.setNumVertices (4);
262 _VertexBuffer
.setName("CloudScape");
264 // Material used for cleaning
265 _MatClear
.initUnlit();
266 _MatClear
.setDoubleSided (true);
267 _MatClear
.setZFunc (CMaterial::always
);
268 _MatClear
.setZWrite (false);
269 _MatClear
.setBlend (false);
271 _MatBill
.initUnlit();
272 _MatBill
.setShader (CMaterial::Normal
); // not needed
274 _MatBill
.texEnvOpRGB (0, CMaterial::Replace
);
275 _MatBill
.texEnvArg0RGB (0, CMaterial::Texture
, CMaterial::SrcColor
);
277 _MatBill
.texEnvOpAlpha (0, CMaterial::Replace
);
278 _MatBill
.texEnvArg0Alpha (0, CMaterial::Texture
, CMaterial::SrcAlpha
);
280 _MatBill
.texEnvOpRGB (1, CMaterial::InterpolateDiffuse
);
281 _MatBill
.texEnvArg0RGB (1, CMaterial::Texture
, CMaterial::SrcColor
);
282 _MatBill
.texEnvArg1RGB (1, CMaterial::Previous
, CMaterial::SrcColor
);
284 _MatBill
.texEnvOpAlpha (1, CMaterial::InterpolateDiffuse
);
285 _MatBill
.texEnvArg0Alpha (1, CMaterial::Texture
, CMaterial::SrcAlpha
);
286 _MatBill
.texEnvArg1Alpha (1, CMaterial::Previous
, CMaterial::SrcAlpha
);
288 _MatBill
.setBlend (true);
289 _MatBill
.setBlendFunc(CMaterial::one
, CMaterial::invsrcalpha
);
290 _MatBill
.setZFunc (CMaterial::always
);
291 _MatBill
.setZWrite (false);
292 _MatBill
.setDoubleSided (true);
293 _MatBill
.setAlphaTest(true);
294 _MatBill
.setAlphaTestThreshold(2.0f
/256.0f
);
296 _LODQualityThreshold
= 160.0f
;
297 _IsIncomingCSS
= false;
299 _NbHalfCloudToUpdate
= 1;
300 _CurrentCloudInProcess
= NULL
;
302 _LastAnimRenderTime
= 0;
303 _MaxDeltaTime
= 0.1; // 100 ms
306 // ------------------------------------------------------------------------------------------------
307 CCloudScape::~CCloudScape ()
311 // ------------------------------------------------------------------------------------------------
312 void CCloudScape::init (SCloudScapeSetup
*pCSS
, NL3D::CCamera
*pCamera
)
314 _ResetCounter
= _Driver
->getResetCounter();
315 _ViewerCam
= pCamera
;
319 _AllClouds
.resize (MAX_CLOUDS
, CCloud(this));
320 _CloudPower
.resize (MAX_CLOUDS
);
321 _ShouldProcessCloud
.resize (MAX_CLOUDS
);
323 // For the moment only one clamp texture (generated)
324 Tex3DTemp
.init (64, 32, 32);
325 TexClamp
.init (64, 32, 32,"");
333 _IsIncomingCSS
= false;
334 _TimeNewCSS
= 60.0*60.0;
337 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
339 float newX
, newY
, newZ
, newSizeX
, newSizeY
, newSizeZ
;
341 CCloud
&c
= _AllClouds
[i
];
343 c
.setTex3DTemp (Tex3DTemp
);
344 c
.setTexClamp (TexClamp
);
348 bool bRecalc
= false;
349 newX
= MAX_DIST
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
350 newY
= MAX_DIST
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
351 newZ
= 85.0f
+40.0f
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
353 newSizeX
= 60.0f
+10.0f
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
354 newSizeY
= 30.0f
+10.0f
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
355 newSizeZ
= 30.0f
+10.0f
*(1.0f
-2.0f
*(((float)rand())/RAND_MAX
));
356 float f
= 0.7f
+0.3f
*((float)rand())/RAND_MAX
;
361 float d
= sqrtf(SQR(newX
)+SQR(newY
));
362 if (d
> MAX_DIST
) bRecalc
= true;
364 for (uint32 k
= 0;k
< i
; ++k
)
366 CCloud
&c2
= _AllClouds
[k
];
368 if ((fabs(newX
-c2
.getX()) < (newSizeX
/2+c2
.getSizeX()/2)) &&
369 (fabs(newY
-c2
.getY()) < (newSizeY
/2+c2
.getSizeY()/2)) &&
370 (fabs(newZ
-c2
.getZ()) < (newSizeZ
/2+c2
.getSizeZ()/2)))
376 c
.init (64, 32, 32, 0.122f
, 4);
377 c
.setX (newX
-newSizeX
/2);
378 c
.setY (newY
-newSizeY
/2);
379 c
.setZ (newZ
-newSizeZ
/2);
381 c
.setSizeX (newSizeX
);
382 c
.setSizeY (newSizeY
);
383 c
.setSizeZ (newSizeZ
);
386 c
.FuturTime
= _CurrentCSS
.NbCloud
* 2 * (0.04/_NbHalfCloudToUpdate
);
387 if (i
< _CurrentCSS
.NbCloud
)
389 _CloudPower
[i
] = 255;
390 _ShouldProcessCloud
[i
] = true;
395 _ShouldProcessCloud
[i
] = false;
399 _SortedClouds
.resize (MAX_CLOUDS
);
401 _CloudSchedulerSize
= _CurrentCSS
.NbCloud
;
402 _CloudSchedulerLastAdded
.resize (MAX_CLOUDS
);
404 _CloudScheduler
.clear();
405 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
406 _CloudSchedulerLastAdded
[i
].ValidPos
= false;
408 if (_CurrentCSS
.NbCloud
== 0)
410 for (i
= 0; i
< QUEUE_SIZE
; ++i
)
412 SCloudSchedulerEntry cse
;
414 cse
.Frame
= _FrameCounter
;
415 cse
.Ambient
= _CurrentCSS
.Ambient
;
416 cse
.Diffuse
= _CurrentCSS
.Diffuse
;
417 _CloudScheduler
.insert(_CloudScheduler
.end(), cse
);
423 for (i
= 0; i
< QUEUE_SIZE
; ++i
)
426 nCloudNb
= i
%_CurrentCSS
.NbCloud
;
427 SCloudSchedulerEntry cse
;
428 cse
.CloudIndex
= nCloudNb
;
429 if (_CloudSchedulerLastAdded
[nCloudNb
].ValidPos
== true)
431 SCloudSchedulerEntry
&lastCSE
= *_CloudSchedulerLastAdded
[nCloudNb
].Pos
;
432 sint32 delta
= _FrameCounter
- lastCSE
.Frame
;
433 lastCSE
.DeltaNextCalc
= delta
;
435 cse
.Frame
= _FrameCounter
;
436 cse
.Ambient
= _CurrentCSS
.Ambient
;
437 cse
.Diffuse
= _CurrentCSS
.Diffuse
;
438 cse
.Power
= _CloudPower
[cse
.CloudIndex
];
439 _CloudSchedulerLastAdded
[cse
.CloudIndex
].Pos
= _CloudScheduler
.insert(_CloudScheduler
.end(), cse
);
440 _CloudSchedulerLastAdded
[cse
.CloudIndex
].ValidPos
= true;
441 //_CloudSchedulerLastAdded[cse.CloudIndex].Pos = _CloudScheduler.end()-1;
449 _AverageFrameRate
.init(16);
450 for (i
= 0; i
< 16; ++i
)
451 _AverageFrameRate
.addValue (40.0f
/1000.0f
);
453 _ExtrapolatedPriorities
.resize (MAX_CLOUDS
);
455 for (i
= 0; i
< QUEUE_SIZE
; ++i
)
456 anim (41.0/1000.0, _ViewerCam
);
459 // ------------------------------------------------------------------------------------------------
460 void CCloudScape::set (SCloudScapeSetup
&css
)
463 _IsIncomingCSS
= true;
466 // ------------------------------------------------------------------------------------------------
467 void CCloudScape::anim (double dt
, NL3D::CCamera
*pCamera
)
469 double startDate
= double(CTime::getLocalTime())/1000.0;
473 bool fog
= _Driver
->fogEnabled();
474 _Driver
->enableFog (false);
476 _ViewerCam
= pCamera
;
478 // update the max delta time
479 // 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
480 // Otherwise a cycle occurs, and slow rendering propagate from frame to frame
484 if (dt
!= 0 && _LastAnimRenderTime
> MAX_TIME_FOR_CLOUD_ANIM
&& (_LastAnimRenderTime
/ dt
) > MAX_FRAME_PERCENT_FOR_CLOUD_RENDERING
)
486 // if cloud rendering take too much time of previous frame, allocate less time for clouds
487 // 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
488 // having slow rendering
489 _MaxDeltaTime
= std::max(MIN_CLOUDS_ANIM_DELTA_TIME
, _MaxDeltaTime
/ 2);
493 // clouds didn't take too much time -> allocate more time for them
494 _MaxDeltaTime
= std::min(MAX_CLOUDS_ANIM_DELTA_TIME
, _MaxDeltaTime
+ 0.002);
500 if (dt
> _MaxDeltaTime
) dt
= _MaxDeltaTime
;
501 if (dt
< MIN_CLOUDS_ANIM_DELTA_TIME
) dt
= MIN_CLOUDS_ANIM_DELTA_TIME
;
505 _GlobalTime
+= _DeltaTime
;
506 _AverageFrameRate
.addValue ((float)_DeltaTime
);
509 if (_TimeNewCSS
> _NewCSS
.TimeToChange
)
511 _CurrentCSS
= _NewCSS
;
515 _IsIncomingCSS
= false;
516 _NewCSS
= _IncomingCSS
;
518 if (_NewCSS
.NbCloud
> _OldCSS
.NbCloud
)
519 for (i
= 0; i
< (sint32
)(_NewCSS
.NbCloud
-_OldCSS
.NbCloud
); ++i
)
521 CCloud
&c
= _AllClouds
[_OldCSS
.NbCloud
+i
];
523 _CloudPower
[_OldCSS
.NbCloud
+i
] = 0;
529 float inter
= (float)(_TimeNewCSS
/ _NewCSS
.TimeToChange
);
530 _CurrentCSS
.WindSpeed
= (_NewCSS
.WindSpeed
- _OldCSS
.WindSpeed
)*inter
+ _OldCSS
.WindSpeed
;
531 _CurrentCSS
.CloudSpeed
= (_NewCSS
.CloudSpeed
- _OldCSS
.CloudSpeed
)*inter
+ _OldCSS
.CloudSpeed
;
533 _CurrentCSS
.Ambient
.R
= (uint8
)((_NewCSS
.Ambient
.R
- _OldCSS
.Ambient
.R
)*inter
+ _OldCSS
.Ambient
.R
);
534 _CurrentCSS
.Ambient
.G
= (uint8
)((_NewCSS
.Ambient
.G
- _OldCSS
.Ambient
.G
)*inter
+ _OldCSS
.Ambient
.G
);
535 _CurrentCSS
.Ambient
.B
= (uint8
)((_NewCSS
.Ambient
.B
- _OldCSS
.Ambient
.B
)*inter
+ _OldCSS
.Ambient
.B
);
536 _CurrentCSS
.Ambient
.A
= (uint8
)((_NewCSS
.Ambient
.A
- _OldCSS
.Ambient
.A
)*inter
+ _OldCSS
.Ambient
.A
);
538 _CurrentCSS
.Diffuse
.R
= (uint8
)((_NewCSS
.Diffuse
.R
- _OldCSS
.Diffuse
.R
)*inter
+ _OldCSS
.Diffuse
.R
);
539 _CurrentCSS
.Diffuse
.G
= (uint8
)((_NewCSS
.Diffuse
.G
- _OldCSS
.Diffuse
.G
)*inter
+ _OldCSS
.Diffuse
.G
);
540 _CurrentCSS
.Diffuse
.B
= (uint8
)((_NewCSS
.Diffuse
.B
- _OldCSS
.Diffuse
.B
)*inter
+ _OldCSS
.Diffuse
.B
);
541 _CurrentCSS
.Diffuse
.A
= (uint8
)((_NewCSS
.Diffuse
.A
- _OldCSS
.Diffuse
.A
)*inter
+ _OldCSS
.Diffuse
.A
);
543 if (_NewCSS
.NbCloud
> _OldCSS
.NbCloud
)
546 float slice
= (_NewCSS
.TimeToChange
/4) / (_NewCSS
.NbCloud
-_OldCSS
.NbCloud
);
547 sint32 diffCloud
= _NewCSS
.NbCloud
-_OldCSS
.NbCloud
;
549 _CurrentCSS
.NbCloud
= _OldCSS
.NbCloud
+ (1+(uint32
)(_TimeNewCSS
/slice
));
550 if (_CurrentCSS
.NbCloud
> _NewCSS
.NbCloud
)
551 _CurrentCSS
.NbCloud
= _NewCSS
.NbCloud
;
553 for (i
= 0; i
< diffCloud
; ++i
)
555 _ShouldProcessCloud
[_OldCSS
.NbCloud
+i
] = true;
556 if (_TimeNewCSS
< i
*slice
)
557 _CloudPower
[_OldCSS
.NbCloud
+i
] = 1;
558 else if (_TimeNewCSS
> (i
*slice
+3*_NewCSS
.TimeToChange
/4))
559 _CloudPower
[_OldCSS
.NbCloud
+i
] = 255;
561 _CloudPower
[_OldCSS
.NbCloud
+i
] = (uint8
)(255*(_TimeNewCSS
-i
*slice
)/(3*_NewCSS
.TimeToChange
/4));
566 // Remove some clouds
567 sint32 diffCloud
= _OldCSS
.NbCloud
-_NewCSS
.NbCloud
;
570 float slice
= (_NewCSS
.TimeToChange
/4) / (float)diffCloud
;
571 _CurrentCSS
.NbCloud
= _OldCSS
.NbCloud
;
573 for (i
= 0; i
< diffCloud
; ++i
)
575 if (_TimeNewCSS
< i
*slice
)
576 _CloudPower
[_OldCSS
.NbCloud
-i
-1] = 255;
577 else if (_TimeNewCSS
> (i
*slice
+3*_NewCSS
.TimeToChange
/4))
578 _CloudPower
[_OldCSS
.NbCloud
-i
-1] = 0;
580 _CloudPower
[_OldCSS
.NbCloud
-i
-1] = (uint8
)(255-255*(_TimeNewCSS
-i
*slice
)/(3*_NewCSS
.TimeToChange
/4));
586 // Make the right number of half cloud
589 while (_DTRest
> (0.04/_NbHalfCloudToUpdate
))
592 _DTRest
-= 0.04/_NbHalfCloudToUpdate
;
594 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
596 CCloud
&c
= _AllClouds
[i
];
597 c
.Time
+= 0.04/_NbHalfCloudToUpdate
;
600 _TimeNewCSS
+= 0.04/_NbHalfCloudToUpdate
;
604 _Driver
->enableFog (fog
);
606 // Has the driver been reseted ?
607 if (_ResetCounter
!= _Driver
->getResetCounter())
609 /* Yes. Force the rebuild of all the clouds not setuped in VRAM */
610 _ResetCounter
= _Driver
->getResetCounter();
612 while (i
< MAX_CLOUDS
)
614 while (_ShouldProcessCloud
[i
] &&
615 (!_AllClouds
[i
]._TexBill
->setupedIntoDriver() || !_AllClouds
[i
]._TexOldBill
->setupedIntoDriver()))
617 // Force a cloudscape rebuild
618 anim (41.0/1000.0, _ViewerCam
);
623 double endDate
= double(CTime::getLocalTime())/1000.0;
624 _LastAnimRenderTime
= endDate
- startDate
;
627 // ------------------------------------------------------------------------------------------------
628 void CCloudScape::makeHalfCloud ()
630 CVector Viewer
= CVector(0,0,0); //_ViewerCam->getMatrix().getPos();
634 // Find the next cloud in the list
635 SCloudSchedulerEntry FrontCSE
;
637 FrontCSE
= _CloudScheduler
.front();
639 // Is the cloud do not have another reference in the list add it now because it should be processed
640 sint32 CloudIndexToAdd
= -1;
642 if ((FrontCSE
.CloudIndex
!= -1) &&
643 (_ShouldProcessCloud
[FrontCSE
.CloudIndex
] == true) &&
644 ( (_CloudSchedulerLastAdded
[FrontCSE
.CloudIndex
].ValidPos
== false) ||
645 ((_CloudSchedulerLastAdded
[FrontCSE
.CloudIndex
].ValidPos
== true) &&
646 (_CloudSchedulerLastAdded
[FrontCSE
.CloudIndex
].Pos
== _CloudScheduler
.begin()))
649 // It should be added now !
650 CloudIndexToAdd
= FrontCSE
.CloudIndex
;
651 FrontCSE
.DeltaNextCalc
= QUEUE_SIZE
;
653 else if (_CurrentCSS
.NbCloud
!= 0)
655 // Choose a Cloud Index To Add at the end of the list
656 uint32 nPeriodeMax
= _CurrentCSS
.NbCloud
+_CurrentCSS
.NbCloud
/10;
657 sint32 Priority
= -10000;
660 float sumPrior
= 0.0f
;
661 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
662 if (_ShouldProcessCloud
[i
])
664 CCloud
&rC
= _AllClouds
[i
];
665 float ExtrapolatedTime
= ((0.04f
/_NbHalfCloudToUpdate
) * QUEUE_SIZE
* 2);
666 float x
= rC
.getLastX () + ExtrapolatedTime
* _CurrentCSS
.WindSpeed
;
667 //float d = sqrtf(SQR(x+rC.getSizeX()/2-Viewer.x)+SQR(rC.getY()+rC.getSizeY()/2-Viewer.y)+
668 // SQR(rC.getZ()+rC.getSizeZ()/2-Viewer.z));
669 float d
= SQR(x
+rC
.getSizeX()/2-Viewer
.x
)+SQR(rC
.getY()+rC
.getSizeY()/2-Viewer
.y
)+
670 SQR(rC
.getZ()+rC
.getSizeZ()/2-Viewer
.z
);
671 float d05
= sqrtf(d
);
672 float d025
= sqrtf(d05
);
673 float d075
= d05
*d025
;
675 _ExtrapolatedPriorities
[i
] = 1.0f
/ d075
;
676 sumPrior
+= _ExtrapolatedPriorities
[i
];
680 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
681 if (_ShouldProcessCloud
[i
])
683 // Normalize priorities
684 float factor
= ((float)QUEUE_SIZE
) / sumPrior
;
685 sint32 nbJeton
= (sint32
)(0.5f
+(factor
* _ExtrapolatedPriorities
[i
]));
690 _ExtrapolatedPriorities
[i
] = (float)nbJeton
;
694 if (sumJeton
> QUEUE_SIZE
)
698 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
699 if (_ShouldProcessCloud
[i
])
701 if (_ExtrapolatedPriorities
[i
] > 1)
703 _ExtrapolatedPriorities
[i
] -= 1;
705 if (sumJeton
== QUEUE_SIZE
) break;
709 while (sumJeton
> QUEUE_SIZE
);
712 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
713 if (_ShouldProcessCloud
[i
])
716 sint32 newPriority
= nPeriodeMax
;
717 // Is there a last entry in array ?
718 if (_CloudSchedulerLastAdded
[i
].ValidPos
== true)
720 SCloudSchedulerEntry
&rLastCSE
= *_CloudSchedulerLastAdded
[i
].Pos
;
721 newPriority
= (sint32
)(QUEUE_SIZE
/_ExtrapolatedPriorities
[i
]);
722 newPriority
= (_FrameCounter
- rLastCSE
.Frame
) - newPriority
;
728 if (newPriority
> Priority
)
730 Priority
= newPriority
;
734 nlassert (CloudIndexToAdd
!= -1);
737 // Ok now we have a good cloud index to add so make the new cloud entry
738 SCloudSchedulerEntry newCSE
;
740 newCSE
.CloudIndex
= CloudIndexToAdd
;
741 newCSE
.Frame
= _FrameCounter
;
742 newCSE
.Ambient
= _CurrentCSS
.Ambient
;
743 newCSE
.Diffuse
= _CurrentCSS
.Diffuse
;
744 if (CloudIndexToAdd
!= -1)
746 newCSE
.Power
= _CloudPower
[CloudIndexToAdd
];
748 // If the cloud where added previously to the list
749 if (_CloudSchedulerLastAdded
[CloudIndexToAdd
].ValidPos
== true)
751 // This means that the cloud were added from a long time ago
752 SCloudSchedulerEntry
&lastCSE
= *_CloudSchedulerLastAdded
[CloudIndexToAdd
].Pos
;
753 sint32 delta
= _FrameCounter
- lastCSE
.Frame
;
754 lastCSE
.DeltaNextCalc
= delta
;
756 // But the cloud can be removed (if so we have to not process it anymore)
757 if (newCSE
.Power
== 0)
758 _ShouldProcessCloud
[CloudIndexToAdd
] = false;
762 // No the cloud do not appear previously in the list... So its a new one
763 _AllClouds
[CloudIndexToAdd
].reset (_ViewerCam
);
766 // If the last cloud occurence of the cloud appear at beginning so no more occurence in list
767 if (_CloudSchedulerLastAdded
[FrontCSE
.CloudIndex
].Pos
== _CloudScheduler
.begin())
768 _CloudSchedulerLastAdded
[FrontCSE
.CloudIndex
].ValidPos
= false;
770 _CloudSchedulerLastAdded
[CloudIndexToAdd
].Pos
= _CloudScheduler
.insert(_CloudScheduler
.end(), newCSE
);
771 _CloudSchedulerLastAdded
[CloudIndexToAdd
].ValidPos
= true;
772 //_CloudSchedulerLastAdded[CloudIndexToAdd].Pos = _CloudScheduler.end()-1;
776 _CloudScheduler
.insert(_CloudScheduler
.end(), newCSE
);
778 _CloudScheduler
.pop_front ();
782 // Get the cloud to process (this must be the next occurence of front cloud)
783 std::list
<SCloudSchedulerEntry
>::iterator it
= _CloudScheduler
.begin();
784 while (it
!= _CloudScheduler
.end())
786 SCloudSchedulerEntry
&rCSE
= *it
;
787 if (rCSE
.CloudIndex
== FrontCSE
.CloudIndex
)
792 SCloudSchedulerEntry CSEToCalc
;
793 // The cloud is no more present in the list
794 if (it
== _CloudScheduler
.end())
796 FrontCSE
.DeltaNextCalc
= 1;
797 CSEToCalc
= FrontCSE
;
804 // Is the cloud to calc is a real cloud
805 if (CSEToCalc
.CloudIndex
== -1)
807 _CurrentCloudInProcess
= NULL
;
811 _CurrentCloudInProcess
= &_AllClouds
[CSEToCalc
.CloudIndex
];
812 CCloud
&c
= *_CurrentCloudInProcess
;
814 // To go from Front cloud to CSEToCalc cloud we should take the front DeltaNextCalc
816 _CurrentCloudInProcessFuturTime
= ((0.04/_NbHalfCloudToUpdate
) * FrontCSE
.DeltaNextCalc
* 2);
817 c
.setX ((float)(c
.getLastX() + _CurrentCloudInProcessFuturTime
* _CurrentCSS
.WindSpeed
));
819 float d2D
= sqrtf(SQR(c
.getX()+c
.getSizeX()/2-Viewer
.x
)+SQR(c
.getY()+c
.getSizeY()/2-Viewer
.y
));
822 c
.CloudDistAtt
= 255;
823 else if (d2D
> (MAX_DIST
-100.0f
))
824 c
.CloudDistAtt
= (uint8
)(255*((d2D
-(MAX_DIST
-100.0f
))/100.0f
));
828 c
.LastCloudPower
= c
.CloudPower
;
829 c
.CloudPower
= CSEToCalc
.Power
;
830 c
.CloudDiffuse
= CSEToCalc
.Diffuse
;
831 c
.CloudAmbient
= CSEToCalc
.Ambient
;
833 c
.anim (_CurrentCloudInProcessFuturTime
*_CurrentCSS
.CloudSpeed
,
834 _CurrentCloudInProcessFuturTime
*_CurrentCSS
.WindSpeed
);
836 c
.generate (_Noise3D
);
841 if (_CurrentCloudInProcess
!= NULL
)
843 CCloud
&c
= *_CurrentCloudInProcess
;
846 c
.FuturTime
= _CurrentCloudInProcessFuturTime
;
849 if (c
.getX() > MAX_DIST
)
851 c
.setX (c
.getX() - (2 * MAX_DIST
));
855 float r
= sqrtf(SQR(c
.getSizeX()/2)+SQR(c
.getSizeY()/2)+SQR(c
.getSizeZ()/2));
856 float d
= sqrtf(SQR(c
.getX()+c
.getSizeX()/2-Viewer
.x
)+SQR(c
.getY()+c
.getSizeY()/2-Viewer
.y
)+
857 SQR(c
.getZ()+c
.getSizeZ()/2-Viewer
.z
));
858 uint32 lookAtSize
= (uint32
)(_LODQualityThreshold
*r
/d
);
859 lookAtSize
= raiseToNextPowerOf2 (lookAtSize
);
860 if (lookAtSize
> 128) lookAtSize
= 128;
862 c
.genBill (_ViewerCam
, lookAtSize
);
865 _Generate
= !_Generate
;
868 // ------------------------------------------------------------------------------------------------
869 void CCloudScape::render ()
873 CVector Viewer
= CVector (0,0,0);
876 bool fog
= _Driver
->fogEnabled();
877 _Driver
->enableFog (false);
880 viewMat
= _ViewerCam
->getMatrix ();
881 viewMat
.setPos(CVector(0,0,0));
885 _Driver
->setupScissor (s
);
887 _Driver
->setupViewport (v
);
888 CFrustum f
= _ViewerCam
->getFrustum();
889 _Driver
->setFrustum (f
.Left
, f
.Right
, f
.Bottom
, f
.Top
, f
.Near
, f
.Far
, f
.Perspective
);
890 _Driver
->setupViewMatrix (viewMat
);
891 _Driver
->setupModelMatrix (CMatrix::Identity
);
893 uint32 nNbCloudToRender
= 0;
895 for (i
= 0; i
< MAX_CLOUDS
; ++i
)
897 CCloud
&c
= _AllClouds
[i
];
898 SSortedCloudEntry
&sce
= _SortedClouds
[nNbCloudToRender
];
900 sce
.Distance
= sqrtf(SQR(c
.getX()+c
.getSizeX()/2-Viewer
.x
)+SQR(c
.getY()+c
.getSizeY()/2-Viewer
.y
)+
901 SQR(c
.getZ()+c
.getSizeZ()/2-Viewer
.z
));
905 for (i
= 0; i
< nNbCloudToRender
-1; ++i
)
906 for (j
= i
+1; j
< nNbCloudToRender
; ++j
)
908 if (_SortedClouds
[i
].Distance
< _SortedClouds
[j
].Distance
)
910 SSortedCloudEntry sceTmp
= _SortedClouds
[i
];
911 _SortedClouds
[i
] = _SortedClouds
[j
];
912 _SortedClouds
[j
] = sceTmp
;
916 for (i
= 0; i
< nNbCloudToRender
; ++i
)
918 CCloud
*pC
= _SortedClouds
[i
].Cloud
;
919 if ((pC
->CloudPower
> 0) || (pC
->LastCloudPower
> 0))
920 pC
->dispBill (_ViewerCam
);
924 _Driver
->enableFog (fog
);
927 // ------------------------------------------------------------------------------------------------
928 uint32
CCloudScape::getMemSize()
931 for (uint32 i
= 0; i
< MAX_CLOUDS
; ++i
)
933 CCloud
&c
= _AllClouds
[i
];
934 nMemSize
+= c
.getMemSize();