Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / cloud_scape.cpp
blob5c40d89ecde4ee59508fd9c1b7272efb8b990662
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
17 #include "std3d.h"
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;
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NL3D
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 // ------------------------------------------------------------------------------------------------
47 // SCloudTexture3D
48 // ------------------------------------------------------------------------------------------------
50 // ------------------------------------------------------------------------------------------------
51 SCloudTexture3D::SCloudTexture3D ()
53 Mem = NULL;
54 Mem2 = NULL;
55 MemBuffer = NULL;
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));
77 ToBill.initUnlit();
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);
99 MatCopy.initUnlit();
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)
114 if (Mem != NULL)
115 return;
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);
124 else
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);
139 Tex->generate ();
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);
145 Tex2->generate ();
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 ()
167 Mem = NULL;
168 ToClamp.initUnlit();
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)
184 if (Mem != NULL)
185 return;
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);
194 else
195 NbH = 1 << (vdpo2 / 2);
197 Mem = new uint8[NbW*Width*NbH*Height];
198 uint32 i, j;
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)
207 uint32 d = i+j*NbW;
208 uint32 k, l;
209 for (k = 0; k < Width; ++k)
210 for (l = 0; l < Height; ++l)
212 float x = k+0.5f;
213 float y = l+0.5f;
214 float z = d+0.5f;
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);
222 uint8 col = 255;
223 if (r < 1.0f)
225 col = (uint8)((r)*223+32);
227 Mem[i*Width+k + (j*Height+l)*NbW*Width] = col;
232 else
234 // Load file TODO !
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);
242 Tex->touch();
243 Tex->setReleasable (false);
244 Tex->generate();
246 ToClamp.setTexture(0, Tex);
251 // ------------------------------------------------------------------------------------------------
252 // CCloudScape
253 // ------------------------------------------------------------------------------------------------
255 // ------------------------------------------------------------------------------------------------
256 CCloudScape::CCloudScape (NL3D::IDriver *pDriver) : _Noise3D (pDriver)
258 _Driver = pDriver;
259 // Misc purpose VB
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;
298 _DebugQuad = 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;
317 _Noise3D.init();
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,"");
327 if (pCSS != NULL)
329 _CurrentCSS = *pCSS;
330 _NewCSS = *pCSS;
331 _OldCSS = *pCSS;
333 _IsIncomingCSS = false;
334 _TimeNewCSS = 60.0*60.0;
336 uint32 i;
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);
346 for(;;)
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;
357 newSizeX *= 1.5f*f;
358 newSizeY *= 1.5f*f;
359 newSizeZ *= 1.5f*f;
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)))
371 bRecalc = true;
373 if (!bRecalc) break;
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);
385 c.Time = 0;
386 c.FuturTime = _CurrentCSS.NbCloud * 2 * (0.04/_NbHalfCloudToUpdate);
387 if (i < _CurrentCSS.NbCloud)
389 _CloudPower[i] = 255;
390 _ShouldProcessCloud[i] = true;
392 else
394 _CloudPower[i] = 0;
395 _ShouldProcessCloud[i] = false;
399 _SortedClouds.resize (MAX_CLOUDS);
401 _CloudSchedulerSize = _CurrentCSS.NbCloud;
402 _CloudSchedulerLastAdded.resize (MAX_CLOUDS);
403 _FrameCounter = 0;
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;
413 cse.CloudIndex = -1;
414 cse.Frame = _FrameCounter;
415 cse.Ambient = _CurrentCSS.Ambient;
416 cse.Diffuse = _CurrentCSS.Diffuse;
417 _CloudScheduler.insert(_CloudScheduler.end(), cse);
418 ++_FrameCounter;
421 else
423 for (i = 0; i < QUEUE_SIZE; ++i)
425 sint32 nCloudNb;
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;
442 ++_FrameCounter;
446 _GlobalTime = 0.0f;
447 _DTRest = 0.0f;
448 _Generate = true;
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)
462 _IncomingCSS = css;
463 _IsIncomingCSS = true;
466 // ------------------------------------------------------------------------------------------------
467 void CCloudScape::anim (double dt, NL3D::CCamera *pCamera)
469 double startDate = double(CTime::getLocalTime())/1000.0;
470 sint32 i;
472 // Disable fog
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);
491 else
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);
499 // 10 fps -> 200 fps
500 if (dt > _MaxDeltaTime) dt = _MaxDeltaTime;
501 if (dt < MIN_CLOUDS_ANIM_DELTA_TIME) dt = MIN_CLOUDS_ANIM_DELTA_TIME;
504 _DeltaTime = dt;
505 _GlobalTime += _DeltaTime;
506 _AverageFrameRate.addValue ((float)_DeltaTime);
508 // Animate the CSS
509 if (_TimeNewCSS > _NewCSS.TimeToChange)
511 _CurrentCSS = _NewCSS;
512 _OldCSS = _NewCSS;
513 if (_IsIncomingCSS)
515 _IsIncomingCSS = false;
516 _NewCSS = _IncomingCSS;
517 _TimeNewCSS = 0;
518 if (_NewCSS.NbCloud > _OldCSS.NbCloud)
519 for (i = 0; i < (sint32)(_NewCSS.NbCloud-_OldCSS.NbCloud); ++i)
521 CCloud &c = _AllClouds[_OldCSS.NbCloud+i];
522 c.CloudPower = 0;
523 _CloudPower[_OldCSS.NbCloud+i] = 0;
527 else
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)
545 // Add some clouds
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;
560 else
561 _CloudPower[_OldCSS.NbCloud+i] = (uint8)(255*(_TimeNewCSS-i*slice)/(3*_NewCSS.TimeToChange/4));
564 else
566 // Remove some clouds
567 sint32 diffCloud = _OldCSS.NbCloud-_NewCSS.NbCloud;
568 if (diffCloud)
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;
579 else
580 _CloudPower[_OldCSS.NbCloud-i-1] = (uint8)(255-255*(_TimeNewCSS-i*slice)/(3*_NewCSS.TimeToChange/4));
586 // Make the right number of half cloud
587 _DTRest += dt;
589 while (_DTRest > (0.04/_NbHalfCloudToUpdate))
591 makeHalfCloud ();
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;
603 // Backup fog
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();
611 i = 0;
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);
620 i++;
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();
632 if (_Generate)
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;
658 uint32 i;
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];
679 sint32 sumJeton = 0;
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]));
687 if (nbJeton < 1)
688 nbJeton = 1;
690 _ExtrapolatedPriorities[i] = (float)nbJeton;
691 sumJeton += 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;
704 --sumJeton;
705 if (sumJeton == QUEUE_SIZE) break;
709 while (sumJeton > QUEUE_SIZE);
712 for (i = 0; i < MAX_CLOUDS; ++i)
713 if (_ShouldProcessCloud[i])
715 // Cloud Period
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;
724 else
726 newPriority = 10000;
728 if (newPriority > Priority)
730 Priority = newPriority;
731 CloudIndexToAdd = i;
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;
760 else
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;
774 else
776 _CloudScheduler.insert(_CloudScheduler.end(), newCSE);
778 _CloudScheduler.pop_front ();
779 ++_FrameCounter;
780 // End of scheduling
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)
788 break;
789 ++it;
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;
799 else
801 CSEToCalc = *it;
804 // Is the cloud to calc is a real cloud
805 if (CSEToCalc.CloudIndex == -1)
807 _CurrentCloudInProcess = NULL;
809 else
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));
821 if (d2D > MAX_DIST)
822 c.CloudDistAtt = 255;
823 else if (d2D > (MAX_DIST-100.0f))
824 c.CloudDistAtt = (uint8)(255*((d2D-(MAX_DIST-100.0f))/100.0f));
825 else
826 c.CloudDistAtt = 0;
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);
839 else
841 if (_CurrentCloudInProcess != NULL)
843 CCloud &c = *_CurrentCloudInProcess;
845 c.Time = 0;
846 c.FuturTime = _CurrentCloudInProcessFuturTime;
847 c.light();
849 if (c.getX() > MAX_DIST)
851 c.setX (c.getX() - (2 * MAX_DIST));
852 c.setLooping ();
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 ()
871 uint32 i, j;
873 CVector Viewer = CVector (0,0,0);
875 // Disable fog
876 bool fog = _Driver->fogEnabled();
877 _Driver->enableFog (false);
879 CMatrix viewMat;
880 viewMat = _ViewerCam->getMatrix ();
881 viewMat.setPos(CVector(0,0,0));
882 viewMat.invert ();
883 CScissor s;
884 s.initFullScreen ();
885 _Driver->setupScissor (s);
886 CViewport v;
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];
899 sce.Cloud = &c;
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));
902 nNbCloudToRender++;
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);
923 // Backup fog
924 _Driver->enableFog (fog);
927 // ------------------------------------------------------------------------------------------------
928 uint32 CCloudScape::getMemSize()
930 uint32 nMemSize = 0;
931 for (uint32 i = 0; i < MAX_CLOUDS; ++i)
933 CCloud &c = _AllClouds[i];
934 nMemSize += c.getMemSize();
936 return nMemSize;
939 } // namespace NL3D