diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llvosky.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llvosky.cpp | 2448 |
1 files changed, 2448 insertions, 0 deletions
diff --git a/linden/indra/newview/llvosky.cpp b/linden/indra/newview/llvosky.cpp new file mode 100644 index 0000000..927b784 --- /dev/null +++ b/linden/indra/newview/llvosky.cpp | |||
@@ -0,0 +1,2448 @@ | |||
1 | /** | ||
2 | * @file llvosky.cpp | ||
3 | * @brief LLVOSky class implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llvosky.h" | ||
31 | |||
32 | #include "imageids.h" | ||
33 | #include "llviewercontrol.h" | ||
34 | #include "llframetimer.h" | ||
35 | #include "timing.h" | ||
36 | |||
37 | #include "llagent.h" | ||
38 | #include "lldrawable.h" | ||
39 | #include "llface.h" | ||
40 | #include "llcubemap.h" | ||
41 | #include "lldrawpoolsky.h" | ||
42 | #include "lldrawpoolwater.h" | ||
43 | #include "llglheaders.h" | ||
44 | #include "llsky.h" | ||
45 | #include "llviewercamera.h" | ||
46 | #include "llviewerimagelist.h" | ||
47 | #include "llviewerobjectlist.h" | ||
48 | #include "llviewerregion.h" | ||
49 | #include "llworld.h" | ||
50 | #include "pipeline.h" | ||
51 | #include "viewer.h" // for gSunTextureID | ||
52 | |||
53 | const S32 NUM_TILES_X = 8; | ||
54 | const S32 NUM_TILES_Y = 4; | ||
55 | const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y; | ||
56 | |||
57 | // Heavenly body constants | ||
58 | const F32 SUN_DISK_RADIUS = 0.5f; | ||
59 | const F32 MOON_DISK_RADIUS = SUN_DISK_RADIUS * 0.9f; | ||
60 | const F32 SUN_INTENSITY = 1e5; | ||
61 | const F32 SUN_DISK_INTENSITY = 24.f; | ||
62 | |||
63 | |||
64 | // Texture coordinates: | ||
65 | const LLVector2 TEX00 = LLVector2(0.f, 0.f); | ||
66 | const LLVector2 TEX01 = LLVector2(0.f, 1.f); | ||
67 | const LLVector2 TEX10 = LLVector2(1.f, 0.f); | ||
68 | const LLVector2 TEX11 = LLVector2(1.f, 1.f); | ||
69 | |||
70 | //static | ||
71 | LLColor3 LLHaze::sAirScaSeaLevel; | ||
72 | |||
73 | class LLFastLn | ||
74 | { | ||
75 | public: | ||
76 | LLFastLn() | ||
77 | { | ||
78 | mTable[0] = 0; | ||
79 | for( S32 i = 1; i < 257; i++ ) | ||
80 | { | ||
81 | mTable[i] = log((F32)i); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | F32 ln( F32 x ) | ||
86 | { | ||
87 | const F32 OO_255 = 0.003921568627450980392156862745098f; | ||
88 | const F32 LN_255 = 5.5412635451584261462455391880218f; | ||
89 | |||
90 | if( x < OO_255 ) | ||
91 | { | ||
92 | return log(x); | ||
93 | } | ||
94 | else | ||
95 | if( x < 1 ) | ||
96 | { | ||
97 | x *= 255.f; | ||
98 | S32 index = llfloor(x); | ||
99 | F32 t = x - index; | ||
100 | F32 low = mTable[index]; | ||
101 | F32 high = mTable[index + 1]; | ||
102 | return low + t * (high - low) - LN_255; | ||
103 | } | ||
104 | else | ||
105 | if( x <= 255 ) | ||
106 | { | ||
107 | S32 index = llfloor(x); | ||
108 | F32 t = x - index; | ||
109 | F32 low = mTable[index]; | ||
110 | F32 high = mTable[index + 1]; | ||
111 | return low + t * (high - low); | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | return log( x ); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | F32 pow( F32 x, F32 y ) | ||
120 | { | ||
121 | return (F32)LL_FAST_EXP(y * ln(x)); | ||
122 | } | ||
123 | |||
124 | |||
125 | private: | ||
126 | F32 mTable[257]; // index 0 is unused | ||
127 | }; | ||
128 | |||
129 | LLFastLn gFastLn; | ||
130 | |||
131 | |||
132 | // Functions used a lot. | ||
133 | |||
134 | inline F32 LLHaze::calcPhase(const F32 cos_theta) const | ||
135 | { | ||
136 | const F32 g2 = mG * mG; | ||
137 | const F32 den = 1 + g2 - 2 * mG * cos_theta; | ||
138 | return (1 - g2) * gFastLn.pow(den, -1.5); | ||
139 | } | ||
140 | |||
141 | inline void color_pow(LLColor3 &col, const F32 e) | ||
142 | { | ||
143 | col.mV[0] = gFastLn.pow(col.mV[0], e); | ||
144 | col.mV[1] = gFastLn.pow(col.mV[1], e); | ||
145 | col.mV[2] = gFastLn.pow(col.mV[2], e); | ||
146 | } | ||
147 | |||
148 | inline LLColor3 color_norm(const LLColor3 &col) | ||
149 | { | ||
150 | const F32 m = color_max(col); | ||
151 | if (m > 1.f) | ||
152 | { | ||
153 | return 1.f/m * col; | ||
154 | } | ||
155 | else return col; | ||
156 | } | ||
157 | |||
158 | inline LLColor3 color_norm_fog(const LLColor3 &col) | ||
159 | { | ||
160 | const F32 m = color_max(col); | ||
161 | if (m > 0.75f) | ||
162 | { | ||
163 | return 0.75f/m * col; | ||
164 | } | ||
165 | else return col; | ||
166 | } | ||
167 | |||
168 | |||
169 | inline LLColor4 color_norm_abs(const LLColor4 &col) | ||
170 | { | ||
171 | const F32 m = color_max(col); | ||
172 | if (m > 1e-6) | ||
173 | { | ||
174 | return 1.f/m * col; | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | return col; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | |||
183 | inline F32 color_intens ( const LLColor4 &col ) | ||
184 | { | ||
185 | return col.mV[0] + col.mV[1] + col.mV[2]; | ||
186 | } | ||
187 | |||
188 | |||
189 | inline F32 color_avg ( const LLColor3 &col ) | ||
190 | { | ||
191 | return color_intens(col) / 3; | ||
192 | } | ||
193 | |||
194 | inline void color_gamma_correct(LLColor3 &col) | ||
195 | { | ||
196 | const F32 gamma_inv = 1.f/1.2f; | ||
197 | if (col.mV[0] != 0.f) | ||
198 | { | ||
199 | col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv); | ||
200 | } | ||
201 | if (col.mV[1] != 0.f) | ||
202 | { | ||
203 | col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv); | ||
204 | } | ||
205 | if (col.mV[2] != 0.f) | ||
206 | { | ||
207 | col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | inline F32 min_intens_factor( LLColor3& col, F32 min_intens, BOOL postmultiply = FALSE); | ||
212 | inline F32 min_intens_factor( LLColor3& col, F32 min_intens, BOOL postmultiply) | ||
213 | { | ||
214 | const F32 intens = color_intens(col); | ||
215 | F32 factor = 1; | ||
216 | if (0 == intens) | ||
217 | { | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | if (intens < min_intens) | ||
222 | { | ||
223 | factor = min_intens / intens; | ||
224 | if (postmultiply) | ||
225 | col *= factor; | ||
226 | } | ||
227 | return factor; | ||
228 | } | ||
229 | |||
230 | inline LLVector3 move_vec(const LLVector3& v, const F32 cos_max_angle) | ||
231 | { | ||
232 | LLVector3 v_norm = v; | ||
233 | v_norm.normVec(); | ||
234 | |||
235 | LLVector2 v_norm_proj(v_norm.mV[0], v_norm.mV[1]); | ||
236 | const F32 projection2 = v_norm_proj.magVecSquared(); | ||
237 | const F32 scale = sqrt((1 - cos_max_angle * cos_max_angle) / projection2); | ||
238 | return LLVector3(scale * v_norm_proj.mV[0], scale * v_norm_proj.mV[1], cos_max_angle); | ||
239 | } | ||
240 | |||
241 | |||
242 | /*************************************** | ||
243 | Transparency Map | ||
244 | ***************************************/ | ||
245 | |||
246 | void LLTranspMap::init(const F32 elev, const F32 step, const F32 h, const LLHaze* const haze) | ||
247 | { | ||
248 | mHaze = haze; | ||
249 | mAtmHeight = h; | ||
250 | mElevation = elev; | ||
251 | mStep = step; | ||
252 | mStepInv = 1.f / step; | ||
253 | F32 sin_angle = EARTH_RADIUS/(EARTH_RADIUS + mElevation); | ||
254 | mCosMaxAngle = -sqrt(1 - sin_angle * sin_angle); | ||
255 | mMapSize = S32(ceil((1 - mCosMaxAngle) * mStepInv + 1) + 0.5); | ||
256 | delete mT; | ||
257 | mT = new LLColor3[mMapSize]; | ||
258 | |||
259 | for (S32 i = 0; i < mMapSize; ++i) | ||
260 | { | ||
261 | const F32 cos_a = 1 - i*mStep; | ||
262 | const LLVector3 dir(0, sqrt(1-cos_a*cos_a), cos_a); | ||
263 | mT[i] = calcAirTranspDir(mElevation, dir); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | |||
268 | |||
269 | LLColor3 LLTranspMap::calcAirTranspDir(const F32 elevation, const LLVector3 &dir) const | ||
270 | { | ||
271 | LLColor3 opt_depth(0, 0, 0); | ||
272 | const LLVector3 point(0, 0, EARTH_RADIUS + elevation); | ||
273 | F32 dist = -dir * point; | ||
274 | LLVector3 cur_point; | ||
275 | S32 s; | ||
276 | |||
277 | if (dist > 0) | ||
278 | { | ||
279 | cur_point = point + dist * dir; | ||
280 | // const F32 K = log(dist * INV_FIRST_STEP + 1) * INV_NO_STEPS; | ||
281 | // const F32 e_pow_k = LL_FAST_EXP(K); | ||
282 | const F32 e_pow_k = gFastLn.pow( dist * INV_FIRST_STEP + 1, INV_NO_STEPS ); | ||
283 | F32 step = FIRST_STEP * (1 - 1 / e_pow_k); | ||
284 | |||
285 | for (s = 0; s < NO_STEPS; ++s) | ||
286 | { | ||
287 | const F32 h = cur_point.magVec() - EARTH_RADIUS; | ||
288 | step *= e_pow_k; | ||
289 | opt_depth += calcSigExt(h) * step; | ||
290 | cur_point -= dir * step; | ||
291 | } | ||
292 | opt_depth *= 2; | ||
293 | cur_point = point + 2 * dist * dir; | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | cur_point = point; | ||
298 | } | ||
299 | |||
300 | dist = hitsAtmEdge(cur_point, dir); | ||
301 | // const F32 K = log(dist * INV_FIRST_STEP + 1) * INV_NO_STEPS; | ||
302 | // const F32 e_pow_k = LL_FAST_EXP(K); | ||
303 | const F32 e_pow_k = gFastLn.pow( dist * INV_FIRST_STEP + 1, INV_NO_STEPS ); | ||
304 | F32 step = FIRST_STEP * (1 - 1 / e_pow_k); | ||
305 | |||
306 | for (s = 0; s < NO_STEPS; ++s) | ||
307 | { | ||
308 | const F32 h = cur_point.magVec() - EARTH_RADIUS; | ||
309 | step *= e_pow_k; | ||
310 | opt_depth += calcSigExt(h) * step; | ||
311 | cur_point += dir * step; | ||
312 | } | ||
313 | |||
314 | opt_depth *= -4.0f*F_PI; | ||
315 | opt_depth.exp(); | ||
316 | return opt_depth; | ||
317 | } | ||
318 | |||
319 | |||
320 | |||
321 | F32 LLTranspMap::hitsAtmEdge(const LLVector3& X, const LLVector3& dir) const | ||
322 | { | ||
323 | const F32 tca = -dir * X; | ||
324 | const F32 R = EARTH_RADIUS + mAtmHeight; | ||
325 | const F32 thc2 = R * R - X.magVecSquared() + tca * tca; | ||
326 | return tca + sqrt ( thc2 ); | ||
327 | } | ||
328 | |||
329 | |||
330 | |||
331 | |||
332 | |||
333 | void LLTranspMapSet::init(const S32 size, const F32 first_step, const F32 media_height, const LLHaze* const haze) | ||
334 | { | ||
335 | const F32 angle_step = 0.005f; | ||
336 | mSize = size; | ||
337 | mMediaHeight = media_height; | ||
338 | |||
339 | delete[] mTransp; | ||
340 | mTransp = new LLTranspMap[mSize]; | ||
341 | |||
342 | delete[] mHeights; | ||
343 | mHeights = new F32[mSize]; | ||
344 | |||
345 | F32 h = 0; | ||
346 | mHeights[0] = h; | ||
347 | mTransp[0].init(h, angle_step, mMediaHeight, haze); | ||
348 | const F32 K = log(mMediaHeight / first_step + 1) / (mSize - 1); | ||
349 | const F32 e_pow_k = exp(K); | ||
350 | F32 step = first_step * (e_pow_k - 1); | ||
351 | |||
352 | for (S32 s = 1; s < mSize; ++s) | ||
353 | { | ||
354 | h += step; | ||
355 | mHeights[s] = h; | ||
356 | mTransp[s].init(h, angle_step, mMediaHeight, haze); | ||
357 | step *= e_pow_k; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | LLTranspMapSet::~LLTranspMapSet() | ||
362 | { | ||
363 | delete[] mTransp; | ||
364 | mTransp = NULL; | ||
365 | delete[] mHeights; | ||
366 | mHeights = NULL; | ||
367 | } | ||
368 | |||
369 | |||
370 | |||
371 | /*************************************** | ||
372 | SkyTex | ||
373 | ***************************************/ | ||
374 | |||
375 | S32 LLSkyTex::sComponents = 4; | ||
376 | S32 LLSkyTex::sResolution = 64; | ||
377 | F32 LLSkyTex::sInterpVal = 0.f; | ||
378 | S32 LLSkyTex::sCurrent = 0; | ||
379 | |||
380 | |||
381 | LLSkyTex::LLSkyTex() | ||
382 | { | ||
383 | } | ||
384 | |||
385 | void LLSkyTex::init() | ||
386 | { | ||
387 | mSkyData = new LLColor3[sResolution * sResolution]; | ||
388 | mSkyDirs = new LLVector3[sResolution * sResolution]; | ||
389 | |||
390 | for (S32 i = 0; i < 2; ++i) | ||
391 | { | ||
392 | mImageGL[i] = new LLImageGL(FALSE); | ||
393 | mImageGL[i]->setClamp(TRUE, TRUE); | ||
394 | mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents); | ||
395 | |||
396 | initEmpty(i); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | void LLSkyTex::cleanupGL() | ||
401 | { | ||
402 | mImageGL[0] = NULL; | ||
403 | mImageGL[1] = NULL; | ||
404 | } | ||
405 | |||
406 | void LLSkyTex::restoreGL() | ||
407 | { | ||
408 | for (S32 i = 0; i < 2; i++) | ||
409 | { | ||
410 | mImageGL[i] = new LLImageGL(FALSE); | ||
411 | mImageGL[i]->setClamp(TRUE, TRUE); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | LLSkyTex::~LLSkyTex() | ||
416 | { | ||
417 | delete[] mSkyData; | ||
418 | mSkyData = NULL; | ||
419 | |||
420 | delete[] mSkyDirs; | ||
421 | mSkyDirs = NULL; | ||
422 | } | ||
423 | |||
424 | |||
425 | void LLSkyTex::initEmpty(const S32 tex) | ||
426 | { | ||
427 | U8* data = mImageRaw[tex]->getData(); | ||
428 | for (S32 i = 0; i < sResolution; ++i) | ||
429 | { | ||
430 | for (S32 j = 0; j < sResolution; ++j) | ||
431 | { | ||
432 | const S32 basic_offset = (i * sResolution + j); | ||
433 | S32 offset = basic_offset * sComponents; | ||
434 | data[offset] = 0; | ||
435 | data[offset+1] = 0; | ||
436 | data[offset+2] = 0; | ||
437 | data[offset+3] = 255; | ||
438 | |||
439 | mSkyData[basic_offset].setToBlack(); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | createTexture(tex); | ||
444 | } | ||
445 | |||
446 | |||
447 | void LLSkyTex::create(const F32 brightness_scale, const LLColor3& multiscatt) | ||
448 | { | ||
449 | U8* data = mImageRaw[sCurrent]->getData(); | ||
450 | for (S32 i = 0; i < sResolution; ++i) | ||
451 | { | ||
452 | for (S32 j = 0; j < sResolution; ++j) | ||
453 | { | ||
454 | const S32 basic_offset = (i * sResolution + j); | ||
455 | S32 offset = basic_offset * sComponents; | ||
456 | LLColor3 col(mSkyData[basic_offset]); | ||
457 | if (getDir(i, j).mV[VZ] >= -0.02f) { | ||
458 | col += 0.1f * multiscatt; | ||
459 | col *= brightness_scale; | ||
460 | col.clamp(); | ||
461 | color_gamma_correct(col); | ||
462 | } | ||
463 | |||
464 | U32* pix = (U32*)(data + offset); | ||
465 | LLColor4 temp = LLColor4(col); | ||
466 | LLColor4U temp1 = LLColor4U(temp); | ||
467 | *pix = temp1.mAll; | ||
468 | } | ||
469 | } | ||
470 | createTexture(sCurrent); | ||
471 | } | ||
472 | |||
473 | void LLSkyTex::createTexture(S32 which) | ||
474 | { | ||
475 | mImageGL[which]->createGLTexture(0, mImageRaw[which]); | ||
476 | mImageGL[which]->setClamp(TRUE, TRUE); | ||
477 | } | ||
478 | |||
479 | void LLSkyTex::bindTexture(BOOL curr) | ||
480 | { | ||
481 | mImageGL[getWhich(curr)]->bind(); | ||
482 | } | ||
483 | |||
484 | /*************************************** | ||
485 | Sky | ||
486 | ***************************************/ | ||
487 | |||
488 | F32 LLHeavenBody::sInterpVal = 0; | ||
489 | |||
490 | F32 LLVOSky::sNighttimeBrightness = 1.5f; | ||
491 | |||
492 | S32 LLVOSky::sResolution = LLSkyTex::getResolution(); | ||
493 | S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X; | ||
494 | S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y; | ||
495 | |||
496 | LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) | ||
497 | : LLViewerObject(id, pcode, regionp), | ||
498 | mSun(SUN_DISK_RADIUS), mMoon(MOON_DISK_RADIUS), | ||
499 | mBrightnessScale(1.f), | ||
500 | mBrightnessScaleNew(0.f), | ||
501 | mBrightnessScaleGuess(1.f), | ||
502 | mWeatherChange(FALSE), | ||
503 | mCloudDensity(0.2f), | ||
504 | mWind(0.f), | ||
505 | mForceUpdate(FALSE), | ||
506 | mWorldScale(1.f) | ||
507 | { | ||
508 | mInitialized = FALSE; | ||
509 | mbCanSelect = FALSE; | ||
510 | mUpdateTimer.reset(); | ||
511 | |||
512 | for (S32 i = 0; i < 6; i++) | ||
513 | { | ||
514 | mSkyTex[i].init(); | ||
515 | } | ||
516 | for (S32 i=0; i<FACE_COUNT; i++) | ||
517 | { | ||
518 | mFace[i] = NULL; | ||
519 | } | ||
520 | |||
521 | mCameraPosAgent = gAgent.getCameraPositionAgent(); | ||
522 | mAtmHeight = ATM_HEIGHT; | ||
523 | mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS); | ||
524 | updateHaze(); | ||
525 | |||
526 | mSunDefaultPosition = gSavedSettings.getVector3("SkySunDefaultPosition"); | ||
527 | if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition")) | ||
528 | { | ||
529 | initSunDirection(mSunDefaultPosition, LLVector3(0, 0, 0)); | ||
530 | } | ||
531 | mAmbientScale = gSavedSettings.getF32("SkyAmbientScale"); | ||
532 | mNightColorShift = gSavedSettings.getColor3("SkyNightColorShift"); | ||
533 | mFogColor.mV[VRED] = mFogColor.mV[VGREEN] = mFogColor.mV[VBLUE] = 0.5f; | ||
534 | mFogColor.mV[VALPHA] = 0.0f; | ||
535 | mFogRatio = 1.2f; | ||
536 | |||
537 | mSun.setIntensity(SUN_INTENSITY); | ||
538 | mMoon.setIntensity(0.1f * SUN_INTENSITY); | ||
539 | |||
540 | mCubeMap = NULL; | ||
541 | |||
542 | mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE); | ||
543 | mSunTexturep->setClamp(TRUE, TRUE); | ||
544 | mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE); | ||
545 | mMoonTexturep->setClamp(TRUE, TRUE); | ||
546 | mBloomTexturep = gImageList.getImage(IMG_BLOOM1); | ||
547 | mBloomTexturep->setClamp(TRUE, TRUE); | ||
548 | } | ||
549 | |||
550 | |||
551 | LLVOSky::~LLVOSky() | ||
552 | { | ||
553 | // Don't delete images - it'll get deleted by gImageList on shutdown | ||
554 | // This needs to be done for each texture | ||
555 | |||
556 | delete mCubeMap; | ||
557 | mCubeMap = NULL; | ||
558 | } | ||
559 | |||
560 | void LLVOSky::initClass() | ||
561 | { | ||
562 | LLHaze::initClass(); | ||
563 | } | ||
564 | |||
565 | |||
566 | void LLVOSky::init() | ||
567 | { | ||
568 | // index of refraction calculation. | ||
569 | mTransp.init(NO_STEPS+1+4, FIRST_STEP, mAtmHeight, &mHaze); | ||
570 | |||
571 | const F32 haze_int = color_intens(mHaze.calcSigSca(0)); | ||
572 | mHazeConcentration = haze_int / | ||
573 | (color_intens(LLHaze::calcAirSca(0)) + haze_int); | ||
574 | |||
575 | mBrightnessScaleNew = 0; | ||
576 | |||
577 | // Initialize the cached normalized direction vectors | ||
578 | for (S32 side = 0; side < 6; ++side) | ||
579 | { | ||
580 | for (S32 tile = 0; tile < NUM_TILES; ++tile) | ||
581 | { | ||
582 | initSkyTextureDirs(side, tile); | ||
583 | createSkyTexture(side, tile); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | calcBrightnessScaleAndColors(); | ||
588 | initCubeMap(); | ||
589 | } | ||
590 | |||
591 | void LLVOSky::initCubeMap() | ||
592 | { | ||
593 | std::vector<LLPointer<LLImageRaw> > images; | ||
594 | for (S32 side = 0; side < 6; side++) | ||
595 | { | ||
596 | images.push_back(mSkyTex[side].getImageRaw()); | ||
597 | } | ||
598 | if (mCubeMap != NULL) | ||
599 | { | ||
600 | mCubeMap->init(images); | ||
601 | } | ||
602 | else if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap) | ||
603 | { | ||
604 | mCubeMap = new LLCubeMap(); | ||
605 | mCubeMap->init(images); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | |||
610 | void LLVOSky::cleanupGL() | ||
611 | { | ||
612 | S32 i; | ||
613 | for (i = 0; i < 6; i++) | ||
614 | { | ||
615 | mSkyTex[i].cleanupGL(); | ||
616 | } | ||
617 | if (getCubeMap()) | ||
618 | { | ||
619 | getCubeMap()->destroyGL(); | ||
620 | } | ||
621 | } | ||
622 | |||
623 | void LLVOSky::restoreGL() | ||
624 | { | ||
625 | S32 i; | ||
626 | for (i = 0; i < 6; i++) | ||
627 | { | ||
628 | mSkyTex[i].restoreGL(); | ||
629 | } | ||
630 | mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE); | ||
631 | mSunTexturep->setClamp(TRUE, TRUE); | ||
632 | mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE); | ||
633 | mMoonTexturep->setClamp(TRUE, TRUE); | ||
634 | mBloomTexturep = gImageList.getImage(IMG_BLOOM1); | ||
635 | mBloomTexturep->setClamp(TRUE, TRUE); | ||
636 | |||
637 | calcBrightnessScaleAndColors(); | ||
638 | |||
639 | // Water is currently broken on Mac. | ||
640 | if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap) | ||
641 | { | ||
642 | LLCubeMap* cube_map = getCubeMap(); | ||
643 | |||
644 | std::vector<LLPointer<LLImageRaw> > images; | ||
645 | for (S32 side = 0; side < 6; side++) | ||
646 | { | ||
647 | images.push_back(mSkyTex[side].getImageRaw()); | ||
648 | } | ||
649 | |||
650 | if(cube_map) | ||
651 | { | ||
652 | cube_map->init(images); | ||
653 | mForceUpdate = TRUE; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | if (mDrawable) | ||
658 | { | ||
659 | gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); | ||
660 | } | ||
661 | |||
662 | } | ||
663 | |||
664 | |||
665 | void LLVOSky::updateHaze() | ||
666 | { | ||
667 | time_t timer; | ||
668 | time(&timer); | ||
669 | static LLRand WeatherRandomNumber(gmtime(&timer)->tm_mday); | ||
670 | if (gSavedSettings.getBOOL("FixedWeather")) | ||
671 | { | ||
672 | WeatherRandomNumber.seed(8008135); | ||
673 | } | ||
674 | |||
675 | const F32 fo_upper_bound = 5; | ||
676 | const F32 sca_upper_bound = 6; | ||
677 | const F32 fo = 1 + WeatherRandomNumber.llfrand(fo_upper_bound - 1); | ||
678 | const static F32 upper = 0.5f / gFastLn.ln(fo_upper_bound); | ||
679 | mHaze.setFalloff(fo); | ||
680 | mHaze.setG(WeatherRandomNumber.llfrand(0.0f + upper * gFastLn.ln(fo))); | ||
681 | LLColor3 sca; | ||
682 | const F32 cd = mCloudDensity * 3; | ||
683 | F32 min_r = cd - 1; | ||
684 | if (min_r < 0) | ||
685 | { | ||
686 | min_r = 0; | ||
687 | } | ||
688 | F32 max_r = cd + 1; | ||
689 | if (max_r > sca_upper_bound) | ||
690 | { | ||
691 | max_r = sca_upper_bound; | ||
692 | } | ||
693 | |||
694 | sca.mV[0] = min_r + WeatherRandomNumber.llfrand(max_r - min_r);//frand(6); | ||
695 | |||
696 | min_r = sca.mV[0] - 0.1f; | ||
697 | if (min_r < 0) | ||
698 | { | ||
699 | min_r = 0; | ||
700 | } | ||
701 | max_r = sca.mV[0] + 0.5f; | ||
702 | if (max_r > sca_upper_bound) | ||
703 | { | ||
704 | max_r = sca_upper_bound; | ||
705 | } | ||
706 | |||
707 | sca.mV[1] = min_r + WeatherRandomNumber.llfrand(max_r - min_r); | ||
708 | |||
709 | min_r = sca.mV[1]; | ||
710 | if (min_r < 0) | ||
711 | { | ||
712 | min_r = 0; | ||
713 | } | ||
714 | max_r = sca.mV[1] + 1; | ||
715 | if (max_r > sca_upper_bound) | ||
716 | { | ||
717 | max_r = sca_upper_bound; | ||
718 | } | ||
719 | |||
720 | sca.mV[2] = min_r + WeatherRandomNumber.llfrand(max_r - min_r); | ||
721 | |||
722 | sca = AIR_SCA_AVG * sca; | ||
723 | |||
724 | mHaze.setSigSca(sca); | ||
725 | } | ||
726 | |||
727 | void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile) | ||
728 | { | ||
729 | S32 tile_x = tile % NUM_TILES_X; | ||
730 | S32 tile_y = tile / NUM_TILES_X; | ||
731 | |||
732 | S32 tile_x_pos = tile_x * sTileResX; | ||
733 | S32 tile_y_pos = tile_y * sTileResY; | ||
734 | |||
735 | F32 coeff[3] = {0, 0, 0}; | ||
736 | const S32 curr_coef = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X | ||
737 | const S32 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1 | ||
738 | const S32 x_coef = (curr_coef + 1) % 3; | ||
739 | const S32 y_coef = (x_coef + 1) % 3; | ||
740 | |||
741 | coeff[curr_coef] = (F32)side_dir; | ||
742 | |||
743 | F32 inv_res = 1.f/sResolution; | ||
744 | S32 x, y; | ||
745 | for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y) | ||
746 | { | ||
747 | for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x) | ||
748 | { | ||
749 | coeff[x_coef] = F32((x<<1) + 1) * inv_res - 1.f; | ||
750 | coeff[y_coef] = F32((y<<1) + 1) * inv_res - 1.f; | ||
751 | LLVector3 dir(coeff[0], coeff[1], coeff[2]); | ||
752 | dir.normVec(); | ||
753 | mSkyTex[side].setDir(dir, x, y); | ||
754 | } | ||
755 | } | ||
756 | } | ||
757 | |||
758 | void LLVOSky::createSkyTexture(const S32 side, const S32 tile) | ||
759 | { | ||
760 | S32 tile_x = tile % NUM_TILES_X; | ||
761 | S32 tile_y = tile / NUM_TILES_X; | ||
762 | |||
763 | S32 tile_x_pos = tile_x * sTileResX; | ||
764 | S32 tile_y_pos = tile_y * sTileResY; | ||
765 | |||
766 | S32 x, y; | ||
767 | for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y) | ||
768 | { | ||
769 | for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x) | ||
770 | { | ||
771 | mSkyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y)), x, y); | ||
772 | } | ||
773 | } | ||
774 | } | ||
775 | |||
776 | |||
777 | LLColor3 LLVOSky::calcSkyColorInDir(const LLVector3 &dir) | ||
778 | { | ||
779 | LLColor3 col, transp; | ||
780 | |||
781 | if (dir.mV[VZ] < -0.02) | ||
782 | { | ||
783 | col = LLColor3(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.27f)); | ||
784 | float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]); | ||
785 | x *= x; | ||
786 | col.mV[0] *= x*x; | ||
787 | col.mV[1] *= powf(x, 2.5f); | ||
788 | col.mV[2] *= x*x*x; | ||
789 | return col; | ||
790 | } | ||
791 | |||
792 | |||
793 | calcSkyColorInDir(col, transp, dir); | ||
794 | F32 br = color_max(col); | ||
795 | if (br > mBrightnessScaleNew) | ||
796 | { | ||
797 | mBrightnessScaleNew = br; | ||
798 | mBrightestPointNew = col; | ||
799 | } | ||
800 | return col; | ||
801 | } | ||
802 | |||
803 | |||
804 | LLColor4 LLVOSky::calcInScatter(LLColor4& transp, const LLVector3 &point, F32 exager = 1) const | ||
805 | { | ||
806 | LLColor3 col, tr; | ||
807 | calcInScatter(col, tr, point, exager); | ||
808 | col *= mBrightnessScaleGuess; | ||
809 | transp = LLColor4(tr); | ||
810 | return LLColor4(col); | ||
811 | } | ||
812 | |||
813 | |||
814 | |||
815 | void LLVOSky::calcSkyColorInDir(LLColor3& res, LLColor3& transp, const LLVector3& dir) const | ||
816 | { | ||
817 | const LLVector3& tosun = getToSunLast(); | ||
818 | res.setToBlack(); | ||
819 | LLColor3 haze_res(0.f, 0.f, 0.f); | ||
820 | transp.setToWhite(); | ||
821 | LLVector3 step_v ; | ||
822 | LLVector3 cur_pos = mCameraPosAgent; | ||
823 | F32 h; | ||
824 | |||
825 | F32 dist = calcHitsAtmEdge(mCameraPosAgent, dir); | ||
826 | // const F32 K = log(dist / FIRST_STEP + 1) / NO_STEPS; | ||
827 | const F32 K = gFastLn.ln(dist / FIRST_STEP + 1) / NO_STEPS; | ||
828 | const F32 e_pow_k = (F32)LL_FAST_EXP(K); | ||
829 | F32 step = FIRST_STEP * (1 - 1 / e_pow_k); | ||
830 | |||
831 | for (S32 s = 0; s < NO_STEPS; ++s) | ||
832 | { | ||
833 | h = calcHeight(cur_pos); | ||
834 | step *= e_pow_k; | ||
835 | LLColor3 air_sca_opt_depth; | ||
836 | LLHaze::calcAirSca(h, air_sca_opt_depth); | ||
837 | air_sca_opt_depth *= step; | ||
838 | |||
839 | LLColor3 haze_sca_opt_depth; | ||
840 | mHaze.calcSigSca(h, haze_sca_opt_depth); | ||
841 | haze_sca_opt_depth *= step; | ||
842 | |||
843 | LLColor3 haze_ext_opt_depth = haze_sca_opt_depth; | ||
844 | haze_ext_opt_depth *= (1.f + mHaze.getAbsCoef()); | ||
845 | |||
846 | if (calcHitsEarth(cur_pos, tosun) < 0) // calculates amount of in-scattered light from the sun | ||
847 | { | ||
848 | //visibility check is too expensive | ||
849 | LLColor3 air_transp; | ||
850 | mTransp.calcTransp(calcUpVec(cur_pos) * tosun, h, air_transp); | ||
851 | air_transp *= transp; | ||
852 | res += air_sca_opt_depth * air_transp; | ||
853 | haze_res += haze_sca_opt_depth * air_transp; | ||
854 | } | ||
855 | LLColor3 temp(-4.f * F_PI * (air_sca_opt_depth + haze_ext_opt_depth)); | ||
856 | temp.exp(); | ||
857 | transp *= temp; | ||
858 | step_v = dir * step; | ||
859 | cur_pos += step_v; | ||
860 | } | ||
861 | const F32 cos_dir = dir * tosun; | ||
862 | res *= calcAirPhaseFunc(cos_dir); | ||
863 | res += haze_res * mHaze.calcPhase(cos_dir); | ||
864 | res *= mSun.getIntensity(); | ||
865 | } | ||
866 | |||
867 | |||
868 | |||
869 | |||
870 | void LLVOSky::calcInScatter(LLColor3& res, LLColor3& transp, | ||
871 | const LLVector3& P, const F32 exaggeration) const | ||
872 | { | ||
873 | const LLVector3& tosun = getToSunLast(); | ||
874 | res.setToBlack(); | ||
875 | transp.setToWhite(); | ||
876 | |||
877 | LLVector3 lower, upper; | ||
878 | LLVector3 dir = P - mCameraPosAgent; | ||
879 | |||
880 | F32 dist = exaggeration * dir.normVec(); | ||
881 | |||
882 | const F32 cos_dir = dir * tosun; | ||
883 | |||
884 | if (dir.mV[VZ] > 0) | ||
885 | { | ||
886 | lower = mCameraPosAgent; | ||
887 | upper = P; | ||
888 | } | ||
889 | else | ||
890 | { | ||
891 | lower = P; | ||
892 | upper = mCameraPosAgent; | ||
893 | dir = -dir; | ||
894 | } | ||
895 | |||
896 | const F32 lower_h = calcHeight(lower); | ||
897 | const F32 upper_h = calcHeight(upper); | ||
898 | const LLVector3 up_upper = calcUpVec(upper); | ||
899 | const LLVector3 up_lower = calcUpVec(lower); | ||
900 | |||
901 | transp = color_div(mTransp.calcTransp(up_lower * dir, lower_h), | ||
902 | mTransp.calcTransp(up_upper * dir, upper_h)); | ||
903 | color_pow(transp, exaggeration); | ||
904 | |||
905 | if (calcHitsEarth(upper, tosun) > 0) | ||
906 | { | ||
907 | const F32 avg = color_avg(transp); | ||
908 | //const F32 avg = llmin(1.f, 1.2f * color_avg(transp)); | ||
909 | transp.setVec(avg, avg, avg); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | LLColor3 air_sca_opt_depth = LLHaze::calcAirSca(upper_h); | ||
914 | LLColor3 haze_sca_opt_depth = mHaze.calcSigSca(upper_h); | ||
915 | LLColor3 sun_transp; | ||
916 | mTransp.calcTransp(up_upper * tosun, upper_h, sun_transp); | ||
917 | |||
918 | if (calcHitsEarth(lower, tosun) < 0) | ||
919 | { | ||
920 | air_sca_opt_depth += LLHaze::calcAirSca(lower_h); | ||
921 | air_sca_opt_depth *= 0.5; | ||
922 | haze_sca_opt_depth += mHaze.calcSigSca(lower_h); | ||
923 | haze_sca_opt_depth *= 0.5; | ||
924 | sun_transp += mTransp.calcTransp(up_lower * tosun, lower_h); | ||
925 | sun_transp *= 0.5; | ||
926 | } | ||
927 | |||
928 | res = calcAirPhaseFunc(cos_dir) * air_sca_opt_depth; | ||
929 | res += mHaze.calcPhase(cos_dir) * haze_sca_opt_depth; | ||
930 | res = mSun.getIntensity() * dist * sun_transp * res; | ||
931 | } | ||
932 | |||
933 | |||
934 | |||
935 | |||
936 | |||
937 | |||
938 | F32 LLVOSky::calcHitsEarth(const LLVector3& orig, const LLVector3& dir) const | ||
939 | { | ||
940 | const LLVector3 from_earth_center = mEarthCenter - orig; | ||
941 | const F32 tca = dir * from_earth_center; | ||
942 | if ( tca < 0 ) | ||
943 | { | ||
944 | return -1; | ||
945 | } | ||
946 | |||
947 | const F32 thc2 = EARTH_RADIUS * EARTH_RADIUS - | ||
948 | from_earth_center.magVecSquared() + tca * tca; | ||
949 | if (thc2 < 0 ) | ||
950 | { | ||
951 | return -1; | ||
952 | } | ||
953 | |||
954 | return tca - sqrt ( thc2 ); | ||
955 | } | ||
956 | |||
957 | F32 LLVOSky::calcHitsAtmEdge(const LLVector3& orig, const LLVector3& dir) const | ||
958 | { | ||
959 | const LLVector3 from_earth_center = mEarthCenter - orig; | ||
960 | const F32 tca = dir * from_earth_center; | ||
961 | |||
962 | const F32 thc2 = (EARTH_RADIUS + mAtmHeight) * (EARTH_RADIUS + mAtmHeight) - | ||
963 | from_earth_center.magVecSquared() + tca * tca; | ||
964 | return tca + sqrt(thc2); | ||
965 | } | ||
966 | |||
967 | |||
968 | void LLVOSky::updateBrightestDir() | ||
969 | { | ||
970 | LLColor3 br_pt, transp; | ||
971 | const S32 test_no = 5; | ||
972 | const F32 step = F_PI_BY_TWO / (test_no + 1); | ||
973 | for (S32 i = 0; i < test_no; ++i) | ||
974 | { | ||
975 | F32 cos_dir = cos ((i + 1) * step); | ||
976 | calcSkyColorInDir(br_pt, transp, move_vec(getToSunLast(), cos_dir)); | ||
977 | const F32 br = color_max(br_pt); | ||
978 | if (br > mBrightnessScaleGuess) | ||
979 | { | ||
980 | mBrightnessScaleGuess = br; | ||
981 | mBrightestPointGuess = br_pt; | ||
982 | } | ||
983 | } | ||
984 | } | ||
985 | |||
986 | |||
987 | void LLVOSky::calcBrightnessScaleAndColors() | ||
988 | { | ||
989 | // new correct normalization. | ||
990 | if (mBrightnessScaleNew < 1e-7) | ||
991 | { | ||
992 | mBrightnessScale = 1; | ||
993 | mBrightestPoint.setToBlack(); | ||
994 | } | ||
995 | else | ||
996 | { | ||
997 | mBrightnessScale = 1.f/mBrightnessScaleNew; | ||
998 | mBrightestPoint = mBrightestPointNew; | ||
999 | } | ||
1000 | |||
1001 | mBrightnessScaleNew = 0; | ||
1002 | // and addition | ||
1003 | |||
1004 | // Calculate Sun and Moon color | ||
1005 | const F32 h = llmax(0.0f, mCameraPosAgent.mV[2]); | ||
1006 | const LLColor3 sun_color = mSun.getIntensity() * mTransp.calcTransp(getToSunLast().mV[2], h); | ||
1007 | const LLColor3 moon_color = mNightColorShift * | ||
1008 | mMoon.getIntensity() * mTransp.calcTransp(getToMoonLast().mV[2], h); | ||
1009 | |||
1010 | F32 intens = color_intens(sun_color); | ||
1011 | F32 increase_sun_br = (intens > 0) ? 1.2f * color_intens(mBrightestPoint) / intens : 1; | ||
1012 | |||
1013 | intens = color_intens(moon_color); | ||
1014 | F32 increase_moon_br = (intens > 0) ? 1.2f * llmax(1.0f, color_intens(mBrightestPoint) / intens) : 1; | ||
1015 | |||
1016 | mSun.setColor(mBrightnessScale * increase_sun_br * sun_color); | ||
1017 | mMoon.setColor(mBrightnessScale * increase_moon_br * moon_color); | ||
1018 | |||
1019 | const LLColor3 haze_col = color_norm_abs(mHaze.getSigSca()); | ||
1020 | for (S32 i = 0; i < 6; ++i) | ||
1021 | { | ||
1022 | mSkyTex[i].create(mBrightnessScale, mHazeConcentration * mBrightestPoint * haze_col); | ||
1023 | } | ||
1024 | |||
1025 | mBrightnessScaleGuess = mBrightnessScale; | ||
1026 | mBrightestPointGuess = mBrightestPoint; | ||
1027 | |||
1028 | // calculateColors(); // MSMSM Moving this down to before generateScatterMap(), per Milo Lindens suggestion, to fix orange flashing bug. | ||
1029 | |||
1030 | mSun.renewDirection(); | ||
1031 | mSun.renewColor(); | ||
1032 | mMoon.renewDirection(); | ||
1033 | mMoon.renewColor(); | ||
1034 | |||
1035 | LLColor3 transp; | ||
1036 | |||
1037 | if (calcHitsEarth(mCameraPosAgent, getToSunLast()) < 0) | ||
1038 | { | ||
1039 | calcSkyColorInDir(mBrightestPointGuess, transp, getToSunLast()); | ||
1040 | mBrightnessScaleGuess = color_max(mBrightestPointGuess); | ||
1041 | updateBrightestDir(); | ||
1042 | mBrightnessScaleGuess = 1.f / llmax(1.0f, mBrightnessScaleGuess); | ||
1043 | } | ||
1044 | else if (getToSunLast().mV[2] > -0.5) | ||
1045 | { | ||
1046 | const LLVector3 almost_to_sun = toHorizon(getToSunLast()); | ||
1047 | calcSkyColorInDir(mBrightestPointGuess, transp, almost_to_sun); | ||
1048 | mBrightnessScaleGuess = color_max(mBrightestPointGuess); | ||
1049 | updateBrightestDir(); | ||
1050 | mBrightnessScaleGuess = 1.f / llmax(1.0f, mBrightnessScaleGuess); | ||
1051 | } | ||
1052 | else | ||
1053 | { | ||
1054 | mBrightestPointGuess.setToBlack(); | ||
1055 | mBrightnessScaleGuess = 1; | ||
1056 | } | ||
1057 | |||
1058 | calculateColors(); // MSMSM Moved this down here per Milo Lindens suggestion, to fix orange flashing bug at sunset. | ||
1059 | generateScatterMap(); | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | |||
1064 | void LLVOSky::calculateColors() | ||
1065 | { | ||
1066 | const F32 h = -0.1f; | ||
1067 | const LLVector3& tosun = getToSunLast(); | ||
1068 | |||
1069 | F32 full_on, full_off, on, on_cl; | ||
1070 | F32 sun_factor = 1; | ||
1071 | |||
1072 | // Sun Diffuse | ||
1073 | if (calcHitsEarth(mCameraPosAgent, tosun) < 0) | ||
1074 | { | ||
1075 | mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(tosun.mV[2], h); | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(0, h); | ||
1080 | } | ||
1081 | mSunDiffuse = 1.0f * color_norm(mSunDiffuse); | ||
1082 | |||
1083 | // Sun Ambient | ||
1084 | full_off = -0.3f; | ||
1085 | full_on = -0.03f; | ||
1086 | if (tosun.mV[2] < full_off) | ||
1087 | { | ||
1088 | mSunAmbient.setToBlack(); | ||
1089 | } | ||
1090 | else | ||
1091 | { | ||
1092 | on = (tosun.mV[2] - full_off) / (full_on - full_off); | ||
1093 | sun_factor = llmax(0.0f, llmin(on, 1.0f)); | ||
1094 | |||
1095 | LLColor3 sun_amb = mAmbientScale * (0.8f * mSunDiffuse + | ||
1096 | 0.2f * mBrightnessScaleGuess * mBrightestPointGuess); | ||
1097 | |||
1098 | color_norm_pow(sun_amb, 0.1f, TRUE); | ||
1099 | sun_factor *= min_intens_factor(sun_amb, 1.9f); | ||
1100 | mSunAmbient = LLColor4(sun_factor * sun_amb); | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | // Moon Diffuse | ||
1105 | full_on = 0.3f; | ||
1106 | full_off = 0.01f; | ||
1107 | if (getToMoonLast().mV[2] < full_off) | ||
1108 | { | ||
1109 | mMoonDiffuse.setToBlack(); | ||
1110 | } | ||
1111 | else | ||
1112 | { | ||
1113 | // Steve: Added moonlight diffuse factor scalar (was constant .3) | ||
1114 | F32 diffuse_factor = .1f + sNighttimeBrightness * .2f; // [.1, .5] default = .3 | ||
1115 | on = (getToMoonLast().mV[2] - full_off) / (full_on - full_off); | ||
1116 | on_cl = llmin(on, 1.0f); | ||
1117 | mMoonDiffuse = on_cl * mNightColorShift * diffuse_factor; | ||
1118 | } | ||
1119 | |||
1120 | // Moon Ambient | ||
1121 | |||
1122 | F32 moon_amb_factor = 1.f; | ||
1123 | |||
1124 | if (gAgent.inPrelude()) | ||
1125 | { | ||
1126 | moon_amb_factor *= 2.0f; | ||
1127 | } | ||
1128 | |||
1129 | full_on = 0.30f; | ||
1130 | full_off = 0.01f; | ||
1131 | if (getToMoonLast().mV[2] < full_off) | ||
1132 | { | ||
1133 | mMoonAmbient.setToBlack(); | ||
1134 | } | ||
1135 | else | ||
1136 | { | ||
1137 | on = (getToMoonLast().mV[2] - full_off) / (full_on - full_off); | ||
1138 | on_cl = llmax(0.0f, llmin(on, 1.0f)); | ||
1139 | mMoonAmbient = on_cl * moon_amb_factor * mMoonDiffuse; | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | // Sun Diffuse | ||
1144 | full_off = -0.05f; | ||
1145 | full_on = -0.00f; | ||
1146 | if (tosun.mV[2] < full_off) | ||
1147 | { | ||
1148 | mSunDiffuse.setToBlack(); | ||
1149 | } | ||
1150 | else | ||
1151 | { | ||
1152 | on = (getToSunLast().mV[2] - full_off) / (full_on - full_off); | ||
1153 | sun_factor = llmax(0.0f, llmin(on, 1.0f)); | ||
1154 | |||
1155 | color_norm_pow(mSunDiffuse, 0.12f, TRUE); | ||
1156 | sun_factor *= min_intens_factor(mSunDiffuse, 2.1f); | ||
1157 | mSunDiffuse *= sun_factor; | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | mTotalAmbient = mSunAmbient + mMoonAmbient; | ||
1162 | mTotalAmbient.setAlpha(1); | ||
1163 | //llinfos << "MoonDiffuse: " << mMoonDiffuse << llendl; | ||
1164 | //llinfos << "TotalAmbient: " << mTotalAmbient << llendl; | ||
1165 | |||
1166 | mFadeColor = mTotalAmbient + (mSunDiffuse + mMoonDiffuse) * 0.5f; | ||
1167 | mFadeColor.setAlpha(0); | ||
1168 | } | ||
1169 | |||
1170 | |||
1171 | BOOL LLVOSky::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) | ||
1172 | { | ||
1173 | return TRUE; | ||
1174 | } | ||
1175 | |||
1176 | BOOL LLVOSky::updateSky() | ||
1177 | { | ||
1178 | if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))) | ||
1179 | { | ||
1180 | return TRUE; | ||
1181 | } | ||
1182 | |||
1183 | if (mDead) | ||
1184 | { | ||
1185 | // It's dead. Don't update it. | ||
1186 | return TRUE; | ||
1187 | } | ||
1188 | if (gGLManager.mIsDisabled) | ||
1189 | { | ||
1190 | return TRUE; | ||
1191 | } | ||
1192 | |||
1193 | setPositionAgent(gAgent.getCameraPositionAgent()); | ||
1194 | |||
1195 | static S32 next_frame = 0; | ||
1196 | const S32 total_no_tiles = 6 * NUM_TILES; | ||
1197 | const S32 cycle_frame_no = total_no_tiles + 1; | ||
1198 | |||
1199 | // if (mUpdateTimer.getElapsedTimeF32() > 0.1f) | ||
1200 | { | ||
1201 | mUpdateTimer.reset(); | ||
1202 | const S32 frame = next_frame; | ||
1203 | |||
1204 | ++next_frame; | ||
1205 | next_frame = next_frame % cycle_frame_no; | ||
1206 | |||
1207 | sInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no; | ||
1208 | LLSkyTex::setInterpVal( sInterpVal ); | ||
1209 | LLHeavenBody::setInterpVal( sInterpVal ); | ||
1210 | calculateColors(); | ||
1211 | if (mForceUpdate || total_no_tiles == frame) | ||
1212 | { | ||
1213 | calcBrightnessScaleAndColors(); | ||
1214 | LLSkyTex::stepCurrent(); | ||
1215 | |||
1216 | const static F32 LIGHT_DIRECTION_THRESHOLD = (F32) cos(DEG_TO_RAD * 1.f); | ||
1217 | const static F32 COLOR_CHANGE_THRESHOLD = 0.01f; | ||
1218 | |||
1219 | LLVector3 direction = mSun.getDirection(); | ||
1220 | direction.normVec(); | ||
1221 | const F32 dot_lighting = direction * mLastLightingDirection; | ||
1222 | |||
1223 | LLColor3 delta_color; | ||
1224 | delta_color.setVec(mLastTotalAmbient.mV[0] - mTotalAmbient.mV[0], | ||
1225 | mLastTotalAmbient.mV[1] - mTotalAmbient.mV[1], | ||
1226 | mLastTotalAmbient.mV[2] - mTotalAmbient.mV[2]); | ||
1227 | |||
1228 | if ( mForceUpdate | ||
1229 | || ((dot_lighting < LIGHT_DIRECTION_THRESHOLD) | ||
1230 | || (delta_color.magVec() > COLOR_CHANGE_THRESHOLD) | ||
1231 | || !mInitialized) | ||
1232 | && !direction.isExactlyZero()) | ||
1233 | { | ||
1234 | mLastLightingDirection = direction; | ||
1235 | mLastTotalAmbient = mTotalAmbient; | ||
1236 | mInitialized = TRUE; | ||
1237 | |||
1238 | if (mCubeMap) | ||
1239 | { | ||
1240 | if (mForceUpdate) | ||
1241 | { | ||
1242 | updateFog(gCamera->getFar()); | ||
1243 | for (int side = 0; side < 6; side++) | ||
1244 | { | ||
1245 | for (int tile = 0; tile < NUM_TILES; tile++) | ||
1246 | { | ||
1247 | createSkyTexture(side, tile); | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | calcBrightnessScaleAndColors(); | ||
1252 | |||
1253 | for (int side = 0; side < 6; side++) | ||
1254 | { | ||
1255 | LLImageRaw* raw1 = mSkyTex[side].getImageRaw(TRUE); | ||
1256 | LLImageRaw* raw2 = mSkyTex[side].getImageRaw(FALSE); | ||
1257 | raw2->copy(raw1); | ||
1258 | mSkyTex[side].createTexture(mSkyTex[side].getWhich(FALSE)); | ||
1259 | } | ||
1260 | next_frame = 0; | ||
1261 | //llSkyTex::stepCurrent(); | ||
1262 | } | ||
1263 | |||
1264 | std::vector<LLPointer<LLImageRaw> > images; | ||
1265 | for (S32 side = 0; side < 6; side++) | ||
1266 | { | ||
1267 | images.push_back(mSkyTex[side].getImageRaw(FALSE)); | ||
1268 | } | ||
1269 | mCubeMap->init(images); | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | mForceUpdate = FALSE; | ||
1274 | } | ||
1275 | else | ||
1276 | { | ||
1277 | const S32 side = frame / NUM_TILES; | ||
1278 | const S32 tile = frame % NUM_TILES; | ||
1279 | createSkyTexture(side, tile); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | if (mDrawable) | ||
1285 | { | ||
1286 | gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); | ||
1287 | } | ||
1288 | return TRUE; | ||
1289 | } | ||
1290 | |||
1291 | |||
1292 | void LLVOSky::updateTextures(LLAgent &agent) | ||
1293 | { | ||
1294 | if (mSunTexturep) | ||
1295 | { | ||
1296 | mSunTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); | ||
1297 | mMoonTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); | ||
1298 | mBloomTexturep->addTextureStats( (F32)MAX_IMAGE_AREA ); | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1302 | LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline) | ||
1303 | { | ||
1304 | pipeline->allocDrawable(this); | ||
1305 | mDrawable->setLit(FALSE); | ||
1306 | |||
1307 | LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY); | ||
1308 | poolp->setSkyTex(mSkyTex); | ||
1309 | poolp->setSun(&mSun); | ||
1310 | poolp->setMoon(&mMoon); | ||
1311 | |||
1312 | for (S32 i = 0; i < 6; ++i) | ||
1313 | { | ||
1314 | mFace[FACE_SIDE0 + i] = mDrawable->addFace(poolp, NULL); | ||
1315 | } | ||
1316 | |||
1317 | mFace[FACE_SUN] = mDrawable->addFace(poolp, mSunTexturep); | ||
1318 | mFace[FACE_MOON] = mDrawable->addFace(poolp, mMoonTexturep); | ||
1319 | mFace[FACE_BLOOM] = mDrawable->addFace(poolp, mBloomTexturep); | ||
1320 | |||
1321 | //mDrawable->addFace(poolp, LLViewerImage::sDefaultImagep); | ||
1322 | gPipeline.markMaterialed(mDrawable); | ||
1323 | |||
1324 | return mDrawable; | ||
1325 | } | ||
1326 | |||
1327 | BOOL LLVOSky::updateGeometry(LLDrawable *drawable) | ||
1328 | { | ||
1329 | if (mFace[FACE_REFLECTION] == NULL) | ||
1330 | { | ||
1331 | mFace[FACE_REFLECTION] = drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_WATER), NULL); | ||
1332 | } | ||
1333 | |||
1334 | mCameraPosAgent = drawable->getPositionAgent(); | ||
1335 | mEarthCenter.mV[0] = mCameraPosAgent.mV[0]; | ||
1336 | mEarthCenter.mV[1] = mCameraPosAgent.mV[1]; | ||
1337 | |||
1338 | |||
1339 | LLVector3 v_agent[8]; | ||
1340 | for (S32 i = 0; i < 8; ++i) | ||
1341 | { | ||
1342 | F32 x_sgn = (i&1) ? 1.f : -1.f; | ||
1343 | F32 y_sgn = (i&2) ? 1.f : -1.f; | ||
1344 | F32 z_sgn = (i&4) ? 1.f : -1.f; | ||
1345 | v_agent[i] = mCameraPosAgent + HORIZON_DIST * LLVector3(x_sgn, y_sgn, z_sgn); | ||
1346 | } | ||
1347 | |||
1348 | LLStrider<LLVector3> verticesp; | ||
1349 | LLStrider<LLVector3> normalsp; | ||
1350 | LLStrider<LLVector2> texCoordsp; | ||
1351 | U32 *indicesp; | ||
1352 | S32 index_offset; | ||
1353 | LLFace *face; | ||
1354 | |||
1355 | for (S32 side = 0; side < 6; ++side) | ||
1356 | { | ||
1357 | face = mFace[FACE_SIDE0 + side]; | ||
1358 | face->setPrimType(LLTriangles); | ||
1359 | face->setSize(4, 6); | ||
1360 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
1361 | if (-1 == index_offset) | ||
1362 | { | ||
1363 | return TRUE; | ||
1364 | } | ||
1365 | |||
1366 | S32 vtx = 0; | ||
1367 | S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X | ||
1368 | S32 side_dir = side & 1; // even - 0, odd - 1 | ||
1369 | S32 i_bit = (curr_bit + 2) % 3; | ||
1370 | S32 j_bit = (i_bit + 2) % 3; | ||
1371 | |||
1372 | LLVector3 axis; | ||
1373 | axis.mV[curr_bit] = 1; | ||
1374 | face->mCenterAgent = mCameraPosAgent + (F32)((side_dir << 1) - 1) * axis * HORIZON_DIST; | ||
1375 | |||
1376 | vtx = side_dir << curr_bit; | ||
1377 | *(verticesp++) = v_agent[vtx]; | ||
1378 | *(verticesp++) = v_agent[vtx | 1 << j_bit]; | ||
1379 | *(verticesp++) = v_agent[vtx | 1 << i_bit]; | ||
1380 | *(verticesp++) = v_agent[vtx | 1 << i_bit | 1 << j_bit]; | ||
1381 | |||
1382 | *(texCoordsp++) = TEX00; | ||
1383 | *(texCoordsp++) = TEX01; | ||
1384 | *(texCoordsp++) = TEX10; | ||
1385 | *(texCoordsp++) = TEX11; | ||
1386 | |||
1387 | // Triangles for each side | ||
1388 | *indicesp++ = index_offset + 0; | ||
1389 | *indicesp++ = index_offset + 1; | ||
1390 | *indicesp++ = index_offset + 3; | ||
1391 | |||
1392 | *indicesp++ = index_offset + 0; | ||
1393 | *indicesp++ = index_offset + 3; | ||
1394 | *indicesp++ = index_offset + 2; | ||
1395 | } | ||
1396 | |||
1397 | const LLVector3 &look_at = gCamera->getAtAxis(); | ||
1398 | LLVector3 right = look_at % LLVector3::z_axis; | ||
1399 | LLVector3 up = right % look_at; | ||
1400 | right.normVec(); | ||
1401 | up.normVec(); | ||
1402 | |||
1403 | const static F32 elevation_factor = 0.0f/sResolution; | ||
1404 | const F32 cos_max_angle = cosHorizon(elevation_factor); | ||
1405 | mSun.setDraw(updateHeavenlyBodyGeometry(drawable, FACE_SUN, TRUE, mSun, cos_max_angle, up, right)); | ||
1406 | mMoon.setDraw(updateHeavenlyBodyGeometry(drawable, FACE_MOON, FALSE, mMoon, cos_max_angle, up, right)); | ||
1407 | |||
1408 | const F32 water_height = gAgent.getRegion()->getWaterHeight() + 0.01f; | ||
1409 | // gWorldPointer->getWaterHeight() + 0.01f; | ||
1410 | const F32 camera_height = mCameraPosAgent.mV[2]; | ||
1411 | const F32 height_above_water = camera_height - water_height; | ||
1412 | |||
1413 | BOOL sun = FALSE; | ||
1414 | |||
1415 | if (mSun.isVisible()) | ||
1416 | { | ||
1417 | if (mMoon.isVisible()) | ||
1418 | { | ||
1419 | sun = look_at * mSun.getDirection() > 0; | ||
1420 | } | ||
1421 | else | ||
1422 | { | ||
1423 | sun = TRUE; | ||
1424 | } | ||
1425 | } | ||
1426 | |||
1427 | if (height_above_water > 0) | ||
1428 | { | ||
1429 | #if 1 //1.9.1 | ||
1430 | BOOL render_ref = gPipeline.getPool(LLDrawPool::POOL_WATER)->getVertexShaderLevel() == 0; | ||
1431 | #else | ||
1432 | BOOL render_ref = !(gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT) >= LLDrawPoolWater::SHADER_LEVEL_RIPPLE); | ||
1433 | #endif | ||
1434 | if (sun) | ||
1435 | { | ||
1436 | setDrawRefl(0); | ||
1437 | if (render_ref) | ||
1438 | { | ||
1439 | updateReflectionGeometry(drawable, height_above_water, mSun); | ||
1440 | } | ||
1441 | } | ||
1442 | else | ||
1443 | { | ||
1444 | setDrawRefl(1); | ||
1445 | if (render_ref) | ||
1446 | { | ||
1447 | updateReflectionGeometry(drawable, height_above_water, mMoon); | ||
1448 | } | ||
1449 | } | ||
1450 | } | ||
1451 | else | ||
1452 | { | ||
1453 | setDrawRefl(-1); | ||
1454 | } | ||
1455 | |||
1456 | |||
1457 | LLPipeline::sCompiles++; | ||
1458 | return TRUE; | ||
1459 | } | ||
1460 | |||
1461 | |||
1462 | BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, const BOOL is_sun, | ||
1463 | LLHeavenBody& hb, const F32 cos_max_angle, | ||
1464 | const LLVector3 &up, const LLVector3 &right) | ||
1465 | { | ||
1466 | LLStrider<LLVector3> verticesp; | ||
1467 | LLStrider<LLVector3> normalsp; | ||
1468 | LLStrider<LLVector2> texCoordsp; | ||
1469 | U32 *indicesp; | ||
1470 | S32 index_offset; | ||
1471 | LLFace *facep; | ||
1472 | |||
1473 | LLVector3 to_dir = hb.getDirection(); | ||
1474 | LLVector3 draw_pos = to_dir * HEAVENLY_BODY_DIST; | ||
1475 | |||
1476 | |||
1477 | LLVector3 hb_right = to_dir % LLVector3::z_axis; | ||
1478 | LLVector3 hb_up = hb_right % to_dir; | ||
1479 | hb_right.normVec(); | ||
1480 | hb_up.normVec(); | ||
1481 | |||
1482 | //const static F32 cos_max_turn = sqrt(3.f) / 2; // 30 degrees | ||
1483 | //const F32 cos_turn_right = 1. / (llmax(cos_max_turn, hb_right * right)); | ||
1484 | //const F32 cos_turn_up = 1. / llmax(cos_max_turn, hb_up * up); | ||
1485 | |||
1486 | const F32 enlargm_factor = ( 1 - to_dir.mV[2] ); | ||
1487 | F32 horiz_enlargement = 1 + enlargm_factor * 0.3f; | ||
1488 | F32 vert_enlargement = 1 + enlargm_factor * 0.2f; | ||
1489 | |||
1490 | // Parameters for the water reflection | ||
1491 | hb.setU(HEAVENLY_BODY_FACTOR * horiz_enlargement * hb.getDiskRadius() * hb_right); | ||
1492 | hb.setV(HEAVENLY_BODY_FACTOR * vert_enlargement * hb.getDiskRadius() * hb_up); | ||
1493 | // End of parameters for the water reflection | ||
1494 | |||
1495 | const LLVector3 scaled_right = HEAVENLY_BODY_DIST * hb.getU(); | ||
1496 | const LLVector3 scaled_up = HEAVENLY_BODY_DIST * hb.getV(); | ||
1497 | |||
1498 | //const LLVector3 scaled_right = horiz_enlargement * HEAVENLY_BODY_SCALE * hb.getDiskRadius() * hb_right;//right; | ||
1499 | //const LLVector3 scaled_up = vert_enlargement * HEAVENLY_BODY_SCALE * hb.getDiskRadius() * hb_up;//up; | ||
1500 | LLVector3 v_clipped[4]; | ||
1501 | |||
1502 | hb.corner(0) = draw_pos - scaled_right + scaled_up; | ||
1503 | hb.corner(1) = draw_pos - scaled_right - scaled_up; | ||
1504 | hb.corner(2) = draw_pos + scaled_right + scaled_up; | ||
1505 | hb.corner(3) = draw_pos + scaled_right - scaled_up; | ||
1506 | |||
1507 | |||
1508 | F32 t_left, t_right; | ||
1509 | if (!clip_quad_to_horizon(t_left, t_right, v_clipped, hb.corners(), cos_max_angle)) | ||
1510 | { | ||
1511 | hb.setVisible(FALSE); | ||
1512 | return FALSE; | ||
1513 | } | ||
1514 | hb.setVisible(TRUE); | ||
1515 | |||
1516 | facep = mFace[f]; | ||
1517 | facep->setPrimType(LLTriangles); | ||
1518 | facep->setSize(4, 6); | ||
1519 | index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
1520 | if (-1 == index_offset) | ||
1521 | { | ||
1522 | return TRUE; | ||
1523 | } | ||
1524 | |||
1525 | for (S32 vtx = 0; vtx < 4; ++vtx) | ||
1526 | { | ||
1527 | hb.corner(vtx) = v_clipped[vtx]; | ||
1528 | *(verticesp++) = hb.corner(vtx) + mCameraPosAgent; | ||
1529 | } | ||
1530 | |||
1531 | *(texCoordsp++) = TEX01; | ||
1532 | *(texCoordsp++) = TEX00; | ||
1533 | //*(texCoordsp++) = (t_left > 0) ? LLVector2(0, t_left) : TEX00; | ||
1534 | *(texCoordsp++) = TEX11; | ||
1535 | *(texCoordsp++) = TEX10; | ||
1536 | //*(texCoordsp++) = (t_right > 0) ? LLVector2(1, t_right) : TEX10; | ||
1537 | |||
1538 | *indicesp++ = index_offset + 0; | ||
1539 | *indicesp++ = index_offset + 2; | ||
1540 | *indicesp++ = index_offset + 1; | ||
1541 | |||
1542 | *indicesp++ = index_offset + 1; | ||
1543 | *indicesp++ = index_offset + 2; | ||
1544 | *indicesp++ = index_offset + 3; | ||
1545 | |||
1546 | if (is_sun) | ||
1547 | { | ||
1548 | if ((t_left > 0) && (t_right > 0)) | ||
1549 | { | ||
1550 | F32 t = (t_left + t_right) * 0.5f; | ||
1551 | mSun.setHorizonVisibility(0.5f * (1 + cos(t * F_PI))); | ||
1552 | } | ||
1553 | else | ||
1554 | { | ||
1555 | mSun.setHorizonVisibility(); | ||
1556 | } | ||
1557 | updateSunHaloGeometry(drawable); | ||
1558 | } | ||
1559 | |||
1560 | return TRUE; | ||
1561 | } | ||
1562 | |||
1563 | |||
1564 | |||
1565 | |||
1566 | // Clips quads with top and bottom sides parallel to horizon. | ||
1567 | |||
1568 | BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4], | ||
1569 | const LLVector3 v_corner[4], const F32 cos_max_angle) | ||
1570 | { | ||
1571 | t_left = clip_side_to_horizon(v_corner[1], v_corner[0], cos_max_angle); | ||
1572 | t_right = clip_side_to_horizon(v_corner[3], v_corner[2], cos_max_angle); | ||
1573 | |||
1574 | if ((t_left >= 1) || (t_right >= 1)) | ||
1575 | { | ||
1576 | return FALSE; | ||
1577 | } | ||
1578 | |||
1579 | //const BOOL left_clip = (t_left > 0); | ||
1580 | //const BOOL right_clip = (t_right > 0); | ||
1581 | |||
1582 | //if (!left_clip && !right_clip) | ||
1583 | { | ||
1584 | for (S32 vtx = 0; vtx < 4; ++vtx) | ||
1585 | { | ||
1586 | v_clipped[vtx] = v_corner[vtx]; | ||
1587 | } | ||
1588 | } | ||
1589 | /* else | ||
1590 | { | ||
1591 | v_clipped[0] = v_corner[0]; | ||
1592 | v_clipped[1] = left_clip ? ((1 - t_left) * v_corner[1] + t_left * v_corner[0]) | ||
1593 | : v_corner[1]; | ||
1594 | v_clipped[2] = v_corner[2]; | ||
1595 | v_clipped[3] = right_clip ? ((1 - t_right) * v_corner[3] + t_right * v_corner[2]) | ||
1596 | : v_corner[3]; | ||
1597 | }*/ | ||
1598 | |||
1599 | return TRUE; | ||
1600 | } | ||
1601 | |||
1602 | |||
1603 | F32 clip_side_to_horizon(const LLVector3& V0, const LLVector3& V1, const F32 cos_max_angle) | ||
1604 | { | ||
1605 | const LLVector3 V = V1 - V0; | ||
1606 | const F32 k2 = 1.f/(cos_max_angle * cos_max_angle) - 1; | ||
1607 | const F32 A = V.mV[0] * V.mV[0] + V.mV[1] * V.mV[1] - k2 * V.mV[2] * V.mV[2]; | ||
1608 | const F32 B = V0.mV[0] * V.mV[0] + V0.mV[1] * V.mV[1] - k2 * V0.mV[2] * V.mV[2]; | ||
1609 | const F32 C = V0.mV[0] * V0.mV[0] + V0.mV[1] * V0.mV[1] - k2 * V0.mV[2] * V0.mV[2]; | ||
1610 | |||
1611 | if (fabs(A) < 1e-7) | ||
1612 | { | ||
1613 | return -0.1f; // v0 is cone origin and v1 is on the surface of the cone. | ||
1614 | } | ||
1615 | |||
1616 | const F32 det = sqrt(B*B - A*C); | ||
1617 | const F32 t1 = (-B - det) / A; | ||
1618 | const F32 t2 = (-B + det) / A; | ||
1619 | const F32 z1 = V0.mV[2] + t1 * V.mV[2]; | ||
1620 | const F32 z2 = V0.mV[2] + t2 * V.mV[2]; | ||
1621 | if (z1 * cos_max_angle < 0) | ||
1622 | { | ||
1623 | return t2; | ||
1624 | } | ||
1625 | else if (z2 * cos_max_angle < 0) | ||
1626 | { | ||
1627 | return t1; | ||
1628 | } | ||
1629 | else if ((t1 < 0) || (t1 > 1)) | ||
1630 | { | ||
1631 | return t2; | ||
1632 | } | ||
1633 | else | ||
1634 | { | ||
1635 | return t1; | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | |||
1640 | void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable ) | ||
1641 | { | ||
1642 | const LLVector3* v_corner = mSun.corners(); | ||
1643 | |||
1644 | LLStrider<LLVector3> verticesp; | ||
1645 | LLStrider<LLVector3> normalsp; | ||
1646 | LLStrider<LLVector2> texCoordsp; | ||
1647 | U32 *indicesp; | ||
1648 | S32 index_offset; | ||
1649 | LLFace *face; | ||
1650 | |||
1651 | const LLVector3 right = 2 * (v_corner[2] - v_corner[0]); | ||
1652 | LLVector3 up = 2 * (v_corner[2] - v_corner[3]); | ||
1653 | up.normVec(); | ||
1654 | F32 size = right.magVec(); | ||
1655 | up = size * up; | ||
1656 | const LLVector3 draw_pos = 0.25 * (v_corner[0] + v_corner[1] + v_corner[2] + v_corner[3]); | ||
1657 | |||
1658 | LLVector3 v_glow_corner[4]; | ||
1659 | |||
1660 | v_glow_corner[0] = draw_pos - right + up; | ||
1661 | v_glow_corner[1] = draw_pos - right - up; | ||
1662 | v_glow_corner[2] = draw_pos + right + up; | ||
1663 | v_glow_corner[3] = draw_pos + right - up; | ||
1664 | |||
1665 | face = mFace[FACE_BLOOM]; | ||
1666 | face->setPrimType(LLTriangles); | ||
1667 | face->setSize(4, 6); | ||
1668 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
1669 | if (-1 == index_offset) | ||
1670 | { | ||
1671 | return; | ||
1672 | } | ||
1673 | |||
1674 | for (S32 vtx = 0; vtx < 4; ++vtx) | ||
1675 | { | ||
1676 | *(verticesp++) = v_glow_corner[vtx] + mCameraPosAgent; | ||
1677 | } | ||
1678 | |||
1679 | *(texCoordsp++) = TEX01; | ||
1680 | *(texCoordsp++) = TEX00; | ||
1681 | *(texCoordsp++) = TEX11; | ||
1682 | *(texCoordsp++) = TEX10; | ||
1683 | |||
1684 | *indicesp++ = index_offset + 0; | ||
1685 | *indicesp++ = index_offset + 2; | ||
1686 | *indicesp++ = index_offset + 1; | ||
1687 | |||
1688 | *indicesp++ = index_offset + 1; | ||
1689 | *indicesp++ = index_offset + 2; | ||
1690 | *indicesp++ = index_offset + 3; | ||
1691 | } | ||
1692 | |||
1693 | |||
1694 | F32 dtReflection(const LLVector3& p, F32 cos_dir_from_top, F32 sin_dir_from_top, F32 diff_angl_dir) | ||
1695 | { | ||
1696 | LLVector3 P = p; | ||
1697 | P.normVec(); | ||
1698 | |||
1699 | const F32 cos_dir_angle = -P.mV[VZ]; | ||
1700 | const F32 sin_dir_angle = sqrt(1 - cos_dir_angle * cos_dir_angle); | ||
1701 | |||
1702 | F32 cos_diff_angles = cos_dir_angle * cos_dir_from_top | ||
1703 | + sin_dir_angle * sin_dir_from_top; | ||
1704 | |||
1705 | F32 diff_angles; | ||
1706 | if (cos_diff_angles > (1 - 1e-7)) | ||
1707 | diff_angles = 0; | ||
1708 | else | ||
1709 | diff_angles = acos(cos_diff_angles); | ||
1710 | |||
1711 | const F32 rel_diff_angles = diff_angles / diff_angl_dir; | ||
1712 | const F32 dt = 1 - rel_diff_angles; | ||
1713 | |||
1714 | return (dt < 0) ? 0 : dt; | ||
1715 | } | ||
1716 | |||
1717 | |||
1718 | F32 dtClip(const LLVector3& v0, const LLVector3& v1, F32 far_clip2) | ||
1719 | { | ||
1720 | F32 dt_clip; | ||
1721 | const LLVector3 otrezok = v1 - v0; | ||
1722 | const F32 A = otrezok.magVecSquared(); | ||
1723 | const F32 B = v0 * otrezok; | ||
1724 | const F32 C = v0.magVecSquared() - far_clip2; | ||
1725 | const F32 det = sqrt(B*B - A*C); | ||
1726 | dt_clip = (-B - det) / A; | ||
1727 | if ((dt_clip < 0) || (dt_clip > 1)) | ||
1728 | dt_clip = (-B + det) / A; | ||
1729 | return dt_clip; | ||
1730 | } | ||
1731 | |||
1732 | |||
1733 | void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, | ||
1734 | const LLHeavenBody& HB) | ||
1735 | { | ||
1736 | const LLVector3 &look_at = gCamera->getAtAxis(); | ||
1737 | // const F32 water_height = gAgent.getRegion()->getWaterHeight() + 0.001f; | ||
1738 | // gWorldPointer->getWaterHeight() + 0.001f; | ||
1739 | |||
1740 | LLVector3 to_dir = HB.getDirection(); | ||
1741 | LLVector3 hb_pos = to_dir * (HORIZON_DIST - 10); | ||
1742 | LLVector3 to_dir_proj = to_dir; | ||
1743 | to_dir_proj.mV[VZ] = 0; | ||
1744 | to_dir_proj.normVec(); | ||
1745 | |||
1746 | LLVector3 Right = to_dir % LLVector3::z_axis; | ||
1747 | LLVector3 Up = Right % to_dir; | ||
1748 | Right.normVec(); | ||
1749 | Up.normVec(); | ||
1750 | |||
1751 | // finding angle between look direction and sprite. | ||
1752 | LLVector3 look_at_right = look_at % LLVector3::z_axis; | ||
1753 | look_at_right.normVec(); | ||
1754 | |||
1755 | const static F32 cos_horizon_angle = cosHorizon(0.0f/sResolution); | ||
1756 | //const static F32 horizon_angle = acos(cos_horizon_angle); | ||
1757 | |||
1758 | const F32 enlargm_factor = ( 1 - to_dir.mV[2] ); | ||
1759 | F32 horiz_enlargement = 1 + enlargm_factor * 0.3f; | ||
1760 | F32 vert_enlargement = 1 + enlargm_factor * 0.2f; | ||
1761 | |||
1762 | F32 vert_size = vert_enlargement * HEAVENLY_BODY_SCALE * HB.getDiskRadius(); | ||
1763 | Right *= /*cos_lookAt_toDir */ horiz_enlargement * HEAVENLY_BODY_SCALE * HB.getDiskRadius(); | ||
1764 | Up *= vert_size; | ||
1765 | |||
1766 | LLVector3 v_corner[2]; | ||
1767 | LLVector3 stretch_corner[2]; | ||
1768 | |||
1769 | LLVector3 top_hb = v_corner[0] = stretch_corner[0] = hb_pos - Right + Up; | ||
1770 | v_corner[1] = stretch_corner[1] = hb_pos - Right - Up; | ||
1771 | |||
1772 | F32 dt_hor, dt; | ||
1773 | dt_hor = clip_side_to_horizon(v_corner[1], v_corner[0], cos_horizon_angle); | ||
1774 | |||
1775 | LLVector2 TEX0t = TEX00; | ||
1776 | LLVector2 TEX1t = TEX10; | ||
1777 | LLVector3 lower_corner = v_corner[1]; | ||
1778 | |||
1779 | if ((dt_hor > 0) && (dt_hor < 1)) | ||
1780 | { | ||
1781 | TEX0t = LLVector2(0, dt_hor); | ||
1782 | TEX1t = LLVector2(1, dt_hor); | ||
1783 | lower_corner = (1 - dt_hor) * v_corner[1] + dt_hor * v_corner[0]; | ||
1784 | } | ||
1785 | else | ||
1786 | dt_hor = llmax(0.0f, llmin(1.0f, dt_hor)); | ||
1787 | |||
1788 | top_hb.normVec(); | ||
1789 | const F32 cos_angle_of_view = fabs(top_hb.mV[VZ]); | ||
1790 | const F32 extension = llmin (5.0f, 1.0f / cos_angle_of_view); | ||
1791 | |||
1792 | const S32 cols = 1; | ||
1793 | const S32 raws = lltrunc(16 * extension); | ||
1794 | S32 quads = cols * raws; | ||
1795 | |||
1796 | stretch_corner[0] = lower_corner + extension * (stretch_corner[0] - lower_corner); | ||
1797 | stretch_corner[1] = lower_corner + extension * (stretch_corner[1] - lower_corner); | ||
1798 | |||
1799 | dt = dt_hor; | ||
1800 | |||
1801 | |||
1802 | F32 cos_dir_from_top[2]; | ||
1803 | |||
1804 | LLVector3 dir = stretch_corner[0]; | ||
1805 | dir.normVec(); | ||
1806 | cos_dir_from_top[0] = dir.mV[VZ]; | ||
1807 | |||
1808 | dir = stretch_corner[1]; | ||
1809 | dir.normVec(); | ||
1810 | cos_dir_from_top[1] = dir.mV[VZ]; | ||
1811 | |||
1812 | const F32 sin_dir_from_top = sqrt(1 - cos_dir_from_top[0] * cos_dir_from_top[0]); | ||
1813 | const F32 sin_dir_from_top2 = sqrt(1 - cos_dir_from_top[1] * cos_dir_from_top[1]); | ||
1814 | const F32 cos_diff_dir = cos_dir_from_top[0] * cos_dir_from_top[1] | ||
1815 | + sin_dir_from_top * sin_dir_from_top2; | ||
1816 | const F32 diff_angl_dir = acos(cos_diff_dir); | ||
1817 | |||
1818 | v_corner[0] = stretch_corner[0]; | ||
1819 | v_corner[1] = lower_corner; | ||
1820 | |||
1821 | |||
1822 | LLVector2 TEX0tt = TEX01; | ||
1823 | LLVector2 TEX1tt = TEX11; | ||
1824 | |||
1825 | LLVector3 v_refl_corner[4]; | ||
1826 | LLVector3 v_sprite_corner[4]; | ||
1827 | |||
1828 | S32 vtx; | ||
1829 | for (vtx = 0; vtx < 2; ++vtx) | ||
1830 | { | ||
1831 | LLVector3 light_proj = v_corner[vtx]; | ||
1832 | light_proj.normVec(); | ||
1833 | |||
1834 | const F32 z = light_proj.mV[VZ]; | ||
1835 | const F32 sin_angle = sqrt(1 - z * z); | ||
1836 | light_proj *= 1.f / sin_angle; | ||
1837 | light_proj.mV[VZ] = 0; | ||
1838 | const F32 to_refl_point = H * sin_angle / fabs(z); | ||
1839 | |||
1840 | v_refl_corner[vtx] = to_refl_point * light_proj; | ||
1841 | } | ||
1842 | |||
1843 | |||
1844 | for (vtx = 2; vtx < 4; ++vtx) | ||
1845 | { | ||
1846 | const LLVector3 to_dir_vec = (to_dir_proj * v_refl_corner[vtx-2]) * to_dir_proj; | ||
1847 | v_refl_corner[vtx] = v_refl_corner[vtx-2] + 2 * (to_dir_vec - v_refl_corner[vtx-2]); | ||
1848 | } | ||
1849 | |||
1850 | for (vtx = 0; vtx < 4; ++vtx) | ||
1851 | v_refl_corner[vtx].mV[VZ] -= H; | ||
1852 | |||
1853 | S32 side = 0; | ||
1854 | LLVector3 refl_corn_norm[2]; | ||
1855 | refl_corn_norm[0] = v_refl_corner[1]; | ||
1856 | refl_corn_norm[0].normVec(); | ||
1857 | refl_corn_norm[1] = v_refl_corner[3]; | ||
1858 | refl_corn_norm[1].normVec(); | ||
1859 | |||
1860 | F32 cos_refl_look_at[2]; | ||
1861 | cos_refl_look_at[0] = refl_corn_norm[0] * look_at; | ||
1862 | cos_refl_look_at[1] = refl_corn_norm[1] * look_at; | ||
1863 | |||
1864 | if (cos_refl_look_at[1] > cos_refl_look_at[0]) | ||
1865 | { | ||
1866 | side = 2; | ||
1867 | } | ||
1868 | |||
1869 | //const F32 far_clip = (gCamera->getFar() - 0.01) / far_clip_factor; | ||
1870 | const F32 far_clip = 512; | ||
1871 | const F32 far_clip2 = far_clip*far_clip; | ||
1872 | |||
1873 | F32 dt_clip; | ||
1874 | F32 vtx_near2, vtx_far2; | ||
1875 | |||
1876 | if ((vtx_far2 = v_refl_corner[side].magVecSquared()) > far_clip2) | ||
1877 | { | ||
1878 | // whole thing is sprite: reflection is beyond far clip plane. | ||
1879 | dt_clip = 1.1f; | ||
1880 | quads = 1; | ||
1881 | } | ||
1882 | else if ((vtx_near2 = v_refl_corner[side+1].magVecSquared()) > far_clip2) | ||
1883 | { | ||
1884 | // part is reflection, the rest is sprite. | ||
1885 | dt_clip = dtClip(v_refl_corner[side + 1], v_refl_corner[side], far_clip2); | ||
1886 | const LLVector3 P = (1 - dt_clip) * v_refl_corner[side + 1] + dt_clip * v_refl_corner[side]; | ||
1887 | |||
1888 | F32 dt_tex = dtReflection(P, cos_dir_from_top[0], sin_dir_from_top, diff_angl_dir); | ||
1889 | |||
1890 | dt = dt_tex; | ||
1891 | TEX0tt = LLVector2(0, dt); | ||
1892 | TEX1tt = LLVector2(1, dt); | ||
1893 | quads++; | ||
1894 | } | ||
1895 | else | ||
1896 | { | ||
1897 | // whole thing is correct reflection. | ||
1898 | dt_clip = -0.1f; | ||
1899 | } | ||
1900 | |||
1901 | LLStrider<LLVector3> verticesp; | ||
1902 | LLStrider<LLVector3> normalsp; | ||
1903 | LLStrider<LLVector2> texCoordsp; | ||
1904 | U32 *indicesp; | ||
1905 | S32 index_offset; | ||
1906 | LLFace *face = mFace[FACE_REFLECTION]; | ||
1907 | |||
1908 | face->setPrimType(LLTriangles); | ||
1909 | face->setSize(quads * 4, quads * 6); | ||
1910 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
1911 | if (-1 == index_offset) | ||
1912 | { | ||
1913 | return; | ||
1914 | } | ||
1915 | |||
1916 | LLColor3 hb_col3 = HB.getInterpColor(); | ||
1917 | hb_col3.clamp(); | ||
1918 | const LLColor4 hb_col = LLColor4(hb_col3); | ||
1919 | |||
1920 | const F32 min_attenuation = 0.4f; | ||
1921 | const F32 max_attenuation = 0.7f; | ||
1922 | const F32 attenuation = min_attenuation | ||
1923 | + cos_angle_of_view * (max_attenuation - min_attenuation); | ||
1924 | |||
1925 | LLColor4 hb_refl_col = (1-attenuation) * hb_col + attenuation * mFogColor; | ||
1926 | face->setFaceColor(hb_refl_col); | ||
1927 | |||
1928 | LLVector3 v_far[2]; | ||
1929 | v_far[0] = v_refl_corner[1]; | ||
1930 | v_far[1] = v_refl_corner[3]; | ||
1931 | |||
1932 | if(dt_clip > 0) | ||
1933 | { | ||
1934 | if (dt_clip >= 1) | ||
1935 | { | ||
1936 | for (S32 vtx = 0; vtx < 4; ++vtx) | ||
1937 | { | ||
1938 | F32 ratio = far_clip / v_refl_corner[vtx].magVec(); | ||
1939 | *(verticesp++) = v_refl_corner[vtx] = ratio * v_refl_corner[vtx] + mCameraPosAgent; | ||
1940 | } | ||
1941 | const LLVector3 draw_pos = 0.25 * | ||
1942 | (v_refl_corner[0] + v_refl_corner[1] + v_refl_corner[2] + v_refl_corner[3]); | ||
1943 | face->mCenterAgent = draw_pos; | ||
1944 | } | ||
1945 | else | ||
1946 | { | ||
1947 | F32 ratio = far_clip / v_refl_corner[1].magVec(); | ||
1948 | v_sprite_corner[1] = v_refl_corner[1] * ratio; | ||
1949 | |||
1950 | ratio = far_clip / v_refl_corner[3].magVec(); | ||
1951 | v_sprite_corner[3] = v_refl_corner[3] * ratio; | ||
1952 | |||
1953 | v_refl_corner[1] = (1 - dt_clip) * v_refl_corner[1] + dt_clip * v_refl_corner[0]; | ||
1954 | v_refl_corner[3] = (1 - dt_clip) * v_refl_corner[3] + dt_clip * v_refl_corner[2]; | ||
1955 | v_sprite_corner[0] = v_refl_corner[1]; | ||
1956 | v_sprite_corner[2] = v_refl_corner[3]; | ||
1957 | |||
1958 | for (S32 vtx = 0; vtx < 4; ++vtx) | ||
1959 | { | ||
1960 | *(verticesp++) = v_sprite_corner[vtx] + mCameraPosAgent; | ||
1961 | } | ||
1962 | |||
1963 | const LLVector3 draw_pos = 0.25 * | ||
1964 | (v_refl_corner[0] + v_sprite_corner[1] + v_refl_corner[2] + v_sprite_corner[3]); | ||
1965 | face->mCenterAgent = draw_pos; | ||
1966 | } | ||
1967 | |||
1968 | *(texCoordsp++) = TEX0tt; | ||
1969 | *(texCoordsp++) = TEX0t; | ||
1970 | *(texCoordsp++) = TEX1tt; | ||
1971 | *(texCoordsp++) = TEX1t; | ||
1972 | |||
1973 | *indicesp++ = index_offset + 0; | ||
1974 | *indicesp++ = index_offset + 2; | ||
1975 | *indicesp++ = index_offset + 1; | ||
1976 | |||
1977 | *indicesp++ = index_offset + 1; | ||
1978 | *indicesp++ = index_offset + 2; | ||
1979 | *indicesp++ = index_offset + 3; | ||
1980 | |||
1981 | index_offset += 4; | ||
1982 | } | ||
1983 | |||
1984 | if (dt_clip < 1) | ||
1985 | { | ||
1986 | if (dt_clip <= 0) | ||
1987 | { | ||
1988 | const LLVector3 draw_pos = 0.25 * | ||
1989 | (v_refl_corner[0] + v_refl_corner[1] + v_refl_corner[2] + v_refl_corner[3]); | ||
1990 | face->mCenterAgent = draw_pos; | ||
1991 | } | ||
1992 | |||
1993 | const F32 raws_inv = 1.f/raws; | ||
1994 | const F32 cols_inv = 1.f/cols; | ||
1995 | LLVector3 left = v_refl_corner[0] - v_refl_corner[1]; | ||
1996 | LLVector3 right = v_refl_corner[2] - v_refl_corner[3]; | ||
1997 | left *= raws_inv; | ||
1998 | right *= raws_inv; | ||
1999 | |||
2000 | F32 dt_raw = dt; | ||
2001 | |||
2002 | for (S32 raw = 0; raw < raws; ++raw) | ||
2003 | { | ||
2004 | F32 dt_v0 = raw * raws_inv; | ||
2005 | F32 dt_v1 = (raw + 1) * raws_inv; | ||
2006 | const LLVector3 BL = v_refl_corner[1] + (F32)raw * left; | ||
2007 | const LLVector3 BR = v_refl_corner[3] + (F32)raw * right; | ||
2008 | const LLVector3 EL = BL + left; | ||
2009 | const LLVector3 ER = BR + right; | ||
2010 | dt_v0 = dt_raw; | ||
2011 | dt_raw = dt_v1 = dtReflection(EL, cos_dir_from_top[0], sin_dir_from_top, diff_angl_dir); | ||
2012 | for (S32 col = 0; col < cols; ++col) | ||
2013 | { | ||
2014 | F32 dt_h0 = col * cols_inv; | ||
2015 | *(verticesp++) = (1 - dt_h0) * EL + dt_h0 * ER + mCameraPosAgent; | ||
2016 | *(verticesp++) = (1 - dt_h0) * BL + dt_h0 * BR + mCameraPosAgent; | ||
2017 | F32 dt_h1 = (col + 1) * cols_inv; | ||
2018 | *(verticesp++) = (1 - dt_h1) * EL + dt_h1 * ER + mCameraPosAgent; | ||
2019 | *(verticesp++) = (1 - dt_h1) * BL + dt_h1 * BR + mCameraPosAgent; | ||
2020 | |||
2021 | *(texCoordsp++) = LLVector2(dt_h0, dt_v1); | ||
2022 | *(texCoordsp++) = LLVector2(dt_h0, dt_v0); | ||
2023 | *(texCoordsp++) = LLVector2(dt_h1, dt_v1); | ||
2024 | *(texCoordsp++) = LLVector2(dt_h1, dt_v0); | ||
2025 | |||
2026 | *indicesp++ = index_offset + 0; | ||
2027 | *indicesp++ = index_offset + 2; | ||
2028 | *indicesp++ = index_offset + 1; | ||
2029 | |||
2030 | *indicesp++ = index_offset + 1; | ||
2031 | *indicesp++ = index_offset + 2; | ||
2032 | *indicesp++ = index_offset + 3; | ||
2033 | |||
2034 | index_offset += 4; | ||
2035 | } | ||
2036 | } | ||
2037 | } | ||
2038 | } | ||
2039 | |||
2040 | |||
2041 | |||
2042 | |||
2043 | void LLVOSky::updateFog(const F32 distance) | ||
2044 | { | ||
2045 | if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG)) | ||
2046 | { | ||
2047 | /*gGLSFog.addCap(GL_FOG, FALSE); | ||
2048 | gGLSPipeline.addCap(GL_FOG, FALSE); | ||
2049 | gGLSPipelineAlpha.addCap(GL_FOG, FALSE); | ||
2050 | gGLSPipelinePixieDust.addCap(GL_FOG, FALSE); | ||
2051 | gGLSPipelineSelection.addCap(GL_FOG, FALSE); | ||
2052 | gGLSPipelineAvatar.addCap(GL_FOG, FALSE); | ||
2053 | gGLSPipelineAvatarAlphaOnePass.addCap(GL_FOG, FALSE); | ||
2054 | gGLSPipelineAvatarAlphaPass1.addCap(GL_FOG, FALSE); | ||
2055 | gGLSPipelineAvatarAlphaPass2.addCap(GL_FOG, FALSE); | ||
2056 | gGLSPipelineAvatarAlphaPass3.addCap(GL_FOG, FALSE);*/ | ||
2057 | glFogf(GL_FOG_DENSITY, 0); | ||
2058 | glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV); | ||
2059 | glFogf(GL_FOG_END, 1000000.f); | ||
2060 | return; | ||
2061 | } | ||
2062 | else | ||
2063 | { | ||
2064 | /*gGLSFog.addCap(GL_FOG, TRUE); | ||
2065 | gGLSPipeline.addCap(GL_FOG, TRUE); | ||
2066 | gGLSPipelineAlpha.addCap(GL_FOG, TRUE); | ||
2067 | gGLSPipelinePixieDust.addCap(GL_FOG, TRUE); | ||
2068 | gGLSPipelineSelection.addCap(GL_FOG, TRUE); | ||
2069 | if (!gGLManager.mIsATI) | ||
2070 | { | ||
2071 | gGLSPipelineAvatar.addCap(GL_FOG, TRUE); | ||
2072 | gGLSPipelineAvatarAlphaOnePass.addCap(GL_FOG, TRUE); | ||
2073 | gGLSPipelineAvatarAlphaPass1.addCap(GL_FOG, TRUE); | ||
2074 | gGLSPipelineAvatarAlphaPass2.addCap(GL_FOG, TRUE); | ||
2075 | gGLSPipelineAvatarAlphaPass3.addCap(GL_FOG, TRUE); | ||
2076 | }*/ | ||
2077 | } | ||
2078 | |||
2079 | const BOOL hide_clip_plane = TRUE; | ||
2080 | LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f); | ||
2081 | |||
2082 | const F32 water_height = gAgent.getRegion()->getWaterHeight(); | ||
2083 | // gWorldPointer->getWaterHeight(); | ||
2084 | F32 camera_height = gAgent.getCameraPositionAgent().mV[2]; | ||
2085 | |||
2086 | F32 near_clip_height = gCamera->getAtAxis().mV[VZ] * gCamera->getNear(); | ||
2087 | camera_height += near_clip_height; | ||
2088 | |||
2089 | F32 fog_distance = 0.f; | ||
2090 | LLColor3 res_color[3]; | ||
2091 | |||
2092 | LLColor3 sky_fog_color = LLColor3::white; | ||
2093 | LLColor3 render_fog_color = LLColor3::white; | ||
2094 | |||
2095 | LLColor3 transp; | ||
2096 | LLVector3 tosun = getToSunLast(); | ||
2097 | const F32 tosun_z = tosun.mV[VZ]; | ||
2098 | tosun.mV[VZ] = 0.f; | ||
2099 | tosun.normVec(); | ||
2100 | LLVector3 perp_tosun; | ||
2101 | perp_tosun.mV[VX] = -tosun.mV[VY]; | ||
2102 | perp_tosun.mV[VY] = tosun.mV[VX]; | ||
2103 | LLVector3 tosun_45 = tosun + perp_tosun; | ||
2104 | tosun_45.normVec(); | ||
2105 | |||
2106 | F32 delta = 0.06f; | ||
2107 | tosun.mV[VZ] = delta; | ||
2108 | perp_tosun.mV[VZ] = delta; | ||
2109 | tosun_45.mV[VZ] = delta; | ||
2110 | tosun.normVec(); | ||
2111 | perp_tosun.normVec(); | ||
2112 | tosun_45.normVec(); | ||
2113 | |||
2114 | // Sky colors, just slightly above the horizon in the direction of the sun, perpendicular to the sun, and at a 45 degree angle to the sun. | ||
2115 | calcSkyColorInDir(res_color[0],transp, tosun); | ||
2116 | calcSkyColorInDir(res_color[1],transp, perp_tosun); | ||
2117 | calcSkyColorInDir(res_color[2],transp, tosun_45); | ||
2118 | |||
2119 | sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]); | ||
2120 | |||
2121 | F32 full_off = -0.25f; | ||
2122 | F32 full_on = 0.00f; | ||
2123 | F32 on = (tosun_z - full_off) / (full_on - full_off); | ||
2124 | on = llclamp(on, 0.01f, 1.f); | ||
2125 | sky_fog_color *= 0.5f * on; | ||
2126 | |||
2127 | |||
2128 | // We need to clamp these to non-zero, in order for the gamma correction to work. 0^y = ??? | ||
2129 | S32 i; | ||
2130 | for (i = 0; i < 3; i++) | ||
2131 | { | ||
2132 | sky_fog_color.mV[i] = llmax(0.0001f, sky_fog_color.mV[i]); | ||
2133 | } | ||
2134 | |||
2135 | color_gamma_correct(sky_fog_color); | ||
2136 | |||
2137 | if (!(gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT) > LLDrawPool::SHADER_LEVEL_SCATTERING)) | ||
2138 | { | ||
2139 | render_fog_color = sky_fog_color; | ||
2140 | } | ||
2141 | |||
2142 | if (camera_height > water_height) | ||
2143 | { | ||
2144 | fog_distance = mFogRatio * distance; | ||
2145 | LLColor4 fog(render_fog_color); | ||
2146 | glFogfv(GL_FOG_COLOR, fog.mV); | ||
2147 | } | ||
2148 | else | ||
2149 | { | ||
2150 | // Interpolate between sky fog and water fog... | ||
2151 | F32 depth = water_height - camera_height; | ||
2152 | F32 depth_frac = 1.f/(1.f + 200.f*depth); | ||
2153 | F32 color_frac = 1.f/(1.f + 0.5f* depth)* 0.2f; | ||
2154 | fog_distance = (mFogRatio * distance) * depth_frac + 30.f * (1.f-depth_frac); | ||
2155 | fog_distance = llmin(75.f, fog_distance); | ||
2156 | |||
2157 | F32 brightness = 1.f/(1.f + 0.05f*depth); | ||
2158 | F32 sun_brightness = getSunDiffuseColor().magVec() * 0.3f; | ||
2159 | brightness = llmin(1.f, brightness); | ||
2160 | brightness = llmin(brightness, sun_brightness); | ||
2161 | color_frac = llmin(0.7f, color_frac); | ||
2162 | |||
2163 | LLColor4 fogCol = brightness * (color_frac * render_fog_color + (1.f - color_frac) * LLColor4(0.f, 0.2f, 0.3f, 1.f)); | ||
2164 | fogCol.setAlpha(1); | ||
2165 | glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV); | ||
2166 | } | ||
2167 | |||
2168 | mFogColor = sky_fog_color; | ||
2169 | mFogColor.setAlpha(1); | ||
2170 | LLGLSFog gls_fog; | ||
2171 | |||
2172 | F32 fog_density; | ||
2173 | if (hide_clip_plane) | ||
2174 | { | ||
2175 | // For now, set the density to extend to the cull distance. | ||
2176 | const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f))) | ||
2177 | fog_density = f_log/fog_distance; | ||
2178 | glFogi(GL_FOG_MODE, GL_EXP2); | ||
2179 | } | ||
2180 | else | ||
2181 | { | ||
2182 | const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f)) | ||
2183 | fog_density = (f_log)/fog_distance; | ||
2184 | glFogi(GL_FOG_MODE, GL_EXP); | ||
2185 | } | ||
2186 | |||
2187 | glFogf(GL_FOG_END, fog_distance*2.2f); | ||
2188 | |||
2189 | glFogf(GL_FOG_DENSITY, fog_density); | ||
2190 | |||
2191 | glHint(GL_FOG_HINT, GL_NICEST); | ||
2192 | stop_glerror(); | ||
2193 | } | ||
2194 | |||
2195 | // static | ||
2196 | void LLHaze::initClass() | ||
2197 | { | ||
2198 | sAirScaSeaLevel = LLHaze::calcAirScaSeaLevel(); | ||
2199 | } | ||
2200 | |||
2201 | |||
2202 | |||
2203 | // Functions used a lot. | ||
2204 | |||
2205 | |||
2206 | F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply) | ||
2207 | { | ||
2208 | F32 mv = color_max(col); | ||
2209 | if (0 == mv) | ||
2210 | { | ||
2211 | return 0; | ||
2212 | } | ||
2213 | |||
2214 | col *= 1.f / mv; | ||
2215 | color_pow(col, e); | ||
2216 | if (postmultiply) | ||
2217 | { | ||
2218 | col *= mv; | ||
2219 | } | ||
2220 | return mv; | ||
2221 | } | ||
2222 | |||
2223 | // Returns angle (RADIANs) between the horizontal projection of "v" and the x_axis. | ||
2224 | // Range of output is 0.0f to 2pi //359.99999...f | ||
2225 | // Returns 0.0f when "v" = +/- z_axis. | ||
2226 | F32 azimuth(const LLVector3 &v) | ||
2227 | { | ||
2228 | F32 azimuth = 0.0f; | ||
2229 | if (v.mV[VX] == 0.0f) | ||
2230 | { | ||
2231 | if (v.mV[VY] > 0.0f) | ||
2232 | { | ||
2233 | azimuth = F_PI * 0.5f; | ||
2234 | } | ||
2235 | else if (v.mV[VY] < 0.0f) | ||
2236 | { | ||
2237 | azimuth = F_PI * 1.5f;// 270.f; | ||
2238 | } | ||
2239 | } | ||
2240 | else | ||
2241 | { | ||
2242 | azimuth = (F32) atan(v.mV[VY] / v.mV[VX]); | ||
2243 | if (v.mV[VX] < 0.0f) | ||
2244 | { | ||
2245 | azimuth += F_PI; | ||
2246 | } | ||
2247 | else if (v.mV[VY] < 0.0f) | ||
2248 | { | ||
2249 | azimuth += F_PI * 2; | ||
2250 | } | ||
2251 | } | ||
2252 | return azimuth; | ||
2253 | } | ||
2254 | |||
2255 | |||
2256 | #if 0 | ||
2257 | // Not currently used | ||
2258 | LLColor3 LLVOSky::calcGroundFog(LLColor3& transp, const LLVector3 &view_dir, F32 obj_dist) const | ||
2259 | { | ||
2260 | LLColor3 col; | ||
2261 | calcGroundFog(col, transp, view_dir, obj_dist); | ||
2262 | col *= mBrightnessScaleGuess; | ||
2263 | return col; | ||
2264 | } | ||
2265 | #endif | ||
2266 | |||
2267 | void LLVOSky::setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity) | ||
2268 | { | ||
2269 | LLVector3 sun_direction = (sun_dir.magVec() == 0) ? LLVector3::x_axis : sun_dir; | ||
2270 | sun_direction.normVec(); | ||
2271 | F32 dp = mSun.getDirection() * sun_direction; | ||
2272 | mSun.setDirection(sun_direction); | ||
2273 | mSun.setAngularVelocity(sun_ang_velocity); | ||
2274 | mMoon.setDirection(-sun_direction); | ||
2275 | if (dp < 0.995f) { //the sun jumped a great deal, update immediately | ||
2276 | updateHaze(); | ||
2277 | mWeatherChange = FALSE; | ||
2278 | mForceUpdate = TRUE; | ||
2279 | } | ||
2280 | else if (mWeatherChange && (mSun.getDirection().mV[VZ] > -0.5) ) | ||
2281 | { | ||
2282 | updateHaze(); | ||
2283 | init(); | ||
2284 | mWeatherChange = FALSE; | ||
2285 | } | ||
2286 | else if (mSun.getDirection().mV[VZ] < -0.5) | ||
2287 | { | ||
2288 | mWeatherChange = TRUE; | ||
2289 | } | ||
2290 | } | ||
2291 | |||
2292 | #define INV_WAVELENGTH_R_POW4 (1.f/0.2401f) // = 1/0.7^4 | ||
2293 | #define INV_WAVELENGTH_G_POW4 (1.f/0.0789f) // = 1/0.53^4 | ||
2294 | #define INV_WAVELENGTH_B_POW4 (1.f/0.03748f) // = 1/0.44^4 | ||
2295 | |||
2296 | // Dummy class for globals used below. Replace when KILLERSKY is merged in. | ||
2297 | class LLKillerSky | ||
2298 | { | ||
2299 | public: | ||
2300 | static F32 sRaleighGroundDensity; | ||
2301 | static F32 sMieFactor; | ||
2302 | static F32 sNearFalloffFactor; | ||
2303 | static F32 sSkyContrib; | ||
2304 | |||
2305 | static void getRaleighCoefficients(float eye_sun_dp, float density, float *coefficients) | ||
2306 | { | ||
2307 | float dp = eye_sun_dp; | ||
2308 | float angle_dep = density*(1 + dp*dp); | ||
2309 | coefficients[0] = angle_dep * INV_WAVELENGTH_R_POW4; | ||
2310 | coefficients[1] = angle_dep * INV_WAVELENGTH_G_POW4; | ||
2311 | coefficients[2] = angle_dep * INV_WAVELENGTH_B_POW4; | ||
2312 | } | ||
2313 | |||
2314 | static void getMieCoefficients(float eye_sun_dp, float density, float *coefficient) | ||
2315 | { | ||
2316 | // TOTALLY ARBITRARY FUNCTION. Seems to work though | ||
2317 | // If anyone can replace this with some *actual* mie function, that'd be great | ||
2318 | float dp = eye_sun_dp; | ||
2319 | float dp_highpower = dp*dp; | ||
2320 | float angle_dep = density * (llclamp(dp_highpower*dp, 0.f, 1.f) + 0.4f); | ||
2321 | *coefficient = angle_dep; | ||
2322 | } | ||
2323 | }; | ||
2324 | |||
2325 | F32 LLKillerSky::sRaleighGroundDensity = 0.013f; | ||
2326 | F32 LLKillerSky::sMieFactor = 50; | ||
2327 | F32 LLKillerSky::sNearFalloffFactor = 1.5f; | ||
2328 | F32 LLKillerSky::sSkyContrib = 0.06f; | ||
2329 | |||
2330 | void LLVOSky::generateScatterMap() | ||
2331 | { | ||
2332 | float raleigh[3], mie; | ||
2333 | |||
2334 | mScatterMap = new LLImageGL(FALSE); | ||
2335 | mScatterMapRaw = new LLImageRaw(256, 256, 4); | ||
2336 | U8 *data = mScatterMapRaw->getData(); | ||
2337 | |||
2338 | F32 light_brightness = gSky.getSunDirection().mV[VZ]+0.1f; | ||
2339 | LLColor4 light_color; | ||
2340 | LLColor4 sky_color; | ||
2341 | if (light_brightness > 0) | ||
2342 | { | ||
2343 | F32 interp = sqrtf(light_brightness); | ||
2344 | light_brightness = sqrt(sqrtf(interp)); | ||
2345 | light_color = lerp(gSky.getSunDiffuseColor(), LLColor4(1,1,1,1), interp) * light_brightness; | ||
2346 | sky_color = lerp(LLColor4(0,0,0,0), LLColor4(0.4f, 0.6f, 1.f, 1.f), light_brightness)*LLKillerSky::sSkyContrib; | ||
2347 | } | ||
2348 | else | ||
2349 | { | ||
2350 | light_brightness = /*0.3f*/sqrt(-light_brightness); | ||
2351 | light_color = gSky.getMoonDiffuseColor() * light_brightness; | ||
2352 | sky_color = LLColor4(0,0,0,1); | ||
2353 | } | ||
2354 | |||
2355 | // x = distance [0..1024m] | ||
2356 | // y = dot product [-1,1] | ||
2357 | for (int y=0;y<256;y++) | ||
2358 | { | ||
2359 | // Accumulate outward | ||
2360 | float accum_r = 0, accum_g = 0, accum_b = 0; | ||
2361 | |||
2362 | float dp = (((float)y)/255.f)*1.95f - 0.975f; | ||
2363 | U8 *scanline = &data[y*256*4]; | ||
2364 | for (int x=0;x<256;x++) | ||
2365 | { | ||
2366 | float dist = ((float)x+1)*4; // x -> 2048 | ||
2367 | |||
2368 | float raleigh_density = LLKillerSky::sRaleighGroundDensity * 0.05f; // Arbitrary? Perhaps... | ||
2369 | float mie_density = raleigh_density*LLKillerSky::sMieFactor; | ||
2370 | |||
2371 | float extinction_factor = dist/LLKillerSky::sNearFalloffFactor; | ||
2372 | |||
2373 | LLKillerSky::getRaleighCoefficients(dp, raleigh_density, raleigh); | ||
2374 | LLKillerSky::getMieCoefficients(dp, mie_density, &mie); | ||
2375 | |||
2376 | float falloff_r = pow(llclamp(0.985f-raleigh[0],0.f,1.f), extinction_factor); | ||
2377 | float falloff_g = pow(llclamp(0.985f-raleigh[1],0.f,1.f), extinction_factor); | ||
2378 | float falloff_b = pow(llclamp(0.985f-raleigh[2],0.f,1.f), extinction_factor); | ||
2379 | |||
2380 | float light_r = light_color.mV[0] * (raleigh[0]+mie+sky_color.mV[0]) * falloff_r; | ||
2381 | float light_g = light_color.mV[1] * (raleigh[1]+mie+sky_color.mV[1]) * falloff_g; | ||
2382 | float light_b = light_color.mV[2] * (raleigh[2]+mie+sky_color.mV[2]) * falloff_b; | ||
2383 | |||
2384 | accum_r += light_r; | ||
2385 | accum_g += light_g; | ||
2386 | accum_b += light_b; | ||
2387 | |||
2388 | scanline[x*4] = (U8)llclamp(accum_r*255.f, 0.f, 255.f); | ||
2389 | scanline[x*4+1] = (U8)llclamp(accum_g*255.f, 0.f, 255.f); | ||
2390 | scanline[x*4+2] = (U8)llclamp(accum_b*255.f, 0.f, 255.f); | ||
2391 | float alpha = ((falloff_r+falloff_g+falloff_b)*0.33f); | ||
2392 | scanline[x*4+3] = (U8)llclamp(alpha*255.f, 0.f, 255.f); // Avg falloff | ||
2393 | |||
2394 | // Output color Co, Input color Ci, Map channels Mrgb, Ma: | ||
2395 | // Co = (Ci * Ma) + Mrgb | ||
2396 | } | ||
2397 | } | ||
2398 | |||
2399 | mScatterMap->createGLTexture(0, mScatterMapRaw); | ||
2400 | mScatterMap->bind(0); | ||
2401 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
2402 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
2403 | } | ||
2404 | |||
2405 | #if 0 | ||
2406 | // Not currently used | ||
2407 | void LLVOSky::calcGroundFog(LLColor3& res, LLColor3& transp, const LLVector3 view_dir, F32 obj_dist) const | ||
2408 | { | ||
2409 | const LLVector3& tosun = getToSunLast();//use_old_value ? sunDir() : toSunLast(); | ||
2410 | res.setToBlack(); | ||
2411 | transp.setToWhite(); | ||
2412 | const F32 dist = obj_dist * mWorldScale; | ||
2413 | |||
2414 | //LLVector3 view_dir = gCamera->getAtAxis(); | ||
2415 | |||
2416 | const F32 cos_dir = view_dir * tosun; | ||
2417 | LLVector3 dir = view_dir; | ||
2418 | LLVector3 virtual_P = mCameraPosAgent + dist * dir; | ||
2419 | |||
2420 | if (dir.mV[VZ] < 0) | ||
2421 | { | ||
2422 | dir = -dir; | ||
2423 | } | ||
2424 | |||
2425 | const F32 z_dir = dir.mV[2]; | ||
2426 | |||
2427 | const F32 h = mCameraPosAgent.mV[2]; | ||
2428 | |||
2429 | transp = color_div(mTransp.calcTransp(dir * calcUpVec(virtual_P), 0), | ||
2430 | mTransp.calcTransp(z_dir, h)); | ||
2431 | |||
2432 | if (calcHitsEarth(mCameraPosAgent, tosun) > 0) | ||
2433 | { | ||
2434 | const F32 avg = llmin(1.f, 1.2f * color_avg(transp)); | ||
2435 | transp = LLColor3(avg, avg, avg); | ||
2436 | return; | ||
2437 | } | ||
2438 | |||
2439 | LLColor3 haze_sca_opt_depth = mHaze.getSigSca(); | ||
2440 | LLColor3 sun_transp; | ||
2441 | mTransp.calcTransp(tosun.mV[2], -0.1f, sun_transp); | ||
2442 | |||
2443 | res = calcAirPhaseFunc(cos_dir) * LLHaze::getAirScaSeaLevel(); | ||
2444 | res += mHaze.calcPhase(cos_dir) * mHaze.getSigSca(); | ||
2445 | res = mSun.getIntensity() * dist * sun_transp * res; | ||
2446 | } | ||
2447 | |||
2448 | #endif | ||