aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llettherebelight.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llettherebelight.cpp')
-rw-r--r--linden/indra/newview/llettherebelight.cpp587
1 files changed, 587 insertions, 0 deletions
diff --git a/linden/indra/newview/llettherebelight.cpp b/linden/indra/newview/llettherebelight.cpp
new file mode 100644
index 0000000..7fc2a3d
--- /dev/null
+++ b/linden/indra/newview/llettherebelight.cpp
@@ -0,0 +1,587 @@
1/**
2 * @file llettherebelight.cpp
3 * @brief Handler for Meta7 Lightshare (region-side Windlight settings), and other methods of sharing WindLight.
4 *
5 * Copyright (c) 2010, Tom Grimshaw (Tom Meta)
6 * Copyright (c) 2010, Jacek Antonelli
7 * Copyright (c) 2012, David Seikel
8 *
9 * The source code in this file ("Source Code") is provided to you
10 * under the terms of the GNU General Public License, version 2.0
11 * ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in
12 * this distribution, or online at
13 * http://secondlifegrid.net/programs/open_source/licensing/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at
19 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 *
21 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above,
23 * and agree to abide by those obligations.
24 *
25 * ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO
26 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
27 * COMPLETENESS OR PERFORMANCE.
28 */
29
30
31
32#include "linden_common.h"
33#include "llviewercontrol.h"
34#include "llwaterparammanager.h"
35#include "llwaterparamset.h"
36#include "llwlparammanager.h"
37#include "llwlparamset.h"
38#include "message.h"
39#include "meta7windlight.h"
40
41#include "llettherebelight.h"
42
43#include "llagent.h"
44#include "llworld.h"
45
46
47const std::string LightShare::sRegionPresetName = "(Region settings)";
48const std::string LightShare::sParcelPresetName = "(Parcel settings)";
49const std::string LightShare::sRLVPresetName = "(RLV settings)";
50
51
52LLWaterParamSet* LightShare::mWater = NULL;
53LLWLParamSet* LightShare::mSky = NULL;
54LLUUID* LightShare::mWaterNormal = NULL;
55LLTimer* LightShare::sIgnoreTimer = new LLTimer();
56bool LightShare::sIgnoreRegion = false;
57
58
59LightShare::LightShare( LLMessageSystem* msg ) :
60 mPacket(NULL),
61 mIsValid(false)
62{
63 std::string method;
64 msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method);
65
66 if( method != "Windlight" )
67 {
68 return; // Wrong message type, somehow.
69 }
70
71 S32 size = msg->getSizeFast(_PREHASH_ParamList, 0, _PREHASH_Parameter);
72
73 if( size < 0 || 250 < size )
74 {
75 return; // Too small or too big.
76 }
77
78 // Unpack and process the message's binary payload.
79 char buf[250];
80 msg->getBinaryDataFast(_PREHASH_ParamList,
81 _PREHASH_Parameter,
82 buf, size, 0, 249);
83
84 mWater = new LLWaterParamSet();
85 mSky = new LLWLParamSet();
86
87 mWaterNormal = new LLUUID();
88
89 process_packet(&buf[0]);
90 process_water();
91 process_sky();
92
93 // *TODO: Actually validate the settings.
94 mIsValid = true;
95}
96
97
98LightShare::~LightShare()
99{
100 delete mWater;
101 delete mSky;
102 delete mWaterNormal;
103}
104
105
106// static
107void LightShare::processWindlight(LLMessageSystem* msg, void**)
108{
109 if( gSavedSettings.getU32("LightShareAllowed") <= LIGHTSHARE_NEVER )
110 return;
111
112 LightShare* wl = new LightShare(msg);
113
114 if (!wl)
115 return;
116
117 if(!wl->isValid() )
118 {
119 delete wl;
120 return;
121 }
122
123 applyMaybe(wl->mWater, wl->mWaterNormal, wl->mSky);
124}
125
126
127//static
128void LightShare::applyMaybe(LLWaterParamSet* thisWater, LLUUID* thisWaterNormal, LLWLParamSet* thisSky)
129{
130 if( gSavedSettings.getU32("LightShareAllowed") <= LIGHTSHARE_NEVER )
131 return;
132
133 std::string water = LLWaterParamManager::instance()->mCurParams.mName;
134 std::string sky = LLWLParamManager::instance()->mCurParams.mName;
135
136 // If they are using region settings already, or LightShare is
137 // always allowed, just apply the new settings, don't bother asking.
138 if( gSavedSettings.getU32("LightShareAllowed") == LIGHTSHARE_ALWAYS ||
139 (sky == sRegionPresetName && water == sRegionPresetName) )
140 {
141 mSky = thisSky;
142 mWater = thisWater;
143 mWaterNormal = thisWaterNormal;
144 apply(mWater, mWaterNormal, mSky, WL_SCOPE_REGION);
145 return;
146 }
147
148 if( !ignoreTimerHasExpired() )
149 {
150 // The user recently ignored a windlight message, so ignore
151 // this one too, and restart the timer.
152 restartIgnoreTimer();
153 return;
154 }
155
156 if(sIgnoreRegion)
157 {
158 // We are ignoring new settings until user enters a new region.
159 return;
160 }
161
162 if( gSavedSettings.getU32("LightShareAllowed") == LIGHTSHARE_ASK && mSky == NULL && mWater == NULL)
163 {
164 // No most recent, so store this and create notification
165 // asking the user whether to apply or not.
166 mSky = thisSky;
167 mWater = thisWater;
168 mWaterNormal = thisWaterNormal;
169 LLNotifications::instance().add("ConfirmLightShare", LLSD(), LLSD(),
170 boost::bind(&applyCallback, _1, _2));
171 }
172 else
173 {
174 // No new notification (to avoid spamming the user, we do keep the saves from above)
175 mSky = thisSky;
176 mWater = thisWater;
177 mWaterNormal = thisWaterNormal;
178 }
179}
180
181// static
182bool LightShare::applyCallback(const LLSD& notification, const LLSD& response)
183{
184 S32 option = LLNotification::getSelectedOption(notification, response);
185
186 switch(option)
187 {
188 case 0:{
189 // "Apply"
190 apply(mWater, mWaterNormal, mSky, WL_SCOPE_REGION);
191
192 break;
193 }
194 case 1:{
195 // "Not Now", ignore until the region stops spamming
196 restartIgnoreTimer();
197 break;
198 }
199 case 2:{
200 // "Ignore", ignore all until user leaves the region
201 sIgnoreRegion = true;
202 break;
203 }
204 }
205
206 return false;
207}
208
209// static
210void LightShare::resetRegion()
211{
212 sIgnoreRegion = false;
213 apply(NULL, NULL, NULL, WL_SCOPE_REGION);
214}
215
216// static
217void LightShare::restartIgnoreTimer()
218{
219 F32 time = gSavedSettings.getF32("LightShareIgnoreTimer");
220 sIgnoreTimer->start();
221 sIgnoreTimer->setTimerExpirySec( (time < 0) ? 0 : time );
222}
223
224// static
225bool LightShare::ignoreTimerHasExpired()
226{
227 return sIgnoreTimer->hasExpired();
228}
229
230// TODO - have regionSet and parcelSet be arrays, so we can deal with height zones.
231static struct WLCombined userSet, regionSet, parcelSet, RLVSet;
232
233// TODO - should spread this merging stuff around,
234// so that eventually we can get rid of almost identical code for water and sky.
235// Then one of these two methods goes away.
236
237//static
238void LightShare::mergeWaterSets(LLWaterParamSet* thisSet, LLWaterParamSet* oldSet)
239{
240 for(LLSD::map_const_iterator i = thisSet->mParamValues.beginMap();
241 i != thisSet->mParamValues.endMap();
242 ++i)
243 {
244 const std::string& param = i->first;
245
246 if(i->second.isArray())
247 {
248 for (int j = 0; j < i->second.size(); j++)
249 {
250 oldSet->mParamValues[param][j] = i->second[j].asReal();
251 }
252 }
253 else if(i->second.isReal())
254 oldSet->mParamValues[param] = i->second.asReal();
255 }
256}
257
258//static
259void LightShare::mergeWLSets(LLWLParamSet* thisSet, LLWLParamSet* oldSet)
260{
261 for(LLSD::map_const_iterator i = thisSet->mParamValues.beginMap();
262 i != thisSet->mParamValues.endMap();
263 ++i)
264 {
265 const std::string& param = i->first;
266
267 if(i->second.isArray())
268 {
269 for (int j = 0; j < i->second.size(); j++)
270 {
271 oldSet->mParamValues[param][j] = i->second[j].asReal();
272 }
273 }
274 else if(i->second.isReal())
275 oldSet->mParamValues[param] = i->second.asReal();
276 }
277}
278
279//static
280void LightShare::apply(LLWaterParamSet * newWater, LLUUID *newWaterNormal, LLWLParamSet *newSky, WLScope scope)
281// TODO - Deal with day cycle stuff.
282{
283 LLWaterParamManager* waterMgr = LLWaterParamManager::instance();
284 LLWLParamManager* skyMgr = LLWLParamManager::instance();
285 LLWaterParamSet oldWaterSet = waterMgr->mCurParams;
286 LLWLParamSet oldWLSet = skyMgr->mCurParams;
287 struct WLCombined* thisSet = &userSet;
288 bool user = true;
289
290 switch(scope)
291 {
292 case WL_SCOPE_USER :
293 {
294 thisSet = &userSet;
295 thisSet->water.mName = waterMgr->mCurParams.mName;
296 thisSet->sky.mName = skyMgr->mCurParams.mName;
297 thisSet->enabled = true;
298 // Check if user selected to show the saved region or parcel settings.
299 if (newSky && (sRegionPresetName == skyMgr->mCurParams.mName))
300 thisSet->enabled = false;
301 if (newWater && (sParcelPresetName == skyMgr->mCurParams.mName))
302 thisSet->enabled = false;
303 break;
304 }
305 case WL_SCOPE_REGION :
306 {
307 thisSet = &regionSet;
308 thisSet->water.mName = sRegionPresetName;
309 thisSet->sky.mName = sRegionPresetName;
310 thisSet->enabled = (gSavedSettings.getU32("LightShareAllowed") != LIGHTSHARE_NEVER);
311 break;
312 }
313 case WL_SCOPE_PARCEL :
314 {
315 thisSet = &parcelSet;
316 thisSet->water.mName = sParcelPresetName;
317 thisSet->sky.mName = sParcelPresetName;
318 thisSet->enabled = (gSavedSettings.getU32("LightShareAllowed") != LIGHTSHARE_NEVER);
319 break;
320 }
321 case WL_SCOPE_RLV :
322 {
323 thisSet = &RLVSet;
324 thisSet->water.mName = sRLVPresetName;
325 thisSet->sky.mName = sRLVPresetName;
326 // TODO set enabled properly.
327 break;
328 }
329 }
330
331 if (newWater)
332 thisSet->water.setAll(newWater->getAll());
333 if (newWaterNormal)
334 thisSet->water.mParamValues["normalMap"] = *newWaterNormal;
335 if (newSky)
336 thisSet->sky.setAll(newSky->getAll());
337
338 if ((NULL == newWater) && (NULL == newSky))
339 thisSet->enabled = false;
340
341 F32 fade = 0; //Instant
342 bool error;
343 fade = thisSet->sky.getFloat("fade", error);
344
345 if (fade)
346 {
347 // TODO - should copy the original, then set that here.
348 // The fade should delete this copy once it's done fading.
349 // Dunno if we actually need to do any of this anyway.
350 waterMgr->removeParamSet( oldWaterSet.mName, false );
351 waterMgr->addParamSet( oldWaterSet.mName, oldWaterSet );
352 waterMgr->setNormalMapID( *newWaterNormal );
353 waterMgr->getParamSet(oldWaterSet.mName, waterMgr->mCurParams);
354 waterMgr->propagateParameters();
355
356 skyMgr->removeParamSet( oldWLSet.mName, false );
357 skyMgr->addParamSet( oldWLSet.mName, oldWLSet );
358 skyMgr->getParamSet(oldWLSet.mName, skyMgr->mCurParams);
359 skyMgr->propagateParameters();
360 }
361
362 if (regionSet.enabled)
363 {
364 waterMgr->setParamSet( regionSet.water.mName, regionSet.water );
365 skyMgr->setParamSet( regionSet.sky.mName, regionSet.sky );
366 mergeWaterSets(&(regionSet.water), &oldWaterSet);
367 mergeWLSets(&(regionSet.sky), &oldWLSet);
368 }
369 else
370 {
371 waterMgr->removeParamSet( regionSet.water.mName, false );
372 skyMgr->removeParamSet( regionSet.sky.mName, false );
373 }
374 if (parcelSet.enabled)
375 {
376 waterMgr->setParamSet( parcelSet.water.mName, parcelSet.water );
377 skyMgr->setParamSet( parcelSet.sky.mName, parcelSet.sky );
378 mergeWaterSets(&(parcelSet.water), &oldWaterSet);
379 mergeWLSets(&(parcelSet.sky), &oldWLSet);
380 }
381 else
382 {
383 waterMgr->removeParamSet( parcelSet.water.mName, false );
384 skyMgr->removeParamSet( parcelSet.sky.mName, false );
385 }
386 if (userSet.enabled)
387 {
388 mergeWaterSets(&(userSet.water), &oldWaterSet);
389 mergeWLSets(&(userSet.sky), &oldWLSet);
390 }
391 if (RLVSet.enabled)
392 {
393 mergeWaterSets(&(RLVSet.water), &oldWaterSet);
394 mergeWLSets(&(RLVSet.sky), &oldWLSet);
395 }
396
397 skyMgr->mAnimator.mIsRunning = false;
398 skyMgr->mAnimator.mUseLindenTime = false;
399 if (fade)
400 {
401 waterMgr->SetMixTime(&oldWaterSet, fade);
402 skyMgr->SetMixTime(&oldWLSet, fade);
403 }
404 else
405 {
406 if (newWater)
407 {
408 waterMgr->setParamSet( thisSet->water.mName, oldWaterSet );
409 waterMgr->setNormalMapID( *newWaterNormal );
410 waterMgr->getParamSet(thisSet->water.mName, waterMgr->mCurParams);
411 waterMgr->propagateParameters();
412 }
413
414 if (newSky)
415 {
416 skyMgr->setParamSet( thisSet->sky.mName, oldWLSet );
417 skyMgr->getParamSet(thisSet->sky.mName, skyMgr->mCurParams);
418 skyMgr->propagateParameters();
419 }
420 }
421
422 LLWorld::getInstance()->rebuildClouds(gAgent.getRegion());
423}
424
425bool LightShare::isValid()
426{
427 return mIsValid;
428}
429
430void LightShare::process_packet( char* buf )
431{
432 // *FIXME: Horrible idea, fragile, not byte-order or endian
433 // safe, no validation, etc. etc. -Jacek
434 mPacket = (Meta7WindlightPacket*)buf;
435}
436
437void LightShare::process_water()
438{
439 mWater->set("waterFogColor",
440 mPacket->waterColor.red / 256.f,
441 mPacket->waterColor.green / 256.f,
442 mPacket->waterColor.blue / 256.f);
443
444 mWater->set("waterFogDensity",
445 pow(2.0f, mPacket->waterFogDensityExponent));
446
447 mWater->set("underWaterFogMod", mPacket->underwaterFogModifier);
448
449 mWater->set("normScale",
450 mPacket->reflectionWaveletScale.X,
451 mPacket->reflectionWaveletScale.Y,
452 mPacket->reflectionWaveletScale.Z);
453
454 mWater->set("fresnelScale", mPacket->fresnelScale);
455 mWater->set("fresnelOffset", mPacket->fresnelOffset);
456 mWater->set("scaleAbove", mPacket->refractScaleAbove);
457 mWater->set("scaleBelow", mPacket->refractScaleBelow);
458 mWater->set("blurMultiplier", mPacket->blurMultiplier);
459
460 mWater->set("wave1Dir",
461 mPacket->littleWaveDirection.X,
462 mPacket->littleWaveDirection.Y);
463
464 mWater->set("wave2Dir",
465 mPacket->bigWaveDirection.X,
466 mPacket->bigWaveDirection.Y);
467
468
469 // Format a UUID string from a block of raw bytes. Ugh.
470 std::string uuid = llformat(
471 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
472 (U8)(mPacket->normalMapTexture[0]),
473 (U8)(mPacket->normalMapTexture[1]),
474 (U8)(mPacket->normalMapTexture[2]),
475 (U8)(mPacket->normalMapTexture[3]),
476 (U8)(mPacket->normalMapTexture[4]),
477 (U8)(mPacket->normalMapTexture[5]),
478 (U8)(mPacket->normalMapTexture[6]),
479 (U8)(mPacket->normalMapTexture[7]),
480 (U8)(mPacket->normalMapTexture[8]),
481 (U8)(mPacket->normalMapTexture[9]),
482 (U8)(mPacket->normalMapTexture[10]),
483 (U8)(mPacket->normalMapTexture[11]),
484 (U8)(mPacket->normalMapTexture[12]),
485 (U8)(mPacket->normalMapTexture[13]),
486 (U8)(mPacket->normalMapTexture[14]),
487 (U8)(mPacket->normalMapTexture[15]));
488
489 mWaterNormal->set(uuid);
490}
491
492
493void LightShare::process_sky()
494{
495 mSky->setSunAngle(F_TWO_PI * mPacket->sunMoonPosiiton);
496 mSky->setEastAngle(F_TWO_PI * mPacket->eastAngle);
497
498 mSky->set("sunlight_color",
499 mPacket->sunMoonColor.red * 3.0f,
500 mPacket->sunMoonColor.green * 3.0f,
501 mPacket->sunMoonColor.blue * 3.0f,
502 mPacket->sunMoonColor.alpha * 3.0f);
503
504 mSky->set("ambient",
505 mPacket->ambient.red * 3.0f,
506 mPacket->ambient.green * 3.0f,
507 mPacket->ambient.blue * 3.0f,
508 mPacket->ambient.alpha * 3.0f);
509
510 mSky->set("blue_horizon",
511 mPacket->horizon.red * 2.0f,
512 mPacket->horizon.green *2.0f,
513 mPacket->horizon.blue * 2.0f,
514 mPacket->horizon.alpha * 2.0f);
515
516 mSky->set("blue_density",
517 mPacket->blueDensity.red * 2.0f,
518 mPacket->blueDensity.green * 2.0f,
519 mPacket->blueDensity.blue * 2.0f,
520 mPacket->blueDensity.alpha * 2.0f);
521
522 mSky->set("haze_horizon",
523 mPacket->hazeHorizon,
524 mPacket->hazeHorizon,
525 mPacket->hazeHorizon,
526 1.f);
527
528 mSky->set("haze_density",
529 mPacket->hazeDensity,
530 0.f, 0.f, 1.f);
531
532 mSky->set("cloud_shadow",
533 mPacket->cloudCoverage,
534 0.f, 0.f, 1.f);
535
536 mSky->set("density_multiplier",
537 mPacket->densityMultiplier / 1000.0f,
538 0.f, 0.f, 1.f);
539
540 mSky->set("distance_multiplier",
541 mPacket->distanceMultiplier,
542 0.f, 0.f, 1.f);
543
544 mSky->set("max_y",
545 (F32)mPacket->maxAltitude,
546 0.f, 0.f, 1.f);
547
548 mSky->set("cloud_color",
549 mPacket->cloudColor.red,
550 mPacket->cloudColor.green,
551 mPacket->cloudColor.blue,
552 mPacket->cloudColor.alpha);
553
554 mSky->set("cloud_pos_density1",
555 mPacket->cloudXYDensity.X,
556 mPacket->cloudXYDensity.Y,
557 mPacket->cloudXYDensity.Z,
558 1.f);
559
560 mSky->set("cloud_pos_density2",
561 mPacket->cloudDetailXYDensity.X,
562 mPacket->cloudDetailXYDensity.Y,
563 mPacket->cloudDetailXYDensity.Z,
564 1.f);
565
566 mSky->set("cloud_scale",
567 mPacket->cloudScale,
568 0.f, 0.f, 1.f);
569
570 mSky->set("gamma",
571 mPacket->sceneGamma,
572 0.f, 0.f, 1.f);
573
574 mSky->set("glow",
575 (2 - mPacket->sunGlowSize) * 20,
576 0.f,
577 -mPacket->sunGlowFocus * 5,
578 1.f);
579
580 mSky->setCloudScrollX(mPacket->cloudScrollX + 10.0f);
581 mSky->setCloudScrollY(mPacket->cloudScrollY + 10.0f);
582
583 mSky->setEnableCloudScrollX(!mPacket->cloudScrollXLock);
584 mSky->setEnableCloudScrollY(!mPacket->cloudScrollYLock);
585
586 mSky->setStarBrightness(mPacket->starBrightness);
587}