From 6d52efe452aa8469e0343da1c7d108f3f52ab651 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 27 Feb 2008 18:58:14 +0000
Subject: [PATCH] Merge of windlight into release (QAR-286).  This includes all
 changes in windlight14 which have passed QA (up through r79932).

svn merge -r 80831:80833 svn+ssh://svn.lindenlab.com/svn/linden/branches/merge_windlight14_r80620
---
 doc/contributions.txt                         |    7 +
 indra/llcharacter/llkeyframemotion.cpp        |   58 -
 indra/llcharacter/llkeyframemotion.h          |    1 -
 indra/llcharacter/llmotioncontroller.cpp      |    9 +-
 indra/llcharacter/llmotioncontroller.h        |    2 +
 indra/llcharacter/llpose.cpp                  |   23 +-
 indra/llcommon/llfasttimer.h                  |    7 +-
 indra/llcommon/llfile.cpp                     |    1 +
 indra/llcommon/llkeythrottle.h                |    5 +-
 indra/llmath/llcamera.cpp                     |  127 +-
 indra/llmath/llcamera.h                       |   22 +-
 indra/llmath/llcoordframe.cpp                 |    6 +-
 indra/llmath/llmath.h                         |   16 +
 indra/llmath/lloctree.h                       |  382 +--
 indra/llmath/lltreenode.h                     |   89 +-
 indra/llmath/llvolume.cpp                     |  277 +-
 indra/llmath/llvolume.h                       |   14 +-
 indra/llmath/llvolumemgr.cpp                  |   23 +
 indra/llmath/llvolumemgr.h                    |    1 +
 indra/llmath/v3color.cpp                      |    8 +
 indra/llmath/v3color.h                        |   10 +-
 indra/llmath/v4color.cpp                      |   10 +-
 indra/llmath/v4color.h                        |    4 +-
 indra/llmath/v4math.h                         |    3 +-
 indra/llprimitive/lltextureentry.cpp          |    1 -
 indra/llrender/llfontgl.cpp                   |   73 +-
 indra/llrender/llimagegl.cpp                  |   16 +-
 indra/llrender/llimagegl.h                    |    3 +-
 indra/llrender/llrendertarget.cpp             |  185 ++
 indra/llrender/llrendertarget.h               |  116 +
 indra/llrender/llvertexbuffer.cpp             |  538 +--
 indra/llrender/llvertexbuffer.h               |   67 +-
 indra/llui/llbutton.cpp                       |    9 +-
 indra/llui/llcheckboxctrl.cpp                 |   11 +-
 indra/llui/llfloater.cpp                      |   30 +-
 indra/llui/llmenugl.cpp                       |   33 +-
 indra/llui/llmultislider.cpp                  |  677 ++++
 indra/llui/llmultislider.h                    |  129 +
 indra/llui/llmultisliderctrl.cpp              |  634 ++++
 indra/llui/llmultisliderctrl.h                |  160 +
 indra/llui/llpanel.h                          |    2 +-
 indra/llui/llscrollbar.cpp                    |    5 +-
 indra/llui/llscrollcontainer.cpp              |    3 +-
 indra/llui/llscrolllistctrl.cpp               |    7 +-
 indra/llui/llslider.h                         |    4 +-
 indra/llui/llsliderctrl.h                     |   13 +-
 indra/llui/llspinctrl.h                       |    2 +
 indra/llui/lltabcontainer.cpp                 |   13 +-
 indra/llui/lltexteditor.cpp                   |    8 +-
 indra/llui/llui.cpp                           | 1034 +++---
 indra/llui/llui.h                             |    2 +
 indra/llui/lluictrlfactory.cpp                |   16 +
 indra/llui/lluictrlfactory.h                  |    2 +
 indra/llui/llview.cpp                         |   25 +-
 indra/llui/llviewborder.cpp                   |   41 +-
 indra/llui/llviewborder.h                     |    3 +
 indra/llwindow/lldxhardware.cpp               |    2 +
 indra/llwindow/llwindow.cpp                   |    4 +-
 indra/llwindow/llwindow.h                     |    2 +-
 indra/llwindow/llwindowmacosx.cpp             |   29 +-
 indra/llwindow/llwindowsdl.cpp                |   13 +
 indra/llwindow/llwindowwin32.cpp              |   14 +-
 indra/llwindow/llwindowwin32.h                |    1 +
 indra/newview/app_settings/high_graphics.xml  |   39 +
 indra/newview/app_settings/low_graphics.xml   |   39 +
 indra/newview/app_settings/mid_graphics.xml   |   39 +
 .../shaders/class1/avatar/avatarF.glsl        |    7 +
 .../shaders/class1/avatar/avatarSkinV.glsl    |    7 +-
 .../shaders/class1/avatar/avatarV.glsl        |   22 +-
 .../shaders/class1/avatar/eyeballF.glsl       |    7 +
 .../shaders/class1/avatar/eyeballV.glsl       |   19 +-
 .../shaders/class1/avatar/pickAvatarF.glsl    |    7 +
 .../shaders/class1/avatar/pickAvatarV.glsl    |   10 +-
 .../shaders/class1/effects/glowExtractF.glsl  |   28 +
 .../shaders/class1/effects/glowExtractV.glsl  |   14 +
 .../shaders/class1/effects/glowF.glsl         |   31 +
 .../shaders/class1/effects/glowV.glsl         |   22 +
 .../shaders/class1/environment/terrainF.glsl  |   16 +-
 .../shaders/class1/environment/terrainV.glsl  |   13 +-
 .../class1/environment/terrainWaterF.glsl     |   23 +
 .../class1/environment/underWaterF.glsl       |   45 +
 .../shaders/class1/environment/waterF.glsl    |   96 +-
 .../shaders/class1/environment/waterFogF.glsl |   20 +
 .../shaders/class1/environment/waterV.glsl    |   90 +-
 .../shaders/class1/interface/highlightF.glsl  |    7 +
 .../shaders/class1/interface/highlightV.glsl  |   15 +-
 .../shaders/class1/lighting/lightF.glsl       |   30 +-
 .../class1/lighting/lightFullbrightF.glsl     |   15 +
 .../lighting/lightFullbrightShinyF.glsl       |   15 +
 .../lighting/lightFullbrightWaterF.glsl       |   15 +
 .../class1/lighting/lightFuncSpecularV.glsl   |   46 +
 .../shaders/class1/lighting/lightFuncV.glsl   |   34 +
 .../shaders/class1/lighting/lightShinyF.glsl  |   17 +
 .../class1/lighting/lightShinyWaterF.glsl     |   17 +
 .../class1/lighting/lightSpecularV.glsl       |   26 +
 .../shaders/class1/lighting/lightV.glsl       |   89 +-
 .../shaders/class1/lighting/lightWaterF.glsl  |   15 +
 .../class1/lighting/sumLightsSpecularV.glsl   |   35 +
 .../shaders/class1/lighting/sumLightsV.glsl   |   29 +
 .../shaders/class1/objects/fullbrightF.glsl   |   13 +
 .../class1/objects/fullbrightShinyF.glsl      |   13 +
 .../class1/objects/fullbrightShinyV.glsl      |   29 +
 .../shaders/class1/objects/fullbrightV.glsl   |   23 +
 .../class1/objects/fullbrightWaterF.glsl      |   13 +
 .../shaders/class1/objects/shinyF.glsl        |   16 +-
 .../shaders/class1/objects/shinyV.glsl        |   25 +-
 .../shaders/class1/objects/shinyWaterF.glsl   |   13 +
 .../shaders/class1/objects/simpleF.glsl       |    7 +
 .../shaders/class1/objects/simpleV.glsl       |   22 +-
 .../shaders/class1/objects/simpleWaterF.glsl  |   13 +
 .../class1/windlight/atmosphericsF.glsl       |   13 +
 .../windlight/atmosphericsHelpersV.glsl       |   34 +
 .../class1/windlight/atmosphericsV.glsl       |   15 +
 .../class1/windlight/atmosphericsVarsF.glsl   |   13 +
 .../class1/windlight/atmosphericsVarsV.glsl   |   19 +
 .../shaders/class1/windlight/gammaF.glsl      |   19 +
 .../shaders/class1/windlight/transportF.glsl  |   26 +
 .../shaders/class2/avatar/eyeballV.glsl       |   21 +-
 .../shaders/class2/effects/blurF.glsl         |   31 +
 .../shaders/class2/effects/blurV.glsl         |   35 +
 .../shaders/class2/effects/colorFilterF.glsl  |   31 +
 .../shaders/class2/effects/drawQuadV.glsl     |   14 +
 .../shaders/class2/effects/extractF.glsl      |   22 +
 .../shaders/class2/effects/nightVisionF.glsl  |   42 +
 .../shaders/class2/effects/simpleF.glsl       |   14 +
 .../shaders/class2/environment/terrainF.glsl  |   38 +
 .../shaders/class2/environment/terrainV.glsl  |   52 +
 .../class2/environment/terrainWaterF.glsl     |   39 +
 .../class2/environment/underWaterF.glsl       |   88 +
 .../shaders/class2/environment/waterF.glsl    |  223 +-
 .../shaders/class2/environment/waterFogF.glsl |   54 +
 .../shaders/class2/lighting/lightF.glsl       |   41 +-
 .../class2/lighting/lightFullbrightF.glsl     |   23 +
 .../lighting/lightFullbrightShinyF.glsl       |   30 +
 .../lighting/lightFullbrightWaterF.glsl       |   21 +
 .../shaders/class2/lighting/lightShinyF.glsl  |   29 +
 .../class2/lighting/lightShinyWaterF.glsl     |   27 +
 .../class2/lighting/lightSpecularV.glsl       |   16 +
 .../shaders/class2/lighting/lightV.glsl       |  128 +-
 .../shaders/class2/lighting/lightWaterF.glsl  |   21 +
 .../class2/lighting/sumLightsSpecularV.glsl   |   41 +
 .../shaders/class2/lighting/sumLightsV.glsl   |   34 +
 .../shaders/class2/objects/shinyV.glsl        |   31 +
 .../class2/windlight/atmosphericsF.glsl       |   24 +
 .../windlight/atmosphericsHelpersV.glsl       |   41 +
 .../class2/windlight/atmosphericsV.glsl       |  137 +
 .../class2/windlight/atmosphericsVarsF.glsl   |   34 +
 .../class2/windlight/atmosphericsVarsV.glsl   |   60 +
 .../shaders/class2/windlight/cloudsF.glsl     |   76 +
 .../shaders/class2/windlight/cloudsV.glsl     |  163 +
 .../shaders/class2/windlight/gammaF.glsl      |   24 +
 .../shaders/class2/windlight/skyF.glsl        |   41 +
 .../shaders/class2/windlight/skyV.glsl        |  138 +
 .../shaders/class2/windlight/transportF.glsl  |   35 +
 .../shaders/class3/avatar/avatarV.glsl        |  112 +-
 .../class3/lighting/sumLightsSpecularV.glsl   |   44 +
 .../shaders/class3/lighting/sumLightsV.glsl   |   41 +
 .../app_settings/shaders/shader_heirarchy.txt |  176 +
 indra/newview/app_settings/ultra_graphics.xml |   39 +
 .../app_settings/windlight/clouds2.tga        |  Bin 0 -> 262935 bytes
 .../app_settings/windlight/days/Default.xml   |   36 +
 .../windlight/postprocesseffects.xml          |    2 +
 .../app_settings/windlight/skies/A%2D12AM.xml |  141 +
 .../app_settings/windlight/skies/A%2D12PM.xml |  141 +
 .../app_settings/windlight/skies/A%2D3AM.xml  |  141 +
 .../app_settings/windlight/skies/A%2D3PM.xml  |  141 +
 .../app_settings/windlight/skies/A%2D6AM.xml  |  141 +
 .../app_settings/windlight/skies/A%2D6PM.xml  |  141 +
 .../app_settings/windlight/skies/A%2D9AM.xml  |  141 +
 .../app_settings/windlight/skies/A%2D9PM.xml  |  141 +
 .../windlight/skies/Barcelona.xml             |  141 +
 .../app_settings/windlight/skies/Blizzard.xml |  141 +
 .../windlight/skies/Blue%20Midday.xml         |  141 +
 .../windlight/skies/Coastal%20Afternoon.xml   |  141 +
 .../windlight/skies/Coastal%20Sunset.xml      |  141 +
 .../app_settings/windlight/skies/Default.xml  |  141 +
 .../windlight/skies/Desert%20Sunset.xml       |  141 +
 .../windlight/skies/Fine%20Day.xml            |  141 +
 .../windlight/skies/Fluffy%20Big%20Clouds.xml |  141 +
 .../app_settings/windlight/skies/Foggy.xml    |  141 +
 .../windlight/skies/Funky%20Funky%20Funky.xml |  141 +
 .../windlight/skies/Funky%20Funky.xml         |  141 +
 .../app_settings/windlight/skies/Gelatto.xml  |  141 +
 .../app_settings/windlight/skies/Ghost.xml    |  141 +
 .../windlight/skies/Incongruent%20Truths.xml  |  141 +
 .../windlight/skies/Midday%201.xml            |  141 +
 .../windlight/skies/Midday%202.xml            |  141 +
 .../windlight/skies/Midday%203.xml            |  141 +
 .../windlight/skies/Midday%204.xml            |  141 +
 .../app_settings/windlight/skies/Night.xml    |  141 +
 .../app_settings/windlight/skies/Pirate.xml   |  141 +
 .../app_settings/windlight/skies/Purple.xml   |  141 +
 .../windlight/skies/Sailor%27s%20Delight.xml  |  141 +
 .../windlight/skies/Sheer%20Surreality.xml    |  141 +
 .../app_settings/windlight/water/Default.xml  |   43 +
 .../app_settings/windlight/water/Glassy.xml   |   43 +
 .../app_settings/windlight/water/Murky.xml    |   43 +
 .../app_settings/windlight/water/Pond.xml     |   43 +
 .../windlight/water/SNAKE%21%21%21.xml        |   43 +
 .../windlight/water/Second%20Plague.xml       |   43 +
 .../app_settings/windlight/water/Valdez.xml   |   43 +
 indra/newview/featuretable.txt                |  338 +-
 indra/newview/featuretable_linux.txt          |  337 +-
 indra/newview/featuretable_mac.txt            |  325 +-
 indra/newview/featuretable_solaris.txt        |    2 +-
 indra/newview/gpu_table.txt                   |  314 +-
 .../installers/windows/installer_template.nsi | 1894 +++++------
 indra/newview/licenses-linux.txt              |   43 +
 indra/newview/licenses-mac.txt                |   43 +
 indra/newview/licenses-solaris.txt            |   43 +
 indra/newview/licenses-win32.txt              |   45 +
 indra/newview/linux_tools/wrapper.sh          |    4 +-
 indra/newview/llagent.cpp                     |  121 +-
 indra/newview/llagent.h                       |    1 -
 indra/newview/llappviewer.cpp                 |  170 +-
 indra/newview/llbox.cpp                       |   28 +-
 indra/newview/llcallingcard.cpp               |    6 +-
 indra/newview/llcloud.cpp                     |   35 -
 indra/newview/llcloud.h                       |    1 -
 indra/newview/llcolorswatch.cpp               |   11 +-
 indra/newview/lldrawable.cpp                  |  359 +-
 indra/newview/lldrawable.h                    |   28 +-
 indra/newview/lldrawpool.cpp                  |  240 +-
 indra/newview/lldrawpool.h                    |   33 +-
 indra/newview/lldrawpoolalpha.cpp             |  288 +-
 indra/newview/lldrawpoolalpha.h               |   18 +-
 indra/newview/lldrawpoolavatar.cpp            |  309 +-
 indra/newview/lldrawpoolavatar.h              |    6 +-
 indra/newview/lldrawpoolbump.cpp              |  530 ++-
 indra/newview/lldrawpoolbump.h                |   40 +-
 indra/newview/lldrawpoolclouds.h              |    1 -
 indra/newview/lldrawpoolground.cpp            |   14 +-
 indra/newview/lldrawpoolground.h              |    1 -
 indra/newview/lldrawpoolsimple.cpp            |  165 +-
 indra/newview/lldrawpoolsimple.h              |    3 +
 indra/newview/lldrawpoolsky.cpp               |   58 +-
 indra/newview/lldrawpoolsky.h                 |    4 +-
 indra/newview/lldrawpoolterrain.cpp           |  274 +-
 indra/newview/lldrawpoolterrain.h             |    6 +-
 indra/newview/lldrawpooltree.cpp              |  112 +-
 indra/newview/lldrawpooltree.h                |    3 +-
 indra/newview/lldrawpoolwater.cpp             |  393 +--
 indra/newview/lldrawpoolwater.h               |   14 +-
 indra/newview/lldrawpoolwlsky.cpp             |  343 ++
 indra/newview/lldrawpoolwlsky.h               |   84 +
 indra/newview/lldynamictexture.cpp            |   14 +-
 indra/newview/llface.cpp                      |  587 ++--
 indra/newview/llface.h                        |   92 +-
 indra/newview/llface.inl                      |   81 -
 indra/newview/llfasttimerview.cpp             |  175 +-
 indra/newview/llfasttimerview.h               |    1 +
 indra/newview/llfeaturemanager.cpp            |  338 +-
 indra/newview/llfeaturemanager.h              |   56 +-
 indra/newview/llflexibleobject.cpp            |   78 +-
 indra/newview/llflexibleobject.h              |    3 +-
 indra/newview/llfloateranimpreview.cpp        |   38 +-
 indra/newview/llfloaterauction.cpp            |    2 +-
 indra/newview/llfloatercolorpicker.cpp        |   65 +-
 indra/newview/llfloatercolorpicker.h          |    2 +-
 indra/newview/llfloaterdaycycle.cpp           |  612 ++++
 indra/newview/llfloaterdaycycle.h             |  146 +
 indra/newview/llfloaterenvsettings.cpp        |  384 +++
 indra/newview/llfloaterenvsettings.h          |  106 +
 indra/newview/llfloaterhardwaresettings.cpp   |  207 ++
 indra/newview/llfloaterhardwaresettings.h     |  102 +
 indra/newview/llfloaterimagepreview.cpp       |  130 +-
 indra/newview/llfloaterpostprocess.cpp        |  273 ++
 indra/newview/llfloaterpostprocess.h          |   90 +
 indra/newview/llfloaterpreference.cpp         |   44 +-
 indra/newview/llfloaterpreference.h           |   10 +-
 indra/newview/llfloaterregioninfo.cpp         |   20 +
 indra/newview/llfloaterregioninfo.h           |    5 +
 indra/newview/llfloaterreporter.cpp           |    2 +-
 indra/newview/llfloatersnapshot.cpp           |  504 ++-
 indra/newview/llfloaterwater.cpp              |  735 +++++
 indra/newview/llfloaterwater.h                |  133 +
 indra/newview/llfloaterwindlight.cpp          |  998 ++++++
 indra/newview/llfloaterwindlight.h            |  142 +
 indra/newview/llfolderview.cpp                |    4 +-
 indra/newview/llglsandbox.cpp                 |  435 +--
 indra/newview/llhudeffectbeam.cpp             |   45 -
 indra/newview/llhudeffectlookat.cpp           |   20 +-
 indra/newview/llhudeffectpointat.cpp          |   19 +-
 indra/newview/llhudeffecttrail.cpp            |   10 +-
 indra/newview/llhudicon.cpp                   |   32 +-
 indra/newview/llhudmanager.cpp                |    3 +-
 indra/newview/llhudmanager.h                  |    3 -
 indra/newview/llhudobject.cpp                 |    9 -
 indra/newview/llhudrender.cpp                 |   10 +-
 indra/newview/llhudtext.cpp                   |   36 +-
 indra/newview/lljoystickbutton.cpp            |   23 +-
 indra/newview/llmanip.cpp                     |   45 +-
 indra/newview/llmaniprotate.cpp               |   51 +-
 indra/newview/llmanipscale.cpp                |  143 +-
 indra/newview/llmaniptranslate.cpp            |  386 +--
 indra/newview/llmemoryview.cpp                |    7 +-
 indra/newview/llnetmap.cpp                    |  107 +-
 indra/newview/lloverlaybar.cpp                |    1 +
 indra/newview/llpanelface.cpp                 |   65 +-
 indra/newview/llpanelface.h                   |    3 +
 indra/newview/llpanelgrouplandmoney.cpp       |    1 -
 indra/newview/llpanelobject.cpp               |   15 +-
 indra/newview/llpanelvolume.cpp               |   13 +
 indra/newview/llpreviewanim.cpp               |   27 -
 indra/newview/llpreviewanim.h                 |    1 -
 indra/newview/llpreviewtexture.cpp            |    1 -
 indra/newview/llprogressview.cpp              |    5 +-
 indra/newview/llselectmgr.cpp                 |  104 +-
 indra/newview/llselectmgr.h                   |    2 +
 indra/newview/llsky.cpp                       |  100 +-
 indra/newview/llsky.h                         |   13 +-
 indra/newview/llspatialpartition.cpp          | 2213 ++++++-------
 indra/newview/llspatialpartition.h            |  213 +-
 indra/newview/llsprite.cpp                    |   10 +-
 indra/newview/llstartup.cpp                   |    8 +
 indra/newview/llsurface.cpp                   |   77 -
 indra/newview/llsurface.h                     |    2 -
 indra/newview/llsurfacepatch.cpp              |   19 +-
 indra/newview/lltexlayer.cpp                  |   60 +-
 indra/newview/lltexturectrl.cpp               |   61 +-
 indra/newview/lltextureview.cpp               |   25 +-
 indra/newview/lltoolbrush.cpp                 |   17 +-
 indra/newview/lltoolgun.cpp                   |    1 +
 indra/newview/lltoolmorph.cpp                 |   28 +-
 indra/newview/lltoolselectrect.cpp            |    9 +-
 indra/newview/lltracker.cpp                   |   45 +-
 indra/newview/llviewercamera.cpp              |  195 +-
 indra/newview/llviewercamera.h                |    7 +-
 indra/newview/llviewercontrol.h               |    3 +
 indra/newview/llviewerdisplay.cpp             |  594 ++--
 indra/newview/llviewerdisplay.h               |    5 +-
 indra/newview/llviewerjoint.cpp               |  205 +-
 indra/newview/llviewerjoint.h                 |    1 -
 indra/newview/llviewerjointattachment.cpp     |   52 +-
 indra/newview/llviewerjointattachment.h       |    3 -
 indra/newview/llviewerjointmesh.cpp           |  290 +-
 indra/newview/llviewerjointmesh.h             |    5 +-
 indra/newview/llviewerjointmesh_sse.cpp       |    2 +
 indra/newview/llviewerjointmesh_sse2.cpp      |    2 +
 indra/newview/llviewerjointmesh_vec.cpp       |    2 +
 indra/newview/llviewermenu.cpp                |  216 +-
 indra/newview/llviewermenufile.cpp            |   15 +-
 indra/newview/llviewermessage.cpp             |    1 -
 indra/newview/llviewerobject.cpp              |   84 +-
 indra/newview/llviewerobject.h                |   24 +-
 indra/newview/llviewerobjectlist.cpp          |   45 +-
 indra/newview/llviewerobjectlist.h            |    1 -
 indra/newview/llviewerparceloverlay.cpp       |   38 +-
 indra/newview/llviewerpartsim.cpp             |  200 +-
 indra/newview/llviewerpartsim.h               |   34 +-
 indra/newview/llviewerpartsource.cpp          |   65 +-
 indra/newview/llviewerpartsource.h            |    2 +
 indra/newview/llviewerregion.cpp              |   37 +-
 indra/newview/llviewerregion.h                |   27 +-
 indra/newview/llviewerstats.cpp               |    6 +-
 indra/newview/llviewerwindow.cpp              |  339 +-
 indra/newview/llviewerwindow.h                |    6 +-
 indra/newview/llvoavatar.cpp                  | 1008 +++---
 indra/newview/llvoavatar.h                    |   56 +-
 indra/newview/llvoclouds.cpp                  |  159 +-
 indra/newview/llvoclouds.h                    |    3 +-
 indra/newview/llvograss.cpp                   |    8 +-
 indra/newview/llvograss.h                     |    2 +-
 indra/newview/llvoground.cpp                  |    3 +-
 indra/newview/llvoicevisualizer.cpp           |   50 +-
 indra/newview/llvopartgroup.cpp               |  207 +-
 indra/newview/llvopartgroup.h                 |    5 +-
 indra/newview/llvosky.cpp                     | 1505 ++++-----
 indra/newview/llvosky.h                       |  407 +--
 indra/newview/llvosurfacepatch.cpp            |   94 +-
 indra/newview/llvosurfacepatch.h              |   12 +-
 indra/newview/llvotextbubble.cpp              |    5 +-
 indra/newview/llvotextbubble.h                |    2 +-
 indra/newview/llvotree.cpp                    |  195 +-
 indra/newview/llvotree.h                      |    4 +-
 indra/newview/llvovolume.cpp                  |  726 ++---
 indra/newview/llvovolume.h                    |   31 +-
 indra/newview/llvowater.cpp                   |   84 +-
 indra/newview/llvowater.h                     |    4 +
 indra/newview/llvowlsky.cpp                   |  821 +++++
 indra/newview/llvowlsky.h                     |  110 +
 indra/newview/llwaterparammanager.cpp         |  433 +++
 indra/newview/llwaterparammanager.h           |  401 +++
 indra/newview/llwaterparamset.cpp             |  233 ++
 indra/newview/llwaterparamset.h               |  156 +
 indra/newview/llwlanimator.cpp                |  168 +
 indra/newview/llwlanimator.h                  |   76 +
 indra/newview/llwldaycycle.cpp                |  233 ++
 indra/newview/llwldaycycle.h                  |  105 +
 indra/newview/llwlparammanager.cpp            |  572 ++++
 indra/newview/llwlparammanager.h              |  292 ++
 indra/newview/llwlparamset.cpp                |  403 +++
 indra/newview/llwlparamset.h                  |  252 ++
 indra/newview/llworld.cpp                     |   87 +-
 indra/newview/llworld.h                       |    3 +
 indra/newview/llworldmapview.cpp              |  212 +-
 indra/newview/pipeline.cpp                    | 2898 ++++++++++++-----
 indra/newview/pipeline.h                      |  201 +-
 indra/newview/viewer_manifest.py              |    2 +
 399 files changed, 32993 insertions(+), 13069 deletions(-)
 create mode 100644 indra/llrender/llrendertarget.cpp
 create mode 100644 indra/llrender/llrendertarget.h
 create mode 100644 indra/llui/llmultislider.cpp
 create mode 100644 indra/llui/llmultislider.h
 create mode 100644 indra/llui/llmultisliderctrl.cpp
 create mode 100644 indra/llui/llmultisliderctrl.h
 create mode 100644 indra/newview/app_settings/high_graphics.xml
 create mode 100644 indra/newview/app_settings/low_graphics.xml
 create mode 100644 indra/newview/app_settings/mid_graphics.xml
 create mode 100644 indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/effects/glowF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/effects/glowV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
 create mode 100755 indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/blurF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/blurV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/extractF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
 create mode 100755 indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
 create mode 100755 indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
 create mode 100644 indra/newview/app_settings/shaders/shader_heirarchy.txt
 create mode 100644 indra/newview/app_settings/ultra_graphics.xml
 create mode 100644 indra/newview/app_settings/windlight/clouds2.tga
 create mode 100644 indra/newview/app_settings/windlight/days/Default.xml
 create mode 100644 indra/newview/app_settings/windlight/postprocesseffects.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D12AM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D12PM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D3AM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D3PM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D6AM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D6PM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D9AM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/A%2D9PM.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Barcelona.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Blizzard.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Blue%20Midday.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Coastal%20Afternoon.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Coastal%20Sunset.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Default.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Desert%20Sunset.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Fine%20Day.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Fluffy%20Big%20Clouds.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Foggy.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Funky%20Funky%20Funky.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Funky%20Funky.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Gelatto.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Ghost.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Incongruent%20Truths.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Midday%201.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Midday%202.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Midday%203.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Midday%204.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Night.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Pirate.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Purple.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Sailor%27s%20Delight.xml
 create mode 100644 indra/newview/app_settings/windlight/skies/Sheer%20Surreality.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Default.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Glassy.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Murky.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Pond.xml
 create mode 100644 indra/newview/app_settings/windlight/water/SNAKE%21%21%21.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Second%20Plague.xml
 create mode 100644 indra/newview/app_settings/windlight/water/Valdez.xml
 create mode 100644 indra/newview/lldrawpoolwlsky.cpp
 create mode 100644 indra/newview/lldrawpoolwlsky.h
 create mode 100644 indra/newview/llfloaterdaycycle.cpp
 create mode 100644 indra/newview/llfloaterdaycycle.h
 create mode 100644 indra/newview/llfloaterenvsettings.cpp
 create mode 100644 indra/newview/llfloaterenvsettings.h
 create mode 100644 indra/newview/llfloaterhardwaresettings.cpp
 create mode 100644 indra/newview/llfloaterhardwaresettings.h
 create mode 100644 indra/newview/llfloaterpostprocess.cpp
 create mode 100644 indra/newview/llfloaterpostprocess.h
 create mode 100644 indra/newview/llfloaterwater.cpp
 create mode 100644 indra/newview/llfloaterwater.h
 create mode 100644 indra/newview/llfloaterwindlight.cpp
 create mode 100644 indra/newview/llfloaterwindlight.h
 create mode 100644 indra/newview/llvowlsky.cpp
 create mode 100644 indra/newview/llvowlsky.h
 create mode 100644 indra/newview/llwaterparammanager.cpp
 create mode 100644 indra/newview/llwaterparammanager.h
 create mode 100644 indra/newview/llwaterparamset.cpp
 create mode 100644 indra/newview/llwaterparamset.h
 create mode 100644 indra/newview/llwlanimator.cpp
 create mode 100644 indra/newview/llwlanimator.h
 create mode 100644 indra/newview/llwldaycycle.cpp
 create mode 100644 indra/newview/llwldaycycle.h
 create mode 100644 indra/newview/llwlparammanager.cpp
 create mode 100644 indra/newview/llwlparammanager.h
 create mode 100644 indra/newview/llwlparamset.cpp
 create mode 100644 indra/newview/llwlparamset.h

diff --git a/doc/contributions.txt b/doc/contributions.txt
index e3f12fe4396..c57a2792d99 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -8,6 +8,9 @@ Able Whitman
 	VWR-650
 	VWR-1460
 	VWR-1691
+Aimee Trescothick
+	VWR-3903
+	VWR-4803
 Alejandro Rosenthal
 	VWR-1184
 Alissa Sabre
@@ -44,9 +47,12 @@ Balp Allen
 Benja Kepler
 	VWR-746
 Blakar Ogre
+	VWR-418
 	VWR-881
+	VWR-983
 	VWR-1612
 	VWR-1613
+	VWR-2164
 blino Nakamura
 	VWR-17
 Boroondas Gupte
@@ -172,6 +178,7 @@ McCabe Maxsted
 Michelle2 Zenovka
 	VWR-2652
 	VWR-2834
+	VWR-3749
 Mm Alder
 	VWR-3777
 Mr Greggan
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 76fa0b93eee..1d00f18f2d7 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -2030,64 +2030,6 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
 	}
 }
 
-
-//-----------------------------------------------------------------------------
-// writeCAL3D()
-//-----------------------------------------------------------------------------
-void LLKeyframeMotion::writeCAL3D(apr_file_t* fp)
-{
-//	<ANIMATION VERSION="1000" DURATION="1.03333" NUMTRACKS="58">
-//		<TRACK BONEID="0" NUMKEYFRAMES="31">
-//			<KEYFRAME TIME="0">
-//				<TRANSLATION>0 0 48.8332</TRANSLATION>
-//				<ROTATION>0.0512905 0.05657 0.66973 0.738668</ROTATION>
-//			</KEYFRAME>
-//			</TRACK>
-//	</ANIMATION>
-
-	apr_file_printf(fp, "<ANIMATION VERSION=\"1000\" DURATION=\"%.5f\" NUMTRACKS=\"%d\">\n",  getDuration(), mJointMotionList->getNumJointMotions());
-	for (U32 joint_index = 0; joint_index < mJointMotionList->getNumJointMotions(); joint_index++)
-	{
-		JointMotion* joint_motionp = mJointMotionList->getJointMotion(joint_index);
-		LLJoint* animated_joint = mCharacter->getJoint(joint_motionp->mJointName);
-		S32 joint_num = animated_joint->mJointNum + 1;
-
-		apr_file_printf(fp, "	<TRACK BONEID=\"%d\" NUMKEYFRAMES=\"%d\">\n",  joint_num, joint_motionp->mRotationCurve.mNumKeys );
-		PositionKey* pos_keyp = joint_motionp->mPositionCurve.mKeys.getFirstData();
-		for (RotationKey* rot_keyp = joint_motionp->mRotationCurve.mKeys.getFirstData();
-			rot_keyp;
-			rot_keyp = joint_motionp->mRotationCurve.mKeys.getNextData())
-		{
-			apr_file_printf(fp, "		<KEYFRAME TIME=\"%0.3f\">\n", rot_keyp->mTime);
-			LLVector3 nominal_pos = animated_joint->getPosition();
-			if (animated_joint->getParent())
-			{
-				nominal_pos.scaleVec(animated_joint->getParent()->getScale());
-			}
-			nominal_pos = nominal_pos * 100.f;
-
-			if (joint_motionp->mUsage & LLJointState::POS && pos_keyp)
-			{
-				LLVector3 pos_val = pos_keyp->mPosition;
-				pos_val = pos_val * 100.f;
-				pos_val += nominal_pos;
-				apr_file_printf(fp, "			<TRANSLATION>%0.4f %0.4f %0.4f</TRANSLATION>\n", pos_val.mV[VX], pos_val.mV[VY], pos_val.mV[VZ]);
-				pos_keyp = joint_motionp->mPositionCurve.mKeys.getNextData();
-			}
-			else
-			{
-				apr_file_printf(fp, "			<TRANSLATION>%0.4f %0.4f %0.4f</TRANSLATION>\n", nominal_pos.mV[VX], nominal_pos.mV[VY], nominal_pos.mV[VZ]);
-			}
-
-			LLQuaternion rot_val = ~rot_keyp->mRotation;
-			apr_file_printf(fp, "			<ROTATION>%0.4f %0.4f %0.4f %0.4f</ROTATION>\n", rot_val.mQ[VX], rot_val.mQ[VY], rot_val.mQ[VZ], rot_val.mQ[VW]);
-			apr_file_printf(fp, "		</KEYFRAME>\n");
-		}
-		apr_file_printf(fp, "	</TRACK>\n");
-	}
-	apr_file_printf(fp, "</ANIMATION>\n");
-}
-
 //--------------------------------------------------------------------
 // LLKeyframeDataCache::dumpDiagInfo()
 //--------------------------------------------------------------------
diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h
index 9cea7f3a590..8d6ebbf4b7c 100644
--- a/indra/llcharacter/llkeyframemotion.h
+++ b/indra/llcharacter/llkeyframemotion.h
@@ -158,7 +158,6 @@ class LLKeyframeMotion :
 	U32		getFileSize();
 	BOOL	serialize(LLDataPacker& dp) const;
 	BOOL	deserialize(LLDataPacker& dp);
-	void	writeCAL3D(apr_file_t* fp);
 	BOOL	isLoaded() { return mJointMotionList != NULL; }
 
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index 603ee6a27ba..fff19dbefe1 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -746,7 +746,7 @@ void LLMotionController::updateMotion()
 			
 			// is calculating a new keyframe pose, make sure the last one gets applied
 			mPoseBlender.interpolate(1.f);
-			mPoseBlender.clearBlenders();
+			clearBlenders();
 
 			mTimeStepCount = quantum_count;
 			mLastTime = mTime;
@@ -824,6 +824,13 @@ void LLMotionController::updateMotion()
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
+	// It's not clear why the getWeight() line seems to be crashing this, but
+	// hopefully this fixes it.
+	if (motion == NULL || motion->getPose() == NULL)
+	{
+		return FALSE;	
+	}
+
 	if (mLoadingMotions.find(motion) != mLoadingMotions.end())
 	{
 		// we want to start this motion, but we can't yet, so flag it as started
diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h
index 63c9219fbf7..effea0940a5 100644
--- a/indra/llcharacter/llmotioncontroller.h
+++ b/indra/llcharacter/llmotioncontroller.h
@@ -157,6 +157,8 @@ class LLMotionController
 	// deactivates terminated motions`
 	void updateMotion();
 
+	void clearBlenders() { mPoseBlender.clearBlenders(); }
+
 	// flush motions
 	// releases all motion instances
 	void flushAllMotions();
diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp
index 557bbd2d56c..2120cb223eb 100644
--- a/indra/llcharacter/llpose.cpp
+++ b/indra/llcharacter/llpose.cpp
@@ -379,15 +379,20 @@ void LLJointStateBlender::blendJointStates(BOOL apply_now)
 		}
 	}
 
-	// apply blended transforms
-	target_joint->setPosition(blended_pos);
-	target_joint->setScale(blended_scale);
-	target_joint->setRotation(blended_rot);
-
-	// apply additive transforms
-	target_joint->setPosition(target_joint->getPosition() + added_pos);
-	target_joint->setScale(target_joint->getScale() + added_scale);
-	target_joint->setRotation(added_rot * target_joint->getRotation());
+	if (!added_scale.isFinite())
+	{
+		added_scale.clearVec();
+	}
+
+	if (!blended_scale.isFinite())
+	{
+		blended_scale.setVec(1,1,1);
+	}
+
+	// apply transforms
+	target_joint->setPosition(blended_pos + added_pos);
+	target_joint->setScale(blended_scale + added_scale);
+	target_joint->setRotation(added_rot * blended_rot);
 
 	if (apply_now)
 	{
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 3c7232daa8b..e92f04441c0 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -62,6 +62,7 @@ class LLFastTimer
 		FTM_SIMULATE_PARTICLES,
 		FTM_UPDATE_SKY,
 		FTM_UPDATE_TEXTURES,
+		FTM_UPDATE_WLPARAM,
 		FTM_UPDATE_WATER,
 		FTM_UPDATE_CLOUDS,
 		FTM_UPDATE_GRASS,
@@ -86,8 +87,12 @@ class LLFastTimer
 		 FTM_RENDER_HUD,
 		 FTM_RENDER_PARTICLES,
 		 FTM_RENDER_WATER,
+		 FTM_RENDER_WL_SKY,
+		 FTM_RENDER_FAKE_VBO_UPDATE,
 		FTM_RENDER_TIMER,
 		FTM_RENDER_UI,
+		FTM_RENDER_BLOOM,
+			FTM_RENDER_BLOOM_FBO,		
 		FTM_RENDER_FONTS,
 		
 		// newview specific
@@ -124,6 +129,7 @@ class LLFastTimer
 		FTM_GEO_RESERVE,
 		FTM_GEO_LIGHT,
 		FTM_GEO_SHADOW,
+		FTM_GEO_SKY,
 		FTM_GEN_VOLUME,
 		FTM_GEN_TRIANGLES,
 		FTM_GEN_FLEX,
@@ -150,7 +156,6 @@ class LLFastTimer
 		FTM_PIPELINE,
 		FTM_VFILE_WAIT,
 		FTM_FLEXIBLE_UPDATE,
-		FTM_OCCLUSION,
 		FTM_OCCLUSION_READBACK,
 		FTM_HUD_EFFECTS,
 		FTM_HUD_UPDATE,
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 241b13f84f6..2a18e5c64c9 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -286,6 +286,7 @@ llofstream::llofstream(const char *_Filename,
 
 llofstream::~llofstream()
 {	// destroy the object
+	close();
 	delete _Filebuffer;
 }
 
diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h
index 775ecdfc993..d831eadd59e 100644
--- a/indra/llcommon/llkeythrottle.h
+++ b/indra/llcommon/llkeythrottle.h
@@ -192,10 +192,7 @@ class LLKeyThrottle
 	{
 		noteAction(id);
 		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
-		if (curr.count < m.countLimit)
-		{
-			curr.count = m.countLimit;
-		}
+		curr.count = llmax(m.countLimit, curr.count);
 		curr.blocked = TRUE;
 	}
 
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 2ec9ba85039..3b9ba9d0f76 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -43,7 +43,8 @@ LLCamera::LLCamera() :
 	mViewHeightInPixels( -1 ),			// invalid height
 	mNearPlane(DEFAULT_NEAR_PLANE),
 	mFarPlane(DEFAULT_FAR_PLANE),
-	mFixedDistance(-1.f)
+	mFixedDistance(-1.f),
+	mPlaneCount(6)
 {
 	calculateFrustumPlanes();
 } 
@@ -56,7 +57,8 @@ LLCamera::LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pix
 	mViewHeightInPixels(view_height_in_pixels),
 	mNearPlane(near_plane),
 	mFarPlane(far_plane),
-	mFixedDistance(-1.f)
+	mFixedDistance(-1.f),
+	mPlaneCount(6)
 {
 	if (mView < MIN_FIELD_OF_VIEW) 			{ mView = MIN_FIELD_OF_VIEW; }
 	else if (mView > MAX_FIELD_OF_VIEW)		{ mView = MAX_FIELD_OF_VIEW; }
@@ -78,6 +80,18 @@ LLCamera::LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pix
 
 // ---------------- LLCamera::setFoo() member functions ----------------
 
+void LLCamera::setUserClipPlane(LLPlane plane)
+{
+	mPlaneCount = 7;
+	mAgentPlanes[6].p = plane;
+	mAgentPlanes[6].mask = calcPlaneMask(plane);
+}
+
+void LLCamera::disableUserClipPlane()
+{
+	mPlaneCount = 6;
+}
+
 void LLCamera::setView(F32 field_of_view) 
 {
 	mView = field_of_view;
@@ -150,7 +164,7 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
 
 // ---------------- test methods  ---------------- 
 
-int LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius) 
+S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius) 
 {
 	static const LLVector3 scaler[] = {
 		LLVector3(-1,-1,-1),
@@ -166,10 +180,56 @@ int LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
 	U8 mask = 0;
 	S32 result = 2;
 
-	for (int i = 0; i < 6; i++)
+	for (U32 i = 0; i < mPlaneCount; i++)
+	{
+		mask = mAgentPlanes[i].mask;
+		LLPlane p = mAgentPlanes[i].p;
+		LLVector3 n = LLVector3(p);
+		float d = p.mV[3];
+		LLVector3 rscale = radius.scaledVec(scaler[mask]);
+
+		LLVector3 minp = center - rscale;
+		LLVector3 maxp = center + rscale;
+
+		if (n * minp > -d) 
+		{
+			return 0;
+		}
+	
+		if (n * maxp > -d)
+		{
+			result = 1;
+		}
+	}
+
+	return result;
+}
+
+S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius) 
+{
+	static const LLVector3 scaler[] = {
+		LLVector3(-1,-1,-1),
+		LLVector3( 1,-1,-1),
+		LLVector3(-1, 1,-1),
+		LLVector3( 1, 1,-1),
+		LLVector3(-1,-1, 1),
+		LLVector3( 1,-1, 1),
+		LLVector3(-1, 1, 1),
+		LLVector3( 1, 1, 1)
+	};
+
+	U8 mask = 0;
+	S32 result = 2;
+
+	for (U32 i = 0; i < mPlaneCount; i++)
 	{
-		mask = mAgentPlaneMask[i];
-		LLPlane p = mAgentPlanes[i];
+		if (i == 5)
+		{
+			continue;
+		}
+
+		mask = mAgentPlanes[i].mask;
+		LLPlane p = mAgentPlanes[i].p;
 		LLVector3 n = LLVector3(p);
 		float d = p.mV[3];
 		LLVector3 rscale = radius.scaledVec(scaler[mask]);
@@ -312,7 +372,7 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius)
 	int res = 2;
 	for (int i = 0; i < 6; i++)
 	{
-		float d = mAgentPlanes[i].dist(sphere_center);
+		float d = mAgentPlanes[i].p.dist(sphere_center);
 
 		if (d > radius) 
 		{
@@ -477,6 +537,25 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)
 	return LLPlane(p1, n);
 }
 
+U8 LLCamera::calcPlaneMask(const LLPlane& plane)
+{
+	U8 mask = 0;
+	
+	if (plane.mV[0] >= 0)
+	{
+		mask |= 1;
+	}
+	if (plane.mV[1] >= 0)
+	{
+		mask |= 2;
+	}
+	if (plane.mV[2] >= 0)
+	{
+		mask |= 4;
+	}
+
+	return mask;
+}
 
 void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 {
@@ -486,48 +565,34 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 		mAgentFrustum[i] = frust[i];
 	}
 
+	mFrustumCornerDist = (frust[5] - getOrigin()).magVec();
+
 	//frust contains the 8 points of the frustum, calculate 6 planes
 
 	//order of planes is important, keep most likely to fail in the front of the list
 
 	//near - frust[0], frust[1], frust[2]
-	mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
+	mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
 
 	//far  
-	mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
+	mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
 
 	//left  
-	mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
+	mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
 
 	//right  
-	mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
+	mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
 
 	//top  
-	mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
+	mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
 
 	//bottom  
-	mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
+	mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
 
 	//cache plane octant facing mask for use in AABBInFrustum
-	for (int i = 0; i < 6; i++)
+	for (U32 i = 0; i < mPlaneCount; i++)
 	{
-		U8 mask = 0;
-		LLPlane p = mAgentPlanes[i];
-		LLVector3 n = LLVector3(p);
-
-		if (n.mV[0] >= 0)
-		{
-			mask |= 1;
-		}
-		if (n.mV[1] >= 0)
-		{
-			mask |= 2;
-		}
-		if (n.mV[2] >= 0)
-		{
-			mask |= 4;
-		}
-		mAgentPlaneMask[i] = mask;
+		mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
 	}
 }
 
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 67ffb2e4503..bd894753f8f 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -46,7 +46,7 @@ const F32 MAX_FIELD_OF_VIEW = F_PI;
 const F32 MAX_ASPECT_RATIO 	= 50.0f;
 const F32 MAX_NEAR_PLANE 	= 10.f;
 const F32 MAX_FAR_PLANE 	= 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
-const F32 MAX_FAR_CLIP		= 1024.0f;
+const F32 MAX_FAR_CLIP		= 512.0f;
 
 const F32 MIN_FIELD_OF_VIEW = 0.1f;
 const F32 MIN_ASPECT_RATIO 	= 0.02f;
@@ -114,16 +114,28 @@ class LLCamera
 	
 	LLPlane mWorldPlanes[PLANE_NUM];
 	LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
-	LLPlane mAgentPlanes[6];		//frustum in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
-	U8 mAgentPlaneMask[6];
+
+	typedef struct 
+	{
+		LLPlane p;
+		U8 mask;
+	} frustum_plane;
+	frustum_plane mAgentPlanes[7];  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+									
+	U32 mPlaneCount;  //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
+
 	LLVector3 mWorldPlanePos;		// Position of World Planes (may be offset from camera)
 public:
-	LLVector3 mAgentFrustum[8];
+	LLVector3 mAgentFrustum[8];  //8 corners of 6-plane frustum
+	F32	mFrustumCornerDist;		//distance to corner of frustum against far clip plane
 	
 public:
 	LLCamera();
 	LLCamera(F32 z_field_of_view, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
 
+	void setUserClipPlane(LLPlane plane);
+	void disableUserClipPlane();
+	U8 calcPlaneMask(const LLPlane& plane);
 	void setView(F32 new_view);
 	void setViewHeightInPixels(S32 height);
 	void setAspect(F32 new_aspect);
@@ -164,6 +176,8 @@ class LLCamera
 	S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
 	S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
 	S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
+	S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
+
 	//does a quick 'n dirty sphere-sphere check
 	S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius); 
 
diff --git a/indra/llmath/llcoordframe.cpp b/indra/llmath/llcoordframe.cpp
index 70d4646264a..f1084547315 100644
--- a/indra/llmath/llcoordframe.cpp
+++ b/indra/llmath/llcoordframe.cpp
@@ -730,7 +730,11 @@ void LLCoordFrame::lookDir(const LLVector3 &at, const LLVector3 &up_direction)
 	left.normVec();
 
 	LLVector3 up = at % left;
-	setAxes(at, left, up);
+
+	if (at.isFinite() && left.isFinite() && up.isFinite())
+	{
+		setAxes(at, left, up);
+	}
 }
 
 void LLCoordFrame::lookDir(const LLVector3 &xuv)
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index f1b223f559e..6df241d3ab9 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -440,4 +440,20 @@ inline F32 llsimple_angle(F32 angle)
 	return angle;
 }
 
+//calculate the nearesr power of two number for val, bounded by max_power_two
+inline U32 get_nearest_power_two(U32 val, U32 max_power_two)
+{
+	if(!max_power_two)
+	{
+		max_power_two = 1 << 31 ;
+	}
+	if(max_power_two & (max_power_two - 1))
+	{
+		return 0 ;
+	}
+
+	for(; val < max_power_two ; max_power_two >>= 1) ;
+	
+	return max_power_two ;
+}
 #endif
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index def6cb415a0..fab80702592 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -47,10 +47,9 @@
 #if LL_DARWIN
 #define LL_OCTREE_MAX_CAPACITY 32
 #else
-#define LL_OCTREE_MAX_CAPACITY 256
+#define LL_OCTREE_MAX_CAPACITY 128
 #endif
 
-template <class T> class LLOctreeState;
 template <class T> class LLOctreeNode;
 
 template <class T>
@@ -64,15 +63,27 @@ class LLOctreeListener: public LLTreeListener<T>
 	virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0;
 };
 
+template <class T>
+class LLOctreeTraveler : public LLTreeTraveler<T>
+{
+public:
+	virtual void traverse(const LLTreeNode<T>* node);
+	virtual void visit(const LLTreeNode<T>* state) { }
+	virtual void visit(const LLOctreeNode<T>* branch) = 0;
+};
 
 template <class T>
 class LLOctreeNode : public LLTreeNode<T>
 {
 public:
-
+	typedef LLOctreeTraveler<T>									oct_traveler;
+	typedef LLTreeTraveler<T>									tree_traveler;
+	typedef typename std::set<LLPointer<T> >					element_list;
+	typedef typename std::set<LLPointer<T> >::iterator			element_iter;
+	typedef typename std::set<LLPointer<T> >::const_iterator	const_element_iter;
+	typedef typename std::vector<LLTreeListener<T>*>::iterator	tree_listener_iter;
+	typedef typename std::vector<LLOctreeNode<T>* >				child_list;
 	typedef LLTreeNode<T>		BaseType;
-	typedef LLTreeState<T>		tree_state;
-	typedef LLOctreeState<T>	oct_state;
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
 
@@ -82,11 +93,9 @@ class LLOctreeNode : public LLTreeNode<T>
 		
 	LLOctreeNode(	LLVector3d center, 
 					LLVector3d size, 
-					tree_state* state, 
 					BaseType* parent, 
 					U8 octant = 255)
-	:	BaseType(state), 
-		mParent((oct_node*)parent), 
+	:	mParent((oct_node*)parent), 
 		mCenter(center), 
 		mSize(size), 
 		mOctant(octant) 
@@ -96,9 +105,19 @@ class LLOctreeNode : public LLTreeNode<T>
 		{
 			mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
 		}
+
+		clearChildren();
 	}
 
-	~LLOctreeNode()								{ BaseType::destroyListeners(); delete this->mState; }
+	virtual ~LLOctreeNode()								
+	{ 
+		BaseType::destroyListeners(); 
+		
+		for (U32 i = 0; i < getChildCount(); i++)
+		{
+			delete getChild(i);
+		} 
+	}
 
 	inline const BaseType* getParent()	const			{ return mParent; }
 	inline void setParent(BaseType* parent)			{ mParent = (oct_node*) parent; }
@@ -106,25 +125,12 @@ class LLOctreeNode : public LLTreeNode<T>
 	inline const LLVector3d& getSize() const			{ return mSize; }
 	inline void setCenter(LLVector3d center)			{ mCenter = center; }
 	inline void setSize(LLVector3d size)				{ mSize = size; }
-    inline bool balance()								{ return getOctState()->balance(); }
-	inline void validate()								{ getOctState()->validate(); }
-	inline U32 getChildCount()	const					{ return getOctState()->getChildCount(); }
-	inline oct_node* getChild(U32 index)				{ return getOctState()->getChild(index); }
-	inline const oct_node* getChild(U32 index) const	{ return getOctState()->getChild(index); }
-	inline U32 getElementCount() const					{ return getOctState()->getElementCount(); }
-	inline void removeByAddress(T* data)				{ getOctState()->removeByAddress(data); }
-	inline bool hasLeafState()	const					{ return getOctState()->isLeaf(); }
-	inline void destroy()								{ getOctState()->destroy(); }
-	inline oct_node* getNodeAt(T* data)				{ return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
-	inline oct_node* getNodeAt(const LLVector3d& pos, const F64& rad) { return getOctState()->getNodeAt(pos, rad); }
+    inline oct_node* getNodeAt(T* data)				{ return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
 	inline U8 getOctant() const						{ return mOctant; }
 	inline void setOctant(U8 octant)					{ mOctant = octant; }
-	inline const oct_state* getOctState() const		{ return (const oct_state*) BaseType::mState; }
-	inline oct_state* getOctState()	 				{ return (oct_state*) BaseType::mState; }
 	inline const oct_node*	getOctParent() const		{ return (const oct_node*) getParent(); }
 	inline oct_node* getOctParent() 					{ return (oct_node*) getParent(); }
-	inline void deleteChild(oct_node* child)			{ getOctState()->deleteChild(child); }
-
+	
 	U8 getOctant(const F64 pos[]) const	//get the octant pos is in
 	{
 		U8 ret = 0;
@@ -205,9 +211,9 @@ class LLOctreeNode : public LLTreeNode<T>
 				(radius <= p_size && radius > size);
 	}
 
-	static void pushCenter(LLVector3d &center, LLVector3d &size, T* data)
+	static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
 	{
-		LLVector3d pos(data->getPositionGroup());
+		const LLVector3d& pos = data->getPositionGroup();
 		for (U32 i = 0; i < 3; i++)
 		{
 			if (pos.mdV[i] > center.mdV[i])
@@ -221,76 +227,25 @@ class LLOctreeNode : public LLTreeNode<T>
 		}
 	}
 
-protected:
-	oct_node* mParent;
-	LLVector3d mCenter;
-	LLVector3d mSize;
-	LLVector3d mMax;
-	LLVector3d mMin;
-	U8 mOctant;
-};
-
-template <class T>
-class LLOctreeTraveler : public LLTreeTraveler<T>
-{
-public:
-	virtual void traverse(const LLTreeNode<T>* node);
-	virtual void visit(const LLTreeState<T>* state) { }
-	virtual void visit(const LLOctreeState<T>* branch) = 0;
-};
-
-//will pass requests to a child, might make a new child
-template <class T>
-class LLOctreeState : public LLTreeState<T> 
-{
-public:
-	typedef LLTreeState<T>										BaseType;
-	typedef LLOctreeTraveler<T>									oct_traveler;
-	typedef LLOctreeNode<T>										oct_node;
-	typedef LLOctreeListener<T>									oct_listener;
-	typedef LLTreeTraveler<T>									tree_traveler;
-	typedef typename std::set<LLPointer<T> >					element_list;
-	typedef typename std::set<LLPointer<T> >::iterator			element_iter;
-	typedef typename std::set<LLPointer<T> >::const_iterator	const_element_iter;
-	typedef typename std::vector<LLTreeListener<T>*>::iterator	tree_listener_iter;
-	typedef typename std::vector<LLOctreeNode<T>* >				child_list;
+	void accept(oct_traveler* visitor)				{ visitor->visit(this); }
+	virtual bool isLeaf() const						{ return mChild.empty(); }
 	
-	LLOctreeState(oct_node* node = NULL): BaseType(node)	{ this->clearChildren(); }
-	virtual ~LLOctreeState() 
-	{	
-		for (U32 i = 0; i < getChildCount(); i++)
-		{
-			delete getChild(i);
-		}
-	}
-																
+	U32 getElementCount() const						{ return mData.size(); }
+	element_list& getData()							{ return mData; }
+	const element_list& getData() const				{ return mData; }
 	
-	virtual void accept(oct_traveler* visitor)				{ visitor->visit(this); }
-	virtual bool isLeaf() const								{ return mChild.empty(); }
+	U32 getChildCount()	const						{ return mChild.size(); }
+	oct_node* getChild(U32 index)					{ return mChild[index]; }
+	const oct_node* getChild(U32 index) const		{ return mChild[index]; }
+	child_list& getChildren()						{ return mChild; }
+	const child_list& getChildren() const			{ return mChild; }
 	
-	virtual U32 getElementCount() const						{ return mData.size(); }
-	virtual element_list& getData()							{ return mData; }
-	virtual const element_list& getData() const				{ return mData; }
+	void accept(tree_traveler* visitor) const		{ visitor->visit(this); }
+	void accept(oct_traveler* visitor) const		{ visitor->visit(this); }
 	
-	virtual U32 getChildCount()	const						{ return mChild.size(); }
-	virtual oct_node* getChild(U32 index)					{ return mChild[index]; }
-	virtual const oct_node* getChild(U32 index) const		{ return mChild[index]; }
-	virtual child_list& getChildren()						{ return mChild; }
-	virtual const child_list& getChildren() const			{ return mChild; }
-	
-	virtual void accept(tree_traveler* visitor) const		{ visitor->visit(this); }
-	virtual void accept(oct_traveler* visitor) const		{ visitor->visit(this); }
-	const oct_node* getOctNode() const						{ return (const oct_node*) BaseType::getNode(); }
-	oct_node* getOctNode()									{ return (oct_node*) BaseType::getNode(); }
-
-	virtual oct_node* getNodeAt(T* data)
-	{
-		return getNodeAt(data->getPositionGroup(), data->getBinRadius());
-	}
-
-	virtual oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
+	oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
 	{ 
-		LLOctreeNode<T>* node = getOctNode();
+		LLOctreeNode<T>* node = this;
 
 		if (node->isInside(pos, rad))
 		{		
@@ -328,26 +283,19 @@ class LLOctreeState : public LLTreeState<T>
 	{
 		if (data == NULL)
 		{
-			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
+			//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
 			return false;
 		}
-		LLOctreeNode<T>* node = getOctNode();
-		LLOctreeNode<T>* parent = node->getOctParent();
+		LLOctreeNode<T>* parent = getOctParent();
 
 		//is it here?
-		if (node->isInside(data->getPositionGroup()))
+		if (isInside(data->getPositionGroup()))
 		{
 			if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
-				(node->contains(data->getBinRadius()) ||
-				(data->getBinRadius() > node->getSize().mdV[0] &&
+				(contains(data->getBinRadius()) ||
+				(data->getBinRadius() > getSize().mdV[0] &&
 				parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) 
 			{ //it belongs here
-				if (data == NULL)
-				{
-					OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE LEAF !!!" << llendl;
-					return false;
-				}
-				
 #if LL_OCTREE_PARANOIA_CHECK
 				//if this is a redundant insertion, error out (should never happen)
 				if (mData.find(data) != mData.end())
@@ -358,6 +306,7 @@ class LLOctreeState : public LLTreeState<T>
 #endif
 
 				mData.insert(data);
+				BaseType::insert(data);
 				return true;
 			}
 			else
@@ -375,8 +324,8 @@ class LLOctreeState : public LLTreeState<T>
 				}
 				
 				//it's here, but no kids are in the right place, make a new kid
-				LLVector3d center(node->getCenter());
-				LLVector3d size(node->getSize()*0.5);
+				LLVector3d center(getCenter());
+				LLVector3d size(getSize()*0.5);
 		        		
 				//push center in direction of data
 				LLOctreeNode<T>::pushCenter(center, size, data);
@@ -386,7 +335,6 @@ class LLOctreeState : public LLTreeState<T>
 				{
 					//this really isn't possible, something bad has happened
 					OCT_ERRS << "Octree detected floating point error and gave up." << llendl;
-					//bool check = node->isInside(data);
 					return false;
 				}
 				
@@ -396,25 +344,25 @@ class LLOctreeState : public LLTreeState<T>
 					if (mChild[i]->getCenter() == center)
 					{
 						OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
-						//bool check = node->isInside(data);
-						//check = getChild(i)->isInside(data);
 						return false;
 					}
 				}
 #endif
 
 				//make the new kid
-				LLOctreeState<T>* newstate = new LLOctreeState<T>();
-				child = new LLOctreeNode<T>(center, size, newstate, node);
+				child = new LLOctreeNode<T>(center, size, this);
 				addChild(child);
-
+								
 				child->insert(data);
 			}
 		}
 		else 
 		{
 			//it's not in here, give it to the root
-			LLOctreeNode<T>* parent = node->getOctParent();
+			//OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
+
+			oct_node* node = this;
+
 			while (parent)
 			{
 				node = parent;
@@ -427,22 +375,20 @@ class LLOctreeState : public LLTreeState<T>
 		return false;
 	}
 
-	virtual bool remove(T* data)
+	bool remove(T* data)
 	{
-		oct_node* node = getOctNode();
-
 		if (mData.find(data) != mData.end())
 		{	//we have data
 			mData.erase(data);
-			node->notifyRemoval(data);
+			notifyRemoval(data);
 			checkAlive();
 			return true;
 		}
-		else if (node->isInside(data))
+		else if (isInside(data))
 		{
 			oct_node* dest = getNodeAt(data);
 
-			if (dest != node)
+			if (dest != this)
 			{
 				return dest->remove(data);
 			}
@@ -451,7 +397,9 @@ class LLOctreeState : public LLTreeState<T>
 		//SHE'S GONE MISSING...
 		//none of the children have it, let's just brute force this bastard out
 		//starting with the root node (UGLY CODE COMETH!)
-		oct_node* parent = node->getOctParent();
+		oct_node* parent = getOctParent();
+		oct_node* node = this;
+
 		while (parent != NULL)
 		{
 			node = parent;
@@ -464,12 +412,12 @@ class LLOctreeState : public LLTreeState<T>
 		return true;
 	}
 
-	virtual void removeByAddress(T* data)
+	void removeByAddress(T* data)
 	{
         if (mData.find(data) != mData.end())
 		{
 			mData.erase(data);
-			getOctNode()->notifyRemoval(data);
+			notifyRemoval(data);
 			llwarns << "FOUND!" << llendl;
 			checkAlive();
 			return;
@@ -482,20 +430,18 @@ class LLOctreeState : public LLTreeState<T>
 		}
 	}
 
-	virtual void clearChildren()
+	void clearChildren()
 	{
 		mChild.clear();
 	}
 
-	virtual void validate()
+	void validate()
 	{
 #if LL_OCTREE_PARANOIA_CHECK
-		LLOctreeNode<T>* node = this->getOctNode();
-
 		for (U32 i = 0; i < getChildCount(); i++)
 		{
 			mChild[i]->validate();
-			if (mChild[i]->getParent() != node)
+			if (mChild[i]->getParent() != this)
 			{
 				llerrs << "Octree child has invalid parent." << llendl;
 			}
@@ -508,7 +454,7 @@ class LLOctreeState : public LLTreeState<T>
 		return false;
 	}
 
-	virtual void destroy()
+	void destroy()
 	{
 		for (U32 i = 0; i < getChildCount(); i++) 
 		{	
@@ -517,7 +463,7 @@ class LLOctreeState : public LLTreeState<T>
 		}
 	}
 
-	virtual void addChild(oct_node* child, BOOL silent = FALSE) 
+	void addChild(oct_node* child, BOOL silent = FALSE) 
 	{
 #if LL_OCTREE_PARANOIA_CHECK
 		for (U32 i = 0; i < getChildCount(); i++)
@@ -539,27 +485,24 @@ class LLOctreeState : public LLTreeState<T>
 #endif
 
 		mChild.push_back(child);
-		child->setParent(getOctNode());
+		child->setParent(this);
 
 		if (!silent)
 		{
-			oct_node* node = getOctNode();
-			
-			for (U32 i = 0; i < node->getListenerCount(); i++)
+			for (U32 i = 0; i < this->getListenerCount(); i++)
 			{
-				oct_listener* listener = node->getOctListener(i);
-				listener->handleChildAddition(node, child);
+				oct_listener* listener = getOctListener(i);
+				listener->handleChildAddition(this, child);
 			}
 		}
 	}
 
-	virtual void removeChild(U8 index, BOOL destroy = FALSE)
+	void removeChild(U8 index, BOOL destroy = FALSE)
 	{
-		oct_node* node = getOctNode();
-		for (U32 i = 0; i < node->getListenerCount(); i++)
+		for (U32 i = 0; i < this->getListenerCount(); i++)
 		{
-			oct_listener* listener = node->getOctListener(i);
-			listener->handleChildRemoval(node, getChild(index));
+			oct_listener* listener = getOctListener(i);
+			listener->handleChildRemoval(this, getChild(index));
 		}
 
 		if (destroy)
@@ -572,20 +515,19 @@ class LLOctreeState : public LLTreeState<T>
 		checkAlive();
 	}
 
-	virtual void checkAlive()
+	void checkAlive()
 	{
 		if (getChildCount() == 0 && getElementCount() == 0)
 		{
-			oct_node* node = getOctNode();
-			oct_node* parent = node->getOctParent();
+			oct_node* parent = getOctParent();
 			if (parent)
 			{
-				parent->deleteChild(node);
+				parent->deleteChild(this);
 			}
 		}
 	}
 
-	virtual void deleteChild(oct_node* node)
+	void deleteChild(oct_node* node)
 	{
 		for (U32 i = 0; i < getChildCount(); i++)
 		{
@@ -596,55 +538,62 @@ class LLOctreeState : public LLTreeState<T>
 			}
 		}
 
-		OCT_ERRS << "Octree failed to delete requested child." << llendl;
+		//OCT_ERRS << "Octree failed to delete requested child." << llendl;
 	}
 
-protected:
+protected:	
 	child_list mChild;
 	element_list mData;
+	oct_node* mParent;
+	LLVector3d mCenter;
+	LLVector3d mSize;
+	LLVector3d mMax;
+	LLVector3d mMin;
+	U8 mOctant;
 };
 
-//just like a branch, except it might expand the node it points to
+//just like a regular node, except it might expand on insert and compress on balance
 template <class T>
-class LLOctreeRoot : public LLOctreeState<T>
+class LLOctreeRoot : public LLOctreeNode<T>
 {
 public:
-	typedef LLOctreeState<T>	BaseType;
+	typedef LLOctreeNode<T>	BaseType;
 	typedef LLOctreeNode<T>		oct_node;
+
+	LLOctreeRoot(	LLVector3d center, 
+					LLVector3d size, 
+					BaseType* parent)
+	:	BaseType(center, size, parent)
+	{
+	}
 	
-	LLOctreeRoot(oct_node* node = NULL) : BaseType(node) { }
-	
-	oct_node* getOctNode()	{ return BaseType::getOctNode(); }
-	virtual bool isLeaf()	{ return false; }
+	bool isLeaf()	{ return false; }
 
-	virtual bool balance()
+	bool balance()
 	{	
-		//the cached node might be invalid, so don't reference it
 		if (this->getChildCount() == 1 && 
-			!(this->mChild[0]->hasLeafState()) &&
+			!(this->mChild[0]->isLeaf()) &&
 			this->mChild[0]->getElementCount() == 0) 
 		{ //if we have only one child and that child is an empty branch, make that child the root
-			BaseType* state = this->mChild[0]->getOctState();
 			oct_node* child = this->mChild[0];
-			oct_node* root = getOctNode();
-		
+					
 			//make the root node look like the child
-			root->setCenter(this->mChild[0]->getCenter());
-			root->setSize(this->mChild[0]->getSize());
-			root->updateMinMax();
+			this->setCenter(this->mChild[0]->getCenter());
+			this->setSize(this->mChild[0]->getSize());
+			this->updateMinMax();
 
 			//reset root node child list
 			this->clearChildren();
 
 			//copy the child's children into the root node silently 
 			//(don't notify listeners of addition)
-			for (U32 i = 0; i < state->getChildCount(); i++)
+			for (U32 i = 0; i < child->getChildCount(); i++)
 			{
-				addChild(state->getChild(i), TRUE);
+				addChild(child->getChild(i), TRUE);
 			}
 
 			//destroy child
-			state->clearChildren();
+			child->clearChildren();
 			delete child;
 		}
 		
@@ -652,69 +601,90 @@ class LLOctreeRoot : public LLOctreeState<T>
 	}
 
 	// LLOctreeRoot::insert
-	virtual bool insert(T* data)
+	bool insert(T* data)
 	{
 		if (data == NULL) 
 		{
-			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
+			//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
 			return false;
 		}
 		
 		if (data->getBinRadius() > 4096.0)
 		{
-			OCT_ERRS << "!!! ELEMENT EXCEDES MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+			//OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+			return false;
 		}
 		
-		LLOctreeNode<T>* node = getOctNode();
-		if (node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup()))
+		const F64 MAX_MAG = 1024.0*1024.0;
+
+		const LLVector3d& v = data->getPositionGroup();
+		if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
+		      fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
+		      fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
+		{
+			//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+			return false;
+		}
+
+		if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
 		{
 			//we got it, just act like a branch
-			LLOctreeState<T>::insert(data);
+			oct_node* node = getNodeAt(data);
+			if (node == this)
+			{
+				LLOctreeNode<T>::insert(data);
+			}
+			else
+			{
+				node->insert(data);
+			}
 		}
 		else if (this->getChildCount() == 0)
 		{
 			//first object being added, just wrap it up
-			while (!(node->getSize().mdV[0] > data->getBinRadius() && node->isInside(data->getPositionGroup())))
+			while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
 			{
 				LLVector3d center, size;
-				center = node->getCenter();
-				size = node->getSize();
+				center = this->getCenter();
+				size = this->getSize();
 				LLOctreeNode<T>::pushCenter(center, size, data);
-				node->setCenter(center);
-				node->setSize(size*2);
-				node->updateMinMax();
+				this->setCenter(center);
+				this->setSize(size*2);
+				this->updateMinMax();
 			}
-			LLOctreeState<T>::insert(data);
+			LLOctreeNode<T>::insert(data);
 		}
 		else
 		{
-			//the data is outside the root node, we need to grow
-			LLVector3d center(node->getCenter());
-			LLVector3d size(node->getSize());
-
-			//expand this node
-			LLVector3d newcenter(center);
-			LLOctreeNode<T>::pushCenter(newcenter, size, data);
-			node->setCenter(newcenter);
-			node->setSize(size*2);
-			node->updateMinMax();
-
-			//copy our children to a new branch
-			LLOctreeState<T>* newstate = new LLOctreeState<T>();
-			LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, newstate, node);
-			
-			for (U32 i = 0; i < this->getChildCount(); i++)
+			while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
 			{
-				LLOctreeNode<T>* child = this->getChild(i);
-				newstate->addChild(child);
-			}
+				//the data is outside the root node, we need to grow
+				LLVector3d center(this->getCenter());
+				LLVector3d size(this->getSize());
+
+				//expand this node
+				LLVector3d newcenter(center);
+				LLOctreeNode<T>::pushCenter(newcenter, size, data);
+				this->setCenter(newcenter);
+				this->setSize(size*2);
+				this->updateMinMax();
+
+				//copy our children to a new branch
+				LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
+				
+				for (U32 i = 0; i < this->getChildCount(); i++)
+				{
+					LLOctreeNode<T>* child = this->getChild(i);
+					newnode->addChild(child);
+				}
 
-			//clear our children and add the root copy
-			this->clearChildren();
-			addChild(newnode);
+				//clear our children and add the root copy
+				this->clearChildren();
+				addChild(newnode);
+			}
 
 			//insert the data
-			node->insert(data);
+			insert(data);
 		}
 
 		return false;
@@ -726,13 +696,13 @@ class LLOctreeRoot : public LLOctreeState<T>
 //		LLOctreeTraveler
 //========================
 template <class T>
-void LLOctreeTraveler<T>::traverse(const LLTreeNode<T>* node)
+void LLOctreeTraveler<T>::traverse(const LLTreeNode<T>* tree_node)
 {
-	const LLOctreeState<T>* state = (const LLOctreeState<T>*) node->getState();
-	state->accept(this);
-	for (U32 i = 0; i < state->getChildCount(); i++)
+	const LLOctreeNode<T>* node = (const LLOctreeNode<T>*) tree_node;
+	node->accept(this);
+	for (U32 i = 0; i < node->getChildCount(); i++)
 	{
-		traverse(state->getChild(i));
+		traverse(node->getChild(i));
 	}
 }
 
diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h
index 6cafee01d4f..6685915bcf2 100644
--- a/indra/llmath/lltreenode.h
+++ b/indra/llmath/lltreenode.h
@@ -39,23 +39,6 @@ template <class T> class LLTreeNode;
 template <class T> class LLTreeTraveler;
 template <class T> class LLTreeListener;
 
-template <class T>
-class LLTreeState
-{
-public:
-	LLTreeState(LLTreeNode<T>* node)				{ setNode(node); }
-	virtual ~LLTreeState() { };
-	virtual bool insert(T* data) = 0;
-	virtual bool remove(T* data) = 0;
-	virtual void setNode(LLTreeNode<T>* node);
-	virtual const LLTreeNode<T>* getNode() const	{ return mNode; }
-	virtual LLTreeNode<T>* getNode()				{ return mNode; }
-	virtual void accept(LLTreeTraveler<T>* traveler) const = 0;
-	virtual LLTreeListener<T>* getListener(U32 index) const;
-private:
-	LLTreeNode<T>* mNode;
-};
-
 template <class T>
 class LLTreeListener: public LLRefCount
 {
@@ -70,19 +53,14 @@ template <class T>
 class LLTreeNode 
 {
 public:
-	LLTreeNode(LLTreeState<T>* state)				{ setState(state); }
 	virtual ~LLTreeNode();
-	LLTreeState<T>* getState()				{ return mState; }
-	const LLTreeState<T>* getState() const	{ return mState; }
-
-	void setState(LLTreeState<T>* state);
-	void insert(T* data);
-	bool remove(T* data);
-	void notifyRemoval(T* data);
-	inline U32 getListenerCount()					{ return mListeners.size(); }
-	inline LLTreeListener<T>* getListener(U32 index) const { return mListeners[index]; }
-	inline void addListener(LLTreeListener<T>* listener) { mListeners.push_back(listener); }
-	inline void removeListener(U32 index) { mListeners.erase(mListeners.begin()+index); }
+	
+	virtual bool insert(T* data);
+	virtual bool remove(T* data);
+	virtual void notifyRemoval(T* data);
+	virtual U32 getListenerCount()					{ return mListeners.size(); }
+	virtual LLTreeListener<T>* getListener(U32 index) const { return mListeners[index]; }
+	virtual void addListener(LLTreeListener<T>* listener) { mListeners.push_back(listener); }
 
 protected:
 	void destroyListeners()
@@ -94,7 +72,6 @@ class LLTreeNode
 		mListeners.clear();
 	}
 	
-	LLTreeState<T>* mState;
 public:
 	std::vector<LLPointer<LLTreeListener<T> > > mListeners;
 };
@@ -105,7 +82,7 @@ class LLTreeTraveler
 public:
 	virtual ~LLTreeTraveler() { }; 
 	virtual void traverse(const LLTreeNode<T>* node) = 0;
-	virtual void visit(const LLTreeState<T>* state) = 0;
+	virtual void visit(const LLTreeNode<T>* node) = 0;
 };
 
 template <class T>
@@ -115,25 +92,19 @@ LLTreeNode<T>::~LLTreeNode()
 };
 
 template <class T>
-void LLTreeNode<T>::insert(T* data)
+bool LLTreeNode<T>::insert(T* data)
 { 
-	if (mState->insert(data))
+	for (U32 i = 0; i < mListeners.size(); i++)
 	{
-		for (U32 i = 0; i < mListeners.size(); i++)
-		{
-			mListeners[i]->handleInsertion(this, data);
-		}
+		mListeners[i]->handleInsertion(this, data);
 	}
+	return true;
 };
 
 template <class T>
 bool LLTreeNode<T>::remove(T* data)
 {
-	if (mState->remove(data))
-	{
-		return true;
-	}
-	return false;
+	return true;
 };
 
 template <class T>
@@ -145,38 +116,4 @@ void LLTreeNode<T>::notifyRemoval(T* data)
 	}
 }
 
-template <class T>
-void LLTreeNode<T>::setState(LLTreeState<T>* state)
-{
-	mState = state;
-	if (state)
-	{
-		if (state->getNode() != this)
-		{
-			state->setNode(this);
-		}
-
-		for (U32 i = 0; i < mListeners.size(); i++)
-		{
-			mListeners[i]->handleStateChange(this);
-		}
-	}
-};
-
-template <class T>
-void LLTreeState<T>::setNode(LLTreeNode<T>* node)
-{
-	mNode = node;
-	if (node && node->getState() != this) 
-	{
-		node->setState(this);
-	}
-};
-
-template <class T>
-LLTreeListener<T>* LLTreeState<T>::getListener(U32 index) const
-{
-	return mNode->getListener(index);
-}
-
 #endif
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 037357c92ee..ab2eef0ee92 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1639,12 +1639,27 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	}
 }
 
+void LLVolume::resizePath(S32 length)
+{
+	mPathp->resizePath(length);
+	if (mVolumeFaces != NULL)
+	{
+		delete[] mVolumeFaces;
+		mVolumeFaces = NULL;
+	}
+}
+
 void LLVolume::regen()
 {
 	generate();
 	createVolumeFaces();
 }
 
+void LLVolume::genBinormals(S32 face)
+{
+	mVolumeFaces[face].createBinormals();
+}
+
 LLVolume::~LLVolume()
 {
 	sNumMeshPoints -= mMesh.size();
@@ -1746,12 +1761,6 @@ void LLVolume::createVolumeFaces()
 {
 	S32 i;
 
-	if (mVolumeFaces != NULL)
-	{
-		delete[] mVolumeFaces;
-		mVolumeFaces = NULL;
-	}
-
 	if (mGenerateSingleFace)
 	{
 		mNumVolumeFaces = 0;
@@ -1760,7 +1769,12 @@ void LLVolume::createVolumeFaces()
 	{
 		S32 num_faces = getNumFaces();
 		mNumVolumeFaces = num_faces;
-		mVolumeFaces = new LLVolumeFace[num_faces];
+		BOOL partial_build = TRUE;
+		if (!mVolumeFaces)
+		{
+			partial_build = FALSE;
+			mVolumeFaces = new LLVolumeFace[num_faces];
+		}
 		// Initialize volume faces with parameter data
 		for (i = 0; i < num_faces; i++)
 		{
@@ -1823,7 +1837,7 @@ void LLVolume::createVolumeFaces()
 
 		for (i = 0; i < mNumVolumeFaces; i++)
 		{
-			mVolumeFaces[i].create();
+			mVolumeFaces[i].create(partial_build);
 		}
 	}
 }
@@ -3967,18 +3981,19 @@ LLVolumeFace::LLVolumeFace()
 	mBeginT = 0;
 	mNumS = 0;
 	mNumT = 0;
+	mHasBinormals = FALSE;
 }
 
 
-BOOL LLVolumeFace::create()
+BOOL LLVolumeFace::create(BOOL partial_build)
 {
 	if (mTypeMask & CAP_MASK)
 	{
-		return createCap();
+		return createCap(partial_build);
 	}
 	else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
 	{
-		return createSide();
+		return createSide(partial_build);
 	}
 	else
 	{
@@ -4000,7 +4015,7 @@ void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
 	vout.mBinormal = v0.mBinormal;
 }
 
-BOOL LLVolumeFace::createUnCutCubeCap()
+BOOL LLVolumeFace::createUnCutCubeCap(BOOL partial_build)
 {
 	const std::vector<LLVolume::Point>& mesh = mVolumep->getMesh();
 	const std::vector<LLVector3>& profile = mVolumep->getProfile().mProfile;
@@ -4055,6 +4070,12 @@ BOOL LLVolumeFace::createUnCutCubeCap()
 		corners[t].mBinormal = baseVert.mBinormal;
 		corners[t].mNormal = baseVert.mNormal;
 	}
+	mHasBinormals = TRUE;
+
+	if (partial_build)
+	{
+		mVertices.clear();
+	}
 
 	S32	vtop = mVertices.size();
 	for(int gx = 0;gx<grid_size+1;gx++){
@@ -4082,22 +4103,25 @@ BOOL LLVolumeFace::createUnCutCubeCap()
 	
 	mCenter = (min + max) * 0.5f;
 
-	int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
-	for(int gx = 0;gx<grid_size;gx++){
-		for(int gy = 0;gy<grid_size;gy++){
-			if (mTypeMask & TOP_MASK){
-				for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
-			}else{
-				for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
+	if (!partial_build)
+	{
+		int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
+		for(int gx = 0;gx<grid_size;gx++){
+			for(int gy = 0;gy<grid_size;gy++){
+				if (mTypeMask & TOP_MASK){
+					for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
+				}else{
+					for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
+				}
 			}
 		}
 	}
-	
+		
 	return TRUE;
 }
 
 
-BOOL LLVolumeFace::createCap()
+BOOL LLVolumeFace::createCap(BOOL partial_build)
 {
 	if (!(mTypeMask & HOLLOW_MASK) && 
 		!(mTypeMask & OPEN_MASK) && 
@@ -4106,7 +4130,7 @@ BOOL LLVolumeFace::createCap()
 		(mVolumep->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE &&
 			mVolumep->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE)	
 		){
-		return createUnCutCubeCap();
+		return createUnCutCubeCap(partial_build);
 	}
 
 	S32 i;
@@ -4118,8 +4142,13 @@ BOOL LLVolumeFace::createCap()
 	// All types of caps have the same number of vertices and indices
 	num_vertices = profile.size();
 	num_indices = (profile.size() - 2)*3;
-	vector_append(mVertices,num_vertices);
-	vector_append(mIndices,num_indices);
+
+	mVertices.resize(num_vertices);
+
+	if (!partial_build)
+	{
+		mIndices.resize(num_indices);
+	}
 
 	S32 max_s = mVolumep->getProfile().getTotal();
 	S32 max_t = mVolumep->getPath().mPath.size();
@@ -4203,7 +4232,10 @@ BOOL LLVolumeFace::createCap()
 	{
 		mVertices.push_back(vd);
 		num_vertices++;
-		vector_append(mIndices, 3);
+		if (!partial_build)
+		{
+			vector_append(mIndices, 3);
+		}
 	}
 		
 	
@@ -4213,6 +4245,13 @@ BOOL LLVolumeFace::createCap()
 		mVertices[i].mNormal = normal;
 	}
 
+	mHasBinormals = TRUE;
+
+	if (partial_build)
+	{
+		return TRUE;
+	}
+
 	if (mTypeMask & HOLLOW_MASK)
 	{
 		if (mTypeMask & TOP_MASK)
@@ -4480,7 +4519,50 @@ BOOL LLVolumeFace::createCap()
 	return TRUE;
 }
 
-BOOL LLVolumeFace::createSide()
+void LLVolumeFace::createBinormals()
+{
+	if (!mHasBinormals)
+	{
+		//generate binormals
+		for (U32 i = 0; i < mIndices.size()/3; i++) 
+		{	//for each triangle
+			const VertexData& v0 = mVertices[mIndices[i*3+0]];
+			const VertexData& v1 = mVertices[mIndices[i*3+1]];
+			const VertexData& v2 = mVertices[mIndices[i*3+2]];
+						
+			//calculate binormal
+			LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
+															v1.mPosition, v1.mTexCoord,
+															v2.mPosition, v2.mTexCoord);
+
+			for (U32 j = 0; j < 3; j++) 
+			{ //add triangle normal to vertices
+				mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
+			}
+
+			//even out quad contributions
+			if (i % 2 == 0) 
+			{
+				mVertices[mIndices[i*3+2]].mBinormal += binorm;
+			}
+			else 
+			{
+				mVertices[mIndices[i*3+1]].mBinormal += binorm;
+			}
+		}
+
+		//normalize binormals
+		for (U32 i = 0; i < mVertices.size(); i++) 
+		{
+			mVertices[i].mBinormal.normVec();
+			mVertices[i].mNormal.normVec();
+		}
+
+		mHasBinormals = TRUE;
+	}
+}
+
+BOOL LLVolumeFace::createSide(BOOL partial_build)
 {
 	BOOL flat = mTypeMask & FLAT_MASK;
 	S32 num_vertices, num_indices;
@@ -4496,9 +4578,14 @@ BOOL LLVolumeFace::createSide()
 
 	num_vertices = mNumS*mNumT;
 	num_indices = (mNumS-1)*(mNumT-1)*6;
-	vector_append(mVertices,num_vertices);
-	vector_append(mIndices,num_indices);
-	vector_append(mEdge, num_indices);
+
+	mVertices.resize(num_vertices);
+
+	if (!partial_build)
+	{
+		mIndices.resize(num_indices);
+		mEdge.resize(num_indices);
+	}
 
 	LLVector3& face_min = mExtents[0];
 	LLVector3& face_max = mExtents[1];
@@ -4609,61 +4696,63 @@ BOOL LLVolumeFace::createSide()
 	S32 cur_edge = 0;
 	BOOL flat_face = mTypeMask & FLAT_MASK;
 
-	// Now we generate the indices.
-	for (t = 0; t < (mNumT-1); t++)
-	{
-		for (s = 0; s < (mNumS-1); s++)
-		{	
-			mIndices[cur_index++] = s   + mNumS*t;			//bottom left
-			mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
-			mIndices[cur_index++] = s   + mNumS*(t+1);		//top left
-			mIndices[cur_index++] = s   + mNumS*t;			//bottom left
-			mIndices[cur_index++] = s+1 + mNumS*t;			//bottom right
-			mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
-
-			mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;						//bottom left/top right neighbor face 
-			if (t < mNumT-2) {												//top right/top left neighbor face 
-				mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
-			}
-			else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
-				mEdge[cur_edge++] = -1;
-			}
-			else { //wrap on T
-				mEdge[cur_edge++] = s*2+1;
-			}
-			if (s > 0) {													//top left/bottom left neighbor face
-				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
-			}
-			else if (flat_face ||  mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
-				mEdge[cur_edge++] = -1;
-			}
-			else {	//wrap on S
-				mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
-			}
-			
-			if (t > 0) {													//bottom left/bottom right neighbor face
-				mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
-			}
-			else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
-				mEdge[cur_edge++] = -1;
-			}
-			else { //wrap on T
-				mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
-			}
-			if (s < mNumS-2) {												//bottom right/top right neighbor face
-				mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
-			}
-			else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
-				mEdge[cur_edge++] = -1;
-			}
-			else { //wrap on S
-				mEdge[cur_edge++] = (mNumS-1)*2*t;
+	if (!partial_build)
+	{
+		// Now we generate the indices.
+		for (t = 0; t < (mNumT-1); t++)
+		{
+			for (s = 0; s < (mNumS-1); s++)
+			{	
+				mIndices[cur_index++] = s   + mNumS*t;			//bottom left
+				mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
+				mIndices[cur_index++] = s   + mNumS*(t+1);		//top left
+				mIndices[cur_index++] = s   + mNumS*t;			//bottom left
+				mIndices[cur_index++] = s+1 + mNumS*t;			//bottom right
+				mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
+
+				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;						//bottom left/top right neighbor face 
+				if (t < mNumT-2) {												//top right/top left neighbor face 
+					mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
+				}
+				else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
+					mEdge[cur_edge++] = -1;
+				}
+				else { //wrap on T
+					mEdge[cur_edge++] = s*2+1;
+				}
+				if (s > 0) {													//top left/bottom left neighbor face
+					mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
+				}
+				else if (flat_face ||  mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
+					mEdge[cur_edge++] = -1;
+				}
+				else {	//wrap on S
+					mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
+				}
+				
+				if (t > 0) {													//bottom left/bottom right neighbor face
+					mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
+				}
+				else if (mNumT <= 3 || mVolumep->getPath().isOpen() == TRUE) { //no neighbor
+					mEdge[cur_edge++] = -1;
+				}
+				else { //wrap on T
+					mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
+				}
+				if (s < mNumS-2) {												//bottom right/top right neighbor face
+					mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
+				}
+				else if (flat_face || mVolumep->getProfile().isOpen() == TRUE) { //no neighbor
+					mEdge[cur_edge++] = -1;
+				}
+				else { //wrap on S
+					mEdge[cur_edge++] = (mNumS-1)*2*t;
+				}
+				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;							//top right/bottom left neighbor face	
 			}
-            mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;							//top right/bottom left neighbor face	
 		}
 	}
 
-
 	//generate normals
 	for (U32 i = 0; i < mIndices.size()/3; i++) {	//for each triangle
 		const VertexData& v0 = mVertices[mIndices[i*3+0]];
@@ -4674,27 +4763,22 @@ BOOL LLVolumeFace::createSide()
 		LLVector3 norm = (v0.mPosition-v1.mPosition)%
 						(v0.mPosition-v2.mPosition);
 
-		//calculate binormal
-		LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
-														v1.mPosition, v1.mTexCoord,
-														v2.mPosition, v2.mTexCoord);
-
-		for (U32 j = 0; j < 3; j++) { //add triangle normal to vertices
+		for (U32 j = 0; j < 3; j++) 
+		{ //add triangle normal to vertices
 			mVertices[mIndices[i*3+j]].mNormal += norm; // * (weight_sum - d[j])/weight_sum;
-			mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
 		}
 
 		//even out quad contributions
-		if (i % 2 == 0) {
+		if (i % 2 == 0) 
+		{
 			mVertices[mIndices[i*3+2]].mNormal += norm;
-			mVertices[mIndices[i*3+2]].mBinormal += binorm;
 		}
-		else {
+		else 
+		{
 			mVertices[mIndices[i*3+1]].mNormal += norm;
-			mVertices[mIndices[i*3+1]].mBinormal += binorm;
 		}
 	}
-
+	
 	// adjust normals based on wrapping and stitching
 	
 	BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
@@ -4820,15 +4904,6 @@ BOOL LLVolumeFace::createSide()
 
 	}
 
-
-	//normalize normals and binormals here so the meshes that reference
-	//this volume data don't have to
-	for (U32 i = 0; i < mVertices.size(); i++) 
-	{
-		mVertices[i].mNormal.normVec();
-		mVertices[i].mBinormal.normVec();
-	}
-
 	return TRUE;
 }
 
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 3dadc56261c..3e619479478 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -762,7 +762,8 @@ class LLVolumeFace
 {
 public:
 	LLVolumeFace();
-	BOOL create();
+	BOOL create(BOOL partial_build = FALSE);
+	void createBinormals();
 
 	class VertexData
 	{
@@ -792,6 +793,7 @@ class LLVolumeFace
 	S32 mID;
 	U32 mTypeMask;
 	LLVector3 mCenter;
+	BOOL mHasBinormals;
 
 	// Only used for INNER/OUTER faces
 	S32 mBeginS;
@@ -802,7 +804,7 @@ class LLVolumeFace
 	LLVector3 mExtents[2]; //minimum and maximum point of face
 
 	std::vector<VertexData> mVertices;
-	std::vector<S32>	mIndices;
+	std::vector<U16>	mIndices;
 	std::vector<S32>	mEdge;
 	LLVolume *mVolumep; // Deliberately NOT reference counted - djs 11/20/03 - otherwise would make an annoying circular reference
 
@@ -811,9 +813,9 @@ class LLVolumeFace
 							 LLStrider<LLColor4U> &new_colors, const S32 num_new, const LLVolumeFace &new_face);
 	
 protected:
-	BOOL createUnCutCubeCap();
-	BOOL createCap();
-	BOOL createSide();
+	BOOL createUnCutCubeCap(BOOL partial_build = FALSE);
+	BOOL createCap(BOOL partial_build = FALSE);
+	BOOL createSide(BOOL partial_build = FALSE);
 };
 
 class LLVolume : public LLRefCount
@@ -850,12 +852,14 @@ class LLVolume : public LLRefCount
 	LLVolumeParams getCopyOfParams() const					{ return mParams; }
 	const LLProfile& getProfile() const						{ return *mProfilep; }
 	LLPath& getPath() const									{ return *mPathp; }
+	void resizePath(S32 length);
 	const std::vector<Point>& getMesh() const				{ return mMesh; }
 	const LLVector3& getMeshPt(const U32 i) const			{ return mMesh[i].mPos; }
 
 	void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
 
 	void regen();
+	void genBinormals(S32 face);
 
 	BOOL isConvex() const;
 	BOOL isCap(S32 face);
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index eae6ab7f4a2..945d74f7c12 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -283,6 +283,29 @@ S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
 	return NUM_LODS - 1;
 }
 
+void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher)
+{
+	S32 detail = getDetailFromTan(tan_angle);
+	
+	if (detail > 0)
+	{
+		to_lower = tan_angle - mDetailThresholds[detail];
+	}
+	else
+	{
+		to_lower = 1024.f*1024.f;
+	}
+
+	if (detail < NUM_LODS-1)
+	{
+		to_higher = mDetailThresholds[detail+1] - tan_angle;
+	}
+	else
+	{
+		to_higher = 1024.f*1024.f;
+	}
+}
+
 F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
 {
 	return mDetailScales[detail];
diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h
index 7aa0a3f3bf3..3d7b6636701 100644
--- a/indra/llmath/llvolumemgr.h
+++ b/indra/llmath/llvolumemgr.h
@@ -56,6 +56,7 @@ class LLVolumeLODGroup : public LLThreadSafeRefCount
 
 	BOOL derefLOD(LLVolume *volumep);
 	static S32 getDetailFromTan(const F32 tan_angle);
+	static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher);
 	static F32 getVolumeScaleFromDetail(const S32 detail);
 
 	LLVolume *getLOD(const S32 detail);
diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp
index 462075c7631..8a49be5615b 100644
--- a/indra/llmath/v3color.cpp
+++ b/indra/llmath/v3color.cpp
@@ -33,6 +33,7 @@
 
 #include "v3color.h"
 #include "v4color.h"
+#include "v4math.h"
 
 LLColor3 LLColor3::white(1.0f, 1.0f, 1.0f);
 LLColor3 LLColor3::black(0.0f, 0.0f, 0.0f);
@@ -45,6 +46,13 @@ LLColor3::LLColor3(const LLColor4 &a)
 	mV[2] = a.mV[2];
 }
 
+LLColor3::LLColor3(const LLVector4 &a)
+{
+	mV[0] = a.mV[0];
+	mV[1] = a.mV[1];
+	mV[2] = a.mV[2];
+}
+
 LLColor3::LLColor3(const LLSD &sd)
 {
 	mV[0] = (F32) sd[0].asReal();
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index d09af7a8c47..56820148d5a 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -33,6 +33,7 @@
 #define LL_V3COLOR_H
 
 class LLColor4;
+class LLVector4;
 
 #include "llerror.h"
 #include "llmath.h"
@@ -57,6 +58,7 @@ class LLColor3
 	LLColor3(const F32 *vec);			// Initializes LLColor3 to (vec[0]. vec[1], vec[2])
 	LLColor3(char *color_string);       // html format color ie "#FFDDEE"
 	explicit LLColor3(const LLColor4& color4);  // "explicit" to avoid automatic conversion
+	explicit LLColor3(const LLVector4& vector4);  // "explicit" to avoid automatic conversion
 	LLColor3(const LLSD& sd);
 	
 
@@ -87,6 +89,7 @@ class LLColor3
 	F32		magVec() const;				// Returns magnitude of LLColor3
 	F32		magVecSquared() const;		// Returns magnitude squared of LLColor3
 	F32		normVec();					// Normalizes and returns the magnitude of LLColor3
+	F32		brightness() const;			// Returns brightness of LLColor3
 
 	const LLColor3&	operator=(const LLColor4 &a);
 	
@@ -98,7 +101,7 @@ class LLColor3
 	friend const LLColor3& operator-=(LLColor3 &a, const LLColor3 &b);	// Return vector a minus b
 	friend const LLColor3& operator*=(LLColor3 &a, const LLColor3 &b);
 
-	friend LLColor3 operator*(const LLColor3 &a, const LLColor3 &b);		// Return a dot b
+	friend LLColor3 operator*(const LLColor3 &a, const LLColor3 &b);	// Return component wise a * b
 	friend LLColor3 operator*(const LLColor3 &a, F32 k);				// Return a times scaler k
 	friend LLColor3 operator*(F32 k, const LLColor3 &a);				// Return a times scaler k
 
@@ -231,6 +234,11 @@ inline const LLColor3&	LLColor3::setVec(const F32 *vec)
 	return (*this);
 }
 
+inline F32		LLColor3::brightness(void) const
+{
+	return (mV[0] + mV[1] + mV[2]) / 3.0f;
+}
+
 inline F32		LLColor3::magVec(void) const
 {
 	return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp
index 4ce8e10527e..21166472e4b 100644
--- a/indra/llmath/v4color.cpp
+++ b/indra/llmath/v4color.cpp
@@ -36,7 +36,7 @@
 #include "v4color.h"
 #include "v4coloru.h"
 #include "v3color.h"
-//#include "vmath.h"
+#include "v4math.h"
 #include "llmath.h"
 
 // LLColor4
@@ -153,6 +153,14 @@ LLColor4::LLColor4(const LLColor4U& color4u)
 	mV[VW] = color4u.mV[VW] * SCALE;
 }
 
+LLColor4::LLColor4(const LLVector4& vector4)
+{
+	mV[VX] = vector4.mV[VX];
+	mV[VY] = vector4.mV[VY];
+	mV[VZ] = vector4.mV[VZ];
+	mV[VW] = vector4.mV[VW];
+}
+
 const LLColor4&	LLColor4::setVec(const LLColor4U& color4u)
 {
 	const F32 SCALE = 1.f/255.f;
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index 0514870ef66..bd990444b5e 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -39,6 +39,7 @@
 
 class LLColor3;
 class LLColor4U;
+class LLVector4;
 
 //  LLColor4 = |x y z w|
 
@@ -58,6 +59,7 @@ class LLColor4
 		LLColor4(const LLColor3 &vec, F32 a = 1.f);	// Initializes LLColor4 to (vec, a)
 		LLColor4(const LLSD& sd);
 		explicit LLColor4(const LLColor4U& color4u);  // "explicit" to avoid automatic conversion
+		explicit LLColor4(const LLVector4& vector4);  // "explicit" to avoid automatic conversion
 
 		LLSD getValue() const
 		{
@@ -107,7 +109,7 @@ class LLColor4
 		friend std::ostream&	 operator<<(std::ostream& s, const LLColor4 &a);		// Print a
 		friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b);	// Return vector a + b
 		friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b);	// Return vector a minus b
-		friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b);	// Return a * b
+		friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b);	// Return component wise a * b
 		friend LLColor4 operator*(const LLColor4 &a, F32 k);				// Return rgb times scaler k (no alpha change)
 		friend LLColor4 operator*(F32 k, const LLColor4 &a);				// Return rgb times scaler k (no alpha change)
 		friend LLColor4 operator%(const LLColor4 &a, F32 k);				// Return alpha times scaler k (no rgb change)
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index 57dcad35fe2..34b5f9e33c1 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -312,7 +312,8 @@ inline bool operator!=(const LLVector4 &a, const LLVector4 &b)
 {
 	return (  (a.mV[VX] != b.mV[VX])
 			||(a.mV[VY] != b.mV[VY])
-			||(a.mV[VZ] != b.mV[VZ]));
+			||(a.mV[VZ] != b.mV[VZ])
+			||(a.mV[VW] != b.mV[VW]) );
 }
 
 inline const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b)
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index e6eee9bf132..837f8ef361c 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -389,4 +389,3 @@ S32 LLTextureEntry::setGlow(F32 glow)
 	}
 	return 0;
 }
-
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index dd67dbc3791..2e767ebb9c1 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -36,6 +36,7 @@
 #include "llfont.h"
 #include "llfontgl.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v4color.h"
 #include "llstl.h"
 
@@ -556,8 +557,8 @@ S32 LLFontGL::render(const LLWString &wstr,
 					 BOOL use_embedded,
 					 BOOL use_ellipses) const
 {
-	LLGLEnable texture_2d(GL_TEXTURE_2D);
-	
+	LLGLEnable tex(GL_TEXTURE_2D);
+
 	if (wstr.empty())
 	{
 		return 0;
@@ -593,9 +594,9 @@ S32 LLFontGL::render(const LLWString &wstr,
 		}
 	}
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
-	glTranslatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
+	gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
 	//glScalef(sScaleX, sScaleY, 1.0f);
 	
 	// avoid half pixels
@@ -604,20 +605,20 @@ S32 LLFontGL::render(const LLWString &wstr,
 	//F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
 	//if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
 	//{
-		glTranslatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
+		gGL.translatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
 	//}
 
 	// this code would just snap to pixel grid, although it seems to introduce more jitter
 	//F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
 	//F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
-	//glTranslatef(-pixel_offset_x, -pixel_offset_y, 0.f);
+	//gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);
 
 	// scale back to native pixel size
 	//glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
 	//glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
 	LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);
 
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 
 	S32 chars_drawn = 0;
 	S32 i;
@@ -638,7 +639,7 @@ S32 LLFontGL::render(const LLWString &wstr,
 	
 	mImageGLp->bind(0);
 	
- 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
+ 	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
 	
 	cur_x = ((F32)x * sScaleX);
 	cur_y = ((F32)y * sScaleY);
@@ -743,9 +744,9 @@ S32 LLFontGL::render(const LLWString &wstr,
 
 			if (!label.empty())
 			{
-				glPushMatrix();
+				gGL.pushMatrix();
 				//glLoadIdentity();
-				//glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
+				//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
 				//glScalef(sScaleX, sScaleY, 1.f);
 				gExtCharFont->render(label, 0,
 									 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
@@ -753,10 +754,10 @@ S32 LLFontGL::render(const LLWString &wstr,
 									 color,
 									 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
 									 TRUE );
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 
-			glColor4fv(color.mV);
+			gGL.color4fv(color.mV);
 
 			chars_drawn++;
 			cur_x += ext_advance;
@@ -836,10 +837,10 @@ S32 LLFontGL::render(const LLWString &wstr,
 	if (style & UNDERLINE)
 	{
 		LLGLSNoTexture no_texture;
-		glBegin(GL_LINES);
-		glVertex2f(start_x, cur_y - (mDescender));
-		glVertex2f(cur_x, cur_y - (mDescender));
-		glEnd();
+		gGL.begin(GL_LINES);
+		gGL.vertex2f(start_x, cur_y - (mDescender));
+		gGL.vertex2f(cur_x, cur_y - (mDescender));
+		gGL.end();
 	}
 
 	// *FIX: get this working in all alignment cases, etc.
@@ -847,9 +848,9 @@ S32 LLFontGL::render(const LLWString &wstr,
 	{
 		// recursively render ellipses at end of string
 		// we've already reserved enough room
-		glPushMatrix();
+		gGL.pushMatrix();
 		//glLoadIdentity();
-		//glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
+		//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
 		//glScalef(sScaleX, sScaleY, 1.f);
 		renderUTF8("...", 
 				0,
@@ -860,10 +861,10 @@ S32 LLFontGL::render(const LLWString &wstr,
 				S32_MAX, max_pixels,
 				right_x,
 				FALSE); 
-		glPopMatrix();
+		gGL.popMatrix();
 	}
 
-	glPopMatrix();
+	gGL.popMatrix();
 
 	return chars_drawn;
 }
@@ -1309,20 +1310,20 @@ void LLFontGL::removeEmbeddedChar( llwchar wc )
 
 void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
 {
-	glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
-	glVertex2f(llfont_round_x(screen_rect.mRight), 
+	gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+	gGL.vertex2f(llfont_round_x(screen_rect.mRight), 
 				llfont_round_y(screen_rect.mTop));
 
-	glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
-	glVertex2f(llfont_round_x(screen_rect.mLeft), 
+	gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+	gGL.vertex2f(llfont_round_x(screen_rect.mLeft), 
 				llfont_round_y(screen_rect.mTop));
 
-	glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-	glVertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
+	gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+	gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
 				llfont_round_y(screen_rect.mBottom));
 
-	glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
-	glVertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
+	gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+	gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
 				llfont_round_y(screen_rect.mBottom));
 }
 
@@ -1331,13 +1332,13 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
 	F32 slant_offset;
 	slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
 		//FIXME: bold and drop shadow are mutually exclusive only for convenience
 		//Allow both when we need them.
 		if (style & BOLD)
 		{
-			glColor4fv(color.mV);
+			gGL.color4fv(color.mV);
 			for (S32 pass = 0; pass < 2; pass++)
 			{
 				LLRectf screen_rect_offset = screen_rect;
@@ -1350,7 +1351,7 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
 		{
 			LLColor4 shadow_color = LLFontGL::sShadowColor;
 			shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
-			glColor4fv(shadow_color.mV);
+			gGL.color4fv(shadow_color.mV);
 			for (S32 pass = 0; pass < 5; pass++)
 			{
 				LLRectf screen_rect_offset = screen_rect;
@@ -1376,28 +1377,28 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
 			
 				renderQuad(screen_rect_offset, uv_rect, slant_offset);
 			}
-			glColor4fv(color.mV);
+			gGL.color4fv(color.mV);
 			renderQuad(screen_rect, uv_rect, slant_offset);
 		}
 		else if (style & DROP_SHADOW)
 		{
 			LLColor4 shadow_color = LLFontGL::sShadowColor;
 			shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
-			glColor4fv(shadow_color.mV);
+			gGL.color4fv(shadow_color.mV);
 			LLRectf screen_rect_shadow = screen_rect;
 			screen_rect_shadow.translate(1.f, -1.f);
 			renderQuad(screen_rect_shadow, uv_rect, slant_offset);
-			glColor4fv(color.mV);
+			gGL.color4fv(color.mV);
 			renderQuad(screen_rect, uv_rect, slant_offset);
 		}
 		else // normal rendering
 		{
-			glColor4fv(color.mV);
+			gGL.color4fv(color.mV);
 			renderQuad(screen_rect, uv_rect, slant_offset);
 		}
 
 	}
-	glEnd();
+	gGL.end();
 }
 
 // static
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 748e405065d..2a8424a09b4 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,8 @@
 
 #include "llmath.h"
 #include "llgl.h"
+#include "llglimmediate.h"
+
 
 //----------------------------------------------------------------------------
 
@@ -49,6 +51,8 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;
 //statics
 LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
 
+U32 LLImageGL::sUniqueCount				= 0;
+U32 LLImageGL::sBindCount				= 0;
 S32 LLImageGL::sGlobalTextureMemory		= 0;
 S32 LLImageGL::sBoundTextureMemory		= 0;
 S32 LLImageGL::sCurBoundTextureMemory	= 0;
@@ -123,6 +127,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 // static
 void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target )
 {
+	gGL.flush();
 	glActiveTextureARB(GL_TEXTURE0_ARB + stage);
 	glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
 	glBindTexture(bind_target, gl_name);
@@ -135,6 +140,7 @@ void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
 	// LLGLSLShader can return -1
 	if (stage >= 0)
 	{
+		gGL.flush();
 		glActiveTextureARB(GL_TEXTURE0_ARB + stage);
 		glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
 		glBindTexture(bind_target, 0);
@@ -148,6 +154,7 @@ void LLImageGL::unbindTexture(S32 stage)
 	// LLGLSLShader can return -1
 	if (stage >= 0)
 	{
+		gGL.flush();
 		glActiveTextureARB(GL_TEXTURE0_ARB + stage);
 		glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
 		glBindTexture(GL_TEXTURE_2D, 0);
@@ -411,6 +418,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 		llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
 	}
 
+
 	glActiveTextureARB(GL_TEXTURE0_ARB + stage);
 		
 	if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName)
@@ -425,12 +433,15 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 		mMissed = ! getIsResident(TRUE);
 #endif
 
+		gGL.flush();
 		glBindTexture(mBindTarget, mTexName);
 		sCurrentBoundTextures[stage] = mTexName;
+		sBindCount++;
 
 		if (mLastBindTime != sLastFrameTime)
 		{
 			// we haven't accounted for this texture yet this frame
+			sUniqueCount++;
 			updateBoundTexMem(mTextureMemory);
 			mLastBindTime = sLastFrameTime;
 		}
@@ -439,6 +450,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 	}
 	else
 	{
+		gGL.flush();
 		glBindTexture(mBindTarget, 0);
 		sCurrentBoundTextures[stage] = 0;
 		return FALSE;
@@ -665,7 +677,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		}
 		mHasMipMaps = FALSE;
 	}
-	glFlush();
 	stop_glerror();
 }
 
@@ -759,7 +770,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 		glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 		stop_glerror();
 	}
-	glFlush();
+	
 	return TRUE;
 }
 
@@ -1046,6 +1057,7 @@ void LLImageGL::destroyGLTexture()
 			{
 				unbindTexture(i, GL_TEXTURE_2D);
 				stop_glerror();
+				glActiveTextureARB(GL_TEXTURE0_ARB);
 			}
 		}
 
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index cbfa3c22028..20cf4ae10f0 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -185,7 +185,8 @@ class LLImageGL : public LLRefCount
 	static S32 sGlobalTextureMemory;		// Tracks main memory texmem
 	static S32 sBoundTextureMemory;			// Tracks bound texmem for last completed frame
 	static S32 sCurBoundTextureMemory;		// Tracks bound texmem for current frame
-
+	static U32 sBindCount;					// Tracks number of texture binds for current frame
+	static U32 sUniqueCount;				// Tracks number of unique texture binds for current frame
 	static BOOL sGlobalUseAnisotropic;
 
 #if DEBUG_MISS
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
new file mode 100644
index 00000000000..c082b931641
--- /dev/null
+++ b/indra/llrender/llrendertarget.cpp
@@ -0,0 +1,185 @@
+/** 
+ * @file llrendertarget.cpp
+ * @brief LLRenderTarget implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llrendertarget.h"
+#include "llglimmediate.h"
+
+
+BOOL LLRenderTarget::sUseFBO = FALSE;
+
+LLRenderTarget::LLRenderTarget()
+{
+	mResX = mResY = mTex = mFBO = mDepth = 0;
+	mUseDepth = FALSE;
+	mUsage = GL_TEXTURE_2D;
+}
+
+LLRenderTarget::~LLRenderTarget()
+{
+	release();
+}
+
+void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, U32 usage, BOOL force_fbo)
+{
+	mResX = resx;
+	mResY = resy;
+
+	mUsage = usage;
+	mUseDepth = depth;
+	release();
+
+	glGenTextures(1, (GLuint *) &mTex);
+	glBindTexture(mUsage, mTex);
+	glTexImage2D(mUsage, 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL);
+
+	glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+	if (mUsage != GL_TEXTURE_RECTANGLE_ARB)
+	{
+		glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+		glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	}
+	else
+	{
+		// ATI doesn't support mirrored repeat for rectangular textures.
+		glTexParameteri(mUsage, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(mUsage, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	}
+
+	stop_glerror();
+
+	if (sUseFBO || force_fbo)
+	{
+		if (depth)
+		{
+			glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
+			glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
+			glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,mResX,mResY);
+			glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);	
+		}
+
+		glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+
+		if (mDepth)
+		{
+			glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+											GL_RENDERBUFFER_EXT, mDepth);	
+		}
+		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+						mUsage, mTex, 0);
+
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	}
+}
+
+void LLRenderTarget::release()
+{
+	if (mFBO)
+	{
+		glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
+		mFBO = 0;
+	}
+
+	if (mTex)
+	{
+		glDeleteTextures(1, (GLuint *) &mTex);
+		mTex = 0;
+	}
+
+	if (mDepth)
+	{
+		glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
+		mDepth = 0;
+	}
+}
+
+void LLRenderTarget::bindTarget()
+{
+	if (mFBO)
+	{
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+	}
+
+	glViewport(0, 0, mResX, mResY);
+}
+
+void LLRenderTarget::clear()
+{
+	U32 mask = GL_COLOR_BUFFER_BIT;
+	if (mUseDepth)
+	{
+		mask |= GL_DEPTH_BUFFER_BIT;
+	}
+	if (mFBO)
+	{
+		glClear(mask);
+	}
+	else
+	{
+		LLGLEnable scissor(GL_SCISSOR_TEST);
+		glScissor(0, 0, mResX, mResY);
+		glClear(mask);
+	}
+}
+
+void LLRenderTarget::bindTexture()
+{
+	glBindTexture(mUsage, mTex);
+}
+
+void LLRenderTarget::flush()
+{
+	gGL.flush();
+	if (!mFBO)
+	{
+		bindTexture();
+		glCopyTexSubImage2D(mUsage, 0, 0, 0, 0, 0, mResX, mResY);
+	}
+}
+
+BOOL LLRenderTarget::isComplete() const
+{
+	return (mTex || mDepth) ? TRUE : FALSE;
+}
+
+void LLRenderTarget::getViewport(S32* viewport)
+{
+	viewport[0] = 0;
+	viewport[1] = 0;
+	viewport[2] = mResX;
+	viewport[3] = mResY;
+}
+
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
new file mode 100644
index 00000000000..0c0eab2b100
--- /dev/null
+++ b/indra/llrender/llrendertarget.h
@@ -0,0 +1,116 @@
+/** 
+ * @file llrendertarget.h
+ * @brief Off screen render target abstraction.  Loose wrapper for GL_EXT_framebuffer_objects.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLRENDERTARGET_H
+#define LL_LLRENDERTARGET_H
+
+#include "llgl.h"
+
+/*
+ SAMPLE USAGE:
+
+	LLFBOTarget target;
+
+	...
+
+	//allocate a 256x256 RGBA render target with depth buffer
+	target.allocate(256,256,GL_RGBA,TRUE);
+
+	//render to contents of offscreen buffer
+	target.bindTarget();
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	... <issue drawing commands> ...
+	target.flush();
+
+	...
+
+	//use target as a texture
+	target.bindTexture();
+	... <issue drawing commands> ...
+
+*/
+
+
+class LLRenderTarget
+{
+public:
+	//whether or not to use FBO implementation
+	static BOOL sUseFBO; 
+
+	LLRenderTarget();
+	~LLRenderTarget();
+
+	//allocate resources for rendering
+	//must be called before use
+	//multiple calls will release previously allocated resources
+	void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, U32 usage = GL_TEXTURE_2D, BOOL force_fbo = FALSE);
+
+	//free any allocated resources
+	//safe to call redundantly
+	void release();
+
+	//bind target for rendering
+	//applies appropriate viewport
+	void bindTarget();
+
+	//clear render targer, clears depth buffer if present,
+	//uses scissor rect if in copy-to-texture mode
+	void clear();
+	
+	//get applied viewport
+	void getViewport(S32* viewport);
+
+	//bind results of render for sampling
+	void bindTexture();
+
+	//flush rendering operations
+	//must be called when rendering is complete
+	//should be used 1:1 with bindTarget 
+	// call bindTarget once, do all your rendering, call flush once
+	void flush();
+
+	//Returns TRUE if target is ready to be rendered into.
+	//That is, if the target has been allocated with at least
+	//one renderable attachment (i.e. color buffer, depth buffer).
+	BOOL isComplete() const;
+
+private:
+	U32 mResX;
+	U32 mResY;
+	U32 mTex;
+	U32 mFBO;
+	U32 mDepth;
+	BOOL mUseDepth;
+	U32 mUsage;
+};
+
+#endif
+
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 2a54fca2509..9303e00228b 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -31,6 +31,8 @@
 
 #include "linden_common.h"
 
+#include <boost/static_assert.hpp>
+
 #include "llvertexbuffer.h"
 // #include "llrender.h"
 #include "llglheaders.h"
@@ -40,8 +42,16 @@
 //============================================================================
 
 //static
+LLVBOPool LLVertexBuffer::sStreamVBOPool;
+LLVBOPool LLVertexBuffer::sDynamicVBOPool;
+LLVBOPool LLVertexBuffer::sStreamIBOPool;
+LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+
+U32 LLVertexBuffer::sBindCount = 0;
+U32 LLVertexBuffer::sSetCount = 0;
 S32 LLVertexBuffer::sCount = 0;
 S32 LLVertexBuffer::sGLCount = 0;
+S32 LLVertexBuffer::sMappedCount = 0;
 BOOL LLVertexBuffer::sEnableVBOs = TRUE;
 U32 LLVertexBuffer::sGLRenderBuffer = 0;
 U32 LLVertexBuffer::sGLRenderIndices = 0;
@@ -50,9 +60,9 @@ BOOL LLVertexBuffer::sVBOActive = FALSE;
 BOOL LLVertexBuffer::sIBOActive = FALSE;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
 BOOL LLVertexBuffer::sRenderActive = FALSE;
+BOOL LLVertexBuffer::sMapped = FALSE;
 
 std::vector<U32> LLVertexBuffer::sDeleteList;
-LLVertexBuffer::buffer_list_t LLVertexBuffer::sLockedList;
 
 S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
 {
@@ -70,6 +80,10 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
 void LLVertexBuffer::initClass(bool use_vbo)
 {
 	sEnableVBOs = use_vbo;
+	LLGLNamePool::registerPool(&sDynamicVBOPool);
+	LLGLNamePool::registerPool(&sDynamicIBOPool);
+	LLGLNamePool::registerPool(&sStreamVBOPool);
+	LLGLNamePool::registerPool(&sStreamIBOPool);
 }
 
 //static 
@@ -88,13 +102,13 @@ void LLVertexBuffer::unbind()
 
 	sGLRenderBuffer = 0;
 	sGLRenderIndices = 0;
+	sLastMask = 0;
 }
 
 //static
 void LLVertexBuffer::cleanupClass()
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
-	sLockedList.clear();
 	startRender(); 
 	stopRender();
 	clientCopy(); // deletes GL buffers
@@ -127,41 +141,8 @@ void LLVertexBuffer::clientCopy(F64 max_time)
 {
 	if (!sDeleteList.empty())
 	{
-		size_t num = sDeleteList.size();
 		glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
 		sDeleteList.clear();
-		sGLCount -= num;
-	}
-
-	if (sEnableVBOs)
-	{
-		LLTimer timer;
-		BOOL reset = TRUE;
-		buffer_list_t::iterator iter = sLockedList.begin();
-		while(iter != sLockedList.end())
-		{
-			LLVertexBuffer* buffer = *iter;
-			if (buffer->isLocked() && buffer->useVBOs())
-			{
-				buffer->setBuffer(0);
-			}
-			++iter;
-			if (reset)
-			{
-				reset = FALSE;
-				timer.reset(); //skip first copy (don't count pipeline stall)
-			}
-			else
-			{
-				if (timer.getElapsedTimeF64() > max_time)
-				{
-					break;
-				}
-			}
-
-		}
-
-		sLockedList.erase(sLockedList.begin(), iter);
 	}
 }
 
@@ -175,27 +156,40 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	mFinal(FALSE),
 	mFilthy(FALSE),
 	mEmpty(TRUE),
-	mResized(FALSE)
+	mResized(FALSE),
+	mDynamicSize(FALSE)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
 	if (!sEnableVBOs)
 	{
-		mUsage = GL_STREAM_DRAW_ARB;
+		mUsage = 0 ; 
 	}
 	
+	S32 stride = calcStride(typemask, mOffsets);
+
+	mTypeMask = typemask;
+	mStride = stride;
+	sCount++;
+}
+
+//static
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
+{
 	S32 stride = 0;
 	for (S32 i=0; i<TYPE_MAX; i++)
 	{
 		U32 mask = 1<<i;
 		if (typemask & mask)
 		{
-			mOffsets[i] = stride;
+			if (offsets)
+			{
+				offsets[i] = stride;
+			}
 			stride += sTypeOffsets[i];
 		}
 	}
-	mTypeMask = typemask;
-	mStride = stride;
-	sCount++;
+
+	return stride;
 }
 
 // protected, use unref()
@@ -206,23 +200,80 @@ LLVertexBuffer::~LLVertexBuffer()
 	destroyGLBuffer();
 	destroyGLIndices();
 	sCount--;
-	
-	if (mLocked)
-	{
-		//pull off of locked list
-		for (buffer_list_t::iterator i = sLockedList.begin(); i != sLockedList.end(); ++i)
-		{
-			if (*i == this)
-			{
-				sLockedList.erase(i);
-				break;
-			}
-		}
-	}
 };
 
 //----------------------------------------------------------------------------
 
+void LLVertexBuffer::genBuffer()
+{
+	if (mUsage == GL_STREAM_DRAW_ARB)
+	{
+		mGLBuffer = sStreamVBOPool.allocate();
+	}
+	else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+	{
+		mGLBuffer = sDynamicVBOPool.allocate();
+	}
+	else
+	{
+		BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
+		glGenBuffersARB(1, (GLuint*)&mGLBuffer);
+	}
+	sGLCount++;
+}
+
+void LLVertexBuffer::genIndices()
+{
+	if (mUsage == GL_STREAM_DRAW_ARB)
+	{
+		mGLIndices = sStreamIBOPool.allocate();
+	}
+	else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+	{
+		mGLIndices = sDynamicIBOPool.allocate();
+	}
+	else
+	{
+		BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
+		glGenBuffersARB(1, (GLuint*)&mGLIndices);
+	}
+	sGLCount++;
+}
+
+void LLVertexBuffer::releaseBuffer()
+{
+	if (mUsage == GL_STREAM_DRAW_ARB)
+	{
+		sStreamVBOPool.release(mGLBuffer);
+	}
+	else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+	{
+		sDynamicVBOPool.release(mGLBuffer);
+	}
+	else
+	{
+		sDeleteList.push_back(mGLBuffer);
+	}
+	sGLCount--;
+}
+
+void LLVertexBuffer::releaseIndices()
+{
+	if (mUsage == GL_STREAM_DRAW_ARB)
+	{
+		sStreamIBOPool.release(mGLIndices);
+	}
+	else if (mUsage == GL_DYNAMIC_DRAW_ARB)
+	{
+		sDynamicIBOPool.release(mGLIndices);
+	}
+	else
+	{
+		sDeleteList.push_back(mGLIndices);
+	}
+	sGLCount--;
+}
+
 void LLVertexBuffer::createGLBuffer()
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
@@ -238,20 +289,20 @@ void LLVertexBuffer::createGLBuffer()
 		return;
 	}
 
-	mMappedData = new U8[size];
-	memset(mMappedData, 0, size);
 	mEmpty = TRUE;
 
 	if (useVBOs())
 	{
-		glGenBuffersARB(1, (GLuint*) &mGLBuffer);
+		mMappedData = NULL;
+		genBuffer();
 		mResized = TRUE;
-		sGLCount++;
 	}
 	else
 	{
 		static int gl_buffer_idx = 0;
 		mGLBuffer = ++gl_buffer_idx;
+		mMappedData = new U8[size];
+		memset(mMappedData, 0, size);
 	}
 }
 
@@ -270,18 +321,18 @@ void LLVertexBuffer::createGLIndices()
 		return;
 	}
 
-	mMappedIndexData = new U8[size];
-	memset(mMappedIndexData, 0, size);
 	mEmpty = TRUE;
 
 	if (useVBOs())
 	{
-		glGenBuffersARB(1, (GLuint*) &mGLIndices);
+		mMappedIndexData = NULL;
+		genIndices();
 		mResized = TRUE;
-		sGLCount++;
 	}
 	else
 	{
+		mMappedIndexData = new U8[size];
+		memset(mMappedIndexData, 0, size);
 		static int gl_buffer_idx = 0;
 		mGLIndices = ++gl_buffer_idx;
 	}
@@ -294,12 +345,19 @@ void LLVertexBuffer::destroyGLBuffer()
 	{
 		if (useVBOs())
 		{
-			sDeleteList.push_back(mGLBuffer);
+			if (mMappedData || mMappedIndexData)
+			{
+				llerrs << "Vertex buffer destroyed while mapped!" << llendl;
+			}
+			releaseBuffer();
+		}
+		else
+		{
+			delete [] mMappedData;
+			mMappedData = NULL;
+			mEmpty = TRUE;
 		}
-		
-		delete [] mMappedData;
-		mMappedData = NULL;
-		mEmpty = TRUE;
+
 		sAllocatedBytes -= getSize();
 	}
 	
@@ -313,12 +371,19 @@ void LLVertexBuffer::destroyGLIndices()
 	{
 		if (useVBOs())
 		{
-			sDeleteList.push_back(mGLIndices);
+			if (mMappedData || mMappedIndexData)
+			{
+				llerrs << "Vertex buffer destroyed while mapped." << llendl;
+			}
+			releaseIndices();
+		}
+		else
+		{
+			delete [] mMappedIndexData;
+			mMappedIndexData = NULL;
+			mEmpty = TRUE;
 		}
-		
-		delete [] mMappedIndexData;
-		mMappedIndexData = NULL;
-		mEmpty = TRUE;
+
 		sAllocatedBytes -= getIndicesSize();
 	}
 
@@ -328,6 +393,15 @@ void LLVertexBuffer::destroyGLIndices()
 void LLVertexBuffer::updateNumVerts(S32 nverts)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
+
+	if (nverts >= 65535)
+	{
+		llwarns << "Vertex buffer overflow!" << llendl;
+		nverts = 65535;
+	}
+
+	mRequestedNumVerts = nverts;
+	
 	if (!mDynamicSize)
 	{
 		mNumVerts = nverts;
@@ -336,18 +410,19 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
 		nverts > mNumVerts ||
 		nverts < mNumVerts/2)
 	{
-		if (mUsage != GL_STATIC_DRAW_ARB)
+		if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
 		{
 			nverts += nverts/4;
 		}
-
 		mNumVerts = nverts;
 	}
+
 }
 
 void LLVertexBuffer::updateNumIndices(S32 nindices)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
+	mRequestedNumIndices = nindices;
 	if (!mDynamicSize)
 	{
 		mNumIndices = nindices;
@@ -365,54 +440,6 @@ void LLVertexBuffer::updateNumIndices(S32 nindices)
 	}
 }
 
-void LLVertexBuffer::makeStatic()
-{
-	if (!sEnableVBOs)
-	{
-		return;
-	}
-	
-	if (sRenderActive)
-	{
-		llerrs << "Make static called during render." << llendl;
-	}
-	
-	if (mUsage != GL_STATIC_DRAW_ARB)
-	{
-		if (useVBOs())
-		{
-			if (mGLBuffer)
-			{
-				sDeleteList.push_back(mGLBuffer);
-			}
-			if (mGLIndices)
-			{
-				sDeleteList.push_back(mGLIndices);
-			}
-		}
-	
-		if (mGLBuffer)
-		{
-			sGLCount++;
-			glGenBuffersARB(1, (GLuint*) &mGLBuffer);
-		}
-		if (mGLIndices)
-		{
-			sGLCount++;
-			glGenBuffersARB(1, (GLuint*) &mGLIndices);
-		}
-			
-		mUsage = GL_STATIC_DRAW_ARB;
-		mResized = TRUE;
-
-		if (!mLocked)
-		{
-			mLocked = TRUE;
-			sLockedList.push_back(this);
-		}
-	}
-}
-
 void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
@@ -435,6 +462,9 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 
 void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 {
+	mRequestedNumVerts = newnverts;
+	mRequestedNumIndices = newnindices;
+
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
 	mDynamicSize = TRUE;
 	if (mUsage == GL_STATIC_DRAW_ARB)
@@ -469,22 +499,25 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			else
 			{
 				//delete old buffer, keep GL buffer for now
-				U8* old = mMappedData;
-				mMappedData = new U8[newsize];
-				if (old)
-				{	
-					memcpy(mMappedData, old, llmin(newsize, oldsize));
-					if (newsize > oldsize)
+				if (!useVBOs())
+				{
+					U8* old = mMappedData;
+					mMappedData = new U8[newsize];
+					if (old)
+					{	
+						memcpy(mMappedData, old, llmin(newsize, oldsize));
+						if (newsize > oldsize)
+						{
+							memset(mMappedData+oldsize, 0, newsize-oldsize);
+						}
+
+						delete [] old;
+					}
+					else
 					{
-						memset(mMappedData+oldsize, 0, newsize-oldsize);
+						memset(mMappedData, 0, newsize);
+						mEmpty = TRUE;
 					}
-
-					delete [] old;
-				}
-				else
-				{
-					memset(mMappedData, 0, newsize);
-					mEmpty = TRUE;
 				}
 				mResized = TRUE;
 			}
@@ -502,22 +535,26 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			}
 			else
 			{
-				//delete old buffer, keep GL buffer for now
-				U8* old = mMappedIndexData;
-				mMappedIndexData = new U8[new_index_size];
-				if (old)
-				{	
-					memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
-					if (new_index_size > old_index_size)
+				if (!useVBOs())
+				{
+					//delete old buffer, keep GL buffer for now
+					U8* old = mMappedIndexData;
+					mMappedIndexData = new U8[new_index_size];
+					
+					if (old)
+					{	
+						memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
+						if (new_index_size > old_index_size)
+						{
+							memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
+						}
+						delete [] old;
+					}
+					else
 					{
-						memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
+						memset(mMappedIndexData, 0, new_index_size);
+						mEmpty = TRUE;
 					}
-					delete [] old;
-				}
-				else
-				{
-					memset(mMappedIndexData, 0, new_index_size);
-					mEmpty = TRUE;
 				}
 				mResized = TRUE;
 			}
@@ -527,18 +564,29 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			destroyGLIndices();
 		}
 	}
+
+	if (mResized && useVBOs())
+	{
+		setBuffer(0);
+	}
 }
 
 BOOL LLVertexBuffer::useVBOs() const
 {
-	//it's generally ineffective to use VBO for things that are streaming
-	//when we already have a client buffer around
-	if (mUsage == GL_STREAM_DRAW_ARB)
+	//it's generally ineffective to use VBO for things that are streaming on apple
+		
+#if LL_DARWIN
+	if (!mUsage || mUsage == GL_STREAM_DRAW_ARB)
 	{
 		return FALSE;
 	}
-
-	return sEnableVBOs && (!sRenderActive || !mLocked);
+#else
+	if (!mUsage)
+	{
+		return FALSE;
+	}
+#endif
+	return sEnableVBOs; // && (!sRenderActive || !mLocked);
 }
 
 //----------------------------------------------------------------------------
@@ -547,27 +595,27 @@ BOOL LLVertexBuffer::useVBOs() const
 U8* LLVertexBuffer::mapBuffer(S32 access)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
-	if (sRenderActive)
-	{
-		llwarns << "Buffer mapped during render frame!" << llendl;
-	}
-	if (!mGLBuffer && !mGLIndices)
-	{
-		llerrs << "LLVertexBuffer::mapBuffer() called  before createGLBuffer" << llendl;
-	}
 	if (mFinal)
 	{
 		llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
 	}
-	if (!mMappedData && !mMappedIndexData)
+	if (!useVBOs() && !mMappedData && !mMappedIndexData)
 	{
 		llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
 	}
-	
+		
 	if (!mLocked && useVBOs())
 	{
+		setBuffer(0);
 		mLocked = TRUE;
-		sLockedList.push_back(this);
+		mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+		mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+		/*if (sMapped)
+		{
+			llerrs << "Mapped two VBOs at the same time!" << llendl;
+		}
+		sMapped = TRUE;*/
+		sMappedCount++;
 	}
 	
 	return mMappedData;
@@ -580,64 +628,19 @@ void LLVertexBuffer::unmapBuffer()
 	{
 		if (useVBOs() && mLocked)
 		{
-			if (mGLBuffer)
-			{
-				if (mResized)
-				{
-					glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), mMappedData, mUsage);
-				}
-				else
-				{
-					if (mEmpty || mDirtyRegions.empty())
-					{
-						glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
-					}
-					else
-					{
-						for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
-						{
-							DirtyRegion& region = *i;
-							glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride);
-						}
-					}
-				}
-			}
-			
-			if (mGLIndices)
+			glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+
+			/*if (!sMapped)
 			{
-				if (mResized)
-				{
-					glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), mMappedIndexData, mUsage);
-				}
-				else
-				{
-					if (mEmpty || mDirtyRegions.empty())
-					{
-						glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
-					}
-					else
-					{
-						for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
-						{
-							DirtyRegion& region = *i;
-							glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32), 
-								region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32));
-						}
-					}
-				}
+				llerrs << "Redundantly unmapped VBO!" << llendl;
 			}
-
-			mDirtyRegions.clear();
-			mFilthy = FALSE;
-			mResized = FALSE;
+			sMapped = FALSE;*/
+			sMappedCount--;
 
 			if (mUsage == GL_STATIC_DRAW_ARB)
 			{ //static draw buffers can only be mapped a single time
 				//throw out client data (we won't be using it again)
-				delete [] mMappedData;
-				delete [] mMappedIndexData;
-				mMappedIndexData = NULL;
-				mMappedData = NULL;
 				mEmpty = TRUE;
 				mFinal = TRUE;
 			}
@@ -645,10 +648,11 @@ void LLVertexBuffer::unmapBuffer()
 			{
 				mEmpty = FALSE;
 			}
+
+			mMappedIndexData = NULL;
+			mMappedData = NULL;
 			
 			mLocked = FALSE;
-			
-			glFlush();
 		}
 	}
 }
@@ -690,9 +694,9 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
 {
 	return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index);
 }
-bool LLVertexBuffer::getIndexStrider(LLStrider<U32>& strider, S32 index)
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index)
 {
-	return VertexBufferStrider<U32,TYPE_INDEX>::get(*this, strider, index);
+	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index);
 }
 bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index)
 {
@@ -755,16 +759,46 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 	{
 		if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
 		{
+			/*if (sMapped)
+			{
+				llerrs << "VBO bound while another VBO mapped!" << llendl;
+			}*/
 			glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+			sBindCount++;
 			sVBOActive = TRUE;
 			setup = TRUE; // ... or the bound buffer changed
 		}
 		if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
 		{
+			/*if (sMapped)
+			{
+				llerrs << "VBO bound while another VBO mapped!" << llendl;
+			}*/
 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+			sBindCount++;
 			sIBOActive = TRUE;
 		}
 		
+		if (mResized)
+		{
+			if (mGLBuffer)
+			{
+				glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
+			}
+			if (mGLIndices)
+			{
+				glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
+			}
+
+			mEmpty = TRUE;
+			mResized = FALSE;
+
+			if (data_mask != 0)
+			{
+				llerrs << "Buffer set for rendering before being filled after resize." << llendl;
+			}
+		}
+
 		unmapBuffer();
 	}
 	else
@@ -774,6 +808,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 			if (sEnableVBOs && sVBOActive)
 			{
 				glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+				sBindCount++;
 				sVBOActive = FALSE;
 				setup = TRUE; // ... or a VBO is deactivated
 			}
@@ -784,7 +819,12 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 		}
 		if (sEnableVBOs && mGLIndices && sIBOActive)
 		{
+			/*if (sMapped)
+			{
+				llerrs << "VBO unbound while potentially mapped!" << llendl;
+			}*/
 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+			sBindCount++;
 			sIBOActive = FALSE;
 		}
 	}
@@ -803,9 +843,11 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 				llwarns << "Vertex buffer set for rendering outside of render frame." << llendl;
 			}
 			setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
-			sLastMask = data_mask;
+			sSetCount++;
 		}
 	}
+
+	sLastMask = data_mask;
 }
 
 // virtual (default)
@@ -821,10 +863,6 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
 	}
 
-	if (data_mask & MAP_VERTEX)
-	{
-		glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
-	}
 	if (data_mask & MAP_NORMAL)
 	{
 		glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
@@ -855,49 +893,19 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 	{
 		glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE,  stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
 	}
+	if (data_mask & MAP_VERTEX)
+	{
+		glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
+	}
 
 	llglassertok();
 }
 
 void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
 {
-	if (useVBOs() && !mFilthy)
-	{
-		if (!mDirtyRegions.empty())
-		{
-			DirtyRegion& region = *(mDirtyRegions.rbegin());
-			
-			if (region.mIndex+region.mCount > vert_index)
-			{
-				//this buffer has received multiple updates since the last copy, mark it filthy
-				mFilthy = TRUE;
-				mDirtyRegions.clear();
-				return;
-			}
-			
-			if (region.mIndex + region.mCount == vert_index &&
-				region.mIndicesIndex + region.mIndicesCount == indices_index)
-			{
-				region.mCount += vert_count;
-				region.mIndicesCount += indices_count;
-				return;
-			}
-		}
-
-		mDirtyRegions.push_back(DirtyRegion(vert_index,vert_count,indices_index,indices_count));
-	}
-}
-
-void LLVertexBuffer::markClean()
-{
-	if (!mResized && !mEmpty && !mFilthy)
+	// TODO: use GL_APPLE_flush_buffer_range here
+	/*if (useVBOs() && !mFilthy)
 	{
-		buffer_list_t::reverse_iterator iter = sLockedList.rbegin();
-		if (*iter == this)
-		{
-			mLocked = FALSE;
-			sLockedList.pop_back();
-		}
-	}
+	
+	}*/
 }
-
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index cf36eb664c7..e2a4196b0e3 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -50,12 +50,38 @@
 //  be called as soon as getVertexPointer(), etc is called (which MUST ONLY be
 //  called from the main (i.e OpenGL) thread)
 
+
+//============================================================================
+// gl name pools for dynamic and streaming buffers
+
+class LLVBOPool : public LLGLNamePool
+{
+protected:
+	virtual GLuint allocateName()
+	{
+		GLuint name;
+		glGenBuffersARB(1, &name);
+		return name;
+	}
+
+	virtual void releaseName(GLuint name)
+	{
+		glDeleteBuffersARB(1, &name);
+	}
+};
+
+
 //============================================================================
 // base class
 
 class LLVertexBuffer : public LLRefCount
 {
 public:
+	static LLVBOPool sStreamVBOPool;
+	static LLVBOPool sDynamicVBOPool;
+	static LLVBOPool sStreamIBOPool;
+	static LLVBOPool sDynamicIBOPool;
+
 	static void initClass(bool use_vbo);
 	static void cleanupClass();
  	static void startRender(); //between start and stop render, no client copies will occur
@@ -63,6 +89,12 @@ class LLVertexBuffer : public LLRefCount
 	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
 	static void unbind(); //unbind any bound vertex buffer
 
+	//get the size of a vertex with the given typemask
+	//if offsets is not NULL, its contents will be filled
+	//with the offset of each vertex component in the buffer, 
+	// indexed by the following enum
+	static S32 calcStride(const U32& typemask, S32* offsets = NULL); 										
+
 	enum {
 		TYPE_VERTEX,
 		TYPE_NORMAL,
@@ -92,10 +124,16 @@ class LLVertexBuffer : public LLRefCount
 	};
 	
 protected:
+	friend class LLGLImmediate;
+
 	virtual ~LLVertexBuffer(); // use unref()
 
 	virtual void setupVertexBuffer(U32 data_mask) const; // pure virtual, called from mapBuffer()
-
+	
+	void	genBuffer();
+	void	genIndices();
+	void	releaseBuffer();
+	void	releaseIndices();
 	void	createGLBuffer();
 	void	createGLIndices();
 	void 	destroyGLBuffer();
@@ -104,7 +142,7 @@ class LLVertexBuffer : public LLRefCount
 	void	updateNumIndices(S32 nindices); 
 	virtual BOOL	useVBOs() const;
 	void	unmapBuffer();
-	
+		
 public:
 	LLVertexBuffer(U32 typemask, S32 usage);
 	
@@ -115,8 +153,7 @@ class LLVertexBuffer : public LLRefCount
 	// allocate buffer
 	void	allocateBuffer(S32 nverts, S32 nindices, bool create);
 	virtual void resizeBuffer(S32 newnverts, S32 newnindices);
-	void	makeStatic();
-	
+		
 	// Only call each getVertexPointer, etc, once before calling unmapBuffer()
 	// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
 	// example:
@@ -125,7 +162,7 @@ class LLVertexBuffer : public LLRefCount
 	//   setVertsNorms(verts, norms);
 	//   vb->unmapBuffer();
 	bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0);
-	bool getIndexStrider(LLStrider<U32>& strider, S32 index=0);
+	bool getIndexStrider(LLStrider<U16>& strider, S32 index=0);
 	bool getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index=0);
 	bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0);
 	bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
@@ -138,13 +175,16 @@ class LLVertexBuffer : public LLRefCount
 	BOOL isLocked() const					{ return mLocked; }
 	S32 getNumVerts() const					{ return mNumVerts; }
 	S32 getNumIndices() const				{ return mNumIndices; }
+	S32 getRequestedVerts() const			{ return mRequestedNumVerts; }
+	S32 getRequestedIndices() const			{ return mRequestedNumIndices; }
+
 	U8* getIndicesPointer() const			{ return useVBOs() ? NULL : mMappedIndexData; }
 	U8* getVerticesPointer() const			{ return useVBOs() ? NULL : mMappedData; }
 	S32 getStride() const					{ return mStride; }
 	S32 getTypeMask() const					{ return mTypeMask; }
 	BOOL hasDataType(S32 type) const		{ return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
 	S32 getSize() const						{ return mNumVerts*mStride; }
-	S32 getIndicesSize() const				{ return mNumIndices * sizeof(U32); }
+	S32 getIndicesSize() const				{ return mNumIndices * sizeof(U16); }
 	U8* getMappedData() const				{ return mMappedData; }
 	U8* getMappedIndices() const			{ return mMappedIndexData; }
 	S32 getOffset(S32 type) const			{ return mOffsets[type]; }
@@ -153,11 +193,13 @@ class LLVertexBuffer : public LLRefCount
 	void setStride(S32 type, S32 new_stride);
 	
 	void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count);
-	void markClean();
 
 protected:	
-	S32		mNumVerts;		// Number of vertices
-	S32		mNumIndices;	// Number of indices
+	S32		mNumVerts;		// Number of vertices allocated
+	S32		mNumIndices;	// Number of indices allocated
+	S32		mRequestedNumVerts;  // Number of vertices requested
+	S32		mRequestedNumIndices;  // Number of indices requested
+
 	S32		mStride;
 	U32		mTypeMask;
 	S32		mUsage;			// GL usage
@@ -192,10 +234,11 @@ class LLVertexBuffer : public LLRefCount
 	static BOOL sRenderActive;
 	static S32 sCount;
 	static S32 sGLCount;
+	static S32 sMappedCount;
+	static BOOL sMapped;
 	static std::vector<U32> sDeleteList;
 	typedef std::list<LLVertexBuffer*> buffer_list_t;
-	static buffer_list_t sLockedList;
-	
+		
 	static BOOL sEnableVBOs;
 	static S32 sTypeOffsets[TYPE_MAX];
 	static U32 sGLRenderBuffer;
@@ -204,6 +247,8 @@ class LLVertexBuffer : public LLRefCount
 	static BOOL sIBOActive;
 	static U32 sLastMask;
 	static U32 sAllocatedBytes;
+	static U32 sBindCount;
+	static U32 sSetCount;
 };
 
 
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 435e1d17019..8132396cb51 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -48,6 +48,7 @@
 #include "llglheaders.h"
 #include "llfocusmgr.h"
 #include "llwindow.h"
+#include "llglimmediate.h"
 
 // globals loaded from settings.xml
 S32	LLBUTTON_ORIG_H_PAD	= 6; // Pre-zoomable UI
@@ -601,9 +602,9 @@ void LLButton::draw()
 			mImagep->draw(0, 0, getEnabled() ? mImageColor : mDisabledImageColor );
 			if (mCurGlowStrength > 0.01f)
 			{
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
 				mImagep->drawSolid(0, 0, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			}
 		}
 		else
@@ -612,9 +613,9 @@ void LLButton::draw()
 			mImagep->draw(0, 0, getRect().getWidth(), getRect().getHeight(), getEnabled() ? mImageColor : mDisabledImageColor  );
 			if (mCurGlowStrength > 0.01f)
 			{
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
 				mImagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			}
 		}
 		else
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 536e9a6dc64..0b3156fa1e7 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -89,7 +89,16 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLString& name, const LLRect& rect,
 		LLCHECKBOXCTRL_VPAD + 1, // padding to get better alignment
 		text_width + LLCHECKBOXCTRL_HPAD,
 		text_height );
-	mLabel = new LLTextBox( "CheckboxCtrl Label", label_rect, label.c_str(), mFont );
+
+	// *HACK Get rid of this with SL-55508... 
+	// this allows blank check boxes and radio boxes for now
+	LLString local_label = label;
+	if(local_label.empty())
+	{
+		local_label = " ";
+	}
+
+	mLabel = new LLTextBox( "CheckboxCtrl Label", label_rect, local_label.c_str(), mFont );
 	mLabel->setFollowsLeft();
 	mLabel->setFollowsBottom();
 	addChild(mLabel);
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 68719bea400..fed39b79178 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2123,42 +2123,40 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
 	if( floater->isResizable() )
 	{
 		LLRect view_rect = floater->getRect();
-		S32 view_width = view_rect.getWidth();
-		S32 view_height = view_rect.getHeight();
+		S32 old_width = view_rect.getWidth();
+		S32 old_height = view_rect.getHeight();
 		S32 min_width;
 		S32 min_height;
 		floater->getResizeLimits( &min_width, &min_height );
 
 		// Make sure floater isn't already smaller than its min height/width?
-		S32 new_width = llmax( min_width, view_width );
-		S32 new_height = llmax( min_height, view_height );
+		S32 new_width = llmax( min_width, old_width );
+		S32 new_height = llmax( min_height, old_height);
 
-		if( !allow_partial_outside
-			&& ( (new_width > screen_width)
-			|| (new_height > screen_height) ) )
+		if((new_width > screen_width) || (new_height > screen_height))
 		{
-			// We have to force this window to be inside the screen.
+			// We have to make this window able to fit on screen
 			new_width = llmin(new_width, screen_width);
 			new_height = llmin(new_height, screen_height);
 
-			// Still respect minimum width/height
+			// ...while respecting minimum width/height
 			new_width = llmax(new_width, min_width);
 			new_height = llmax(new_height, min_height);
 
 			floater->reshape( new_width, new_height, TRUE );
+			if (floater->followsRight())
+			{
+				floater->translate(old_width - new_width, 0);
+			}
 
-			// Make sure the damn thing is actually onscreen.
-			if (floater->translateIntoRect(snap_rect_local, FALSE))
+			if (floater->followsTop())
 			{
-				floater->clearSnapTarget();
+				floater->translate(0, old_height - new_height);
 			}
 		}
-		else if (!floater->isMinimized())
-		{
-			floater->reshape(new_width, new_height, TRUE);
-		}
 	}
 
+	// move window fully onscreen
 	if (floater->translateIntoRect( snap_rect_local, allow_partial_outside ))
 	{
 		floater->clearSnapTarget();
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 4e94aff7a5f..00b4c37bb0a 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -47,6 +47,7 @@
 
 #include "llmath.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llfocusmgr.h"
 #include "llfont.h"
 #include "llcoord.h"
@@ -470,7 +471,7 @@ void LLMenuItemGL::draw( void )
 	// let disabled items be highlighted, just don't draw them as such
 	if( getEnabled() && getHighlight() && !mBriefItem)
 	{
-		glColor4fv( sHighlightBackground.mV );
+		gGL.color4fv( sHighlightBackground.mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
@@ -580,7 +581,7 @@ LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const LLString &name ) :
 
 void LLMenuItemSeparatorGL::draw( void )
 {
-	glColor4fv( getDisabledColor().mV );
+	gGL.color4fv( getDisabledColor().mV );
 	const S32 y = getRect().getHeight() / 2;
 	const S32 PAD = 6;
 	gl_line_2d( PAD, y, getRect().getWidth() - PAD, y );
@@ -701,17 +702,17 @@ void LLMenuItemTearOffGL::draw()
 	// disabled items can be highlighted, but shouldn't render as such
 	if( getEnabled() && getHighlight() && !isBriefItem())
 	{
-		glColor4fv( getHighlightBGColor().mV );
+		gGL.color4fv( getHighlightBGColor().mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
 	if (getEnabled())
 	{
-		glColor4fv( getEnabledColor().mV );
+		gGL.color4fv( getEnabledColor().mV );
 	}
 	else
 	{
-		glColor4fv( getDisabledColor().mV );
+		gGL.color4fv( getDisabledColor().mV );
 	}
 	const S32 y = getRect().getHeight() / 3;
 	const S32 PAD = 6;
@@ -1638,7 +1639,7 @@ void LLMenuItemBranchDownGL::draw( void )
 
 	if( getHighlight() )
 	{
-		glColor4fv( getHighlightBGColor().mV );
+		gGL.color4fv( getHighlightBGColor().mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
@@ -2949,7 +2950,7 @@ void LLMenuGL::draw( void )
 
 void LLMenuGL::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
 {
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 	LLRect item_rect = itemp->getRect();
 	gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0);
 }
@@ -3476,9 +3477,9 @@ void LLPieMenu::draw()
 	F32 center_y = height/2;
 	S32 steps = 100;
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef(center_x, center_y, 0.f);
+		gGL.translatef(center_x, center_y, 0.f);
 
 		F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth");
 		LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor");
@@ -3517,16 +3518,16 @@ void LLPieMenu::draw()
 		gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color );
 
 		// inner circle
-		glColor4fv( line_color.mV );
+		gGL.color4fv( line_color.mV );
 		gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
 
 		// outer circle
-		glColor4fv( outer_color.mV );
+		gGL.color4fv( outer_color.mV );
 		gl_circle_2d( 0, 0, mCurRadius, steps, FALSE );
 
 		LLUI::setLineWidth(1.0f);
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 
 	mHoverThisFrame = FALSE;
 
@@ -3541,10 +3542,10 @@ void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
 	F32 center_y = height/2;
 	S32 steps = 100;
 
-	glColor4fv( color.mV );
-	glPushMatrix();
+	gGL.color4fv( color.mV );
+	gGL.pushMatrix();
 	{
-		glTranslatef(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
+		gGL.translatef(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
 
 		item_list_t::iterator item_iter;
 		S32 i = 0;
@@ -3564,7 +3565,7 @@ void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
 			i++;
 		}
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 // virtual
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
new file mode 100644
index 00000000000..b4bf3a92d5a
--- /dev/null
+++ b/indra/llui/llmultislider.cpp
@@ -0,0 +1,677 @@
+/** 
+ * @file llmultisldr.cpp
+ * @brief LLMultiSlider base class
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llmultislider.h"
+#include "llui.h"
+
+#include "llgl.h"
+#include "llwindow.h"
+#include "llfocusmgr.h"
+#include "llkeyboard.h"			// for the MASK constants
+#include "llcontrol.h"
+#include "llimagegl.h"
+
+#include <sstream>
+
+const S32 MULTI_THUMB_WIDTH = 8;
+const S32 MULTI_TRACK_HEIGHT = 6;
+const F32 FLOAT_THRESHOLD = 0.00001f;
+const S32 EXTRA_TRIANGLE_WIDTH = 2;
+const S32 EXTRA_TRIANGLE_HEIGHT = -2;
+
+S32 LLMultiSlider::mNameCounter = 0;
+
+LLMultiSlider::LLMultiSlider( 
+	const LLString& name,
+	const LLRect& rect,
+	void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
+	void* callback_userdata,
+	F32 initial_value,
+	F32 min_value,
+	F32 max_value,
+	F32 increment,
+	S32 max_sliders,
+	BOOL allow_overlap,
+	BOOL draw_track,
+	BOOL use_triangle,
+	const LLString& control_name)
+	:
+	LLUICtrl( name, rect, TRUE,	on_commit_callback, callback_userdata, 
+		FOLLOWS_LEFT | FOLLOWS_TOP),
+
+	mInitialValue( initial_value ),
+	mMinValue( min_value ),
+	mMaxValue( max_value ),
+	mIncrement( increment ),
+	mMaxNumSliders(max_sliders),
+	mAllowOverlap(allow_overlap),
+	mDrawTrack(draw_track),
+	mUseTriangle(use_triangle),
+	mMouseOffset( 0 ),
+	mDragStartThumbRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 ),
+	mTrackColor(		LLUI::sColorsGroup->getColor( "MultiSliderTrackColor" ) ),
+	mThumbOutlineColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbOutlineColor" ) ),
+	mThumbCenterColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterColor" ) ),
+	mThumbCenterSelectedColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ),
+	mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ),
+	mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ),
+	mMouseDownCallback( NULL ),
+	mMouseUpCallback( NULL )
+{
+	mValue.emptyMap();
+	mCurSlider = LLString::null;
+
+	// properly handle setting the starting thumb rect
+	// do it this way to handle both the operating-on-settings
+	// and standalone ways of using this
+	setControlName(control_name, NULL);
+	setValue(getValue());
+}
+
+EWidgetType LLMultiSlider::getWidgetType() const
+{
+	return WIDGET_TYPE_MULTI_SLIDER_BAR;
+}
+
+LLString LLMultiSlider::getWidgetTag() const
+{
+	return LL_MULTI_SLIDER_TAG;
+}
+
+void LLMultiSlider::setSliderValue(const LLString& name, F32 value, BOOL from_event)
+{
+	// exit if not there
+	if(!mValue.has(name)) {
+		return;
+	}
+
+	value = llclamp( value, mMinValue, mMaxValue );
+
+	// Round to nearest increment (bias towards rounding down)
+	value -= mMinValue;
+	value += mIncrement/2.0001f;
+	value -= fmod(value, mIncrement);
+	F32 newValue = mMinValue + value;
+
+	// now, make sure no overlap
+	// if we want that
+	if(!mAllowOverlap) {
+		bool hit = false;
+
+		// look at the current spot
+		// and see if anything is there
+		LLSD::map_iterator mIt = mValue.beginMap();
+		for(;mIt != mValue.endMap(); mIt++) {
+			
+			F32 testVal = (F32)mIt->second.asReal() - newValue;
+			if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD &&
+				mIt->first != name) {
+				hit = true;
+				break;
+			}
+		}
+
+		// if none found, stop
+		if(hit) {
+			return;
+		}
+	}
+	
+
+	// now set it in the map
+	mValue[name] = newValue;
+
+	// set the control if it's the current slider and not from an event
+	if (!from_event && name == mCurSlider)
+	{
+		setControlValue(mValue);
+	}
+	
+	F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
+
+	S32 left_edge = MULTI_THUMB_WIDTH/2;
+	S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
+
+	S32 x = left_edge + S32( t * (right_edge - left_edge) );
+	mThumbRects[name].mLeft = x - (MULTI_THUMB_WIDTH/2);
+	mThumbRects[name].mRight = x + (MULTI_THUMB_WIDTH/2);
+}
+
+void LLMultiSlider::setValue(const LLSD& value)
+{
+	// only do if it's a map
+	if(value.isMap()) {
+		
+		// add each value... the first in the map becomes the current
+		LLSD::map_const_iterator mIt = value.beginMap();
+		mCurSlider = mIt->first;
+
+		for(; mIt != value.endMap(); mIt++) {
+			setSliderValue(mIt->first, (F32)mIt->second.asReal(), TRUE);
+		}
+	}
+}
+
+F32 LLMultiSlider::getSliderValue(const LLString& name) const
+{
+	return (F32)mValue[name].asReal();
+}
+
+void LLMultiSlider::setCurSlider(const LLString& name)
+{
+	if(mValue.has(name)) {
+		mCurSlider = name;
+	}
+}
+
+const LLString& LLMultiSlider::addSlider()
+{
+	return addSlider(mInitialValue);
+}
+
+const LLString& LLMultiSlider::addSlider(F32 val)
+{
+	std::stringstream newName;
+	F32 initVal = val;
+
+	if(mValue.size() >= mMaxNumSliders) {
+		return LLString::null;
+	}
+
+	// create a new name
+	newName << "sldr" << mNameCounter;
+	mNameCounter++;
+
+	bool foundOne = findUnusedValue(initVal);
+	if(!foundOne) {
+		return LLString::null;
+	}
+
+	// add a new thumb rect
+	mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 );
+
+	// add the value and set the current slider to this one
+	mValue.insert(newName.str(), initVal);
+	mCurSlider = newName.str();
+
+	// move the slider
+	setSliderValue(mCurSlider, initVal, TRUE);
+
+	return mCurSlider;
+}
+
+bool LLMultiSlider::findUnusedValue(F32& initVal)
+{
+	bool firstTry = true;
+
+	// find the first open slot starting with
+	// the initial value
+	while(true) {
+		
+		bool hit = false;
+
+		// look at the current spot
+		// and see if anything is there
+		LLSD::map_iterator mIt = mValue.beginMap();
+		for(;mIt != mValue.endMap(); mIt++) {
+			
+			F32 testVal = (F32)mIt->second.asReal() - initVal;
+			if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD) {
+				hit = true;
+				break;
+			}
+		}
+
+		// if we found one
+		if(!hit) {
+			break;
+		}
+
+		// increment and wrap if need be
+		initVal += mIncrement;
+		if(initVal > mMaxValue) {
+			initVal = mMinValue;
+		}
+
+		// stop if it's filled
+		if(initVal == mInitialValue && !firstTry) {
+			llwarns << "Whoa! Too many multi slider elements to add one to" << llendl;
+			return false;
+		}
+
+		firstTry = false;
+		continue;
+	}
+
+	return true;
+}
+
+
+void LLMultiSlider::deleteSlider(const LLString& name)
+{
+	// can't delete last slider
+	if(mValue.size() <= 0) {
+		return;
+	}
+
+	// get rid of value from mValue and its thumb rect
+	mValue.erase(name);
+	mThumbRects.erase(name);
+
+	// set to the last created
+	if(mValue.size() > 0) {
+		std::map<LLString, LLRect>::iterator mIt = mThumbRects.end();
+		mIt--;
+		mCurSlider = mIt->first;
+	}
+}
+
+void LLMultiSlider::clear()
+{
+	while(mThumbRects.size() > 0) {
+		deleteCurSlider();
+	}
+
+	LLUICtrl::clear();
+}
+
+BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
+{
+	if( gFocusMgr.getMouseCapture() == this )
+	{
+		S32 left_edge = MULTI_THUMB_WIDTH/2;
+		S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
+
+		x += mMouseOffset;
+		x = llclamp( x, left_edge, right_edge );
+
+		F32 t = F32(x - left_edge) / (right_edge - left_edge);
+		setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue );
+		onCommit();
+
+		getWindow()->setCursor(UI_CURSOR_ARROW);
+		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;		
+	}
+	else
+	{
+		getWindow()->setCursor(UI_CURSOR_ARROW);
+		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;		
+	}
+	return TRUE;
+}
+
+BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	BOOL handled = FALSE;
+
+	if( gFocusMgr.getMouseCapture() == this )
+	{
+		gFocusMgr.setMouseCapture( NULL );
+
+		if( mMouseUpCallback )
+		{
+			mMouseUpCallback( this, mCallbackUserData );
+		}
+		handled = TRUE;
+		make_ui_sound("UISndClickRelease");
+	}
+	else
+	{
+		handled = TRUE;
+	}
+
+	return handled;
+}
+
+BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	// only do sticky-focus on non-chrome widgets
+	if (!getIsChrome())
+	{
+		setFocus(TRUE);
+	}
+	if( mMouseDownCallback )
+	{
+		mMouseDownCallback( this, mCallbackUserData );
+	}
+
+	if (MASK_CONTROL & mask) // if CTRL is modifying
+	{
+		setCurSliderValue(mInitialValue);
+		onCommit();
+	}
+	else
+	{
+		// scroll through thumbs to see if we have a new one selected and select that one
+		std::map<LLString, LLRect>::iterator mIt = mThumbRects.begin();
+		for(; mIt != mThumbRects.end(); mIt++) {
+			
+			// check if inside.  If so, set current slider and continue
+			if(mIt->second.pointInRect(x,y)) {
+				mCurSlider = mIt->first;
+				break;
+			}
+		}
+
+		// Find the offset of the actual mouse location from the center of the thumb.
+		if (mThumbRects[mCurSlider].pointInRect(x,y))
+		{
+			mMouseOffset = (mThumbRects[mCurSlider].mLeft + MULTI_THUMB_WIDTH/2) - x;
+		}
+		else
+		{
+			mMouseOffset = 0;
+		}
+
+		// Start dragging the thumb
+		// No handler needed for focus lost since this class has no state that depends on it.
+		gFocusMgr.setMouseCapture( this );
+		mDragStartThumbRect = mThumbRects[mCurSlider];				
+	}
+	make_ui_sound("UISndClick");
+
+	return TRUE;
+}
+
+BOOL	LLMultiSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
+{
+	BOOL handled = FALSE;
+	if( getVisible() && getEnabled() && !called_from_parent )
+	{
+		switch(key)
+		{
+		case KEY_UP:
+		case KEY_DOWN:
+			// eat up and down keys to be consistent
+			handled = TRUE;
+			break;
+		case KEY_LEFT:
+			setCurSliderValue(getCurSliderValue() - getIncrement());
+			onCommit();
+			handled = TRUE;
+			break;
+		case KEY_RIGHT:
+			setCurSliderValue(getCurSliderValue() + getIncrement());
+			onCommit();
+			handled = TRUE;
+			break;
+		default:
+			break;
+		}
+	}
+	return handled;
+}
+
+void LLMultiSlider::draw()
+{
+	LLColor4 curThumbColor;
+
+	std::map<LLString, LLRect>::iterator mIt;
+	std::map<LLString, LLRect>::iterator curSldrIt;
+	if( getVisible() )
+	{
+		// Draw background and thumb.
+
+		// drawing solids requires texturing be disabled
+		LLGLSNoTexture no_texture;
+
+		LLRect rect(mDragStartThumbRect);
+
+		F32 opacity = getEnabled() ? 1.f : 0.3f;
+
+		// Track
+		LLUUID thumb_image_id;
+		thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
+		LLPointer<LLImageGL> thumb_imagep(LLUI::sImageProvider->getUIImageByID(thumb_image_id)->getImage());
+
+		S32 height_offset = (getRect().getHeight() - MULTI_TRACK_HEIGHT) / 2;
+		LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset );
+
+
+		if(mDrawTrack)
+		{
+			track_rect.stretch(-1);
+			gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
+				thumb_imagep, mTrackColor % opacity);
+		}
+
+		// if we're supposed to use a drawn triangle
+		// simple gl call for the triangle
+		if(mUseTriangle) {
+
+			for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
+
+				gl_triangle_2d(
+					mIt->second.mLeft - EXTRA_TRIANGLE_WIDTH, 
+					mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT,
+					mIt->second.mRight + EXTRA_TRIANGLE_WIDTH, 
+					mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT,
+					mIt->second.mLeft + mIt->second.getWidth() / 2, 
+					mIt->second.mBottom - EXTRA_TRIANGLE_HEIGHT,
+					mTriangleColor, TRUE);
+			}
+		}
+		else if (!thumb_imagep)
+		{
+			// draw all the thumbs
+			curSldrIt = mThumbRects.end();
+			for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
+				
+				// choose the color
+				curThumbColor = mThumbCenterColor;
+				if(mIt->first == mCurSlider) {
+					
+					curSldrIt = mIt;
+					continue;
+					//curThumbColor = mThumbCenterSelectedColor;
+				}
+
+				// the draw command
+				gl_rect_2d(mIt->second, curThumbColor, TRUE);
+			}
+
+			// now draw the current slider
+			if(curSldrIt != mThumbRects.end()) {
+				gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor, TRUE);
+			}
+
+			// and draw the drag start
+			if (gFocusMgr.getMouseCapture() == this)
+			{
+				gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE);
+			}
+		}
+		else if( gFocusMgr.getMouseCapture() == this )
+		{
+			// draw drag start
+			gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, 
+				mDragStartThumbRect.mBottom, 16, 16, 
+				mDragStartThumbRect.getWidth(), 
+				mDragStartThumbRect.getHeight(), 
+				thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
+
+			// draw the highlight
+			if (hasFocus())
+			{
+				F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
+				LLRect highlight_rect = mThumbRects[mCurSlider];
+				highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
+				gl_draw_scaled_image_with_border(highlight_rect.mLeft, 
+					highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), 
+					highlight_rect.getHeight(),
+					thumb_imagep, gFocusMgr.getFocusColor());
+			}
+
+			// draw the thumbs
+			curSldrIt = mThumbRects.end();
+			for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
+				
+				// choose the color
+				curThumbColor = mThumbCenterColor;
+				if(mIt->first == mCurSlider) {
+					// don't draw now, draw last
+					curSldrIt = mIt;
+					continue;				
+				}
+				
+				// the draw command
+				gl_draw_scaled_image_with_border(
+					mIt->second.mLeft, 
+					mIt->second.mBottom, 16, 16, 
+					mIt->second.getWidth(), 
+					mIt->second.getHeight(), thumb_imagep, 
+					curThumbColor, TRUE);
+			}
+			
+			// draw cur slider last
+			if(curSldrIt != mThumbRects.end()) {
+				gl_draw_scaled_image_with_border(
+					curSldrIt->second.mLeft, 
+					curSldrIt->second.mBottom, 16, 16, 
+					curSldrIt->second.getWidth(), 
+					curSldrIt->second.getHeight(), thumb_imagep, 
+					mThumbCenterSelectedColor, TRUE);
+			}
+			
+		}
+		else
+		{ 
+			// draw highlight
+			if (hasFocus())
+			{
+				F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
+				LLRect highlight_rect = mThumbRects[mCurSlider];
+				highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
+				gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
+					thumb_imagep, gFocusMgr.getFocusColor());
+			}
+
+			// draw thumbs
+			curSldrIt = mThumbRects.end();
+			for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
+				
+				// choose the color
+				curThumbColor = mThumbCenterColor;
+				if(mIt->first == mCurSlider) {
+					curSldrIt = mIt;
+					continue;
+					//curThumbColor = mThumbCenterSelectedColor;
+				}				
+				
+				// the draw command
+				gl_draw_scaled_image_with_border(
+					mIt->second.mLeft, 
+					mIt->second.mBottom, 16, 16, 
+					mIt->second.getWidth(), 
+					mIt->second.getHeight(), thumb_imagep, 
+					curThumbColor % opacity, TRUE);
+			}
+
+			if(curSldrIt != mThumbRects.end()) {
+				gl_draw_scaled_image_with_border(
+					curSldrIt->second.mLeft, 
+					curSldrIt->second.mBottom, 16, 16, 
+					curSldrIt->second.getWidth(), 
+					curSldrIt->second.getHeight(), thumb_imagep, 
+					mThumbCenterSelectedColor % opacity, TRUE);
+			}
+		}
+
+		LLUICtrl::draw();
+	}
+}
+
+// virtual
+LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const
+{
+	LLXMLNodePtr node = LLUICtrl::getXML();
+
+	node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue());
+	node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
+	node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
+	node->createChild("increment", TRUE)->setFloatValue(getIncrement());
+
+	return node;
+}
+
+
+//static
+LLView* LLMultiSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+{
+	LLString name("multi_slider_bar");
+	node->getAttributeString("name", name);
+
+	LLRect rect;
+	createRect(node, rect, parent, LLRect());
+
+	F32 initial_value = 0.f;
+	node->getAttributeF32("initial_val", initial_value);
+
+	F32 min_value = 0.f;
+	node->getAttributeF32("min_val", min_value);
+
+	F32 max_value = 1.f; 
+	node->getAttributeF32("max_val", max_value);
+
+	F32 increment = 0.1f;
+	node->getAttributeF32("increment", increment);
+
+	S32 max_sliders = 1;
+	node->getAttributeS32("max_sliders", max_sliders);
+
+	BOOL allow_overlap = FALSE;
+	node->getAttributeBOOL("allow_overlap", allow_overlap);
+
+	BOOL draw_track = TRUE;
+	node->getAttributeBOOL("draw_track", draw_track);
+
+	BOOL use_triangle = FALSE;
+	node->getAttributeBOOL("use_triangle", use_triangle);
+
+	LLMultiSlider* multiSlider = new LLMultiSlider(name,
+							rect,
+							NULL,
+							NULL,
+							initial_value,
+							min_value,
+							max_value,
+							increment,
+							max_sliders,
+							allow_overlap,
+							draw_track,
+							use_triangle);
+
+	multiSlider->initFromXML(node, parent);
+
+	return multiSlider;
+}
diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h
new file mode 100644
index 00000000000..67f627d21c6
--- /dev/null
+++ b/indra/llui/llmultislider.h
@@ -0,0 +1,129 @@
+/** 
+ * @file llmultislider.h
+ * @brief A simple multislider
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_MULTI_SLIDER_H
+#define LL_MULTI_SLIDER_H
+
+#include "lluictrl.h"
+#include "v4color.h"
+
+class LLUICtrlFactory;
+
+class LLMultiSlider : public LLUICtrl
+{
+public:
+	LLMultiSlider( 
+		const LLString& name,
+		const LLRect& rect,
+		void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
+		void* callback_userdata,
+		F32 initial_value,
+		F32 min_value,
+		F32 max_value,
+		F32 increment,
+		S32 max_sliders,
+		BOOL allow_overlap,
+		BOOL draw_track,
+		BOOL use_triangle,
+		const LLString& control_name = LLString::null );
+
+	virtual EWidgetType getWidgetType() const;
+	virtual LLString getWidgetTag() const;
+	virtual LLXMLNodePtr getXML(bool save_children = true) const;
+	static  LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+
+	void			setSliderValue(const LLString& name, F32 value, BOOL from_event = FALSE);
+	F32				getSliderValue(const LLString& name) const;
+
+	const LLString& getCurSlider() const					{ return mCurSlider; }
+	F32				getCurSliderValue() const				{ return getSliderValue(mCurSlider); }
+	void			setCurSlider(const LLString& name);
+	void			setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); }
+
+	virtual void	setValue(const LLSD& value);
+	virtual LLSD	getValue() const		{ return mValue; }
+
+	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
+	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal());  }
+
+	F32				getInitialValue() const { return mInitialValue; }
+	F32				getMinValue() const		{ return mMinValue; }
+	F32				getMaxValue() const		{ return mMaxValue; }
+	F32				getIncrement() const	{ return mIncrement; }
+	void			setMinValue(F32 min_value) { mMinValue = min_value; }
+	void			setMaxValue(F32 max_value) { mMaxValue = max_value; }
+	void			setIncrement(F32 increment) { mIncrement = increment; }
+	void			setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
+	void			setMouseUpCallback(	void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
+
+	bool findUnusedValue(F32& initVal);
+	const LLString&	addSlider();
+	const LLString&	addSlider(F32 val);
+	void			deleteSlider(const LLString& name);
+	void			deleteCurSlider()			{ deleteSlider(mCurSlider); }
+	void			clear();
+
+	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
+	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
+	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
+	virtual BOOL	handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
+	virtual void	draw();
+
+protected:
+	LLSD			mValue;
+	F32				mInitialValue;
+	F32				mMinValue;
+	F32				mMaxValue;
+	F32				mIncrement;
+	LLString		mCurSlider;
+	static S32		mNameCounter;
+
+	S32				mMaxNumSliders;
+	BOOL			mAllowOverlap;
+	BOOL			mDrawTrack;
+	BOOL			mUseTriangle;			/// hacked in toggle to use a triangle
+
+	S32				mMouseOffset;
+	LLRect			mDragStartThumbRect;
+
+	std::map<LLString, LLRect>	mThumbRects;
+	LLColor4		mTrackColor;
+	LLColor4		mThumbOutlineColor;
+	LLColor4		mThumbCenterColor;
+	LLColor4		mThumbCenterSelectedColor;
+	LLColor4		mDisabledThumbColor;
+	LLColor4		mTriangleColor;
+	
+	void			(*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
+	void			(*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
+};
+
+#endif  // LL_LLSLIDER_H
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
new file mode 100644
index 00000000000..6f921a4e5e6
--- /dev/null
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -0,0 +1,634 @@
+/** 
+ * @file llmultisliderctrl.cpp
+ * @brief LLMultiSliderCtrl base class
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llmultisliderctrl.h"
+
+#include "audioengine.h"
+#include "sound_ids.h"
+
+#include "llmath.h"
+#include "llfontgl.h"
+#include "llgl.h"
+#include "llkeyboard.h"
+#include "lllineeditor.h"
+#include "llmultislider.h"
+#include "llstring.h"
+#include "lltextbox.h"
+#include "llui.h"
+#include "lluiconstants.h"
+#include "llcontrol.h"
+#include "llfocusmgr.h"
+#include "llresmgr.h"
+
+const U32 MAX_STRING_LENGTH = 10;
+
+ 
+LLMultiSliderCtrl::LLMultiSliderCtrl(const LLString& name, const LLRect& rect, 
+						   const LLString& label,
+						   const LLFontGL* font,
+						   S32 label_width,
+						   S32 text_left,
+						   BOOL show_text,
+						   BOOL can_edit_text,
+						   void (*commit_callback)(LLUICtrl*, void*),
+						   void* callback_user_data,
+						   F32 initial_value, F32 min_value, F32 max_value, F32 increment,
+						   S32 max_sliders, BOOL allow_overlap,
+						   BOOL draw_track,
+						   BOOL use_triangle,
+						   const LLString& control_which)
+	: LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ),
+	  mFont(font),
+	  mShowText( show_text ),
+	  mCanEditText( can_edit_text ),
+	  mPrecision( 3 ),
+	  mLabelBox( NULL ),
+	  mLabelWidth( label_width ),
+
+	  mEditor( NULL ),
+	  mTextBox( NULL ),
+	  mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
+	  mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
+	  mSliderMouseUpCallback( NULL ),
+	  mSliderMouseDownCallback( NULL )
+{
+	S32 top = getRect().getHeight();
+	S32 bottom = 0;
+	S32 left = 0;
+
+	// Label
+	if( !label.empty() )
+	{
+		if (label_width == 0)
+		{
+			label_width = font->getWidth(label);
+		}
+		LLRect label_rect( left, top, label_width, bottom );
+		mLabelBox = new LLTextBox( "MultiSliderCtrl Label", label_rect, label.c_str(), font );
+		addChild(mLabelBox);
+	}
+
+	S32 slider_right = getRect().getWidth();
+	if( show_text )
+	{
+		slider_right = text_left - MULTI_SLIDERCTRL_SPACING;
+	}
+
+	S32 slider_left = label_width ? label_width + MULTI_SLIDERCTRL_SPACING : 0;
+	LLRect slider_rect( slider_left, top, slider_right, bottom );
+	mMultiSlider = new LLMultiSlider( 
+		"multi_slider",
+		slider_rect, 
+		LLMultiSliderCtrl::onSliderCommit, this, 
+		initial_value, min_value, max_value, increment,
+		max_sliders, allow_overlap, draw_track,
+		use_triangle,
+		control_which );
+	addChild( mMultiSlider );
+	mCurValue = mMultiSlider->getCurSliderValue();
+	
+	if( show_text )
+	{
+		LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
+		if( can_edit_text )
+		{
+			mEditor = new LLLineEditor( "MultiSliderCtrl Editor", text_rect,
+				"", font,
+				MAX_STRING_LENGTH,
+				&LLMultiSliderCtrl::onEditorCommit, NULL, NULL, this,
+				&LLLineEditor::prevalidateFloat );
+			mEditor->setFollowsLeft();
+			mEditor->setFollowsBottom();
+			mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::onEditorGainFocus );
+			mEditor->setIgnoreTab(TRUE);
+			// don't do this, as selecting the entire text is single clicking in some cases
+			// and double clicking in others
+			//mEditor->setSelectAllonFocusReceived(TRUE);
+			addChild(mEditor);
+		}
+		else
+		{
+			mTextBox = new LLTextBox( "MultiSliderCtrl Text", text_rect,	"",	font);
+			mTextBox->setFollowsLeft();
+			mTextBox->setFollowsBottom();
+			addChild(mTextBox);
+		}
+	}
+
+	updateText();
+}
+
+LLMultiSliderCtrl::~LLMultiSliderCtrl()
+{
+	// Children all cleaned up by default view destructor.
+}
+
+// static
+void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
+{
+	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
+	llassert( caller == self->mEditor );
+
+	self->onFocusReceived();
+}
+
+
+void LLMultiSliderCtrl::setValue(const LLSD& value)
+{
+	mMultiSlider->setValue(value);
+	mCurValue = mMultiSlider->getCurSliderValue();
+	updateText();
+}
+
+void LLMultiSliderCtrl::setSliderValue(const LLString& name, F32 v, BOOL from_event)
+{
+	mMultiSlider->setSliderValue(name, v, from_event );
+	mCurValue = mMultiSlider->getCurSliderValue();
+	updateText();
+}
+
+void LLMultiSliderCtrl::setCurSlider(const LLString& name)
+{
+	mMultiSlider->setCurSlider(name);
+	mCurValue = mMultiSlider->getCurSliderValue();
+}
+
+BOOL LLMultiSliderCtrl::setLabelArg( const LLString& key, const LLString& text )
+{
+	BOOL res = FALSE;
+	if (mLabelBox)
+	{
+		res = mLabelBox->setTextArg(key, text);
+		if (res && mLabelWidth == 0)
+		{
+			S32 label_width = mFont->getWidth(mLabelBox->getText());
+			LLRect rect = mLabelBox->getRect();
+			S32 prev_right = rect.mRight;
+			rect.mRight = rect.mLeft + label_width;
+			mLabelBox->setRect(rect);
+				
+			S32 delta = rect.mRight - prev_right;
+			rect = mMultiSlider->getRect();
+			S32 left = rect.mLeft + delta;
+			left = llclamp(left, 0, rect.mRight-MULTI_SLIDERCTRL_SPACING);
+			rect.mLeft = left;
+			mMultiSlider->setRect(rect);
+		}
+	}
+	return res;
+}
+
+const LLString& LLMultiSliderCtrl::addSlider()
+{
+	const LLString& name = mMultiSlider->addSlider();
+	
+	// if it returns null, pass it on
+	if(name == LLString::null) {
+		return LLString::null;
+	}
+
+	// otherwise, update stuff
+	mCurValue = mMultiSlider->getCurSliderValue();
+	updateText();
+	return name;
+}
+
+const LLString& LLMultiSliderCtrl::addSlider(F32 val)
+{
+	const LLString& name = mMultiSlider->addSlider(val);
+
+	// if it returns null, pass it on
+	if(name == LLString::null) {
+		return LLString::null;
+	}
+
+	// otherwise, update stuff
+	mCurValue = mMultiSlider->getCurSliderValue();
+	updateText();
+	return name;
+}
+
+void LLMultiSliderCtrl::deleteSlider(const LLString& name)
+{
+	mMultiSlider->deleteSlider(name);
+	mCurValue = mMultiSlider->getCurSliderValue();
+	updateText();
+}
+
+
+void LLMultiSliderCtrl::clear()
+{
+	setCurSliderValue(0.0f);
+	if( mEditor )
+	{
+		mEditor->setText(LLString(""));
+	}
+	if( mTextBox )
+	{
+		mTextBox->setText(LLString(""));
+	}
+
+	// get rid of sliders
+	mMultiSlider->clear();
+
+}
+
+BOOL LLMultiSliderCtrl::isMouseHeldDown()
+{
+	return gFocusMgr.getMouseCapture() == mMultiSlider;
+}
+
+void LLMultiSliderCtrl::updateText()
+{
+	if( mEditor || mTextBox )
+	{
+		LLLocale locale(LLLocale::USER_LOCALE);
+
+		// Don't display very small negative values as -0.000
+		F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
+
+		LLString format = llformat("%%.%df", mPrecision);
+		LLString text = llformat(format.c_str(), displayed_value);
+		if( mEditor )
+		{
+			mEditor->setText( text );
+		}
+		else
+		{
+			mTextBox->setText( text );
+		}
+	}
+}
+
+// static
+void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
+{
+	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
+	llassert( caller == self->mEditor );
+
+	BOOL success = FALSE;
+	F32 val = self->mCurValue;
+	F32 saved_val = self->mCurValue;
+
+	LLString text = self->mEditor->getText();
+	if( LLLineEditor::postvalidateFloat( text ) )
+	{
+		LLLocale locale(LLLocale::USER_LOCALE);
+		val = (F32) atof( text.c_str() );
+		if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() )
+		{
+			if( self->mValidateCallback )
+			{
+				self->setCurSliderValue( val );  // set the value temporarily so that the callback can retrieve it.
+				if( self->mValidateCallback( self, self->mCallbackUserData ) )
+				{
+					success = TRUE;
+				}
+			}
+			else
+			{
+				self->setCurSliderValue( val );
+				success = TRUE;
+			}
+		}
+	}
+
+	if( success )
+	{
+		self->onCommit();
+	}
+	else
+	{
+		if( self->getCurSliderValue() != saved_val )
+		{
+			self->setCurSliderValue( saved_val );
+		}
+		self->reportInvalidData();		
+	}
+	self->updateText();
+}
+
+// static
+void LLMultiSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata )
+{
+	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
+	//llassert( caller == self->mSlider );
+
+	BOOL success = FALSE;
+	F32 saved_val = self->mCurValue;
+	F32 new_val = self->mMultiSlider->getCurSliderValue();
+
+	if( self->mValidateCallback )
+	{
+		self->mCurValue = new_val;  // set the value temporarily so that the callback can retrieve it.
+		if( self->mValidateCallback( self, self->mCallbackUserData ) )
+		{
+			success = TRUE;
+		}
+	}
+	else
+	{
+		self->mCurValue = new_val;
+		success = TRUE;
+	}
+
+	if( success )
+	{
+		self->onCommit();
+	}
+	else
+	{
+		if( self->mCurValue != saved_val )
+		{
+			self->setCurSliderValue( saved_val );
+		}
+		self->reportInvalidData();		
+	}
+	self->updateText();
+}
+
+void LLMultiSliderCtrl::setEnabled(BOOL b)
+{
+	LLUICtrl::setEnabled( b );
+
+	if( mLabelBox )
+	{
+		mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+	}
+
+	mMultiSlider->setEnabled( b );
+
+	if( mEditor )
+	{
+		mEditor->setEnabled( b );
+	}
+
+	if( mTextBox )
+	{
+		mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+	}
+}
+
+
+void LLMultiSliderCtrl::setTentative(BOOL b)
+{
+	if( mEditor )
+	{
+		mEditor->setTentative(b);
+	}
+	LLUICtrl::setTentative(b);
+}
+
+
+void LLMultiSliderCtrl::onCommit()
+{
+	setTentative(FALSE);
+
+	if( mEditor )
+	{
+		mEditor->setTentative(FALSE);
+	}
+
+	LLUICtrl::onCommit();
+}
+
+
+void LLMultiSliderCtrl::setPrecision(S32 precision)
+{
+	if (precision < 0 || precision > 10)
+	{
+		llerrs << "LLMultiSliderCtrl::setPrecision - precision out of range" << llendl;
+		return;
+	}
+
+	mPrecision = precision;
+	updateText();
+}
+
+void LLMultiSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
+{
+	mSliderMouseDownCallback = slider_mousedown_callback;
+	mMultiSlider->setMouseDownCallback( LLMultiSliderCtrl::onSliderMouseDown );
+}
+
+// static
+void LLMultiSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
+{
+	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
+	if( self->mSliderMouseDownCallback )
+	{
+		self->mSliderMouseDownCallback( self, self->mCallbackUserData );
+	}
+}
+
+
+void LLMultiSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
+{
+	mSliderMouseUpCallback = slider_mouseup_callback;
+	mMultiSlider->setMouseUpCallback( LLMultiSliderCtrl::onSliderMouseUp );
+}
+
+// static
+void LLMultiSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
+{
+	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
+	if( self->mSliderMouseUpCallback )
+	{
+		self->mSliderMouseUpCallback( self, self->mCallbackUserData );
+	}
+}
+
+void LLMultiSliderCtrl::onTabInto()
+{
+	if( mEditor )
+	{
+		mEditor->onTabInto(); 
+	}
+}
+
+void LLMultiSliderCtrl::reportInvalidData()
+{
+	make_ui_sound("UISndBadKeystroke");
+}
+
+//virtual
+LLString LLMultiSliderCtrl::getControlName() const
+{
+	return mMultiSlider->getControlName();
+}
+
+// virtual
+void LLMultiSliderCtrl::setControlName(const LLString& control_name, LLView* context)
+{
+	mMultiSlider->setControlName(control_name, context);
+}
+
+// virtual
+LLXMLNodePtr LLMultiSliderCtrl::getXML(bool save_children) const
+{
+	LLXMLNodePtr node = LLUICtrl::getXML();
+
+	node->createChild("show_text", TRUE)->setBoolValue(mShowText);
+
+	node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText);
+
+	node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
+
+	if (mLabelBox)
+	{
+		node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
+	}
+
+	// TomY TODO: Do we really want to export the transient state of the slider?
+	node->createChild("value", TRUE)->setFloatValue(mCurValue);
+
+	if (mMultiSlider)
+	{
+		node->createChild("initial_val", TRUE)->setFloatValue(mMultiSlider->getInitialValue());
+		node->createChild("min_val", TRUE)->setFloatValue(mMultiSlider->getMinValue());
+		node->createChild("max_val", TRUE)->setFloatValue(mMultiSlider->getMaxValue());
+		node->createChild("increment", TRUE)->setFloatValue(mMultiSlider->getIncrement());
+	}
+	addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
+	addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
+
+	return node;
+}
+
+LLView* LLMultiSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+{
+	LLString name("multi_slider");
+	node->getAttributeString("name", name);
+
+	LLString label;
+	node->getAttributeString("label", label);
+
+	LLRect rect;
+	createRect(node, rect, parent, LLRect());
+
+	LLFontGL* font = LLView::selectFont(node);
+
+	// HACK: Font might not be specified.
+	if (!font)
+	{
+		font = LLFontGL::sSansSerifSmall;
+	}
+
+	S32 label_width = 0;
+	node->getAttributeS32("label_width", label_width);
+
+	BOOL show_text = TRUE;
+	node->getAttributeBOOL("show_text", show_text);
+
+	BOOL can_edit_text = FALSE;
+	node->getAttributeBOOL("can_edit_text", can_edit_text);
+	
+	BOOL allow_overlap = FALSE;
+	node->getAttributeBOOL("allow_overlap", allow_overlap);
+
+	BOOL draw_track = TRUE;
+	node->getAttributeBOOL("draw_track", draw_track);
+
+	BOOL use_triangle = FALSE;
+	node->getAttributeBOOL("use_triangle", use_triangle);
+
+	F32 initial_value = 0.f;
+	node->getAttributeF32("initial_val", initial_value);
+
+	F32 min_value = 0.f;
+	node->getAttributeF32("min_val", min_value);
+
+	F32 max_value = 1.f; 
+	node->getAttributeF32("max_val", max_value);
+
+	F32 increment = 0.1f;
+	node->getAttributeF32("increment", increment);
+
+	U32 precision = 3;
+	node->getAttributeU32("decimal_digits", precision);
+
+	S32 max_sliders = 1;
+	node->getAttributeS32("max_sliders", max_sliders);
+
+
+	S32 text_left = 0;
+	if (show_text)
+	{
+		// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
+		if ( max_value )
+			text_left = font->getWidth("0") * ( static_cast < S32 > ( log10  ( max_value ) ) + precision + 1 );
+
+		if ( increment < 1.0f )
+			text_left += font->getWidth(".");	// (mostly) take account of decimal point in value
+
+		if ( min_value < 0.0f || max_value < 0.0f )
+			text_left += font->getWidth("-");	// (mostly) take account of minus sign 
+
+		// padding to make things look nicer
+		text_left += 8;
+	}
+
+	LLUICtrlCallback callback = NULL;
+
+	if (label.empty())
+	{
+		label.assign(node->getTextContents());
+	}
+
+	LLMultiSliderCtrl* slider = new LLMultiSliderCtrl(name,
+							rect,
+							label,
+							font,
+							label_width,
+							rect.getWidth() - text_left,
+							show_text,
+							can_edit_text,
+							callback,
+							NULL,
+							initial_value,
+							min_value, 
+							max_value,
+							increment,
+							max_sliders,
+							allow_overlap,
+							draw_track,
+							use_triangle);
+
+	slider->setPrecision(precision);
+
+	slider->initFromXML(node, parent);
+
+	slider->updateText();
+	
+	return slider;
+}
diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h
new file mode 100644
index 00000000000..028f54ed5e5
--- /dev/null
+++ b/indra/llui/llmultisliderctrl.h
@@ -0,0 +1,160 @@
+/** 
+ * @file llmultisliderctrl.h
+ * @brief LLMultiSliderCtrl base class
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_MULTI_SLIDERCTRL_H
+#define LL_MULTI_SLIDERCTRL_H
+
+#include "lluictrl.h"
+#include "v4color.h"
+#include "llmultislider.h"
+#include "lltextbox.h"
+#include "llrect.h"
+
+//
+// Constants
+//
+const S32	MULTI_SLIDERCTRL_SPACING	=  4;			// space between label, slider, and text
+const S32	MULTI_SLIDERCTRL_HEIGHT		=  16;
+
+//
+// Classes
+//
+class LLFontGL;
+class LLLineEditor;
+class LLSlider;
+
+
+class LLMultiSliderCtrl : public LLUICtrl
+{
+public:
+	LLMultiSliderCtrl(const LLString& name, 
+		const LLRect& rect, 
+		const LLString& label, 
+		const LLFontGL* font,
+		S32 slider_left,
+		S32 text_left,
+		BOOL show_text,
+		BOOL can_edit_text,
+		void (*commit_callback)(LLUICtrl*, void*),
+		void* callback_userdata,
+		F32 initial_value, F32 min_value, F32 max_value, F32 increment,
+		S32 max_sliders, BOOL allow_overlap, BOOL draw_track,
+		BOOL use_triangle,
+		const LLString& control_which = LLString::null );
+
+	virtual ~LLMultiSliderCtrl();
+	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MULTI_SLIDER; }
+	virtual LLString getWidgetTag() const { return LL_MULTI_SLIDER_CTRL_TAG; }
+	virtual LLXMLNodePtr getXML(bool save_children = true) const;
+	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+
+	F32				getSliderValue(const LLString& name) const;
+	void			setSliderValue(const LLString& name, F32 v, BOOL from_event = FALSE);
+
+	virtual void	setValue(const LLSD& value );
+	virtual LLSD	getValue() const		{ return mMultiSlider->getValue(); }
+	virtual BOOL	setLabelArg( const LLString& key, const LLString& text );
+
+	const LLString& getCurSlider() const					{ return mMultiSlider->getCurSlider(); }
+	F32				getCurSliderValue() const				{ return mCurValue; }
+	void			setCurSlider(const LLString& name);		
+	void			setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); }
+
+	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
+	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal());  }
+
+	BOOL			isMouseHeldDown();
+
+	virtual void    setEnabled( BOOL b );
+	virtual void	clear();
+	virtual void	setPrecision(S32 precision);
+	void			setMinValue(F32 min_value) {mMultiSlider->setMinValue(min_value);}
+	void			setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);}
+	void			setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);}
+
+	/// for adding and deleting sliders
+	const LLString&	addSlider();
+	const LLString&	addSlider(F32 val);
+	void			deleteSlider(const LLString& name);
+	void			deleteCurSlider()			{ deleteSlider(mMultiSlider->getCurSlider()); }
+
+	F32				getMinValue() { return mMultiSlider->getMinValue(); }
+	F32				getMaxValue() { return mMultiSlider->getMaxValue(); }
+
+	void			setLabel(const LLString& label)				{ if (mLabelBox) mLabelBox->setText(label); }
+	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
+	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; }
+
+	void			setSliderMouseDownCallback(	void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) );
+	void			setSliderMouseUpCallback(	void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) );
+
+	virtual void	onTabInto();
+
+	virtual void	setTentative(BOOL b);			// marks value as tentative
+	virtual void	onCommit();						// mark not tentative, then commit
+
+	virtual void		setControlName(const LLString& control_name, LLView* context);
+	virtual LLString 	getControlName() const;
+	
+	static void		onSliderCommit(LLUICtrl* caller, void* userdata);
+	static void		onSliderMouseDown(LLUICtrl* caller,void* userdata);
+	static void		onSliderMouseUp(LLUICtrl* caller,void* userdata);
+
+	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
+	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
+	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
+
+private:
+	void			updateText();
+	void			reportInvalidData();
+
+private:
+	const LLFontGL*	mFont;
+	BOOL			mShowText;
+	BOOL			mCanEditText;
+
+	S32				mPrecision;
+	LLTextBox*		mLabelBox;
+	S32				mLabelWidth;
+
+	F32				mCurValue;
+	LLMultiSlider*	mMultiSlider;
+	LLLineEditor*	mEditor;
+	LLTextBox*		mTextBox;
+
+	LLColor4		mTextEnabledColor;
+	LLColor4		mTextDisabledColor;
+
+	void			(*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
+	void			(*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
+};
+
+#endif  // LL_MULTI_SLIDERCTRL_H
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 6c2df683e48..96417d358b6 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -188,7 +188,7 @@ class LLPanel : public LLUICtrl
 	BOOL childSetLabelArg(const LLString& id, const LLString& key, const LLStringExplicit& text);
 	BOOL childSetToolTipArg(const LLString& id, const LLString& key, const LLStringExplicit& text);
 	
-	// LLSlider / LLSpinCtrl
+	// LLSlider / LLMultiSlider / LLSpinCtrl
 	void childSetMinValue(const LLString& id, LLSD min_value);
 	void childSetMaxValue(const LLString& id, LLSD max_value);
 
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 056a94afb87..c3afb325705 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -46,6 +46,7 @@
 #include "llwindow.h"
 #include "llglheaders.h"
 #include "llcontrol.h"
+#include "llglimmediate.h"
 
 LLScrollbar::LLScrollbar(
 		const LLString& name, LLRect rect,
@@ -538,10 +539,10 @@ void LLScrollbar::draw()
 							rounded_rect_imagep, mThumbColor );
 			if (mCurGlowStrength > 0.01f)
 			{
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
 				gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), 
 							rounded_rect_imagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			}
 		}
 
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index b9d5141eb74..991ba0ed04c 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -33,6 +33,7 @@
 #include "linden_common.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 
 #include "llscrollcontainer.h"
 #include "llscrollbar.h"
@@ -459,7 +460,7 @@ void LLScrollableContainerView::draw()
 		if( mIsOpaque )
 		{
 			LLGLSNoTexture no_texture;
-			glColor4fv( mBackgroundColor.mV );
+			gGL.color4fv( mBackgroundColor.mV );
 			gl_rect_2d( mInnerRect );
 		}
 		
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 4227a347777..35e8f7300b4 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -43,6 +43,7 @@
 #include "llclipboard.h"
 #include "llfocusmgr.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llglheaders.h"
 #include "llresmgr.h"
 #include "llscrollbar.h"
@@ -280,7 +281,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 	if (mHighlightCount > 0)
 	{
 		mRoundedRectImage->bind();
-		glColor4fv(highlight_color.mV);
+		gGL.color4fv(highlight_color.mV);
 		S32 left = 0;
 		switch(mFontAlignment)
 		{
@@ -392,7 +393,7 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
 	bg_rect.stretch(LIST_BORDER_PAD, 0);
 	{
 		LLGLSNoTexture no_texture;
-		glColor4fv(bg_color.mV);
+		gGL.color4fv(bg_color.mV);
 		gl_rect_2d( bg_rect );
 	}
 
@@ -1711,7 +1712,7 @@ void LLScrollListCtrl::draw()
 		if (mBackgroundVisible)
 		{
 			LLGLSNoTexture no_texture;
-			glColor4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV );
+			gGL.color4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV );
 			gl_rect_2d(background);
 		}
 
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 6b1acfeaaa3..9ca51120fc7 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -70,8 +70,8 @@ class LLSlider : public LLUICtrl
 	F32				getMinValue() const		{ return mMinValue; }
 	F32				getMaxValue() const		{ return mMaxValue; }
 	F32				getIncrement() const	{ return mIncrement; }
-	void			setMinValue(F32 min_value) {mMinValue = min_value;}
-	void			setMaxValue(F32 max_value) {mMaxValue = max_value;}
+	void			setMinValue(F32 min_value) {mMinValue = min_value; updateThumbRect(); }
+	void			setMaxValue(F32 max_value) {mMaxValue = max_value; updateThumbRect(); }
 	void			setIncrement(F32 increment) {mIncrement = increment;}
 	void			setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
 	void			setMouseUpCallback(	void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index f154c230f45..4f96b0915c2 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -83,9 +83,9 @@ class LLSliderCtrl : public LLUICtrl
 	virtual void    setEnabled( BOOL b );
 	virtual void	clear();
 	virtual void	setPrecision(S32 precision);
-	void			setMinValue(F32 min_value)	{ mSlider->setMinValue(min_value); }
-	void			setMaxValue(F32 max_value)	{ mSlider->setMaxValue(max_value); }
-	void			setIncrement(F32 increment)	{ mSlider->setIncrement(increment); }
+	void			setMinValue(F32 min_value)  { mSlider->setMinValue(min_value); updateText(); }
+	void			setMaxValue(F32 max_value)  { mSlider->setMaxValue(max_value); updateText(); }
+	void			setIncrement(F32 increment) { mSlider->setIncrement(increment);}
 
 	F32				getMinValue() { return mSlider->getMinValue(); }
 	F32				getMaxValue() { return mSlider->getMaxValue(); }
@@ -102,7 +102,12 @@ class LLSliderCtrl : public LLUICtrl
 	virtual void	setTentative(BOOL b);			// marks value as tentative
 	virtual void	onCommit();						// mark not tentative, then commit
 
-	virtual void		setControlName(const LLString& control_name, LLView* context) { mSlider->setControlName(control_name, context); }
+	virtual void		setControlName(const LLString& control_name, LLView* context)
+	{
+		LLView::setControlName(control_name, context);
+		mSlider->setControlName(control_name, context);
+	}
+
 	virtual LLString 	getControlName() const { return mSlider->getControlName(); }
 	
 	static void		onSliderCommit(LLUICtrl* caller, void* userdata);
diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h
index 77a91f80c10..2e1c06d2c4f 100644
--- a/indra/llui/llspinctrl.h
+++ b/indra/llui/llspinctrl.h
@@ -86,6 +86,8 @@ class LLSpinCtrl
 	virtual void	setMinValue(F32 min)			{ mMinValue = min; }
 	virtual void	setMaxValue(F32 max)			{ mMaxValue = max; }
 	virtual void	setIncrement(F32 inc)			{ mIncrement = inc; }
+	virtual F32		getMinValue()			{ return mMinValue ; }
+	virtual F32 	getMaxValue()			{ return mMaxValue ; }
 
 	void			setLabel(const LLStringExplicit& label);
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 4568ebac29b..0e64c6df5c4 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -40,6 +40,7 @@
 #include "llcriticaldamp.h"
 #include "lluictrlfactory.h"
 #include "lltabcontainervertical.h"
+#include "llglimmediate.h"
 
 
 const F32 SCROLL_STEP_TIME = 0.4f;
@@ -287,15 +288,15 @@ void LLTabContainer::draw()
 			if( mIsVertical && has_scroll_arrows )
 			{
 				// Redraw the arrows so that they appears on top.
-				glPushMatrix();
-				glTranslatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
+				gGL.pushMatrix();
+				gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
 				mPrevArrowBtn->draw();
-				glPopMatrix();
+				gGL.popMatrix();
 
-				glPushMatrix();
-				glTranslatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
+				gGL.pushMatrix();
+				gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
 				mNextArrowBtn->draw();
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 		}
 
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 540283c3fea..c76576895c0 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -37,6 +37,7 @@
 
 #include "llfontgl.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llui.h"
 #include "lluictrlfactory.h"
 #include "llrect.h"
@@ -424,7 +425,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
 			else
 			{ 
 				const llwchar* str = mWText.c_str() + start_idx;
-				S32 drawn = mGLFont->maxDrawableChars(str, (F32)mTextRect.getWidth() - line_width,
+				S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width,
 													  end_idx - start_idx, mWordWrap, mAllowEmbeddedItems );
 				if( 0 == drawn && line_width == 0)
 				{
@@ -2601,7 +2602,7 @@ void LLTextEditor::drawSelectionBackground()
 			LLGLSNoTexture no_texture;
 			const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor;
 			F32 alpha = hasFocus() ? 1.f : 0.5f;
-			glColor4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
+			gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
 
 			if( selection_left_y == selection_right_y )
 			{
@@ -2729,7 +2730,7 @@ void LLTextEditor::drawCursor()
 				
 				LLGLSNoTexture no_texture;
 
-				glColor4fv( mCursorColor.mV );
+				gGL.color4fv( mCursorColor.mV );
 				
 				gl_rect_2d(llfloor(cursor_left), llfloor(cursor_top),
 					llfloor(cursor_right), llfloor(cursor_bottom));
@@ -2750,7 +2751,6 @@ void LLTextEditor::drawCursor()
 					{
 						text_color = mFgColor;
 					}
-					LLGLSTexture texture;
 					mGLFont->render(text, mCursorPos, next_char_left, cursor_bottom + line_height, 
 						LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f),
 						LLFontGL::LEFT, LLFontGL::TOP,
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index ad523db78b2..aed7893df7a 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -42,6 +42,7 @@
 #include "v2math.h"
 #include "v4color.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llrect.h"
 #include "llimagegl.h"
 //#include "llviewerimage.h"
@@ -148,26 +149,26 @@ void gl_draw_x(const LLRect& rect, const LLColor4& color)
 {
 	LLGLSNoTexture no_texture;
 
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 
-	glBegin( GL_LINES );
-		glVertex2i( rect.mLeft,		rect.mTop );
-		glVertex2i( rect.mRight,	rect.mBottom );
-		glVertex2i( rect.mLeft,		rect.mBottom );
-		glVertex2i( rect.mRight,	rect.mTop );
-	glEnd();
+	gGL.begin( GL_LINES );
+		gGL.vertex2i( rect.mLeft,		rect.mTop );
+		gGL.vertex2i( rect.mRight,	rect.mBottom );
+		gGL.vertex2i( rect.mLeft,		rect.mBottom );
+		gGL.vertex2i( rect.mRight,	rect.mTop );
+	gGL.end();
 }
 
 
 void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled)
 {
-	glColor4fv(color.mV);
+	gGL.color4fv(color.mV);
 	gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled);
 }
 
 void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled)
 {
-	glPushMatrix();
+	gGL.pushMatrix();
 	left += LLFontGL::sCurOrigin.mX;
 	right += LLFontGL::sCurOrigin.mX;
 	bottom += LLFontGL::sCurOrigin.mY;
@@ -179,7 +180,7 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixe
 				llfloor((F32)right * LLUI::sGLScaleFactor.mV[VX]) + pixel_offset,
 				llfloor((F32)bottom * LLUI::sGLScaleFactor.mV[VY]) - pixel_offset,
 				filled);
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 
@@ -191,48 +192,48 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
 	// Counterclockwise quad will face the viewer
 	if( filled )
 	{
-		glBegin( GL_QUADS );
-			glVertex2i(left, top);
-			glVertex2i(left, bottom);
-			glVertex2i(right, bottom);
-			glVertex2i(right, top);
-		glEnd();
+		gGL.begin( GL_QUADS );
+			gGL.vertex2i(left, top);
+			gGL.vertex2i(left, bottom);
+			gGL.vertex2i(right, bottom);
+			gGL.vertex2i(right, top);
+		gGL.end();
 	}
 	else
 	{
 		if( gGLManager.mATIOffsetVerticalLines )
 		{
 			// Work around bug in ATI driver: vertical lines are offset by (-1,-1)
-			glBegin( GL_LINES );
+			gGL.begin( GL_LINES );
 
 				// Verticals 
-				glVertex2i(left + 1, top);
-				glVertex2i(left + 1, bottom);
+				gGL.vertex2i(left + 1, top);
+				gGL.vertex2i(left + 1, bottom);
 
-				glVertex2i(right, bottom);
-				glVertex2i(right, top);
+				gGL.vertex2i(right, bottom);
+				gGL.vertex2i(right, top);
 
 				// Horizontals
 				top--;
 				right--;
-				glVertex2i(left, bottom);
-				glVertex2i(right, bottom);
+				gGL.vertex2i(left, bottom);
+				gGL.vertex2i(right, bottom);
 
-				glVertex2i(left, top);
-				glVertex2i(right, top);
-			glEnd();
+				gGL.vertex2i(left, top);
+				gGL.vertex2i(right, top);
+			gGL.end();
 		}
 		else
 		{
 			top--;
 			right--;
-			glBegin( GL_LINE_STRIP );
-				glVertex2i(left, top);
-				glVertex2i(left, bottom);
-				glVertex2i(right, bottom);
-				glVertex2i(right, top);
-				glVertex2i(left, top);
-			glEnd();
+			gGL.begin( GL_LINE_STRIP );
+				gGL.vertex2i(left, top);
+				gGL.vertex2i(left, bottom);
+				gGL.vertex2i(right, bottom);
+				gGL.vertex2i(right, top);
+				gGL.vertex2i(left, top);
+			gGL.end();
 		}
 	}
 	stop_glerror();
@@ -240,14 +241,14 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled )
 
 void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled )
 {
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 	gl_rect_2d( left, top, right, bottom, filled );
 }
 
 
 void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled )
 {
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 	gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled );
 }
 
@@ -267,52 +268,52 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st
 	LLColor4 end_color = start_color;
 	end_color.mV[VALPHA] = 0.f;
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 
 	// Right edge, CCW faces screen
-	glColor4fv(start_color.mV);
-	glVertex2i(right,		top-lines);
-	glVertex2i(right,		bottom);
-	glColor4fv(end_color.mV);
-	glVertex2i(right+lines, bottom);
-	glVertex2i(right+lines, top-lines);
+	gGL.color4fv(start_color.mV);
+	gGL.vertex2i(right,		top-lines);
+	gGL.vertex2i(right,		bottom);
+	gGL.color4fv(end_color.mV);
+	gGL.vertex2i(right+lines, bottom);
+	gGL.vertex2i(right+lines, top-lines);
 
 	// Bottom edge, CCW faces screen
-	glColor4fv(start_color.mV);
-	glVertex2i(right,		bottom);
-	glVertex2i(left+lines,	bottom);
-	glColor4fv(end_color.mV);
-	glVertex2i(left+lines,	bottom-lines);
-	glVertex2i(right,		bottom-lines);
+	gGL.color4fv(start_color.mV);
+	gGL.vertex2i(right,		bottom);
+	gGL.vertex2i(left+lines,	bottom);
+	gGL.color4fv(end_color.mV);
+	gGL.vertex2i(left+lines,	bottom-lines);
+	gGL.vertex2i(right,		bottom-lines);
 
 	// bottom left Corner
-	glColor4fv(start_color.mV);
-	glVertex2i(left+lines,	bottom);
-	glColor4fv(end_color.mV);
-	glVertex2i(left,		bottom);
+	gGL.color4fv(start_color.mV);
+	gGL.vertex2i(left+lines,	bottom);
+	gGL.color4fv(end_color.mV);
+	gGL.vertex2i(left,		bottom);
 	// make the bottom left corner not sharp
-	glVertex2i(left+1,		bottom-lines+1);
-	glVertex2i(left+lines,	bottom-lines);
+	gGL.vertex2i(left+1,		bottom-lines+1);
+	gGL.vertex2i(left+lines,	bottom-lines);
 
 	// bottom right corner
-	glColor4fv(start_color.mV);
-	glVertex2i(right,		bottom);
-	glColor4fv(end_color.mV);
-	glVertex2i(right,		bottom-lines);
+	gGL.color4fv(start_color.mV);
+	gGL.vertex2i(right,		bottom);
+	gGL.color4fv(end_color.mV);
+	gGL.vertex2i(right,		bottom-lines);
 	// make the rightmost corner not sharp
-	glVertex2i(right+lines-1,	bottom-lines+1);
-	glVertex2i(right+lines,	bottom);
+	gGL.vertex2i(right+lines-1,	bottom-lines+1);
+	gGL.vertex2i(right+lines,	bottom);
 
 	// top right corner
-	glColor4fv(start_color.mV);
-	glVertex2i( right,			top-lines );
-	glColor4fv(end_color.mV);
-	glVertex2i( right+lines,	top-lines );
+	gGL.color4fv(start_color.mV);
+	gGL.vertex2i( right,			top-lines );
+	gGL.color4fv(end_color.mV);
+	gGL.vertex2i( right+lines,	top-lines );
 	// make the corner not sharp
-	glVertex2i( right+lines-1,	top-1 );
-	glVertex2i( right,			top );
+	gGL.vertex2i( right+lines-1,	top-1 );
+	gGL.vertex2i( right,			top );
 
-	glEnd();
+	gGL.end();
 	stop_glerror();
 }
 
@@ -329,10 +330,10 @@ void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 )
 
 	LLGLSNoTexture no_texture;
 	
-	glBegin(GL_LINES);
-		glVertex2i(x1, y1);
-		glVertex2i(x2, y2);
-	glEnd();
+	gGL.begin(GL_LINES);
+		gGL.vertex2i(x1, y1);
+		gGL.vertex2i(x2, y2);
+	gGL.end();
 }
 
 void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
@@ -348,32 +349,32 @@ void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color )
 
 	LLGLSNoTexture no_texture;
 
-	glColor4fv( color.mV );
+	gGL.color4fv( color.mV );
 
-	glBegin(GL_LINES);
-		glVertex2i(x1, y1);
-		glVertex2i(x2, y2);
-	glEnd();
+	gGL.begin(GL_LINES);
+		gGL.vertex2i(x1, y1);
+		gGL.vertex2i(x2, y2);
+	gGL.end();
 }
 
 void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled)
 {
 	LLGLSNoTexture no_texture;
 
-	glColor4fv(color.mV);
+	gGL.color4fv(color.mV);
 
 	if (filled)
 	{
-		glBegin(GL_TRIANGLES);
+		gGL.begin(GL_TRIANGLES);
 	}
 	else
 	{
-		glBegin(GL_LINE_LOOP);
+		gGL.begin(GL_LINE_LOOP);
 	}
-	glVertex2i(x1, y1);
-	glVertex2i(x2, y2);
-	glVertex2i(x3, y3);
-	glEnd();
+	gGL.vertex2i(x1, y1);
+	gGL.vertex2i(x2, y2);
+	gGL.vertex2i(x3, y3);
+	gGL.end();
 }
 
 void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac)
@@ -382,31 +383,31 @@ void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max
 
 	length = llmin((S32)(max_frac*(right - left)), length);
 	length = llmin((S32)(max_frac*(top - bottom)), length);
-	glBegin(GL_LINES);
-	glVertex2i(left, top);
-	glVertex2i(left + length, top);
+	gGL.begin(GL_LINES);
+	gGL.vertex2i(left, top);
+	gGL.vertex2i(left + length, top);
 	
-	glVertex2i(left, top);
-	glVertex2i(left, top - length);
+	gGL.vertex2i(left, top);
+	gGL.vertex2i(left, top - length);
 
-	glVertex2i(left, bottom);
-	glVertex2i(left + length, bottom);
+	gGL.vertex2i(left, bottom);
+	gGL.vertex2i(left + length, bottom);
 	
-	glVertex2i(left, bottom);
-	glVertex2i(left, bottom + length);
+	gGL.vertex2i(left, bottom);
+	gGL.vertex2i(left, bottom + length);
 
-	glVertex2i(right, top);
-	glVertex2i(right - length, top);
+	gGL.vertex2i(right, top);
+	gGL.vertex2i(right - length, top);
 
-	glVertex2i(right, top);
-	glVertex2i(right, top - length);
+	gGL.vertex2i(right, top);
+	gGL.vertex2i(right, top - length);
 
-	glVertex2i(right, bottom);
-	glVertex2i(right - length, bottom);
+	gGL.vertex2i(right, bottom);
+	gGL.vertex2i(right - length, bottom);
 
-	glVertex2i(right, bottom);
-	glVertex2i(right, bottom + length);
-	glEnd();
+	gGL.vertex2i(right, bottom);
+	gGL.vertex2i(right, bottom + length);
+	gGL.end();
 }
 
 
@@ -499,136 +500,136 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLIma
 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB,	GL_SRC_ALPHA);
 	}
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef((F32)x, (F32)y, 0.f);
+		gGL.translatef((F32)x, (F32)y, 0.f);
 
 		image->bind();
 
-		glColor4fv(color.mV);
+		gGL.color4fv(color.mV);
 		
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		{
 			// draw bottom left
-			glTexCoord2d(uv_rect.mLeft, uv_rect.mBottom);
-			glVertex2i(0, 0);
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+			gGL.vertex2i(0, 0);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, 0);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, 0);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(0, draw_scale_rect.mBottom);
+			gGL.texCoord2f(uv_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(0, draw_scale_rect.mBottom);
 
 			// draw bottom middle
-			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, 0);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, 0);
 
-			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, 0);
+			gGL.texCoord2f(clipped_scale_rect.mRight, uv_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, 0);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
 			// draw bottom right
-			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, 0);
+			gGL.texCoord2f(clipped_scale_rect.mRight, uv_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, 0);
 
-			glTexCoord2d(uv_rect.mRight, uv_rect.mBottom);
-			glVertex2i(width, 0);
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+			gGL.vertex2i(width, 0);
 
-			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(width, draw_scale_rect.mBottom);
+			gGL.texCoord2f(uv_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(width, draw_scale_rect.mBottom);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
 			// draw left 
-			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(0, draw_scale_rect.mBottom);
+			gGL.texCoord2f(uv_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(0, draw_scale_rect.mBottom);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(0, draw_scale_rect.mTop);
+			gGL.texCoord2f(uv_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(0, draw_scale_rect.mTop);
 
 			// draw middle
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
 			// draw right 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
-			glVertex2i(width, draw_scale_rect.mBottom);
+			gGL.texCoord2f(uv_rect.mRight, clipped_scale_rect.mBottom);
+			gGL.vertex2i(width, draw_scale_rect.mBottom);
 
-			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(width, draw_scale_rect.mTop);
+			gGL.texCoord2f(uv_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(width, draw_scale_rect.mTop);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
 			// draw top left
-			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(0, draw_scale_rect.mTop);
+			gGL.texCoord2f(uv_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(0, draw_scale_rect.mTop);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, height);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, height);
 
-			glTexCoord2d(uv_rect.mLeft, uv_rect.mTop);
-			glVertex2i(0, height);
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+			gGL.vertex2i(0, height);
 
 			// draw top middle
-			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, height);
+			gGL.texCoord2f(clipped_scale_rect.mRight, uv_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, height);
 
-			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
-			glVertex2i(draw_scale_rect.mLeft, height);
+			gGL.texCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mLeft, height);
 
 			// draw top right
-			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+			gGL.texCoord2f(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
-			glVertex2i(width, draw_scale_rect.mTop);
+			gGL.texCoord2f(uv_rect.mRight, clipped_scale_rect.mTop);
+			gGL.vertex2i(width, draw_scale_rect.mTop);
 
-			glTexCoord2d(uv_rect.mRight, uv_rect.mTop);
-			glVertex2i(width, height);
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+			gGL.vertex2i(width, height);
 
-			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
-			glVertex2i(draw_scale_rect.mRight, height);
+			gGL.texCoord2f(clipped_scale_rect.mRight, uv_rect.mTop);
+			gGL.vertex2i(draw_scale_rect.mRight, height);
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 
 	if (solid_color)
 	{
@@ -651,39 +652,39 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 	LLGLSUIDefault gls_ui;
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef((F32)x, (F32)y, 0.f);
+		gGL.translatef((F32)x, (F32)y, 0.f);
 		if( degrees )
 		{
 			F32 offset_x = F32(width/2);
 			F32 offset_y = F32(height/2);
-			glTranslatef( offset_x, offset_y, 0.f);
+			gGL.translatef( offset_x, offset_y, 0.f);
 			glRotatef( degrees, 0.f, 0.f, 1.f );
-			glTranslatef( -offset_x, -offset_y, 0.f );
+			gGL.translatef( -offset_x, -offset_y, 0.f );
 		}
 
 		image->bind();
 
-		glColor4fv(color.mV);
+		gGL.color4fv(color.mV);
 		
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		{
-			glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
-			glVertex2i(width, height );
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+			gGL.vertex2i(width, height );
 
-			glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
-			glVertex2i(0, height );
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+			gGL.vertex2i(0, height );
 
-			glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-			glVertex2i(0, 0);
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+			gGL.vertex2i(0, 0);
 
-			glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
-			glVertex2i(width, 0);
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+			gGL.vertex2i(width, 0);
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 
@@ -697,31 +698,31 @@ void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageG
 
 	LLGLSUIDefault gls_ui;
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef((F32)x, (F32)y, 0.f);
+		gGL.translatef((F32)x, (F32)y, 0.f);
 
 		image->bind();
 
-		glColor4fv(color.mV);
+		gGL.color4fv(color.mV);
 		
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		{
-			glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
-			glVertex2i(width, height );
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
+			gGL.vertex2i(width, height );
 
-			glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-			glVertex2i(0, height );
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
+			gGL.vertex2i(0, height );
 
-			glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
-			glVertex2i(0, 0);
+			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
+			gGL.vertex2i(0, 0);
 
-			glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
-			glVertex2i(width, 0);
+			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
+			gGL.vertex2i(width, 0);
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 
@@ -734,16 +735,18 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 	// Stippled line
 	LLGLEnable stipple(GL_LINE_STIPPLE);
 	
-	glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
+	gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]);
+
+	gGL.flush();
 	glLineWidth(2.5f);
 	glLineStipple(2, 0x3333 << shift);
 
-	glBegin(GL_LINES);
+	gGL.begin(GL_LINES);
 	{
-		glVertex3fv( start.mV );
-		glVertex3fv( end.mV );
+		gGL.vertex3fv( start.mV );
+		gGL.vertex3fv( end.mV );
 	}
-	glEnd();
+	gGL.end();
 
 	LLUI::setLineWidth(1.f);
 }
@@ -751,16 +754,16 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 
 void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom)
 {
-	glColor4fv( LLColor4::white.mV );
+	gGL.color4fv( LLColor4::white.mV );
 	glLogicOp( GL_XOR );
 	stop_glerror();
 
-	glBegin(GL_QUADS);
-		glVertex2i(left, top);
-		glVertex2i(left, bottom);
-		glVertex2i(right, bottom);
-		glVertex2i(right, top);
-	glEnd();
+	gGL.begin(GL_QUADS);
+		gGL.vertex2i(left, top);
+		gGL.vertex2i(left, bottom);
+		gGL.vertex2i(right, bottom);
+		gGL.vertex2i(right, top);
+	gGL.end();
 
 	glLogicOp( GL_COPY );
 	stop_glerror();
@@ -774,9 +777,9 @@ void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F
 		end_angle += F_TWO_PI;
 	}
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef(center_x, center_y, 0.f);
+		gGL.translatef(center_x, center_y, 0.f);
 
 		// Inexact, but reasonably fast.
 		F32 delta = (end_angle - start_angle) / steps;
@@ -787,35 +790,35 @@ void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F
 
 		if (filled)
 		{
-			glBegin(GL_TRIANGLE_FAN);
-			glVertex2f(0.f, 0.f);
+			gGL.begin(GL_TRIANGLE_FAN);
+			gGL.vertex2f(0.f, 0.f);
 			// make sure circle is complete
 			steps += 1;
 		}
 		else
 		{
-			glBegin(GL_LINE_STRIP);
+			gGL.begin(GL_LINE_STRIP);
 		}
 
 		while( steps-- )
 		{
 			// Successive rotations
-			glVertex2f( x, y );
+			gGL.vertex2f( x, y );
 			F32 x_new = x * cos_delta - y * sin_delta;
 			y = x * sin_delta +  y * cos_delta;
 			x = x_new;
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled)
 {
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
 		LLGLSNoTexture gls_no_texture;
-		glTranslatef(center_x, center_y, 0.f);
+		gGL.translatef(center_x, center_y, 0.f);
 
 		// Inexact, but reasonably fast.
 		F32 delta = F_TWO_PI / steps;
@@ -826,27 +829,27 @@ void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled
 
 		if (filled)
 		{
-			glBegin(GL_TRIANGLE_FAN);
-			glVertex2f(0.f, 0.f);
+			gGL.begin(GL_TRIANGLE_FAN);
+			gGL.vertex2f(0.f, 0.f);
 			// make sure circle is complete
 			steps += 1;
 		}
 		else
 		{
-			glBegin(GL_LINE_LOOP);
+			gGL.begin(GL_LINE_LOOP);
 		}
 
 		while( steps-- )
 		{
 			// Successive rotations
-			glVertex2f( x, y );
+			gGL.vertex2f( x, y );
 			F32 x_new = x * cos_delta - y * sin_delta;
 			y = x * sin_delta +  y * cos_delta;
 			x = x_new;
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 // Renders a ring with sides (tube shape)
@@ -855,40 +858,40 @@ void gl_deep_circle( F32 radius, F32 depth, S32 steps )
 	F32 x = radius;
 	F32 y = 0.f;
 	F32 angle_delta = F_TWO_PI / (F32)steps;
-	glBegin( GL_TRIANGLE_STRIP  );
+	gGL.begin( GL_TRIANGLE_STRIP  );
 	{
 		S32 step = steps + 1; // An extra step to close the circle.
 		while( step-- )
 		{
-			glVertex3f( x, y, depth );
-			glVertex3f( x, y, 0.f );
+			gGL.vertex3f( x, y, depth );
+			gGL.vertex3f( x, y, 0.f );
 
 			F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta);
 			y = x * sinf(angle_delta) +  y * cosf(angle_delta);
 			x = x_new;
 		}
 	}
-	glEnd();
+	gGL.end();
 }
 
 void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center )
 {
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef(0.f, 0.f, -width / 2);
+		gGL.translatef(0.f, 0.f, -width / 2);
 		if( render_center )
 		{
-			glColor4fv(center_color.mV);
+			gGL.color4fv(center_color.mV);
 			gl_deep_circle( radius, width, steps );
 		}
 		else
 		{
 			gl_washer_2d(radius, radius - width, steps, side_color, side_color);
-			glTranslatef(0.f, 0.f, width);
+			gGL.translatef(0.f, 0.f, width);
 			gl_washer_2d(radius - width, radius, steps, side_color, side_color);
 		}
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 // Draw gray and white checkerboard with black border
@@ -913,15 +916,17 @@ void gl_rect_2d_checkerboard(const LLRect& rect)
 	LLGLSNoTexture gls_no_texture;
 
 	// ...white squares
-	glColor3f( 1.f, 1.f, 1.f );
+	gGL.color3f( 1.f, 1.f, 1.f );
 	gl_rect_2d(rect);
 
 	// ...gray squares
-	glColor3f( .7f, .7f, .7f );
+	gGL.color3f( .7f, .7f, .7f );
+	gGL.flush();
 	glPolygonStipple( checkerboard );
 
 	LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE);
 	gl_rect_2d(rect);
+	gGL.flush();
 }
 
 
@@ -940,15 +945,15 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4&
 
 	LLGLSNoTexture gls_no_texture;
 
-	glBegin( GL_TRIANGLE_STRIP  );
+	gGL.begin( GL_TRIANGLE_STRIP  );
 	{
 		steps += 1; // An extra step to close the circle.
 		while( steps-- )
 		{
-			glColor4fv(outer_color.mV);
-			glVertex2f( x1, y1 );
-			glColor4fv(inner_color.mV);
-			glVertex2f( x2, y2 );
+			gGL.color4fv(outer_color.mV);
+			gGL.vertex2f( x1, y1 );
+			gGL.color4fv(inner_color.mV);
+			gGL.vertex2f( x2, y2 );
 
 			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
 			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
@@ -959,7 +964,7 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4&
 			x2 = x2_new;
 		}
 	}
-	glEnd();
+	gGL.end();
 }
 
 // Draws the area between two concentric circles, like
@@ -976,15 +981,15 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
 	F32 y2 = inner_radius * sin( start_radians );
 
 	LLGLSNoTexture gls_no_texture;
-	glBegin( GL_TRIANGLE_STRIP  );
+	gGL.begin( GL_TRIANGLE_STRIP  );
 	{
 		steps += 1; // An extra step to close the circle.
 		while( steps-- )
 		{
-			glColor4fv(outer_color.mV);
-			glVertex2f( x1, y1 );
-			glColor4fv(inner_color.mV);
-			glVertex2f( x2, y2 );
+			gGL.color4fv(outer_color.mV);
+			gGL.vertex2f( x1, y1 );
+			gGL.color4fv(inner_color.mV);
+			gGL.vertex2f( x2, y2 );
 
 			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
 			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
@@ -995,7 +1000,7 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
 			x2 = x2_new;
 		}
 	}
-	glEnd();
+	gGL.end();
 }
 
 // Draws spokes around a circle.
@@ -1013,14 +1018,14 @@ void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LL
 
 	LLGLSNoTexture gls_no_texture;
 
-	glBegin( GL_LINES  );
+	gGL.begin( GL_LINES  );
 	{
 		while( count-- )
 		{
-			glColor4fv(outer_color.mV);
-			glVertex2f( x1, y1 );
-			glColor4fv(inner_color.mV);
-			glVertex2f( x2, y2 );
+			gGL.color4fv(outer_color.mV);
+			gGL.vertex2f( x1, y1 );
+			gGL.color4fv(inner_color.mV);
+			gGL.vertex2f( x2, y2 );
 
 			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
 			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
@@ -1031,36 +1036,36 @@ void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LL
 			x2 = x2_new;
 		}
 	}
-	glEnd();
+	gGL.end();
 }
 
 void gl_rect_2d_simple_tex( S32 width, S32 height )
 {
-	glBegin( GL_QUADS );
+	gGL.begin( GL_QUADS );
 
-		glTexCoord2f(1.f, 1.f);
-		glVertex2i(width, height);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex2i(width, height);
 
-		glTexCoord2f(0.f, 1.f);
-		glVertex2i(0, height);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex2i(0, height);
 
-		glTexCoord2f(0.f, 0.f);
-		glVertex2i(0, 0);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex2i(0, 0);
 
-		glTexCoord2f(1.f, 0.f);
-		glVertex2i(width, 0);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex2i(width, 0);
 	
-	glEnd();
+	gGL.end();
 }
 
 void gl_rect_2d_simple( S32 width, S32 height )
 {
-	glBegin( GL_QUADS );
-		glVertex2i(width, height);
-		glVertex2i(0, height);
-		glVertex2i(0, 0);
-		glVertex2i(width, 0);
-	glEnd();
+	gGL.begin( GL_QUADS );
+		gGL.vertex2i(width, height);
+		gGL.vertex2i(0, height);
+		gGL.vertex2i(0, 0);
+		gGL.vertex2i(width, 0);
+	gGL.end();
 }
 
 void gl_segmented_rect_2d_tex(const S32 left, 
@@ -1075,9 +1080,9 @@ void gl_segmented_rect_2d_tex(const S32 left,
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
 
-	glPushMatrix();
+	gGL.pushMatrix();
 
-	glTranslatef((F32)left, (F32)bottom, 0.f);
+	gGL.translatef((F32)left, (F32)bottom, 0.f);
 	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
 
 	if (border_uv_scale.mV[VX] > 0.5f)
@@ -1097,128 +1102,128 @@ void gl_segmented_rect_2d_tex(const S32 left,
 	LLVector2 width_vec((F32)width, 0.f);
 	LLVector2 height_vec(0.f, (F32)height);
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
 		// draw bottom left
-		glTexCoord2f(0.f, 0.f);
-		glVertex2f(0.f, 0.f);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex2f(0.f, 0.f);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 0.f);
-		glVertex2fv(border_width_left.mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+		gGL.vertex2fv(border_width_left.mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + border_height_bottom).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
 
-		glTexCoord2f(0.f, border_uv_scale.mV[VY]);
-		glVertex2fv(border_height_bottom.mV);
+		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
+		gGL.vertex2fv(border_height_bottom.mV);
 
 		// draw bottom middle
-		glTexCoord2f(border_uv_scale.mV[VX], 0.f);
-		glVertex2fv(border_width_left.mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+		gGL.vertex2fv(border_width_left.mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
-		glVertex2fv((width_vec - border_width_right).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+		gGL.vertex2fv((width_vec - border_width_right).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + border_height_bottom).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
 
 		// draw bottom right
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
-		glVertex2fv((width_vec - border_width_right).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+		gGL.vertex2fv((width_vec - border_width_right).mV);
 
-		glTexCoord2f(1.f, 0.f);
-		glVertex2fv(width_vec.mV);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex2fv(width_vec.mV);
 
-		glTexCoord2f(1.f, border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec + border_height_bottom).mV);
+		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec + border_height_bottom).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
 
 		// draw left 
-		glTexCoord2f(0.f, border_uv_scale.mV[VY]);
-		glVertex2fv(border_height_bottom.mV);
+		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]);
+		gGL.vertex2fv(border_height_bottom.mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + border_height_bottom).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
 
-		glTexCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((height_vec - border_height_top).mV);
+		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((height_vec - border_height_top).mV);
 
 		// draw middle
-		glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + border_height_bottom).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + border_height_bottom).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
 
 		// draw right 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + border_height_bottom).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV);
 
-		glTexCoord2f(1.f, border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec + border_height_bottom).mV);
+		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec + border_height_bottom).mV);
 
-		glTexCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
 
 		// draw top left
-		glTexCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((height_vec - border_height_top).mV);
+		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((height_vec - border_height_top).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f);
-		glVertex2fv((border_width_left + height_vec).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+		gGL.vertex2fv((border_width_left + height_vec).mV);
 
-		glTexCoord2f(0.f, 1.f);
-		glVertex2fv((height_vec).mV);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex2fv((height_vec).mV);
 
 		// draw top middle
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((border_width_left + height_vec - border_height_top).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
-		glVertex2fv((width_vec - border_width_right + height_vec).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
 
-		glTexCoord2f(border_uv_scale.mV[VX], 1.f);
-		glVertex2fv((border_width_left + height_vec).mV);
+		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+		gGL.vertex2fv((border_width_left + height_vec).mV);
 
 		// draw top right
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV);
 
-		glTexCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
-		glVertex2fv((width_vec + height_vec - border_height_top).mV);
+		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]);
+		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV);
 
-		glTexCoord2f(1.f, 1.f);
-		glVertex2fv((width_vec + height_vec).mV);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex2fv((width_vec + height_vec).mV);
 
-		glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
-		glVertex2fv((width_vec - border_width_right + height_vec).mV);
+		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV);
 	}
-	glEnd();
+	gGL.end();
 
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 void gl_segmented_rect_2d_fragment_tex(const S32 left, 
@@ -1235,9 +1240,9 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
 	S32 width = llabs(right - left);
 	S32 height = llabs(top - bottom);
 
-	glPushMatrix();
+	gGL.pushMatrix();
 
-	glTranslatef((F32)left, (F32)bottom, 0.f);
+	gGL.translatef((F32)left, (F32)bottom, 0.f);
 	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height);
 
 	if (border_uv_scale.mV[VX] > 0.5f)
@@ -1265,7 +1270,7 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
 	LLVector2 x_min;
 	LLVector2 x_max;
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
 		if (start_fragment < middle_start)
 		{
@@ -1275,43 +1280,43 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
 			x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left;
 
 			// draw bottom left
-			glTexCoord2f(u_min, 0.f);
-			glVertex2fv(x_min.mV);
+			gGL.texCoord2f(u_min, 0.f);
+			gGL.vertex2fv(x_min.mV);
 
-			glTexCoord2f(border_uv_scale.mV[VX], 0.f);
-			glVertex2fv(x_max.mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+			gGL.vertex2fv(x_max.mV);
 
-			glTexCoord2f(u_max, border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(u_min, border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
 			// draw left 
-			glTexCoord2f(u_min, border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
-			glTexCoord2f(u_max, border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 			
 			// draw top left
-			glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_max, 1.f);
-			glVertex2fv((x_max + height_vec).mV);
+			gGL.texCoord2f(u_max, 1.f);
+			gGL.vertex2fv((x_max + height_vec).mV);
 
-			glTexCoord2f(u_min, 1.f);
-			glVertex2fv((x_min + height_vec).mV);
+			gGL.texCoord2f(u_min, 1.f);
+			gGL.vertex2fv((x_min + height_vec).mV);
 		}
 
 		if (end_fragment > middle_start || start_fragment < middle_end)
@@ -1320,43 +1325,43 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
 			x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec;
 
 			// draw bottom middle
-			glTexCoord2f(border_uv_scale.mV[VX], 0.f);
-			glVertex2fv(x_min.mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f);
+			gGL.vertex2fv(x_min.mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
-			glVertex2fv((x_max).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f);
+			gGL.vertex2fv((x_max).mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
 			// draw middle
-			glTexCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 
 			// draw top middle
-			glTexCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
-			glVertex2fv((x_max + height_vec).mV);
+			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f);
+			gGL.vertex2fv((x_max + height_vec).mV);
 
-			glTexCoord2f(border_uv_scale.mV[VX], 1.f);
-			glVertex2fv((x_min + height_vec).mV);
+			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f);
+			gGL.vertex2fv((x_min + height_vec).mV);
 		}
 
 		if (end_fragment > middle_end)
@@ -1367,48 +1372,48 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
 			x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right);
 
 			// draw bottom right
-			glTexCoord2f(u_min, 0.f);
-			glVertex2fv((x_min).mV);
+			gGL.texCoord2f(u_min, 0.f);
+			gGL.vertex2fv((x_min).mV);
 
-			glTexCoord2f(u_max, 0.f);
-			glVertex2fv(x_max.mV);
+			gGL.texCoord2f(u_max, 0.f);
+			gGL.vertex2fv(x_max.mV);
 
-			glTexCoord2f(u_max, border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(u_min, border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
 			// draw right 
-			glTexCoord2f(u_min, border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + border_height_bottom).mV);
+			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + border_height_bottom).mV);
 
-			glTexCoord2f(u_max, border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + border_height_bottom).mV);
+			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + border_height_bottom).mV);
 
-			glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 
 			// draw top right
-			glTexCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_min + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_min + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
-			glVertex2fv((x_max + height_vec - border_height_top).mV);
+			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]);
+			gGL.vertex2fv((x_max + height_vec - border_height_top).mV);
 
-			glTexCoord2f(u_max, 1.f);
-			glVertex2fv((x_max + height_vec).mV);
+			gGL.texCoord2f(u_max, 1.f);
+			gGL.vertex2fv((x_max + height_vec).mV);
 
-			glTexCoord2f(u_min, 1.f);
-			glVertex2fv((x_min + height_vec).mV);
+			gGL.texCoord2f(u_min, 1.f);
+			gGL.vertex2fv((x_min + height_vec).mV);
 		}
 	}
-	glEnd();
+	gGL.end();
 
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, 
@@ -1421,126 +1426,128 @@ void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& bo
 	LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero;
 	LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero;
 
-	glBegin(GL_QUADS);
+
+	gGL.begin(GL_QUADS);
 	{
 		// draw bottom left
-		glTexCoord2f(0.f, 0.f);
-		glVertex3f(0.f, 0.f, 0.f);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex3f(0.f, 0.f, 0.f);
 
-		glTexCoord2f(border_scale.mV[VX], 0.f);
-		glVertex3fv(left_border_width.mV);
+		gGL.texCoord2f(border_scale.mV[VX], 0.f);
+		gGL.vertex3fv(left_border_width.mV);
 
-		glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((left_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(0.f, border_scale.mV[VY]);
-		glVertex3fv(bottom_border_height.mV);
+		gGL.texCoord2f(0.f, border_scale.mV[VY]);
+		gGL.vertex3fv(bottom_border_height.mV);
 
 		// draw bottom middle
-		glTexCoord2f(border_scale.mV[VX], 0.f);
-		glVertex3fv(left_border_width.mV);
+		gGL.texCoord2f(border_scale.mV[VX], 0.f);
+		gGL.vertex3fv(left_border_width.mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 0.f);
-		glVertex3fv((width_vec - right_border_width).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
+		gGL.vertex3fv((width_vec - right_border_width).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((left_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
 
 		// draw bottom right
-		glTexCoord2f(1.f - border_scale.mV[VX], 0.f);
-		glVertex3fv((width_vec - right_border_width).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
+		gGL.vertex3fv((width_vec - right_border_width).mV);
 
-		glTexCoord2f(1.f, 0.f);
-		glVertex3fv(width_vec.mV);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex3fv(width_vec.mV);
 
-		glTexCoord2f(1.f, border_scale.mV[VY]);
-		glVertex3fv((width_vec + bottom_border_height).mV);
+		gGL.texCoord2f(1.f, border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec + bottom_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
 
 		// draw left 
-		glTexCoord2f(0.f, border_scale.mV[VY]);
-		glVertex3fv(bottom_border_height.mV);
+		gGL.texCoord2f(0.f, border_scale.mV[VY]);
+		gGL.vertex3fv(bottom_border_height.mV);
 
-		glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((left_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(0.f, 1.f - border_scale.mV[VY]);
-		glVertex3fv((height_vec - top_border_height).mV);
+		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((height_vec - top_border_height).mV);
 
 		// draw middle
-		glTexCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((left_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
 
 		// draw right 
-		glTexCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + bottom_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
 
-		glTexCoord2f(1.f, border_scale.mV[VY]);
-		glVertex3fv((width_vec + bottom_border_height).mV);
+		gGL.texCoord2f(1.f, border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec + bottom_border_height).mV);
 
-		glTexCoord2f(1.f, 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
 
 		// draw top left
-		glTexCoord2f(0.f, 1.f - border_scale.mV[VY]);
-		glVertex3fv((height_vec - top_border_height).mV);
+		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((height_vec - top_border_height).mV);
 
-		glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(border_scale.mV[VX], 1.f);
-		glVertex3fv((left_border_width + height_vec).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f);
+		gGL.vertex3fv((left_border_width + height_vec).mV);
 
-		glTexCoord2f(0.f, 1.f);
-		glVertex3fv((height_vec).mV);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex3fv((height_vec).mV);
 
 		// draw top middle
-		glTexCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((left_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f);
-		glVertex3fv((width_vec - right_border_width + height_vec).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
 
-		glTexCoord2f(border_scale.mV[VX], 1.f);
-		glVertex3fv((left_border_width + height_vec).mV);
+		gGL.texCoord2f(border_scale.mV[VX], 1.f);
+		gGL.vertex3fv((left_border_width + height_vec).mV);
 
 		// draw top right
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
 
-		glTexCoord2f(1.f, 1.f - border_scale.mV[VY]);
-		glVertex3fv((width_vec + height_vec - top_border_height).mV);
+		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
+		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
 
-		glTexCoord2f(1.f, 1.f);
-		glVertex3fv((width_vec + height_vec).mV);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex3fv((width_vec + height_vec).mV);
 
-		glTexCoord2f(1.f - border_scale.mV[VX], 1.f);
-		glVertex3fv((width_vec - right_border_width + height_vec).mV);
+		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
+		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
 	}
-	glEnd();
+	gGL.end();
+
 }
 
 void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec)
@@ -1588,7 +1595,7 @@ void LLUI::cleanupClass()
 //static
 void LLUI::translate(F32 x, F32 y, F32 z)
 {
-	glTranslatef(x,y,z);
+	gGL.translatef(x,y,z);
 	LLFontGL::sCurOrigin.mX += (S32) x;
 	LLFontGL::sCurOrigin.mY += (S32) y;
 	LLFontGL::sCurOrigin.mZ += z;
@@ -1597,14 +1604,14 @@ void LLUI::translate(F32 x, F32 y, F32 z)
 //static
 void LLUI::pushMatrix()
 {
-	glPushMatrix();
+	gGL.pushMatrix();
 	LLFontGL::sOriginStack.push_back(LLFontGL::sCurOrigin);
 }
 
 //static
 void LLUI::popMatrix()
 {
-	glPopMatrix();
+	gGL.popMatrix();
 	LLFontGL::sCurOrigin = *LLFontGL::sOriginStack.rbegin();
 	LLFontGL::sOriginStack.pop_back();
 }
@@ -1627,6 +1634,7 @@ void LLUI::setScaleFactor(const LLVector2 &scale_factor)
 //static
 void LLUI::setLineWidth(F32 width)
 {
+	gGL.flush();
 	glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f));
 }
 
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index b5b15eef23b..e7750087cf4 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -224,6 +224,8 @@ typedef enum e_widget_type
 	WIDGET_TYPE_SLIDER,	// actually LLSliderCtrl
 	WIDGET_TYPE_SLIDER_BAR, // actually LLSlider
 	WIDGET_TYPE_VOLUME_SLIDER,//actually LLVolumeSliderCtrl
+	WIDGET_TYPE_MULTI_SLIDER,	// actually LLMultiSliderCtrl
+	WIDGET_TYPE_MULTI_SLIDER_BAR, // actually LLMultiSlider
 	WIDGET_TYPE_SPINNER,
 	WIDGET_TYPE_TEXT_EDITOR,
 	WIDGET_TYPE_TEXTURE_PICKER,
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 47919408ab1..4acfc69f3a4 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -59,6 +59,8 @@
 #include "llscrolllistctrl.h"
 #include "llslider.h"
 #include "llsliderctrl.h"
+#include "llmultislider.h"
+#include "llmultisliderctrl.h"
 #include "llspinctrl.h"
 #include "lltabcontainer.h"
 #include "lltabcontainervertical.h"
@@ -92,6 +94,8 @@ const LLString LLUICtrlFactory::sUICtrlNames[WIDGET_TYPE_COUNT] =
 	LLString("slider"),		//WIDGET_TYPE_SLIDER, actually LLSliderCtrl
 	LLString("slider_bar"), //WIDGET_TYPE_SLIDER_BAR, actually LLSlider
 	LLString("volume_slider"),	//WIDGET_TYPE_VOLUME_SLIDER, actually LLSlider + "volume" param
+	LLString("multi_slider"),		//WIDGET_TYPE_MULTI_SLIDER, actually LLMultiSliderCtrl
+	LLString("multi_slider_bar"), //WIDGET_TYPE_MULTI_SLIDER_BAR, actually LLMultiSlider
 	LLString("spinner"),		//WIDGET_TYPE_SPINNER, actually LLSpinCtrl
 	LLString("text_editor"),	//WIDGET_TYPE_TEXT_EDITOR
 	LLString("texture_picker"),//WIDGET_TYPE_TEXTURE_PICKER
@@ -206,6 +210,8 @@ LLUICtrlFactory::LLUICtrlFactory()
 	LLUICtrlCreator<LLSliderCtrl>::registerCreator(LL_SLIDER_CTRL_TAG, this);
 	LLUICtrlCreator<LLSlider>::registerCreator(LL_SLIDER_TAG, this);
 	LLUICtrlCreator<LLSlider>::registerCreator(LL_VOLUME_SLIDER_CTRL_TAG, this);
+	LLUICtrlCreator<LLMultiSliderCtrl>::registerCreator(LL_MULTI_SLIDER_CTRL_TAG, this);
+	LLUICtrlCreator<LLMultiSlider>::registerCreator(LL_MULTI_SLIDER_TAG, this);
 	LLUICtrlCreator<LLSpinCtrl>::registerCreator(LL_SPIN_CTRL_TAG, this);
 	LLUICtrlCreator<LLTextBox>::registerCreator(LL_TEXT_BOX_TAG, this);
 	LLUICtrlCreator<LLRadioGroup>::registerCreator(LL_RADIO_GROUP_TAG, this);
@@ -729,6 +735,16 @@ LLScrollingPanelList* LLUICtrlFactory::getScrollingPanelList(const LLPanel* pane
 	return panelp->getChild<LLScrollingPanelList>(name);
 }
 
+LLMultiSliderCtrl* LLUICtrlFactory::getMultiSliderByName(const LLPanel* panelp, const LLString& name)		
+{ 
+	return panelp->getChild<LLMultiSliderCtrl>(name); 
+}
+
+LLMultiSlider* LLUICtrlFactory::getMultiSliderBarByName(const LLPanel* panelp, const LLString& name)		
+{ 
+	return panelp->getChild<LLMultiSlider>(name); 
+}
+
 
 LLCtrlListInterface* LLUICtrlFactory::getListInterfaceByName(const LLPanel* panelp, const LLString& name)
 {
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 1b90e64322b..c2a6cfe510a 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -91,6 +91,8 @@ class LLUICtrlFactory
 	static class LLPanel* 				getPanelByName(			const LLPanel* panelp, const LLString& name);
 	static class LLMenuItemCallGL*		getMenuItemCallByName(	const LLPanel* panelp, const LLString& name);
 	static class LLScrollingPanelList*	getScrollingPanelList(	const LLPanel* panelp, const LLString& name);
+	static class LLMultiSliderCtrl*		getMultiSliderByName(	const LLPanel* panelp, const LLString& name);
+	static class LLMultiSlider*			getMultiSliderBarByName(const LLPanel* panelp, const LLString& name);
 
 	// interface getters
 	static LLCtrlListInterface* getListInterfaceByName(	const LLPanel* panelp, const LLString& name);
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 56e24085ac2..0a37c03ac5d 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -37,6 +37,7 @@
 #include <cassert>
 #include <boost/tokenizer.hpp>
 
+#include "llglimmediate.h"
 #include "llevent.h"
 #include "llfontgl.h"
 #include "llfocusmgr.h"
@@ -1290,28 +1291,28 @@ void LLView::drawDebugRect()
 			border_color.mV[sDepth%3] = 1.f;
 		}
 
-		glColor4fv( border_color.mV );
+		gGL.color4fv( border_color.mV );
 
-		glBegin(GL_LINES);
-			glVertex2i(0, debug_rect.getHeight() - 1);
-			glVertex2i(0, 0);
+		gGL.begin(GL_LINES);
+			gGL.vertex2i(0, debug_rect.getHeight() - 1);
+			gGL.vertex2i(0, 0);
 
-			glVertex2i(0, 0);
-			glVertex2i(debug_rect.getWidth() - 1, 0);
+			gGL.vertex2i(0, 0);
+			gGL.vertex2i(debug_rect.getWidth() - 1, 0);
 
-			glVertex2i(debug_rect.getWidth() - 1, 0);
-			glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+			gGL.vertex2i(debug_rect.getWidth() - 1, 0);
+			gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
 
-			glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
-			glVertex2i(0, debug_rect.getHeight() - 1);
-		glEnd();
+			gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+			gGL.vertex2i(0, debug_rect.getHeight() - 1);
+		gGL.end();
 
 		// Draw the name if it's not a leaf node
 		if (mChildList.size() && !sEditingUI)
 		{
 			//char temp[256];
 			S32 x, y;
-			glColor4fv( border_color.mV );
+			gGL.color4fv( border_color.mV );
 			x = debug_rect.getWidth()/2;
 			y = debug_rect.getHeight()/2;
 			LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index 546eb23c033..301efa38721 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -30,6 +30,7 @@
 
 #include "linden_common.h"
 #include "llviewborder.h"
+#include "llglimmediate.h"
 #include "llfocusmgr.h"
 
 LLViewBorder::LLViewBorder( const LLString& name, const LLRect& rect, EBevel bevel, EStyle style, S32 width )
@@ -145,11 +146,11 @@ void LLViewBorder::drawOnePixelLines()
 	S32 right	= getRect().getWidth();
 	S32 bottom	= 0;
 
-	glColor4fv( top_color.mV );
+	gGL.color4fv( top_color.mV );
 	gl_line_2d(left, bottom, left, top);
 	gl_line_2d(left, top, right, top);
 
-	glColor4fv( bottom_color.mV );
+	gGL.color4fv( bottom_color.mV );
 	gl_line_2d(right, top, right, bottom);
 	gl_line_2d(left, bottom, right, bottom);
 
@@ -205,19 +206,19 @@ void LLViewBorder::drawTwoPixelLines()
 	S32 bottom	= 0;
 
 	// draw borders
-	glColor3fv( top_out_color );
+	gGL.color3fv( top_out_color );
 	gl_line_2d(left, bottom, left, top-1);
 	gl_line_2d(left, top-1, right, top-1);
 
-	glColor3fv( top_in_color );
+	gGL.color3fv( top_in_color );
 	gl_line_2d(left+1, bottom+1, left+1, top-2);
 	gl_line_2d(left+1, top-2, right-1, top-2);
 
-	glColor3fv( bottom_out_color );
+	gGL.color3fv( bottom_out_color );
 	gl_line_2d(right-1, top-1, right-1, bottom);
 	gl_line_2d(left, bottom, right, bottom);
 
-	glColor3fv( bottom_in_color );
+	gGL.color3fv( bottom_in_color );
 	gl_line_2d(right-2, top-2, right-2, bottom+1);
 	gl_line_2d(left+1, bottom+1, right-1, bottom+1);
 }
@@ -228,7 +229,7 @@ void LLViewBorder::drawTextures()
 
 	llassert( FALSE );  // TODO: finish implementing
 
-	glColor4fv(UI_VERTEX_COLOR.mV);
+	gGL.color4fv(UI_VERTEX_COLOR.mV);
 
 	mTexture->bind();
 	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
@@ -243,12 +244,12 @@ void LLViewBorder::drawTextures()
 
 void LLViewBorder::drawTextureTrapezoid( F32 degrees, S32 width, S32 length, F32 start_x, F32 start_y )
 {
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef(start_x, start_y, 0.f);
+		gGL.translatef(start_x, start_y, 0.f);
 		glRotatef( degrees, 0, 0, 1 );
 
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		{
 			//      width, width   /---------\ length-width, width		//
 			//	   			      /           \							//
@@ -256,21 +257,21 @@ void LLViewBorder::drawTextureTrapezoid( F32 degrees, S32 width, S32 length, F32
 			//				    /---------------\						//
 			//    			0,0					  length, 0				//
 
-			glTexCoord2f( 0, 0 );
-			glVertex2i( 0, 0 );
+			gGL.texCoord2f( 0, 0 );
+			gGL.vertex2i( 0, 0 );
 
-			glTexCoord2f( (GLfloat)length, 0 );
-			glVertex2i( length, 0 );
+			gGL.texCoord2f( (GLfloat)length, 0 );
+			gGL.vertex2i( length, 0 );
 
-			glTexCoord2f( (GLfloat)(length - width), (GLfloat)width );
-			glVertex2i( length - width, width );
+			gGL.texCoord2f( (GLfloat)(length - width), (GLfloat)width );
+			gGL.vertex2i( length - width, width );
 
-			glTexCoord2f( (GLfloat)width, (GLfloat)width );
-			glVertex2i( width, width );
+			gGL.texCoord2f( (GLfloat)width, (GLfloat)width );
+			gGL.vertex2i( width, width );
 		}
-		glEnd();
+		gGL.end();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 BOOL LLViewBorder::getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel& bevel_style)
diff --git a/indra/llui/llviewborder.h b/indra/llui/llviewborder.h
index e9fd8aa4e1b..d35663c857f 100644
--- a/indra/llui/llviewborder.h
+++ b/indra/llui/llviewborder.h
@@ -64,6 +64,9 @@ class LLViewBorder : public LLView
 				  				   const LLColor4& highlight_light, const LLColor4& highlight_dark );
 	void		setTexture( const class LLUUID &image_id );
 
+	LLColor4	getHighlightLight() {return mHighlightLight;}
+	LLColor4	getShadowDark() {return mHighlightDark;}
+
 	EStyle		getStyle() const { return mStyle; }
 
 	void		setKeyboardFocusHighlight( BOOL b )	{ mHasKeyboardFocus = b; }
diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp
index 2aff05232e2..ab43e6d7d9e 100644
--- a/indra/llwindow/lldxhardware.cpp
+++ b/indra/llwindow/lldxhardware.cpp
@@ -35,7 +35,9 @@
 
 #include "linden_common.h"
 
+#define INITGUID
 #include <dxdiag.h>
+#undef INITGUID
 
 #include <boost/tokenizer.hpp>
 
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index e845afe3204..fce0d055e60 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -247,7 +247,7 @@ LLWindow::LLWindow(BOOL fullscreen, U32 flags)
 	  mFlags(flags),
 	  mHighSurrogate(0)
 {
-	for (U32 i = 0; i < 6; i++)
+	for (U32 i = 0; i < 8; i++)
 	{
 		mJoyAxis[i] = 0;
 	}
@@ -275,7 +275,7 @@ void LLWindow::decBusyCount()
 
 F32 LLWindow::getJoystickAxis(U32 axis)
 {
-	if (axis < 6)
+	if (axis < 8)
 	{
 		return mJoyAxis[axis];
 	}
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 0554d3a8db9..bc444ae8117 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -258,7 +258,7 @@ class LLWindow
 	ESwapMethod mSwapMethod;
 	BOOL		mHideCursorPermanent;
 	U32			mFlags;
-	F32			mJoyAxis[6]; 
+	F32			mJoyAxis[8]; 
 	U8			mJoyButtonState[16];
 	U16			mHighSurrogate;
 
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index fe127b407ed..5184a6caec4 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -42,6 +42,7 @@
 #include "llgl.h"
 #include "llstring.h"
 #include "lldir.h"
+#include "llviewercontrol.h"
 
 #include "llglheaders.h"
 
@@ -800,22 +801,24 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 	}
 	aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap);  
 
-#if 0 // SJB: Got a compile error. Plus I don't want to test this along with everything else ; save it for later
 	//enable multi-threaded OpenGL
-	CGLError cgl_err;
-	CGLContextObj ctx = CGLGetCurrentContext();
-			
-	cgl_err =  CGLEnable( ctx, kCGLCEMPEngine);
-			
-	if (cgl_err != kCGLNoError )
-	{
-		 llinfos << "Multi-threaded OpenGL not available." << llendl;
-	}    
-	else
+	if (gSavedSettings.getBOOL("RenderAppleUseMultGL"))
 	{
-		llinfos << "Multi-threaded OpenGL enabled." << llendl;
+		CGLError cgl_err;
+		CGLContextObj ctx = CGLGetCurrentContext();
+
+		cgl_err =  CGLEnable( ctx, kCGLCEMPEngine);
+
+		if (cgl_err != kCGLNoError )
+		{
+			llinfos << "Multi-threaded OpenGL not available." << llendl;
+		}    
+		else
+		{
+			llinfos << "Multi-threaded OpenGL enabled." << llendl;
+		}
 	}
-#endif 		
+
 	// Don't need to get the current gamma, since there's a call that restores it to the system defaults.
 	return TRUE;
 }
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index e7475d577db..686be3385ec 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -505,6 +505,9 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
 	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
 #if !LL_SOLARIS
         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24);
+	// We need stencil support for a few (minor) things.
+	if (!getenv("LL_GL_NO_STENCIL"))
+		SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
 #else
 	// NOTE- use smaller Z-buffer to enable more graphics cards
         //     - This should not affect better GPUs and has been proven
@@ -587,6 +590,11 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
 		}
 
 		mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN);
+		if (!mWindow && bits > 16)
+		{
+			SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+			mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN);
+		}
 
 		if (mWindow)
 		{
@@ -629,6 +637,11 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
 
 		llinfos << "createContext: creating window " << width << "x" << height << "x" << bits << llendl;
 		mWindow = SDL_SetVideoMode(width, height, bits, sdlflags);
+		if (!mWindow && bits > 16)
+		{
+			SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+			mWindow = SDL_SetVideoMode(width, height, bits, sdlflags);
+		}
 
 		if (!mWindow)
 		{
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 3c270d9175d..0bba56f74f5 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -44,6 +44,7 @@
 
 // Require DirectInput version 8
 #define DIRECTINPUT_VERSION 0x0800
+
 #include <dinput.h>
 
 
@@ -428,7 +429,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
 	mhInstance = GetModuleHandle(NULL);
 	mWndProc = NULL;
 
-	mSwapMethod = SWAP_METHOD_UNDEFINED;
+	mSwapMethod = SWAP_METHOD_EXCHANGE;
 
 	// No WPARAM yet.
 	mLastSizeWParam = 0;
@@ -774,7 +775,7 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
 			attrib_list[cur_attrib++] = GL_TRUE;
 
 			attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
-			attrib_list[cur_attrib++] = 24;
+			attrib_list[cur_attrib++] = 32;
 
 			attrib_list[cur_attrib++] = WGL_RED_BITS_ARB;
 			attrib_list[cur_attrib++] = 8;
@@ -1018,6 +1019,11 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
 	// based on the system's (or user's) default settings.
 	allowLanguageTextInput(NULL, FALSE);
 
+	initInputDevices();
+}
+
+void LLWindowWin32::initInputDevices()
+{
 	// Direct Input
 	HRESULT hr;
 
@@ -1753,6 +1759,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disa
 	SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
 	show();
 
+	initInputDevices();
+
 	// ok to post quit messages now
 	mPostQuit = TRUE;
 	return TRUE;
@@ -3199,6 +3207,8 @@ void LLWindowWin32::updateJoystick( )
 	mJoyAxis[3] = js.lRx/1000.f;
 	mJoyAxis[4] = js.lRy/1000.f;
 	mJoyAxis[5] = js.lRz/1000.f;
+	mJoyAxis[6] = js.rglSlider[0]/1000.f;
+	mJoyAxis[7] = js.rglSlider[1]/1000.f;
 
 	for (U32 i = 0; i < 16; i++)
 	{
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 9ad99b02016..b21df8981e1 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -122,6 +122,7 @@ class LLWindowWin32 : public LLWindow
 	~LLWindowWin32();
 
 	void	initCursors();
+	void	initInputDevices();
 	HCURSOR loadColorCursor(LPCTSTR name);
 	BOOL	isValid();
 	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size);
diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml
new file mode 100644
index 00000000000..6368f7099e7
--- /dev/null
+++ b/indra/newview/app_settings/high_graphics.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<settings version = "101">
+	<!--NO SHADERS-->
+	<RenderAvatarCloth value="FALSE"/>
+	<!--Default for now-->
+	<RenderAvatarLODFactor value="1.0"/>
+	<!--NO SHADERS-->
+	<RenderAvatarVP value="TRUE"/>
+	<!--Short Range-->
+	<RenderFarClip value="128"/>
+	<!--Default for now-->
+	<RenderFlexTimeFactor value="1"/>
+	<!--256... but they don't use this-->
+	<RenderGlowResolutionPow value="9"/>
+	<!--Sun/Moon only-->
+	<RenderLightingDetail value="1"/>
+	<!--Low number-->
+	<RenderMaxPartCount value="4096"/>
+	<!--bump okay-->
+	<RenderObjectBump value="TRUE"/>
+	<!--NO SHADERS-->
+	<RenderReflectionDetail value="2"/>
+	<!--Simple-->
+	<RenderTerrainDetail value="1"/>
+	<!--Default for now-->
+	<RenderTerrainLODFactor value="2"/>
+	<!--Default for now-->
+	<RenderTreeLODFactor value="0.5"/>
+	<!--Try Impostors-->
+	<RenderUseImpostors value="TRUE"/>
+	<!--Default for now-->
+	<RenderVolumeLODFactor value="1.125"/>
+	<!--NO SHADERS-->
+	<RenderWaterReflections value="FALSE"/>
+	<!--NO SHADERS-->
+	<VertexShaderEnable value="TRUE"/>
+	<!--NO SHADERS-->
+	<WindLightUseAtmosShaders value="TRUE"/>
+</settings>
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
new file mode 100644
index 00000000000..3f67a70d7ac
--- /dev/null
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<settings version = "101">
+	<!--NO SHADERS-->
+	<RenderAvatarCloth value="FALSE"/>
+	<!--Default for now-->
+	<RenderAvatarLODFactor value="0.5"/>
+	<!--NO SHADERS-->
+	<RenderAvatarVP value="FALSE"/>
+	<!--Short Range-->
+	<RenderFarClip value="64"/>
+	<!--Default for now-->
+	<RenderFlexTimeFactor value="0.5"/>
+	<!--256... but they don't use this-->
+	<RenderGlowResolutionPow value="8"/>
+	<!--Sun/Moon only-->
+	<RenderLightingDetail value="0"/>
+	<!--Low number-->
+	<RenderMaxPartCount value="1024"/>
+	<!--bump okay-->
+	<RenderObjectBump value="FALSE"/>
+	<!--NO SHADERS-->
+	<RenderReflectionDetail value="0"/>
+	<!--Simple-->
+	<RenderTerrainDetail value="0"/>
+	<!--Default for now-->
+	<RenderTerrainLODFactor value="1.0"/>
+	<!--Default for now-->
+	<RenderTreeLODFactor value="0.5"/>
+	<!--Try Impostors-->
+	<RenderUseImpostors value="TRUE"/>
+	<!--Default for now-->
+	<RenderVolumeLODFactor value="1.125"/>
+	<!--NO SHADERS-->
+	<RenderWaterReflections value="FALSE"/>
+	<!--NO SHADERS-->
+	<VertexShaderEnable value="FALSE"/>
+	<!--NO SHADERS-->
+	<WindLightUseAtmosShaders value="FALSE"/>
+</settings>
diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml
new file mode 100644
index 00000000000..12da77da400
--- /dev/null
+++ b/indra/newview/app_settings/mid_graphics.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<settings version = "101">
+	<!--NO SHADERS-->
+	<RenderAvatarCloth value="FALSE"/>
+	<!--Default for now-->
+	<RenderAvatarLODFactor value="0.5"/>
+	<!--NO SHADERS-->
+	<RenderAvatarVP value="TRUE"/>
+	<!--Short Range-->
+	<RenderFarClip value="96"/>
+	<!--Default for now-->
+	<RenderFlexTimeFactor value="1"/>
+	<!--256... but they don't use this-->
+	<RenderGlowResolutionPow value="8"/>
+	<!--Sun/Moon only-->
+	<RenderLightingDetail value="1"/>
+	<!--Low number-->
+	<RenderMaxPartCount value="2048"/>
+	<!--bump okay-->
+	<RenderObjectBump value="TRUE"/>
+	<!--NO SHADERS-->
+	<RenderReflectionDetail value="0"/>
+	<!--Simple-->
+	<RenderTerrainDetail value="1"/>
+	<!--Default for now-->
+	<RenderTerrainLODFactor value="1.0"/>
+	<!--Default for now-->
+	<RenderTreeLODFactor value="0.5"/>
+	<!--Try Impostors-->
+	<RenderUseImpostors value="TRUE"/>
+	<!--Default for now-->
+	<RenderVolumeLODFactor value="1.125"/>
+	<!--NO SHADERS-->
+	<RenderWaterReflections value="FALSE"/>
+	<!--NO SHADERS-->
+	<VertexShaderEnable value="TRUE"/>
+	<!--NO SHADERS-->
+	<WindLightUseAtmosShaders value="FALSE"/>
+</settings>
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
index 5731add4d53..b6cc7f7712a 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
@@ -1,3 +1,10 @@
+/** 
+ * @file avatarF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 void default_lighting();
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
index 1fcc0019119..292dbfdab49 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
@@ -1,4 +1,9 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
+/** 
+ * @file avatarSkinV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
 attribute vec4 weight;  //1
 
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
index 50f9b0192ec..ee3410d7320 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
@@ -1,9 +1,13 @@
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file avatarV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 mat4 getSkinnedTransform();
-vec2 getScatterCoord(vec3 viewVec, vec3 lightDir);
-
-attribute vec4 materialColor;
+void calcAtmospherics(vec3 inPositionEye);
 
 void main()
 {
@@ -24,12 +28,16 @@ void main()
 	norm = normalize(norm);
 		
 	gl_Position = gl_ProjectionMatrix * pos;
-	 
+	
 	//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
 	
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
+	gl_FogFragCoord = length(pos.xyz);
 
-	vec4 color = calcLighting(pos.xyz, norm, materialColor, gl_Color);
+	calcAtmospherics(pos.xyz);
+
+	vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0,0,0,0));
 	gl_FrontColor = color; 
 
 }
+
+
diff --git a/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl b/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
index 5731add4d53..4d93c19441a 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
@@ -1,3 +1,10 @@
+/** 
+ * @file eyeballF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 void default_lighting();
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
index d436b4e00ad..b3c988a9242 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
@@ -1,7 +1,12 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec3 baseCol);
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file eyeballV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-attribute vec4 materialColor;
+vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
 
 void main()
 {
@@ -12,9 +17,11 @@ void main()
 	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 		
-	vec4 color = calcLighting(pos, norm, materialColor, gl_Color.rgb);
-	default_scatter(pos, gl_LightSource[0].position.xyz);
-	
+	calcAtmospherics(pos.xyz);
+
+	vec4 specular = vec4(1.0);
+	vec4 color = calcLightingSpecular(pos, norm, gl_Color, specular, vec4(0.0));	
 	gl_FrontColor = color;
+
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
index b311afb59ca..20193004183 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
@@ -1,3 +1,10 @@
+/** 
+ * @file pickAvatarF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 uniform sampler2D diffuseMap;
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
index b6dcbe16935..12d8f9d2f9c 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
@@ -1,4 +1,10 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color);
+/** 
+ * @file pickAvatarV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 mat4 getSkinnedTransform();
 
 void main()
@@ -14,4 +20,4 @@ void main()
 	gl_FrontColor = gl_Color;
 	gl_TexCoord[0] = gl_MultiTexCoord0;
 	gl_Position = gl_ProjectionMatrix * pos;
-}
\ No newline at end of file
+}
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
new file mode 100644
index 00000000000..dbdfe1174c4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
@@ -0,0 +1,28 @@
+/** 
+ * @file glowExtractF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseMap;
+uniform float minLuminance;
+uniform float maxExtractAlpha;
+uniform vec3 lumWeights;
+uniform vec3 warmthWeights;
+uniform float warmthAmount;
+
+void main()
+{
+	vec4 col = texture2DRect(diffuseMap, gl_TexCoord[0].xy);	
+
+	/// CALCULATING LUMINANCE (Using NTSC lum weights)
+	/// http://en.wikipedia.org/wiki/Luma_%28video%29
+	float lum = smoothstep(minLuminance, 1.0, dot(col.rgb, lumWeights ) );
+	float warmth = smoothstep(minLuminance, 1.0, max(col.r * warmthWeights.r, max(col.g * warmthWeights.g, col.b * warmthWeights.b)) ); 
+	
+	gl_FragColor.rgb = col.rgb; 
+	gl_FragColor.a = max(col.a, mix(lum, warmth, warmthAmount) * maxExtractAlpha);
+}
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
new file mode 100644
index 00000000000..61dfd2f126f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
@@ -0,0 +1,14 @@
+/** 
+ * @file glowExtractV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+void main() 
+{
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+	
+	gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
+}
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowF.glsl
new file mode 100644
index 00000000000..21c7ad765f3
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/effects/glowF.glsl
@@ -0,0 +1,31 @@
+/** 
+ * @file glowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform float glowStrength;
+
+void main()
+{
+
+	vec4 col = vec4(0.0, 0.0, 0.0, 0.0);
+
+	// ATI compiler falls down on array initialization.
+	float kern[8];
+		kern[0] = 0.25; kern[1] = 0.5; kern[2] = 0.8; kern[3] = 1.0;
+		kern[4] = 1.0;  kern[5] = 0.8; kern[6] = 0.5; kern[7] = 0.25;
+	
+	col += kern[0] * texture2D(diffuseMap, gl_TexCoord[0].xy);	
+	col += kern[1] * texture2D(diffuseMap, gl_TexCoord[1].xy);
+	col += kern[2] * texture2D(diffuseMap, gl_TexCoord[2].xy);	
+	col += kern[3] * texture2D(diffuseMap, gl_TexCoord[3].xy);	
+	col += kern[4] * texture2D(diffuseMap, gl_TexCoord[0].zw);	
+	col += kern[5] * texture2D(diffuseMap, gl_TexCoord[1].zw);	
+	col += kern[6] * texture2D(diffuseMap, gl_TexCoord[2].zw);	
+	col += kern[7] * texture2D(diffuseMap, gl_TexCoord[3].zw);	
+	
+	gl_FragColor = vec4(col.rgb * glowStrength, col.a);
+}
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl
new file mode 100644
index 00000000000..13ce7c7854b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl
@@ -0,0 +1,22 @@
+/** 
+ * @file glowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec2 glowDelta;
+
+void main() 
+{
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+	
+	gl_TexCoord[0].xy = gl_MultiTexCoord0.xy + glowDelta*(-3.5);
+	gl_TexCoord[1].xy = gl_MultiTexCoord0.xy + glowDelta*(-2.5);
+	gl_TexCoord[2].xy = gl_MultiTexCoord0.xy + glowDelta*(-1.5);
+	gl_TexCoord[3].xy = gl_MultiTexCoord0.xy + glowDelta*(-0.5);
+	gl_TexCoord[0].zw = gl_MultiTexCoord0.xy + glowDelta*(0.5);
+	gl_TexCoord[1].zw = gl_MultiTexCoord0.xy + glowDelta*(1.5);
+	gl_TexCoord[2].zw = gl_MultiTexCoord0.xy + glowDelta*(2.5);
+	gl_TexCoord[3].zw = gl_MultiTexCoord0.xy + glowDelta*(3.5);
+}
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
index fde370155d1..2278c6916d1 100644
--- a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
@@ -1,9 +1,13 @@
-void terrain_lighting(inout vec3 color);
-
-uniform sampler2D detail0; //0
-uniform sampler2D detail1; //2
-uniform sampler2D alphaRamp; //1
+/** 
+ * @file terrainF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
+uniform sampler2D detail0;
+uniform sampler2D detail1;
+uniform sampler2D alphaRamp;
 
 void main() 
 {
@@ -12,8 +16,6 @@ void main()
 					 texture2D(detail0, gl_TexCoord[0].xy).rgb,
 					 a);
 
-	terrain_lighting(color);
-	
 	gl_FragColor.rgb = color;
 	gl_FragColor.a = texture2D(alphaRamp, gl_TexCoord[3].xy).a;
 }
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
index 3153a80e934..112d669819a 100644
--- a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
@@ -1,7 +1,11 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file terrainV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-attribute vec4 materialColor;
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 
 vec4 texgen_object(vec4  vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
 {
@@ -25,7 +29,7 @@ void main()
 	vec4 pos = gl_ModelViewMatrix * gl_Vertex;
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 	
-	vec4 color = calcLighting(pos.xyz, norm, materialColor, gl_Color);
+	vec4 color = calcLighting(pos.xyz, norm, vec4(1,1,1,1), gl_Color);
 	
 	gl_FrontColor = color;
 	
@@ -33,5 +37,4 @@ void main()
 	gl_TexCoord[1] = gl_TextureMatrix[1]*gl_MultiTexCoord1;
 	gl_TexCoord[2] = texgen_object(gl_Vertex,gl_MultiTexCoord2,gl_TextureMatrix[2],gl_ObjectPlaneS[2],gl_ObjectPlaneT[2]);
 	gl_TexCoord[3] = gl_TextureMatrix[3]*gl_MultiTexCoord3;
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);	
 }
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
new file mode 100644
index 00000000000..e2f68e88269
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
@@ -0,0 +1,23 @@
+/** 
+ * @file terrainWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// this class1 shader is just a copy of terrainF
+
+uniform sampler2D detail0;
+uniform sampler2D detail1;
+uniform sampler2D alphaRamp;
+
+void main() 
+{
+	float a = texture2D(alphaRamp, gl_TexCoord[1].xy).a;
+	vec3 color = mix(texture2D(detail1, gl_TexCoord[2].xy).rgb,
+					 texture2D(detail0, gl_TexCoord[0].xy).rgb,
+					 a);
+
+	gl_FragColor.rgb = color;
+	gl_FragColor.a = texture2D(alphaRamp, gl_TexCoord[3].xy).a;
+}
diff --git a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
new file mode 100644
index 00000000000..f1740a4dcd7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
@@ -0,0 +1,45 @@
+/**
+ * @file underWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+
+uniform float refScale;
+uniform vec4 waterFogColor;
+
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+
+void main() 
+{
+	vec4 color;    
+	
+	//get bigwave normal
+	vec3 wavef = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0;
+    
+	//get detail normals
+	vec3 dcol = texture2D(bumpMap, littleWave.xy).rgb*0.75;
+	dcol += texture2D(bumpMap, littleWave.zw).rgb*1.25;
+	    
+	//interpolate between big waves and little waves (big waves in deep water)
+	wavef = (wavef+dcol)*0.5;
+
+	//crunch normal to range [-1,1]
+	wavef -= vec3(1,1,1);
+	
+	//figure out distortion vector (ripply)   
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	distort = distort+wavef.xy*refScale;
+		
+	vec4 fb = texture2D(screenTex, distort);
+	
+	gl_FragColor.rgb = mix(waterFogColor.rgb, fb.rgb, waterFogColor.a * 0.001 + 0.999);
+	gl_FragColor.a = fb.a;
+}
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
index f8b8031ce6b..1c14381df94 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
@@ -1,22 +1,94 @@
-void water_lighting(inout vec3 diff);
+/** 
+ * @file waterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 scaleSoftClip(vec3 inColor);
+vec3 atmosTransport(vec3 inColor);
 
-uniform samplerCube environmentMap;
 uniform sampler2D diffuseMap;
-uniform sampler2D bumpMap;
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+
+uniform float sunAngle;
+uniform float sunAngle2;
+uniform float scaledAngle;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform float refScale;
+uniform float kd;
+uniform vec2 screenRes;
+uniform vec3 normScale;
+uniform float fresnelScale;
+uniform float fresnelOffset;
+uniform float blurMultiplier;
+uniform vec4 fogCol;
 
-varying vec4 specular;
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
 
 void main() 
 {
-	vec4 depth = texture2D(diffuseMap, gl_TexCoord[0].xy);
-	vec4 diff = texture2D(bumpMap, gl_TexCoord[1].xy);
-	vec3 ref = textureCube(environmentMap, gl_TexCoord[2].xyz).rgb;
+	vec3 viewVec = view.xyz;
+	vec4 color;
+	
+	float dist = length(viewVec.xy);
+	
+	//normalize view vector
+	viewVec = normalize(viewVec);
+	
+	//get wave normals
+	vec3 wavef = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0;
+
+	//get detail normals
+	vec3 dcol = texture2D(bumpMap, littleWave.xy).rgb*0.75;
+	dcol += texture2D(bumpMap, littleWave.zw).rgb*1.25;
+
+	//interpolate between big waves and little waves (big waves in deep water)
+	wavef = (wavef + dcol) * 0.5;
+	
+	//crunch normal to range [-1,1]
+	wavef -= vec3(1,1,1);
+	wavef = normalize(wavef);
+   
+	//get base fresnel components	
 	
-	diff.rgb *= depth.rgb;
+	float df = dot(viewVec,wavef) * fresnelScale + fresnelOffset;
+		    
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	
+	float dist2 = dist;
+	dist = max(dist, 5.0);
+	
+	//get reflected color
+	vec2 refdistort = wavef.xy*dot(normScale, vec3(0.333));
+	vec2 refvec = distort+refdistort/dist;
+	vec4 refcol = texture2D(refTex, refvec);
+
+	//get specular component
+	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+	
+	//harden specular
+	spec = pow(spec, lightExp);
+
+	//figure out distortion vector (ripply)   
+	vec2 distort2 = distort+wavef.xy*refScale/max(dist*df, 1.0);
 		
-	vec3 col = mix(diff.rgb, ref, specular.a)+specular.rgb*diff.rgb;
+	vec4 fb = texture2D(screenTex, distort2);
+	
+	//mix with reflection
+	color.rgb = mix(mix(fogCol.rgb, fb.rgb, fogCol.a), refcol.rgb, df);
+	color.rgb += spec * specular;
 	
-	water_lighting(col.rgb); 
-	gl_FragColor.rgb = col.rgb;
-	gl_FragColor.a = (gl_Color.a+depth.a)*0.5;	
+	color.rgb = atmosTransport(color.rgb);
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = spec * sunAngle2;
+
+	gl_FragColor = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
new file mode 100644
index 00000000000..59e44fa871e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
@@ -0,0 +1,20 @@
+/**
+ * @file waterFogF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 applyWaterFog(vec4 color)
+{
+	// GL_EXP2 Fog
+	float fog = exp(-gl_Fog.density * gl_Fog.density * gl_FogFragCoord * gl_FogFragCoord);
+	// GL_EXP Fog
+	// float fog = exp(-gl_Fog.density * gl_FogFragCoord);
+	// GL_LINEAR Fog
+	// float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
+	fog = clamp(fog, 0.0, 1.0);
+	color.rgb = mix(gl_Fog.color.rgb, color.rgb, fog);
+	return color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
index 873a6fcb34e..d3327981030 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
@@ -1,41 +1,73 @@
-void default_scatter(vec3 viewVec, vec3 lightDir);
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec3 baseCol);
-vec2 getScatterCoord(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file waterV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-varying vec4 specular;
+void calcAtmospherics(vec3 inPositionEye);
 
-vec4 texgen_object(vec4  vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
+uniform vec2 d1;
+uniform vec2 d2;
+uniform float time;
+uniform vec3 eyeVec;
+uniform float waterHeight;
+
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+
+float wave(vec2 v, float t, float f, vec2 d, float s) 
 {
-	vec4 tcoord;
-	
-	tcoord.x = dot(vpos, tp0);
-	tcoord.y = dot(vpos, tp1);
-	tcoord.z = tc.z;
-	tcoord.w = tc.w;
-	
-	tcoord = mat * tcoord; 
-	
-	return tcoord; 
+   return (dot(d, v)*f + t*s)*f;
 }
 
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
-	gl_TexCoord[0] = gl_MultiTexCoord0;
-	gl_TexCoord[1] = texgen_object(gl_Vertex, gl_MultiTexCoord1, gl_TextureMatrix[1], gl_ObjectPlaneS[1],gl_ObjectPlaneT[1]);
+	vec4 position = gl_Vertex;
+	mat4 modelViewProj = gl_ModelViewProjectionMatrix;
 	
-	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
-	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
-	vec4 spec = gl_Color;
-	gl_FrontColor.rgb = calcLightingSpecular(pos, norm, gl_Color, spec, vec3(0.0, 0.0, 0.0)).rgb;			
-	gl_FrontColor.a = gl_Color.a;
-	specular = spec;
-	specular.a = gl_Color.a*0.5;
-	vec3 ref = reflect(pos,norm);
+	vec4 oPosition;
+		    
+	//get view vector
+	vec3 oEyeVec;
+	oEyeVec.xyz = position.xyz-eyeVec;
+		
+	float d = length(oEyeVec.xy);
+	float ld = min(d, 2560.0);
 	
-	gl_TexCoord[2] = gl_TextureMatrix[2]*vec4(ref,1);
+	position.xy = eyeVec.xy + oEyeVec.xy/d*ld;
+	view.xyz = oEyeVec;
+		
+	d = clamp(ld/1536.0-0.5, 0.0, 1.0);	
+	d *= d;
 		
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
+	oPosition = position;
+	oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d);
+	oPosition = modelViewProj * oPosition;
+	refCoord.xyz = oPosition.xyz + vec3(0,0,0.2);
+	
+	//get wave position parameter (create sweeping horizontal waves)
+	vec3 v = position.xyz;
+	v.x += (cos(v.x*0.08/*+time*0.01*/)+sin(v.y*0.02))*6.0;
+	    
+	//push position for further horizon effect.
+	position.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z);
+	position.w = 1.0;
+	position = position*gl_ModelViewMatrix;
+	
+	calcAtmospherics((gl_ModelViewMatrix * gl_Vertex).xyz);
+	
+	
+	//pass wave parameters to pixel shader
+	vec2 bigWave =  (v.xy) * vec2(0.04,0.04)  + d1 * time * 0.055;
+	//get two normal map (detail map) texture coordinates
+	littleWave.xy = (v.xy) * vec2(0.6, 1.2)   + d2 * time * 0.05;
+	// littleWave.zw = (v.xy) * vec2(0.07, 0.15) - d1 * time * 0.043;
+	littleWave.zw = (v.xy) * vec2(0.3, 0.6) + d1 * time * 0.1;
+	view.w = bigWave.y;
+	refCoord.w = bigWave.x;
+	
+	gl_Position = oPosition;
 }
-
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
index 1e342fb51ba..328c41652d2 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
@@ -1,3 +1,10 @@
+/** 
+ * @file highlightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 uniform sampler2D diffuseMap;
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
index bb6707b2a98..a9ea6e856a8 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
@@ -1,9 +1,14 @@
-attribute vec4 materialColor;
+/** 
+ * @file highlightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+	gl_Position = ftransform();
 	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
 	pos = normalize(pos);
 	float d = dot(pos, normalize(gl_NormalMatrix * gl_Normal));
@@ -11,10 +16,10 @@ void main()
 	d = 1.0 - d;
 	d *= d;
 		
-	d = min(d, materialColor.a*2.0);
+	d = min(d, gl_Color.a*2.0);
 			
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
-	gl_FrontColor.rgb = materialColor.rgb;
-	gl_FrontColor.a = max(d, materialColor.a);
+	gl_FrontColor.rgb = gl_Color.rgb;
+	gl_FrontColor.a = max(d, gl_Color.a);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
index c169fceb887..9ab986be6d1 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
@@ -1,31 +1,15 @@
-void applyScatter(inout vec3 color);
+/** 
+ * @file lightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
 uniform sampler2D diffuseMap;
 
 void default_lighting() 
 {
-	vec4 color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
-	//applyScatter(color.rgb);
+	color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
 	gl_FragColor = color;
 }
 
-void alpha_lighting() 
-{
-	default_lighting();
-}
-
-void water_lighting(inout vec3 diff)
-{
-	applyScatter(diff);
-}
-
-void terrain_lighting(inout vec3 color)
-{
-	color.rgb *= gl_Color.rgb;
-	applyScatter(color);
-}
-
-vec4 getLightColor()
-{
-	return gl_Color;
-}
\ No newline at end of file
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
new file mode 100644
index 00000000000..b12cca9126b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file lightFullbrightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+
+void fullbright_lighting()
+{
+	gl_FragColor = texture2D(diffuseMap, gl_TexCoord[0].xy);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
new file mode 100644
index 00000000000..bc795a7513b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file lightFullbrightShinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+void fullbright_shiny_lighting() 
+{
+	gl_FragColor = texture2D(diffuseMap, gl_TexCoord[0].xy);
+}
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
new file mode 100644
index 00000000000..b13088fb191
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file lightFullbrightWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+
+void fullbright_lighting_water()
+{
+	gl_FragColor = texture2D(diffuseMap, gl_TexCoord[0].xy);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
new file mode 100644
index 00000000000..bbbd9f3dfef
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
@@ -0,0 +1,46 @@
+/** 
+ * @file lightFuncSpecularV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLight(vec3 n, vec3 l)
+{
+	float a = max(dot(n,l),0.0);
+	return a;
+}
+
+float calcDirectionalSpecular(vec3 view, vec3 n, vec3 l)
+{
+	return pow(max(dot(reflect(view, n),l), 0.0),8.0);
+}
+
+float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da)
+{
+	
+	specular.rgb += calcDirectionalSpecular(view,n,l)*lightCol*da;
+	return max(dot(n,l),0.0);
+}
+
+vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol)
+{
+	//get light vector
+	vec3 lv = l-v;
+	
+	//get distance
+	float d = length(lv);
+	
+	//normalize light vector
+	lv *= 1.0/d;
+	
+	//distance attenuation
+	float da = clamp(1.0/(r * d), 0.0, 1.0);
+	
+	//angular attenuation
+	
+	da *= calcDirectionalLightSpecular(specular, view, n, lv, lightCol, da);
+	
+	return da*lightCol;	
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
new file mode 100644
index 00000000000..3e8fdfb3e48
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
@@ -0,0 +1,34 @@
+/** 
+ * @file lightFuncV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+float calcDirectionalLight(vec3 n, vec3 l)
+{
+	float a = max(dot(n,l),0.0);
+	return a;
+}
+
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la)
+{
+	//get light vector
+	vec3 lv = lp.xyz-v;
+	
+	//get distance
+	float d = length(lv);
+	
+	//normalize light vector
+	lv *= 1.0/d;
+	
+	//distance attenuation
+	float da = clamp(1.0/(la * d), 0.0, 1.0);
+	
+	//angular attenuation
+	da *= calcDirectionalLight(n, lv);
+	
+	return da;	
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
new file mode 100644
index 00000000000..c6f7f8b81bf
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file lightShinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+void shiny_lighting() 
+{
+	color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
new file mode 100644
index 00000000000..75f61ccdf19
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file lightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+void shiny_lighting_water() 
+{
+	color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
new file mode 100644
index 00000000000..853212923cf
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
@@ -0,0 +1,26 @@
+/** 
+ * @file lightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLight(vec3 n, vec3 l);
+
+// Same as non-specular lighting in lightV.glsl
+vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
+{
+	specularColor.rgb = vec3(0.0, 0.0, 0.0);
+	vec4 col;
+	col.a = color.a;
+
+	col.rgb = gl_LightModel.ambient.rgb + baseCol.rgb;
+
+	col.rgb += gl_LightSource[0].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[0].position.xyz);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+
+	return col;	
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
index e3816318a12..8c2813a859a 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
@@ -1,66 +1,11 @@
+/** 
+ * @file lightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-float calcDirectionalLight(vec3 n, vec3 l)
-{
-	float a = max(dot(n,l),0.0);
-	return a;
-}
-
-float calcPointLight(vec3 v, vec3 n, vec3 l, float r, float pw)
-{
-	//get light vector
-	vec3 lv = l-v;
-	
-	//get distance
-	float d = length(lv);
-	
-	//normalize light vector
-	lv *= 1.0/d;
-	
-	//distance attenuation
-	float da = max((r-d)/r, 0.0);
-	
-	//da = pow(da, pw);
-	
-	//angular attenuation
-	da *= calcDirectionalLight(n, lv);
-	
-	return da;	
-}
-
-float calcDirectionalSpecular(vec3 view, vec3 n, vec3 l)
-{
-	float a = max(dot(n,l),0.0);
-	return a;
-}
-
-float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da)
-{
-	
-	specular.rgb += calcDirectionalSpecular(view,n,l)*lightCol*da;
-	return calcDirectionalLight(n,l);
-}
-
-vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol)
-{
-	//get light vector
-	vec3 lv = l-v;
-	
-	//get distance
-	float d = length(lv);
-	
-	//normalize light vector
-	lv *= 1.0/d;
-	
-	//distance attenuation
-	float da = clamp((r-d)/r, 0.0, 1.0);
-
-	//da = pow(da, pw);
-	
-	//angular attenuation
-	da *= calcDirectionalLightSpecular(specular, view, n, lv, lightCol, da);
-	
-	return da*lightCol;	
-}
+float calcDirectionalLight(vec3 n, vec3 l);
 
 vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
 {
@@ -77,23 +22,3 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
 	return col;	
 }
 
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec3 baseLight)
-{
-	return calcLighting(pos, norm, color, vec4(baseLight, 1.0));
-}
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color)
-{
-	return calcLighting(pos, norm, color, vec3(0.0,0.0,0.0));
-}
-
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
-{
-	specularColor.rgb = vec3(0.0, 0.0, 0.0);
-	return calcLighting(pos, norm, color, baseCol);
-}
-
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec3 baseCol)
-{
-	return calcLightingSpecular(pos, norm, color, specularColor, vec4(baseCol, 1.0));
-}
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
new file mode 100644
index 00000000000..81dff1ef39a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file lightWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+void default_lighting_water() 
+{
+	vec4 color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
new file mode 100644
index 00000000000..218585fb86d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
@@ -0,0 +1,35 @@
+/**
+ * @file sumLightsSpecularV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 atmosGetDiffuseSunlightColor();
+vec3 scaleDownLight(vec3 light);
+
+vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
+{
+	vec4 col;
+	col.a = color.a;
+	
+	
+	vec3 view = normalize(pos);
+	
+	/// collect all the specular values from each calcXXXLightSpecular() function
+	vec4 specularSum = vec4(0.0);
+
+	col.rgb = gl_LightSource[1].diffuse.rgb * calcDirectionalLightSpecular(specularColor, view, norm, gl_LightSource[1].position.xyz, gl_LightSource[1].diffuse.rgb, 1.0);
+	col.rgb = scaleDownLight(col.rgb);
+	col.rgb += atmosAmbient(baseCol.rgb);
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, gl_LightSource[0].position.xyz,atmosGetDiffuseSunlightColor() * baseCol.a, 1.0));
+
+	col.rgb = min(col.rgb * color.rgb, 1.0);
+	specularColor.rgb = min(specularColor.rgb * specularSum.rgb, 1.0);
+
+	col.rgb += specularColor.rgb;
+
+	return col;	
+}
diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
new file mode 100644
index 00000000000..e5361033efa
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
@@ -0,0 +1,29 @@
+/**
+ * @file sumLightsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLight(vec3 n, vec3 l);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+
+vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
+{
+	vec4 col;
+	col.a = color.a;
+	
+	col.rgb = gl_LightSource[1].diffuse.rgb * calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	col.rgb += atmosAmbient(baseLight.rgb);
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz));
+	
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+	
+	return col;	
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
new file mode 100755
index 00000000000..1b0ffb911a5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file fullbrightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void fullbright_lighting();
+
+void main() 
+{
+	fullbright_lighting();
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
new file mode 100644
index 00000000000..936c228b4e5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file fullbrightShinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void fullbright_shiny_lighting();
+
+void main() 
+{
+	fullbright_shiny_lighting();
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
new file mode 100755
index 00000000000..ba2aa024dc6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
@@ -0,0 +1,29 @@
+/**
+ * @file fullbrightShinyV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec4 origin;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform();
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vec3 ref = reflect(pos.xyz, -norm);
+
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_TexCoord[1] = gl_TextureMatrix[1]*vec4(ref,1.0);
+
+	calcAtmospherics(pos.xyz);
+
+	gl_FrontColor = gl_Color;
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
new file mode 100755
index 00000000000..e64ccb844d9
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
@@ -0,0 +1,23 @@
+/**
+ * @file fullbrightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform();
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+
+	calcAtmospherics(pos.xyz);
+
+	gl_FrontColor = gl_Color;
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
new file mode 100755
index 00000000000..fd855aa9105
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file fullbrightWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void fullbright_lighting_water();
+
+void main() 
+{
+	fullbright_lighting_water();
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
index 694213219ef..bdb0b05f97d 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
@@ -1,13 +1,13 @@
-void applyScatter(inout vec3 col);
+/** 
+ * @file shinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-uniform samplerCube environmentMap;
+void shiny_lighting();
 
 void main() 
 {
-	vec3 ref = textureCube(environmentMap, gl_TexCoord[0].xyz).rgb;
-			
-	applyScatter(ref);
-		
-	gl_FragColor.rgb = ref;
-	gl_FragColor.a = gl_Color.a;
+	shiny_lighting();
 }
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
index 16fba0154b7..c2e1ddf734f 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
@@ -1,27 +1,30 @@
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file shinyV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
 
 uniform vec4 origin;
 
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+	gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex;
 	
-	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+	calcAtmospherics(pos.xyz);
 	
 	gl_FrontColor = gl_Color;
 	
-	vec3 ref = reflect(pos, norm);
-	
-	vec3 d = pos - origin.xyz;
-	float dist = dot(normalize(d), ref);
-	vec3 e = d + (ref * max(origin.w-dist, 0.0));
-	
-	ref = e - origin.xyz;
+	vec3 ref = reflect(pos.xyz, -norm);
 	
 	gl_TexCoord[0] = gl_TextureMatrix[0]*vec4(ref,1.0);
 	
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
+	gl_FogFragCoord = pos.z;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
new file mode 100755
index 00000000000..0a2a5f624b6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file shinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void shiny_lighting_water();
+
+void main() 
+{
+	shiny_lighting_water();
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
index ce5ab12b74a..7dacca4fe18 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
@@ -1,3 +1,10 @@
+/** 
+ * @file simpleF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
 void default_lighting();
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
index 2aa3521931b..0df89c8fc37 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
@@ -1,20 +1,26 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file simpleV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-attribute vec4 materialColor;
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
 
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+	gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex;
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
-	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
 	
-	default_scatter(pos, gl_LightSource[0].position.xyz);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+	calcAtmospherics(pos.xyz);
 
-	vec4 color = calcLighting(pos, norm, materialColor, gl_Color);
+	vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
 	gl_FrontColor = color;
 
 	gl_FogFragCoord = pos.z;
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
new file mode 100755
index 00000000000..e066b3d02ff
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file simpleWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void default_lighting_water();
+
+void main() 
+{
+	default_lighting_water();
+}
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
new file mode 100644
index 00000000000..248c322011e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file atmosphericsF.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 atmosLighting(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
new file mode 100644
index 00000000000..c2c39e2e103
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
@@ -0,0 +1,34 @@
+/** 
+ * @file atmosphericsHelpersV.glsl 
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 atmosAmbient(vec3 light)
+{
+	return gl_LightModel.ambient.rgb + light;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return gl_LightSource[0].diffuse.rgb * lightIntensity;
+}
+
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return gl_LightSource[0].diffuse.rgb;
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
new file mode 100644
index 00000000000..551b6434032
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file atmosphericsV.glsl 
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void setPositionEye(vec3 v);
+
+void calcAtmospherics(vec3 inPositionEye)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	setPositionEye(inPositionEye);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
new file mode 100644
index 00000000000..c001a4070b9
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
@@ -0,0 +1,13 @@
+/** 
+ * @file atmosphericVarsF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_PositionEye;
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
new file mode 100644
index 00000000000..1b263b08542
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
@@ -0,0 +1,19 @@
+/** 
+ * @file atmosphericVarsV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_PositionEye;
+
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
diff --git a/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
new file mode 100644
index 00000000000..c1ffda15968
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
@@ -0,0 +1,19 @@
+/** 
+ * @file gammaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec4 gamma;
+
+/// Soft clips the light with a gamma correction
+vec3 scaleSoftClip(vec3 light) {
+	// For compatibility with lower cards. Do nothing.
+	return light;
+}
+
+vec3 fullbrightScaleSoftClip(vec3 light) {
+	return scaleSoftClip(light);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
new file mode 100644
index 00000000000..7097906fdd1
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
@@ -0,0 +1,26 @@
+/** 
+ * @file transportF.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 atmosTransport(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
+vec3 fullbrightAtmosTransport(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
+
+vec3 fullbrightShinyAtmosTransport(vec3 light)
+{
+	/* stub function for fallback compatibility on class1 hardware */
+	return light;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
index 7957eddb317..3dd62d2d145 100644
--- a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
+++ b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
@@ -1,8 +1,12 @@
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec3 baseCol);
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file eyeballV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-attribute vec4 materialColor;
-attribute vec4 specularColor;
+vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
 
 void main()
 {
@@ -12,12 +16,15 @@ void main()
 	
 	vec3 pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+	calcAtmospherics(pos.xyz);
 	
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
-	vec4 specular = specularColor;
-	vec4 color = calcLightingSpecular(pos, norm, materialColor, specular, gl_Color.rgb);
+	// vec4 specular = specularColor;
+	vec4 specular = vec4(1.0);
+	vec4 color = calcLightingSpecular(pos, norm, gl_Color, specular, vec4(0.0));
 			
 	gl_FrontColor = color;
 	gl_FogFragCoord = pos.z;
+
 }
 
diff --git a/indra/newview/app_settings/shaders/class2/effects/blurF.glsl b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl
new file mode 100644
index 00000000000..94433202afd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl
@@ -0,0 +1,31 @@
+/**
+ * @file blurf.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect RenderTexture;
+uniform float bloomStrength;
+
+varying vec4 gl_TexCoord[gl_MaxTextureCoords];
+void main(void) 
+{
+	float blurWeights[7];
+	blurWeights[0] = 0.05;
+	blurWeights[1] = 0.1;
+	blurWeights[2] = 0.2;
+	blurWeights[3] = 0.3;
+	blurWeights[4] = 0.2;
+	blurWeights[5] = 0.1;
+	blurWeights[6] = 0.05;
+	
+	vec3 color = vec3(0,0,0);
+	for (int i = 0; i < 7; i++){
+		color += vec3(texture2DRect(RenderTexture, gl_TexCoord[i].st)) * blurWeights[i];
+	}
+
+	color *= bloomStrength;
+
+	gl_FragColor = vec4(color, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/blurV.glsl b/indra/newview/app_settings/shaders/class2/effects/blurV.glsl
new file mode 100644
index 00000000000..ba65b16cc11
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/blurV.glsl
@@ -0,0 +1,35 @@
+/**
+ * @file blurV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec2 texelSize;
+uniform vec2 blurDirection;
+uniform float blurWidth;
+
+void main(void)
+{
+	// Transform vertex
+	gl_Position = ftransform();
+	
+	vec2 blurDelta = texelSize * blurDirection * vec2(blurWidth, blurWidth);
+	vec2 s = gl_MultiTexCoord0.st - (blurDelta * 3.0);
+	
+	// for (int i = 0; i < 7; i++) {
+		// gl_TexCoord[i].st = s + (i * blurDelta);
+	// }
+
+	// MANUALLY UNROLL
+	gl_TexCoord[0].st = s;
+	gl_TexCoord[1].st = s + blurDelta;
+	gl_TexCoord[2].st = s + (2. * blurDelta);
+	gl_TexCoord[3].st = s + (3. * blurDelta);
+	gl_TexCoord[4].st = s + (4. * blurDelta);
+	gl_TexCoord[5].st = s + (5. * blurDelta);
+	gl_TexCoord[6].st = s + (6. * blurDelta);
+
+	// gl_TexCoord[0].st = s;
+	// gl_TexCoord[1].st = blurDelta;
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl b/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
new file mode 100644
index 00000000000..623ef7a81a5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
@@ -0,0 +1,31 @@
+/**
+ * @file colorFilterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect RenderTexture;
+uniform float brightness;
+uniform float contrast;
+uniform vec3  contrastBase;
+uniform float saturation;
+uniform vec3  lumWeights;
+
+const float gamma = 2.0;
+
+void main(void) 
+{
+	vec3 color = vec3(texture2DRect(RenderTexture, gl_TexCoord[0].st));
+
+	/// Modulate brightness
+	color *= brightness;
+
+	/// Modulate contrast
+	color = mix(contrastBase, color, contrast);
+
+	/// Modulate saturation
+	color = mix(vec3(dot(color, lumWeights)), color, saturation);
+
+	gl_FragColor = vec4(color, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl b/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
new file mode 100644
index 00000000000..29c2a0948c2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
@@ -0,0 +1,14 @@
+/**
+ * @file drawQuadV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void main(void)
+{
+	//transform vertex
+	gl_Position = ftransform();
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+	gl_TexCoord[1] = gl_MultiTexCoord1;
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/extractF.glsl b/indra/newview/app_settings/shaders/class2/effects/extractF.glsl
new file mode 100644
index 00000000000..a1583b13ebb
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/extractF.glsl
@@ -0,0 +1,22 @@
+/**
+ * @file extractF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect RenderTexture;
+uniform float extractLow;
+uniform float extractHigh;
+uniform vec3 lumWeights;
+
+void main(void) 
+{
+	/// Get scene color
+	vec3 color = vec3(texture2DRect(RenderTexture, gl_TexCoord[0].st));
+	
+	/// Extract luminance and scale up by night vision brightness
+	float lum = smoothstep(extractLow, extractHigh, dot(color, lumWeights));
+
+	gl_FragColor = vec4(vec3(lum), 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl b/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
new file mode 100644
index 00000000000..271d5cf8d64
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
@@ -0,0 +1,42 @@
+/**
+ * @file nightVisionF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect RenderTexture;
+uniform sampler2D NoiseTexture;
+uniform float brightMult;
+uniform float noiseStrength;
+
+float luminance(vec3 color)
+{
+	/// CALCULATING LUMINANCE (Using NTSC lum weights)
+	/// http://en.wikipedia.org/wiki/Luma_%28video%29
+	return dot(color, vec3(0.299, 0.587, 0.114));
+}
+
+void main(void) 
+{
+	/// Get scene color
+	vec3 color = vec3(texture2DRect(RenderTexture, gl_TexCoord[0].st));
+	
+	/// Extract luminance and scale up by night vision brightness
+	float lum = luminance(color) * brightMult;
+
+	/// Convert into night vision color space
+	/// Newer NVG colors (crisper and more saturated)
+	vec3 outColor = (lum * vec3(0.91, 1.21, 0.9)) + vec3(-0.07, 0.1, -0.12); 
+
+	/// Add noise
+	float noiseValue = texture2D(NoiseTexture, gl_TexCoord[1].st).r;
+	noiseValue = (noiseValue - 0.5) * noiseStrength;
+
+	/// Older NVG colors (more muted)
+	// vec3 outColor = (lum * vec3(0.82, 0.75, 0.83)) + vec3(0.05, 0.32, -0.11); 
+	
+	outColor += noiseValue;
+
+	gl_FragColor = vec4(outColor, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl b/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
new file mode 100644
index 00000000000..e55d278b81f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
@@ -0,0 +1,14 @@
+/**
+ * @file simpleF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect RenderTexture;
+
+void main(void) 
+{
+	vec3 color = vec3(texture2DRect(RenderTexture, gl_TexCoord[0].st));
+	gl_FragColor = vec4(1.0 - color, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
new file mode 100644
index 00000000000..4253bc21c3a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
@@ -0,0 +1,38 @@
+/**
+ * @file terrainF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D detail_0;
+uniform sampler2D detail_1;
+uniform sampler2D detail_2;
+uniform sampler2D detail_3;
+uniform sampler2D alpha_ramp;
+
+vec3 atmosLighting(vec3 light);
+
+vec3 scaleSoftClip(vec3 color);
+
+void main()
+{
+	/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
+	
+	/// TODO Confirm tex coords and bind them appropriately in vert shader.
+	vec4 color0 = texture2D(detail_0, gl_TexCoord[0].xy);
+	vec4 color1 = texture2D(detail_1, gl_TexCoord[0].xy);
+	vec4 color2 = texture2D(detail_2, gl_TexCoord[0].xy);
+	vec4 color3 = texture2D(detail_3, gl_TexCoord[0].xy);
+
+	float alpha1 = texture2D(alpha_ramp, gl_TexCoord[0].zw).a;
+	float alpha2 = texture2D(alpha_ramp,gl_TexCoord[1].xy).a;
+	float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a;
+	vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal );
+	
+	/// Add WL Components
+	outColor.rgb = atmosLighting(outColor.rgb * gl_Color.rgb);
+	
+	gl_FragColor = vec4(scaleSoftClip(outColor.rgb), 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
new file mode 100644
index 00000000000..119d55a2cd8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
@@ -0,0 +1,52 @@
+/**
+ * @file terrainV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+
+vec4 texgen_object(vec4  vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
+{
+	vec4 tcoord;
+	
+	tcoord.x = dot(vpos, tp0);
+	tcoord.y = dot(vpos, tp1);
+	tcoord.z = tc.z;
+	tcoord.w = tc.w;
+	
+	tcoord = mat * tcoord; 
+	
+	return tcoord; 
+}
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform();
+
+	vec4 pos = gl_ModelViewMatrix * gl_Vertex;
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+	/// Potentially better without it for water.
+	pos /= pos.w;
+
+	calcAtmospherics((gl_ModelViewMatrix * gl_Vertex).xyz);
+
+	vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0));
+	
+	gl_FrontColor = color;
+
+	// Transform and pass tex coords
+ 	gl_TexCoord[0].xy = texgen_object(gl_Vertex, gl_MultiTexCoord0, gl_TextureMatrix[0], gl_ObjectPlaneS[0], gl_ObjectPlaneT[0]).xy;
+	
+	vec4 t = gl_MultiTexCoord1;
+	
+	gl_TexCoord[0].zw = t.xy;
+	gl_TexCoord[1].xy = t.xy-vec2(2.0, 0.0);
+	gl_TexCoord[1].zw = t.xy-vec2(1.0, 0.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
new file mode 100755
index 00000000000..3a98970f8c7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
@@ -0,0 +1,39 @@
+/**
+ * @file terrainWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D detail_0;
+uniform sampler2D detail_1;
+uniform sampler2D detail_2;
+uniform sampler2D detail_3;
+uniform sampler2D alpha_ramp;
+
+vec3 atmosLighting(vec3 light);
+
+vec4 applyWaterFog(vec4 color);
+
+void main()
+{
+	/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
+	
+	/// TODO Confirm tex coords and bind them appropriately in vert shader.
+	vec4 color0 = texture2D(detail_0, gl_TexCoord[0].xy);
+	vec4 color1 = texture2D(detail_1, gl_TexCoord[0].xy);
+	vec4 color2 = texture2D(detail_2, gl_TexCoord[0].xy);
+	vec4 color3 = texture2D(detail_3, gl_TexCoord[0].xy);
+
+	float alpha1 = texture2D(alpha_ramp, gl_TexCoord[0].zw).a;
+	float alpha2 = texture2D(alpha_ramp,gl_TexCoord[1].xy).a;
+	float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a;
+	vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal );
+	
+	/// Add WL Components
+	outColor.rgb = atmosLighting(outColor.rgb * gl_Color.rgb);
+	
+	outColor = applyWaterFog(outColor);
+	gl_FragColor = outColor;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
new file mode 100644
index 00000000000..1998fea227a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
@@ -0,0 +1,88 @@
+/**
+ * @file underWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+uniform sampler2D screenDepth;
+
+uniform vec4 fogCol;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform vec2 fbScale;
+uniform float refScale;
+uniform float znear;
+uniform float zfar;
+uniform float kd;
+uniform vec4 waterPlane;
+uniform vec3 eyeVec;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+uniform vec2 screenRes;
+
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+
+vec4 applyWaterFog(vec4 color, vec3 viewVec)
+{
+	//normalize view vector
+	vec3 view = normalize(viewVec);
+	float es = -view.z;
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	//get object depth
+	float depth = length(viewVec);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	//return vec4(1.0, 0.0, 1.0, 1.0);
+	return color * D + kc * L;
+	//depth /= 10.0;
+	//return vec4(depth,depth,depth,0.0);
+}
+
+void main() 
+{
+	vec4 color;
+	    
+	//get detail normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;    
+	vec3 wavef = normalize(wave1+wave2+wave3);
+	
+	//figure out distortion vector (ripply)   
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	distort = distort+wavef.xy*refScale;
+		
+	vec4 fb = texture2D(screenTex, distort);
+	
+	gl_FragColor = applyWaterFog(fb,view.xyz);
+}
diff --git a/indra/newview/app_settings/shaders/class2/environment/waterF.glsl b/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
index 11a057b1777..8f3d11badc3 100644
--- a/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
@@ -1,138 +1,117 @@
-void applyScatter(inout vec3 color);
+/** 
+ * @file waterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 scaleSoftClip(vec3 inColor);
+vec3 atmosTransport(vec3 inColor);
 
-uniform sampler2D diffuseMap;
 uniform sampler2D bumpMap;   
-uniform samplerCube environmentMap; //: TEXUNIT4,   // Environment map texture
-uniform sampler2D screenTex;   //   : TEXUNIT5
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
 
+uniform float sunAngle;
+uniform float sunAngle2;
 uniform vec3 lightDir;
 uniform vec3 specular;
 uniform float lightExp;
-uniform vec2 fbScale;
 uniform float refScale;
+uniform float kd;
+uniform vec2 screenRes;
+uniform vec3 normScale;
+uniform float fresnelScale;
+uniform float fresnelOffset;
+uniform float blurMultiplier;
 
-float msin(float x) {
-   float k = sin(x)+1.0;
-   k *= 0.5;
-   k *= k;
-   return 2.0 * k;
-}
 
-float mcos(float x) {
-   float k = cos(x)+1.0;
-   k *= 0.5;
-   k *= k;
-   return 2.0 * k;
-}
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
 
-float waveS(vec2 v, float t, float a, float f, vec2 d, float s, sampler1D sinMap) 
+void main() 
 {
-   return texture1D(sinMap, (dot(d, v)*f + t*s)*f).r*a;
-}
+	vec4 color;
+	
+	float dist = length(view.xy);
+	
+	//normalize view vector
+	vec3 viewVec = normalize(view.xyz);
+	
+	//get wave normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;
+	//get base fresnel components	
+	
+	vec3 df = vec3(
+					dot(viewVec, wave1),
+					dot(viewVec, wave2),
+					dot(viewVec, wave3)
+				 ) * fresnelScale + fresnelOffset;
+	df *= df;
+		    
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	
+	float dist2 = dist;
+	dist = max(dist, 5.0);
+	
+	float dmod = sqrt(dist);
+	
+	vec2 dmod_scale = vec2(dmod*dmod, dmod);
+	
+	//get reflected color
+	vec2 refdistort1 = wave1.xy*normScale.x;
+	vec2 refvec1 = distort+refdistort1/dmod_scale;
+	vec4 refcol1 = texture2D(refTex, refvec1);
+	
+	vec2 refdistort2 = wave2.xy*normScale.y;
+	vec2 refvec2 = distort+refdistort2/dmod_scale;
+	vec4 refcol2 = texture2D(refTex, refvec2);
+	
+	vec2 refdistort3 = wave3.xy*normScale.z;
+	vec2 refvec3 = distort+refdistort3/dmod_scale;
+	vec4 refcol3 = texture2D(refTex, refvec3);
 
-float waveC(vec2 v, float t, float a, float f, vec2 d, float s, sampler1D sinMap) 
-{
-   return texture1D(sinMap, (dot(d, v)*f + t*s)*f).g*a*2.0-1.0;
-}
+	vec4 refcol = refcol1 + refcol2 + refcol3;
+	float df1 = df.x + df.y + df.z;
+	refcol *= df1 * 0.333;
+	
+	vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
+	
+	wavef.z *= max(-viewVec.z, 0.1);
+	wavef = normalize(wavef);
+	
+	float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset;
+	
+	vec2 refdistort4 = wavef.xy*0.125;
+	refdistort4.y -= abs(refdistort4.y);
+	vec2 refvec4 = distort+refdistort4/dmod;
+	float dweight = min(dist2*blurMultiplier, 1.0);
+	vec4 baseCol = texture2D(refTex, refvec4);
+	refcol = mix(baseCol*df2, refcol, dweight);
 
-float magnitude(vec3 vec) {
-   return sqrt(dot(vec,vec));
-}
-
-vec3 mreflect(vec3 i, vec3 n) {
-   return i + n * 2.0 * abs(dot(n,i))+vec3(0.0,0.0,0.5);
-}
-
-void main() 
-{
-   vec2 texCoord = gl_TexCoord[0].xy;   // Texture coordinates
-   vec2 littleWave1 = gl_TexCoord[0].zw;
-   vec2 littleWave2 = gl_TexCoord[1].xy;
-   vec2 bigWave = gl_TexCoord[1].zw;
-   vec3 viewVec = gl_TexCoord[2].xyz;
-   vec4 refCoord = gl_TexCoord[3];
-   vec4 col = gl_Color;
-   vec4 color;
-   
-   //get color from alpha map (alpha denotes water depth), rgb denotes water color
-   vec4 wcol = texture2D(diffuseMap, texCoord.xy);
-      
-   //store texture alpha
-   float da = wcol.a;
-         
-   //modulate by incoming water color
-   //wcol.a *= refCoord.w;
-   
-   //scale wcol.a (water depth) for steep transition
-   wcol.a *= wcol.a;
-   
-   //normalize view vector
-   viewVec = normalize(viewVec);
-   
-   //get bigwave normal
-   vec3 wavef = texture2D(bumpMap, bigWave).xyz*2.0;
-      
-   vec3 view = vec3(viewVec.x, viewVec.y, viewVec.z);
-   
-   float dx = 1.0-(dot(wavef*2.0-vec3(1.0), view))*da;
-   dx *= 0.274;
-      
-   //get detail normals
-   vec3 dcol = texture2D(bumpMap, littleWave1+dx*view.xy).rgb*0.75;
-   dcol += texture2D(bumpMap, littleWave2+view.xy*dx*0.1).rgb*1.25;
-      
-   //interpolate between big waves and little waves (big waves in deep water)
-   wavef = wavef*wcol.a + dcol*(1.0-wcol.a);
-   
-   //crunch normal to range [-1,1]
-   wavef -= vec3(1,1,1);
-   
-   //get base fresnel component
-   float df = dot(viewVec,wavef);
-   //reposition fresnel to latter half of [0,1]
-   df = 1.0-clamp(df,0.0,1.0);
+	//get specular component
+	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+		
+	//harden specular
+	spec = pow(spec, 128.0);
 
-   //set output alpha based on fresnel
-   color.a = clamp((df+da)*0.5,0.0,1.0);
-      
-   //calculate reflection vector
-   vec3 ref = reflect(viewVec.xyz, wavef);
-   
-   //get specular component
-   float spec = clamp(dot(lightDir, normalize(ref)),0.0,1.0);
-      
-   //fudge reflection to be more noisy at good angles
-   ref.z = ref.z*ref.z+df*df*0.5;
-   
-   //get diffuse component
-   float diff = clamp((abs(dot(ref, wavef))),0.0,1.0)*0.9;
-      
-   //fudge diffuse for extra contrast and ambience
-   diff *= diff;      
-   diff += 0.4;
-    
-   //set diffuse color contribution
-   color.rgb = textureCube(environmentMap, ref).rgb*diff;
-   
-   //harden specular
-   spec = pow(spec, lightExp);
-   
-   //add specular color contribution
-   color.rgb += spec * specular;
+	//figure out distortion vector (ripply)   
+	vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0);
+		
+	vec4 fb = texture2D(screenTex, distort2);
+	
+	//mix with reflection
+	// Note we actually want to use just df1, but multiplying by 0.999999 gets around and nvidia compiler bug
+	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
+	color.rgb += spec * specular;
+	
+	color.rgb = atmosTransport(color.rgb);
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = spec * sunAngle2;
 
-   //figure out distortion vector (ripply)   
-   vec2 distort = clamp(((refCoord.xy/refCoord.z) * 0.5 + 0.5 + wavef.xy*refScale),0.0,0.99);
-   
-   //read from framebuffer (offset)
-   vec4 fb = texture2D(screenTex, distort*fbScale);
-   
-   //tint by framebuffer
-   color.rgb = color.a*color.rgb + (1.0-color.a)*fb.rgb;
-   
-   //apply fog
-   applyScatter(color.rgb);
-   
-   color.a = spec*0.5+fb.a;
-   
-   gl_FragColor = color;
+	gl_FragColor = color;
 }
diff --git a/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
new file mode 100644
index 00000000000..522c990cf8e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
@@ -0,0 +1,54 @@
+/**
+ * @file waterFogF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec4 lightnorm;
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec3 getPositionEye();
+
+vec4 applyWaterFog(vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(getPositionEye());
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(getPositionEye() - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
index 6f732ed731c..b372d662982 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
@@ -1,36 +1,23 @@
-void applyScatter(inout vec3 color);
+/** 
+ * @file lightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
 uniform sampler2D diffuseMap;
 
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
 void default_lighting() 
 {
-	vec4 color = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
-	//applyScatter(color.rgb);
-	gl_FragColor = color;
-}
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	
+	color.rgb = atmosLighting(color.rgb);
 
-void alpha_lighting() 
-{
-	vec4 diff = texture2D(diffuseMap, gl_TexCoord[0].xy);
-	vec3 color = gl_Color.rgb * diff.rgb;
-	applyScatter(color);
-	gl_FragColor.rgb = color;
-	gl_FragColor.a = diff.a * gl_Color.a;	
-}
+	color.rgb = scaleSoftClip(color.rgb);
 
-void water_lighting(inout vec3 diff)
-{
-	diff = (diff*0.9 + gl_Color.rgb*0.1);
-	applyScatter(diff);
-}
-
-void terrain_lighting(inout vec3 color)
-{
-	color.rgb *= gl_Color.rgb;
-	applyScatter(color);
+	gl_FragColor = color;
 }
 
-vec4 getLightColor()
-{
-	return gl_Color;
-}
\ No newline at end of file
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
new file mode 100644
index 00000000000..e6b6d858081
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
@@ -0,0 +1,23 @@
+/** 
+ * @file lightFullbrightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+vec3 fullbrightAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+void fullbright_lighting()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	
+	color.rgb = fullbrightAtmosTransport(color.rgb);
+	
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
new file mode 100644
index 00000000000..8f408c04362
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
@@ -0,0 +1,30 @@
+/** 
+ * @file lightFullbrightShinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+vec3 fullbrightShinyAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+void fullbright_shiny_lighting()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
+
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	color.a = max(color.a, gl_Color.a);
+
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
new file mode 100644
index 00000000000..060ad9cb671
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
@@ -0,0 +1,21 @@
+/** 
+ * @file lightFullbrightWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+vec3 fullbrightAtmosTransport(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void fullbright_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+
+	color.rgb = fullbrightAtmosTransport(color.rgb);
+	
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
new file mode 100644
index 00000000000..b3927c77a67
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
@@ -0,0 +1,29 @@
+/** 
+ * @file lightShinyF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+vec3 scaleSoftClip(vec3 light);
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void shiny_lighting()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = max(color.a, gl_Color.a);
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
new file mode 100644
index 00000000000..f090306be6f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
@@ -0,0 +1,27 @@
+/** 
+ * @file lightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void shiny_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = atmosLighting(color.rgb);
+	color.a = max(color.a, gl_Color.a);
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
new file mode 100644
index 00000000000..c3384ffc5dd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
@@ -0,0 +1,16 @@
+/** 
+ * @file lightSpecularV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// All lights, no specular highlights
+
+vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol);
+
+vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
+{
+	return sumLightsSpecular(pos, norm, color, specularColor, baseCol);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
index b15960dea2d..ff3bcb5cd2b 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
@@ -1,126 +1,16 @@
-// All lights, no specular highlights
-
-float calcDirectionalLight(vec3 n, vec3 l)
-{
-	float a = max(dot(n,l),0.0);
-	return a;
-}
-
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la)
-{
-	//get light vector
-	vec3 lv = lp.xyz-v;
-	
-	//get distance
-	float d = length(lv);
-	
-	//normalize light vector
-	lv *= 1.0/d;
-	
-	//distance attenuation
-	float da = clamp(1.0/(la * d), 0.0, 1.0);
-	
-	//angular attenuation
-	da *= calcDirectionalLight(n, lv);
-	
-	return da;	
-}
+/** 
+ * @file lightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-float calcDirectionalSpecular(vec3 view, vec3 n, vec3 l)
-{
-	return pow(max(dot(reflect(view, n),l), 0.0),8.0);
-}
+// All lights, no specular highlights
 
-float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da)
-{
-	
-	specular.rgb += calcDirectionalSpecular(view,n,l)*lightCol*da;
-	return calcDirectionalLight(n,l);
-}
-
-vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol)
-{
-	//get light vector
-	vec3 lv = l-v;
-	
-	//get distance
-	float d = length(lv);
-	
-	//normalize light vector
-	lv *= 1.0/d;
-	
-	//distance attenuation
-	float da = clamp(1.0/(r * d), 0.0, 1.0);
-	
-	//angular attenuation
-	
-	da *= calcDirectionalLightSpecular(specular, view, n, lv, lightCol, da);
-	
-	return da*lightCol;	
-}
+vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight);
 
 vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
 {
-	vec4 col;
-	col.a = color.a;
-	
-	col.rgb = gl_LightModel.ambient.rgb + baseLight.rgb;
-	
-	col.rgb += gl_LightSource[0].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[0].position.xyz);
-	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
-	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
-	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
-				
-	col.rgb = min(col.rgb*color.rgb, 1.0);
-	
-	gl_FrontColor = vec4(col.rgb, col.a);
-	return col;	
-}
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec3 baseLight)
-{
-	return calcLighting(pos, norm, color, vec4(baseLight, 1.0));
-}
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color)
-{
-	return calcLighting(pos, norm, color, vec3(0.0,0.0,0.0));
+	return sumLights(pos, norm, color, baseLight);
 }
 
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
-{
-	vec4 col;
-	col.a = color.a;
-	
-	col.rgb = gl_LightModel.ambient.rgb;
-	
-	vec3 view = normalize(pos);
-	
-	vec4 specular = specularColor;
-	specularColor.rgb = vec3(0.0, 0.0, 0.0);
-	
-	col.rgb += baseCol.a*gl_LightSource[0].diffuse.rgb*calcDirectionalLightSpecular(specularColor, view, norm, gl_LightSource[0].position.xyz,gl_LightSource[0].diffuse.rgb*baseCol.a, 1.0);
-	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLightSpecular(specularColor, view, norm, gl_LightSource[1].position.xyz,gl_LightSource[1].diffuse.rgb, 1.0);
-	col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[2].position.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation,gl_LightSource[2].diffuse.rgb);
-	col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[3].position.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation,gl_LightSource[3].diffuse.rgb);
-	col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[4].position.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation,gl_LightSource[4].diffuse.rgb);
-	col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[5].position.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation,gl_LightSource[5].diffuse.rgb);
-	//col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[6].position.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation,gl_LightSource[6].diffuse.rgb);
-	//col.rgb += calcPointLightSpecular(specularColor, view, pos, norm, gl_LightSource[7].position.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation,gl_LightSource[7].diffuse.rgb);
-	col.rgb += baseCol.rgb;
-						
-	col.rgb = min(col.rgb*color.rgb, 1.0);
-	specularColor.rgb = min(specularColor.rgb*specular.rgb, 1.0);
-
-	gl_FrontColor = vec4(col.rgb+specularColor.rgb,col.a);	
-	return col;	
-}
-
-vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec3 baseCol)
-{
-	return calcLightingSpecular(pos, norm, color, specularColor, vec4(baseCol, 1.0));
-}
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
new file mode 100644
index 00000000000..086954cd47b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
@@ -0,0 +1,21 @@
+/** 
+ * @file lightWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void default_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+
+	color.rgb = atmosLighting(color.rgb);
+
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
new file mode 100644
index 00000000000..edd1a8a9465
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
@@ -0,0 +1,41 @@
+/**
+ * @file sumLightsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
+vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 atmosGetDiffuseSunlightColor();
+vec3 scaleDownLight(vec3 light);
+
+vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
+{
+	vec4 col = vec4(0.0, 0.0, 0.0, color.a);
+	
+	vec3 view = normalize(pos);
+	
+	/// collect all the specular values from each calcXXXLightSpecular() function
+	vec4 specularSum = vec4(0.0);
+	
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[1].diffuse.rgb * calcDirectionalLightSpecular(specularColor, view, norm, gl_LightSource[1].position.xyz, gl_LightSource[1].diffuse.rgb, 1.0);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[2].position.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[3].position.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation, gl_LightSource[3].diffuse.rgb);
+	//col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[4].position.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].diffuse.rgb);
+	col.rgb = scaleDownLight(col.rgb);
+						
+	// Add windlight lights
+	col.rgb += atmosAmbient(baseCol.rgb);
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, gl_LightSource[0].position.xyz, atmosGetDiffuseSunlightColor()*baseCol.a, 1.0));
+
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+	specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0);
+	col.rgb += specularColor.rgb;
+
+	return col;	
+}
diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
new file mode 100644
index 00000000000..f4c59734a47
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
@@ -0,0 +1,34 @@
+/**
+ * @file sumLightsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+
+vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
+{
+	vec4 col = vec4(0.0, 0.0, 0.0, color.a);
+	
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[1].diffuse.rgb * calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb += gl_LightSource[2].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	//col.rgb += gl_LightSource[4].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb = scaleDownLight(col.rgb);
+
+	// Add windlight lights
+	col.rgb += atmosAmbient(baseLight.rgb);
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz));
+				
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+	
+	return col;	
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
new file mode 100755
index 00000000000..0d52f32a2e8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
@@ -0,0 +1,31 @@
+/**
+ * @file shinyV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec4 origin;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform();
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vec3 ref = reflect(pos.xyz, -norm);
+
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_TexCoord[1] = gl_TextureMatrix[1]*vec4(ref,1.0);
+
+	calcAtmospherics(pos.xyz);
+
+	gl_FrontColor = calcLighting(pos.xyz, norm, gl_Color, vec4(0.0));
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
new file mode 100644
index 00000000000..92c0664a5e6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
@@ -0,0 +1,24 @@
+/** 
+ * @file atmosphericsF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//////////////////////////////////////////////////////////
+// The fragment shader for the terrain atmospherics
+//////////////////////////////////////////////////////////
+
+vec3 getAdditiveColor();
+vec3 getAtmosAttenuation();
+
+uniform sampler2D cloudMap;
+uniform vec4 cloud_pos_density1;
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
new file mode 100644
index 00000000000..32d5ed5db2f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
@@ -0,0 +1,41 @@
+/**
+ * @file atmosphericsHelpersV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// Output variables
+vec3 getSunlitColor();
+vec3 getAmblitColor();
+vec3 getAdditiveColor();
+vec3 getAtmosAttenuation();
+vec3 getPositionEye();
+
+uniform float scene_light_strength;
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + light / 2.0;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * lightIntensity;
+}
+
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / scene_light_strength );
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * scene_light_strength);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
new file mode 100644
index 00000000000..e40372e819a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
@@ -0,0 +1,137 @@
+/**
+ * @file atmosphericsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// varying param funcs
+void setSunlitColor(vec3 v);
+void setAmblitColor(vec3 v);
+void setAdditiveColor(vec3 v);
+void setAtmosAttenuation(vec3 v);
+void setPositionEye(vec3 v);
+
+vec3 getAdditiveColor();
+
+//varying vec4 vary_CloudUVs;
+//varying float vary_CloudDensity;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 distance_multiplier;
+uniform vec4 max_y;
+uniform vec4 glow;
+
+void calcAtmospherics(vec3 inPositionEye) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	//(TERRAIN) limit altitude
+	if (P.y > max_y.x) P *= (max_y.x / P.y);
+	if (P.y < -max_y.x) P *= (-max_y.x / P.y);
+
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float  Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density.r);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density.r) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier.x);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	//vary_AtmosAttenuation = distance_multiplier / 10000.;
+	//vary_AtmosAttenuation = density_multiplier * 100.;
+	//vary_AtmosAttenuation = vec4(Plen / 100000., 0., 0., 1.);
+
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+
+
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient)
+	  + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x
+		  + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+
+	// vary_SunlitColor = vec3(0);
+	// vary_AmblitColor = vec3(0);
+	// vary_AdditiveColor = vec4(Pn, 1.0);
+
+	/*
+	const float cloudShadowScale = 100.;
+	// Get cloud uvs for shadowing
+	vec3 cloudPos = inPositionEye + camPosWorld - cloudShadowScale / 2.;
+	vary_CloudUVs.xy = cloudPos.xz / cloudShadowScale;
+
+	// We can take uv1 and multiply it by (TerrainSpan / CloudSpan)
+//	cloudUVs *= (((worldMaxZ - worldMinZ) * 20) /40000.);
+	vary_CloudUVs *= (10000./40000.);
+
+	// Offset by sun vector * (CloudAltitude / CloudSpan)
+	vary_CloudUVs.x += tmpLightnorm.x / tmpLightnorm.y * (3000./40000.);
+	vary_CloudUVs.y += tmpLightnorm.z / tmpLightnorm.y * (3000./40000.);
+	*/
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
new file mode 100644
index 00000000000..0dbf2d35e7c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
@@ -0,0 +1,34 @@
+/** 
+ * @file atmosphericVars.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_PositionEye;
+
+varying vec3 vary_SunlitColor;
+varying vec3 vary_AmblitColor;
+varying vec3 vary_AdditiveColor;
+varying vec3 vary_AtmosAttenuation;
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
new file mode 100644
index 00000000000..b528837a5fd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
@@ -0,0 +1,60 @@
+/** 
+ * @file atmosphericVars.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_PositionEye;
+
+varying vec3 vary_SunlitColor;
+varying vec3 vary_AmblitColor;
+varying vec3 vary_AdditiveColor;
+varying vec3 vary_AtmosAttenuation;
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
new file mode 100644
index 00000000000..b7d7e5a2c29
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
@@ -0,0 +1,76 @@
+/** 
+ * @file WLCloudsF.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+/////////////////////////////////////////////////////////////////////////
+// The fragment shader for the sky
+/////////////////////////////////////////////////////////////////////////
+
+varying vec4 vary_CloudColorSun;
+varying vec4 vary_CloudColorAmbient;
+varying float vary_CloudDensity;
+
+uniform sampler2D cloud_noise_texture;
+uniform vec4 cloud_pos_density1;
+uniform vec4 cloud_pos_density2;
+uniform vec4 gamma;
+
+/// Soft clips the light with a gamma correction
+vec3 scaleSoftClip(vec3 light) {
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+void main()
+{
+	// Set variables
+	vec2 uv1 = gl_TexCoord[0].xy;
+	vec2 uv2 = gl_TexCoord[1].xy;
+
+	vec4 cloudColorSun = vary_CloudColorSun;
+	vec4 cloudColorAmbient = vary_CloudColorAmbient;
+	float cloudDensity = vary_CloudDensity;
+	vec2 uv3 = gl_TexCoord[2].xy;
+	vec2 uv4 = gl_TexCoord[3].xy;
+
+	// Offset texture coords
+	uv1 += cloud_pos_density1.xy;	//large texture, visible density
+	uv2 += cloud_pos_density1.xy;	//large texture, self shadow
+	uv3 += cloud_pos_density2.xy;	//small texture, visible density
+	uv4 += cloud_pos_density2.xy;	//small texture, self shadow
+
+
+	// Compute alpha1, the main cloud opacity
+	float alpha1 = (texture2D(cloud_noise_texture, uv1).x - 0.5) + (texture2D(cloud_noise_texture, uv3).x - 0.5) * cloud_pos_density2.z;
+	alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10. * cloud_pos_density1.z, 1.);
+
+	// And smooth
+	alpha1 = 1. - alpha1 * alpha1;
+	alpha1 = 1. - alpha1 * alpha1;	
+
+
+	// Compute alpha2, for self shadowing effect
+	// (1 - alpha2) will later be used as percentage of incoming sunlight
+	float alpha2 = (texture2D(cloud_noise_texture, uv2).x - 0.5);
+	alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.);
+
+	// And smooth
+	alpha2 = 1. - alpha2;
+	alpha2 = 1. - alpha2 * alpha2;	
+
+	// Combine
+	vec4 color;
+	color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient);
+	color *= 2.;
+
+	/// Gamma correct for WL (soft clip effect).
+	gl_FragColor.rgb = scaleSoftClip(color.rgb);
+	gl_FragColor.a = alpha1;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
new file mode 100644
index 00000000000..e149d5861f7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
@@ -0,0 +1,163 @@
+/** 
+ * @file WLCloudsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//////////////////////////////////////////////////////////////////////////
+// The vertex shader for creating the atmospheric sky
+///////////////////////////////////////////////////////////////////////////////
+
+// Output parameters
+varying vec4 vary_CloudColorSun;
+varying vec4 vary_CloudColorAmbient;
+varying float vary_CloudDensity;
+
+// Inputs
+uniform vec3 camPosLocal;
+
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 max_y;
+
+uniform vec4 glow;
+
+uniform vec4 cloud_color;
+
+uniform vec4 cloud_scale;
+
+void main()
+{
+
+	// World / view / projection
+	gl_Position = ftransform();
+
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+
+	// Get relative position
+	vec3 P = gl_Vertex.xyz - camPosLocal.xyz + vec3(0,50,0);
+
+	// Set altitude
+	if (P.y > 0.)
+	{
+		P *= (max_y.x / P.y);
+	}
+	else
+	{
+		P *= (-32000. / P.y);
+	}
+
+	// Can normalize then
+	vec3 Pn = normalize(P);
+	float  Plen = length(P);
+
+	// Initialize temp variables
+	vec4 temp1 = vec4(0.);
+	vec4 temp2 = vec4(0.);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+
+	// Sunlight attenuation effect (hue and brightness) due to atmosphere
+	// this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + haze_density.x * 0.25) * (density_multiplier.x * max_y.x);
+
+	// Calculate relative weights
+	temp1 = blue_density + haze_density.x;
+	blue_weight = blue_density / temp1;
+	haze_weight = haze_density.x / temp1;
+
+	// Compute sunlight from P & lightnorm (for long rays like sky)
+	temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y );
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// Distance
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z);
+
+
+	// Compute haze glow
+	temp2.x = dot(Pn, lightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		// temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .001);	
+		// Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		// Higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		// glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	// Add "minimum anti-solar illumination"
+	temp2.x += .25;
+
+	// Increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient;
+	tmpAmbient += (1. - tmpAmbient) * cloud_shadow.x * 0.5; 
+
+	// Dim sunlight by cloud shadow percentage
+	sunlight *= (1. - cloud_shadow.x);
+
+	// Haze color below cloud
+	vec4 additiveColorBelowCloud = (	  blue_horizon * blue_weight * (sunlight + tmpAmbient)
+				+ (haze_horizon.r * haze_weight) * (sunlight * temp2.x + tmpAmbient)
+			 );	
+
+	// CLOUDS
+
+	sunlight = sunlight_color;
+	temp2.y = max(0., lightnorm.y * 2.);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// Cloud color out
+	vary_CloudColorSun = (sunlight * temp2.x) * cloud_color;
+	vary_CloudColorAmbient = tmpAmbient * cloud_color;
+	
+	// Attenuate cloud color by atmosphere
+	temp1 = sqrt(temp1);	//less atmos opacity (more transparency) below clouds
+	vary_CloudColorSun *= temp1;
+	vary_CloudColorAmbient *= temp1;
+	vec4 oHazeColorBelowCloud = additiveColorBelowCloud * (1. - temp1);
+
+	// Make a nice cloud density based on the cloud_shadow value that was passed in.
+	vary_CloudDensity = 2. * (cloud_shadow.x - 0.25);
+
+
+	// Texture coords
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+	gl_TexCoord[0].xy -= 0.5;
+	gl_TexCoord[0].xy /= cloud_scale.x;
+	gl_TexCoord[0].xy += 0.5;
+
+	gl_TexCoord[1] = gl_TexCoord[0];
+	gl_TexCoord[1].x += lightnorm.x * 0.0125;
+	gl_TexCoord[1].y += lightnorm.z * 0.0125;
+
+	gl_TexCoord[2] = gl_TexCoord[0] * 16.;
+	gl_TexCoord[3] = gl_TexCoord[1] * 16.;
+
+	// Combine these to minimize register use
+	vary_CloudColorAmbient += oHazeColorBelowCloud;
+
+	// needs this to compile on mac
+	//vary_AtmosAttenuation = vec3(0.0,0.0,0.0);
+
+	// END CLOUDS
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
new file mode 100644
index 00000000000..5410889ed8b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
@@ -0,0 +1,24 @@
+/** 
+ * @file gammaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec4 gamma;
+
+vec3 getAtmosAttenuation();
+
+/// Soft clips the light with a gamma correction
+vec3 scaleSoftClip(vec3 light) {
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+vec3 fullbrightScaleSoftClip(vec3 light) {
+	return mix(scaleSoftClip(light.rgb), light.rgb, getAtmosAttenuation());
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
new file mode 100644
index 00000000000..bc6d6d33ff2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @file WLSkyF.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+/////////////////////////////////////////////////////////////////////////
+// The fragment shader for the sky
+/////////////////////////////////////////////////////////////////////////
+
+varying vec4 vary_HazeColor;
+
+uniform sampler2D cloud_noise_texture;
+uniform vec4 gamma;
+
+/// Soft clips the light with a gamma correction
+vec3 scaleSoftClip(vec3 light) {
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+void main()
+{
+	// Potential Fill-rate optimization.  Add cloud calculation 
+	// back in and output alpha of 0 (so that alpha culling kills 
+	// the fragment) if the sky wouldn't show up because the clouds 
+	// are fully opaque.
+
+	vec4 color;
+	color = vary_HazeColor;
+	color *= 2.;
+
+	/// Gamma correct for WL (soft clip effect).
+	gl_FragColor.rgb = scaleSoftClip(color.rgb);
+	gl_FragColor.a = 1.0;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
new file mode 100644
index 00000000000..e396aea6c94
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
@@ -0,0 +1,138 @@
+/** 
+ * @file WLSkyV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// SKY ////////////////////////////////////////////////////////////////////////
+// The vertex shader for creating the atmospheric sky
+///////////////////////////////////////////////////////////////////////////////
+
+// Output parameters
+varying vec4 vary_HazeColor;
+
+// Inputs
+uniform vec3 camPosLocal;
+
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 max_y;
+
+uniform vec4 glow;
+
+uniform vec4 cloud_color;
+
+uniform vec4 cloud_scale;
+
+void main()
+{
+
+	// World / view / projection
+	gl_Position = ftransform();
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+
+	// Get relative position
+	vec3 P = gl_Vertex.xyz - camPosLocal.xyz + vec3(0,50,0);
+	//vec3 P = gl_Vertex.xyz + vec3(0,50,0);
+
+	// Set altitude
+	if (P.y > 0.)
+	{
+		P *= (max_y.x / P.y);
+	}
+	else
+	{
+		P *= (-32000. / P.y);
+	}
+
+	// Can normalize then
+	vec3 Pn = normalize(P);
+	float  Plen = length(P);
+
+	// Initialize temp variables
+	vec4 temp1 = vec4(0.);
+	vec4 temp2 = vec4(0.);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+
+	// Sunlight attenuation effect (hue and brightness) due to atmosphere
+	// this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + haze_density.x * 0.25) * (density_multiplier.x * max_y.x);
+
+	// Calculate relative weights
+	temp1 = blue_density + haze_density.x;
+	blue_weight = blue_density / temp1;
+	haze_weight = haze_density.x / temp1;
+
+	// Compute sunlight from P & lightnorm (for long rays like sky)
+	temp2.y = max(0., max(0., Pn.y) * 1.0 + lightnorm.y );
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// Distance
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z);
+
+
+	// Compute haze glow
+	temp2.x = dot(Pn, lightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		// temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .001);	
+		// Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		// Higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		// glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	// Add "minimum anti-solar illumination"
+	temp2.x += .25;
+
+
+	// Haze color above cloud
+	vary_HazeColor = (	  blue_horizon * blue_weight * (sunlight + ambient)
+				+ (haze_horizon.r * haze_weight) * (sunlight * temp2.x + ambient)
+			 );	
+
+
+	// Increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient;
+	tmpAmbient += (1. - tmpAmbient) * cloud_shadow.x * 0.5; 
+
+	// Dim sunlight by cloud shadow percentage
+	sunlight *= (1. - cloud_shadow.x);
+
+	// Haze color below cloud
+	vec4 additiveColorBelowCloud = (	  blue_horizon * blue_weight * (sunlight + tmpAmbient)
+				+ (haze_horizon.r * haze_weight) * (sunlight * temp2.x + tmpAmbient)
+			 );	
+
+	// Final atmosphere additive
+	vary_HazeColor *= (1. - temp1);
+	
+	// Attenuate cloud color by atmosphere
+	temp1 = sqrt(temp1);	//less atmos opacity (more transparency) below clouds
+
+	// At horizon, blend high altitude sky color towards the darker color below the clouds
+	vary_HazeColor += (additiveColorBelowCloud - vary_HazeColor) * (1. - sqrt(temp1));
+	
+	// won't compile on mac without this being set
+	//vary_AtmosAttenuation = vec3(0.0,0.0,0.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
new file mode 100644
index 00000000000..b7678cac66a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
@@ -0,0 +1,35 @@
+/** 
+ * @file transportF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//////////////////////////////////////////////////////////
+// The fragment shader for the terrain atmospherics
+//////////////////////////////////////////////////////////
+
+vec3 getAdditiveColor();
+vec3 getAtmosAttenuation();
+
+uniform sampler2D cloudMap;
+uniform vec4 cloud_pos_density1;
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+
+vec3 fullbrightAtmosTransport(vec3 light) {
+	float brightness = dot(light.rgb, vec3(0.33333));
+
+	return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness);
+}
+
+vec3 fullbrightShinyAtmosTransport(vec3 light) {
+	float brightness = dot(light.rgb, vec3(0.33333));
+
+	return mix(atmosTransport(light.rgb), (light.rgb + getAdditiveColor().rgb) * (2.0 - brightness), brightness * brightness);
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
index 2505afea65c..04c10536e00 100644
--- a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
@@ -1,10 +1,14 @@
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec3 baseCol);
-mat4 getSkinnedTransform();
-void default_scatter(vec3 viewVec, vec3 lightDir);
+/** 
+ * @file avatarV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
 
-attribute vec4 materialColor; //2
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+mat4 getSkinnedTransform();
+void calcAtmospherics(vec3 inPositionEye);
 
-attribute vec4 binormal; //6
 attribute vec4 clothing; //4
 
 attribute vec4 gWindDir;		//7
@@ -27,102 +31,80 @@ void main()
 	norm.z = dot(trans[2].xyz, gl_Normal);
 	norm = normalize(norm);
 		
-	vec3 binorm;
-	binorm.x = dot(trans[0].xyz, binormal.xyz);
-	binorm.y = dot(trans[1].xyz, binormal.xyz);
-	binorm.z = dot(trans[2].xyz, binormal.xyz);
-	norm = normalize(norm);
-	
 	//wind
 	vec4 windEffect;
-	windEffect = vec4(dot(norm, gWindDir.xyz));				//	DP3 windEffect, blendNorm, gWindDir;
-	pos.x = dot(trans[2].xyz, gl_Vertex.xyz);				//	DP3 blendPos.x, blendMatZ, iPos;
+	windEffect = vec4(dot(norm, gWindDir.xyz));	
+	pos.x = dot(trans[2].xyz, gl_Vertex.xyz);
 	windEffect.xyz = pos.x * vec3(0.015, 0.015, 0.015)
-						+ windEffect.xyz;					//	MAD windEffect.xyz, blendPos.x, {0.015, 0.015, 0.015, 0}, windEffect;
-	windEffect.w = windEffect.w * 2.0 + 1.0;				//	MAD	windEffect.w, windEffect, {0, 0, 0, 2}, {0, 0, 0, 1};	# move wind offset value to [-1, 3]
-	windEffect.w = windEffect.w*gWindDir.w;					//	MUL windEffect.w, windEffect, gWindDir;								# modulate wind strength 
+						+ windEffect.xyz;
+	windEffect.w = windEffect.w * 2.0 + 1.0;				// move wind offset value to [-1, 3]
+	windEffect.w = windEffect.w*gWindDir.w;					// modulate wind strength 
 	
 	windEffect.xyz = windEffect.xyz*gSinWaveParams.xyz
-						+vec3(gSinWaveParams.w);			//	MAD windEffect.xyz, windEffect, gSinWaveParams, gSinWaveParams.w;		# use sin wave params to scale and offset input
+						+vec3(gSinWaveParams.w);			// use sin wave params to scale and offset input
 
 		
 	//reduce to period of 2 PI
 	vec4 temp1, temp0, temp2, offsetPos;
-	temp1.xyz = windEffect.xyz * gPiConstants.x;			//	MUL    temp1.xyz, windEffect, gPiConstants.x;						# change input as multiple of [0-2PI] to [0-1]
-	temp0.y = mod(temp1.x,1.0);								//	EXP    temp0, temp1.x;												# find mod(x, 1)
-	windEffect.x = temp0.y * gPiConstants.y;				//	MUL    windEffect.x, temp0.y, gPiConstants.y;						# scale from [0,1] to [0, 2PI]
-	temp1.z = temp1.z - gPiConstants.w;						//	ADD    temp1.z, temp1.z, -gPiConstants.w;							# shift normal oscillation by PI/2
-	temp0.y = mod(temp1.z,1.0);								//	EXP    temp0, temp1.z;												# find mod(x, 1)
+	temp1.xyz = windEffect.xyz * gPiConstants.x;			// change input as multiple of [0-2PI] to [0-1]
+	temp0.y = mod(temp1.x,1.0);	
+	windEffect.x = temp0.y * gPiConstants.y;				// scale from [0,1] to [0, 2PI]
+	temp1.z = temp1.z - gPiConstants.w;						// shift normal oscillation by PI/2
+	temp0.y = mod(temp1.z,1.0);
 	
-	windEffect.z = temp0.y * gPiConstants.y;				//	MUL    windEffect.z, temp0.y, gPiConstants.y;						# scale from [0,1] to [0, 2PI]
-	windEffect.xyz = windEffect.xyz + vec3(-3.141592);		//	# offset to [-PI, PI]
-															//	ADD    windEffect.xyz, windEffect, {-3.141592, -3.141592, -3.141592, -3.141592};
+	windEffect.z = temp0.y * gPiConstants.y;				// scale from [0,1] to [0, 2PI]
+	windEffect.xyz = windEffect.xyz + vec3(-3.141592);		// offset to [-PI, PI]
+															
 
 	//calculate sinusoid
 	vec4 sinWave;
-	temp1 = windEffect*windEffect;							//	MUL    temp1,    windEffect, windEffect;							# x^2
+	temp1 = windEffect*windEffect;
 	sinWave = -temp1 * gMinMaxConstants.w 
-				+ vec4(gMinMaxConstants.z);					//	MAD    sinWave, -temp1, gMinMaxConstants.w, gMinMaxConstants.z;		# y = -(x^2)/7! + 1/5!
-	sinWave = sinWave * -temp1 + vec4(gMinMaxConstants.y);	//	MAD    sinWave, sinWave, -temp1, gMinMaxConstants.y;				# y = -(x^2) * (-(x^2)/7! + 1/5!) + 1/3!
-	sinWave = sinWave * -temp1 + vec4(gMinMaxConstants.x);	//	MAD    sinWave, sinWave, -temp1, gMinMaxConstants.x;				# y = -(x^2) * (-(x^2) * (-(x^2)/7! + 1/5!) + 1/3!) + 1
-	sinWave = sinWave * windEffect;							//	MUL    sinWave, sinWave, windEffect;								# y = x * (-(x^2) * (-(x^2) * (-(x^2)/7! + 1/5!) + 1/3!) + 1)
+				+ vec4(gMinMaxConstants.z);					// y = -(x^2)/7! + 1/5!
+	sinWave = sinWave * -temp1 + vec4(gMinMaxConstants.y);	// y = -(x^2) * (-(x^2)/7! + 1/5!) + 1/3!
+	sinWave = sinWave * -temp1 + vec4(gMinMaxConstants.x);	// y = -(x^2) * (-(x^2) * (-(x^2)/7! + 1/5!) + 1/3!) + 1
+	sinWave = sinWave * windEffect;							// y = x * (-(x^2) * (-(x^2) * (-(x^2)/7! + 1/5!) + 1/3!) + 1)
 	
 	// sinWave.x holds sin(norm . wind_direction) with primary frequency
 	// sinWave.y holds sin(norm . wind_direction) with secondary frequency
 	// sinWave.z hold cos(norm . wind_direction) with primary frequency
 	sinWave.xyz = sinWave.xyz * gWindDir.w 
-				+ vec3(windEffect.w);						//	MAD sinWave.xyz, sinWave, gWindDir.w, windEffect.w;					# multiply by wind strength in gWindDir.w [-wind, wind]
+				+ vec3(windEffect.w);						// multiply by wind strength in gWindDir.w [-wind, wind]
 
 	// add normal facing bias offset [-wind,wind] -> [-wind - .25, wind + 1]
-	temp1 = vec4(dot(norm, gGravity.xyz));					//	DP3 temp1, blendNorm, gGravity;										# how much is this normal facing in direction of gGravity?
-	temp1 = min(temp1, vec4(0.2,0.0,0.0,0.0));				//	MIN temp1, temp1, {0.2, 0, 0, 0};									# clamp [-1, 1] to [-1, 0.2]
-	temp1 = temp1*vec4(1.5,0.0,0.0,0.0);					//	MUL temp1, temp1, {1.5, 0, 0, 0};									# scale from [-1,0.2] to [-1.5, 0.3]
-	sinWave.x = sinWave.x + temp1.x;						//	ADD sinWave.x, sinWave, temp1;										# add gGravity effect to sinwave (only primary frequency)
-	sinWave.xyz = sinWave.xyz * clothing.w;					//	MUL sinWave.xyz, sinWave, iClothing.w;								# modulate by clothing coverage
+	temp1 = vec4(dot(norm, gGravity.xyz));					// how much is this normal facing in direction of gGravity?
+	temp1 = min(temp1, vec4(0.2,0.0,0.0,0.0));				// clamp [-1, 1] to [-1, 0.2]
+	temp1 = temp1*vec4(1.5,0.0,0.0,0.0);					// scale from [-1,0.2] to [-1.5, 0.3]
+	sinWave.x = sinWave.x + temp1.x;						// add gGravity effect to sinwave (only primary frequency)
+	sinWave.xyz = sinWave.xyz * clothing.w;					// modulate by clothing coverage
 	
-	sinWave.xyz = max(sinWave.xyz, vec3(-1.0, -1.0, -1.0));	//	MAX sinWave.xyz, sinWave, {-1, -1, -1, -1};							# clamp to underlying body shape
-	offsetPos = clothing * sinWave.x;						//	MUL offsetPos, iClothing, sinWave.x;								# multiply wind effect times clothing displacement
-	temp2 = gWindDir*sinWave.z + vec4(norm,0);				//	MAD temp2, gWindDir, sinWave.z, blendNorm;							# calculate normal offset due to wind oscillation
-	offsetPos = vec4(1.0,1.0,1.0,0.0)*offsetPos+gl_Vertex;	//	MAD offsetPos, {1.0, 1.0, 1.0, 0.0}, offsetPos, iPos;				# add to offset vertex position, and zero out effect from w
-	norm += temp2.xyz*2.0;									//	MAD blendNorm, temp2, {2, 2, 2, 2}, blendNorm;						# add sin wave effect on normals (exaggerated)
+	sinWave.xyz = max(sinWave.xyz, vec3(-1.0, -1.0, -1.0));	// clamp to underlying body shape
+	offsetPos = clothing * sinWave.x;						// multiply wind effect times clothing displacement
+	temp2 = gWindDir*sinWave.z + vec4(norm,0);				// calculate normal offset due to wind oscillation
+	offsetPos = vec4(1.0,1.0,1.0,0.0)*offsetPos+gl_Vertex;	// add to offset vertex position, and zero out effect from w
+	norm += temp2.xyz*2.0;									// add sin wave effect on normals (exaggerated)
 	
 	//add "backlighting" effect
 	float colorAcc;
-	colorAcc = 1.0 - clothing.w;							//	SUB colorAcc, {1, 1, 1, 1}, iClothing;
-	norm.z -= colorAcc * 0.2;								//	MAD blendNorm, colorAcc.w, {0, 0, -0.2, 0}, blendNorm;
+	colorAcc = 1.0 - clothing.w;
+	norm.z -= colorAcc * 0.2;
 	
 	//renormalize normal (again)
-	norm = normalize(norm);									//	DP3 divisor.w, blendNorm, blendNorm;
-															// RSQ divisor.xyz, divisor.w;
-															// MUL blendNorm.xyz, blendNorm, divisor;
-
-	//project binormal to normal plane to ensure orthogonality
-	temp2 = vec4(dot(norm, binorm));						//	DP3 temp2, blendNorm, blendBinorm;
-	binorm = binorm - temp2.xyz;							//	SUB blendBinorm, blendBinorm, temp2;
-
-	//renormalize binormal
-	binorm = normalize(binorm);								//	DP3 divisor.w, blendBinorm, blendBinorm;
-															//	RSQ divisor.xyz, divisor.w;
-															//	MUL blendBinorm.xyz, blendBinorm, divisor;
+	norm = normalize(norm);
 
 	pos.x = dot(trans[0], offsetPos);
 	pos.y = dot(trans[1], offsetPos);
 	pos.z = dot(trans[2], offsetPos);
 	pos.w = 1.0;
+
+	calcAtmospherics(pos.xyz);
 	
-	vec4 color = calcLighting(pos.xyz, norm, materialColor, gl_Color.rgb);			
+	vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.0));			
 	gl_FrontColor = color; 
 					
 	gl_Position = gl_ProjectionMatrix * pos;
 	
-	vec3 N = norm;
-	vec3 B = binorm;
-	vec3 T = cross(N,B);
 	
-	//gl_TexCoord[1].xy = gl_MultiTexCoord0.xy + 1.0/512.0 * vec2(dot(T,gl_LightSource[0].position.xyz),
-	//												dot(B,gl_LightSource[0].position.xyz));
-
 	gl_TexCoord[2] = vec4(pos.xyz, 1.0);
-	default_scatter(pos.xyz, gl_LightSource[0].position.xyz);
-										 
-}
\ No newline at end of file
+
+}
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
new file mode 100644
index 00000000000..bf5c78f3ea3
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
@@ -0,0 +1,44 @@
+/**
+ * @file sumLightsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
+vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 atmosGetDiffuseSunlightColor();
+vec3 scaleDownLight(vec3 light);
+
+vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol)
+{
+	vec4 col = vec4(0.0, 0.0, 0.0, color.a);
+	
+	vec3 view = normalize(pos);
+	
+	/// collect all the specular values from each calcXXXLightSpecular() function
+	vec4 specularSum = vec4(0.0);
+	
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[1].diffuse.rgb * calcDirectionalLightSpecular(specularColor, view, norm, gl_LightSource[1].position.xyz,gl_LightSource[1].diffuse.rgb, 1.0);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[2].position.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation,gl_LightSource[2].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[3].position.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation,gl_LightSource[3].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[4].position.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation,gl_LightSource[4].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[5].position.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation,gl_LightSource[5].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[6].position.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation,gl_LightSource[6].diffuse.rgb);
+	col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, gl_LightSource[7].position.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation,gl_LightSource[7].diffuse.rgb);
+	col.rgb = scaleDownLight(col.rgb);
+						
+	// Add windlight lights
+	col.rgb += atmosAmbient(baseCol.rgb);
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, gl_LightSource[0].position.xyz,atmosGetDiffuseSunlightColor()*baseCol.a, 1.0));
+
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+	specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0);
+
+	col.rgb += specularColor.rgb;
+	return col;	
+}
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
new file mode 100644
index 00000000000..1c5234c4502
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
@@ -0,0 +1,41 @@
+/**
+ * @file sumLightsV.glsl
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
+{
+	vec4 col;
+	col.a = color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz));
+	col.rgb += atmosAmbient(baseLight.rgb);
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+				
+
+	col.rgb = min(col.rgb*color.rgb, 1.0);
+	
+	return col;	
+}
+
diff --git a/indra/newview/app_settings/shaders/shader_heirarchy.txt b/indra/newview/app_settings/shaders/shader_heirarchy.txt
new file mode 100644
index 00000000000..d8bbf69b389
--- /dev/null
+++ b/indra/newview/app_settings/shaders/shader_heirarchy.txt
@@ -0,0 +1,176 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/avatarV.glsl - gAvatarProgram, gAvatarWaterProgram
+	main() - avatar/avatarV.glsl
+		getSkinnedTransform() - avatarSkinV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+		calcLighting() - lighting/lightV.glsl
+			sumLights() - lighting/sumLightsV.glsl
+				calcDirectionalLight() - lighting/lightFuncV.glsl
+				calcPointLight() - lighting/lightFuncV.glsl
+				scaleDownLight() - windlight/atmosphericsHelpersV.glsl
+				atmosAmbient() - windlight/atmosphericsHelpersV.glsl
+				atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/avatarF.glsl - gAvatarProgram
+	main() - avatar/avatarF.glsl
+		default_lighting() - lighting/lightF.glsl
+			calc_default_lighting() - lighting/lightF.glsl
+				atmosLighting() - windlight/atmosphericsF.glsl
+				scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/eyeballV.glsl - gAvatarEyeballProgram
+	main() - avatar/eyeballV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+		calcLightingSpecular() - lighting/lightSpecularV.glsl
+			sumLightsSpecular() - lighting/sumLightsSpecularV.glsl
+				calcDirectionalLightSpecular() - lighting/lightFuncSpecularV.glsl
+				calcPointLightSpecular() - lighting/lightFuncSpecularV.glsl
+				atmosAmbient() - windlight/atmosphericsHelpersV.glsl
+				atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl
+				atmosGetDiffuseSunlightColor() - windlight/atmosphericsHelpersV.glsl
+				scaleDownLight() - windlight/atmosphericsHelpersV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/eyeballF.glsl - gAvatarEyeballProgram
+	main() - avatar/eyeballF.glsl
+		default_lighting() - lighting/lightF.glsl
+			calc_default_lighting() - lighting/lightF.glsl
+				atmosLighting() - windlight/atmosphericsF.glsl
+				scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/pickAvatarV.glsl - gAvatarPickProgram
+	main() - avatar/pickAvatarV.glsl
+		getSkinnedTransform() - avatarSkinV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+avatar/pickAvatarF.glsl - gAvatarPickProgram
+	main() - avatar/pickAvatarF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/terrainV.glsl - gTerrainProgram, gTerrainWaterProgram
+	texgen_object() - environment/terrainV.glsl
+	main() - environment/terrainV.glsl
+		texgen_object() - environment/terrainV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+		calcLighting() - lighting/lightV.glsl
+			sumLights() - lighting/sumLightsV.glsl
+				calcDirectionalLight() - lighting/lightFuncV.glsl
+				calcPointLight() - lighting/lightFuncV.glsl
+				scaleDownLight() - windlight/atmosphericsHelpersV.glsl
+				atmosAmbient() - windlight/atmosphericsHelpersV.glsl
+				atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/terrainF.glsl - gTerrainProgram
+	main() - environment/terrainF.glsl
+		atmosLighting() - windlight/atmosphericsF.glsl
+		scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/terrainWaterF.glsl - gTerrainWaterProgram
+	main() - environment/terrainWaterF.glsl
+		atmosLighting() - windlight/atmosphericsF.glsl
+		applyWaterFog() - environment/waterFogF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/underWaterF.glsl - gUnderWaterProgram
+	applyWaterFog() - environment/underWaterF.glsl (NOTE: different than one in waterFogF.glsl)
+	main() - environment/underWaterF.glsl
+		applyWaterFog() - environment/underWaterF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/waterV.glsl - gWaterProgram, gUnderWaterProgram
+	main() - environment/waterV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+environment/waterF.glsl - gWaterProgram
+	main() - environment/waterF.glsl
+		atmosTransport() - windlight/transportF.glsl
+		scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/fullbrightV.glsl - gObjectFullbrightProgram, gObjectFullbrightWaterProgram
+	main() - objects/fullbrightV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/fullbrightF.glsl - gObjectFullbrightProgram
+	main() - objects/fullbrightF.glsl
+		fullbright_lighting() - lighting/lightFullbrightF.glsl
+			fullbrightAtmosTransport() - windlight/transportF.glsl
+				atmosTransport() - windlight/transportF.glsl
+			fullbrightScaleSoftClip() - windlight/gammaF.glsl
+				scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/fullbrightShinyV.glsl - gObjectFullbrightShinyProgram
+	main() - objects/fullbrightShinyV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/fullbrightShinyF.glsl - gObjectFullbrightShinyProgram
+	main() - objects/fullbrightShinyF.glsl
+		fullbright_shiny_lighting() - lighting/lightFullbrightShinyF.glsl
+			fullbrightShinyAtmosTransport() - windlight/transportF.glsl
+				atmosTransport() - windlight/transportF.glsl
+			fullbrightScaleSoftClip() - windlight/gammaF.glsl
+				scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/fullbrightWaterF.glsl - gObjectFullbrightWaterProgram
+	main() - objects/fullbrightWaterF.glsl
+		fullbright_lighting_water() - lighting/lightFullbrightWaterF.glsl
+			fullbrightAtmosTransport() - windlight/transportF.glsl
+				atmosTransport() - windlight/transportF.glsl
+			applyWaterFog() - environment/waterFogF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/shinyV.glsl - gObjectShinyProgram, gObjectShinyWaterProgram
+	main() - objects/shinyV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+		calcLighting() - lighting/lightV.glsl
+			calcLighting(vec4) - lighting/lightV.glsl
+				sumLights() - lighting/sumLightsV.glsl
+					calcDirectionalLight() - lighting/lightFuncV.glsl
+					calcPointLight() - lighting/lightFuncV.glsl
+					scaleDownLight() - windlight/atmosphericsHelpersV.glsl
+					atmosAmbient() - windlight/atmosphericsHelpersV.glsl
+					atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/shinyF.glsl - gObjectShinyProgram
+	main() - objects/shinyF.glsl
+		shiny_lighting() - lighting/lightShinyF.glsl
+			atmosLighting() - windlight/atmosphericsF.glsl
+			scaleSoftClip() - windlight/gammaF.glsl	
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/shinyWaterF.glsl - gObjectShinyWaterProgram
+	main() - objects/shinyWaterF.glsl
+		shiny_lighting_water() - lighting/lightShinyWaterF.glsl
+			atmosLighting() - windlight/atmosphericsF.glsl
+			applyWaterFog() - environment/waterFogF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/simpleV.glsl - gObjectSimpleProgram, gObjectSimpleWaterProgram
+	main() - objects/simpleV.glsl
+		calcAtmospherics() - windlight/atmosphericsV.glsl
+		calcLighting() - lighting/lightV.glsl
+			sumLights() - lighting/sumLightsV.glsl
+				calcDirectionalLight() - lighting/lightFuncV.glsl
+				calcPointLight() - lighting/lightFuncV.glsl
+				scaleDownLight() - windlight/atmosphericsHelpersV.glsl
+				atmosAmbient() - windlight/atmosphericsHelpersV.glsl
+				atmosAffectDirectionalLight() - windlight/atmosphericsHelpersV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/simpleF.glsl - gObjectSimpleProgram
+	main() - objects/simpleF.glsl
+		default_lighting() - lighting/lightF.glsl
+			atmosLighting() - windlight/atmosphericsF.glsl
+			scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+objects/simpleWaterF.glsl - gObjectSimpleWaterProgram, gAvatarWaterProgram
+	main() - objects/simpleWaterF.glsl
+		default_lighting_water() - lighting/lightWaterF.glsl
+			atmosLighting() - windlight/atmosphericsF.glsl
+			applyWaterFog() - environment/waterFogF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+windlight/skyV.glsl - gWLSkyProgram
+	main() - windlight/skyV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+windlight/skyF.glsl - gWLSkyProgram
+	main() - windlight/skyF.glsl
+		scaleSoftClip() - windlight/gammaF.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+windlight/cloudsV.glsl - gWLCloudProgram
+	main() - windlight/cloudsV.glsl
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+windlight/cloudsF.glsl - gWLCloudProgram
+	main() - windlight/cloudsF.glsl
+		scaleSoftClip() - windlight/gammaF.glsl
+
+
diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml
new file mode 100644
index 00000000000..f16ec6c30f2
--- /dev/null
+++ b/indra/newview/app_settings/ultra_graphics.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<settings version = "101">
+	<!--NO SHADERS-->
+	<RenderAvatarCloth value="TRUE"/>
+	<!--Default for now-->
+	<RenderAvatarLODFactor value="1.0"/>
+	<!--NO SHADERS-->
+	<RenderAvatarVP value="TRUE"/>
+	<!--Short Range-->
+	<RenderFarClip value="256"/>
+	<!--Default for now-->
+	<RenderFlexTimeFactor value="1"/>
+	<!--256... but they don't use this-->
+	<RenderGlowResolutionPow value="9"/>
+	<!--Sun/Moon only-->
+	<RenderLightingDetail value="1"/>
+	<!--Low number-->
+	<RenderMaxPartCount value="4096"/>
+	<!--bump okay-->
+	<RenderObjectBump value="TRUE"/>
+	<!--NO SHADERS-->
+	<RenderReflectionDetail value="3"/>
+	<!--Simple-->
+	<RenderTerrainDetail value="1"/>
+	<!--Default for now-->
+	<RenderTerrainLODFactor value="2.0"/>
+	<!--Default for now-->
+	<RenderTreeLODFactor value="1.0"/>
+	<!--Try Impostors-->
+	<RenderUseImpostors value="TRUE"/>
+	<!--Default for now-->
+	<RenderVolumeLODFactor value="2.0"/>
+	<!--NO SHADERS-->
+	<RenderWaterReflections value="TRUE"/>
+	<!--NO SHADERS-->
+	<VertexShaderEnable value="TRUE"/>
+	<!--NO SHADERS-->
+	<WindLightUseAtmosShaders value="TRUE"/>
+</settings>
diff --git a/indra/newview/app_settings/windlight/clouds2.tga b/indra/newview/app_settings/windlight/clouds2.tga
new file mode 100644
index 0000000000000000000000000000000000000000..c95ce7fec41e8c61100672f70d1dfb65afcccee9
GIT binary patch
literal 262935
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%0Aw5wUUO
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
z%0D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
EAE{4^=Kufz

literal 0
HcmV?d00001

diff --git a/indra/newview/app_settings/windlight/days/Default.xml b/indra/newview/app_settings/windlight/days/Default.xml
new file mode 100644
index 00000000000..3d3afd50750
--- /dev/null
+++ b/indra/newview/app_settings/windlight/days/Default.xml
@@ -0,0 +1,36 @@
+<llsd>
+    <array>
+        <array>
+            <real>0</real>
+            <string>A-12AM</string>
+        </array>
+        <array>
+            <real>0.125</real>
+            <string>A-3AM</string>
+        </array>
+        <array>
+            <real>0.25</real>
+            <string>A-6AM</string>
+        </array>
+        <array>
+            <real>0.375</real>
+            <string>A-9AM</string>
+        </array>
+        <array>
+            <real>0.5</real>
+            <string>A-12PM</string>
+        </array>
+        <array>
+            <real>0.625</real>
+            <string>A-3PM</string>
+        </array>
+        <array>
+            <real>0.75</real>
+            <string>A-6PM</string>
+        </array>
+        <array>
+            <real>0.875</real>
+            <string>A-9PM</string>
+        </array>
+    </array>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/postprocesseffects.xml b/indra/newview/app_settings/windlight/postprocesseffects.xml
new file mode 100644
index 00000000000..4645215a471
--- /dev/null
+++ b/indra/newview/app_settings/windlight/postprocesseffects.xml
@@ -0,0 +1,2 @@
+<llsd><map><key>Asi Weird</key><map><key>bloom_strength</key><real>4.5799999237060547</real><key>bloom_width</key><real>12.539999961853027</real><key>brightness</key><real>0.89999997615814209</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>0.22999998927116394</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><integer>1</integer><key>enable_color_filter</key><integer>1</integer><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.47999998927116394</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>-1</real></map><key>NegativeSaturation</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><integer>1</integer><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>-1</real></map><key>NightVision</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><integer>1</integer><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map><key>WGhost</key><map><key>bloom_strength</key><real>2.0399999618530273</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><integer>1</integer><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.22999998927116394</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map><key>default</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map></map></llsd>
+><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map></map></llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D12AM.xml b/indra/newview/app_settings/windlight/skies/A%2D12AM.xml
new file mode 100644
index 00000000000..0aba31214a4
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D12AM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.20405027270317078</real>
+            <real>0.24246673285961151</real>
+            <real>0.32999998331069946</real>
+            <real>0.10999999940395355</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.44999998807907104</real>
+            <real>0.44999998807907104</real>
+            <real>0.44999998807907104</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.23999999463558197</real>
+            <real>0.23999999463558197</real>
+            <real>0.23999999463558197</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.87999999523162842</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00030000001424923539</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>4</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.8876205482883961e-007</real>
+            <real>1</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>906.20001220703125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>2</real>
+    <key>sun_angle</key>
+        <real>4.7123894691467285</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.34876692295074463</real>
+            <real>0.35574248433113098</real>
+            <real>0.65999996662139893</real>
+            <real>0.2199999988079071</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D12PM.xml b/indra/newview/app_settings/windlight/skies/A%2D12PM.xml
new file mode 100644
index 00000000000..119b3e1418c
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D12PM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>0.34999999403953552</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.24475815892219543</real>
+            <real>0.44872328639030457</real>
+            <real>0.75999999046325684</real>
+            <real>0.37999999523162842</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.49548381567001343</real>
+            <real>0.49548381567001343</real>
+            <real>0.63999998569488525</real>
+            <real>0.31999999284744263</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00017999998817685992</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.80000001192092896</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18999999761581421</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.3711388286737929e-008</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1605</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.5707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.7342105507850647</real>
+            <real>0.78157895803451538</real>
+            <real>0.89999997615814209</real>
+            <real>0.29999998211860657</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D3AM.xml b/indra/newview/app_settings/windlight/skies/A%2D3AM.xml
new file mode 100644
index 00000000000..f790d3d9612
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D3AM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.22259476780891418</real>
+            <real>0.26450252532958984</real>
+            <real>0.35999998450279236</real>
+            <real>0.11999999731779099</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.44999116536295314</real>
+            <real>0.44999854555993368</real>
+            <real>0.45001013284446073</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.23999616268583132</real>
+            <real>0.239999227803052</real>
+            <real>0.24000028550619668</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615400241566114</real>
+            <real>0.22615400241566114</real>
+            <real>0.22615400241566114</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.88000000953681223</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.499400354105791</real>
+            <real>10.011000104419489</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003000046529240592</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>7.8213197608078763e-005</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5.0000000000023022</real>
+            <real>0.0010000000214220922</real>
+            <real>-0.47999999165507345</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>3.9999044060931555</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>4.6348559691012062e-006</real>
+            <real>0.19915600437461423</real>
+            <real>0.19915600437461423</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.70710653066635132</real>
+            <real>-0.70710700750350952</real>
+            <real>1</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>906.19008370909478</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>1.9999420642852783</real>
+    <key>sun_angle</key>
+        <real>5.4977874755859375</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.60242295265197754</real>
+            <real>0.61447036266326904</real>
+            <real>1.1399999856948853</real>
+            <real>0.37999999523162842</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D3PM.xml b/indra/newview/app_settings/windlight/skies/A%2D3PM.xml
new file mode 100644
index 00000000000..ec9706773e6
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D3PM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>0.34999999403953552</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.2447581488182351</real>
+            <real>0.44872328639030457</real>
+            <real>0.75999999046325684</real>
+            <real>0.38000004053115788</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.49548382097675159</real>
+            <real>0.49548381382419748</real>
+            <real>0.63999999284744291</real>
+            <real>0.31999999642372146</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.40999999165535073</real>
+            <real>0.40999999165535073</real>
+            <real>0.40999999165535073</real>
+            <real>0.40999999165535073</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.99999999999999289</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.4199999868869746</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00017999998817685818</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.80000001192093606</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18999999761581243</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.70710659027099609</real>
+            <real>-0.70710694789886475</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1605</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>2.3561947345733643</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.73421055078505759</real>
+            <real>0.78157895803450828</real>
+            <real>0.89999997615813498</real>
+            <real>0.29999998211860301</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D6AM.xml b/indra/newview/app_settings/windlight/skies/A%2D6AM.xml
new file mode 100644
index 00000000000..bbc7aeec597
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D6AM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.80999994277954102</real>
+            <real>0.46289783716201782</real>
+            <real>0.62999993562698364</real>
+            <real>0.26999998092651367</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.15793180465698242</real>
+            <real>0.43499568104743958</real>
+            <real>0.87000000476837158</real>
+            <real>0.87000000476837158</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.20673196017742157</real>
+            <real>0.40988314151763916</real>
+            <real>0.47999998927116394</real>
+            <real>0.47999998927116394</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22616604226328718</real>
+            <real>0.22616604226328718</real>
+            <real>0.22616604226328718</real>
+            <real>0.99997219085526012</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.88000025272481253</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013883861</real>
+            <real>10.010999679576344</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00062000000616535544</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>2.6999279499073054</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5.0009990693069994</real>
+            <real>0.0010000000474963411</real>
+            <real>-0.48000101923815919</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.53999996185302734</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.15999999642372131</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.094108223915100098</real>
+            <real>0.99556195735931396</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>563</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>0.094247691333293915</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.369999885559082</real>
+            <real>2.369999885559082</real>
+            <real>2.369999885559082</real>
+            <real>0.78999996185302734</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D6PM.xml b/indra/newview/app_settings/windlight/skies/A%2D6PM.xml
new file mode 100644
index 00000000000..6e82f2eb218
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D6PM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.14840038120746613</real>
+            <real>0.17633917927742004</real>
+            <real>0.23999999463558197</real>
+            <real>0.079999998211860657</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.10767599940299988</real>
+            <real>0.21348699927330017</real>
+            <real>0.25</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.87999999523162842</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00046000001020729542</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>2.7000000476837158</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.15999999642372131</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.07532646507024765</real>
+            <real>-0.99715894460678101</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>562.5</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0661947727203369</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D9AM.xml b/indra/newview/app_settings/windlight/skies/A%2D9AM.xml
new file mode 100644
index 00000000000..413e3a27d9a
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D9AM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>1.0499999949065426</real>
+            <real>1.0499999988079054</real>
+            <real>1.0499999988079054</real>
+            <real>0.3500000095367426</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.15999999642372131</real>
+            <real>0.44872328639030457</real>
+            <real>0.75999999046325684</real>
+            <real>0.75999999046325684</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.53999996185302734</real>
+            <real>0.47999998927116394</real>
+            <real>0.69999998807907104</real>
+            <real>0.34999999403953552</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.37000000476837158</real>
+            <real>0.37000000476837158</real>
+            <real>0.37000000476837158</real>
+            <real>0.37000000476837158</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.99999998569455784</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999997615814166</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999844956437</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.27333331108093262</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00017999998102430359</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.80000008344649842</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>4.9999999284740397</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999999046327346</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.70000003576435432</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18999999284767277</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.70710676908493042</real>
+            <real>0.70710676908493042</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1605</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>0.78539818525314331</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.73421054104441197</real>
+            <real>0.7815789463510896</real>
+            <real>0.89999995470046912</real>
+            <real>0.29999997496605069</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/A%2D9PM.xml b/indra/newview/app_settings/windlight/skies/A%2D9PM.xml
new file mode 100644
index 00000000000..292f6713b70
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/A%2D9PM.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.20404692765200849</real>
+            <real>0.24246276689169122</real>
+            <real>0.33000383615406292</real>
+            <real>0.1100123608103587</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.44999116536295314</real>
+            <real>0.44999854555993368</real>
+            <real>0.45001013284446073</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.23999616268583132</real>
+            <real>0.239999227803052</real>
+            <real>0.24000028550619668</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615400241566114</real>
+            <real>0.22615400241566114</real>
+            <real>0.22615400241566114</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.88000000953681223</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.499400354105791</real>
+            <real>10.011000104419489</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003000046529240592</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>7.8213197608078763e-005</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5.0000000000023022</real>
+            <real>0.0010000000214220922</real>
+            <real>-0.47999999165507345</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>3.9999044060931555</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>4.6348559691012062e-006</real>
+            <real>0.19915600437461423</real>
+            <real>0.19915600437461423</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.70710688829421997</real>
+            <real>0.70710664987564087</real>
+            <real>1</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>906.19008370909478</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>1.9999420642852783</real>
+    <key>sun_angle</key>
+        <real>3.9269909858703613</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.34878980098432066</real>
+            <real>0.35576509414380553</real>
+            <real>0.66003586768772493</real>
+            <real>0.22001197576412324</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Barcelona.xml b/indra/newview/app_settings/windlight/skies/Barcelona.xml
new file mode 100644
index 00000000000..ea9cab8fbb6
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Barcelona.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.22260047495365143</real>
+            <real>0.26450866460800171</real>
+            <real>0.35999998450279236</real>
+            <real>0.11999999731779099</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15130999684333801</real>
+            <real>0.30000001192092896</real>
+            <real>0.35131001472473145</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.50999999046325684</real>
+            <real>0.50999999046325684</real>
+            <real>0.50999999046325684</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.30000001192092896</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>6</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.062790460884571075</real>
+            <real>-0.99802672863006592</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>21</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0787608623504639</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.1699999570846558</real>
+            <real>1.1699999570846558</real>
+            <real>1.1699999570846558</real>
+            <real>0.38999998569488525</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Blizzard.xml b/indra/newview/app_settings/windlight/skies/Blizzard.xml
new file mode 100644
index 00000000000..d17d2790a83
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Blizzard.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.4823022186756134</real>
+            <real>0.57310229539871216</real>
+            <real>0.77999997138977051</real>
+            <real>0.25999999046325684</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15130999684333801</real>
+            <real>0.30000001192092896</real>
+            <real>0.35131001472473145</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.12862999737262726</real>
+            <real>0.12862999737262726</real>
+            <real>0.12862999737262726</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.88419097661972046</real>
+            <real>0.53047597408294678</real>
+            <real>0.4270470142364502</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.38419300317764282</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10</real>
+            <real>10</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.61711597442626953</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0001250890054507181</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>11.40000057220459</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>6.4079799652099609</real>
+            <real>0.0012815999798476696</real>
+            <real>-0.42292699217796326</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>4</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.21744099259376526</real>
+            <real>0.21744099259376526</real>
+            <real>0.21744099259376526</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.15643447637557983</real>
+            <real>0.98768836259841919</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>4000</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>2</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>0.15707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>3</real>
+            <real>3</real>
+            <real>3</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Blue%20Midday.xml b/indra/newview/app_settings/windlight/skies/Blue%20Midday.xml
new file mode 100644
index 00000000000..570f059961c
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Blue%20Midday.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.14999999105930328</real>
+            <real>0.14999999105930328</real>
+            <real>0.14999999105930328</real>
+            <real>0.049999997019767761</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.18153078854084015</real>
+            <real>0.49999505281448364</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.43070217967033386</real>
+            <real>0.85394656658172607</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.53962135314941406</real>
+            <real>0.53962135314941406</real>
+            <real>0.53962135314941406</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.69569224119186401</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.10999999195337296</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.3765256404876709</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>2.9846153259277344</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>4.2061538696289062</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.44246155023574829</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>2.8830769062042236</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.49740666151046753</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.86074197292327881</real>
+            <real>-0.50904154777526855</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>10</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>2.1048672199249268</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.88526362180709839</real>
+            <real>1.2300000190734863</real>
+            <real>1.2300000190734863</real>
+            <real>0.40999999642372131</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Coastal%20Afternoon.xml b/indra/newview/app_settings/windlight/skies/Coastal%20Afternoon.xml
new file mode 100644
index 00000000000..4925b29eea8
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Coastal%20Afternoon.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.89040267467498779</real>
+            <real>1.0580335855484009</real>
+            <real>1.4399999380111694</real>
+            <real>0.47999998927116394</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15130999684333801</real>
+            <real>0.30000001192092896</real>
+            <real>0.35131001472473145</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.21396400034427643</real>
+            <real>0.21396400034427643</real>
+            <real>0.21396400034427643</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.16495099663734436</real>
+            <real>0.09771379828453064</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.079754598438739777</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.644780158996582</real>
+            <real>10.423800468444824</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.30061298608779907</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00015800200344529003</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.13210900127887726</real>
+            <real>0.13210900127887726</real>
+            <real>0.13210900127887726</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.031410444527864456</real>
+            <real>-0.99950659275054932</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>3</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.1101770401000977</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>3</real>
+            <real>3</real>
+            <real>3</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Coastal%20Sunset.xml b/indra/newview/app_settings/windlight/skies/Coastal%20Sunset.xml
new file mode 100644
index 00000000000..f4736cf4c69
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Coastal%20Sunset.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.31535112857818604</real>
+            <real>0.37471914291381836</real>
+            <real>0.50999999046325684</real>
+            <real>0.17000000178813934</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.11645399779081345</real>
+            <real>0.32075101137161255</real>
+            <real>0.64150899648666382</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.054176401346921921</real>
+            <real>0.10741499811410904</real>
+            <real>0.12578600645065308</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.21396400034427643</real>
+            <real>0.21396400034427643</real>
+            <real>0.21396400034427643</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.27044001221656799</real>
+            <real>1</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.10062900185585022</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.644780158996582</real>
+            <real>10.423800468444824</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.32704401016235352</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00015849100600462407</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>3.4000000953674316</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>6.867919921875</real>
+            <real>0.0013735899701714516</real>
+            <real>-0.45328301191329956</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.6792449951171875</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.13210900127887726</real>
+            <real>0.13210900127887726</real>
+            <real>0.13210900127887726</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.031410444527864456</real>
+            <real>-0.99950659275054932</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1308.1800537109375</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>5</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.1101770401000977</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>3</real>
+            <real>3</real>
+            <real>3</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Default.xml b/indra/newview/app_settings/windlight/skies/Default.xml
new file mode 100644
index 00000000000..13a2c75046c
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Default.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>0.34999999403953552</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.24475815892219543</real>
+            <real>0.44872328639030457</real>
+            <real>0.75999999046325684</real>
+            <real>0.37999999523162842</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.49548381567001343</real>
+            <real>0.49548381567001343</real>
+            <real>0.63999998569488525</real>
+            <real>0.31999999284744263</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00017999998817685992</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.80000001192092896</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18999999761581421</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.91269159317016602</real>
+            <real>-0.40864911675453186</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1605</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.9917697906494141</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.7342105507850647</real>
+            <real>0.78157895803451538</real>
+            <real>0.89999997615814209</real>
+            <real>0.29999998211860657</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Desert%20Sunset.xml b/indra/newview/app_settings/windlight/skies/Desert%20Sunset.xml
new file mode 100644
index 00000000000..b2a611163da
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Desert%20Sunset.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.07420019805431366</real>
+            <real>0.088169597089290619</real>
+            <real>0.11999999731779099</real>
+            <real>1</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.10767599940299988</real>
+            <real>0.21348699927330017</real>
+            <real>0.25</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.37999999523162842</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00046000001020729542</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>2</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.6100000143051147</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.15999999642372131</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.062790460884571075</real>
+            <real>-0.99802672863006592</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>562.5</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0787608623504639</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Fine%20Day.xml b/indra/newview/app_settings/windlight/skies/Fine%20Day.xml
new file mode 100644
index 00000000000..e053815be13
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Fine%20Day.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.21194984018802643</real>
+            <real>0.25700280070304871</real>
+            <real>0.25999999046325684</real>
+            <real>0.25999999046325684</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.10031381994485855</real>
+            <real>0.2849995493888855</real>
+            <real>0.56999999284744263</real>
+            <real>0.56999999284744263</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15806557238101959</real>
+            <real>0.31211116909980774</real>
+            <real>0.52999997138977051</real>
+            <real>0.52999997138977051</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.62000000476837158</real>
+            <real>0.72737622261047363</real>
+            <real>0.73626559972763062</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.89999997615814209</real>
+            <real>0.93999999761581421</real>
+            <real>0.74000000953674316</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.11999999731779099</real>
+            <real>0.20999999344348907</real>
+            <real>0.029999999329447746</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.25999999046325684</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.993240904292179</real>
+            <real>10.010000228881836</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.29999998211860657</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00013000000035390258</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>10.100000381469727</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>3.8955750465393066</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.4699999094009399</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>11.200000762939453</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.64999997615814209</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.35999998450279236</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.11999999731779099</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0.66304093599319458</real>
+            <real>0.24868990480899811</real>
+            <real>-0.70606660842895508</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>789</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>24</integer>
+    <key>star_brightness</key>
+        <real>0.18999999761581421</real>
+    <key>sun_angle</key>
+        <real>0.25132742524147034</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.25</real>
+            <real>1.2599999904632568</real>
+            <real>0.59999996423721313</real>
+            <real>2.25</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Fluffy%20Big%20Clouds.xml b/indra/newview/app_settings/windlight/skies/Fluffy%20Big%20Clouds.xml
new file mode 100644
index 00000000000..8576ec125c8
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Fluffy%20Big%20Clouds.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.029999999329447746</real>
+            <real>0</real>
+            <real>0</real>
+            <real>0.029999999329447746</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.097999997437000275</real>
+            <real>0.2800000011920929</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.11999999731779099</real>
+            <real>0.35094299912452698</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.48999997973442078</real>
+            <real>0.79000002145767212</real>
+            <real>0.80000001192092896</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.53999996185302734</real>
+            <real>0.5</real>
+            <real>0.75999999046325684</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.38999998569488525</real>
+            <real>0.5</real>
+            <real>0.039999999105930328</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.43999999761581421</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>11.809999465942383</real>
+            <real>12.799999237060547</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.32999998331069946</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00021999998716637492</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>4</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>3.2044246196746826</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.5399999618530273</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>3.8000010331979865</real>
+            <real>0.001000000059761974</real>
+            <real>-0.49999996688498527</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.20999999344348907</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.049999997019767761</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0.056814663112163544</real>
+            <real>0.42577928304672241</real>
+            <real>-0.90304160118103027</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>676.10003662109375</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>18</integer>
+    <key>star_brightness</key>
+        <real>0.44999998807907104</real>
+    <key>sun_angle</key>
+        <real>0.4398229718208313</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.7999999523162842</real>
+            <real>1.4099999666213989</real>
+            <real>1.0199999809265137</real>
+            <real>1.7999999523162842</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Foggy.xml b/indra/newview/app_settings/windlight/skies/Foggy.xml
new file mode 100644
index 00000000000..cb7395d589b
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Foggy.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.32999998331069946</real>
+            <real>0.32999998331069946</real>
+            <real>0.32999998331069946</real>
+            <real>0.10999999940395355</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.43070214986801147</real>
+            <real>0.85394668579101563</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0.69999998807907104</real>
+            <real>0.69999998807907104</real>
+            <real>0.69999998807907104</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.53999996185302734</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.29999998211860657</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.39999997615814209</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>4</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>3.7999999523162842</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.5</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>4</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.64999997615814209</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.3711388286737929e-008</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>18</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.5707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.53999996185302734</real>
+            <real>0.53999996185302734</real>
+            <real>0.53999996185302734</real>
+            <real>0.17999999225139618</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Funky%20Funky%20Funky.xml b/indra/newview/app_settings/windlight/skies/Funky%20Funky%20Funky.xml
new file mode 100644
index 00000000000..32be0d25e62
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Funky%20Funky%20Funky.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.29999998211860657</real>
+            <real>0.23511900007724762</real>
+            <real>0.31999999284744263</real>
+            <real>1</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.13977900147438049</real>
+            <real>0.38499599695205688</real>
+            <real>0.76999998092651367</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.18999999761581421</real>
+            <real>0.18999999761581421</real>
+            <real>0.18999999761581421</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>5.3780298233032227</real>
+            <real>1.9675600528717041</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>5.3780298233032227</real>
+            <real>1.9675600528717041</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.739999771118164</real>
+            <real>10.600000381469727</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.31000000238418579</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00052000000141561031</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>3.4000000953674316</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>0.77999997138977051</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>1.1000000238418579</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.12999999523162842</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.53582650423049927</real>
+            <real>-0.84432810544967651</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>656.20001220703125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>28</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>2.5761063098907471</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.1299998760223389</real>
+            <real>1.5299999713897705</real>
+            <real>2.8385701179504395</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Funky%20Funky.xml b/indra/newview/app_settings/windlight/skies/Funky%20Funky.xml
new file mode 100644
index 00000000000..ae16b2d1356
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Funky%20Funky.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.32999998331069946</real>
+            <real>0.32999998331069946</real>
+            <real>0.32999998331069946</real>
+            <real>0.10999999940395355</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15130999684333801</real>
+            <real>0.30000001192092896</real>
+            <real>0.35131001472473145</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.65280699729919434</real>
+            <real>0.50335597991943359</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.65280699729919434</real>
+            <real>0.50335597991943359</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.33064401149749756</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.062790460884571075</real>
+            <real>-0.99802672863006592</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>11</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0787608623504639</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.86811381578445435</real>
+            <real>2.2200000286102295</real>
+            <real>2.2200000286102295</real>
+            <real>0.74000000953674316</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Gelatto.xml b/indra/newview/app_settings/windlight/skies/Gelatto.xml
new file mode 100644
index 00000000000..66b3d317b8f
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Gelatto.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0</real>
+            <real>0.15999999642372131</real>
+            <real>0</real>
+            <real>0.15999999642372131</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.019999999552965164</real>
+            <real>0.22999770939350128</real>
+            <real>0.45999997854232788</real>
+            <real>0.55000001192092896</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0</real>
+            <real>0.6319204568862915</real>
+            <real>0.74000000953674316</real>
+            <real>0.84999996423721313</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.53999996185302734</real>
+            <real>0.50999999046325684</real>
+            <real>0.23999999463558197</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.059999998658895493</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.2800000011920929</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>20</real>
+            <real>20</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.32999998331069946</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00016999999934341758</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>8.1000003814697266</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>3.7699110507965088</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>0</boolean>
+            <boolean>0</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.5399999618530273</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>0.39999961853027344</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.49999997019767761</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>3.2599999904632568</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.4699999988079071</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0.58749508857727051</real>
+            <real>-0.031410761177539825</real>
+            <real>-0.80861783027648926</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1267.5999755859375</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>18</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>-0.031415928155183792</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.75</real>
+            <real>0.71999996900558472</real>
+            <real>0.37800011038780212</real>
+            <real>0.80999994277954102</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Ghost.xml b/indra/newview/app_settings/windlight/skies/Ghost.xml
new file mode 100644
index 00000000000..447202ed513
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Ghost.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.23999999463558197</real>
+            <real>0.23999999463558197</real>
+            <real>0.23999999463558197</real>
+            <real>0.079999998211860657</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.16700799763202667</real>
+            <real>0.45999500155448914</real>
+            <real>0.92000001668930054</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.18089599907398224</real>
+            <real>0.35865798592567444</real>
+            <real>0.41999998688697815</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>11.539999961853027</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.36000001430511475</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00042999998549930751</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>8.1000003814697266</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.51999998092651367</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.75</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18000000715255737</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.89100658893585205</real>
+            <real>0.45399042963981628</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>718.70001220703125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>23</integer>
+    <key>star_brightness</key>
+        <real>2</real>
+    <key>sun_angle</key>
+        <real>1.0995575189590454</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Incongruent%20Truths.xml b/indra/newview/app_settings/windlight/skies/Incongruent%20Truths.xml
new file mode 100644
index 00000000000..098844e16e3
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Incongruent%20Truths.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0</real>
+            <real>0</real>
+            <real>0.44999998807907104</real>
+            <real>0.44999998807907104</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.13997539444089213</real>
+            <real>0.38665792478461469</real>
+            <real>0.77332294252195766</real>
+            <real>0.95108884837904384</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0</real>
+            <real>0.22876684367656708</real>
+            <real>0.290018230676651</real>
+            <real>0.31999999284744263</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.25999999046325684</real>
+            <real>0.28883209824562073</real>
+            <real>0.28994369506835938</real>
+            <real>0.28999999165534973</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.17999999225139618</real>
+            <real>0.50999999046325684</real>
+            <real>0.91999995708465576</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.079999998211860657</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.25</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.436104517528292</real>
+            <real>10</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.34000000357627869</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0002899999963119626</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>1.3000000715255737</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>2.2619466781616211</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.5399999618530273</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>4.0000009536743164</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.74999994039535522</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.12999999523162842</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.14999999105930328</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>-0.74630612134933472</real>
+            <real>0.24868990480899811</real>
+            <real>-0.61739814281463623</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>394.39999389648437</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>18</integer>
+    <key>star_brightness</key>
+        <real>0.44999998807907104</real>
+    <key>sun_angle</key>
+        <real>0.25132742524147034</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.25</real>
+            <real>1.957500696182251</real>
+            <real>1.170000433921814</real>
+            <real>0.75</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Midday%201.xml b/indra/newview/app_settings/windlight/skies/Midday%201.xml
new file mode 100644
index 00000000000..13a2c75046c
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Midday%201.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>1.0499999523162842</real>
+            <real>0.34999999403953552</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.24475815892219543</real>
+            <real>0.44872328639030457</real>
+            <real>0.75999999046325684</real>
+            <real>0.37999999523162842</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.49548381567001343</real>
+            <real>0.49548381567001343</real>
+            <real>0.63999998569488525</real>
+            <real>0.31999999284744263</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+            <real>0.40999999642372131</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.6884100437164307</real>
+            <real>0.52609699964523315</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00017999998817685992</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.80000001192092896</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.18999999761581421</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.91269159317016602</real>
+            <real>-0.40864911675453186</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1605</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>22</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.9917697906494141</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.7342105507850647</real>
+            <real>0.78157895803451538</real>
+            <real>0.89999997615814209</real>
+            <real>0.29999998211860657</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Midday%202.xml b/indra/newview/app_settings/windlight/skies/Midday%202.xml
new file mode 100644
index 00000000000..04f2ba85ee0
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Midday%202.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.43070214986801147</real>
+            <real>0.85394668579101563</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0.69999998807907104</real>
+            <real>0.69999998807907104</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.53999996185302734</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.29999998211860657</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.199999809265137</real>
+            <real>10.069999694824219</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.22999998927116394</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.6100000143051147</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>3.7999999523162842</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.5</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.3711388286737929e-008</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>-1163005939</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.5707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.80999994277954102</real>
+            <real>0.80999994277954102</real>
+            <real>0.80999994277954102</real>
+            <real>0.26999998092651367</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Midday%203.xml b/indra/newview/app_settings/windlight/skies/Midday%203.xml
new file mode 100644
index 00000000000..a23dcab60bb
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Midday%203.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.16449999809265137</real>
+            <real>0.4699999988079071</real>
+            <real>0.93999999761581421</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.17547200620174408</real>
+            <real>0.35094299912452698</real>
+            <real>0.62000000476837158</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.5899999737739563</real>
+            <real>0.79000002145767212</real>
+            <real>0.80000001192092896</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>2.8148899078369141</real>
+            <real>5.6909198760986328</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>5.9584097862243652</real>
+            <real>6.9909601211547852</real>
+            <real>0.070000000298023224</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.9300003051757813</real>
+            <real>10.199999809265137</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.25999999046325684</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00039000000106170774</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.6100000143051147</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-1.1599999666213989</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.20999999344348907</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.11999999731779099</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.3711388286737929e-008</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>2250</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>24</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.5707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.2599999904632568</real>
+            <real>1.2599999904632568</real>
+            <real>1.2599999904632568</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Midday%204.xml b/indra/newview/app_settings/windlight/skies/Midday%204.xml
new file mode 100644
index 00000000000..255e314e0f2
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Midday%204.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>0.33000001311302185</real>
+            <real>1</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.097999997437000275</real>
+            <real>0.2800000011920929</real>
+            <real>0.56000000238418579</real>
+            <real>0.56000000238418579</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.17547200620174408</real>
+            <real>0.35094299912452698</real>
+            <real>0.61000001430511475</real>
+            <real>0.61000001430511475</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.5899999737739563</real>
+            <real>0.79000002145767212</real>
+            <real>0.80000001192092896</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>2.8148899078369141</real>
+            <real>5.6909198760986328</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>5.9584097862243652</real>
+            <real>6.9909601211547852</real>
+            <real>0.070000000298023224</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.32999998331069946</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.9300003051757813</real>
+            <real>10.199999809265137</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.22999998927116394</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00039000000106170774</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.6100000143051147</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>3.8000011444091797</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.49999997019767761</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.20999999344348907</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.19999998807907104</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>-4.3711388286737929e-008</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>1802.800048828125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>24</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>1.5707963705062866</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.2599999904632568</real>
+            <real>1.2599999904632568</real>
+            <real>1.2599999904632568</real>
+            <real>0.41999998688697815</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Night.xml b/indra/newview/app_settings/windlight/skies/Night.xml
new file mode 100644
index 00000000000..c4938949ce8
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Night.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.20405027105862608</real>
+            <real>0.24246673976617727</real>
+            <real>0.32999997392212316</real>
+            <real>0.11000000166951449</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.44999999369830818</real>
+            <real>0.44999999398335949</real>
+            <real>0.4499999944309046</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.23999999567946317</real>
+            <real>0.23999999579784967</real>
+            <real>0.23999999583870221</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615400241575034</real>
+            <real>0.22615400241575034</real>
+            <real>0.22615400241575034</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.88000000953711155</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940035411295</real>
+            <real>10.011000104431371</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.36000001430511475</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00030000001824737163</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>3.0208916693946743e-009</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000214212465</real>
+            <real>-0.47999999165502744</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>3.9999999963077992</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>1.7901579546794781e-010</real>
+            <real>0.19915600437467304</real>
+            <real>0.19915600437467304</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>1</real>
+            <real>3.0028815672267228e-005</real>
+            <real>1</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>906.20003957594895</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>26</integer>
+    <key>star_brightness</key>
+        <real>2</real>
+    <key>sun_angle</key>
+        <real>4.7123589515686035</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.34876692389196384</real>
+            <real>0.3557424864638451</real>
+            <real>0.65999994893325931</real>
+            <real>0.22000000284673543</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Pirate.xml b/indra/newview/app_settings/windlight/skies/Pirate.xml
new file mode 100644
index 00000000000..dcb9c27ba4f
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Pirate.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.27825063467025757</real>
+            <real>0.33063584566116333</real>
+            <real>0.44999998807907104</real>
+            <real>0.14999999105930328</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.14522500336170197</real>
+            <real>0.39999699592590332</real>
+            <real>0.80000197887420654</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.15130999684333801</real>
+            <real>0.30000001192092896</real>
+            <real>0.35131001472473145</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>1.2046600580215454</real>
+            <real>0.51547497510910034</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>1.2046600580215454</real>
+            <real>0.51547497510910034</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.49940013885498</real>
+            <real>10.01099967956543</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.33064401149749756</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.0003499999875202775</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>3.4000000953674316</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.36000001430511475</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.69999998807907104</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.062790460884571075</real>
+            <real>-0.99802672863006592</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>600</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>27</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0787608623504639</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>2.8385701179504395</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Purple.xml b/indra/newview/app_settings/windlight/skies/Purple.xml
new file mode 100644
index 00000000000..0e9ac3f36e3
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Purple.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.1978670060634613</real>
+            <real>0.23511900007724762</real>
+            <real>0.31999999284744263</real>
+            <real>1</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.13977900147438049</real>
+            <real>0.38499599695205688</real>
+            <real>0.76999998092651367</real>
+            <real>1</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.18999999761581421</real>
+            <real>0.18999999761581421</real>
+            <real>0.18999999761581421</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>0.22615399956703186</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>5.3780298233032227</real>
+            <real>1.9675600528717041</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>5.3780298233032227</real>
+            <real>1.9675600528717041</real>
+            <real>0.125</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.41999998688697815</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>10.739999771118164</real>
+            <real>10.600000381469727</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.31000000238418579</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00052000000141561031</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>3.4000000953674316</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>0</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>5</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.47999998927116394</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>1.1000000238418579</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.12999999523162842</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0</real>
+            <real>0.094108030200004578</real>
+            <real>-0.99556201696395874</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>656.20001220703125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>28</integer>
+    <key>star_brightness</key>
+        <real>0</real>
+    <key>sun_angle</key>
+        <real>3.0473451614379883</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.5</real>
+            <real>1.5299999713897705</real>
+            <real>2.8385701179504395</real>
+            <real>1</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Sailor%27s%20Delight.xml b/indra/newview/app_settings/windlight/skies/Sailor%27s%20Delight.xml
new file mode 100644
index 00000000000..70df6b0e609
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Sailor%27s%20Delight.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0.8399999737739563</real>
+            <real>0.090738050639629364</real>
+            <real>0.1234893873333931</real>
+            <real>0.8399999737739563</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0.93999999761581421</real>
+            <real>0.69999998807907104</real>
+            <real>0.25</real>
+            <real>0.93999999761581421</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>1</real>
+            <real>0.59999996423721313</real>
+            <real>0.25001853704452515</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.65999996662139893</real>
+            <real>0.38999998569488525</real>
+            <real>0.22618354856967926</real>
+            <real>0.65999996662139893</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.76999998092651367</real>
+            <real>0.50999999046325684</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.5</real>
+            <real>0.5899999737739563</real>
+            <real>0.019999999552965164</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.26999998092651367</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>9.4499998092651367</real>
+            <real>9.4399995803833008</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.5</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00019999999494757503</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>6.7000002861022949</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>3.7070791721343994</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.4800000190734863</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>0.79999923706054688</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.94999998807907104</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.89999997615814209</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.29999998211860657</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>0.53160154819488525</real>
+            <real>0.12533323466777802</real>
+            <real>-0.83767020702362061</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>281.70001220703125</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>18</integer>
+    <key>star_brightness</key>
+        <real>1.3799999952316284</real>
+    <key>sun_angle</key>
+        <real>0.12566371262073517</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>0.75</real>
+            <real>1.6800000667572021</real>
+            <real>1.0777359008789062</real>
+            <real>0.56000000238418579</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/skies/Sheer%20Surreality.xml b/indra/newview/app_settings/windlight/skies/Sheer%20Surreality.xml
new file mode 100644
index 00000000000..4c44a1bdb24
--- /dev/null
+++ b/indra/newview/app_settings/windlight/skies/Sheer%20Surreality.xml
@@ -0,0 +1,141 @@
+<llsd>
+    <map>
+    <key>ambient</key>
+        <array>
+            <real>0</real>
+            <real>0.059999998658895493</real>
+            <real>0</real>
+            <real>0.059999998658895493</real>
+        </array>
+    <key>blue_density</key>
+        <array>
+            <real>0</real>
+            <real>0.099999994039535522</real>
+            <real>0.32999998331069946</real>
+            <real>0.32999998331069946</real>
+        </array>
+    <key>blue_horizon</key>
+        <array>
+            <real>0.029999999329447746</real>
+            <real>0</real>
+            <real>1</real>
+            <real>1</real>
+        </array>
+    <key>cloud_color</key>
+        <array>
+            <real>0.81999999284744263</real>
+            <real>0.18999999761581421</real>
+            <real>0.039999999105930328</real>
+            <real>0.81999999284744263</real>
+        </array>
+    <key>cloud_pos_density1</key>
+        <array>
+            <real>0.74000000953674316</real>
+            <real>0.93999999761581421</real>
+            <real>0.20999999344348907</real>
+            <real>1</real>
+        </array>
+    <key>cloud_pos_density2</key>
+        <array>
+            <real>0.65999996662139893</real>
+            <real>0.52999997138977051</real>
+            <real>0.0099999997764825821</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scale</key>
+        <array>
+            <real>0.14000000059604645</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>cloud_scroll_rate</key>
+        <array>
+            <real>18</real>
+            <real>20</real>
+        </array>
+    <key>cloud_shadow</key>
+        <array>
+            <real>0.37999999523162842</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>density_multiplier</key>
+        <array>
+            <real>0.00018000000272877514</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>distance_multiplier</key>
+        <array>
+            <real>6.7000002861022949</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>east_angle</key>
+        <real>2.3247785568237305</real>
+    <key>enable_cloud_scroll</key>
+        <array>
+            <boolean>1</boolean>
+            <boolean>1</boolean>
+        </array>
+    <key>gamma</key>
+        <array>
+            <real>1.9499999284744263</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>glow</key>
+        <array>
+            <real>17.399999618530273</real>
+            <real>0.0010000000474974513</real>
+            <real>-0.64999997615814209</real>
+            <real>1</real>
+        </array>
+    <key>haze_density</key>
+        <array>
+            <real>0.40999999642372131</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>haze_horizon</key>
+        <array>
+            <real>0.17000000178813934</real>
+            <real>0.19915600121021271</real>
+            <real>0.19915600121021271</real>
+            <real>1</real>
+        </array>
+    <key>lightnorm</key>
+        <array>
+            <real>-0.72322052717208862</real>
+            <real>0.12533323466777802</real>
+            <real>-0.67914927005767822</real>
+            <real>0</real>
+        </array>
+    <key>max_y</key>
+        <array>
+            <real>263</real>
+            <real>0</real>
+            <real>0</real>
+            <real>1</real>
+        </array>
+    <key>preset_num</key>
+        <integer>24</integer>
+    <key>star_brightness</key>
+        <real>1.0399999618530273</real>
+    <key>sun_angle</key>
+        <real>0.12566371262073517</real>
+    <key>sunlight_color</key>
+        <array>
+            <real>1.5899999141693115</real>
+            <real>1.5299999713897705</real>
+            <real>0.53999996185302734</real>
+            <real>1.5899999141693115</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Default.xml b/indra/newview/app_settings/windlight/water/Default.xml
new file mode 100644
index 00000000000..dce4148c7d3
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Default.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.040000002831220627</real>
+    <key>fresnelOffset</key>
+        <real>0.5</real>
+    <key>fresnelScale</key>
+        <real>0.39999997615814209</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.029999999329447746</real>
+    <key>scaleBelow</key>
+        <real>0.20000000298023224</real>
+    <key>underWaterFogMod</key>
+        <real>0.25</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.015686275437474251</real>
+            <real>0.14901961386203766</real>
+            <real>0.25098040699958801</real>
+            <real>1</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>16</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>1.0499997138977051</real>
+            <real>-0.42000007629394531</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>1.1099996566772461</real>
+            <real>-1.1600000858306885</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Glassy.xml b/indra/newview/app_settings/windlight/water/Glassy.xml
new file mode 100644
index 00000000000..01183e46871
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Glassy.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.003000000026077032089233398</real>
+    <key>fresnelOffset</key>
+        <real>0.579999983310699462890625</real>
+    <key>fresnelScale</key>
+        <real>0.0999999940395355224609375</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.07999999821186065673828125</real>
+    <key>scaleBelow</key>
+        <real>0.2000000029802322387695312</real>
+    <key>underWaterFogMod</key>
+        <real>0.25</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.04999999701976776123046875</real>
+            <real>0.37999999523162841796875</real>
+            <real>0.5299999713897705078125</real>
+            <real>0.5299999713897705078125</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>1</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.1700000017881393432617188</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.579999983310699462890625</real>
+            <real>-0.670000016689300537109375</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Murky.xml b/indra/newview/app_settings/windlight/water/Murky.xml
new file mode 100644
index 00000000000..1d9e0224221
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Murky.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.0030000000260770321</real>
+    <key>fresnelOffset</key>
+        <real>0.39999997615814209</real>
+    <key>fresnelScale</key>
+        <real>0.5</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.079999998211860657</real>
+    <key>scaleBelow</key>
+        <real>0.20000000298023224</real>
+    <key>underWaterFogMod</key>
+        <real>0.76999998092651367</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.08999999612569809</real>
+            <real>0.17000000178813934</real>
+            <real>0.20999999344348907</real>
+            <real>0.20999999344348907</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>16</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.17000000178813934</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.57999998331069946</real>
+            <real>-0.67000001668930054</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Pond.xml b/indra/newview/app_settings/windlight/water/Pond.xml
new file mode 100644
index 00000000000..59e3c441eaf
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Pond.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.0030000000260770321</real>
+    <key>fresnelOffset</key>
+        <real>0.50999999046325684</real>
+    <key>fresnelScale</key>
+        <real>0.099999994039535522</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.079999998211860657</real>
+    <key>scaleBelow</key>
+        <real>0.20000000298023224</real>
+    <key>underWaterFogMod</key>
+        <real>0.25</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.059999998658895493</real>
+            <real>0.37999999523162842</real>
+            <real>0.52999997138977051</real>
+            <real>0.52999997138977051</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>2.1000001430511475</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.17000000178813934</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.57999998331069946</real>
+            <real>-0.67000001668930054</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/SNAKE%21%21%21.xml b/indra/newview/app_settings/windlight/water/SNAKE%21%21%21.xml
new file mode 100644
index 00000000000..6dbc4e87191
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/SNAKE%21%21%21.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.0030000000260770321</real>
+    <key>fresnelOffset</key>
+        <real>0.57999998331069946</real>
+    <key>fresnelScale</key>
+        <real>0.099999994039535522</real>
+    <key>normScale</key>
+        <array>
+            <real>10</real>
+            <real>10</real>
+            <real>10</real>
+        </array>
+    <key>normalMap</key>
+        <uuid>470626e3-ac38-8554-d49b-90311c0176a9</uuid>
+    <key>scaleAbove</key>
+        <real>0.91999995708465576</real>
+    <key>scaleBelow</key>
+        <real>0.93999999761581421</real>
+    <key>underWaterFogMod</key>
+        <real>0.25</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.049999997019767761</real>
+            <real>0.37999999523162842</real>
+            <real>0.52999997138977051</real>
+            <real>0.52999997138977051</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>3.2000000476837158</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.17000000178813934</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.57999998331069946</real>
+            <real>-0.67000001668930054</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Second%20Plague.xml b/indra/newview/app_settings/windlight/water/Second%20Plague.xml
new file mode 100644
index 00000000000..137483ab64d
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Second%20Plague.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.017000000923871994</real>
+    <key>fresnelOffset</key>
+        <real>0.37000000476837158</real>
+    <key>fresnelScale</key>
+        <real>0</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.079999998211860657</real>
+    <key>scaleBelow</key>
+        <real>0.20000000298023224</real>
+    <key>underWaterFogMod</key>
+        <real>0.85999995470046997</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0.48999997973442078</real>
+            <real>0</real>
+            <real>0</real>
+            <real>0.48999997973442078</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>20</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.17000000178813934</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.57999998331069946</real>
+            <real>-0.67000001668930054</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/windlight/water/Valdez.xml b/indra/newview/app_settings/windlight/water/Valdez.xml
new file mode 100644
index 00000000000..eb70a142e07
--- /dev/null
+++ b/indra/newview/app_settings/windlight/water/Valdez.xml
@@ -0,0 +1,43 @@
+<llsd>
+    <map>
+    <key>blurMultiplier</key>
+        <real>0.0020000000949949026</real>
+    <key>fresnelOffset</key>
+        <real>0.28999999165534973</real>
+    <key>fresnelScale</key>
+        <real>0</real>
+    <key>normScale</key>
+        <array>
+            <integer>2</integer>
+            <integer>2</integer>
+            <integer>2</integer>
+        </array>
+    <key>normalMap</key>
+        <uuid>822ded49-9a6c-f61c-cb89-6df54f42cdf4</uuid>
+    <key>scaleAbove</key>
+        <real>0.079999998211860657</real>
+    <key>scaleBelow</key>
+        <real>0.20000000298023224</real>
+    <key>underWaterFogMod</key>
+        <real>1</real>
+    <key>waterFogColor</key>
+        <array>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+            <real>0</real>
+        </array>
+    <key>waterFogDensity</key>
+        <real>1024</real>
+    <key>wave1Dir</key>
+        <array>
+            <real>0.5</real>
+            <real>-0.17000000178813934</real>
+        </array>
+    <key>wave2Dir</key>
+        <array>
+            <real>0.57999998331069946</real>
+            <real>-0.67000001668930054</real>
+        </array>
+    </map>
+</llsd>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index f98b42bba28..8a023de5f65 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 10
+version 15
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -12,7 +12,7 @@ version 10
 //		<name> <available> <recommended>
 //		<name> is the name of a feature
 //		<available> is 0 or 1, whether the feature is available
-//		<recommended> is an S32 which is the recommended value
+//		<recommended> is an F32 which is the recommended value
 //
 // For now, the first list read sets up all of the default values
 //
@@ -23,102 +23,197 @@ version 10
 // NOTE: All settings are set to the MIN of applied values, including 'all'!
 //
 list all
-RenderVBO			1	1
-RenderAniso			1	0
-RenderAvatarMode	1	2
-RenderAvatarVP		1	1
-RenderDistance		1	128
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderParticleCount	1	4096
-RenderRippleWater	1	1
-RenderTerrainDetail	1	2
-VertexShaderEnable	1	1
-UseOcclusion		1	1
-RenderCubeMap		1	1
-
-//
-// Class 0 Hardware (Unknown or just old)
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderCubeMap				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderFogRatio				1	4.0
+RenderGamma					1	0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderNightBrightness		1	1.0
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVBOEnable				1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+UseOcclusion				1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+
+//
+// Low Graphics Settings
+//
+list Low
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	0
+RenderFarClip				1	64
+RenderFlexTimeFactor		1	0.5
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	1024
+RenderObjectBump			1	0
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	0
+RenderTerrainLODFactor		1	1
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	0
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// Mid Graphics Settings
+//
+list Mid
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	1
+RenderFarClip				1	96
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	2048
+RenderObjectBump			1	1
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	1.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// High Graphics Settings (purty)
+//
+list High
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	128
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	4096
+RenderObjectBump			1	1
+RenderReflectionDetail		1	2
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	48
+
+//
+// Ultra graphics (REALLY PURTY!)
+//
+list Ultra
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+
+//
+// Class Unknown Hardware (unknown)
+//
+list Unknown
+RenderVBOEnable				1	0
+
+//
+// Class 0 Hardware (just old)
 //
 list Class0
-VertexShaderEnable	1	0
-RenderVBO			1	0
-RenderDistance		1	64
-RenderAvatarVP		1	0
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 1 Hardware
 //
 list Class1
-VertexShaderEnable	1	0
-RenderVBO			1	1
-RenderDistance		1	96
-RenderAvatarVP		1	1
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 2 Hardware (make it purty)
 //
 list Class2
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	1
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // Class 3 Hardware (make it purty)
 //
 list Class3
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	1
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // No Pixel Shaders available
 //
 list NoPixelShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // No Vertex Shaders available
 //
 list NoVertexShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
-//
 // "Default" setups for safe, low, medium, high
 //
 list safe
-RenderVBO			1	0
-RenderAniso			1	0
-RenderAvatarVP		0	0
-RenderLighting		1	0
-RenderParticleCount	1	1024
-RenderTerrainDetail 1	0
-
-
-list low
-RenderVBO			1	0
-RenderAniso			1	0
-RenderLighting		1	0
-
-list medium
-RenderLighting		1	0
-
+RenderAnisotropic			1	0
+RenderAvatarCloth			0	0
+RenderAvatarVP				0	0
+RenderLightingDetail		1	0
+RenderObjectBump			0	0
+RenderMaxPartCount			1	1024
+RenderTerrainDetail 		1	0
+RenderUseImpostors			0	0
+RenderVBOEnable				1	0
+RenderWaterReflections		0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // CPU based feature masks
@@ -126,37 +221,110 @@ RenderLighting		1	0
 
 // 1Ghz or less (equiv)
 list CPUSlow
-RenderParticleCount	1	1024
-
+RenderMaxPartCount			1	1024
 
 //
 // RAM based feature masks
 //
 list RAM256MB
-RenderObjectBump	0	0
-
+RenderObjectBump			0	0
 
 //
 // Graphics card based feature masks
 //
 list OpenGLPre15
-RenderVBO			1	0
+RenderVBOEnable				1	0
 
 list Intel
-RenderVBO			1	0
-RenderAniso			1	0
-RenderLighting		1	0
-RenderTerrainDetail	1	0
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
 
 list GeForce2
-RenderVBO			1	1
-RenderAniso			1	0
-RenderLighting		1	0
-RenderParticleCount	1	2048
-RenderTerrainDetail	1	0
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	2048
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	1
+
+list Intel_965
+UseOcclusion				0	0
+
+list ATI_Mobility_Radeon_9800
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+list ATI_Mobility_Radeon_9700
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+list ATI_Mobility_Radeon_9600
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+// Avatar hardware skinning causes
+// invisible avatars on x2600... so I masked
+// out other possible bad ones till it's fixed
+list ATI_Radeon_X2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+
+list ATI_Radeon_HD_2300
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
 
-list ATI_Mobility_Radeon_X3xx
-VertexShaderEnable	1	0
+list ATI_ASUS_AH24xx
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_ASUS_AH26xx
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_ASUS_EAH24xx
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_ASUS_EAH26xx
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_ASUS_EAH38xx
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
 
-list ATI_Mobility_Radeon_X6xx
-VertexShaderEnable	1	0
+list NVIDIA_GeForce_Go_6100
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6200
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6500
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6600
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6700
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6800
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6
+RenderVBOEnable				1	0
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index f31fc0dbb6f..ccffc8d4245 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -1,6 +1,6 @@
-version 10
+version 15
 
-// NOTE: This is mostly identical to featuretable.txt with a few differences
+// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
 
 //
@@ -12,7 +12,7 @@ version 10
 //		<name> <available> <recommended>
 //		<name> is the name of a feature
 //		<available> is 0 or 1, whether the feature is available
-//		<recommended> is an S32 which is the recommended value
+//		<recommended> is an F32 which is the recommended value
 //
 // For now, the first list read sets up all of the default values
 //
@@ -23,104 +23,197 @@ version 10
 // NOTE: All settings are set to the MIN of applied values, including 'all'!
 //
 list all
-RenderVBO			1	1
-RenderAniso			1	0
-RenderAvatarMode	1	2
-RenderAvatarVP		1	1
-RenderDistance		1	128
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderParticleCount	1	4096
-RenderRippleWater	1	1
-RenderTerrainDetail	1	2
-VertexShaderEnable	1	1
-UseOcclusion		1	1
-RenderCubeMap		1	1
-
-//
-// Class 0 Hardware (Unknown or just old)
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderCubeMap				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderFogRatio				1	4.0
+RenderGamma					1	0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderNightBrightness		1	1.0
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVBOEnable				1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+UseOcclusion				1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+
+//
+// Low Graphics Settings
+//
+list Low
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	0
+RenderFarClip				1	64
+RenderFlexTimeFactor		1	0.5
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	1024
+RenderObjectBump			1	0
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	0
+RenderTerrainLODFactor		1	1
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	0
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// Mid Graphics Settings
+//
+list Mid
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	1
+RenderFarClip				1	96
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	2048
+RenderObjectBump			1	1
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	1.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// High Graphics Settings (purty)
+//
+list High
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	128
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	4096
+RenderObjectBump			1	1
+RenderReflectionDetail		1	2
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	48
+
+//
+// Ultra graphics (REALLY PURTY!)
+//
+list Ultra
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+
+//
+// Class Unknown Hardware (unknown)
+//
+list Unknown
+RenderVBOEnable				1	0
+
+//
+// Class 0 Hardware (just old)
 //
 list Class0
-VertexShaderEnable	1	0
-RenderVBO			1	0
-RenderDistance		1	64
-RenderAvatarVP		1	0
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 1 Hardware
 //
 list Class1
-VertexShaderEnable	1	0
-RenderVBO			1	1
-RenderDistance		1	96
-RenderAvatarVP		1	1
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 2 Hardware (make it purty)
 //
 list Class2
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	1
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // Class 3 Hardware (make it purty)
 //
 list Class3
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	1
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // No Pixel Shaders available
 //
 list NoPixelShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // No Vertex Shaders available
 //
 list NoVertexShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
-//
 // "Default" setups for safe, low, medium, high
 //
 list safe
-RenderVBO			1	0
-RenderAniso			1	0
-RenderAvatarVP		0	0
-RenderLighting		1	0
-RenderParticleCount	1	1024
-RenderTerrainDetail 1	0
-RenderCubeMap		0	0
-UseOcclusion		0	0
-
-
-list low
-RenderVBO			1	0
-RenderAniso			1	0
-RenderLighting		1	0
-
-list medium
-RenderLighting		1	0
-
+RenderAnisotropic			1	0
+RenderAvatarCloth			0	0
+RenderAvatarVP				0	0
+RenderLightingDetail		1	0
+RenderObjectBump			0	0
+RenderMaxPartCount			1	1024
+RenderTerrainDetail 		1	0
+RenderUseImpostors			0	0
+RenderVBOEnable				1	0
+RenderWaterReflections		0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // CPU based feature masks
@@ -128,52 +221,100 @@ RenderLighting		1	0
 
 // 1Ghz or less (equiv)
 list CPUSlow
-RenderParticleCount	1	1024
-
+RenderMaxPartCount			1	1024
 
 //
 // RAM based feature masks
 //
 list RAM256MB
-RenderObjectBump	0	0
-
+RenderObjectBump			0	0
 
 //
 // Graphics card based feature masks
 //
 list OpenGLPre15
-RenderVBO			1	0
+RenderVBOEnable				1	0
 
 list Intel
-RenderVBO			1	0
-RenderAniso			1	0
-RenderLighting		1	0
-RenderTerrainDetail	1	0
-RenderCubeMap		0	0
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderCubeMap				0	0
+
 
 list GeForce2
-RenderVBO			1	1
-RenderAniso			1	0
-RenderLighting		1	0
-RenderParticleCount	1	2048
-RenderTerrainDetail	1	0
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	2048
+RenderTerrainDetail			1	0
 
-list GeForce3
+list Intel_965
+UseOcclusion				0	0
 
 list ATI
-UseOcclusion		0	0
+UseOcclusion				0	0
+WindLightUseAtmosShaders	0	0
+RenderVBOEnable				1	0
+
+list ATI_Mobility_Radeon_9800
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+list ATI_Mobility_Radeon_9700
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
-list Radeon8500
-RenderLighting		1	0
-RenderParticleCount	1	4096
+list ATI_Mobility_Radeon_9600
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
-// Hacked to be paranoid "safe"
-list Radeon9700
-RenderParticleCount	1	4096
+// Avatar hardware skinning causes
+// invisible avatars on x2600... so I masked
+// out other possible bad ones till it's fixed
+list ATI_Radeon_X2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
 
-// Hacked to be paranoid "safe"
-list MobilityRadeon9000
-RenderLighting		1	0
-RenderParticleCount	1	4096
+list ATI_Radeon_HD_2300
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
 
-list GeForceFX
+list NVIDIA_GeForce_Go_6100
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6200
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6500
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6600
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6700
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6800
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6
+RenderVBOEnable				1	0
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index fe5ae7a4ae0..bebb51fc125 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,6 +1,6 @@
-version 10
+version 15
 
-// NOTE: This is mostly identical to featuretable.txt with a few differences
+// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
 
 //
@@ -12,7 +12,7 @@ version 10
 //		<name> <available> <recommended>
 //		<name> is the name of a feature
 //		<available> is 0 or 1, whether the feature is available
-//		<recommended> is an S32 which is the recommended value
+//		<recommended> is an F32 which is the recommended value
 //
 // For now, the first list read sets up all of the default values
 //
@@ -22,102 +22,199 @@ version 10
 // All contains everything at their default settings for high end machines
 // NOTE: All settings are set to the MIN of applied values, including 'all'!
 //
-// Mac specific: RenderAvatarVP not enabled at all
 list all
-RenderVBO			1	0
-RenderAniso			1	0
-RenderAvatarMode	1	2
-RenderAvatarVP		1	0
-RenderDistance		1	128
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderParticleCount	1	4096
-RenderRippleWater	1	1
-RenderTerrainDetail	1	2
-VertexShaderEnable	1	1
-UseOcclusion		1	1
-RenderCubeMap		1	1
-
-//
-// Class 0 Hardware (Unknown or just old)
+RenderAnisotropic			1	0
+RenderAvatarCloth			0	0
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	0
+RenderCubeMap				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderFogRatio				1	4.0
+RenderGamma					1	0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderNightBrightness		1	1.0
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVBOEnable				1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+UseOcclusion				1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+RenderUseCleverUI			1	1
+
+//
+// Low Graphics Settings
+//
+list Low
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	0
+RenderFarClip				1	64
+RenderFlexTimeFactor		1	0.5
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	1024
+RenderObjectBump			1	0
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	0
+RenderTerrainLODFactor		1	1
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	0
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// Mid Graphics Settings
+//
+list Mid
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	1
+RenderFarClip				1	96
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	8
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	2048
+RenderObjectBump			1	1
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	1.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+
+//
+// High Graphics Settings (purty)
+//
+list High
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	128
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	4096
+RenderObjectBump			1	1
+RenderReflectionDetail		1	2
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+RenderWaterReflections		1	0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	48
+
+//
+// Ultra graphics (REALLY PURTY!)
+//
+list Ultra
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderLightingDetail		1	1
+RenderMaxPartCount			1	8192
+RenderObjectBump			1	1
+RenderReflectionDetail		1	3
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	2.0
+RenderWaterReflections		1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+
+//
+// Class Unknown Hardware (unknown)
+//
+list Unknown
+RenderVBOEnable				1	0
+
+//
+// Class 0 Hardware (just old)
 //
 list Class0
-VertexShaderEnable	1	0
-RenderAvatarVP		1	0
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 1 Hardware
 //
 list Class1
-VertexShaderEnable	1	0
-RenderAvatarVP		1	1
-RenderAvatarMode	1	0
-RenderLighting		1	0
-RenderObjectBump	1	0
-RenderRippleWater	1	0
+RenderVBOEnable				1	1
 
 //
 // Class 2 Hardware (make it purty)
 //
 list Class2
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	2
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // Class 3 Hardware (make it purty)
 //
 list Class3
-VertexShaderEnable	1	1
-RenderAvatarVP		1	1
-RenderAvatarMode	1	2
-RenderLighting		1	1
-RenderObjectBump	1	1
-RenderRippleWater	1	1
+RenderVBOEnable				1	1
 
 //
 // No Pixel Shaders available
 //
 list NoPixelShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // No Vertex Shaders available
 //
 list NoVertexShaders
-VertexShaderEnable	0	0
-RenderAvatarVP		0  0
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderWaterReflections		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
 
-//
 // "Default" setups for safe, low, medium, high
 //
 list safe
-RenderVBO			1	0
-RenderAniso			1	0
-RenderAvatarVP		0	0
-RenderDistance		1	64
-RenderLighting		1	0
-RenderParticleCount	1	1024
-RenderTerrainDetail 1	0
-
-
-list low
-RenderVBO			1	0
-RenderAniso			1	0
-RenderDistance		1	96
-RenderLighting		1	0
-
-list medium
-RenderLighting		1	0
-
+RenderAnisotropic			1	0
+RenderAvatarCloth			0	0
+RenderAvatarVP				0	0
+RenderLightingDetail		1	0
+RenderObjectBump			0	0
+RenderMaxPartCount			1	1024
+RenderTerrainDetail 		1	0
+RenderUseImpostors			0	0
+RenderVBOEnable				1	0
+RenderWaterReflections		0	0
+WindLightUseAtmosShaders	0	0
 
 //
 // CPU based feature masks
@@ -125,34 +222,94 @@ RenderLighting		1	0
 
 // 1Ghz or less (equiv)
 list CPUSlow
-RenderDistance			1	96
-RenderParticleCount	1	1024
-
+RenderMaxPartCount			1	1024
 
 //
 // RAM based feature masks
 //
 list RAM256MB
-RenderDistance		1	96
-RenderObjectBump	0	0
+RenderObjectBump			0	0
 
 //
 // Graphics card based feature masks
 //
 list OpenGLPre15
-RenderVBO			1	0
+RenderVBOEnable				1	0
 
-// nVidia settings
-list NVIDIA
+list Intel
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
 
 list GeForce2
-RenderAniso			1	0
-RenderDistance		1	64
-RenderLighting		1	0
-RenderParticleCount	1	2048
-RenderTerrainDetail	1	0
+RenderAnisotropic			1	0
+RenderLightingDetail		1	0
+RenderMaxPartCount			1	2048
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	1
 
-//
-// ATI settings
-//
-list ATI
+list Intel_965
+UseOcclusion				0	0
+
+list ATI_Mobility_Radeon_9800
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+list ATI_Mobility_Radeon_9700
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+list ATI_Mobility_Radeon_9600
+RenderAvatarCloth			0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+
+// Avatar hardware skinning causes
+// invisible avatars on x2600... so I masked
+// out other possible bad ones till it's fixed
+list ATI_Radeon_X2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_X3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+
+list ATI_Radeon_HD_2300
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2400
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2600
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_2900
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+list ATI_Radeon_HD_3800
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+
+list NVIDIA_GeForce_Go_6100
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6200
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6500
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6600
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6700
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6800
+RenderVBOEnable				1	0
+list NVIDIA_GeForce_Go_6
+RenderVBOEnable				1	0
diff --git a/indra/newview/featuretable_solaris.txt b/indra/newview/featuretable_solaris.txt
index 6c7acfa1871..7dd7c22cdf0 100644
--- a/indra/newview/featuretable_solaris.txt
+++ b/indra/newview/featuretable_solaris.txt
@@ -1,4 +1,4 @@
-version 10
+version 15
 
 // NOTE: This is mostly identical to featuretable.txt with a few differences
 // Should be combined into one table
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index 4b9bf655b5f..5d73a704978 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -1,139 +1,193 @@
 // 
 // Categorizes graphics chips into various classes by name
 //
-// The table contains chip names			 regular expressions to match
-// against driver strings			 and a class number.
+// The table contains chip names regular expressions to match
+// against driver strings, a class number, and whether we claim
+// to support them or not.
 //
 // Class Numbers:
-//		0 - Compatibility rendering only
-//		1 - Shaders available			 off by default
-//		2 - Shaders enabled by default
-//		3 - Everything on.
+//		0 - Defaults to low graphics settings.  No shaders on by default
+//		1 - Defaults to mid graphics settings.  Basic shaders on by default
+//		2 - Defaults to high graphics settings.  Atmospherics on by default.
+//		3 - Same as class 2 for now.
+//
+// Supported Number:
+//		0 - We claim to not support this card.
+//		1 - We claim to support this card.
 //
 // Format:
-//   <chip name>	<regexp>	<class>
+//   <chip name>	<regexp>	<class>		<supported>
 //	
 
-3Dfx							.*3Dfx.*								0
-3Dlabs							.*3Dlabs.*								0
-ATI All-in-Wonder PCI-E			.*ATI.*All-in-Wonder.*PCI-E.*			1
-ATI All-in-Wonder X800			.*ATI.*All-in-Wonder X8.*				2
-ATI All-in-Wonder X1800			.*ATI.*All-in-Wonder X18.*				3
-ATI All-in-Wonder X1900			.*ATI.*All-in-Wonder X19.*				3
-ATI ASUS X1xxx					.*ASUS X1.*			 					3
-ATI Mobility Radeon X1xxx		.*ATI.*Mobility.*X1.*					2
-ATI Mobility Radeon X3xx		.*ATI.*Mobility.*X3.*					1
-ATI Mobility Radeon X6xx		.*ATI.*Mobility.*X6.*					1
-ATI Mobility Radeon X7xx		.*ATI.*Mobility.*X7.*					1
-ATI Mobility Radeon Xxxx		.*ATI.*Mobility.*X.*					1
-ATI Mobility Radeon				.*ATI.*Mobility.*						0
-ATI Radeon OpenGL				.*ATI.*Radeon OpenGL.* 					3
-ATI Diamond X1xxx				.*ATI.*Diamond.*X1.*					3
-ATI FireGL 5xxx					.*ATI.*FireGL V5.*						3
-ATI FireGL						.*ATI.*Fire.*GL.*						0
-ATI FireMV						.*ATI.*FireMV.*							0
-ATI Generic						.*ATI.*Generic.*						0
-ATI Radeon 7000					.*ATI.*Radeon 7.*						0
-ATI Radeon 8000					.*ATI.*Radeon 8.*						0
-ATI Radeon 9000					.*ATI.*Radeon 90.*						1
-ATI Radeon 9100					.*ATI.*Radeon 91.*						1
-ATI Radeon 9200					.*ATI.*Radeon 92.*						1
-ATI Radeon 9500					.*ATI.*Radeon 95.*						1
-ATI Radeon 9600					.*ATI.*Radeon 96.*						1
-ATI Radeon 9700					.*ATI.*Radeon 97.*						1
-ATI Radeon 9800					.*ATI.*Radeon 98.*						1
-ATI Radeon X1300				.*ATI.*Radeon X13.*						3
-ATI Radeon X1400				.*ATI.*Radeon X14.*						3
-ATI Radeon X1500				.*ATI.*Radeon X15.*						3
-ATI Radeon X1600				.*ATI.*Radeon X16.*						3
-ATI Radeon X1700				.*ATI.*Radeon X17.*						3
-ATI Radeon X1800				.*ATI.*Radeon X18.*						3
-ATI Radeon X1900				.*ATI.*Radeon X19.*						3
-ATI Radeon X2400				.*ATI.*Radeon X24.*						3
-ATI Radeon X2600				.*ATI.*Radeon X26.*						3
-ATI Radeon X2900				.*ATI.*Radeon X29.*						3
-ATI Radeon X300					.*ATI.*Radeon X3.*						2
-ATI Radeon X400					.*ATI.*Radeon X4.*						2
-ATI Radeon X500					.*ATI.*Radeon X5.*						2
-ATI Radeon X600					.*ATI.*Radeon X6.*						2
-ATI Radeon X700					.*ATI.*Radeon X7.*						2
-ATI Radeon X800					.*ATI.*Radeon X8.*						2
-ATI Radeon X900					.*ATI.*Radeon X9.*						2
-ATI Radeon Xpress				.*ATI.*Radeon Xpress.*					1
-ATI Rage 128					.*ATI.*Rage 128.*						0
-Intel 830M						.*Intel.*830M							0
-Intel 845G						.*Intel.*845G							0
-Intel 855GM						.*Intel.*855GM							0
-Intel 865G						.*Intel.*865G							0
-Intel 900						.*Intel.*900.*900						0
-Intel 915G						.*Intel.*915G							0
-Intel 915GM						.*Intel.*915GM							0
-Intel 945G						.*Intel.*945G							0
-Intel 945GM						.*Intel.*945GM							0
-Intel 950						.*Intel.*950.*950						0
-Intel G965						.*Intel.*G965.*							0
-Intel GM965						.*Intel.*GM965.*						0
-Intel G33						.*Intel.*G33.*							0
-Intel Brookdale					.*Intel.*Brookdale.*					0
-Intel Montara					.*Intel.*Montara.*						0
-Intel Springdale				.*Intel.*Springdale.*					0
-Matrox							.*Matrox.*								0
-NVIDIA GeForce					.*GeForce 256.*							0
-NVIDIA GeForce 2				.*GeForce2.*							0
-NVIDIA GeForce 3				.*GeForce3.*							0
-NVIDIA GeForce 4 Go				.*NVIDIA.*GeForce4.*Go.*				0
-NVIDIA GeForce 4 MX				.*NVIDIA.*GeForce4 MX.*					0
-NVIDIA GeForce 4 Ti				.*NVIDIA.*GeForce4 Ti.*					0
-NVIDIA GeForce 6100				.*NVIDIA.*GeForce 61.*					2
-NVIDIA GeForce 6200				.*NVIDIA.*GeForce 62.*					2
-NVIDIA GeForce 6500				.*NVIDIA.*GeForce 65.*					2
-NVIDIA GeForce 6600				.*NVIDIA.*GeForce 66.*					2
-NVIDIA GeForce 6700				.*NVIDIA.*GeForce 67.*					2
-NVIDIA GeForce 6800				.*NVIDIA.*GeForce 68.*					2
-NVIDIA GeForce 7300				.*NVIDIA.*GeForce 73.*					3
-NVIDIA GeForce 7600				.*NVIDIA.*GeForce 76.*					3
-NVIDIA GeForce 7800				.*NVIDIA.*GeForce 78.*					3
-NVIDIA GeForce 7900				.*NVIDIA.*GeForce 79.*					3
-NVIDIA GeForce 8800				.*NVIDIA.*GeForce 88.*					3
-NVIDIA GeForce FX 5100			.*NVIDIA.*GeForce FX 51.*				1
-NVIDIA GeForce FX 5200			.*NVIDIA.*GeForce FX 52.*				1
-NVIDIA GeForce FX 5500			.*NVIDIA.*GeForce FX 55.*				1
-NVIDIA GeForce FX 5600			.*NVIDIA.*GeForce FX 56.*				1
-NVIDIA GeForce FX 5700			.*NVIDIA.*GeForce FX 57.*				1
-NVIDIA GeForce FX 5800			.*NVIDIA.*GeForce FX 58.*				1
-NVIDIA GeForce FX 5900			.*NVIDIA.*GeForce FX 59.*				1
-NVIDIA GeForce FX Go5100		.*NVIDIA.*GeForce FX Go51.*				1
-NVIDIA GeForce FX Go5200		.*NVIDIA.*GeForce FX Go52.*				1
-NVIDIA GeForce FX Go5300		.*NVIDIA.*GeForce FX Go53.*				1
-NVIDIA GeForce FX Go5500		.*NVIDIA.*GeForce FX Go55.*				1
-NVIDIA GeForce FX Go5600		.*NVIDIA.*GeForce FX Go56.*				1
-NVIDIA GeForce FX Go5700		.*NVIDIA.*GeForce FX Go57.*				1
-NVIDIA GeForce FX Go5800		.*NVIDIA.*GeForce FX Go58.*				1
-NVIDIA GeForce FX Go5900		.*NVIDIA.*GeForce FX Go59.*				1
-NVIDIA GeForce Go 6100			.*NVIDIA.*GeForce Go 61.*				2
-NVIDIA GeForce Go 6200			.*NVIDIA.*GeForce Go 62.*				2
-NVIDIA GeForce Go 6500			.*NVIDIA.*GeForce Go 65.*				2
-NVIDIA GeForce Go 6600			.*NVIDIA.*GeForce Go 66.*				2
-NVIDIA GeForce Go 6700			.*NVIDIA.*GeForce Go 67.*				2
-NVIDIA GeForce Go 6800			.*NVIDIA.*GeForce Go 68.*				2
-NVIDIA GeForce Go 7300			.*NVIDIA.*GeForce Go 73.*				3
-NVIDIA GeForce Go 7400			.*NVIDIA.*GeForce Go 74.*				3
-NVIDIA GeForce Go 7600			.*NVIDIA.*GeForce Go 76.*				3
-NVIDIA GeForce Go 7700			.*NVIDIA.*GeForce Go 77.*				3
-NVIDIA GeForce Go 7800			.*NVIDIA.*GeForce Go 78.*				3
-NVIDIA GeForce Go 7900			.*NVIDIA.*GeForce Go 79.*				3
-NVIDIA GeForce Go 6				.*GeForce Go 6.*						2
-NVIDIA GeForce PCX				.*GeForce PCX.*							1
-NVIDIA Generic					.*NVIDIA.*NV.*							0
-NVIDIA Generic					.*NVIDIA.*Unknown.*						0
-NVIDIA Quadro 2					.*Quadro2.*								0
-NVIDIA Quadro 4					.*Quadro4.*								0
-NVIDIA Quadro DCC				.*Quadro DCC.*							0
-NVIDIA Quadro FX				.*Quadro FX.*							1
-NVIDIA Quadro NVS				.*Quadro NVS.*							0
-NVIDIA RIVA TNT					.*RIVA TNT.*							0
-S3								.*S3 Graphics.*							0
-SiS								SiS.*									0
-Trident							Trident.*								0
-Tungsten Graphics				Tungsten.*								0
-XGI								XGI.*									0
+3Dfx							.*3Dfx.*							0		0
+3Dlabs							.*3Dlabs.*							0		0
+ATI 3D-Analyze					.*ATI.*3D-Analyze.*					0		0
+ATI All-in-Wonder PCI-E			.*ATI.*All-in-Wonder.*PCI-E.*		1		1
+ATI All-in-Wonder 9xxx			.*ATI.*All-in-Wonder 9.*			1		1
+ATI All-in-Wonder X800			.*ATI.*All-in-Wonder X8.*			2		1
+ATI All-in-Wonder X1800			.*ATI.*All-in-Wonder X18.*			3		1
+ATI All-in-Wonder X1900			.*ATI.*All-in-Wonder X19.*			3		1
+ATI ASUS A9xxx					.*ATI.*ASUS.*A9.*					1		1
+ATI ASUS AH24xx					.*ATI.*ASUS.*AH24.*					3		1
+ATI ASUS AH26xx					.*ATI.*ASUS.*AH26.*					3		1
+ATI ASUS AX3xx					.*ATI.*ASUS.*AX3.*					1		1
+ATI ASUS AX5xx					.*ATI.*ASUS.*AX5.*					1		1
+ATI ASUS AX8xx					.*ATI.*ASUS.*AX8.* 					2		1
+ATI ASUS EAH38xx				.*ATI.*ASUS.*EAH38.*				3		1
+ATI ASUS EAH24xx				.*ATI.*ASUS.*EAH24.*				2		1
+ATI ASUS EAH26xx				.*ATI.*ASUS.*EAH26.*				3		1
+ATI ASUS X1xxx					.*ATI.*ASUS.*X1.*					2		1
+ATI Diamond X1xxx				.*ATI.*Diamond.*X1.*				3		1
+ATI Diamond X550				.*ATI.*Diamond X550.*				1		1
+ATI FireGL 5xxx					.*ATI.*FireGL V5.*					1		0
+ATI FireGL						.*ATI.*Fire.*GL.*					0		0
+ATI FireMV						.*ATI.*FireMV.*						0		0
+ATI Generic						.*ATI.*Generic.*					0		0
+ATI Hercules 9800				.*ATI.*Hercules.*9800.*				1		1
+ATI IGP 340M					.*ATI.*IGP.*340M.*					0		0
+ATI M52							.*ATI.*M52.*						1		1
+ATI Mobility Radeon 9800		.*ATI.*Mobility.*98.*				1		1
+ATI Mobility Radeon 9700		.*ATI.*Mobility.*97.*				1		1
+ATI Mobility Radeon 9600		.*ATI.*Mobility.*96.*				0		1
+ATI Mobility Radeon X1xxx		.*ATI.*Mobility.*X1.*				1		1
+ATI Mobility Radeon X2xxx		.*ATI.*Mobility.*X2.*				1		1
+ATI Mobility Radeon X3xx		.*ATI.*Mobility.*X3.*				1		1
+ATI Mobility Radeon X6xx		.*ATI.*Mobility.*X6.*				1		1
+ATI Mobility Radeon X7xx		.*ATI.*Mobility.*X7.*				1		1
+ATI Mobility Radeon Xxxx		.*ATI.*Mobility.*X.*				1		1
+ATI Mobility Radeon				.*ATI.*Mobility.*					0		1
+ATI Radeon HD 2300				.*ATI.*Radeon HD 23.*				2		1
+ATI Radeon HD 2400				.*ATI.*Radeon HD 24.*				2		1
+ATI Radeon HD 2600				.*ATI.*Radeon HD 26.*				2		1
+ATI Radeon HD 2900				.*ATI.*Radeon HD 29.*				3		1
+ATI Radeon HD 3800				.*ATI.*Radeon HD 38.*				3		1
+ATI Radeon OpenGL				.*ATI.*Radeon OpenGL.* 				0		0
+ATI Radeon 7000					.*ATI.*Radeon 7.*					0		1
+ATI Radeon 8000					.*ATI.*Radeon 8.*					0		1
+ATI Radeon 9000					.*ATI.*Radeon 90.*					0		1
+ATI Radeon 9100					.*ATI.*Radeon 91.*					0		1
+ATI Radeon 9200					.*ATI.*Radeon 92.*					0		1
+ATI Radeon 9500					.*ATI.*Radeon 95.*					0		1
+ATI Radeon 9600					.*ATI.*Radeon 96.*					0		1
+ATI Radeon 9700					.*ATI.*Radeon 97.*					1		1
+ATI Radeon 9800					.*ATI.*Radeon 98.*					1		1
+ATI Radeon RV250				.*ATI.*RV250.*						0		1
+ATI Radeon RX700				.*ATI.*RX70.*						1		1
+ATI Radeon RX800				.*ATI.*Radeon *RX80.*				2		1
+ATI Radeon VE					.*ATI.*Radeon.*VE.*					0		0
+ATI Radeon X1000				.*ATI.*Radeon *X10.*				0		1
+ATI Radeon X1200				.*ATI.*Radeon *X12.*				1		1
+ATI Radeon X1300				.*ATI.*Radeon *X13.*				1		1
+ATI Radeon X1400				.*ATI.*Radeon X14.*					1		1
+ATI Radeon X1500				.*ATI.*Radeon X15.*					1		1
+ATI Radeon X1600				.*ATI.*Radeon X16.*					1		1
+ATI Radeon X1700				.*ATI.*Radeon X17.*					1		1
+ATI Radeon X1800				.*ATI.*Radeon X18.*					3		1
+ATI Radeon X1900				.*ATI.*Radeon X19.*					3		1
+ATI Radeon X2400				.*ATI.*Radeon X24.*					3		1
+ATI Radeon X2600				.*ATI.*Radeon X26.*					3		1
+ATI Radeon X2900				.*ATI.*Radeon X29.*					3		1
+ATI Radeon X300					.*ATI.*Radeon *X3.*					1		1
+ATI Radeon X400					.*ATI.*Radeon X4.*					1		1
+ATI Radeon X500					.*ATI.*Radeon X5.*					1		1
+ATI Radeon X600					.*ATI.*Radeon X6.*					1		1
+ATI Radeon X700					.*ATI.*Radeon X7.*					1		1
+ATI Radeon X800					.*ATI.*Radeon X8.*					2		1
+ATI Radeon X900					.*ATI.*Radeon X9.*					2		1
+ATI Radeon Xpress				.*ATI.*Radeon Xpress.*				0		0
+ATI Rage 128					.*ATI.*Rage 128.*					0		1
+ATI RV250						.*ATI.*RV250.*						0		1
+ATI RV530						.*ATI.*RV530.*						1		1
+ATI RX700						.*ATI.*RX700.*						1		1
+Intel x3100						.*Intel.*x3100						0		1
+Intel 830M						.*Intel.*830M						0		0
+Intel 845G						.*Intel.*845G						0		0
+Intel 855GM						.*Intel.*855GM						0		0
+Intel 865G						.*Intel.*865G						0		0
+Intel 900						.*Intel.*900.*900					0		0
+Intel 915GM						.*Intel.*915GM						0		0
+Intel 915G						.*Intel.*915G						0		0
+Intel 945GM						.*Intel.*945GM						0		1
+Intel 945G						.*Intel.*945G						0		1
+Intel 950						.*Intel.*950.*						0		1
+Intel 965						.*Intel.*965.*						0		1
+Intel G33						.*Intel.*G33.*						0		0
+Intel Bear Lake					.*Intel.*Bear Lake.*				0		0
+Intel Broadwater 				.*Intel.*Broadwater.*				0		0
+Intel Brookdale					.*Intel.*Brookdale.*				0		0
+Intel Montara					.*Intel.*Montara.*					0		0
+Intel Springdale				.*Intel.*Springdale.*				0		0
+Matrox							.*Matrox.*							0		0
+Mesa							.*Mesa.*							0		0
+NVIDIA G72						.*NVIDIA.*G72.*						1		1
+NVIDIA G73						.*NVIDIA.*G73.*						2		1
+NVIDIA GeForce					.*GeForce 256.*						0		0
+NVIDIA GeForce 2				.*GeForce2.*						0		1
+NVIDIA GeForce 3				.*GeForce3.*						0		1
+NVIDIA GeForce 4 Go				.*NVIDIA.*GeForce4.*Go.*			0		1
+NVIDIA GeForce 4 MX				.*NVIDIA.*GeForce4 MX.*				0		1
+NVIDIA GeForce 4 Ti				.*NVIDIA.*GeForce4 Ti.*				0		1
+NVIDIA GeForce 6100				.*NVIDIA.*GeForce 61.*				0		1
+NVIDIA GeForce 6200				.*NVIDIA.*GeForce 62.*				0		1
+NVIDIA GeForce 6500				.*NVIDIA.*GeForce 65.*				1		1
+NVIDIA GeForce 6600				.*NVIDIA.*GeForce 66.*				1		1
+NVIDIA GeForce 6700				.*NVIDIA.*GeForce 67.*				2		1
+NVIDIA GeForce 6800				.*NVIDIA.*GeForce 68.*				2		1
+NVIDIA GeForce 7000				.*NVIDIA.*GeForce 70.*				0		1
+NVIDIA GeForce 7100				.*NVIDIA.*GeForce 71.*				1		1
+NVIDIA GeForce 7200				.*NVIDIA.*GeForce 72.*				1		1
+NVIDIA GeForce 7300				.*NVIDIA.*GeForce 73.*				1		1
+NVIDIA GeForce 7500				.*NVIDIA.*GeForce 75.*				1		1
+NVIDIA GeForce 7600				.*NVIDIA.*GeForce 76.*				2		1
+NVIDIA GeForce 7800				.*NVIDIA.*GeForce 78.*				2		1
+NVIDIA GeForce 7900				.*NVIDIA.*GeForce 79.*				2		1
+NVIDIA GeForce 8300				.*NVIDIA.*GeForce 83.*				1		1
+NVIDIA GeForce 8400				.*NVIDIA.*GeForce 84.*				1		1
+NVIDIA GeForce 8500				.*NVIDIA.*GeForce 85.*				3		1
+NVIDIA GeForce 8600				.*NVIDIA.*GeForce 86.*				3		1
+NVIDIA GeForce 8700				.*NVIDIA.*GeForce 87.*				3		1
+NVIDIA GeForce 8800				.*NVIDIA.*GeForce 88.*				3		1
+NVIDIA GeForce FX 5100			.*NVIDIA.*GeForce FX 51.*			0		1
+NVIDIA GeForce FX 5200			.*NVIDIA.*GeForce FX 52.*			0		1
+NVIDIA GeForce FX 5500			.*NVIDIA.*GeForce FX 55.*			0		1
+NVIDIA GeForce FX 5600			.*NVIDIA.*GeForce FX 56.*			1		1
+NVIDIA GeForce FX 5700			.*NVIDIA.*GeForce FX 57.*			1		1
+NVIDIA GeForce FX 5800			.*NVIDIA.*GeForce FX 58.*			1		1
+NVIDIA GeForce FX 5900			.*NVIDIA.*GeForce FX 59.*			1		1
+NVIDIA GeForce FX Go5100		.*NVIDIA.*GeForce FX Go51.*			0		1
+NVIDIA GeForce FX Go5200		.*NVIDIA.*GeForce FX Go52.*			0		1
+NVIDIA GeForce FX Go5300		.*NVIDIA.*GeForce FX Go53.*			0		1
+NVIDIA GeForce FX Go5500		.*NVIDIA.*GeForce FX Go55.*			0		1
+NVIDIA GeForce FX Go5600		.*NVIDIA.*GeForce FX Go56.*			0		1
+NVIDIA GeForce FX Go5700		.*NVIDIA.*GeForce FX Go57.*			1		1
+NVIDIA GeForce FX Go5800		.*NVIDIA.*GeForce FX Go58.*			1		1
+NVIDIA GeForce FX Go5900		.*NVIDIA.*GeForce FX Go59.*			1		1
+NVIDIA GeForce Go 6100			.*NVIDIA.*GeForce Go 61.*			0		1
+NVIDIA GeForce Go 6200			.*NVIDIA.*GeForce Go 62.*			0		1
+NVIDIA GeForce Go 6500			.*NVIDIA.*GeForce Go 65.*			1		1
+NVIDIA GeForce Go 6600			.*NVIDIA.*GeForce Go 66.*			1		1
+NVIDIA GeForce Go 6700			.*NVIDIA.*GeForce Go 67.*			1		1
+NVIDIA GeForce Go 6800			.*NVIDIA.*GeForce Go 68.*			1		1
+NVIDIA GeForce Go 7200			.*NVIDIA.*GeForce Go 72.*			1		1
+NVIDIA GeForce Go 7300			.*NVIDIA.*GeForce Go 73.*			1		1
+NVIDIA GeForce Go 7400			.*NVIDIA.*GeForce Go 74.*			1		1
+NVIDIA GeForce Go 7600			.*NVIDIA.*GeForce Go 76.*			2		1
+NVIDIA GeForce Go 7700			.*NVIDIA.*GeForce Go 77.*			2		1
+NVIDIA GeForce Go 7800			.*NVIDIA.*GeForce Go 78.*			2		1
+NVIDIA GeForce Go 7900			.*NVIDIA.*GeForce Go 79.*			2		1
+NVIDIA GeForce Go 6				.*GeForce Go 6.*					1		1
+NVIDIA GeForce PCX				.*GeForce PCX.*						0		1
+NVIDIA Generic					.*NVIDIA.*Unknown.*					0		0
+NVIDIA Quadro2					.*Quadro2.*							0		0
+NVIDIA Quadro4					.*Quadro4.*							0		0
+NVIDIA Quadro DCC				.*Quadro DCC.*						0		0
+NVIDIA Quadro FX				.*Quadro FX.*						1		0
+NVIDIA Quadro NVS				.*Quadro NVS.*						0		0
+NVIDIA RIVA TNT					.*RIVA TNT.*						0		0
+S3								.*S3 Graphics.*						0		0
+SiS								SiS.*								0		0
+Trident							Trident.*							0		0
+Tungsten Graphics				Tungsten.*							0		0
+XGI								XGI.*								0		0
+VIA								VIA.*								0		0
+
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 7a225fa1632..fa94a09a50a 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -1,938 +1,956 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; secondlife setup.nsi
-;; Copyright 2004-2007, Linden Research, Inc.
-;; For info, see http://www.nullsoft.com/free/nsis/
-;;
-;; NSIS 2.22 or higher required
-;; Author: James Cook, Don Kjer, Callum Prentice
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Detect NSIS compiler version
-!define "NSIS${NSIS_VERSION}"
-!ifdef "NSISv2.02" | "NSISv2.03" | "NSISv2.04" | "NSISv2.05" | "NSISv2.06"
-    ;; before 2.07 defaulted lzma to solid (whole file)
-    SetCompressor lzma
-!else
-    ;; after 2.07 required /solid for whole file compression
-    SetCompressor /solid lzma
-!endif
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Compiler flags
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-SetOverwrite on				; overwrite files
-SetCompress auto			; compress iff saves space
-SetDatablockOptimize off	; only saves us 0.1%, not worth it
-XPStyle on                  ; add an XP manifest to the installer
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Project flags
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-%%VERSION%%
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; - language files - one for each language (or flavor thereof)
-;; (these files are in the same place as the nsi template but the python script generates a new nsi file in the 
-;; application directory so we have to add a path to these include files)
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-!include "installers\windows\lang_de.nsi"
-!include "installers\windows\lang_en-us.nsi"
-!include "installers\windows\lang_ja.nsi"
-!include "installers\windows\lang_ko.nsi"
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Tweak for different servers/builds (this placeholder is replaced by viewer_manifest.py)
-%%GRID_VARS%%
-
-Name ${INSTNAME}
-
-SubCaption 0 $(LicenseSubTitleSetup)	; override "license agreement" text
-
-BrandingText " "						; bottom of window text
-Icon res\install_icon.ico				; our custom icon
-UninstallIcon res\uninstall_icon.ico    ; our custom icon
-WindowIcon on							; show our icon in left corner
-BGGradient off							; no big background window
-CRCCheck on								; make sure CRC is OK
-InstProgressFlags smooth colored		; new colored smooth look
-ShowInstDetails nevershow				; no details, no "show" button
-SetOverwrite on							; stomp files by default
-AutoCloseWindow true					; after all files install, close window
-
-!ifdef UPDATE
-LicenseText $(LicenseDescUpdate) $(LicenseDescNext)
-!else
-LicenseText $(LicenseDescSetup) $(LicenseDescNext)
-!endif
-
-LicenseData "releasenotes.txt"
-
-InstallDir "$PROGRAMFILES\${INSTNAME}"
-InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
-!ifdef UPDATE
-DirText $(DirectoryChooseTitle) $(DirectoryChooseUpdate)
-!else
-DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
-!endif
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Variables
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Var INSTPROG
-Var INSTEXE
-Var INSTFLAGS
-Var LANGFLAGS
-Var INSTSHORTCUT
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Sections
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Section ""						; (default section)
-
-SetShellVarContext all			; install for all users (if you change this, change it in the uninstall as well)
-
-; Start with some default values.
-StrCpy $INSTFLAGS "${INSTFLAGS}"
-StrCpy $INSTFLAGS "$INSTFLAGS $LANGFLAGS"
-StrCpy $INSTPROG "${INSTNAME}"
-StrCpy $INSTEXE "${INSTEXE}"
-StrCpy $INSTSHORTCUT "${SHORTCUT}"
-
-IfSilent +2
-Goto NOT_SILENT
-  Call CheckStartupParams                 ; Figure out where, what and how to install.
-NOT_SILENT:
-Call CheckWindowsVersion		; warn if on Windows 98/ME
-Call CheckIfAdministrator		; Make sure the user can install/uninstall
-Call CheckIfAlreadyCurrent		; Make sure that we haven't already installed this version
-Call CloseSecondLife			; Make sure we're not running
-Call RemoveNSIS					; Check for old NSIS install to remove
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Don't remove cache files during a regular install, removing the inventory cache on upgrades results in lots of damage to the servers.
-;Call RemoveCacheFiles			; Installing over removes potentially corrupted
-								; VFS and cache files.
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Files
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
-%%INSTALL_FILES%%
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; If this is a silent update, we don't need to re-create these shortcuts or registry entries.
-IfSilent POST_INSTALL
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Shortcuts in start menu
-CreateDirectory	"$SMPROGRAMS\$INSTSHORTCUT"
-SetOutPath "$INSTDIR"
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
-				"$INSTDIR\$INSTEXE" "$INSTFLAGS"
-
-!ifdef MUSEUM
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum.lnk" \
-
-				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum Spanish.lnk" \
-
-				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
-!endif
-
-WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Create Trial Account.url" \
-				"InternetShortcut" "URL" \
-				"http://www.secondlife.com/registration/"
-WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \
-				"InternetShortcut" "URL" \
-				"http://www.secondlife.com/account/"
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk" \
-				"$INSTDIR\releasenotes.txt"
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Scripting Language Help.lnk" \
-				"$INSTDIR\lsl_guide.html"
-CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
-				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Other shortcuts
-SetOutPath "$INSTDIR"
-CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
-CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
-CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
-				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
-
-!ifdef MUSEUM
-CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
-
-CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
-
-CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
-
-CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
-
-!endif
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Write registry
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
-WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)"
-WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe" /P="$INSTPROG"'
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Write URL registry info
-WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
-WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" ""
-WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'
-WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'
-
-Goto WRITE_UNINST
-
-POST_INSTALL:
-; Run a post-executable script if necessary.
-Call PostInstallExe
-
-WRITE_UNINST:
-; write out uninstaller
-WriteUninstaller "$INSTDIR\uninst.exe"
-
-; end of default section
-SectionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; PostInstallExe
-; This just runs any post installation scripts.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function PostInstallExe
-push $0
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "PostInstallExe"
-  ;MessageBox MB_OK '$0'
-  ExecWait '$0'
-pop $0
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; CheckStartupParameters
-; Sets INSTFLAGS, INSTPROG, and INSTEXE.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CheckStartupParams
-push $0
-push $R0
-
-  ; Look for a registry entry with info about where to update.
-  Call GetProgramName
-  pop $R0
-  StrCpy $INSTPROG "$R0"
-  StrCpy $INSTEXE "$R0.exe"
-
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
-  ; If key doesn't exist, skip install
-  IfErrors ABORT
-  StrCpy $INSTDIR "$0"
-
-  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
-  IfErrors +2
-  StrCpy $INSTFLAGS "$0"
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
-  IfErrors +2
-  StrCpy $INSTSHORTCUT "$0"
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
-  IfErrors +2
-  StrCpy $INSTEXE "$0"
-  Goto FINISHED
-
-ABORT:
-  MessageBox MB_OK $(CheckStartupParamsMB)
-  Quit
-
-FINISHED:
-  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
-pop $R0
-pop $0
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.CheckStartupParams
-push $0
-push $R0
-
-  ; Look for a registry entry with info about where to update.
-  Call un.GetProgramName
-  pop $R0
-  StrCpy $INSTPROG "$R0"
-  StrCpy $INSTEXE "$R0.exe"
-
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
-  ; If key doesn't exist, skip install
-  IfErrors ABORT
-  StrCpy $INSTDIR "$0"
-
-  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
-  IfErrors +2
-  StrCpy $INSTFLAGS "$0"
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
-  IfErrors +2
-  StrCpy $INSTSHORTCUT "$0"
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
-  IfErrors +2
-  StrCpy $INSTEXE "$0"
-  Goto FINISHED
-
-ABORT:
-  MessageBox MB_OK $(CheckStartupParamsMB)
-  Quit
-
-FINISHED:
-  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
-pop $R0
-pop $0
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; After install completes, offer readme file
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function .onInstSuccess
-	MessageBox MB_YESNO \
-	$(InstSuccesssQuestion) /SD IDYES IDNO NoReadme
-		; Assumes SetOutPath $INSTDIR
-		Exec '"$INSTDIR\$INSTEXE" $INSTFLAGS'
-	NoReadme:
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Remove old NSIS version. Modifies no variables.
-; Does NOT delete the LindenWorld directory, or any
-; user files in that directory.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function RemoveNSIS
-  Push $0
-  ; Grab the installation directory of the old version
-  DetailPrint $(RemoveOldNSISVersion)
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
-
-  ; If key doesn't exist, skip uninstall
-  IfErrors NO_NSIS
-
-  ; Clean up legacy beta shortcuts
-  Delete "$SMPROGRAMS\Second Life Beta.lnk"
-  Delete "$DESKTOP\Second Life Beta.lnk"
-  Delete "$SMPROGRAMS\Second Life.lnk"
-  
-  ; Clean up old newview.exe file
-  Delete "$INSTDIR\newview.exe"
-
-  ; Intentionally don't delete the stuff in
-  ; Documents and Settings, so we keep the user's settings
-
-  NO_NSIS:
-  Pop $0
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Make sure we're not on Windows 98 / ME
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CheckWindowsVersion
-	DetailPrint "Checking Windows version..."
-	Call GetWindowsVersion
-	Pop $R0
-	; Just get first two characters, ignore 4.0 part of "NT 4.0"
-	StrCpy $R0 $R0 2
-	; Blacklist certain OS versions
-	StrCmp $R0 "95" win_ver_bad
-	StrCmp $R0 "98" win_ver_bad
-	StrCmp $R0 "ME" win_ver_bad
-	StrCmp $R0 "NT" win_ver_bad
-	Return
-win_ver_bad:
-	MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort
-	Return
-win_ver_abort:
-	Quit
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Make sure the user can install/uninstall
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CheckIfAdministrator
-		DetailPrint $(CheckAdministratorInstDP)
-         UserInfo::GetAccountType
-         Pop $R0
-         StrCmp $R0 "Admin" is_admin
-         MessageBox MB_OK $(CheckAdministratorInstMB)
-         Quit
-is_admin:
-         Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.CheckIfAdministrator
-		DetailPrint $(CheckAdministratorUnInstDP)
-         UserInfo::GetAccountType
-         Pop $R0
-         StrCmp $R0 "Admin" is_admin
-         MessageBox MB_OK $(CheckAdministratorUnInstMB)
-         Quit
-is_admin:
-         Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Checks to see if the current version has already been installed (according to the registry).
-; If it has, allow user to bail out of install process.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CheckIfAlreadyCurrent
-  Push $0
-	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
-    StrCmp $0 ${VERSION_LONG} 0 DONE
-	MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE
-    Quit
-
-  DONE:
-    Pop $0
-    Return
-FunctionEnd
-	
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Close the program, if running. Modifies no variables.
-; Allows user to bail out of install process.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CloseSecondLife
-  Push $0
-  FindWindow $0 "Second Life" ""
-  IntCmp $0 0 DONE
-  MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
-
-  CANCEL_INSTALL:
-    Quit
-
-  CLOSE:
-    DetailPrint $(CloseSecondLifeInstDP)
-    SendMessage $0 16 0 0
-
-  LOOP:
-	  FindWindow $0 "Second Life" ""
-	  IntCmp $0 0 DONE
-	  Sleep 500
-	  Goto LOOP
-
-  DONE:
-    Pop $0
-    Return
-FunctionEnd
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Delete files in Documents and Settings\<user>\SecondLife\cache
-; Delete files in Documents and Settings\All Users\SecondLife\cache
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;Function RemoveCacheFiles
-;
-;; Delete files in Documents and Settings\<user>\SecondLife
-;Push $0
-;Push $1
-;Push $2
-;  DetailPrint $(RemoveCacheFilesDP)
-;
-;  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
-;
-;  LOOP:
-;    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
-;    StrCmp $1 "" DONE               ; no more users
-;
-;    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
-;    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
-;
-;    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
-;    ExpandEnvStrings $2 $2
-;
-;	; When explicitly uninstalling, everything goes away
-;    RMDir /r "$2\Application Data\SecondLife\cache"
-;
-;  CONTINUE:
-;    IntOp $0 $0 + 1
-;    Goto LOOP
-;  DONE:
-;Pop $2
-;Pop $1
-;Pop $0
-;
-;; Delete files in Documents and Settings\All Users\SecondLife
-;Push $0
-;  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
-;  StrCmp $0 "" +2
-;  RMDir /r "$0\SecondLife\cache"
-;Pop $0
-;
-;; Delete filse in C:\Windows\Application Data\SecondLife
-;; If the user is running on a pre-NT system, Application Data lives here instead of
-;; in Documents and Settings.
-;RMDir /r "$WINDIR\Application Data\SecondLife\cache"
-;
-;FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Delete files in Documents and Settings\<user>\SecondLife
-; Delete files in Documents and Settings\All Users\SecondLife
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.DocumentsAndSettingsFolder
-
-; Delete files in Documents and Settings\<user>\SecondLife
-Push $0
-Push $1
-Push $2
-
-  DetailPrint "Deleting files in Documents and Settings folder"
-
-  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
-
-  LOOP:
-    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
-    StrCmp $1 "" DONE               ; no more users
-
-    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
-    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
-
-    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
-    ExpandEnvStrings $2 $2
-
-	; If uninstalling a normal install remove everything
-	; Otherwise (preview/dmz etc) just remove cache
-    StrCmp $INSTFLAGS "" RM_ALL RM_CACHE
-      RM_ALL:
-        RMDir /r "$2\Application Data\SecondLife"
-        GoTo CONTINUE
-      RM_CACHE:
-        RMDir /r "$2\Application Data\SecondLife\Cache"
-
-  CONTINUE:
-    IntOp $0 $0 + 1
-    Goto LOOP
-  DONE:
-
-Pop $2
-Pop $1
-Pop $0
-
-; Delete files in Documents and Settings\All Users\SecondLife
-Push $0
-  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
-  StrCmp $0 "" +2
-  RMDir /r "$0\SecondLife"
-Pop $0
-
-; Delete filse in C:\Windows\Application Data\SecondLife
-; If the user is running on a pre-NT system, Application Data lives here instead of
-; in Documents and Settings.
-RMDir /r "$WINDIR\Application Data\SecondLife"
-
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Close the program, if running. Modifies no variables.
-; Allows user to bail out of uninstall process.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.CloseSecondLife
-  Push $0
-  FindWindow $0 "Second Life" ""
-  IntCmp $0 0 DONE
-  MessageBox MB_OKCANCEL $(CloseSecondLifeUnInstMB) IDOK CLOSE IDCANCEL CANCEL_UNINSTALL
-
-  CANCEL_UNINSTALL:
-    Quit
-
-  CLOSE:
-    DetailPrint $(CloseSecondLifeUnInstDP)
-    SendMessage $0 16 0 0
-
-  LOOP:
-	  FindWindow $0 "Second Life" ""
-	  IntCmp $0 0 DONE
-	  Sleep 500
-	  Goto LOOP
-
-  DONE:
-    Pop $0
-    Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Delete the installed files
-;;; This deletes the uninstall executable, but it works 
-;;; because it is copied to temp directory before running
-;;;
-;;; Note:  You must list all files here, because we only
-;;; want to delete our files, not things users left in the
-;;; application directories.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.ProgramFiles
-
-;; Remove mozilla file first so recursive directory deletion doesn't get hung up
-Delete "$INSTDIR\app_settings\mozilla\components"
-
-;; This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
-%%DELETE_FILES%%
-
-;; Optional/obsolete files.  Delete won't fail if they don't exist.
-Delete "$INSTDIR\dronesettings.ini"
-Delete "$INSTDIR\message_template.msg"
-Delete "$INSTDIR\newview.pdb"
-Delete "$INSTDIR\newview.map"
-Delete "$INSTDIR\SecondLife.pdb"
-Delete "$INSTDIR\SecondLife.map"
-Delete "$INSTDIR\comm.dat"
-Delete "$INSTDIR\*.glsl"
-Delete "$INSTDIR\motions\*.lla"
-Delete "$INSTDIR\trial\*.html"
-Delete "$INSTDIR\newview.exe"
-;; Remove entire help directory
-Delete "$INSTDIR\help\Advanced\*"
-RMDir  "$INSTDIR\help\Advanced"
-Delete "$INSTDIR\help\basics\*"
-RMDir  "$INSTDIR\help\basics"
-Delete "$INSTDIR\help\Concepts\*"
-RMDir  "$INSTDIR\help\Concepts"
-Delete "$INSTDIR\help\welcome\*"
-RMDir  "$INSTDIR\help\welcome"
-Delete "$INSTDIR\help\*"
-RMDir  "$INSTDIR\help"
-
-Delete "$INSTDIR\uninst.exe"
-RMDir "$INSTDIR"
-
-IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
-
-FOLDERFOUND:
-  MessageBox MB_YESNO $(DeleteProgramFilesMB) IDNO NOFOLDER
-  RMDir /r "$INSTDIR"
-
-NOFOLDER:
-
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Uninstall settings
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-UninstallText $(UninstallTextMsg)
-ShowUninstDetails show
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Uninstall section
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Section Uninstall
-
-; Start with some default values.
-StrCpy $INSTFLAGS ""
-StrCpy $INSTPROG "${INSTNAME}"
-StrCpy $INSTEXE "${INSTEXE}"
-StrCpy $INSTSHORTCUT "${SHORTCUT}"
-Call un.CheckStartupParams              ; Figure out where, what and how to uninstall.
-Call un.CheckIfAdministrator		; Make sure the user can install/uninstall
-
-; uninstall for all users (if you change this, change it in the install as well)
-SetShellVarContext all			
-
-; Make sure we're not running
-Call un.CloseSecondLife
-
-; Clean up registry keys (these should all be !defines somewhere)
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
-DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
-DeleteRegKey HKEY_LOCAL_MACHINE "Software\Linden Research, Inc.\Installer Language" 
-
-; Clean up shortcuts
-Delete "$SMPROGRAMS\$INSTSHORTCUT\*.*"
-RMDir  "$SMPROGRAMS\$INSTSHORTCUT"
-
-Delete "$DESKTOP\$INSTSHORTCUT.lnk"
-Delete "$INSTDIR\$INSTSHORTCUT.lnk"
-Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk"
-
-; Clean up cache and log files.
-; Leave them in-place for non AGNI installs.
-
-!ifdef UNINSTALL_SETTINGS
-Call un.DocumentsAndSettingsFolder
-!endif
-
-Call un.ProgramFiles
-
-SectionEnd 				; end of uninstall section
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; (From the NSIS wiki, DK)
-; GetParameterValue
-;
-; Usage:
-; !insertmacro GetParameterValue "/L=" "1033"
-; pop $R0
-;
-; Returns on top of stack
-;
-; Example command lines:
-; foo.exe /S /L=1033 /D=C:\Program Files\Foo
-; or:
-; foo.exe /S "/L=1033" /D="C:\Program Files\Foo"
-; gpv "/L=" "1033"
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- !macro GetParameterValue SWITCH DEFAULT
-   Push $0
-   Push $1
-   Push $2
-   Push $3
-   Push $4
-
- ;$CMDLINE='"My Setup\Setup.exe" /L=1033 /S'
-   Push "$CMDLINE"
-   Push '${SWITCH}"'
-   !insertmacro StrStr
-   Pop $0
-   StrCmp "$0" "" gpv_notquoted
- ;$0='/L="1033" /S'
-   StrLen $2 "$0"
-   Strlen $1 "${SWITCH}"
-   IntOp $1 $1 + 1
-   StrCpy $0 "$0" $2 $1
- ;$0='1033" /S'
-   Push "$0"
-   Push '"'
-   !insertmacro StrStr
-   Pop $1
-   StrLen $2 "$0"
-   StrLen $3 "$1"
-   IntOp $4 $2 - $3
-   StrCpy $0 $0 $4 0
-   Goto gpv_done
-
-   gpv_notquoted:
-   Push "$CMDLINE"
-   Push "${SWITCH}"
-   !insertmacro StrStr
-   Pop $0
-   StrCmp "$0" "" gpv_done
- ;$0='/L="1033" /S'
-   StrLen $2 "$0"
-   Strlen $1 "${SWITCH}"
-   StrCpy $0 "$0" $2 $1
- ;$0=1033 /S'
-   Push "$0"
-   Push ' '
-   !insertmacro StrStr
-   Pop $1
-   StrLen $2 "$0"
-   StrLen $3 "$1"
-   IntOp $4 $2 - $3
-   StrCpy $0 $0 $4 0
-   Goto gpv_done
-
-   gpv_done:
-   StrCmp "$0" "" 0 +2
-   StrCpy $0 "${DEFAULT}"
-
-   Pop $4
-   Pop $3
-   Pop $2
-   Pop $1
-   Exch $0
- !macroend
-
-; And I had to modify StrStr a tiny bit.
-; Possible upgrade switch the goto's to use ${__LINE__}
-
-!macro STRSTR
-  Exch $R1 ; st=haystack,old$R1, $R1=needle
-  Exch    ; st=old$R1,haystack
-  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
-  Push $R3
-  Push $R4
-  Push $R5
-  StrLen $R3 $R1
-  StrCpy $R4 0
-  ; $R1=needle
-  ; $R2=haystack
-  ; $R3=len(needle)
-  ; $R4=cnt
-  ; $R5=tmp
- ;  loop;
-    StrCpy $R5 $R2 $R3 $R4
-    StrCmp $R5 $R1 +4
-    StrCmp $R5 "" +3
-    IntOp $R4 $R4 + 1
-    Goto -4
- ;  done;
-  StrCpy $R1 $R2 "" $R4
-  Pop $R5
-  Pop $R4
-  Pop $R3
-  Pop $R2
-  Exch $R1
-!macroend
-
-Function GetProgramName
-  !insertmacro GetParameterValue "/P=" "SecondLife"
-FunctionEnd
-
-Function un.GetProgramName
-  !insertmacro GetParameterValue "/P=" "SecondLife"
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; (From the NSIS documentation, JC)
-; GetWindowsVersion
-;
-; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
-; Updated by Joost Verburg
-;
-; Returns on top of stack
-;
-; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003)
-; or
-; '' (Unknown Windows Version)
-;
-; Usage:
-;   Call GetWindowsVersion
-;   Pop $R0
-;   ; at this point $R0 is "NT 4.0" or whatnot
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function GetWindowsVersion
- 
-   Push $R0
-   Push $R1
- 
-   ReadRegStr $R0 HKLM \
-   "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
-
-   IfErrors 0 lbl_winnt
-   
-   ; we are not NT
-   ReadRegStr $R0 HKLM \
-   "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber
- 
-   StrCpy $R1 $R0 1
-   StrCmp $R1 '4' 0 lbl_error
- 
-   StrCpy $R1 $R0 3
- 
-   StrCmp $R1 '4.0' lbl_win32_95
-   StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98
- 
-   lbl_win32_95:
-     StrCpy $R0 '95'
-   Goto lbl_done
- 
-   lbl_win32_98:
-     StrCpy $R0 '98'
-   Goto lbl_done
- 
-   lbl_win32_ME:
-     StrCpy $R0 'ME'
-   Goto lbl_done
- 
-   lbl_winnt:
- 
-   StrCpy $R1 $R0 1
- 
-   StrCmp $R1 '3' lbl_winnt_x
-   StrCmp $R1 '4' lbl_winnt_x
- 
-   StrCpy $R1 $R0 3
- 
-   StrCmp $R1 '5.0' lbl_winnt_2000
-   StrCmp $R1 '5.1' lbl_winnt_XP
-   StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error
- 
-   lbl_winnt_x:
-     StrCpy $R0 "NT $R0" 6
-   Goto lbl_done
- 
-   lbl_winnt_2000:
-     Strcpy $R0 '2000'
-   Goto lbl_done
- 
-   lbl_winnt_XP:
-     Strcpy $R0 'XP'
-   Goto lbl_done
- 
-   lbl_winnt_2003:
-     Strcpy $R0 '2003'
-   Goto lbl_done
- 
-   lbl_error:
-     Strcpy $R0 ''
-   lbl_done:
- 
-   Pop $R1
-   Exch $R0
- 
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;  Note: to add new languages, add a language file include to the list 
-;;  at the top of this file, add an entry to the menu and then add an 
-;;  entry to the language ID selector below
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function .onInit
-
-	; read the language from registry (ok if not there) and set langauge menu
-	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
-	StrCpy $LANGUAGE $0
-
-	Push ""
-	Push ${LANG_ENGLISH}
-	Push English
-	Push ${LANG_GERMAN}
-	Push German
-	Push ${LANG_JAPANESE}
-	Push Japanese
-	Push ${LANG_KOREAN}
-	Push Korean
-	Push A ; A means auto count languages for the auto count to work the first empty push (Push "") must remain
-	LangDLL::LangDialog "Installer Language" "Please select the language of the installer"
-	Pop $LANGUAGE
-	StrCmp $LANGUAGE "cancel" 0 +2
-		Abort
-
-	; save language in registry		
-	WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE
-	
-	; generate language ID that will be used as a command line arg	
-	StrCmp $LANGUAGE "1042" 0 +3
-	StrCpy $LANGFLAGS " -set SystemLanguage ko"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1041" 0 +3
-	StrCpy $LANGFLAGS " -set SystemLanguage ja"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1031" 0 +3
-	StrCpy $LANGFLAGS " -set SystemLanguage de"
-	Goto EndOfFunc
-
-	StrCmp $LANGUAGE "1033" 0 +3
-	StrCpy $LANGFLAGS " -set SystemLanguage en-us"
-	Goto EndOfFunc
-	
-	EndOfFunc:
-
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.onInit
-
-	; read language from registry and set for ininstaller
-	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
-	StrCpy $LANGUAGE $0
-
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EOF  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\ No newline at end of file
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; secondlife setup.nsi
+;; Copyright 2004-2007, Linden Research, Inc.
+;; For info, see http://www.nullsoft.com/free/nsis/
+;;
+;; NSIS 2.22 or higher required
+;; Author: James Cook, Don Kjer, Callum Prentice
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Detect NSIS compiler version
+!define "NSIS${NSIS_VERSION}"
+!ifdef "NSISv2.02" | "NSISv2.03" | "NSISv2.04" | "NSISv2.05" | "NSISv2.06"
+    ;; before 2.07 defaulted lzma to solid (whole file)
+    SetCompressor lzma
+!else
+    ;; after 2.07 required /solid for whole file compression
+    SetCompressor /solid lzma
+!endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Compiler flags
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+SetOverwrite on				; overwrite files
+SetCompress auto			; compress iff saves space
+SetDatablockOptimize off	; only saves us 0.1%, not worth it
+XPStyle on                  ; add an XP manifest to the installer
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Project flags
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%%VERSION%%
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; - language files - one for each language (or flavor thereof)
+;; (these files are in the same place as the nsi template but the python script generates a new nsi file in the 
+;; application directory so we have to add a path to these include files)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+!include "installers\windows\lang_de.nsi"
+!include "installers\windows\lang_en-us.nsi"
+!include "installers\windows\lang_ja.nsi"
+!include "installers\windows\lang_ko.nsi"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tweak for different servers/builds (this placeholder is replaced by viewer_manifest.py)
+%%GRID_VARS%%
+
+Name ${INSTNAME}
+
+SubCaption 0 $(LicenseSubTitleSetup)	; override "license agreement" text
+
+BrandingText " "						; bottom of window text
+Icon res\install_icon.ico				; our custom icon
+UninstallIcon res\uninstall_icon.ico    ; our custom icon
+WindowIcon on							; show our icon in left corner
+BGGradient off							; no big background window
+CRCCheck on								; make sure CRC is OK
+InstProgressFlags smooth colored		; new colored smooth look
+ShowInstDetails nevershow				; no details, no "show" button
+SetOverwrite on							; stomp files by default
+AutoCloseWindow true					; after all files install, close window
+
+!ifdef UPDATE
+LicenseText $(LicenseDescUpdate) $(LicenseDescNext)
+!else
+LicenseText $(LicenseDescSetup) $(LicenseDescNext)
+!endif
+
+LicenseData "releasenotes.txt"
+
+InstallDir "$PROGRAMFILES\${INSTNAME}"
+InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
+!ifdef UPDATE
+DirText $(DirectoryChooseTitle) $(DirectoryChooseUpdate)
+!else
+DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
+!endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Variables
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Var INSTPROG
+Var INSTEXE
+Var INSTFLAGS
+Var LANGFLAGS
+Var INSTSHORTCUT
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Sections
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Section ""						; (default section)
+
+SetShellVarContext all			; install for all users (if you change this, change it in the uninstall as well)
+
+; Start with some default values.
+StrCpy $INSTFLAGS "${INSTFLAGS}"
+StrCpy $INSTFLAGS "$INSTFLAGS $LANGFLAGS"
+StrCpy $INSTPROG "${INSTNAME}"
+StrCpy $INSTEXE "${INSTEXE}"
+StrCpy $INSTSHORTCUT "${SHORTCUT}"
+
+IfSilent +2
+Goto NOT_SILENT
+  Call CheckStartupParams                 ; Figure out where, what and how to install.
+NOT_SILENT:
+Call CheckWindowsVersion		; warn if on Windows 98/ME
+Call CheckIfAdministrator		; Make sure the user can install/uninstall
+Call CheckIfAlreadyCurrent		; Make sure that we haven't already installed this version
+Call CloseSecondLife			; Make sure we're not running
+Call RemoveNSIS					; Check for old NSIS install to remove
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Don't remove cache files during a regular install, removing the inventory cache on upgrades results in lots of damage to the servers.
+;Call RemoveCacheFiles			; Installing over removes potentially corrupted
+								; VFS and cache files.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Need to clean out shader files from previous installs to fix DEV-5663
+Call RemoveOldShaders
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Files
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
+%%INSTALL_FILES%%
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; If this is a silent update, we don't need to re-create these shortcuts or registry entries.
+IfSilent POST_INSTALL
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Shortcuts in start menu
+CreateDirectory	"$SMPROGRAMS\$INSTSHORTCUT"
+SetOutPath "$INSTDIR"
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
+				"$INSTDIR\$INSTEXE" "$INSTFLAGS"
+
+!ifdef MUSEUM
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum.lnk" \
+
+				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT Museum Spanish.lnk" \
+
+				"$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
+!endif
+
+WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Create Trial Account.url" \
+				"InternetShortcut" "URL" \
+				"http://www.secondlife.com/registration/"
+WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \
+				"InternetShortcut" "URL" \
+				"http://www.secondlife.com/account/"
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk" \
+				"$INSTDIR\releasenotes.txt"
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\SL Scripting Language Help.lnk" \
+				"$INSTDIR\lsl_guide.html"
+CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
+				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Other shortcuts
+SetOutPath "$INSTDIR"
+CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
+CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS"
+CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
+				'"$INSTDIR\uninst.exe"' '/P="$INSTPROG"'
+
+!ifdef MUSEUM
+CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
+
+CreateShortCut "$DESKTOP\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
+
+CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple"
+
+CreateShortCut "$INSTDIR\$INSTSHORTCUT Museum Spanish.lnk" "$INSTDIR\$INSTEXE" "$INSTFLAGS -simple -spanish"
+
+!endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Write registry
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
+WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
+WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)"
+WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe" /P="$INSTPROG"'
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Write URL registry info
+WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life"
+WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" ""
+WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"'
+WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"'
+
+Goto WRITE_UNINST
+
+POST_INSTALL:
+; Run a post-executable script if necessary.
+Call PostInstallExe
+
+WRITE_UNINST:
+; write out uninstaller
+WriteUninstaller "$INSTDIR\uninst.exe"
+
+; end of default section
+SectionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; PostInstallExe
+; This just runs any post installation scripts.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function PostInstallExe
+push $0
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "PostInstallExe"
+  ;MessageBox MB_OK '$0'
+  ExecWait '$0'
+pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; CheckStartupParameters
+; Sets INSTFLAGS, INSTPROG, and INSTEXE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CheckStartupParams
+push $0
+push $R0
+
+  ; Look for a registry entry with info about where to update.
+  Call GetProgramName
+  pop $R0
+  StrCpy $INSTPROG "$R0"
+  StrCpy $INSTEXE "$R0.exe"
+
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
+  ; If key doesn't exist, skip install
+  IfErrors ABORT
+  StrCpy $INSTDIR "$0"
+
+  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
+  IfErrors +2
+  StrCpy $INSTFLAGS "$0"
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
+  IfErrors +2
+  StrCpy $INSTSHORTCUT "$0"
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
+  IfErrors +2
+  StrCpy $INSTEXE "$0"
+  Goto FINISHED
+
+ABORT:
+  MessageBox MB_OK $(CheckStartupParamsMB)
+  Quit
+
+FINISHED:
+  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
+pop $R0
+pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.CheckStartupParams
+push $0
+push $R0
+
+  ; Look for a registry entry with info about where to update.
+  Call un.GetProgramName
+  pop $R0
+  StrCpy $INSTPROG "$R0"
+  StrCpy $INSTEXE "$R0.exe"
+
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
+  ; If key doesn't exist, skip install
+  IfErrors ABORT
+  StrCpy $INSTDIR "$0"
+
+  ; We now have a directory to install to.  Get the startup parameters and shortcut as well.
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags"
+  IfErrors +2
+  StrCpy $INSTFLAGS "$0"
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut"
+  IfErrors +2
+  StrCpy $INSTSHORTCUT "$0"
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe"
+  IfErrors +2
+  StrCpy $INSTEXE "$0"
+  Goto FINISHED
+
+ABORT:
+  MessageBox MB_OK $(CheckStartupParamsMB)
+  Quit
+
+FINISHED:
+  ;MessageBox MB_OK "INSTPROG: $INSTPROG, INSTEXE: $INSTEXE, INSTFLAGS: $INSTFLAGS"
+pop $R0
+pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; After install completes, offer readme file
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function .onInstSuccess
+	MessageBox MB_YESNO \
+	$(InstSuccesssQuestion) /SD IDYES IDNO NoReadme
+		; Assumes SetOutPath $INSTDIR
+		Exec '"$INSTDIR\$INSTEXE" $INSTFLAGS'
+	NoReadme:
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Remove old NSIS version. Modifies no variables.
+; Does NOT delete the LindenWorld directory, or any
+; user files in that directory.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function RemoveNSIS
+  Push $0
+  ; Grab the installation directory of the old version
+  DetailPrint $(RemoveOldNSISVersion)
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" ""
+
+  ; If key doesn't exist, skip uninstall
+  IfErrors NO_NSIS
+
+  ; Clean up legacy beta shortcuts
+  Delete "$SMPROGRAMS\Second Life Beta.lnk"
+  Delete "$DESKTOP\Second Life Beta.lnk"
+  Delete "$SMPROGRAMS\Second Life.lnk"
+  
+  ; Clean up old newview.exe file
+  Delete "$INSTDIR\newview.exe"
+
+  ; Intentionally don't delete the stuff in
+  ; Documents and Settings, so we keep the user's settings
+
+  NO_NSIS:
+  Pop $0
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Make sure we're not on Windows 98 / ME
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CheckWindowsVersion
+	DetailPrint "Checking Windows version..."
+	Call GetWindowsVersion
+	Pop $R0
+	; Just get first two characters, ignore 4.0 part of "NT 4.0"
+	StrCpy $R0 $R0 2
+	; Blacklist certain OS versions
+	StrCmp $R0 "95" win_ver_bad
+	StrCmp $R0 "98" win_ver_bad
+	StrCmp $R0 "ME" win_ver_bad
+	StrCmp $R0 "NT" win_ver_bad
+	Return
+win_ver_bad:
+	MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort
+	Return
+win_ver_abort:
+	Quit
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Make sure the user can install/uninstall
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CheckIfAdministrator
+		DetailPrint $(CheckAdministratorInstDP)
+         UserInfo::GetAccountType
+         Pop $R0
+         StrCmp $R0 "Admin" is_admin
+         MessageBox MB_OK $(CheckAdministratorInstMB)
+         Quit
+is_admin:
+         Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.CheckIfAdministrator
+		DetailPrint $(CheckAdministratorUnInstDP)
+         UserInfo::GetAccountType
+         Pop $R0
+         StrCmp $R0 "Admin" is_admin
+         MessageBox MB_OK $(CheckAdministratorUnInstMB)
+         Quit
+is_admin:
+         Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Checks to see if the current version has already been installed (according to the registry).
+; If it has, allow user to bail out of install process.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CheckIfAlreadyCurrent
+  Push $0
+	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
+    StrCmp $0 ${VERSION_LONG} 0 DONE
+	MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE
+    Quit
+
+  DONE:
+    Pop $0
+    Return
+FunctionEnd
+	
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Close the program, if running. Modifies no variables.
+; Allows user to bail out of install process.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CloseSecondLife
+  Push $0
+  FindWindow $0 "Second Life" ""
+  IntCmp $0 0 DONE
+  MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
+
+  CANCEL_INSTALL:
+    Quit
+
+  CLOSE:
+    DetailPrint $(CloseSecondLifeInstDP)
+    SendMessage $0 16 0 0
+
+  LOOP:
+	  FindWindow $0 "Second Life" ""
+	  IntCmp $0 0 DONE
+	  Sleep 500
+	  Goto LOOP
+
+  DONE:
+    Pop $0
+    Return
+FunctionEnd
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Delete files in Documents and Settings\<user>\SecondLife\cache
+; Delete files in Documents and Settings\All Users\SecondLife\cache
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;Function RemoveCacheFiles
+;
+;; Delete files in Documents and Settings\<user>\SecondLife
+;Push $0
+;Push $1
+;Push $2
+;  DetailPrint $(RemoveCacheFilesDP)
+;
+;  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
+;
+;  LOOP:
+;    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
+;    StrCmp $1 "" DONE               ; no more users
+;
+;    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
+;    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
+;
+;    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
+;    ExpandEnvStrings $2 $2
+;
+;	; When explicitly uninstalling, everything goes away
+;    RMDir /r "$2\Application Data\SecondLife\cache"
+;
+;  CONTINUE:
+;    IntOp $0 $0 + 1
+;    Goto LOOP
+;  DONE:
+;Pop $2
+;Pop $1
+;Pop $0
+;
+;; Delete files in Documents and Settings\All Users\SecondLife
+;Push $0
+;  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
+;  StrCmp $0 "" +2
+;  RMDir /r "$0\SecondLife\cache"
+;Pop $0
+;
+;; Delete filse in C:\Windows\Application Data\SecondLife
+;; If the user is running on a pre-NT system, Application Data lives here instead of
+;; in Documents and Settings.
+;RMDir /r "$WINDIR\Application Data\SecondLife\cache"
+;
+;FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Delete the installed shader files
+;;; Since shaders are in active development, we'll likely need to shuffle them
+;;; around a bit from build to build.  This ensures that shaders that we move
+;;; or rename in the dev tree don't get left behind in the install.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function RemoveOldShaders
+
+;; Remove old shader files first so fallbacks will work. see DEV-5663
+RMDir /r "$INSTDIR\app_settings\shaders\*"
+
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Delete files in Documents and Settings\<user>\SecondLife
+; Delete files in Documents and Settings\All Users\SecondLife
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.DocumentsAndSettingsFolder
+
+; Delete files in Documents and Settings\<user>\SecondLife
+Push $0
+Push $1
+Push $2
+
+  DetailPrint "Deleting files in Documents and Settings folder"
+
+  StrCpy $0 0 ; Index number used to iterate via EnumRegKey
+
+  LOOP:
+    EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0
+    StrCmp $1 "" DONE               ; no more users
+
+    ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" 
+    StrCmp $2 "" CONTINUE 0         ; "ProfileImagePath" value is missing
+
+    ; Required since ProfileImagePath is of type REG_EXPAND_SZ
+    ExpandEnvStrings $2 $2
+
+	; If uninstalling a normal install remove everything
+	; Otherwise (preview/dmz etc) just remove cache
+    StrCmp $INSTFLAGS "" RM_ALL RM_CACHE
+      RM_ALL:
+        RMDir /r "$2\Application Data\SecondLife"
+        GoTo CONTINUE
+      RM_CACHE:
+        RMDir /r "$2\Application Data\SecondLife\Cache"
+        Delete "$2\Application Data\SecondLife\user_settings\settings_windlight.xml"
+
+  CONTINUE:
+    IntOp $0 $0 + 1
+    Goto LOOP
+  DONE:
+
+Pop $2
+Pop $1
+Pop $0
+
+; Delete files in Documents and Settings\All Users\SecondLife
+Push $0
+  ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData"
+  StrCmp $0 "" +2
+  RMDir /r "$0\SecondLife"
+Pop $0
+
+; Delete filse in C:\Windows\Application Data\SecondLife
+; If the user is running on a pre-NT system, Application Data lives here instead of
+; in Documents and Settings.
+RMDir /r "$WINDIR\Application Data\SecondLife"
+
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Close the program, if running. Modifies no variables.
+; Allows user to bail out of uninstall process.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.CloseSecondLife
+  Push $0
+  FindWindow $0 "Second Life" ""
+  IntCmp $0 0 DONE
+  MessageBox MB_OKCANCEL $(CloseSecondLifeUnInstMB) IDOK CLOSE IDCANCEL CANCEL_UNINSTALL
+
+  CANCEL_UNINSTALL:
+    Quit
+
+  CLOSE:
+    DetailPrint $(CloseSecondLifeUnInstDP)
+    SendMessage $0 16 0 0
+
+  LOOP:
+	  FindWindow $0 "Second Life" ""
+	  IntCmp $0 0 DONE
+	  Sleep 500
+	  Goto LOOP
+
+  DONE:
+    Pop $0
+    Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Delete the installed files
+;;; This deletes the uninstall executable, but it works 
+;;; because it is copied to temp directory before running
+;;;
+;;; Note:  You must list all files here, because we only
+;;; want to delete our files, not things users left in the
+;;; application directories.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.ProgramFiles
+
+;; Remove mozilla file first so recursive directory deletion doesn't get hung up
+Delete "$INSTDIR\app_settings\mozilla\components"
+
+;; This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
+%%DELETE_FILES%%
+
+;; Optional/obsolete files.  Delete won't fail if they don't exist.
+Delete "$INSTDIR\dronesettings.ini"
+Delete "$INSTDIR\message_template.msg"
+Delete "$INSTDIR\newview.pdb"
+Delete "$INSTDIR\newview.map"
+Delete "$INSTDIR\SecondLife.pdb"
+Delete "$INSTDIR\SecondLife.map"
+Delete "$INSTDIR\comm.dat"
+Delete "$INSTDIR\*.glsl"
+Delete "$INSTDIR\motions\*.lla"
+Delete "$INSTDIR\trial\*.html"
+Delete "$INSTDIR\newview.exe"
+;; Remove entire help directory
+Delete "$INSTDIR\help\Advanced\*"
+RMDir  "$INSTDIR\help\Advanced"
+Delete "$INSTDIR\help\basics\*"
+RMDir  "$INSTDIR\help\basics"
+Delete "$INSTDIR\help\Concepts\*"
+RMDir  "$INSTDIR\help\Concepts"
+Delete "$INSTDIR\help\welcome\*"
+RMDir  "$INSTDIR\help\welcome"
+Delete "$INSTDIR\help\*"
+RMDir  "$INSTDIR\help"
+
+Delete "$INSTDIR\uninst.exe"
+RMDir "$INSTDIR"
+
+IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
+
+FOLDERFOUND:
+  MessageBox MB_YESNO $(DeleteProgramFilesMB) IDNO NOFOLDER
+  RMDir /r "$INSTDIR"
+
+NOFOLDER:
+
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Uninstall settings
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+UninstallText $(UninstallTextMsg)
+ShowUninstDetails show
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Uninstall section
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Section Uninstall
+
+; Start with some default values.
+StrCpy $INSTFLAGS ""
+StrCpy $INSTPROG "${INSTNAME}"
+StrCpy $INSTEXE "${INSTEXE}"
+StrCpy $INSTSHORTCUT "${SHORTCUT}"
+Call un.CheckStartupParams              ; Figure out where, what and how to uninstall.
+Call un.CheckIfAdministrator		; Make sure the user can install/uninstall
+
+; uninstall for all users (if you change this, change it in the install as well)
+SetShellVarContext all			
+
+; Make sure we're not running
+Call un.CloseSecondLife
+
+; Clean up registry keys (these should all be !defines somewhere)
+DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
+DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
+DeleteRegKey HKEY_LOCAL_MACHINE "Software\Linden Research, Inc.\Installer Language" 
+
+; Clean up shortcuts
+Delete "$SMPROGRAMS\$INSTSHORTCUT\*.*"
+RMDir  "$SMPROGRAMS\$INSTSHORTCUT"
+
+Delete "$DESKTOP\$INSTSHORTCUT.lnk"
+Delete "$INSTDIR\$INSTSHORTCUT.lnk"
+Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk"
+
+; Clean up cache and log files.
+; Leave them in-place for non AGNI installs.
+
+!ifdef UNINSTALL_SETTINGS
+Call un.DocumentsAndSettingsFolder
+!endif
+
+Call un.ProgramFiles
+
+SectionEnd 				; end of uninstall section
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; (From the NSIS wiki, DK)
+; GetParameterValue
+;
+; Usage:
+; !insertmacro GetParameterValue "/L=" "1033"
+; pop $R0
+;
+; Returns on top of stack
+;
+; Example command lines:
+; foo.exe /S /L=1033 /D=C:\Program Files\Foo
+; or:
+; foo.exe /S "/L=1033" /D="C:\Program Files\Foo"
+; gpv "/L=" "1033"
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ !macro GetParameterValue SWITCH DEFAULT
+   Push $0
+   Push $1
+   Push $2
+   Push $3
+   Push $4
+
+ ;$CMDLINE='"My Setup\Setup.exe" /L=1033 /S'
+   Push "$CMDLINE"
+   Push '${SWITCH}"'
+   !insertmacro StrStr
+   Pop $0
+   StrCmp "$0" "" gpv_notquoted
+ ;$0='/L="1033" /S'
+   StrLen $2 "$0"
+   Strlen $1 "${SWITCH}"
+   IntOp $1 $1 + 1
+   StrCpy $0 "$0" $2 $1
+ ;$0='1033" /S'
+   Push "$0"
+   Push '"'
+   !insertmacro StrStr
+   Pop $1
+   StrLen $2 "$0"
+   StrLen $3 "$1"
+   IntOp $4 $2 - $3
+   StrCpy $0 $0 $4 0
+   Goto gpv_done
+
+   gpv_notquoted:
+   Push "$CMDLINE"
+   Push "${SWITCH}"
+   !insertmacro StrStr
+   Pop $0
+   StrCmp "$0" "" gpv_done
+ ;$0='/L="1033" /S'
+   StrLen $2 "$0"
+   Strlen $1 "${SWITCH}"
+   StrCpy $0 "$0" $2 $1
+ ;$0=1033 /S'
+   Push "$0"
+   Push ' '
+   !insertmacro StrStr
+   Pop $1
+   StrLen $2 "$0"
+   StrLen $3 "$1"
+   IntOp $4 $2 - $3
+   StrCpy $0 $0 $4 0
+   Goto gpv_done
+
+   gpv_done:
+   StrCmp "$0" "" 0 +2
+   StrCpy $0 "${DEFAULT}"
+
+   Pop $4
+   Pop $3
+   Pop $2
+   Pop $1
+   Exch $0
+ !macroend
+
+; And I had to modify StrStr a tiny bit.
+; Possible upgrade switch the goto's to use ${__LINE__}
+
+!macro STRSTR
+  Exch $R1 ; st=haystack,old$R1, $R1=needle
+  Exch    ; st=old$R1,haystack
+  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+  Push $R3
+  Push $R4
+  Push $R5
+  StrLen $R3 $R1
+  StrCpy $R4 0
+  ; $R1=needle
+  ; $R2=haystack
+  ; $R3=len(needle)
+  ; $R4=cnt
+  ; $R5=tmp
+ ;  loop;
+    StrCpy $R5 $R2 $R3 $R4
+    StrCmp $R5 $R1 +4
+    StrCmp $R5 "" +3
+    IntOp $R4 $R4 + 1
+    Goto -4
+ ;  done;
+  StrCpy $R1 $R2 "" $R4
+  Pop $R5
+  Pop $R4
+  Pop $R3
+  Pop $R2
+  Exch $R1
+!macroend
+
+Function GetProgramName
+  !insertmacro GetParameterValue "/P=" "SecondLife"
+FunctionEnd
+
+Function un.GetProgramName
+  !insertmacro GetParameterValue "/P=" "SecondLife"
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; (From the NSIS documentation, JC)
+; GetWindowsVersion
+;
+; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
+; Updated by Joost Verburg
+;
+; Returns on top of stack
+;
+; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003)
+; or
+; '' (Unknown Windows Version)
+;
+; Usage:
+;   Call GetWindowsVersion
+;   Pop $R0
+;   ; at this point $R0 is "NT 4.0" or whatnot
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function GetWindowsVersion
+ 
+   Push $R0
+   Push $R1
+ 
+   ReadRegStr $R0 HKLM \
+   "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+
+   IfErrors 0 lbl_winnt
+   
+   ; we are not NT
+   ReadRegStr $R0 HKLM \
+   "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber
+ 
+   StrCpy $R1 $R0 1
+   StrCmp $R1 '4' 0 lbl_error
+ 
+   StrCpy $R1 $R0 3
+ 
+   StrCmp $R1 '4.0' lbl_win32_95
+   StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98
+ 
+   lbl_win32_95:
+     StrCpy $R0 '95'
+   Goto lbl_done
+ 
+   lbl_win32_98:
+     StrCpy $R0 '98'
+   Goto lbl_done
+ 
+   lbl_win32_ME:
+     StrCpy $R0 'ME'
+   Goto lbl_done
+ 
+   lbl_winnt:
+ 
+   StrCpy $R1 $R0 1
+ 
+   StrCmp $R1 '3' lbl_winnt_x
+   StrCmp $R1 '4' lbl_winnt_x
+ 
+   StrCpy $R1 $R0 3
+ 
+   StrCmp $R1 '5.0' lbl_winnt_2000
+   StrCmp $R1 '5.1' lbl_winnt_XP
+   StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error
+ 
+   lbl_winnt_x:
+     StrCpy $R0 "NT $R0" 6
+   Goto lbl_done
+ 
+   lbl_winnt_2000:
+     Strcpy $R0 '2000'
+   Goto lbl_done
+ 
+   lbl_winnt_XP:
+     Strcpy $R0 'XP'
+   Goto lbl_done
+ 
+   lbl_winnt_2003:
+     Strcpy $R0 '2003'
+   Goto lbl_done
+ 
+   lbl_error:
+     Strcpy $R0 ''
+   lbl_done:
+ 
+   Pop $R1
+   Exch $R0
+ 
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;  Note: to add new languages, add a language file include to the list 
+;;  at the top of this file, add an entry to the menu and then add an 
+;;  entry to the language ID selector below
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function .onInit
+
+	; read the language from registry (ok if not there) and set langauge menu
+	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
+	StrCpy $LANGUAGE $0
+
+	Push ""
+	Push ${LANG_ENGLISH}
+	Push English
+	Push ${LANG_GERMAN}
+	Push German
+	Push ${LANG_JAPANESE}
+	Push Japanese
+	Push ${LANG_KOREAN}
+	Push Korean
+	Push A ; A means auto count languages for the auto count to work the first empty push (Push "") must remain
+	LangDLL::LangDialog "Installer Language" "Please select the language of the installer"
+	Pop $LANGUAGE
+	StrCmp $LANGUAGE "cancel" 0 +2
+		Abort
+
+	; save language in registry		
+	WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE
+	
+	; generate language ID that will be used as a command line arg	
+	StrCmp $LANGUAGE "1042" 0 +3
+	StrCpy $LANGFLAGS " -set SystemLanguage ko"
+	Goto EndOfFunc
+
+	StrCmp $LANGUAGE "1041" 0 +3
+	StrCpy $LANGFLAGS " -set SystemLanguage ja"
+	Goto EndOfFunc
+
+	StrCmp $LANGUAGE "1031" 0 +3
+	StrCpy $LANGFLAGS " -set SystemLanguage de"
+	Goto EndOfFunc
+
+	StrCmp $LANGUAGE "1033" 0 +3
+	StrCpy $LANGFLAGS " -set SystemLanguage en-us"
+	Goto EndOfFunc
+	
+	EndOfFunc:
+
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.onInit
+
+	; read language from registry and set for ininstaller
+	ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
+	StrCpy $LANGUAGE $0
+
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EOF  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/indra/newview/licenses-linux.txt b/indra/newview/licenses-linux.txt
index 795b7cc3dfd..b43c402e643 100644
--- a/indra/newview/licenses-linux.txt
+++ b/indra/newview/licenses-linux.txt
@@ -148,6 +148,49 @@ BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+=========================
+glh OpenGL helper library
+=========================
+
+glh - is a platform-indepenedent C++ OpenGL helper library
+
+
+Copyright (c) 2000 Cass Everitt
+    Copyright (c) 2000 NVIDIA Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+    without modification, are permitted provided that the following
+    conditions are met:
+
+ * Redistributions of source code must retain the above
+       copyright notice, this list of conditions and the following
+       disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials
+       provided with the distribution.
+
+ * The names of contributors to this software may not be used
+       to endorse or promote products derived from this software
+       without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+              LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+       POSSIBILITY OF SUCH DAMAGE.
+
+
+Cass Everitt - cass@r3.nu
+
 =======================
 JPEG Library 6b License
 =======================
diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt
index e87d2441416..d488c7487e1 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -148,6 +148,49 @@ BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+=========================
+glh OpenGL helper library
+=========================
+
+glh - is a platform-indepenedent C++ OpenGL helper library
+
+
+Copyright (c) 2000 Cass Everitt
+    Copyright (c) 2000 NVIDIA Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+    without modification, are permitted provided that the following
+    conditions are met:
+
+ * Redistributions of source code must retain the above
+       copyright notice, this list of conditions and the following
+       disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials
+       provided with the distribution.
+
+ * The names of contributors to this software may not be used
+       to endorse or promote products derived from this software
+       without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+              LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+       POSSIBILITY OF SUCH DAMAGE.
+
+
+Cass Everitt - cass@r3.nu
+
 =======================
 JPEG Library 6b License
 =======================
diff --git a/indra/newview/licenses-solaris.txt b/indra/newview/licenses-solaris.txt
index 792330f706a..c19f939a807 100644
--- a/indra/newview/licenses-solaris.txt
+++ b/indra/newview/licenses-solaris.txt
@@ -148,6 +148,49 @@ BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+=========================
+glh OpenGL helper library
+=========================
+
+glh - is a platform-indepenedent C++ OpenGL helper library
+
+
+Copyright (c) 2000 Cass Everitt
+    Copyright (c) 2000 NVIDIA Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+    without modification, are permitted provided that the following
+    conditions are met:
+
+ * Redistributions of source code must retain the above
+       copyright notice, this list of conditions and the following
+       disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials
+       provided with the distribution.
+
+ * The names of contributors to this software may not be used
+       to endorse or promote products derived from this software
+       without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+              LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+       POSSIBILITY OF SUCH DAMAGE.
+
+
+Cass Everitt - cass@r3.nu
+
 =======================
 JPEG Library 6b License
 =======================
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 3d9ef9b3b50..5f6cf14c05d 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -187,6 +187,51 @@ BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+ 
+=========================
+glh OpenGL helper library 
+=========================   
+
+glh - is a platform-indepenedent C++ OpenGL helper library 
+
+
+Copyright (c) 2000 Cass Everitt
+    Copyright (c) 2000 NVIDIA Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+    without modification, are permitted provided that the following
+    conditions are met:
+
+ * Redistributions of source code must retain the above
+       copyright notice, this list of conditions and the following
+       disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials
+       provided with the distribution.
+
+ * The names of contributors to this software may not be used
+       to endorse or promote products derived from this software
+       without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+       `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+       FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+       REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+       INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+       BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+       POSSIBILITY OF SUCH DAMAGE. 
+
+
+Cass Everitt - cass@r3.nu
+
 =======================
 JPEG Library 6b License
 =======================
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index a5cb6ae8a7a..e7c47cbba6a 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -17,7 +17,9 @@
 ##   on some hardware.  Disabling this option may cause BETTER PERFORMANCE but
 ##   may also cause CRASHES and hangs on some unstable combinations of drivers
 ##   and hardware.
-export LL_GL_BASICEXT=x
+## NOTE: This is 'off' for WindLight to help testing.  Hopefully it's not
+##   really needed any more anyway.
+#export LL_GL_BASICEXT=x
 
 ## - Avoids *all* optional OpenGL extensions.  This is the safest and least-
 ##   exciting option.  Enable this if you experience stability issues, and
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index bd885f955c6..156b4a395df 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -463,7 +463,6 @@ void LLAgent::cleanup()
 	mPointAt = NULL;
 	mRegionp = NULL;
 	setFocusObject(NULL);
-	mFadeObjects.clear();
 }
 
 //-----------------------------------------------------------------------------
@@ -833,20 +832,18 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 
 			setPositionAgent(getPositionAgent() - delta);
 			LLVector3 camera_position_agent = gCamera->getOrigin();
+			
 			gCamera->setOrigin(camera_position_agent - delta);
 
 			// Update all of the regions.
 			gWorldPointer->updateAgentOffset(agent_offset_global);
 
 			// Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
+			// *TODO: possibly refactor into gSky->setAgentRegion(regionp)? -Brad
 			if (gSky.mVOSkyp)
 			{
 				gSky.mVOSkyp->setRegion(regionp);
 			}
-			if (gSky.mVOStarsp)
-			{
-				gSky.mVOStarsp->setRegion(regionp);
-			}
 			if (gSky.mVOGroundp)
 			{
 				gSky.mVOGroundp->setRegion(regionp);
@@ -1390,12 +1387,6 @@ LLVector3d LLAgent::calcFocusOffset(LLViewerObject *object, S32 x, S32 y)
 	if (!is_avatar) 
 	{
 		//unproject relative clicked coordinate from window coordinate using GL
-		glPushMatrix();
-		glMatrixMode(GL_PROJECTION);
-		glLoadMatrixf((const GLfloat*) gCamera->getProjection().mMatrix);
-		glMatrixMode(GL_MODELVIEW);
-		glLoadMatrixf((const GLfloat*) gCamera->getModelview().mMatrix);
-		glMultMatrixf((const GLfloat*) obj_matrix.mMatrix);
 
 		GLint viewport[4];
 		GLdouble modelview[16];
@@ -1403,8 +1394,16 @@ LLVector3d LLAgent::calcFocusOffset(LLViewerObject *object, S32 x, S32 y)
 		GLfloat winX, winY, winZ;
 		GLdouble posX, posY, posZ;
 
-		glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
-		glGetDoublev( GL_PROJECTION_MATRIX, projection );
+		// convert our matrices to something that has a multiply that works
+		glh::matrix4f newModel((F32*)gCamera->getModelview().mMatrix);
+		glh::matrix4f tmpObjMat((F32*)obj_matrix.mMatrix);
+		newModel *= tmpObjMat;
+
+		for(U32 i = 0; i < 16; ++i)
+		{
+			modelview[i] = newModel.m[i];
+			projection[i] = gCamera->getProjection().mMatrix[i/4][i%4];
+		}
 		glGetIntegerv( GL_VIEWPORT, viewport );
 
 		winX = ((F32)x) * gViewerWindow->getDisplayScale().mV[VX];
@@ -1413,14 +1412,12 @@ LLVector3d LLAgent::calcFocusOffset(LLViewerObject *object, S32 x, S32 y)
 
 		gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
 
-		glPopMatrix();
-
-		LLVector3 obj_rel = LLVector3((F32)posX, (F32)posY, (F32)posZ);
-		LLVector3 obj_center = LLVector3(0, 0, 0);
-		obj_rel = obj_rel * object->getRenderMatrix(); //mDrawable->getWorldMatrix();
-		obj_center = obj_center * object->getRenderMatrix();//mDrawable->getWorldMatrix();
-		obj_rel -= object->getRenderPosition();//mDrawable->getWorldPosition();
+		LLVector3 obj_rel((F32)posX, (F32)posY, (F32)posZ);
+		obj_rel = obj_rel * object->getRenderMatrix();
+		obj_rel -= object->getRenderPosition();
 		
+		LLVector3 obj_center = LLVector3(0, 0, 0) * object->getRenderMatrix();
+
 		//now that we have the object relative position, we should bias toward the center of the object 
 		//based on the distance of the camera to the focus point vs. the distance of the camera to the focus
 
@@ -3151,74 +3148,6 @@ void LLAgent::updateCamera()
 	mCameraFOVZoomFactor = calcCameraFOVZoomFactor();
 	camera_target_global = focus_target_global + (camera_target_global - focus_target_global) * (1.f + mCameraFOVZoomFactor);
 
-	// do alpha fade on focus object
-	F32 fade_increment = mFocusObjectFadeTimer.getElapsedTimeAndResetF32();
-
-	if (mFocusObject.notNull() && !mFocusObject->isAttachment() && mFocusObject->mDrawable.notNull())
-	{
-		F32 increment = fade_increment;
-		if (mFocusObjectDist < -0.2f)
-		{
-			increment *= -1.f;
-		}
-
-		if (mFocusObject->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
-		{
-			S32 num_faces = mFocusObject->mDrawable->getNumFaces();
-			for (S32 i = 0; i < num_faces; i++)
-			{
-				LLFace* facep = mFocusObject->mDrawable->getFace(i);
-				F32 fade = facep->mAlphaFade;
-				fade = llclamp(fade + increment, 0.f, 1.f);
-				facep->mAlphaFade = fade;
-			}
-		}
-	}
-
-	// do alpha fade in on fade objects
-	std::set< LLPointer<LLViewerObject> >::iterator fade_object_it;
-	for (fade_object_it = mFadeObjects.begin(); fade_object_it != mFadeObjects.end(); )
-	{
-		LLViewerObject* fade_object = *fade_object_it;
-		if (fade_object->isDead())
-		{
-			// remove from list
-			mFadeObjects.erase(fade_object_it++);
-		}
-		else
-		{
-			LLDrawable* drawablep = fade_object->mDrawable;
-			if (drawablep && fade_object->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
-			{
-				S32 num_faces = drawablep->getNumFaces();
-				BOOL fade_done = TRUE;
-				for (S32 i = 0; i < num_faces; i++)
-				{
-					LLFace* facep = drawablep->getFace(i);
-					F32 fade = facep->mAlphaFade;
-					fade = llclamp(fade - fade_increment, 0.f, 1.f);
-					facep->mAlphaFade = fade;
-					if (fade > 0.f)
-					{
-						fade_done = FALSE;
-					}
-				}
-				if (fade_done)
-				{
-					mFadeObjects.erase(fade_object_it++);
-				}
-				else
-				{
-					fade_object_it++;
-				}
-			}
-			else
-			{
-				fade_object_it++;
-			}
-		}
-	}
-
 	mShowAvatar = TRUE; // can see avatar by default
 
 	// Adjust position for animation
@@ -4316,19 +4245,6 @@ void LLAgent::clearFocusObject()
 
 void LLAgent::setFocusObject(LLViewerObject* object)
 {
-	if (mFocusObject.notNull() && 
-		mFocusObject->mDrawable.notNull() && 
-		mFocusObject->getPCode() == LL_PCODE_VOLUME &&
-		mFocusObject != object)
-	{
-		LLPointer<LLViewerObject> fade_object_ptr(mFocusObject);
-
-		if (fade_object_ptr.notNull() && mFadeObjects.find(fade_object_ptr) == mFadeObjects.end())
-		{
-			mFadeObjects.insert(fade_object_ptr);
-		}
-	}
-
 	mFocusObject = object;
 }
 
@@ -5783,6 +5699,9 @@ bool LLAgent::teleportCore(bool is_local)
 	{
 		gTeleportDisplay = TRUE;
 		gAgent.setTeleportState( LLAgent::TELEPORT_START );
+
+		//release geometry from old location
+		gPipeline.resetVertexBuffers();
 	}
 	make_ui_sound("UISndTeleportOut");
 	
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 1b21a712127..6fe978b6cbf 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -841,7 +841,6 @@ class LLAgent : public LLObservable
 	U8				mGodLevel;
 	LLFrameTimer	mFidgetTimer;
 	LLFrameTimer	mFocusObjectFadeTimer;
-	std::set<LLPointer <LLViewerObject> > mFadeObjects;
 	F32				mNextFidgetTime;
 	S32				mCurrentFidget;
 	BOOL			mFirstLogin;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fe1d93c7bc4..106b2b1517f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -100,6 +100,9 @@
 #include "lltracker.h"
 #include "llviewerparcelmgr.h"
 #include "llworldmapview.h"
+#include "llpostprocess.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
 
 #include "lldebugview.h"
 #include "llconsole.h"
@@ -127,6 +130,9 @@
 #include "llframestats.h"
 #include "llagentpilot.h"
 #include "llsrv.h"
+#include "llvovolume.h"
+#include "llflexibleobject.h" 
+#include "llvosurfacepatch.h"
 
 // includes for idle() idleShutdown()
 #include "llviewercontrol.h"
@@ -458,8 +464,6 @@ static void saved_settings_to_globals()
 	LLCOMBOBOX_WIDTH	= 128;
 
 	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
-
-	LLVOSky::sNighttimeBrightness		= gSavedSettings.getF32("RenderNightBrightness");
 	
 	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic");
 	LLVOVolume::sLODFactor				= gSavedSettings.getF32("RenderVolumeLODFactor");
@@ -492,6 +496,11 @@ static void saved_settings_to_globals()
 	gHandleKeysAsync = gSavedSettings.getBOOL("AsyncKeyboard");
 	LLHoverView::sShowHoverTips = gSavedSettings.getBOOL("ShowHoverTips");
 
+	LLRenderTarget::sUseFBO				= gSavedSettings.getBOOL("RenderUseFBO");
+	LLVOAvatar::sUseImpostors			= gSavedSettings.getBOOL("RenderUseImpostors");
+	LLVOSurfacePatch::sLODFactor		= gSavedSettings.getF32("RenderTerrainLODFactor");
+	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //sqaure lod factor to get exponential range of [1,4]
+
 #if LL_VECTORIZE
 	if (gSysCPU.hasAltivec())
 	{
@@ -1009,13 +1018,6 @@ bool LLAppViewer::init()
         gCurrentVersion = llformat("%s %d.%d.%d.%d", gChannelName.c_str(), LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD );
 	
 	//
-	// Load the feature tables
-	//
-	llinfos << "Loading feature tables." << llendl;
-	
-	gFeatureManagerp->loadFeatureTables();
-	gFeatureManagerp->initCPUFeatureMasks();
-
 	// Merge with the command line overrides
 	gSavedSettings.applyOverrides(gCommandLineSettings);
 
@@ -1260,26 +1262,64 @@ bool LLAppViewer::init()
 	llinfos << "Viewer Digest: " << gViewerDigest << llendl;
 
 	// If we don't have the right GL requirements, exit.
-	// BUG: This should just be changed to a generic GL "Not good enough" flag
-	if (!gGLManager.mHasMultitexture && !gNoRender)
-	{
-		std::ostringstream msg;
-		msg <<
-			"You do not appear to have the proper hardware requirements "
-			"for " << gSecondLife << ". " << gSecondLife << " requires an OpenGL graphics "
-			"card that has multitexture support. If this is the case, "
-			"you may want to make sure that you have the latest drivers for "
-			"your graphics card, and service packs and patches for your "
-			"operating system.\n"
-			"If you continue to have problems, please go to: "
-			"www.secondlife.com/support ";
+	if (!gGLManager.mHasRequirements && !gNoRender)
+	{	
+		// can't use an alert here since we're existing and
+		// all hell breaks lose.
 		OSMessageBox(
-			msg.str().c_str(),
+			LLAlertDialog::getTemplateMessage("UnsupportedGLRequirements").c_str(),
 			NULL,
 			OSMB_OK);
 		return 0;
 	}
 
+	// alert the user if they are using unsupported hardware
+	if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
+	{
+		bool unsupported = false;
+		LLString::format_map_t args;
+		LLString minSpecs;
+		
+		// get cpu data from xml
+		std::stringstream minCPUString(LLAlertDialog::getTemplateMessage("UnsupportedCPUAmount"));
+		S32 minCPU = 0;
+		minCPUString >> minCPU;
+
+		// get RAM data from XML
+		std::stringstream minRAMString(LLAlertDialog::getTemplateMessage("UnsupportedRAMAmount"));
+		U64 minRAM = 0;
+		minRAMString >> minRAM;
+		minRAM = minRAM * 1024 * 1024;
+
+		if(!gFeatureManagerp->isGPUSupported())
+		{
+			minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedGPU");
+			minSpecs += "\n";
+			unsupported = true;
+		}
+		if(gSysCPU.getMhz() < minCPU)
+		{
+			minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedCPU");
+			minSpecs += "\n";
+			unsupported = true;
+		}
+		if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
+		{
+			minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedRAM");
+			minSpecs += "\n";
+			unsupported = true;
+		}
+
+		if(unsupported)
+		{
+			args["MINSPECS"] = minSpecs;
+			gViewerWindow->alertXml("UnsupportedHardware", args );
+			
+			// turn off flag
+			gSavedSettings.setBOOL("AlertedUnsupportedHardware", TRUE);
+		}
+	}
+	
 	// Save the current version to the prefs file
 	gSavedSettings.setString("LastRunVersion", gCurrentVersion);
 
@@ -1337,6 +1377,7 @@ bool LLAppViewer::mainLoop()
 				debugTime.reset();
 			}
 #endif
+
 			if (!LLApp::isExiting())
 			{
 				// Scan keyboard for movement keys.  Command keys and typing
@@ -1434,7 +1475,7 @@ bool LLAppViewer::mainLoop()
 
 				const F64 min_frame_time = 0.0; //(.0333 - .0010); // max video frame rate = 30 fps
 				const F64 min_idle_time = 0.0; //(.0010); // min idle time = 1 ms
-				const F64 max_idle_time = run_multiple_threads ? min_idle_time : .005; // 5 ms
+				const F64 max_idle_time = run_multiple_threads ? min_idle_time : llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
 				idleTimer.reset();
 				while(1)
 				{
@@ -1620,7 +1661,11 @@ bool LLAppViewer::cleanup()
 	LLSelectMgr::cleanupGlobals();
 
 	LLViewerObject::cleanupVOClasses();
-		
+
+	LLWaterParamManager::cleanupClass();
+	LLWLParamManager::cleanupClass();
+	LLPostProcess::cleanupClass();
+
 	LLTracker::cleanupInstance();
 	
 	// *FIX: This is handled in LLAppViewerWin32::cleanup().
@@ -2316,16 +2361,33 @@ bool LLAppViewer::initWindow()
 		gViewerWindow->getWindow()->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
 	}
 
+	if (!gNoRender)
+	{
+		//
+		// Initialize GL stuff
+		//
+
+		// Set this flag in case we crash while initializing GL
+		gSavedSettings.setBOOL("RenderInitError", TRUE);
+		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
+	
+		gPipeline.init();
+		stop_glerror();
+		gViewerWindow->initGLDefaults();
+
+		gSavedSettings.setBOOL("RenderInitError", FALSE);
+		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
+	}
+
 	LLUI::sWindow = gViewerWindow->getWindow();
 
 	LLAlertDialog::parseAlerts("alerts.xml");
 	LLNotifyBox::parseNotify("notify.xml");
 
-	//
-	// Clean up the feature manager lookup table - settings were updated
-	// in the LLViewerWindow constructor
-	//
-	gFeatureManagerp->cleanupFeatureTables();
+	// *TODO - remove this when merging into release
+	// DON'T Clean up the feature manager lookup table - settings are needed
+	// for setting the graphics level.
+	//gFeatureManagerp->cleanupFeatureTables();
 
 	// Show watch cursor
 	gViewerWindow->setCursor(UI_CURSOR_WAIT);
@@ -3268,8 +3330,7 @@ void LLAppViewer::idle()
 	if (!gDisconnected)
 	{
 		LLFastTimer t(LLFastTimer::FTM_NETWORK);
-		
-	    // Update spaceserver timeinfo
+		// Update spaceserver timeinfo
 	    gWorldp->setSpaceTimeUSec(gWorldp->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
     
     
@@ -3372,8 +3433,6 @@ void LLAppViewer::idle()
 
 		//  Update statistics for this frame
 		update_statistics(gFrameCount);
-
-		gViewerWindow->updateDebugText();
 	}
 
 	////////////////////////////////////////
@@ -3403,30 +3462,13 @@ void LLAppViewer::idle()
 	//
 		LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
 
-// 		BOOL was_in_prelude = gAgent.inPrelude();
-
 	{
-		//LLFastTimer t(LLFastTimer::FTM_TEMP1);
-		
 		// After agent and camera moved, figure out if we need to
 		// deselect objects.
 		gSelectMgr->deselectAllIfTooFar();
 
 	}
 
-	{
-		LLFastTimer t(LLFastTimer::FTM_RESET_DRAWORDER);
-			
-		//////////////////////////////////////////////
-		//
-		// Clear draw orders
-		//
-		// Should actually be done after render, but handlePerFrameHover actually does a "render"
-		// to do its selection.
-		//
-
-		gPipeline.resetDrawOrders();
-	}
 	{
 		// Handle pending gesture processing
 		gGestureManager.update();
@@ -3444,11 +3486,6 @@ void LLAppViewer::idle()
 		}
 	}
 	
-	{
-		LLFastTimer t(LLFastTimer::FTM_UPDATE_SKY);	
-		gSky.updateSky();
-	}
-
 	//////////////////////////////////////
 	//
 	// Deletes objects...
@@ -3476,8 +3513,6 @@ void LLAppViewer::idle()
 	//
 
 	{
-		//LLFastTimer t(LLFastTimer::FTM_TEMP3);
-		
 		gFrameStats.start(LLFrameStats::UPDATE_EFFECTS);
 		gSelectMgr->updateEffects();
 		gHUDManager->cleanupEffects();
@@ -3552,16 +3587,18 @@ void LLAppViewer::idle()
 	//
 	gFrameStats.start(LLFrameStats::IMAGE_UPDATE);
 
-	LLFastTimer t(LLFastTimer::FTM_IMAGE_UPDATE);
-	
-	LLViewerImage::updateClass(gCamera->getVelocityStat()->getMean(),
-								gCamera->getAngularVelocityStat()->getMean());
+	{
+		LLFastTimer t(LLFastTimer::FTM_IMAGE_UPDATE);
+		
+		LLViewerImage::updateClass(gCamera->getVelocityStat()->getMean(),
+									gCamera->getAngularVelocityStat()->getMean());
 
-	gBumpImageList.updateImages();  // must be called before gImageList version so that it's textures are thrown out first.
+		gBumpImageList.updateImages();  // must be called before gImageList version so that it's textures are thrown out first.
 
-	const F32 max_image_decode_time = 0.005f; // 5 ms decode time
-	gImageList.updateImages(max_image_decode_time);
-	stop_glerror();
+		const F32 max_image_decode_time = llmin(0.005f, 0.005f*10.f*gFrameIntervalSeconds); // 50 ms/second decode time (no more than 5ms/frame)
+		gImageList.updateImages(max_image_decode_time);
+		stop_glerror();
+	}
 
 	//////////////////////////////////////
 	//
@@ -3571,6 +3608,7 @@ void LLAppViewer::idle()
 	
 	if (!gNoRender)
 	{
+		LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE);
 		gFrameStats.start(LLFrameStats::UPDATE_MOVE);
 		gPipeline.updateMove();
 
diff --git a/indra/newview/llbox.cpp b/indra/newview/llbox.cpp
index 6f0edf717eb..d0505b6b06f 100644
--- a/indra/newview/llbox.cpp
+++ b/indra/newview/llbox.cpp
@@ -34,6 +34,7 @@
 #include "llbox.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llglheaders.h"
 
 LLBox		gBox;
@@ -61,7 +62,7 @@ void LLBox::cleanupGL()
 
 void LLBox::renderface(S32 which_face)
 {
-	static F32 normals[6][3] =
+	/*static F32 normals[6][3] =
 	{
 		{-1.0f,  0.0f,  0.0f},
 		{ 0.0f,  1.0f,  0.0f},
@@ -69,7 +70,7 @@ void LLBox::renderface(S32 which_face)
 		{ 0.0f, -1.0f,  0.0f},
 		{ 0.0f,  0.0f,  1.0f},
 		{ 0.0f,  0.0f, -1.0f}
-	};
+		};*/
 	static S32 faces[6][4] =
 	{
 		{0, 1, 2, 3},
@@ -80,17 +81,17 @@ void LLBox::renderface(S32 which_face)
 		{7, 4, 0, 3}
 	};
 
-	glBegin(GL_QUADS);
-		glNormal3fv(&normals[which_face][0]);
-		glTexCoord2f(1,0);
-		glVertex3fv(&mVertex[ faces[which_face][0] ][0]);
-		glTexCoord2f(1,1);
-		glVertex3fv(&mVertex[ faces[which_face][1] ][0]);
-		glTexCoord2f(0,1);
-		glVertex3fv(&mVertex[ faces[which_face][2] ][0]);
-		glTexCoord2f(0,0);
-		glVertex3fv(&mVertex[ faces[which_face][3] ][0]);
-	glEnd();
+	gGL.begin(GL_QUADS);
+		//gGL.normal3fv(&normals[which_face][0]);
+		gGL.texCoord2f(1,0);
+		gGL.vertex3fv(&mVertex[ faces[which_face][0] ][0]);
+		gGL.texCoord2f(1,1);
+		gGL.vertex3fv(&mVertex[ faces[which_face][1] ][0]);
+		gGL.texCoord2f(0,1);
+		gGL.vertex3fv(&mVertex[ faces[which_face][2] ][0]);
+		gGL.texCoord2f(0,0);
+		gGL.vertex3fv(&mVertex[ faces[which_face][3] ][0]);
+	gGL.end();
 }
 
 void LLBox::render()
@@ -125,4 +126,5 @@ void LLBox::render()
 	renderface(2);
 	renderface(1);
 	renderface(0);
+	gGL.flush();
 }
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 108e2cafe05..0e0880959ed 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -193,7 +193,7 @@ bool LLAvatarTracker::haveTrackingInfo()
 
 LLVector3d LLAvatarTracker::getGlobalPos()
 {
-	if(!mTrackedAgentValid) return LLVector3d();
+	if(!mTrackedAgentValid || !mTrackingData) return LLVector3d();
 	LLVector3d global_pos;
 	
 	LLViewerObject* object = gObjectList.findObject(mTrackingData->mAvatarID);
@@ -452,8 +452,10 @@ void LLAvatarTracker::empowerList(const buddy_map_t& list, bool grant)
 
 void LLAvatarTracker::deleteTrackingData()
 {
-	delete mTrackingData;
+	//make sure mTrackingData never points to freed memory
+	LLTrackingData* tmp = mTrackingData;
 	mTrackingData = NULL;
+	delete tmp;
 }
 
 void LLAvatarTracker::findAgent()
diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp
index b3b6b411ab2..ee793bf6e43 100644
--- a/indra/newview/llcloud.cpp
+++ b/indra/newview/llcloud.cpp
@@ -425,41 +425,6 @@ F32 LLCloudLayer::getDensityRegion(const LLVector3 &pos_region)
 	return density;
 }
 
-// a debug method that may yet be useful
-void LLCloudLayer::renderDensityField()
-{
-// 	F32 x, y, z;
-// 	U32 i, j, k;
-// 	LLGLSNoTexture gls_ui_no_texture;
-// 	// Render a bunch of triangles to represent the cloud density field
-// 	glBegin(GL_TRIANGLES);
-// 	for(j=0; j<CLOUD_GRIDS_PER_EDGE-1; j++)
-// 	{
-// 		y = j * mMetersPerGrid;
-
-// 		for(i=0; i<CLOUD_GRIDS_PER_EDGE; i++)
-// 		{
-// 			k = i + j*CLOUD_GRIDS_PER_EDGE;
-// 			x = i * mMetersPerGrid;
-
-// 			z = 0.5f * CLOUD_MAX_HEIGHT + 40.0f * *(mDensityp + k + CLOUD_GRIDS_PER_EDGE);
-// 			glColor3f(1.0f - *(mDensityp + k + CLOUD_GRIDS_PER_EDGE), *(mDensityp + k + CLOUD_GRIDS_PER_EDGE), 0.0f);
-// 			glVertex3f(x, y+mMetersPerGrid, z);
-
-// 			z = 0.5f * CLOUD_MAX_HEIGHT + 40.0f * *(mDensityp + k);
-// 			glColor3f(1.0f - *(mDensityp + k), *(mDensityp + k), 0.0f);
-// 			glVertex3f(x, y, z);
-
-// 			z = 0.5f * CLOUD_MAX_HEIGHT + 40.0f * *(mDensityp + k + 1);
-// 			glColor3f(1.0f - *(mDensityp + k + 1), *(mDensityp + k + 1), 0.0f);
-// 			glVertex3f(x+mMetersPerGrid, y, z);
-
-// 		}
-// 	}
-// 	glEnd();
-}
-
-
 void LLCloudLayer::decompress(LLBitPack &bitpack, LLGroupHeader *group_headerp)
 {
 	LLPatchHeader  patch_header;
diff --git a/indra/newview/llcloud.h b/indra/newview/llcloud.h
index 1943cac2c20..4d5f652361b 100644
--- a/indra/newview/llcloud.h
+++ b/indra/newview/llcloud.h
@@ -175,7 +175,6 @@ class LLCloudLayer
 
 	F32 getDensityRegion(const LLVector3 &pos_region);		// "position" is in local coordinates
 
-	void renderDensityField();
 	void decompress(LLBitPack &bitpack, LLGroupHeader *group_header);
 
 	LLCloudLayer* getNeighbor(const S32 n) const					{ return mNeighbors[n]; }
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index b2b29ffc9fa..caf506a21e2 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -39,6 +39,7 @@
 
 // Project includes
 #include "llui.h"
+#include "llglimmediate.h"
 #include "lluiconstants.h"
 #include "llviewerwindow.h"
 #include "llviewercontrol.h"
@@ -215,23 +216,21 @@ void LLColorSwatchCtrl::draw()
 		// Check state
 		if ( mValid )
 		{
-			LLGLSTexture gls_texture;
-
 			// Draw the color swatch
 			gl_rect_2d_checkerboard( interior );
 			gl_rect_2d(interior, mColor, TRUE);
 			LLColor4 opaque_color = mColor;
 			opaque_color.mV[VALPHA] = 1.f;
-			glColor4fv(opaque_color.mV);
+			gGL.color4fv(opaque_color.mV);
 			if (mAlphaGradientImage.notNull())
 			{
-				glPushMatrix();
+				gGL.pushMatrix();
 				{
-					glTranslatef((F32)interior.mLeft, (F32)interior.mBottom, 0.f);
+					gGL.translatef((F32)interior.mLeft, (F32)interior.mBottom, 0.f);
 					LLViewerImage::bindTexture(mAlphaGradientImage);
 					gl_rect_2d_simple_tex(interior.getWidth(), interior.getHeight());
 				}
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 		}
 		else
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 17593766b9c..fd36ed666d1 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -94,11 +94,7 @@ void LLDrawable::init()
 	mRenderType = 0;
 	mCurrentScale = LLVector3(1,1,1);
 	mDistanceWRTCamera = 0.0f;
-	// mUVRect
-	mUVZ = 0.f;
-	// mLightSet
-	// mBlockSet
-	// mSavePos
+
 	mQuietCount = 0;
 
 	mState     = 0;
@@ -107,7 +103,6 @@ void LLDrawable::init()
 	mSpatialGroupp = NULL;
 	mVisible = 0;
 	mRadius = 0.f;
-	mSunShadowFactor = 1.f;
 	
 	mGeneration = -1;
 	mBinRadius = 1.f;
@@ -185,21 +180,6 @@ BOOL LLDrawable::isLight() const
 	}
 }
 
-void LLDrawable::clearLightSet()
-{
-	// Remove this object from any object which has it as a light
-	for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
-	{
-		LLDrawable *targetp = *iter;
-		if (targetp != this && !targetp->isDead())
-		{
-			targetp->mLightSet.erase(this);
-			gPipeline.markRelight(targetp);
-		}
-	}
-	mLightSet.clear();
-}
-
 void LLDrawable::cleanupReferences()
 {
 	LLFastTimer t(LLFastTimer::FTM_PIPELINE);
@@ -207,12 +187,8 @@ void LLDrawable::cleanupReferences()
 	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
 	mFaces.clear();
 
-	clearLightSet();
-
 	gObjectList.removeDrawable(this);
 	
-	mBlockSet.clear();
-
 	gPipeline.unlinkDrawable(this);
 	
 	// Cleanup references to other objects
@@ -239,16 +215,6 @@ void LLDrawable::cleanupDeadDrawables()
 S32 LLDrawable::findReferences(LLDrawable *drawablep)
 {
 	S32 count = 0;
-	if (mLightSet.count(drawablep) > 0)
-	{
-		llinfos << this << ": lightset reference" << llendl;
-		count++;
-	}
-	if (mBlockSet.count(drawablep) > 0)
-	{
-		llinfos << this << ": blockset reference" << llendl;
-		count++;
-	}
 	if (mParent == drawablep)
 	{
 		llinfos << this << ": parent reference" << llendl;
@@ -257,20 +223,6 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 	return count;
 }
 
-#if 0
-// SJB: This is SLOW, so we don't want to allow it (we don't currently use it)
-void LLDrawable::removeFace(const S32 i)
-{
-	LLFace *face= mFaces[i];
-
-	if (face)
-	{
-		mFaces.erase(mFaces.begin() + i);
-		delete face;
-	}
-}
-#endif
-
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerImage *texturep)
 {
 	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
@@ -299,11 +251,13 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerImage *texturep)
 {
 	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
 	
-	LLFace *face = new LLFace(this, mVObjp);
+	LLFace *face;
+	face = new LLFace(this, mVObjp);
 
 	face->setTEOffset(mFaces.size());
 	face->setTexture(texturep);
 	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+
 	mFaces.push_back(face);
 
 	if (isState(UNLIT))
@@ -399,7 +353,6 @@ void LLDrawable::makeActive()
 			pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
 			pcode == LLViewerObject::LL_VO_PART_GROUP ||
 			pcode == LLViewerObject::LL_VO_CLOUDS ||
-			pcode == LLViewerObject::LL_VO_STARS ||
 			pcode == LLViewerObject::LL_VO_GROUND ||
 			pcode == LLViewerObject::LL_VO_SKY)
 		{
@@ -429,22 +382,22 @@ void LLDrawable::makeActive()
 				drawable->makeActive();
 			}
 		}
-			
+
 		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 		{
-			if (mVObjp->getVolume()->getPathType() == LL_PCODE_PATH_FLEXIBLE)
+			if (mVObjp->isFlexible())
 			{
 				return;
 			}
 		}
 	
-		clearState(LLDrawable::LIGHTING_BUILT);
 		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 		{
 			gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
 		}
+		updatePartition();
 	}
-	updatePartition();
+
 	if (isRoot())
 	{
 		mQuietCount = 0;
@@ -482,7 +435,6 @@ void LLDrawable::makeStatic()
 			}
 		}
 		
-		gPipeline.markRelight(this);
 		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 		{
 			gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
@@ -526,8 +478,8 @@ F32 LLDrawable::updateXform(BOOL undamped)
 	
 	// Damping
 	F32 dist_squared = 0.f;
-	F32 scaled = 0.f;
-	
+	F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
+
 	if (damped && mDistanceWRTCamera > 0.0f)
 	{
 		F32 lerp_amt = llclamp(LLCriticalDamp::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f);
@@ -538,10 +490,8 @@ F32 LLDrawable::updateXform(BOOL undamped)
 		dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f;
 
 		LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt);
-		scaled = dist_vec_squared(new_scale, target_scale);
+		dist_squared += dist_vec_squared(new_scale, target_scale);
 
-		dist_squared += scaled;
-		F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
 		if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) &&
 			(dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED))
 		{
@@ -549,12 +499,6 @@ F32 LLDrawable::updateXform(BOOL undamped)
 			target_pos = new_pos;
 			target_rot = new_rot;
 			target_scale = new_scale;
-			
-			if (scaled >= MIN_INTERPOLATE_DISTANCE_SQUARED)
-			{		
-				//scaling requires an immediate rebuild
-				gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
-			}
 		}
 		else
 		{
@@ -562,7 +506,17 @@ F32 LLDrawable::updateXform(BOOL undamped)
 			dist_squared = 0.0f;
 		}
 	}
-		
+
+	if ((mCurrentScale != target_scale) ||
+		(!isRoot() && (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED*camdist2)))
+	{ //child prim moving or scale change requires immediate rebuild
+		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
+	}
+	else if (!getVOVolume() && !isAvatar())
+	{
+		movePartition();
+	}
+
 	// Update
 	mXform.setPosition(target_pos);
 	mXform.setRotation(target_rot);
@@ -571,6 +525,10 @@ F32 LLDrawable::updateXform(BOOL undamped)
 	
 	mCurrentScale = target_scale;
 	
+	if (mSpatialBridge)
+	{
+		gPipeline.markMoved(mSpatialBridge, FALSE);
+	}
 	return dist_squared;
 }
 
@@ -591,18 +549,6 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 	{
 		getFace(i)->updateCenterAgent();
 	}
-
-	if (moved || !isState(LLDrawable::BUILT)) // moved since last frame
-	{
-		LLVector3 tmp = mSavePos - mXform.getPositionW();
-		F32 dist = tmp.magVecSquared(); // moved since last _update_
-
-		if (dist > 1.0f || !isState(LLDrawable::BUILT) || isLight())
-		{
-			mSavePos = mXform.getPositionW();
-			gPipeline.markRelight(this);
-		}
-	}
 }
 
 void LLDrawable::movePartition()
@@ -703,17 +649,21 @@ BOOL LLDrawable::updateMoveDamped()
 void LLDrawable::updateDistance(LLCamera& camera)
 {
 	//switch LOD with the spatial group to avoid artifacts
-	LLSpatialGroup* sg = getSpatialGroup();
+	//LLSpatialGroup* sg = getSpatialGroup();
 
 	LLVector3 pos;
 
-	if (!sg || sg->changeLOD())
+	//if (!sg || sg->changeLOD())
 	{
 		LLVOVolume* volume = getVOVolume();
 		if (volume)
 		{
 			volume->updateRelativeXform();
-			pos = LLVector3(0,0,0) * volume->getRelativeXform();
+			pos = volume->getRelativeXform().getTranslation();
+			if (isStatic())
+			{
+				pos += volume->getRegion()->getOriginAgent();
+			}
 
 			for (S32 i = 0; i < getNumFaces(); i++)
 			{
@@ -761,7 +711,7 @@ void LLDrawable::updateTexture()
 	{
 		if (!isActive())
 		{
-			gPipeline.markMoved(this);
+			//gPipeline.markMoved(this);
 		}
 		else
 		{
@@ -783,18 +733,6 @@ BOOL LLDrawable::updateGeometry(BOOL priority)
 {
 	llassert(mVObjp.notNull());
 	BOOL res = mVObjp->updateGeometry(this);
-	if (isState(REBUILD_LIGHTING))
-	{
-		updateLighting(priority ? FALSE : TRUE); // only do actual lighting for non priority updates
-		if (priority)
-		{
-			gPipeline.markRelight(this); // schedule non priority update
-		}
-		else
-		{
-			clearState(REBUILD_LIGHTING);
-		}
-	}
 	return res;
 }
 
@@ -821,7 +759,11 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 
 	if (isStatic())
 	{
-		gPipeline.markRebuild(this, LLDrawable::REBUILD_GEOMETRY, TRUE);
+		LLVOVolume* volume = getVOVolume();
+		if (!volume)
+		{
+			gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE);
+		}
 
 		for (S32 i = 0; i < getNumFaces(); i++)
 		{
@@ -830,7 +772,7 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 			facep->mExtents[0] += shift_vector;
 			facep->mExtents[1] += shift_vector;
 			
-			if (facep->hasGeometry())
+			if (!volume && facep->hasGeometry())
 			{
 				facep->mVertexBuffer = NULL;
 				facep->mLastVertexBuffer = NULL;
@@ -845,9 +787,13 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 	{
 		mSpatialBridge->shiftPos(shift_vector);
 	}
+	else if (isAvatar())
+	{
+		mExtents[0] += shift_vector;
+		mExtents[1] += shift_vector;
+		mPositionGroup += LLVector3d(shift_vector);
+	}
 	
-	mSavePos = mXform.getPositionW();
-
 	mVObjp->onShift(shift_vector);
 }
 
@@ -894,64 +840,11 @@ void LLDrawable::updateBinRadius()
 {
 	if (mVObjp.notNull())
 	{
-		mBinRadius = mVObjp->getBinRadius();
+		mBinRadius = llmin(mVObjp->getBinRadius(), 256.f);
 	}
 	else
 	{
-		mBinRadius = getRadius()*4.f;
-	}
-}
-
-void LLDrawable::updateLightSet()
-{
-	if (isDead())
-	{
-		llwarns << "Updating light set for dead drawable!" << llendl;
-		return;
-	}
-
-	LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME);
-	LLVOVolume* light = getVOVolume();
-	if (isLight() && light)
-	{
-		// mLightSet points to lit objects
-		for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
-		{
-			gPipeline.markRelight(*iter);
-		}
-		mLightSet.clear();
-		part->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet);
-		for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
-		{
-			gPipeline.markRelight(*iter);
-		}
-	}
-	else
-	{
-		// mLightSet points to nearby lights
-		mLightSet.clear();
-		part->getLights(getPositionAgent(), getRadius(), mLightSet);
-		const drawable_set_t::size_type MAX_LIGHTS = 16;
-		if (mLightSet.size() > MAX_LIGHTS)
-		{
-			typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t;
-			sorted_pair_set_t sorted_set;
-			for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
-			{
-				LLDrawable* drawable = *iter;
-				LLVector3 dvec = drawable->getPositionAgent() - getPositionAgent();
-				F32 dist2 = dvec.magVecSquared();
-				sorted_set.insert(std::make_pair(dist2, drawable));
-			}
-			mLightSet.clear();
-			S32 count = 0;
-			for (sorted_pair_set_t::iterator iter = sorted_set.begin(); iter != sorted_set.end(); iter++)
-			{
-				if (++count > 16)
-					break;
-				mLightSet.insert((*iter).second);
-			}
-		}
+		mBinRadius = llmin(getRadius()*4.f, 256.f);
 	}
 }
 
@@ -962,72 +855,6 @@ void LLDrawable::updateSpecialHoverCursor(BOOL enabled)
 	// hover cursor selection. JC
 }
 
-BOOL LLDrawable::updateLighting(BOOL do_lighting)
-{
-	if (do_lighting)
-	{
-		if (gPipeline.getLightingDetail() >= 2 && (getLit() || isLight()))
-		{
-			LLFastTimer t(LLFastTimer::FTM_UPDATE_LIGHTS);
-			updateLightSet();
-			do_lighting = isLight() ? FALSE : TRUE;
-		}
-		else
-		{
-			do_lighting = FALSE;
-		}
-	}
-	if (gPipeline.getLightingDetail() >= 2)
-	{
-		LLFastTimer t(LLFastTimer::FTM_GEO_LIGHT);
-		if (mVObjp->updateLighting(do_lighting))
-		{
-			setState(LIGHTING_BUILT);
-		}
-	}
-
-	return TRUE;
-}
-
-void LLDrawable::applyLightsAsPoint(LLColor4& result)
-{
-	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
-
-	LLVector3 point_agent(getPositionAgent());
-	LLVector3 normal(-gCamera->getXAxis()); // make point agent face camera
-	
-	F32 sun_int = normal * gPipeline.mSunDir;
-	LLColor4 color(gSky.getTotalAmbientColor());
-	color += gPipeline.mSunDiffuse * sun_int;
-	
-	for (drawable_set_t::iterator iter = mLightSet.begin();
-		 iter != mLightSet.end(); ++iter)
-	{
-		LLDrawable* drawable = *iter;
-		LLVOVolume* light = drawable->getVOVolume();
-		if (!light)
-		{
-			continue;
-		}
-		LLColor4 light_color;
-		light->calcLightAtPoint(point_agent, normal, light_color);
-		color += light_color;
-	}
-	
-	// Clamp the color...
-	color.mV[0] = llmax(color.mV[0], 0.f);
-	color.mV[1] = llmax(color.mV[1], 0.f);
-	color.mV[2] = llmax(color.mV[2], 0.f);
-
-	F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]);
-	if (max_color > 1.f)
-	{
-		color *= 1.f/max_color;
-	}
-
-	result = color;
-}
-
 F32 LLDrawable::getVisibilityRadius() const
 {
 	if (isDead())
@@ -1053,10 +880,10 @@ void LLDrawable::updateUVMinMax()
 
 void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 {
-	if (mSpatialGroupp && (groupp != mSpatialGroupp))
+/*if (mSpatialGroupp && (groupp != mSpatialGroupp))
 	{
 		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
-	}
+	}*/
 	mSpatialGroupp = groupp;
 }
 
@@ -1113,7 +940,7 @@ BOOL LLDrawable::isVisible() const
 		{
 			LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() :
 									getSpatialGroup();
-			if (!group || group->isVisible())
+			if (group && group->isVisible())
 			{
 				mVisible = sCurVisible;
 				return TRUE;
@@ -1131,7 +958,7 @@ BOOL LLDrawable::isVisible() const
 	else
 	{
 		LLSpatialGroup* group = getSpatialGroup();
-		if (!group || group->isVisible())
+		if (group && group->isVisible())
 		{
 			mVisible = sCurVisible;
 			return TRUE;
@@ -1154,18 +981,19 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, U32 data_mask)
 	mRenderType = mDrawable->mRenderType;
 	mDrawableType = mDrawable->mRenderType;
 	
-	mPartitionType = LLPipeline::PARTITION_VOLUME;
+	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
 	
 	mOctree->balance();
 	
-	gPipeline.getSpatialPartition(mPartitionType)->put(this);
+	mDrawable->getRegion()->getSpatialPartition(mPartitionType)->put(this);
 }
 
 LLSpatialBridge::~LLSpatialBridge()
 {	
-	if (getSpatialGroup())
+	LLSpatialGroup* group = getSpatialGroup();
+	if (group)
 	{
-		gPipeline.getSpatialPartition(mPartitionType)->remove(this, getSpatialGroup());
+		group->mSpatialPartition->remove(this, group);
 	}
 }
 
@@ -1252,6 +1080,11 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
 	up_axis *= rot;
 	left_axis *= rot;
 
+	if (!delta.isFinite())
+	{
+		delta.clearVec();
+	}
+
 	ret.setOrigin(delta);
 	ret.setAxes(lookAt, left_axis, up_axis);
 		
@@ -1305,13 +1138,13 @@ class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable>
 	virtual void traverse(const LLOctreeNode<LLDrawable>* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		group->clearState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED);
+		group->setVisible();
 		LLOctreeTraveler<LLDrawable>::traverse(node);
 	}
 	
-	void visit(const LLOctreeState<LLDrawable>* branch)
+	void visit(const LLOctreeNode<LLDrawable>* branch)
 	{
-		gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera, TRUE);
+		gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera);
 	}
 };
 
@@ -1322,17 +1155,26 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 		return;
 	}
 
+
+	//HACK don't draw attachments for avatars that haven't been visible in more than a frame
 	LLViewerObject *vobj = mDrawable->getVObj();
 	if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment())
 	{
-		LLVOAvatar* av;
+		LLDrawable* av;
 		LLDrawable* parent = mDrawable->getParent();
 
 		if (parent)
 		{
-			av = (LLVOAvatar*) parent->getVObj().get();
-		
-			if (!av->isVisible())
+			LLViewerObject* objparent = parent->getVObj();
+			av = objparent->mDrawable;
+			LLSpatialGroup* group = av->getSpatialGroup();
+
+			BOOL impostor = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isImpostor();
+
+			if (!group ||
+				av->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance ||
+				LLDrawable::getCurrentFrame() - av->mVisible > 1 ||
+				impostor)
 			{
 				return;
 			}
@@ -1346,7 +1188,8 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 	LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
 	LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
 
-	if (camera_in.AABBInFrustum(center, size))
+	if (camera_in.AABBInFrustumNoFarClip(center, size) && 
+		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))
 	{
 		if (LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
 		{
@@ -1392,7 +1235,11 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in)
 			llwarns << "Corrupt drawable found while updating spatial bridge distance." << llendl;
 			continue;
 		}
-		child->updateDistance(camera);
+
+		if (!child->isAvatar())
+		{
+			child->updateDistance(camera);
+		}
 	}
 }
 
@@ -1401,11 +1248,6 @@ void LLSpatialBridge::makeActive()
 	llerrs << "makeActive called on spatial bridge" << llendl;
 }
 
-void LLSpatialBridge::makeStatic()
-{
-	llerrs << "makeStatic called on spatial bridge" << llendl;
-}
-
 void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
 {
 	LLSpatialPartition::move(drawablep, curp, immediate);
@@ -1415,7 +1257,7 @@ void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL imm
 BOOL LLSpatialBridge::updateMove()
 {
 	mOctree->balance();
-	gPipeline.getSpatialPartition(mPartitionType)->move(this, getSpatialGroup(), TRUE);
+	mDrawable->getRegion()->getSpatialPartition(mPartitionType)->move(this, getSpatialGroup(), TRUE);
 	return TRUE;
 }
 
@@ -1453,14 +1295,12 @@ const LLVector3	LLDrawable::getPositionAgent() const
 	{
 		if (isActive())
 		{
-			if (isRoot())
-			{
-				return LLVector3(0,0,0) * getWorldMatrix();
-			}
-			else
+			LLVector3 pos(0,0,0);
+			if (!isRoot())
 			{
-				return mVObjp->getPosition() * getParent()->getWorldMatrix();
+				pos = mVObjp->getPosition();
 			}
+			return pos * getRenderMatrix();
 		}
 		else
 		{
@@ -1485,11 +1325,6 @@ BOOL LLDrawable::isAnimating() const
 		return TRUE;
 	}
 
-	if (mVObjp->isFlexible())
-	{
-		return TRUE;
-	}
-
 	if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP)
 	{
 		return TRUE;
@@ -1500,12 +1335,6 @@ BOOL LLDrawable::isAnimating() const
 		return TRUE;
 	}
 
-	LLVOVolume* vol = getVOVolume();
-	if (vol && vol->mTextureAnimp)
-	{
-		return TRUE;
-	}
-
 	if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
 	{
 		return TRUE;
@@ -1527,16 +1356,16 @@ LLBridgePartition::LLBridgePartition()
 { 
 	mRenderByGroup = FALSE; 
 	mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; 
-	mPartitionType = LLPipeline::PARTITION_BRIDGE;
-	mLODPeriod = 1;
-	mSlopRatio = 0.f;
+	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
+	mLODPeriod = 16;
+	mSlopRatio = 0.25f;
 }
 
 LLHUDBridge::LLHUDBridge(LLDrawable* drawablep)
 : LLVolumeBridge(drawablep)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
-	mPartitionType = LLPipeline::PARTITION_HUD;
+	mPartitionType = LLViewerRegion::PARTITION_HUD;
 	mSlopRatio = 0.0f;
 }
 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 52082ad5b5d..9a0dafe77b3 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -83,7 +83,7 @@ class LLDrawable : public LLRefCount
 	virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
 
 
-	const LLViewerRegion* getRegion()               const { return mVObjp->getRegion(); }
+	LLViewerRegion* getRegion()               const { return mVObjp->getRegion(); }
 	const LLTextureEntry* getTextureEntry(U8 which) const { return mVObjp->getTE(which); }
 	LLPointer<LLViewerObject>& getVObj()							  { return mVObjp; }
 	const LLViewerObject *getVObj()	const						  { return mVObjp; }
@@ -153,13 +153,8 @@ class LLDrawable : public LLRefCount
 	void updateMaterial();
 	virtual void updateDistance(LLCamera& camera);
 	BOOL updateGeometry(BOOL priority);
-	BOOL updateLighting(BOOL priority);
 	void updateFaceSize(S32 idx);
-	void updateLightSet();
-	
-	F32  getSunShadowFactor() const				{ return mSunShadowFactor; }
-	void setSunShadowFactor(F32 factor)			{ mSunShadowFactor = factor; }
-	void applyLightsAsPoint(LLColor4& result);
+		
 	void updateSpecialHoverCursor(BOOL enabled);
 
 	virtual void shiftPos(const LLVector3 &shift_vector);
@@ -169,7 +164,6 @@ class LLDrawable : public LLRefCount
 	BOOL getLit() const							{ return isState(UNLIT) ? FALSE : TRUE; }
 	void setLit(BOOL lit)						{ lit ? clearState(UNLIT) : setState(UNLIT); }
 
-	void clearLightSet();
 	virtual void cleanupReferences();
 
 	void setRadius(const F32 radius);
@@ -245,7 +239,6 @@ class LLDrawable : public LLRefCount
 	
 	typedef enum e_drawable_flags
 	{
-// 		TEXTURE			= 0x00000001,
  		IN_REBUILD_Q1	= 0x00000002,
  		IN_REBUILD_Q2	= 0x00000004,
  		IN_LIGHT_Q		= 0x00000008,
@@ -260,13 +253,11 @@ class LLDrawable : public LLRefCount
 		REBUILD_VOLUME  = 0x00001000,	//volume changed LOD or parameters, or vertex buffer changed
 		REBUILD_TCOORD	= 0x00002000,	//texture coordinates changed
 		REBUILD_COLOR	= 0x00004000,	//color changed
-		REBUILD_LIGHTING= 0x00008000,	//lighting information changed
 		REBUILD_POSITION= 0x00010000,	//vertex positions/normals changed
 		REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
-		REBUILD_ALL		= REBUILD_GEOMETRY|REBUILD_LIGHTING|REBUILD_VOLUME,
+		REBUILD_ALL		= REBUILD_GEOMETRY|REBUILD_VOLUME,
 		ON_SHIFT_LIST	= 0x00100000,
-// 		NO_INTERP_COLOR = 0x00200000,
 		BLOCKER			= 0x00400000,
 		ACTIVE			= 0x00800000,
 		DEAD			= 0x01000000,
@@ -284,14 +275,7 @@ class LLDrawable : public LLRefCount
 	LLPointer<LLDrawable> mParent;
 
 	F32				mDistanceWRTCamera;
-
-	LLRectf			mUVRect;
-	F32				mUVZ;
-
-	drawable_set_t	mLightSet;
-	drawable_set_t	mBlockSet;
-
-	LLVector3		mSavePos;
+	
 	S32				mQuietCount;
 
 	static S32 getCurrentFrame() { return sCurVisible; }
@@ -301,7 +285,7 @@ class LLDrawable : public LLRefCount
 	
 	static F32 sCurPixelAngle; //current pixels per radian
 
-protected:
+private:
 	typedef std::vector<LLFace*> face_list_t;
 	
 	U32				mState;
@@ -318,8 +302,6 @@ class LLDrawable : public LLRefCount
 	F64				mBinRadius;
 	S32				mGeneration;
 
-	F32				mSunShadowFactor;
-	
 	LLVector3		mCurrentScale;
 	
 	static U32 sCurVisible; // Counter for what value of mVisible means currently visible
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 9875221495c..c987f3e0359 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -32,7 +32,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "lldrawpool.h"
-
+#include "llglimmediate.h"
 #include "llfasttimer.h"
 #include "llviewercontrol.h"
 
@@ -44,17 +44,18 @@
 #include "lldrawpoolground.h"
 #include "lldrawpoolsimple.h"
 #include "lldrawpoolsky.h"
-#include "lldrawpoolstars.h"
 #include "lldrawpooltree.h"
 #include "lldrawpoolterrain.h"
 #include "lldrawpoolwater.h"
 #include "llface.h"
 #include "llviewerobjectlist.h" // For debug listing.
 #include "pipeline.h"
+#include "llspatialpartition.h"
+#include "llviewercamera.h"
+#include "lldrawpoolwlsky.h"
 
 S32 LLDrawPool::sNumDrawPools = 0;
 
-
 //=============================
 // Draw Pool Implementation
 //=============================
@@ -66,15 +67,15 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0)
 	case POOL_SIMPLE:
 		poolp = new LLDrawPoolSimple();
 		break;
+	case POOL_INVISIBLE:
+		poolp = new LLDrawPoolInvisible();
+		break;
 	case POOL_GLOW:
 		poolp = new LLDrawPoolGlow();
 		break;
 	case POOL_ALPHA:
 		poolp = new LLDrawPoolAlpha();
 		break;
-	case POOL_ALPHA_POST_WATER:
-		poolp = new LLDrawPoolAlphaPostWater();
-		break;
 	case POOL_AVATAR:
 		poolp = new LLDrawPoolAvatar();
 		break;
@@ -87,9 +88,6 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0)
 	case POOL_SKY:
 		poolp = new LLDrawPoolSky();
 		break;
-	case POOL_STARS:
-		poolp = new LLDrawPoolStars();
-		break;
 	case POOL_WATER:
 		poolp = new LLDrawPoolWater();
 		break;
@@ -99,6 +97,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0)
 	case POOL_BUMP:
 		poolp = new LLDrawPoolBump();
 		break;
+	case POOL_WL_SKY:
+		poolp = new LLDrawPoolWLSky();
+		break;
 	default:
 		llerrs << "Unknown draw pool type!" << llendl;
 		return NULL;
@@ -196,7 +197,6 @@ S32 LLFacePool::drawLoop(face_array_t& face_list)
 			 iter != face_list.end(); iter++)
 		{
 			LLFace *facep = *iter;
-			//facep->enableLights();
 			res += facep->renderIndexed();
 		}
 	}
@@ -214,7 +214,6 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
 		{
 			LLFace *facep = *iter;
 			facep->bindTexture(stage);
-			facep->enableLights();
 			res += facep->renderIndexed();
 		}
 	}
@@ -236,92 +235,6 @@ void LLFacePool::renderFaceSelected(LLFace *facep,
 {
 }
 
-void LLFacePool::renderVisibility()
-{
-	if (mDrawFace.empty())
-	{
-		return;
-	}
-
-	// SJB: Note: This may be broken now. If you need it, fix it :)
-	
-	glLineWidth(1.0);
-	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
-	glLoadIdentity();
-	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
-	glLoadIdentity();
-
-	glTranslatef(-0.4f,-0.3f,0);
-
-	float table[7][3] = { 
-		{ 1,0,0 },
-		{ 0,1,0 },
-		{ 1,1,0 },
-		{ 0,0,1 },
-		{ 1,0,1 },
-		{ 0,1,1 },
-		{ 1,1,1 }
-	};
-
-	glColor4f(0,0,0,0.5);
-	glBegin(GL_POLYGON);
-	glVertex3f(-0.5f,-0.5f,1.0f);
-	glVertex3f(+0.5f,-0.5f,1.0f);
-	glVertex3f(+0.5f,+0.5f,1.0f);
-	glVertex3f(-0.5f,+0.5f,1.0f);
-	glVertex3f(-0.5f,-0.5f,1.0f);
-	glEnd();
-	
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-
-		S32 geom_count = face->getGeomCount();
-		for (S32 j=0;j<geom_count;j++)
-		{
-			LLVector3 p1;
-			LLVector3 p2;
-
-			intptr_t p = ((intptr_t)face*13) % 7;
-			F32 r = table[p][0];
-			F32 g = table[p][1];
-			F32 b = table[p][2];
-
-			//p1.mV[1] = y;
-			//p2.mV[1] = y;
-
-			p1.mV[2] = 1.0;
-			p2.mV[2] = 1.0;
-
-			glColor4f(r,g,b,0.5f);
-
-			glBegin(GL_LINE_STRIP);
-			glVertex3fv(p1.mV);
-			glVertex3fv(p2.mV);
-			glEnd();
-
-		}		
-	}
-
-	glColor4f(1,1,1,1);
-	glBegin(GL_LINE_STRIP);
-	glVertex3f(-0.5f,-0.5f,1.0f);
-	glVertex3f(+0.5f,-0.5f,1.0f);
-	glVertex3f(+0.5f,+0.5f,1.0f);
-	glVertex3f(-0.5f,+0.5f,1.0f);
-	glVertex3f(-0.5f,-0.5f,1.0f);
-	glEnd();
-
-	glPopMatrix();
-	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
-	glMatrixMode(GL_MODELVIEW);
-
-}
-
 void LLFacePool::enqueue(LLFace* facep)
 {
 	mDrawFace.push_back(facep);
@@ -411,38 +324,17 @@ BOOL LLFacePool::LLOverrideFaceColor::sOverrideFaceColor = FALSE;
 
 void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4& color)
 {
-	if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0)
-	{
-		glVertexAttrib4fvARB(mPool->getMaterialAttribIndex(), color.mV);
-	}
-	else
-	{
-		glColor4fv(color.mV);
-	}
+	glColor4fv(color.mV);
 }
 
 void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4U& color)
 {
-	if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0)
-	{
-		glVertexAttrib4ubvARB(mPool->getMaterialAttribIndex(), color.mV);
-	}
-	else
-	{
-		glColor4ubv(color.mV);
-	}
+	glColor4ubv(color.mV);
 }
 
 void LLFacePool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a)
 {
-	if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0)
-	{
-		glVertexAttrib4fARB(mPool->getMaterialAttribIndex(), r,g,b,a);
-	}
-	else
-	{
-		glColor4f(r,g,b,a);
-	}
+	glColor4f(r,g,b,a);
 }
 
 
@@ -483,51 +375,45 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t
 	}
 }
 
-void LLRenderPass::renderInvisible(U32 mask)
+void LLRenderPass::renderTexture(U32 type, U32 mask)
+{
+	pushBatches(type, mask, TRUE);
+}
+
+void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture)
 {
 #if !LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkClientArrays(mask);
 #endif
-	
-	LLSpatialGroup::drawmap_elem_t& draw_info = gPipeline.mRenderMap[LLRenderPass::PASS_INVISIBLE];	
 
-	for (LLSpatialGroup::drawmap_elem_t::iterator i = draw_info.begin(); i != draw_info.end(); ++i)	
+	for (LLCullResult::drawinfo_list_t::iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
-		
- 		LLDrawInfo *pparams = *i;
-		if (pparams && pparams->mVertexBuffer.notNull()) {
-	 		LLDrawInfo &params = *pparams;
-
-			params.mVertexBuffer->setBuffer(mask);
-			U32 *indices_pointer =
-				(U32 *) params.mVertexBuffer->getIndicesPointer();
-			glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd,
-								params.mCount, GL_UNSIGNED_INT,
-								indices_pointer + params.mOffset);
-			gPipeline.mTrianglesDrawn += params.mCount / 3;
+		LLDrawInfo* pparams = *i;
+		if (pparams) 
+		{
+			pushBatch(*pparams, mask, texture);
 		}
 	}
 }
 
-void LLRenderPass::renderTexture(U32 type, U32 mask)
+void LLRenderPass::applyModelMatrix(LLDrawInfo& params)
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(mask);
-#endif
-
-	LLSpatialGroup::drawmap_elem_t& draw_info = gPipeline.mRenderMap[type];	
-
-	for (LLSpatialGroup::drawmap_elem_t::iterator i = draw_info.begin(); i != draw_info.end(); ++i)	
+	if (params.mModelMatrix != gGLLastMatrix)
 	{
-		LLDrawInfo* pparams = *i;
-		if (pparams) {
-			pushBatch(*pparams, mask, TRUE);
+		gGLLastMatrix = params.mModelMatrix;
+		glLoadMatrixd(gGLModelView);
+		if (params.mModelMatrix)
+		{
+			glMultMatrixf((GLfloat*) params.mModelMatrix->mMatrix);
 		}
+		gPipeline.mMatrixOpCount++;
 	}
 }
 
 void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 {
+	applyModelMatrix(params);
+
 	if (texture)
 	{
 		if (params.mTexture.notNull())
@@ -537,6 +423,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 			{
 				glMatrixMode(GL_TEXTURE);
 				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+				gPipeline.mTextureMatrixOps++;
 			}
 			params.mTexture->addTextureStats(params.mVSize);
 		}
@@ -545,14 +432,14 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 			LLImageGL::unbindTexture(0);
 		}
 	}
-
+	
 	if (params.mVertexBuffer.notNull())
 	{
 		params.mVertexBuffer->setBuffer(mask);
-		U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer();
+		U16* indices_pointer = (U16*) params.mVertexBuffer->getIndicesPointer();
 		glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount,
-							GL_UNSIGNED_INT, indices_pointer+params.mOffset);
-		gPipeline.mTrianglesDrawn += params.mCount/3;
+							GL_UNSIGNED_SHORT, indices_pointer+params.mOffset);
+		gPipeline.addTrianglesDrawn(params.mCount/3);
 	}
 
 	if (params.mTextureMatrix && texture && params.mTexture.notNull())
@@ -562,52 +449,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	}
 }
 
-void LLRenderPass::renderActive(U32 type, U32 mask, BOOL texture)
-{
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(mask);
-#endif
-
-	LLSpatialBridge* last_bridge = NULL;
-	glPushMatrix();
-	
-	for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (!group->isDead() &&
-			gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
-			group->mDrawMap.find(type) != group->mDrawMap.end())
-		{
-			LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition;
-			if (bridge != last_bridge)
-			{
-				glPopMatrix();
-				glPushMatrix();
-				glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix);
-				last_bridge = bridge;
-			}
-
-			renderGroup(group,type,mask,texture);
-		}
-	}
-	
-	glPopMatrix();
-}
-
-void LLRenderPass::renderStatic(U32 type, U32 mask, BOOL texture)
+void LLRenderPass::renderGroups(U32 type, U32 mask, BOOL texture)
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(mask);
-#endif
-
-	for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mVisibleGroups.begin(); i != gPipeline.mVisibleGroups.end(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (!group->isDead() &&
-			gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
-			group->mDrawMap.find(type) != group->mDrawMap.end())
-		{
-			renderGroup(group,type,mask,texture);
-		}
-	}
+	gPipeline.renderGroups(this, type, mask, texture);
 }
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index cd85a55d34f..30a16a24ba6 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -43,8 +43,6 @@ class LLViewerImage;
 class LLSpatialGroup;
 class LLDrawInfo;
 
-#define DEFAULT_MAX_VERTICES 65535
-
 class LLDrawPool
 {
 public:
@@ -53,18 +51,18 @@ class LLDrawPool
 	enum
 	{
 		// Correspond to LLPipeline render type
-		POOL_SKY = 1,
-		POOL_STARS,
-		POOL_GROUND,
+		POOL_SIMPLE = 1,
 		POOL_TERRAIN,	
-		POOL_SIMPLE,
+		POOL_TREE,
+		POOL_SKY,
+		POOL_WL_SKY,
+		POOL_GROUND,
 		POOL_BUMP,
+		POOL_INVISIBLE,
 		POOL_AVATAR,
-		POOL_TREE,
+		POOL_WATER,
 		POOL_GLOW,
 		POOL_ALPHA,
-		POOL_WATER,
-		POOL_ALPHA_POST_WATER,
 		NUM_POOL_TYPES,
 	};
 	
@@ -82,7 +80,6 @@ class LLDrawPool
 	virtual S32	 getNumPasses() { return 1; }
 	virtual void render(S32 pass = 0) = 0;
 	virtual void prerender() = 0;
-	virtual S32 getMaterialAttribIndex() = 0;
 	virtual U32 getVertexDataMask() = 0;
 	virtual BOOL verify() const { return TRUE; }		// Verify that all data in the draw pool is correct!
 	virtual S32 getVertexShaderLevel() const { return mVertexShaderLevel; }
@@ -110,12 +107,14 @@ class LLRenderPass : public LLDrawPool
 	enum
 	{
 		PASS_SIMPLE = NUM_POOL_TYPES,
-		PASS_GLOW,
+		PASS_GRASS,
 		PASS_FULLBRIGHT,
 		PASS_INVISIBLE,
+		PASS_INVISI_SHINY,
+		PASS_FULLBRIGHT_SHINY,
 		PASS_SHINY,
 		PASS_BUMP,
-		PASS_GRASS,
+		PASS_GLOW,
 		PASS_ALPHA,
 		NUM_RENDER_TYPES,
 	};
@@ -123,17 +122,16 @@ class LLRenderPass : public LLDrawPool
 	LLRenderPass(const U32 type);
 	virtual ~LLRenderPass();
 	/*virtual*/ LLDrawPool* instancePool();
-	/*vritual*/ S32 getMaterialAttribIndex() { return -1; }
 	/*virtual*/ LLViewerImage* getDebugTexture() { return NULL; }
 	LLViewerImage* getTexture() { return NULL; }
 	BOOL isDead() { return FALSE; }
 	void resetDrawOrders() { }
 
+	static void applyModelMatrix(LLDrawInfo& params);
+	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE);
 	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderStatic(U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderActive(U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void renderInvisible(U32 mask);
+	virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE);
 	virtual void renderTexture(U32 type, U32 mask);
 
 };
@@ -179,8 +177,6 @@ class LLFacePool : public LLDrawPool
 	static S32 drawLoopSetTex(face_array_t& face_list, S32 stage);
 	void drawLoop();
 
-	void renderVisibility();
-
 	void addFaceReference(LLFace *facep);
 	void removeFaceReference(LLFace *facep);
 
@@ -235,4 +231,5 @@ class LLFacePool : public LLDrawPool
 	};
 };
 
+
 #endif //LL_LLDRAWPOOL_H
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 0cba2c2923f..4428854369a 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -48,20 +48,20 @@
 #include "llviewerobjectlist.h" // For debugging
 #include "llviewerwindow.h"
 #include "pipeline.h"
-#include "llviewerregion.h"
 #include "llglslshader.h"
+#include "llviewerregion.h"
+#include "lldrawpoolwater.h"
+#include "llspatialpartition.h"
 
 BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
-LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
-	LLRenderPass(type)
-{
 
-}
 
-LLDrawPoolAlphaPostWater::LLDrawPoolAlphaPostWater()
-: LLDrawPoolAlpha(POOL_ALPHA_POST_WATER)
+LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
+		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
+		simple_shader(NULL), fullbright_shader(NULL)
 {
+
 }
 
 LLDrawPoolAlpha::~LLDrawPoolAlpha()
@@ -76,61 +76,58 @@ void LLDrawPoolAlpha::prerender()
 
 void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_COLOR_ARRAY);
-}
-
-void setup_clip_plane(BOOL pre_water)
-{
-	F32 height = gAgent.getRegion()->getWaterHeight();
-	BOOL above = gCamera->getOrigin().mV[2] > height ? TRUE : FALSE;
 	
-	F64 plane[4];
-	
-	plane[0] = 0;
-	plane[1] = 0;
-	plane[2] = above == pre_water ? -1.0 : 1.0;
-	plane[3] = -plane[2] * height;
-	
-	glClipPlane(GL_CLIP_PLANE0, plane);
-}
-
-void LLDrawPoolAlphaPostWater::render(S32 pass)
-{
-    LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
-
-	if (gPipeline.hasRenderType(LLDrawPool::POOL_ALPHA))
+	if (LLPipeline::sUnderWaterRender)
 	{
-		LLGLEnable clip(GL_CLIP_PLANE0);
-		setup_clip_plane(FALSE);
-		LLDrawPoolAlpha::render(gPipeline.mAlphaGroupsPostWater);
+		simple_shader = &gObjectSimpleWaterProgram;
+		fullbright_shader = &gObjectFullbrightWaterProgram;
 	}
 	else
 	{
-		LLDrawPoolAlpha::render(gPipeline.mAlphaGroupsPostWater);
+		simple_shader = &gObjectSimpleProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
 	}
+
+	if (mVertexShaderLevel > 0)
+	{
+		// Start out with no shaders.
+		current_shader = target_shader = NULL;
+		glUseProgramObjectARB(0);
+	}
+	gPipeline.enableLightsDynamic();
 }
 
-void LLDrawPoolAlpha::render(S32 pass)
+void LLDrawPoolAlpha::endRenderPass( S32 pass )
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
-	
-	LLGLEnable clip(GL_CLIP_PLANE0);
-	setup_clip_plane(TRUE);
-	render(gPipeline.mAlphaGroups);
+	LLRenderPass::endRenderPass(pass);
+
+	if(gPipeline.canUseWindLightShaders()) 
+	{
+		glUseProgramObjectARB(0);
+	}
 }
 
-void LLDrawPoolAlpha::render(std::vector<LLSpatialGroup*>& groups)
+void LLDrawPoolAlpha::render(S32 pass)
 {
-	LLGLDepthTest gls_depth(GL_TRUE);
-	LLGLSPipelineAlpha gls_pipeline_alpha;
+	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
 
-	gPipeline.enableLightsDynamic(1.f);
-	renderAlpha(getVertexDataMask(), groups);
+	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ? GL_TRUE : GL_FALSE);
+
+	LLGLSPipelineAlpha gls_pipeline_alpha;
+	
+	renderAlpha(getVertexDataMask());
 
 	if (sShowDebugAlpha)
 	{
+		if(gPipeline.canUseWindLightShaders()) 
+		{
+			glUseProgramObjectARB(0);
+		}
 		glDisableClientState(GL_NORMAL_ARRAY);
 		glDisableClientState(GL_COLOR_ARRAY);
 		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
@@ -138,90 +135,39 @@ void LLDrawPoolAlpha::render(std::vector<LLSpatialGroup*>& groups)
 		LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f);
         LLViewerImage::sSmokeImagep->bind();
 		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD, groups);
+							LLVertexBuffer::MAP_TEXCOORD);
 	}
 }
 
-void LLDrawPoolAlpha::renderAlpha(U32 mask, std::vector<LLSpatialGroup*>& groups)
+void LLDrawPoolAlpha::renderAlpha(U32 mask)
 {
 #if !LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkClientArrays(mask);
 #endif
-
-	LLSpatialBridge* last_bridge = NULL;
-	LLSpatialPartition* last_part = NULL;
-	glPushMatrix();
-	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
-	for (std::vector<LLSpatialGroup*>::iterator i = groups.begin(); i != groups.end(); ++i)
+	
+	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (group->mSpatialPartition->mRenderByGroup &&
 			!group->isDead())
 		{
-			LLSpatialPartition* part = group->mSpatialPartition;
-			if (part != last_part)
-			{
-				LLSpatialBridge* bridge = part->asBridge();
-				if (bridge != last_bridge)
-				{
-					glPopMatrix();
-					glPushMatrix();
-					if (bridge)
-					{
-						glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix);
-					}
-					last_bridge = bridge;
-				}
-
-//				if (!last_part || part->mDepthMask != last_part->mDepthMask)
-//				{
-//					glDepthMask(part->mDepthMask);
-//				}
-				last_part = part;
-			}
-
 			renderGroupAlpha(group,LLRenderPass::PASS_ALPHA,mask,TRUE);
 		}
 	}
-	
-	glPopMatrix();
 }
 
-void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask, std::vector<LLSpatialGroup*>& groups)
+void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 {
 #if !LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkClientArrays(mask);
 #endif
 
-	LLSpatialBridge* last_bridge = NULL;
-	LLSpatialPartition* last_part = NULL;
-	glPushMatrix();
-	
-	for (std::vector<LLSpatialGroup*>::iterator i = groups.begin(); i != groups.end(); ++i)
+	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (group->mSpatialPartition->mRenderByGroup &&
 			!group->isDead())
 		{
-			LLSpatialPartition* part = group->mSpatialPartition;
-			if (part != last_part)
-			{
-				LLSpatialBridge* bridge = part->asBridge();
-				if (bridge != last_bridge)
-				{
-					glPopMatrix();
-					glPushMatrix();
-					if (bridge)
-					{
-						glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix);
-					}
-					last_bridge = bridge;
-				}
-				
-				last_part = part;
-			}
-
 			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];	
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
@@ -232,104 +178,135 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask, std::vector<LLSpatialGroup*
 				{
 					continue;
 				}
+
+				LLRenderPass::applyModelMatrix(params);
+
 				params.mVertexBuffer->setBuffer(mask);
-				U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer();
+				U16* indices_pointer = (U16*) params.mVertexBuffer->getIndicesPointer();
 				glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount,
-									GL_UNSIGNED_INT, indices_pointer+params.mOffset);
-				
-				addIndicesDrawn(params.mCount);
+									GL_UNSIGNED_SHORT, indices_pointer+params.mOffset);
+				gPipeline.addTrianglesDrawn(params.mCount/3);
 			}
 		}
 	}
-	glPopMatrix();
 }
 
 void LLDrawPoolAlpha::renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
-{					
+{
+	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
-
-	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];	
+	BOOL is_particle = FALSE;
+	BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders())
+		|| gPipeline.canUseWindLightShadersOnObjects();
+	F32 dist;
+
+	// check to see if it's a particle and if it's "close"
+	is_particle = !LLPipeline::sUnderWaterRender && (group->mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_PARTICLES);
+	dist = group->mDistance;
 	
-	U32 prim_type = GL_TRIANGLES;
+	// don't use shader if debug setting is off and it's close or if it's a particle
+	// and it's close
+	if(is_particle && !gSavedSettings.getBOOL("RenderUseShaderNearParticles"))
+	{
+		if((dist < gCamera->getFar() * gSavedSettings.getF32("RenderShaderParticleThreshold")))
+		{
+			use_shaders = FALSE;
+		}
+	}
 
-	//F32 width = (F32) gViewerWindow->getWindowDisplayWidth();
+	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
 
-	//F32 view = gCamera->getView();
-	
 	if (group->mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_CLOUDS)
-	{
+	{		
+		if (!gSavedSettings.getBOOL("SkyUseClassicClouds"))
+		{
+			return;
+		}
+		// *TODO - Uhhh, we should always be doing some type of alpha rejection.  These should probably both be 0.01f
 		glAlphaFunc(GL_GREATER, 0.f);
 	}
 	else
 	{
-		glAlphaFunc(GL_GREATER, 0.01f);
+		if (LLPipeline::sImpostorRender)
+		{
+			glAlphaFunc(GL_GREATER, 0.5f);
+		}
+		else
+		{
+			glAlphaFunc(GL_GREATER, 0.01f);
+		}
 	}
 
-	/*LLGLEnable point_sprite(GL_POINT_SPRITE_ARB);
-
-	if (gGLManager.mHasPointParameters)
-	{
-		glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
-		glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 0.f);
-		glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, width*16.f);
-		glPointSize(width/(view*view));
-	}*/
-
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 	{
 		LLDrawInfo& params = **k;
+
+		LLRenderPass::applyModelMatrix(params);
+
 		if (texture && params.mTexture.notNull())
 		{
+			glActiveTextureARB(GL_TEXTURE0_ARB);
 			params.mTexture->bind();
 			params.mTexture->addTextureStats(params.mVSize);
 			if (params.mTextureMatrix)
 			{
 				glMatrixMode(GL_TEXTURE);
 				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+				gPipeline.mTextureMatrixOps++;
 			}
 		}
-		
+
 		if (params.mFullbright)
 		{
-			if (light_enabled)
+			// Turn off lighting if it hasn't already been so.
+			if (light_enabled || !initialized_lighting)
 			{
-				gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-				light_enabled = FALSE;
-				if (LLPipeline::sRenderGlow)
+				initialized_lighting = TRUE;
+				if (use_shaders) 
 				{
-					glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+					target_shader = fullbright_shader;
 				}
+				else
+				{
+					gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+				}
+				light_enabled = FALSE;
 			}
 		}
-		else if (!light_enabled)
+		// Turn on lighting if it isn't already.
+		else if (!light_enabled || !initialized_lighting)
 		{
-			gPipeline.enableLightsDynamic(1.f);
-			light_enabled = TRUE;
-			if (LLPipeline::sRenderGlow)
+			initialized_lighting = TRUE;
+			if (use_shaders) 
+			{
+				target_shader = simple_shader;
+			}
+			else
 			{
-				glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+				gPipeline.enableLightsDynamic();
 			}
+			light_enabled = TRUE;
 		}
 
-		/*if (params.mParticle)
+		// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+		// (this way we won't rebind shaders unnecessarily).
+		if(use_shaders && (current_shader != target_shader))
 		{
-			F32 size = params.mPartSize;
-			size *= size;
-			float param[] = { 0, 0, 0.01f/size*view*view };
-			prim_type = GL_POINTS;
-			glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, param);
+			llassert(target_shader != NULL);
+			current_shader = target_shader;
+			current_shader->bind();
 		}
-		else*/
+		else if (!use_shaders && current_shader != NULL)
 		{
-			prim_type = GL_TRIANGLES;
+			glUseProgramObjectARB(0);
+			current_shader = NULL;
 		}
 
 		params.mVertexBuffer->setBuffer(mask);
-		U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer();
-		glDrawRangeElements(prim_type, params.mStart, params.mEnd, params.mCount,
-							GL_UNSIGNED_INT, indices_pointer+params.mOffset);
-		
-		addIndicesDrawn(params.mCount);
+		U16* indices_pointer = (U16*) params.mVertexBuffer->getIndicesPointer();
+		glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount,
+							GL_UNSIGNED_SHORT, indices_pointer+params.mOffset);
+		gPipeline.addTrianglesDrawn(params.mCount/3);
 
 		if (params.mTextureMatrix && texture && params.mTexture.notNull())
 		{
@@ -340,19 +317,6 @@ void LLDrawPoolAlpha::renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask
 
 	if (!light_enabled)
 	{
-		gPipeline.enableLightsDynamic(1.f);
-	
-		if (LLPipeline::sRenderGlow)
-		{
-			glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-		}
+		gPipeline.enableLightsDynamic();
 	}
-
-	/*glPointSize(1.f);
-
-	if (gGLManager.mHasPointParameters)
-	{
-		float param[] = {1, 0, 0 };
-		glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, param);
-	}*/
-}	
+}
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 0e390035513..637ea25f803 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -37,6 +37,7 @@
 
 class LLFace;
 class LLColor4;
+class LLGLSLShader;
 
 class LLDrawPoolAlpha: public LLRenderPass
 {
@@ -54,15 +55,26 @@ class LLDrawPoolAlpha: public LLRenderPass
 	/*virtual*/ ~LLDrawPoolAlpha();
 
 	/*virtual*/ void beginRenderPass(S32 pass = 0);
+	/*virtual*/ void endRenderPass( S32 pass );
+	/*virtual*/ S32	 getNumPasses() { return 1; }
+
 	virtual void render(S32 pass = 0);
-	void render(std::vector<LLSpatialGroup*>& groups);
 	/*virtual*/ void prerender();
 
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	void renderAlpha(U32 mask, std::vector<LLSpatialGroup*>& groups);
-	void renderAlphaHighlight(U32 mask, std::vector<LLSpatialGroup*>& groups);
+	void renderAlpha(U32 mask);
+	void renderAlphaHighlight(U32 mask);
 	
 	static BOOL sShowDebugAlpha;
+
+private:
+	S32 mDiffuse;
+	LLGLSLShader* current_shader;
+	LLGLSLShader* target_shader;
+	LLGLSLShader* simple_shader;
+	LLGLSLShader* simple_lod_shader;
+	LLGLSLShader* fullbright_shader;	
+	LLGLSLShader* fullbright_lod_shader;
 };
 
 class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 9df9c115316..316c002c1b4 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -32,6 +32,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "lldrawpoolavatar.h"
+#include "llglimmediate.h"
 
 #include "llvoavatar.h"
 #include "m3math.h"
@@ -142,20 +143,33 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 
 S32 LLDrawPoolAvatar::getNumPasses()
 {
-	return 3;
+	return LLPipeline::sImpostorRender ? 1 : 3;
 }
 
 void LLDrawPoolAvatar::render(S32 pass)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+	if (LLPipeline::sImpostorRender)
+	{
+		renderAvatars(NULL, 2);
+		return;
+	}
+
 	renderAvatars(NULL, pass); // render all avatars
 }
 
 void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
 	//reset vertex buffer mappings
 	LLVertexBuffer::unbind();
 
+	if (LLPipeline::sImpostorRender)
+	{
+		beginSkinned();
+		return;
+	}
+
 	switch (pass)
 	{
 	case 0:
@@ -172,6 +186,14 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::endRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+
+	if (LLPipeline::sImpostorRender)
+	{
+		endSkinned();
+		return;
+	}
+
 	switch (pass)
 	{
 	case 0:
@@ -187,31 +209,47 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 
 void LLDrawPoolAvatar::beginFootShadow()
 {
-	glDepthMask(GL_FALSE);
+	if (!LLPipeline::sReflectionRender)
+	{
+		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
+		LLVOAvatar::sNumVisibleAvatars = 0;
+	}
+
 	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
 void LLDrawPoolAvatar::endFootShadow()
 {
-	gPipeline.enableLightsDynamic(1.f);
-	glDepthMask(GL_TRUE);
+	gPipeline.enableLightsDynamic();
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
 void LLDrawPoolAvatar::beginRigid()
 {
-	sVertexProgram = NULL;
-	sShaderLevel = 0;
+	if (gPipeline.canUseVertexShaders())
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectSimpleWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectSimpleProgram;
+		}
+		
+		if (sVertexProgram != NULL)
+		{	//eyeballs render with the specular shader
+			sVertexProgram->bind();
+		}
+	}
+	else
+	{
+		sVertexProgram = NULL;
+	}
+
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	/*if (sShaderLevel > 0)
-	{	//eyeballs render with the specular shader
-		gAvatarEyeballProgram.bind();
-		gMaterialIndex = gAvatarEyeballProgram.mAttribute[LLShaderMgr::MATERIAL_COLOR];
-		gSpecularIndex = gAvatarEyeballProgram.mAttribute[LLShaderMgr::SPECULAR_COLOR];
-	}*/
 }
 
 void LLDrawPoolAvatar::endRigid()
@@ -219,6 +257,10 @@ void LLDrawPoolAvatar::endRigid()
 	sShaderLevel = mVertexShaderLevel;
 	glDisableClientState(GL_NORMAL_ARRAY);
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	if (sVertexProgram != NULL)
+	{
+		sVertexProgram->unbind();
+	}
 }
 
 void LLDrawPoolAvatar::beginSkinned()
@@ -226,17 +268,35 @@ void LLDrawPoolAvatar::beginSkinned()
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
-	sVertexProgram = &gAvatarProgram;
-
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gAvatarWaterProgram;
+			sShaderLevel = llmin((U32) 1, sShaderLevel);
+		}
+		else
+		{
+			sVertexProgram = &gAvatarProgram;
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectSimpleWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectSimpleProgram;
+		}
+	}
+	
 	if (sShaderLevel > 0)  // for hardware blending
 	{
 		sRenderingSkinned = TRUE;
 		glClientActiveTextureARB(GL_TEXTURE1_ARB);
-		if (sShaderLevel >= SHADER_LEVEL_BUMP)
-		{
-			gMaterialIndex = sVertexProgram->mAttribute[LLShaderMgr::MATERIAL_COLOR];
-			gSpecularIndex = sVertexProgram->mAttribute[LLShaderMgr::SPECULAR_COLOR];
-		}
+
 		sVertexProgram->bind();
 		if (sShaderLevel >= SHADER_LEVEL_CLOTH)
 		{
@@ -252,6 +312,15 @@ void LLDrawPoolAvatar::beginSkinned()
 		sVertexProgram->enableTexture(LLShaderMgr::BUMP_MAP);
 		glActiveTextureARB(GL_TEXTURE0_ARB);
 	}
+	else
+	{
+		if(gPipeline.canUseVertexShaders())
+		{
+			// software skinning, use a basic shader for windlight.
+			// TODO: find a better fallback method for software skinning.
+			sVertexProgram->bind();
+		}
+	}
 }
 
 void LLDrawPoolAvatar::endSkinned()
@@ -274,6 +343,16 @@ void LLDrawPoolAvatar::endSkinned()
 		}
 
 		sVertexProgram->unbind();
+		sShaderLevel = mVertexShaderLevel;
+	}
+	else
+	{
+		if(gPipeline.canUseVertexShaders())
+		{
+			// software skinning, use a basic shader for windlight.
+			// TODO: find a better fallback method for software skinning.
+			sVertexProgram->unbind();
+		}
 	}
 
 	glActiveTextureARB(GL_TEXTURE0_ARB);
@@ -299,6 +378,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
+	
+
 	if (!gRenderAvatar)
 	{
 		return;
@@ -330,60 +411,50 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
-    LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f);
+	BOOL impostor = avatarp->isImpostor() && !single_avatar;
+
+	if (impostor && pass != 0)
+	{ //don't draw anything but the impostor for impostored avatars
+		return;
+	}
 	
+	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
+	{ //don't draw foot shadows under water
+		return;
+	}
+
+    LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f);
+
 	if (pass == 0)
 	{
-		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS))
+		if (!LLPipeline::sReflectionRender)
+		{
+			LLVOAvatar::sNumVisibleAvatars++;
+		}
+
+		if (impostor)
+		{
+			avatarp->renderImpostor();
+		}
+		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS))
 		{
 			mIndicesDrawn += avatarp->renderFootShadows();	
 		}
 		return;
 	}
 
-	if (avatarp->mSpecialRenderMode == 0) // normal
-	{
-		gPipeline.enableLightsAvatar(avatarp->mDrawable->getSunShadowFactor());
-	}
-	else if (avatarp->mSpecialRenderMode == 1)  // anim preview
-	{
-		gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
-	}
-	else // 2=image preview,  3=morph view
+	if (single_avatar && avatarp->mSpecialRenderMode >= 2) // 2=image preview,  3=morph view
 	{
 		gPipeline.enableLightsAvatarEdit(LLColor4(.5f, .5f, .5f, 1.f));
 	}
-
+	
 	if (pass == 1)
 	{
 		// render rigid meshes (eyeballs) first
 		mIndicesDrawn += avatarp->renderRigid();
-
-		if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest)
-		{
-			LLVector3 orig_pos_root = avatarp->mRoot.getPosition();
-			LLVector3 next_pos_root = orig_pos_root;
-			for (S32 i = 0; i < NUM_TEST_AVATARS; i++)
-			{
-				next_pos_root.mV[VX] += 1.f;
-				if (i % 5 == 0)
-				{
-					next_pos_root.mV[VY] += 1.f;
-					next_pos_root.mV[VX] = orig_pos_root.mV[VX];
-				}
-
-				avatarp->mRoot.setPosition(next_pos_root); // avatar load test
-				avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test
-
-				mIndicesDrawn += avatarp->renderRigid();
-			}
-			avatarp->mRoot.setPosition(orig_pos_root); // avatar load test
-			avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test
-		}
 		return;
 	}
 	
-
 	if (sShaderLevel > 0)
 	{
 		gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX];
@@ -427,79 +498,57 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 			LLGLSNoTexture gls_no_texture;
 			LLVector3 pos = avatarp->getPositionAgent();
 
-			color.setColor(1.0f, 0.0f, 0.0f, 0.8f);
-			glBegin(GL_LINES);
+			gGL.color4f(1.0f, 0.0f, 0.0f, 0.8f);
+			gGL.begin(GL_LINES);
 			{
-				glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
-			}glEnd();
+				gGL.vertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
+			}gGL.end();
 
 			pos = avatarp->mDrawable->getPositionAgent();
-			color.setColor(1.0f, 0.0f, 0.0f, 0.8f);
-			glBegin(GL_LINES);
+			gGL.color4f(1.0f, 0.0f, 0.0f, 0.8f);
+			gGL.begin(GL_LINES);
 			{
-				glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
-			}glEnd();
+				gGL.vertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
+			}gGL.end();
 
 			pos = avatarp->mRoot.getWorldPosition();
-			color.setColor(1.0f, 1.0f, 1.0f, 0.8f);
-			glBegin(GL_LINES);
+			gGL.color4f(1.0f, 1.0f, 1.0f, 0.8f);
+			gGL.begin(GL_LINES);
 			{
-				glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
-			}glEnd();
+				gGL.vertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
+			}gGL.end();
 
 			pos = avatarp->mPelvisp->getWorldPosition();
-			color.setColor(0.0f, 0.0f, 1.0f, 0.8f);
-			glBegin(GL_LINES);
+			gGL.color4f(0.0f, 0.0f, 1.0f, 0.8f);
+			gGL.begin(GL_LINES);
 			{
-				glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
-				glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
-				glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
-			}glEnd();	
+				gGL.vertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
+				gGL.vertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
+				gGL.vertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
+			}gGL.end();	
 
 			color.setColor(1.0f, 1.0f, 1.0f, 1.0f);
 		}
 
 		mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
-				
-		if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest)
-		{
-			LLVector3 orig_pos_root = avatarp->mRoot.getPosition();
-			LLVector3 next_pos_root = orig_pos_root;
-			for (S32 i = 0; i < NUM_TEST_AVATARS; i++)
-			{
-				next_pos_root.mV[VX] += 1.f;
-				if (i % 5 == 0)
-				{
-					next_pos_root.mV[VY] += 1.f;
-					next_pos_root.mV[VX] = orig_pos_root.mV[VX];
-				}
-
-				avatarp->mRoot.setPosition(next_pos_root); // avatar load test
-				avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test
-
-				mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
-			}
-			avatarp->mRoot.setPosition(orig_pos_root); // avatar load test
-			avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test
-		}
 	}
 }
 
@@ -535,6 +584,31 @@ void LLDrawPoolAvatar::renderForSelect()
 		return;
 	}
 
+	S32 name = avatarp->mDrawable->getVObj()->mGLName;
+	LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name);
+
+	BOOL impostor = avatarp->isImpostor();
+	if (impostor)
+	{
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
+		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_REPLACE);
+		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_MODULATE);
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_PRIMARY_COLOR);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_TEXTURE);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB,		GL_PRIMARY_COLOR_ARB);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB,	GL_SRC_ALPHA);
+
+		avatarp->renderImpostor(color);
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+		return;
+	}
+
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -544,15 +618,10 @@ void LLDrawPoolAvatar::renderForSelect()
 		gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX];
 	}
 	glAlphaFunc(GL_GEQUAL, 0.2f);
-	glBlendFunc(GL_ONE, GL_ZERO);
+	gGL.blendFunc(GL_ONE, GL_ZERO);
 
-	S32 name = avatarp->mDrawable->getVObj()->mGLName;
-	LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name);
 	glColor4ubv(color.mV);
 
-	// render rigid meshes (eyeballs) first
-	//mIndicesDrawn += avatarp->renderRigid();
-
 	if ((sShaderLevel > 0) && !gUseGLPick)  // for hardware blending
 	{
 		glClientActiveTextureARB(GL_TEXTURE0_ARB);
@@ -572,7 +641,7 @@ void LLDrawPoolAvatar::renderForSelect()
 	}
 
 	glAlphaFunc(GL_GREATER, 0.01f);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	// restore texture mode
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 1aa91bb69a5..2de32de5421 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -53,9 +53,7 @@ class LLDrawPoolAvatar : public LLFacePool
 							LLVertexBuffer::MAP_NORMAL |
 							LLVertexBuffer::MAP_TEXCOORD |
 							LLVertexBuffer::MAP_WEIGHT |
-							LLVertexBuffer::MAP_CLOTHWEIGHT |
-							LLVertexBuffer::MAP_BINORMAL
-							
+							LLVertexBuffer::MAP_CLOTHWEIGHT
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
@@ -86,8 +84,6 @@ class LLDrawPoolAvatar : public LLFacePool
 	/*virtual*/ LLViewerImage *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
-	virtual S32 getMaterialAttribIndex() { return 0; }
-
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
 };
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 4de13a3d885..f4bc1571686 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -40,17 +40,19 @@
 #include "m3math.h"
 #include "m4math.h"
 #include "v4math.h"
+#include "llglheaders.h"
+#include "llglimmediate.h"
 
 #include "llagent.h"
 #include "llcubemap.h"
 #include "lldrawable.h"
-#include "lldrawpoolsimple.h"
 #include "llface.h"
 #include "llsky.h"
 #include "lltextureentry.h"
 #include "llviewercamera.h"
 #include "llviewerimagelist.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llglslshader.h"
 
 //#include "llimagebmp.h"
@@ -73,6 +75,10 @@ const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEX
 U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY;
 static LLCubeMap* sCubeMap = NULL;
 
+static LLGLSLShader* shader = NULL;
+static S32 cube_channel = -1;
+static S32 diffuse_channel = -1;
+
 // static 
 void LLStandardBumpmap::init()
 {
@@ -158,8 +164,9 @@ void LLStandardBumpmap::destroyGL()
 ////////////////////////////////////////////////////////////////
 
 LLDrawPoolBump::LLDrawPoolBump() 
-: LLRenderPass(LLDrawPool::POOL_BUMP)
+:  LLRenderPass(LLDrawPool::POOL_BUMP)
 {
+	mShiny = FALSE;
 }
 
 
@@ -173,7 +180,25 @@ S32 LLDrawPoolBump::numBumpPasses()
 {
 	if (gSavedSettings.getBOOL("RenderObjectBump"))
 	{
-		return 2;
+		if (mVertexShaderLevel > 1)
+		{
+			if (LLPipeline::sImpostorRender)
+			{
+				return 2;
+			}
+			else
+			{
+				return 3;
+			}
+		}
+		else if (LLPipeline::sImpostorRender)
+		{
+			return 1;
+		}
+		else
+		{
+			return 2;
+		}
 	}
     else
 	{
@@ -188,12 +213,23 @@ S32 LLDrawPoolBump::getNumPasses()
 
 void LLDrawPoolBump::beginRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP);
 	switch( pass )
 	{
 		case 0:
 			beginShiny();
 			break;
 		case 1:
+			if (mVertexShaderLevel > 1)
+			{
+				beginFullbrightShiny();
+			}
+			else 
+			{
+				beginBump();
+			}
+			break;
+		case 2:
 			beginBump();
 			break;
 		default:
@@ -213,32 +249,47 @@ void LLDrawPoolBump::render(S32 pass)
 	
 	switch( pass )
 	{
-	  case 0:
-	  {
-		  renderShiny();
-		  break;
-	  }
-	  case 1:
-	  {
-		  renderBump();
-		  break;
-	  }
-	  default:
-	  {
-		  llassert(0);
-		  break;
-	  }
+		case 0:
+			renderShiny();
+			break;
+		case 1:
+			if (mVertexShaderLevel > 1)
+			{
+				renderFullbrightShiny();
+			}
+			else 
+			{
+				renderBump(); 
+			}
+			break;
+		case 2:
+			renderBump();
+			break;
+		default:
+			llassert(0);
+			break;
 	}
 }
 
 void LLDrawPoolBump::endRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP);
 	switch( pass )
 	{
 		case 0:
 			endShiny();
 			break;
 		case 1:
+			if (mVertexShaderLevel > 1)
+			{
+				endFullbrightShiny();
+			}
+			else 
+			{
+				endBump();
+			}
+			break;
+		case 2:
 			endBump();
 			break;
 		default:
@@ -248,36 +299,77 @@ void LLDrawPoolBump::endRenderPass(S32 pass)
 }
 
 //static
-void LLDrawPoolBump::beginShiny()
+void LLDrawPoolBump::beginShiny(bool invisible)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
+	if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 
+		invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
+	{
+		return;
+	}
+
+	mShiny = TRUE;
 	sVertexMask = VERTEX_MASK_SHINY;
 	// Second pass: environment map
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_COLOR_ARRAY);
+	if (!invisible && mVertexShaderLevel > 1)
+	{
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD;
+	}
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		shader = &gObjectShinyWaterProgram;
+	}
+	else
+	{
+		shader = &gObjectShinyProgram;
+	}
 
-	LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap();
+	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		cube_map->enable(0);
-		cube_map->setMatrix(0);
-		cube_map->bind();
-
-		if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0)
+		if (!invisible && LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0 )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
 						 LLVector4(gGLModelView+4),
 						 LLVector4(gGLModelView+8),
 						 LLVector4(gGLModelView+12));
-			gObjectShinyProgram.bind();
+			shader->bind();
 			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
-			glUniform4fvARB(gObjectShinyProgram.mUniform[LLShaderMgr::SHINY_ORIGIN], 1,
-				vec4.mV);
+			shader->uniform4fv(LLShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+			if (mVertexShaderLevel > 1)
+			{
+				cube_map->setMatrix(1);
+				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
+				// the cube map in the one pass shiny shaders
+				cube_channel = shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+				cube_map->enableTexture(cube_channel);
+				cube_map->enableTextureCoords(1);
+				diffuse_channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+			}
+			else
+			{
+				cube_channel = 0;
+				diffuse_channel = -1;
+				cube_map->setMatrix(0);
+				cube_map->enable(shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB));
+			}			
+			cube_map->bind();
 		}
 		else
 		{
+			cube_channel = 0;
+			diffuse_channel = -1;
+			cube_map->enable(0);
+			cube_map->setMatrix(0);
+			cube_map->bind();
+
 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,	GL_COMBINE_ARB);
 			
 			//use RGB from texture
@@ -293,63 +385,188 @@ void LLDrawPoolBump::beginShiny()
 	}
 }
 
-void LLDrawPoolBump::renderShiny()
+void LLDrawPoolBump::renderShiny(bool invisible)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
-	
+	if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 
+		invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
+	{
+		return;
+	}
+
 	sCubeMap = NULL;
 
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
 		LLGLEnable blend_enable(GL_BLEND);
-		renderStatic(LLRenderPass::PASS_SHINY, sVertexMask);
-		renderActive(LLRenderPass::PASS_SHINY, sVertexMask);
+		if (!invisible && mVertexShaderLevel > 1)
+		{
+			LLRenderPass::renderTexture(LLRenderPass::PASS_SHINY, sVertexMask);
+		}
+		else if (!invisible)
+		{
+			renderGroups(LLRenderPass::PASS_SHINY, sVertexMask);
+		}
+		else // invisible
+		{
+			renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
+		}
 	}
 }
 
-void LLDrawPoolBump::renderActive(U32 type, U32 mask, BOOL texture)
+void LLDrawPoolBump::endShiny(bool invisible)
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(mask);
-#endif
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
+	if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 
+		invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
+	{
+		return;
+	}
 
-	LLSpatialBridge* last_bridge = NULL;
-	glPushMatrix();
-	
-	for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i)
+	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+	if( cube_map )
 	{
-		LLSpatialGroup* group = *i;
-		if (!group->isDead() &&
-			gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
-			group->mDrawMap.find(type) != group->mDrawMap.end())
+		cube_map->disable();
+		cube_map->restoreMatrix();
+
+		if (!invisible && mVertexShaderLevel > 1)
 		{
-			LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition;
-			if (bridge != last_bridge)
+			shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+					
+			if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0)
 			{
-				glPopMatrix();
-				glPushMatrix();
-				glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix);
-				last_bridge = bridge;
-
-				if (LLPipeline::sDynamicReflections)
+				if (diffuse_channel != 0)
 				{
-					LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME);
-					LLSpatialGroup::OctreeNode* node = part->mOctree->getNodeAt(LLVector3d(bridge->mDrawable->getPositionAgent()), 32.0);
-					if (node)
-					{
-						sCubeMap = ((LLSpatialGroup*) node->getListener(0))->mReflectionMap;
-					}
+					shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
 				}
 			}
 
-			renderGroup(group,type,mask,texture);
+			shader->unbind();
+			glActiveTextureARB(GL_TEXTURE0_ARB);
+			glEnable(GL_TEXTURE_2D);
 		}
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	}
 	
-	glPopMatrix();
+	LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	if (!invisible && mVertexShaderLevel > 1)
+	{
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	}
+
+	diffuse_channel = -1;
+	cube_channel = 0;
+	mShiny = FALSE;
 }
 
+void LLDrawPoolBump::beginFullbrightShiny()
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
+	{
+		return;
+	}
+
+	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD;
+
+	// Second pass: environment map
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_NORMAL_ARRAY);
+	glEnableClientState(GL_COLOR_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		shader = &gObjectShinyWaterProgram;
+	}
+	else
+	{
+		shader = &gObjectFullbrightShinyProgram;
+	}
 
+	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+	if( cube_map )
+	{
+		LLMatrix4 mat;
+		mat.initRows(LLVector4(gGLModelView+0),
+					 LLVector4(gGLModelView+4),
+					 LLVector4(gGLModelView+8),
+					 LLVector4(gGLModelView+12));
+		shader->bind();
+		LLVector3 vec = LLVector3(gShinyOrigin) * mat;
+		LLVector4 vec4(vec, gShinyOrigin.mV[3]);
+		shader->uniform4fv(LLShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+
+		cube_map->setMatrix(1);
+		// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
+		// the cube map in the one pass shiny shaders
+		cube_channel = shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+		cube_map->enableTexture(cube_channel);
+		cube_map->enableTextureCoords(1);
+		diffuse_channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+
+		cube_map->bind();
+	}
+	mShiny = TRUE;
+}
+
+void LLDrawPoolBump::renderFullbrightShiny()
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
+	{
+		return;
+	}
+
+	sCubeMap = NULL;
+
+	if( gSky.mVOSkyp->getCubeMap() )
+	{
+		LLGLEnable blend_enable(GL_BLEND);
+		LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+	}
+}
+
+void LLDrawPoolBump::endFullbrightShiny()
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
+	{
+		return;
+	}
+
+	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+	if( cube_map )
+	{
+		cube_map->disable();
+		cube_map->restoreMatrix();
+
+		if (diffuse_channel != 0)
+		{
+			shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+		}
+		glActiveTextureARB(GL_TEXTURE0_ARB);
+		glEnable(GL_TEXTURE_2D);
+
+		shader->unbind();
+
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	}
+	
+	LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	diffuse_channel = -1;
+	cube_channel = 0;
+	mShiny = FALSE;
+}
 
 void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE)
 {					
@@ -366,6 +583,11 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 			}
 			else
 			{
+				if (params.mModelMatrix)
+				{
+					sCubeMap = gPipeline.findReflectionMap(params.mModelMatrix->getTranslation());	
+				}
+
 				if (sCubeMap)
 				{
 					sCubeMap->bind();
@@ -377,34 +599,14 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 			}
 		}
 		
+		applyModelMatrix(params);
+
 		params.mVertexBuffer->setBuffer(mask);
-		U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer();
+		U16* indices_pointer = (U16*) params.mVertexBuffer->getIndicesPointer();
 		glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount,
-							GL_UNSIGNED_INT, indices_pointer+params.mOffset);
-		gPipeline.mTrianglesDrawn += params.mCount/3;
-	}
-}
-
-void LLDrawPoolBump::endShiny()
-{
-	LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap();
-	if( cube_map )
-	{
-		cube_map->disable();
-		cube_map->restoreMatrix();
-
-		if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0)
-		{
-			gObjectShinyProgram.unbind();
-		}
-
-		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_MODULATE);
+							GL_UNSIGNED_SHORT, indices_pointer+params.mOffset);
+		gPipeline.addTrianglesDrawn(params.mCount/3);
 	}
-	
-	LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
-	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
 }
 
 
@@ -450,6 +652,11 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params)
 //static
 void LLDrawPoolBump::beginBump()
 {	
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+
 	sVertexMask = VERTEX_MASK_BUMP;
 	LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP);
 	// Optional second pass: emboss bump map
@@ -503,28 +710,41 @@ void LLDrawPoolBump::beginBump()
 	//		= 2 * ((1 + bump0 - bump1) / 2) * dst   [0 - 2 * dst]
 	//		= (1 + bump0 - bump1) * dst.rgb
 	//		= dst.rgb + dst.rgb * (bump0 - bump1)
-	glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
-//	glBlendFunc(GL_ONE, GL_ZERO);  // temp
+	gGL.blendFunc(GL_DST_COLOR, GL_SRC_COLOR);
+//	gGL.blendFunc(GL_ONE, GL_ZERO);  // temp
 	glActiveTextureARB(GL_TEXTURE0_ARB);
 	stop_glerror();
+
+	LLViewerImage::unbindTexture(1, GL_TEXTURE_2D);
 }
 
 //static
 void LLDrawPoolBump::renderBump()
 {
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+
 	LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP);
 	LLGLDisable fog(GL_FOG);
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_EQUAL);
-	LLGLEnable tex2d(GL_TEXTURE_2D);
+	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
 	LLGLEnable blend(GL_BLEND);
 	glColor4f(1,1,1,1);
+	/// Get rid of z-fighting with non-bump pass.
+	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(-1.0f, -1.0f);
 	renderBump(LLRenderPass::PASS_BUMP, sVertexMask);
-	renderBumpActive(LLRenderPass::PASS_BUMP, sVertexMask);
 }
 
 //static
 void LLDrawPoolBump::endBump()
 {
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+
 	// Disable texture unit 1
 	glActiveTextureARB(GL_TEXTURE1_ARB);
 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
@@ -538,7 +758,7 @@ void LLDrawPoolBump::endBump()
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	
-	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+	gGL.blendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 }
 
 ////////////////////////////////////////////////////////////////
@@ -864,47 +1084,16 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLIma
 	}
 }
 
-void LLDrawPoolBump::renderBumpActive(U32 type, U32 mask)
-{
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(mask);
-#endif
-
-	LLSpatialBridge* last_bridge = NULL;
-	glPushMatrix();
-	
-	for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (!group->isDead() && 
-			group->mSpatialPartition->mRenderByGroup &&
-			group->mDrawMap.find(type) != group->mDrawMap.end())
-		{
-			LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition;
-			if (bridge != last_bridge)
-			{
-				glPopMatrix();
-				glPushMatrix();
-				glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix);
-				last_bridge = bridge;
-			}
-
-			renderGroupBump(group,type,mask);
-		}
-	}
-	
-	glPopMatrix();
-}
-
 void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 {	
 #if !LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkClientArrays(mask);
 #endif
 
-	LLSpatialGroup::drawmap_elem_t& draw_info = gPipeline.mRenderMap[type];	
+	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
 
-	for (LLSpatialGroup::drawmap_elem_t::iterator i = draw_info.begin(); i != draw_info.end(); ++i)	
+	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
 	{
 		LLDrawInfo& params = **i;
 
@@ -932,25 +1121,96 @@ void LLDrawPoolBump::renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask)
 
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 {
+	applyModelMatrix(params);
+
 	if (params.mTextureMatrix)
 	{
-		glActiveTextureARB(GL_TEXTURE1_ARB);
-		glMatrixMode(GL_TEXTURE);
-		glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-		glActiveTextureARB(GL_TEXTURE0_ARB);
+		if (mShiny)
+		{
+			glActiveTextureARB(GL_TEXTURE0_ARB);
+			glMatrixMode(GL_TEXTURE);
+		}
+		else
+		{
+			glActiveTextureARB(GL_TEXTURE1_ARB);
+			glMatrixMode(GL_TEXTURE);
+			glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+			gPipeline.mTextureMatrixOps++;
+			glActiveTextureARB(GL_TEXTURE0_ARB);
+		}
+
 		glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+		gPipeline.mTextureMatrixOps++;
+	}
+
+	if (mShiny && mVertexShaderLevel > 1 && texture)
+	{
+		if (params.mTexture.notNull())
+		{
+			params.mTexture->bind(diffuse_channel);
+			params.mTexture->addTextureStats(params.mVSize);
+		}
+		else
+		{
+			LLImageGL::unbindTexture(0);
+		}
+
+		if (LLPipeline::sDynamicReflections)
+		{
+			LLCubeMap* cube_map = params.mReflectionMap;
+
+			if (!cube_map && params.mModelMatrix)
+			{
+				cube_map = gPipeline.findReflectionMap(params.mModelMatrix->getTranslation());
+			}
+
+			if (cube_map)
+			{
+				cube_map->enableTexture(cube_channel);
+				cube_map->bind();
+			}	
+		}
 	}
+	
 	params.mVertexBuffer->setBuffer(mask);
-	U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer();
+	U16* indices_pointer = (U16*) params.mVertexBuffer->getIndicesPointer();
 	glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount,
-						GL_UNSIGNED_INT, indices_pointer+params.mOffset);
-	gPipeline.mTrianglesDrawn += params.mCount/3;
+						GL_UNSIGNED_SHORT, indices_pointer+params.mOffset);
+	gPipeline.addTrianglesDrawn(params.mCount/3);
+
 	if (params.mTextureMatrix)
 	{
-		glActiveTextureARB(GL_TEXTURE1_ARB);
-		glLoadIdentity();
-		glActiveTextureARB(GL_TEXTURE0_ARB);
+		if (mShiny)
+		{
+			glActiveTextureARB(GL_TEXTURE0_ARB);
+		}
+		else
+		{
+			glActiveTextureARB(GL_TEXTURE1_ARB);
+			glLoadIdentity();
+			glActiveTextureARB(GL_TEXTURE0_ARB);
+		}
 		glLoadIdentity();
 		glMatrixMode(GL_MODELVIEW);
 	}
 }
+
+void LLDrawPoolInvisible::render(S32 pass)
+{ //render invisiprims
+	LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE);
+  
+	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
+	glStencilMask(0);
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+	glStencilMask(0xFFFFFFFF);
+
+	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
+	{
+		beginShiny(true);
+		renderShiny(true);
+		endShiny(true);
+	}
+}
+
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 15d84639fe0..ae722b2fd38 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -43,31 +43,36 @@ class LLDrawInfo;
 
 class LLDrawPoolBump : public LLRenderPass
 {
+protected :
+	LLDrawPoolBump(const U32 type):LLRenderPass(type) { mShiny = FALSE; }
 public:
 	static U32 sVertexMask;
+	BOOL mShiny;
 
 	virtual U32 getVertexDataMask() { return sVertexMask; }
 
 	LLDrawPoolBump();
 
 	virtual void render(S32 pass = 0);
-	/*virtual*/ void beginRenderPass( S32 pass );
-	/*virtual*/ void endRenderPass( S32 pass );
-	/*virtual*/ S32	 getNumPasses();
+	virtual void beginRenderPass( S32 pass );
+	virtual void endRenderPass( S32 pass );
+	virtual S32	 getNumPasses();
 	/*virtual*/ void prerender();
 	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture);
 
 	void renderBump(U32 type, U32 mask);
-	void renderBumpActive(U32 type, U32 mask);
 	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
 	void renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask);
 	
 	S32 numBumpPasses();
 	
-	void beginShiny();
-	void renderShiny();
-	void endShiny();
-	void renderActive(U32 type, U32 mask, BOOL texture = TRUE);
+	void beginShiny(bool invisible = false);
+	void renderShiny(bool invisible = false);
+	void endShiny(bool invisible = false);
+	
+	void beginFullbrightShiny();
+	void renderFullbrightShiny();
+	void endFullbrightShiny();
 
 	void beginBump();
 	void renderBump();
@@ -143,6 +148,25 @@ class LLBumpImageList
 
 extern LLBumpImageList gBumpImageList;
 
+class LLDrawPoolInvisible : public LLDrawPoolBump
+{
+public:
+	LLDrawPoolInvisible() : LLDrawPoolBump(LLDrawPool::POOL_INVISIBLE) { }
+
+	enum
+	{
+		VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX
+	};
+	
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	virtual void prerender() { }
+
+	virtual void render(S32 pass = 0);
+	virtual void beginRenderPass( S32 pass ) { }
+	virtual void endRenderPass( S32 pass ) { }
+	virtual S32	 getNumPasses() {return 1;}
+};
 
 
 #endif // LL_LLDRAWPOOLBUMP_H
diff --git a/indra/newview/lldrawpoolclouds.h b/indra/newview/lldrawpoolclouds.h
index e155acfb9e1..1047afb8e52 100644
--- a/indra/newview/lldrawpoolclouds.h
+++ b/indra/newview/lldrawpoolclouds.h
@@ -55,7 +55,6 @@ class LLDrawPoolClouds : public LLDrawPool
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void renderForSelect();
-	virtual S32 getMaterialAttribIndex() { return 0; }
 };
 
 #endif // LL_LLDRAWPOOLSKY_H
diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp
index d84f0959bfc..31c4e4fde9e 100644
--- a/indra/newview/lldrawpoolground.cpp
+++ b/indra/newview/lldrawpoolground.cpp
@@ -72,15 +72,10 @@ void LLDrawPoolGround::render(S32 pass)
 	glEnableClientState(GL_VERTEX_ARRAY);
 
 	LLGLSPipelineSkyBox gls_skybox;
-	LLGLDisable tex(GL_TEXTURE_2D);
-	LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
+	LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
+	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
 
-	glMatrixMode( GL_PROJECTION );
-		
-	glPushMatrix();
-	//gViewerWindow->setup3DRender();
-
-	glMatrixMode(GL_MODELVIEW);
+	LLGLClampToFarClip far_clip(glh_get_current_projection());
 
 	F32 water_height = gAgent.getRegion()->getWaterHeight();
 	glPushMatrix();
@@ -94,9 +89,6 @@ void LLDrawPoolGround::render(S32 pass)
 	LLOverrideFaceColor col(this, gSky.mVOSkyp->getGLFogColor());
 	facep->renderIndexed();
 	
-	glMatrixMode( GL_PROJECTION );
-	glPopMatrix();
-	glMatrixMode( GL_MODELVIEW );
 	glPopMatrix();
 }
 
diff --git a/indra/newview/lldrawpoolground.h b/indra/newview/lldrawpoolground.h
index a804c904fa5..fa73314de1b 100644
--- a/indra/newview/lldrawpoolground.h
+++ b/indra/newview/lldrawpoolground.h
@@ -49,7 +49,6 @@ class LLDrawPoolGround : public LLFacePool
 	LLDrawPoolGround();
 
 	/*virtual*/ LLDrawPool *instancePool();
-	virtual S32 getMaterialAttribIndex() { return 0; }
 
 	/*virtual*/ void prerender();
 	/*virtual*/ void render(S32 pass = 0);
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 0a5d4576d8e..174a9ac427e 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -32,7 +32,6 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "lldrawpoolsimple.h"
-#include "lldrawpoolbump.h"
 
 #include "llviewercamera.h"
 #include "llagent.h"
@@ -40,76 +39,46 @@
 #include "llface.h"
 #include "llsky.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llglslshader.h"
+#include "llglimmediate.h"
 
-class LLRenderShinyGlow : public LLDrawPoolBump
-{
-public:
-	LLRenderShinyGlow() { }
-	
-	void render(S32 pass = 0)
-	{
-		LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap();
-		if( cube_map )
-		{
-			cube_map->enable(0);
-			cube_map->setMatrix(0);
-			cube_map->bind();
-			glEnableClientState(GL_NORMAL_ARRAY);
-			
-			glColor4f(1,1,1,1);
-
-            U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL;
-			renderStatic(LLRenderPass::PASS_SHINY, mask);
-			renderActive(LLRenderPass::PASS_SHINY, mask);
-
-			glDisableClientState(GL_NORMAL_ARRAY);
-			cube_map->disable();
-			cube_map->restoreMatrix();
-		}
-	}
-};
+
+static LLGLSLShader* simple_shader = NULL;
+static LLGLSLShader* fullbright_shader = NULL;
 
 void LLDrawPoolGlow::render(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-	renderTexture(LLRenderPass::PASS_GLOW, getVertexDataMask());
-	renderActive(LLRenderPass::PASS_GLOW, getVertexDataMask());
+	LLGLDisable test(GL_ALPHA_TEST);
+	gGL.blendFunc(GL_ONE, GL_ONE);
+	
+	U32 shader_level = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
 
-	if (gSky.mVOSkyp)
+	if (shader_level > 0 && fullbright_shader)
 	{
-		glPushMatrix();
-		LLVector3 origin = gCamera->getOrigin();
-		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
-
-		LLFace* facep = gSky.mVOSkyp->mFace[LLVOSky::FACE_BLOOM];
-
-		if (facep)
-		{
-			LLGLDisable cull(GL_CULL_FACE);
-			facep->getTexture()->bind();
-			glColor4f(1,1,1,1);
-			facep->renderIndexed(getVertexDataMask());
-		}
-
-		glPopMatrix();
+		fullbright_shader->bind();
 	}
-
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	if (LLPipeline::sDynamicReflections)
+	else
 	{
-		LLRenderShinyGlow glow;
-		glow.render();
+		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 	}
 
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+	renderTexture(LLRenderPass::PASS_GLOW, getVertexDataMask());
+
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
 	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	
+	if (shader_level > 0 && fullbright_shader)
+	{
+		fullbright_shader->unbind();
+	}
 }
 
 void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
@@ -131,53 +100,87 @@ void LLDrawPoolSimple::prerender()
 
 void LLDrawPoolSimple::beginRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_COLOR_ARRAY);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		simple_shader = &gObjectSimpleWaterProgram;
+		fullbright_shader = &gObjectFullbrightWaterProgram;
+	}
+	else
+	{
+		simple_shader = &gObjectSimpleProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
+	}
+
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->bind();
+		simple_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 0.f);
+	}
+	else 
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			glUseProgramObjectARB(0);
+		}		
+	}
+}
+
+void LLDrawPoolSimple::endRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+	LLRenderPass::endRenderPass(pass);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	if (mVertexShaderLevel > 0){
+
+		simple_shader->unbind();
+	}
 }
 
 void LLDrawPoolSimple::render(S32 pass)
 {
 	LLGLDisable blend(GL_BLEND);
-	LLGLDisable alpha_test(GL_ALPHA_TEST);
-	
-	{
+	LLGLState alpha_test(GL_ALPHA_TEST, gPipeline.canUseWindLightShadersOnObjects());
+	glAlphaFunc(GL_GREATER, 0.5f);
+
+	{ //render simple
 		LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
-		gPipeline.enableLightsDynamic(1.f);
+		gPipeline.enableLightsDynamic();
 		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
-		renderActive(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 	}
 
 	{
 		LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+		LLGLEnable test(GL_ALPHA_TEST);
 		LLGLEnable blend(GL_BLEND);
-		LLGLEnable alpha_test(GL_ALPHA_TEST);
-		glAlphaFunc(GL_GREATER, 0.5f);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 		//render grass
 		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
-		glAlphaFunc(GL_GREATER, 0.01f);
-	}
-		
-	{
+	}			
+
+	{ //render fullbright
+		if (mVertexShaderLevel > 0)
+		{
+			fullbright_shader->bind();
+			fullbright_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 1.f);
+		}
+		else
+		{
+			gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+		}
 		LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
 		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR;
-		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 		glDisableClientState(GL_NORMAL_ARRAY);
 		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-		renderActive(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
 	}
 
-	{
-		LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE);
-		U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
-		glDisableClientState(GL_COLOR_ARRAY);
-		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-		renderInvisible(invisi_mask);
-		renderActive(LLRenderPass::PASS_INVISIBLE, invisi_mask);
-		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-	}
+	glAlphaFunc(GL_GREATER, 0.01f);
 }
 
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index ff12610d2a9..d2ad5124a69 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -49,6 +49,9 @@ class LLDrawPoolSimple : public LLRenderPass
 	LLDrawPoolSimple();
 	
 	/*virtual*/ void beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/// We need two passes so we can handle emissive materials separately.
+	/*virtual*/ S32	 getNumPasses() { return 1; }
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
 
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 677a5631984..9276ee50e1a 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -49,7 +49,7 @@
 #include "llglslshader.h"
 
 LLDrawPoolSky::LLDrawPoolSky() :
-	LLFacePool(POOL_SKY)
+	LLFacePool(POOL_SKY), mShader(NULL)
 {
 }
 
@@ -61,6 +61,7 @@ LLDrawPool *LLDrawPoolSky::instancePool()
 void LLDrawPoolSky::prerender()
 {
 	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT);
+	gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable);
 }
 
 void LLDrawPoolSky::render(S32 pass)
@@ -70,24 +71,44 @@ void LLDrawPoolSky::render(S32 pass)
 		return;
 	}
 
+	// Don't draw the sky box if we can and are rendering the WL sky dome.
+	if (gPipeline.canUseWindLightShaders())
+	{
+		return;
+	}
+	
+	// use a shader only underwater
+	if(mVertexShaderLevel > 0 && LLPipeline::sUnderWaterRender)
+	{
+		mShader = &gObjectFullbrightWaterProgram;
+		mShader->bind();
+	}
+	else
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			// Ironically, we must support shader objects to be
+			// able to use this call.
+			glUseProgramObjectARB(0);
+		}
+		mShader = NULL;
+	}
+	
+
 	LLVOSky *voskyp = gSky.mVOSkyp;
 	LLGLSPipelineSkyBox gls_skybox;
-	LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
 
-	if (gCamera->getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight())
-		//gWorldPointer->getWaterHeight())
-	{
-		//gGLSFog.set();
-	}
+	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+
+	LLGLClampToFarClip far_clip(glh_get_current_projection());
+
+	LLGLEnable fog_enable( (mVertexShaderLevel < 1 && gCamera->cameraUnderWater()) ? GL_FOG : 0);
 
 	gPipeline.disableLights();
 	
-	glMatrixMode( GL_PROJECTION );
+	LLGLDisable clip(GL_CLIP_PLANE0);
 
-	glPushMatrix();
-	//gViewerWindow->setup3DRender();
-
-	glMatrixMode(GL_MODELVIEW);
 	glPushMatrix();
 	LLVector3 origin = gCamera->getOrigin();
 	glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
@@ -128,21 +149,19 @@ void LLDrawPoolSky::render(S32 pass)
 
 	if (hbfaces[2])
 	{
-		renderSunHalo(hbfaces[2]);
+		// renderSunHalo(hbfaces[2]);
 	}
 	if (hbfaces[0])
 	{
-		renderHeavenlyBody(0, hbfaces[0]);
+		// renderHeavenlyBody(0, hbfaces[0]);
 	}
 	if (hbfaces[1])
 	{
-		renderHeavenlyBody(1, hbfaces[1]);
+		// renderHeavenlyBody(1, hbfaces[1]);
 	}
 
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
-	glMatrixMode( GL_PROJECTION );
-	glPopMatrix();
-	glMatrixMode( GL_MODELVIEW );
 	glPopMatrix();
 }
 
@@ -204,3 +223,6 @@ void LLDrawPoolSky::renderForSelect()
 {
 }
 
+void LLDrawPoolSky::endRenderPass( S32 pass )
+{
+}
diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h
index ceabde3d9dd..1941e9f1a09 100644
--- a/indra/newview/lldrawpoolsky.h
+++ b/indra/newview/lldrawpoolsky.h
@@ -36,12 +36,14 @@
 
 class LLSkyTex;
 class LLHeavenBody;
+class LLGLSLShader;
 
 class LLDrawPoolSky : public LLFacePool
 {
 private:
 	LLSkyTex			*mSkyTex;
 	LLHeavenBody		*mHB[2]; // Sun and Moon
+	LLGLSLShader		*mShader;
 
 public:
 	enum
@@ -59,6 +61,7 @@ class LLDrawPoolSky : public LLFacePool
 	/*virtual*/ void prerender();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void renderForSelect();
+	/*virtual*/ void endRenderPass(S32 pass);
 	void setSkyTex(LLSkyTex* const st) { mSkyTex = st; }
 	void setSun(LLHeavenBody* sun_flag) { mHB[0] = sun_flag; }
 	void setMoon(LLHeavenBody* moon) { mHB[1] = moon; }
@@ -67,7 +70,6 @@ class LLDrawPoolSky : public LLFacePool
 	void renderHeavenlyBody(U8 hb, LLFace* face);
 	void renderSunHalo(LLFace* face);
 
-	virtual S32 getMaterialAttribIndex() { return 0; }
 };
 
 #endif // LL_LLDRAWPOOLSKY_H
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index b48de1db850..d8ebf33d38b 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -52,12 +52,14 @@
 #include "llworld.h"
 #include "pipeline.h"
 #include "llglslshader.h"
+#include "llglimmediate.h"
 
 const F32 DETAIL_SCALE = 1.f/16.f;
 int DebugDetailMap = 0;
 
 S32 LLDrawPoolTerrain::sDetailMode = 1;
 F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE;
+static LLGLSLShader* sShader = NULL;
 
 LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerImage *texturep) :
 	LLFacePool(POOL_TERRAIN),
@@ -95,10 +97,40 @@ LLDrawPool *LLDrawPoolTerrain::instancePool()
 
 void LLDrawPoolTerrain::prerender()
 {
-#if 0 // 1.9.2
-	mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT);
-#endif
-	sDetailMode = gSavedSettings.getS32("RenderTerrainDetail");
+	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT);
+	if (mVertexShaderLevel > 0)
+	{
+		sDetailMode = 1;
+	}
+	else
+	{
+		sDetailMode = gSavedSettings.getS32("RenderTerrainDetail");
+	}
+}
+
+void LLDrawPoolTerrain::beginRenderPass( S32 pass )
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::beginRenderPass(pass);
+
+	sShader = LLPipeline::sUnderWaterRender ? 
+					&gTerrainWaterProgram :
+					&gTerrainProgram;
+
+	if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0)
+	{
+		sShader->bind();
+	}
+}
+
+void LLDrawPoolTerrain::endRenderPass( S32 pass )
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::endRenderPass(pass);
+
+	if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) {
+		sShader->unbind();
+	}
 }
 
 //static
@@ -127,7 +159,7 @@ void LLDrawPoolTerrain::render(S32 pass)
 
 	if (!gGLManager.mHasMultitexture)
 	{
-		// No mulititexture, render simple land.
+		// No multitexture, render simple land.
 		renderSimple(); // Render without multitexture
 		return;
 	}
@@ -141,52 +173,47 @@ void LLDrawPoolTerrain::render(S32 pass)
 	LLGLSPipeline gls;
 	LLOverrideFaceColor override(this, 1.f, 1.f, 1.f, 1.f);
 
-	if (mVertexShaderLevel > 0)
+	if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0)
 	{
-		gPipeline.enableLightsDynamic(1.f);
-		renderFull4TUShader();
+		gPipeline.enableLightsDynamic();
+		renderFullShader();
 	}
 	else
 	{
-		gPipeline.enableLightsStatic(1.f);
-		switch (sDetailMode)
-		{
-		  case 0:
+		gPipeline.enableLightsStatic();
+
+		if (sDetailMode == 0){
 			renderSimple();
-			break;
-		  default:
-			if (gGLManager.mNumTextureUnits < 4)
-			{
-				renderFull2TU();
-			}
-			else
-			{
-				renderFull4TU();
-			}
-			break;
+		} else if (gGLManager.mNumTextureUnits < 4){
+			renderFull2TU();
+		} else {
+			renderFull4TU();
 		}
 	}
 
 	// Special-case for land ownership feedback
 	if (gSavedSettings.getBOOL("ShowParcelOwners"))
 	{
-		gPipeline.disableLights();
-		if ((mVertexShaderLevel > 0))
-		{
-			gHighlightProgram.bind();
-			gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,1,1,1);
+		if (mVertexShaderLevel > 1)
+		{ //use fullbright shader for highlighting
+			LLGLSLShader* old_shader = sShader;
+			sShader->unbind();
+			sShader = &gObjectFullbrightProgram;
+			sShader->bind();
 			renderOwnership();
-			gTerrainProgram.bind();
+			sShader = old_shader;
+			sShader->bind();
 		}
 		else
 		{
+			gPipeline.disableLights();
 			renderOwnership();
 		}
 	}
 }
 
 
-void LLDrawPoolTerrain::renderFull4TUShader()
+void LLDrawPoolTerrain::renderFullShader()
 {
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
@@ -195,9 +222,7 @@ void LLDrawPoolTerrain::renderFull4TUShader()
 	{
 		glEnableClientState(GL_COLOR_ARRAY);
 	}
-	
-	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
-	
+
 	// Hack! Get the region that this draw pool is rendering from!
 	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
 	LLVLComposition *compp = regionp->getComposition();
@@ -206,12 +231,7 @@ void LLDrawPoolTerrain::renderFull4TUShader()
 	LLViewerImage *detail_texture2p = compp->mDetailTextures[2];
 	LLViewerImage *detail_texture3p = compp->mDetailTextures[3];
 
-	static F32 dp = 0.f;
-	static LLFrameTimer timer;
-	dp += timer.getElapsedTimeAndResetF32();
-
 	LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal();
-
 	F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale;
 	F32 offset_y = (F32)fmod(region_origin_global.mdV[VY], 1.0/(F64)sDetailScale)*sDetailScale;
 
@@ -220,145 +240,111 @@ void LLDrawPoolTerrain::renderFull4TUShader()
 	tp0.setVec(sDetailScale, 0.0f, 0.0f, offset_x);
 	tp1.setVec(0.0f, sDetailScale, 0.0f, offset_y);
 
-	//----------------------------------------------------------------------------
-	// Pass 1/1
-
 	//
-	// Stage 0: detail texture 0
+	// detail texture 0
 	//
-	
-	S32 detailTex0 = gTerrainProgram.enableTexture(LLShaderMgr::TERRAIN_DETAIL0);
-	S32 detailTex1 = gTerrainProgram.enableTexture(LLShaderMgr::TERRAIN_DETAIL1);
-	S32 rampTex = gTerrainProgram.enableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
-	
-	LLViewerImage::bindTexture(detail_texture0p,detailTex0);
-
+	S32 detail0 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL0);
+	LLViewerImage::bindTexture(detail_texture0p,detail0);
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	glActiveTextureARB(GL_TEXTURE0_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnable(GL_TEXTURE_GEN_S);
-	glEnable(GL_TEXTURE_GEN_T);
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	//
-	// Stage 1: Generate alpha ramp for detail0/detail1 transition
-	//
-	LLViewerImage::bindTexture(m2DAlphaRampImagep,rampTex);
-
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	//
-	// Stage 2: Interpolate detail1 with existing based on ramp
-	//
-	LLViewerImage::bindTexture(detail_texture1p,detailTex1);
-	
-	glClientActiveTextureARB(GL_TEXTURE2_ARB);
-	glActiveTextureARB(GL_TEXTURE2_ARB);
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glEnable(GL_TEXTURE_GEN_S);
 	glEnable(GL_TEXTURE_GEN_T);
 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
 	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
 
-	//
-	// Stage 3: Modulate with primary color for lighting
-	//
-	//LLViewerImage::bindTexture(detail_texture1p,3); // bind any texture
-	//glEnable(GL_TEXTURE_2D); // Texture unit 3
-	glClientActiveTextureARB(GL_TEXTURE3_ARB);
-	glActiveTextureARB(GL_TEXTURE3_ARB);
-	// GL_BLEND disabled by default
-	drawLoop();
-
-	//----------------------------------------------------------------------------
-	// Second pass
-
-	//
-	// Stage 0: Write detail3 into base
-	//
-	LLViewerImage::bindTexture(detail_texture2p,detailTex0);
-	
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	glActiveTextureARB(GL_TEXTURE0_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnable(GL_TEXTURE_GEN_S);
-	glEnable(GL_TEXTURE_GEN_T);
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
 	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
 	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
+	glMatrixMode(GL_TEXTURE);
+	glLoadIdentity();
+	glMatrixMode(GL_MODELVIEW);
 
 	//
-	// Stage 1: Generate alpha ramp for detail2/detail3 transition
+	// detail texture 1
 	//
-	LLViewerImage::bindTexture(m2DAlphaRampImagep,rampTex);
+	S32 detail1 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL1); 
+	LLViewerImage::bindTexture(detail_texture1p,detail1);
 	
+	/// ALPHA TEXTURE COORDS 0:
 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glActiveTextureARB(GL_TEXTURE1_ARB);
-
-	// Set the texture matrix
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
-	glTranslatef(-2.f, 0.f, 0.f);
-
-	//
-	// Stage 2: Interpolate detail2 with existing based on ramp
+	glMatrixMode(GL_MODELVIEW);
+	
+	// detail texture 2
 	//
-	LLViewerImage::bindTexture(detail_texture3p,detailTex1);
+	S32 detail2 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL2);
+	LLViewerImage::bindTexture(detail_texture2p,detail2);
+	glEnable(GL_TEXTURE_2D);
 	
+	/// ALPHA TEXTURE COORDS 1:
 	glClientActiveTextureARB(GL_TEXTURE2_ARB);
 	glActiveTextureARB(GL_TEXTURE2_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnable(GL_TEXTURE_GEN_S);
-	glEnable(GL_TEXTURE_GEN_T);
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glMatrixMode(GL_TEXTURE);
+	glLoadIdentity();
+	glTranslatef(-2.f, 0.f, 0.f);
+	glMatrixMode(GL_MODELVIEW);
 
 	//
-	// Stage 3: Generate alpha ramp for detail1/detail2 transition
+	// detail texture 3
 	//
-	//LLViewerImage::bindTexture(m2DAlphaRampImagep,3);
-	
-	//glEnable(GL_TEXTURE_2D); // Texture unit 3
+	S32 detail3 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL3);
+	LLViewerImage::bindTexture(detail_texture3p,detail3);
 	
+	/// ALPHA TEXTURE COORDS 2:
 	glClientActiveTextureARB(GL_TEXTURE3_ARB);
 	glActiveTextureARB(GL_TEXTURE3_ARB);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	// Set the texture matrix
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glTranslatef(-1.f, 0.f, 0.f);
+	glMatrixMode(GL_MODELVIEW);
 
-	{
-		LLGLEnable blend(GL_BLEND);
-		drawLoop();
-	}
+	//
+	// Alpha Ramp 
+	//
+	S32 alpha_ramp = sShader->enableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
+	LLViewerImage::bindTexture(m2DAlphaRampImagep,alpha_ramp);
+		
+	// GL_BLEND disabled by default
+	drawLoop();
 
 	// Disable multitexture
-	gTerrainProgram.disableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
-	gTerrainProgram.disableTexture(LLShaderMgr::TERRAIN_DETAIL0);
-	gTerrainProgram.disableTexture(LLShaderMgr::TERRAIN_DETAIL1);
-	
+	sShader->disableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
+	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL0);
+	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL1);
+	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL2);
+	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL3);
+
+	LLImageGL::unbindTexture(alpha_ramp, GL_TEXTURE_2D);
+	glClientActiveTextureARB(GL_TEXTURE4_ARB);
+	glActiveTextureARB(GL_TEXTURE4_ARB);	
+	glDisable(GL_TEXTURE_2D); // Texture unit 4
+	glDisable(GL_TEXTURE_GEN_S);
+	glDisable(GL_TEXTURE_GEN_T);
+	glMatrixMode(GL_TEXTURE);
+	glLoadIdentity();
+	glMatrixMode(GL_MODELVIEW);
+
+	LLImageGL::unbindTexture(detail3, GL_TEXTURE_2D);
 	glClientActiveTextureARB(GL_TEXTURE3_ARB);
 	glActiveTextureARB(GL_TEXTURE3_ARB);
+	glDisable(GL_TEXTURE_2D);	
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisable(GL_TEXTURE_GEN_S);
+	glDisable(GL_TEXTURE_GEN_T);
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
 
+	LLImageGL::unbindTexture(detail2, GL_TEXTURE_2D);
 	glClientActiveTextureARB(GL_TEXTURE2_ARB);
 	glActiveTextureARB(GL_TEXTURE2_ARB);
+	glDisable(GL_TEXTURE_2D);		
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
@@ -366,32 +352,32 @@ void LLDrawPoolTerrain::renderFull4TUShader()
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
 
+	LLImageGL::unbindTexture(detail1, GL_TEXTURE_2D);
 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
 	glActiveTextureARB(GL_TEXTURE1_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisable(GL_TEXTURE_2D);		
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);	
+	glDisable(GL_TEXTURE_GEN_S);
+	glDisable(GL_TEXTURE_GEN_T);
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
-
-	// Restore blend state
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	
 	//----------------------------------------------------------------------------
 	// Restore Texture Unit 0 defaults
 	
+	LLImageGL::unbindTexture(detail0, GL_TEXTURE_2D);
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	glActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnable(GL_TEXTURE_2D);
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
-	glEnable(GL_TEXTURE_2D);
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
 
 	// Restore non Texture Unit specific defaults
 	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 }
 
 void LLDrawPoolTerrain::renderFull4TU()
@@ -416,7 +402,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	tp0.setVec(sDetailScale, 0.0f, 0.0f, offset_x);
 	tp1.setVec(0.0f, sDetailScale, 0.0f, offset_y);
 
-	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
+	gGL.blendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
 	
 	//----------------------------------------------------------------------------
 	// Pass 1/1
@@ -649,7 +635,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	glMatrixMode(GL_MODELVIEW);
 
 	// Restore blend state
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	
 	//----------------------------------------------------------------------------
 	// Restore Texture Unit 0 defaults
@@ -690,7 +676,7 @@ void LLDrawPoolTerrain::renderFull2TU()
 	tp0.setVec(sDetailScale, 0.0f, 0.0f, offset_x);
 	tp1.setVec(0.0f, sDetailScale, 0.0f, offset_y);
 
-	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
+	gGL.blendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
 	
 	//----------------------------------------------------------------------------
 	// Pass 1/4
@@ -887,7 +873,7 @@ void LLDrawPoolTerrain::renderFull2TU()
 	}
 	
 	// Restore blend state
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	
 	// Disable multitexture
 	LLImageGL::unbindTexture(1, GL_TEXTURE_2D);
@@ -1015,7 +1001,6 @@ void LLDrawPoolTerrain::renderOwnership()
 
 	const F32 TEXTURE_FUDGE = 257.f / 256.f;
 	glScalef( TEXTURE_FUDGE, TEXTURE_FUDGE, 1.f );
-
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
 	{
@@ -1082,8 +1067,3 @@ LLColor3 LLDrawPoolTerrain::getDebugColor() const
 {
 	return LLColor3(0.f, 0.f, 1.f);
 }
-
-S32 LLDrawPoolTerrain::getMaterialAttribIndex()
-{
-	return gTerrainProgram.mAttribute[LLShaderMgr::MATERIAL_COLOR];
-}
diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h
index dc95d7d4c48..91464a8a6a4 100644
--- a/indra/newview/lldrawpoolterrain.h
+++ b/indra/newview/lldrawpoolterrain.h
@@ -58,6 +58,8 @@ class LLDrawPoolTerrain : public LLFacePool
 
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
+	/*virtual*/ void beginRenderPass( S32 pass );
+	/*virtual*/ void endRenderPass( S32 pass );
 	/*virtual*/ void renderForSelect();
 	/*virtual*/ void dirtyTextures(const std::set<LLViewerImage*>& textures);
 	/*virtual*/ LLViewerImage *getTexture();
@@ -68,8 +70,6 @@ class LLDrawPoolTerrain : public LLFacePool
 	LLPointer<LLViewerImage> m2DAlphaRampImagep;
 	LLPointer<LLViewerImage> mAlphaNoiseImagep;
 
-	virtual S32 getMaterialAttribIndex();
-
 	static S32 sDetailMode;
 	static F32 sDetailScale; // meters per texture
 protected:
@@ -78,7 +78,7 @@ class LLDrawPoolTerrain : public LLFacePool
 
 	void renderFull2TU();
 	void renderFull4TU();
-	void renderFull4TUShader();
+	void renderFullShader();
 };
 
 #endif // LL_LLDRAWPOOLSIMPLE_H
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index c8e0ff2052f..f70904eba47 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -41,8 +41,10 @@
 #include "pipeline.h"
 #include "llviewercamera.h"
 #include "llglslshader.h"
+#include "llglimmediate.h"
 
 S32 LLDrawPoolTree::sDiffTex = 0;
+static LLGLSLShader* shader = NULL;
 
 LLDrawPoolTree::LLDrawPoolTree(LLViewerImage *texturep) :
 	LLFacePool(POOL_TREE),
@@ -59,15 +61,34 @@ LLDrawPool *LLDrawPoolTree::instancePool()
 
 void LLDrawPoolTree::prerender()
 {
-	mVertexShaderLevel = 0;
+	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
 }
 
 void LLDrawPoolTree::beginRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glAlphaFunc(GL_GREATER, 0.5f);
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		shader = &gObjectSimpleWaterProgram;
+	}
+	else
+	{
+		shader = &gObjectSimpleProgram;
+	}
+
+	if (gPipeline.canUseWindLightShadersOnObjects())
+	{
+		shader->bind();
+	}
+	else
+	{
+		gPipeline.enableLightsDynamic();
+	}
 }
 
 void LLDrawPoolTree::render(S32 pass)
@@ -79,8 +100,7 @@ void LLDrawPoolTree::render(S32 pass)
 		return;
 	}
 
-	gPipeline.enableLightsDynamic(1.f);
-	LLGLSPipelineAlpha gls_pipeline_alpha;
+	LLGLEnable test(GL_ALPHA_TEST);
 	LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f);
 
 	renderTree();
@@ -88,9 +108,15 @@ void LLDrawPoolTree::render(S32 pass)
 
 void LLDrawPoolTree::endRenderPass(S32 pass)
 {
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
 	glAlphaFunc(GL_GREATER, 0.01f);
 	glDisableClientState(GL_NORMAL_ARRAY);
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	if (gPipeline.canUseWindLightShadersOnObjects())
+	{
+		shader->unbind();
+	}
 }
 
 void LLDrawPoolTree::renderForSelect()
@@ -107,7 +133,7 @@ void LLDrawPoolTree::renderForSelect()
 
 	LLGLSObjectSelectAlpha gls_alpha;
 
-	glBlendFunc(GL_ONE, GL_ZERO);
+	gGL.blendFunc(GL_ONE, GL_ZERO);
 	glAlphaFunc(GL_GREATER, 0.5f);
 
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
@@ -126,7 +152,7 @@ void LLDrawPoolTree::renderForSelect()
 	renderTree(TRUE);
 
 	glAlphaFunc(GL_GREATER, 0.01f);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
@@ -138,16 +164,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 	
 	// Bind the texture for this tree.
 	LLViewerImage::bindTexture(mTexturep,sDiffTex);
-	if (mTexturep)
-	{
-		if (mTexturep->getClampS()) {
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-		}
-		if (mTexturep->getClampT()) {
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-		}
-	}
-
+		
 	U32 indices_drawn = 0;
 
 	glMatrixMode(GL_MODELVIEW);
@@ -164,7 +181,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 		}
 
 		face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
-		U32* indicesp = (U32*) face->mVertexBuffer->getIndicesPointer();
+		U16* indicesp = (U16*) face->mVertexBuffer->getIndicesPointer();
 
 		// Render each of the trees
 		LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get();
@@ -180,28 +197,43 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 				color = LLColor4U((U8)(name >> 16), (U8)(name >> 8), (U8)name, 255);
 			}
 			
-			glPushMatrix();
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+			//glPushMatrix();
+			F32 mat[16];
+			for (U32 i = 0; i < 16; i++)
+				mat[i] = (F32) gGLModelView[i];
+
+			LLMatrix4 matrix(mat);
 			
 			// Translate to tree base  HACK - adjustment in Z plants tree underground
 			const LLVector3 &pos_agent = treep->getPositionAgent();
-			glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
-
-			// Rotate to tree position
-			F32 angle_radians, x, y, z;
-			treep->getRotation().getAngleAxis(&angle_radians, &x, &y, &z);
-			glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
-
-			// Rotate and bend for current trunk/wind
+			//glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+			LLMatrix4 trans_mat;
+			trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+			trans_mat *= matrix;
+			
+			// Rotate to tree position and bend for current trunk/wind
 			// Note that trunk stiffness controls the amount of bend at the trunk as 
 			// opposed to the crown of the tree
 			// 
-			glRotatef(90.f, 0, 0, 1);
 			const F32 TRUNK_STIFF = 22.f;
-			glRotatef(treep->mTrunkBend.magVec()*TRUNK_STIFF, treep->mTrunkBend.mV[VX], treep->mTrunkBend.mV[VY], 0);
+			
+			LLQuaternion rot = 
+				LLQuaternion(treep->mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(treep->mTrunkBend.mV[VX], treep->mTrunkBend.mV[VY], 0)) *
+				LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) *
+				treep->getRotation();
 
-			F32 radius = treep->getScale().magVec()*0.5f;
-			radius *= 0.1f;
-			glScalef(radius, radius, radius);
+			LLMatrix4 rot_mat(rot);
+			rot_mat *= trans_mat;
+
+			F32 radius = treep->getScale().magVec()*0.05f;
+			LLMatrix4 scale_mat;
+			scale_mat.mMatrix[0][0] = 
+				scale_mat.mMatrix[1][1] =
+				scale_mat.mMatrix[2][2] = radius;
+
+			scale_mat *= rot_mat;
 
 			const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f;
 			const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f;
@@ -231,7 +263,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 				//  Only the billboard, can use closer to normal alpha func.
 				stop_depth = -1;
 				LLFacePool::LLOverrideFaceColor clr(this, color); 
-				indices_drawn += treep->drawBranchPipeline(indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha);
+				indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha);
 			}
 			else // if (app_angle > (THRESH_ANGLE_FOR_BILLBOARD + BLEND_RANGE_FOR_BILLBOARD))
 			{
@@ -240,20 +272,10 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 				//
 				//stop_depth = (app_angle < THRESH_ANGLE_FOR_RECURSION_REDUCTION);
 				LLFacePool::LLOverrideFaceColor clr(this, color); 
-				indices_drawn += treep->drawBranchPipeline(indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha);
+				indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha);
 			}
 			
-			glPopMatrix();
-		}
-	}
-
-	if (mTexturep)
-	{
-		if (mTexturep->getClampS()) {
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		}
-		if (mTexturep->getClampT()) {
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+			//glPopMatrix();
 		}
 	}
 
@@ -289,7 +311,3 @@ LLColor3 LLDrawPoolTree::getDebugColor() const
 	return LLColor3(1.f, 0.f, 1.f);
 }
 
-S32 LLDrawPoolTree::getMaterialAttribIndex() 
-{ 
-	return gObjectSimpleProgram.mAttribute[LLShaderMgr::MATERIAL_COLOR];
-}
diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h
index 7dee2382b23..c414ebcea9f 100644
--- a/indra/newview/lldrawpooltree.h
+++ b/indra/newview/lldrawpooltree.h
@@ -55,14 +55,13 @@ class LLDrawPoolTree : public LLFacePool
 	/*virtual*/ void beginRenderPass( S32 pass );
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void endRenderPass( S32 pass );
+	/*virtual*/ S32	 getNumPasses() { return 1; }
 	/*virtual*/ void renderForSelect();
 	/*virtual*/ BOOL verify() const;
 	/*virtual*/ LLViewerImage *getTexture();
 	/*virtual*/ LLViewerImage *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
-	virtual S32 getMaterialAttribIndex();
-
 	static S32 sDiffTex;
 
 private:
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index d7fc716c55e..ca2f5ebb863 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -51,12 +51,16 @@
 #include "llworld.h"
 #include "pipeline.h"
 #include "llglslshader.h"
+#include "llwaterparammanager.h"
 
 const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004");
 
 static float sTime;
 
 BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
+BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
+LLColor4 LLDrawPoolWater::sWaterFogColor = LLColor4(0.2f, 0.5f, 0.5f, 0.f);
+LLVector3 LLDrawPoolWater::sLightDir;
 
 LLDrawPoolWater::LLDrawPoolWater() :
 	LLFacePool(POOL_WATER)
@@ -70,7 +74,8 @@ LLDrawPoolWater::LLDrawPoolWater() :
 	mHBTex[1]->setClamp(TRUE, TRUE);
 
 	mWaterImagep = gImageList.getImage(WATER_TEST);
-	mWaterNormp = gImageList.getImage(LLUUID(gViewerArt.getString("water_normal.tga")));
+	//mWaterNormp = gImageList.getImage(LLUUID(gViewerArt.getString("water_normal.tga")));
+	mWaterNormp = gImageList.getImage(LLWaterParamManager::instance()->getNormalMapID());
 
 	restoreGL();
 }
@@ -94,12 +99,25 @@ LLDrawPool *LLDrawPoolWater::instancePool()
 
 void LLDrawPoolWater::prerender()
 {
-	mVertexShaderLevel = (gSavedSettings.getBOOL("RenderRippleWater") && gGLManager.mHasCubeMap && gFeatureManagerp->isFeatureAvailable("RenderCubeMap")) ?
-		LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT) : 0;
+	mVertexShaderLevel = (gGLManager.mHasCubeMap && gFeatureManagerp->isFeatureAvailable("RenderCubeMap")) ?
+		LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_WATER) : 0;
+
+	// got rid of modulation by light color since it got a little too
+	// green at sunset and sl-57047 (underwater turns black at 8:00)
+	sWaterFogColor = LLWaterParamManager::instance()->getFogColor();
+	sWaterFogColor.mV[3] = 0;
 
 }
 
-extern LLColor4U MAX_WATER_COLOR;
+S32 LLDrawPoolWater::getNumPasses()
+{
+	if (gCamera->getOrigin().mV[2] < 1024.f)
+	{
+		return 1;
+	}
+
+	return 0;
+}
 
 void LLDrawPoolWater::render(S32 pass)
 {
@@ -121,18 +139,12 @@ void LLDrawPoolWater::render(S32 pass)
 
 	LLGLEnable blend(GL_BLEND);
 
-	if ((mVertexShaderLevel >= SHADER_LEVEL_RIPPLE))
+	if ((mVertexShaderLevel > 0) && !sSkipScreenCopy)
 	{
 		shade();
 		return;
 	}
 
-	if ((mVertexShaderLevel > 0))
-	{
-		renderShaderSimple();
-		return;
-	}
-	
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
 	stop_glerror();
@@ -229,9 +241,9 @@ void LLDrawPoolWater::render(S32 pass)
 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
 	glActiveTextureARB(GL_TEXTURE1_ARB);
 	glDisable(GL_TEXTURE_2D); // Texture unit 1
-	LLImageGL::unbindTexture(1, GL_TEXTURE_2D);
 	glDisable(GL_TEXTURE_GEN_S); //texture unit 1
 	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
+	LLImageGL::unbindTexture(1, GL_TEXTURE_2D);
 
 	// Disable texture coordinate and color arrays
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
@@ -259,17 +271,6 @@ void LLDrawPoolWater::render(S32 pass)
 
 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
-		/*glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_ADD);
-		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_REPLACE);
-
-		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_PREVIOUS_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
-		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB,		GL_TEXTURE);
-		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB,		GL_SRC_COLOR);
-		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_PREVIOUS_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);*/
-		
 		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 			 iter != mDrawFace.end(); iter++)
 		{
@@ -315,153 +316,6 @@ void LLDrawPoolWater::render(S32 pass)
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 }
 
-
-void LLDrawPoolWater::renderShaderSimple()
-{
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	stop_glerror();
-
-	if (!gGLManager.mHasMultitexture)
-	{
-		// Ack!  No multitexture!  Bail!
-		return;
-	}
-
-	LLFace* refl_face = voskyp->getReflFace();
-
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
-
-	LLGLDisable cullFace(GL_CULL_FACE);
-	
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	
-	// Set up second pass first
-	S32 bumpTex = gWaterProgram.enableTexture(LLShaderMgr::BUMP_MAP);
-	mWaterImagep->addTextureStats(1024.f*1024.f);
-	mWaterImagep->bind(bumpTex);
-
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	
-	LLVector3 camera_up = gCamera->getUpAxis();
-	F32 up_dot = camera_up * LLVector3::z_axis;
-
-	LLColor4 water_color;
-	if (gCamera->cameraUnderWater())
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-	}
-	else
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-	}
-
-	glColor4fv(water_color.mV);
-
-	// Automatically generate texture coords for detail map
-	glActiveTextureARB(GL_TEXTURE1_ARB);
-	glEnable(GL_TEXTURE_GEN_S); //texture unit 1
-	glEnable(GL_TEXTURE_GEN_T); //texture unit 1
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-
-	// Slowly move over time.
-	F32 offset = fmod(gFrameTimeSeconds*2.f, 100.f);
-	F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f};
-	F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f};
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
-
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	glActiveTextureARB(GL_TEXTURE0_ARB);
-	
-	glClearStencil(1);
-	glClear(GL_STENCIL_BUFFER_BIT);
-	LLGLEnable gls_stencil(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
-	glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
-
-	S32 envTex = -1;
-
-	if (gSky.mVOSkyp->getCubeMap())
-	{
-		envTex = gWaterProgram.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
-		gSky.mVOSkyp->getCubeMap()->bind();
-		
-		glMatrixMode(GL_TEXTURE);
-		glLoadIdentity();
-		LLMatrix4 camera_mat = gCamera->getModelview();
-		LLMatrix4 camera_rot(camera_mat.getMat3());
-		camera_rot.invert();
-
-		glLoadMatrixf((F32 *)camera_rot.mMatrix);
-
-		glMatrixMode(GL_MODELVIEW);
-	}
-
-	S32 diffTex = gWaterProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP);
-    
-	gWaterProgram.bind();
-
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-		if (voskyp->isReflFace(face))
-		{
-			continue;
-		}
-		face->bindTexture(diffTex);
-		face->renderIndexed();
-		mIndicesDrawn += face->getIndicesCount();
-	}
-		
-	if (gSky.mVOSkyp->getCubeMap())
-	{
-		gWaterProgram.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
-		glMatrixMode(GL_TEXTURE);
-		glLoadIdentity();
-		glMatrixMode(GL_MODELVIEW);
-	}
-	
-	// Now, disable texture coord generation on texture state 1
-	gWaterProgram.disableTexture(LLShaderMgr::BUMP_MAP);
-	LLImageGL::unbindTexture(bumpTex, GL_TEXTURE_2D);
-
-	glActiveTextureARB(GL_TEXTURE1_ARB);
-	glDisable(GL_TEXTURE_GEN_S); //texture unit 1
-	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
-
-	gWaterProgram.disableTexture(LLShaderMgr::DIFFUSE_MAP);
-	
-	// Disable texture coordinate and color arrays
-	LLImageGL::unbindTexture(diffTex, GL_TEXTURE_2D);
-
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	stop_glerror();
-	
-	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
-	glUseProgramObjectARB(0);
-	gPipeline.disableLights();
-
-	glActiveTextureARB(GL_TEXTURE0_ARB);
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	glEnable(GL_TEXTURE_2D);
-
-    if (refl_face)
-	{
-		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-		renderReflection(refl_face);
-	}
-
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-}
-
 void LLDrawPoolWater::renderReflection(LLFace* face)
 {
 	LLVOSky *voskyp = gSky.mVOSkyp;
@@ -500,47 +354,33 @@ void LLDrawPoolWater::shade()
 {
 	glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
 
-	static LLVector2 d1( 0.5f, -0.17f );
-	static LLVector2 d2( 0.58f, -0.67f );
-	static LLVector2 d3( 0.5f, 0.25f );
-
-	static LLVector3 wave1(1,0.42f,1);
-	static LLVector3 wave2(0.58f,0.42f,0.17f);
-	static LLVector3 wave3(0.42f,0.67f,0.33f);
-
-	/*static LLVector2 d1( 0.83f, -1 );
-	static LLVector2 d2( 0.58f, 1 );
-	static LLVector2 d3( 1, -0.88f );
-
-	static LLVector4 wave1(0.75f,0.08f,0.5f,0.67f);
-	static LLVector4 wave2(0.17f,0.33f,0.53f,0.62f);
-	static LLVector4 wave3(0.17f,0.6f,0.67f,1);*/
-
-	/*LLDebugVarMessageBox::show("Wave Direction 1", &d1, LLVector2(1,1), LLVector2(0.01f, 0.01f));
-	LLDebugVarMessageBox::show("Wave Direction 2", &d2, LLVector2(1,1), LLVector2(0.01f, 0.01f));
-	LLDebugVarMessageBox::show("Wave Direction 3", &d3, LLVector2(1,1), LLVector2(0.01f, 0.01f));
-
-	LLDebugVarMessageBox::show("Wave 1", &wave1, LLVector3(2,1,4), LLVector3(0.01f, 0.01f, 0.01f));
-	LLDebugVarMessageBox::show("Wave 2", &wave2, LLVector3(2,1,4), LLVector3(0.01f, 0.01f, 0.01f));
-	LLDebugVarMessageBox::show("Wave 3", &wave3, LLVector3(2,1,4), LLVector3(0.01f, 0.01f, 0.01f));*/
-
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
+	if(voskyp == NULL) 
+	{
+		return;
+	}
+
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
+	
 	LLGLDisable blend(GL_BLEND);
 
 	LLColor3 light_diffuse(0,0,0);
 	F32 light_exp = 0.0f;
 	LLVector3 light_dir;
+	LLColor3 light_color;
 
 	if (gSky.getSunDirection().mV[2] > NIGHTTIME_ELEVATION_COS) 	 
     { 	 
         light_dir  = gSky.getSunDirection(); 	 
-        light_dir.normVec(); 	 
-        light_diffuse   = gSky.mVOSkyp->getSun().getColorCached(); 	 
-        light_diffuse.normVec(); 	 
+        light_dir.normVec(); 	
+		light_color = gSky.getSunDiffuseColor();
+		if(gSky.mVOSkyp) {
+	        light_diffuse = gSky.mVOSkyp->getSun().getColorCached(); 	 
+			light_diffuse.normVec(); 	 
+		}
         light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); 	 
         light_diffuse *= light_exp + 0.25f; 	 
     } 	 
@@ -548,6 +388,7 @@ void LLDrawPoolWater::shade()
     { 	 
         light_dir       = gSky.getMoonDirection(); 	 
         light_dir.normVec(); 	 
+		light_color = gSky.getMoonDiffuseColor();
         light_diffuse   = gSky.mVOSkyp->getMoon().getColorCached(); 	 
         light_diffuse.normVec(); 	 
         light_diffuse *= 0.5f; 	 
@@ -558,57 +399,112 @@ void LLDrawPoolWater::shade()
 	light_exp *= light_exp;
 	light_exp *= light_exp;
 	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= 512.f;
+	light_exp *= 256.f;
 	light_exp = light_exp > 32.f ? light_exp : 32.f;
 
-	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
-	
-	LLCubeMap* skyMap = gSky.mVOSkyp->getCubeMap();
-	
-	gWaterProgram.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+	LLGLSLShader* shader;
 
-	if (skyMap)
+	F32 eyedepth = gCamera->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
+	
+	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
 	{
-		skyMap->bind();
+		shader = &gUnderWaterProgram;
 	}
 	else
 	{
-		llwarns << "NULL gSky.mVOSkyp->getCubeMap(), not binding." << llendl;
+		shader = &gWaterProgram;
 	}
 
+	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
+	
+	S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
+		
+	if (reftex > -1)
+	{
+		glActiveTextureARB(GL_TEXTURE0_ARB+reftex);
+		gPipeline.mWaterRef.bindTexture();
+		glActiveTextureARB(GL_TEXTURE0_ARB);
+	}	
+
 	//bind normal map
-	S32 bumpTex = gWaterProgram.enableTexture(LLShaderMgr::BUMP_MAP);
+	S32 bumpTex = shader->enableTexture(LLShaderMgr::BUMP_MAP);
+
+	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+
+	// change mWaterNormp if needed
+	if (mWaterNormp->getID() != param_mgr->getNormalMapID())
+	{
+		mWaterNormp = gImageList.getImage(param_mgr->getNormalMapID());
+	}
+
 	mWaterNormp->addTextureStats(1024.f*1024.f);
 	mWaterNormp->bind(bumpTex);
-	
-	gWaterProgram.enableTexture(LLShaderMgr::WATER_SCREENTEX);	
-
-	gWaterProgram.bind();
-	
-	if (!sSkipScreenCopy)
+	if (!gSavedSettings.getBOOL("RenderWaterMipNormal"))
 	{
-		gPipeline.bindScreenToTexture();
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 	}
 	else
 	{
-		glBindTexture(GL_TEXTURE_2D, 0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 	}
 	
-	glUniform2fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_FBSCALE], 1, 
-			gPipeline.mScreenScale.mV);
+	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);	
+	stop_glerror();
+	
+	shader->bind();
 
-	S32 diffTex = gWaterProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP);
+	if (screentex > -1)
+	{
+		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, 
+			param_mgr->getFogDensity());
+	}
 	
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+	gPipeline.mWaterDis.bindTexture();
 
-	glUniform1fARB(gWaterProgram.mUniform[LLShaderMgr::WATER_TIME], sTime);
-	glUniform3fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_SPECULAR], 1, light_diffuse.mV);
-	glUniform1fARB(gWaterProgram.mUniform[LLShaderMgr::WATER_SPECULAR_EXP], light_exp);
-	glUniform3fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_EYEVEC], 1, (GLfloat *)(gCamera->getOrigin().mV));
-	glUniform2fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_WAVE_DIR1], 1, d1.mV);
-	glUniform2fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_WAVE_DIR2], 1, d2.mV);
-	glUniform3fvARB(gWaterProgram.mUniform[LLShaderMgr::WATER_LIGHT_DIR], 1, light_dir.mV);
+	if (mVertexShaderLevel == 1)
+	{
+		sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue;
+		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+	}
+
+	F32 screenRes[] = 
+	{
+		1.f/gGLViewport[2],
+		1.f/gGLViewport[3]
+	};
+	shader->uniform2fv("screenRes", 1, screenRes);
+	stop_glerror();
+	
+	S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+	stop_glerror();
+	
+	light_dir.normVec();
+	sLightDir = light_dir;
+	
+	light_diffuse *= 6.f;
+
+	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
+	shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth);
+	shader->uniform1f(LLShaderMgr::WATER_TIME, sTime);
+	shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, gCamera->getOrigin().mV);
+	shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
+	shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
+	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV);
+	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV);
+	shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
+
+	shader->uniform3fv("normScale", 1, param_mgr->getNormalScale().mV);
+	shader->uniform1f("fresnelScale", param_mgr->getFresnelScale());
+	shader->uniform1f("fresnelOffset", param_mgr->getFresnelOffset());
+	shader->uniform1f("blurMultiplier", param_mgr->getBlurMultiplier());
+
+	F32 sunAngle = llmax(0.f, light_dir.mV[2]);
+	F32 scaledAngle = 1.f - sunAngle;
+
+	shader->uniform1f("sunAngle", sunAngle);
+	shader->uniform1f("scaledAngle", scaledAngle);
+	shader->uniform1f("sunAngle2", 0.1f + 0.2f*sunAngle);
 
 	LLColor4 water_color;
 	LLVector3 camera_up = gCamera->getUpAxis();
@@ -616,13 +512,14 @@ void LLDrawPoolWater::shade()
 	if (gCamera->cameraUnderWater())
 	{
 		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-		glUniform1fARB(gWaterProgram.mUniform[LLShaderMgr::WATER_REFSCALE], 0.25f);
+		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow());
 	}
 	else
 	{
 		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-		glUniform1fARB(gWaterProgram.mUniform[LLShaderMgr::WATER_REFSCALE], 0.01f);
+		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove());
 	}
+
 	if (water_color.mV[3] > 0.9f)
 	{
 		water_color.mV[3] = 0.9f;
@@ -642,24 +539,46 @@ void LLDrawPoolWater::shade()
 				continue;
 			}
 
+			LLVOWater* water = (LLVOWater*) face->getViewerObject();
 			face->bindTexture(diffTex);
-			face->renderIndexed();
+
+			sNeedsReflectionUpdate = TRUE;
+			
+			if (water->getUseTexture())
+			{
+				face->renderIndexed();
+			}
+			else
+			{ //smash background faces to far clip plane
+				if (water->getIsEdgePatch())
+				{
+					LLGLClampToFarClip far_clip(glh_get_current_projection());
+					face->renderIndexed();
+				}
+				else
+				{
+					face->renderIndexed();
+				}
+			}
+						
 			mIndicesDrawn += face->getIndicesCount();
 		}
 	}
 	
-	gWaterProgram.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
-	gWaterProgram.disableTexture(LLShaderMgr::WATER_SCREENTEX);
-	gWaterProgram.disableTexture(LLShaderMgr::BUMP_MAP);
-	gWaterProgram.disableTexture(LLShaderMgr::DIFFUSE_MAP);
+	shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+	shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);	
+	shader->disableTexture(LLShaderMgr::BUMP_MAP);
+	shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
+	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+	shader->unbind();
 
 	glActiveTextureARB(GL_TEXTURE0_ARB);
-	glEnable(GL_TEXTURE_2D);
-	glUseProgramObjectARB(0);
-	
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glEnable(GL_TEXTURE_2D);
 	glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
+
 }
 
 void LLDrawPoolWater::renderForSelect()
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index 24346c4a5f6..d9b91db85cf 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -49,6 +49,11 @@ class LLDrawPoolWater: public LLFacePool
 	const LLWaterSurface *mWaterSurface;
 public:
 	static BOOL sSkipScreenCopy;
+	static BOOL sNeedsReflectionUpdate;
+	static LLVector3 sLightDir;
+
+	static LLColor4 sWaterFogColor;
+
 	enum
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
@@ -58,17 +63,13 @@ class LLDrawPoolWater: public LLFacePool
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 
-	enum
-	{
-		SHADER_LEVEL_RIPPLE = 2,
-	};
-	
 	LLDrawPoolWater();
 	/*virtual*/ ~LLDrawPoolWater();
 
 	/*virtual*/ LLDrawPool *instancePool();
 	static void restoreGL();
 
+	/*virtual*/ S32 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color,
 										const S32 index_offset = 0, const S32 index_count = 0);
@@ -80,9 +81,6 @@ class LLDrawPoolWater: public LLFacePool
 
 	void renderReflection(LLFace* face);
 	void shade();
-	void renderShaderSimple();
-
-	virtual S32 getMaterialAttribIndex() { return 0; }
 };
 
 void cgErrorCallback();
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
new file mode 100644
index 00000000000..e080e4e29b6
--- /dev/null
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -0,0 +1,343 @@
+/** 
+ * @file lldrawpoolwlsky.cpp
+ * @brief LLDrawPoolWLSky class implementation
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawpoolwlsky.h"
+
+#include "llerror.h"
+#include "llgl.h"
+#include "pipeline.h"
+#include "llviewercamera.h"
+#include "llimage.h"
+#include "llwlparammanager.h"
+#include "llsky.h"
+#include "llvowlsky.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llface.h"
+#include "llglimmediate.h"
+
+LLPointer<LLImageGL> LLDrawPoolWLSky::sCloudNoiseTexture = NULL;
+
+LLPointer<LLImageRaw> LLDrawPoolWLSky::sCloudNoiseRawImage = NULL;
+
+
+
+LLDrawPoolWLSky::LLDrawPoolWLSky(void) :
+	LLDrawPool(POOL_WL_SKY)
+{
+	const LLString cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", "clouds2.tga"));
+	llinfos << "loading WindLight cloud noise from " << cloudNoiseFilename << llendl;
+
+	LLPointer<LLImageFormatted> cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename));
+
+	if(cloudNoiseFile.isNull()) {
+		llerrs << "Error: Failed to load cloud noise image " << cloudNoiseFilename << llendl;
+	}
+
+	cloudNoiseFile->load(cloudNoiseFilename);
+
+	sCloudNoiseRawImage = new LLImageRaw();
+
+	cloudNoiseFile->decode(sCloudNoiseRawImage);
+
+	LLImageGL::create(sCloudNoiseTexture, sCloudNoiseRawImage, TRUE);
+
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+LLDrawPoolWLSky::~LLDrawPoolWLSky()
+{
+	//llinfos << "destructing wlsky draw pool." << llendl;
+	sCloudNoiseTexture = 0;
+}
+
+LLViewerImage *LLDrawPoolWLSky::getDebugTexture()
+{
+	return NULL;
+}
+
+void LLDrawPoolWLSky::beginRenderPass( S32 pass )
+{
+}
+
+void LLDrawPoolWLSky::endRenderPass( S32 pass )
+{
+}
+
+void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) const
+{
+	LLVector3 const & origin = gCamera->getOrigin();
+
+	llassert_always(NULL != shader);
+
+	glPushMatrix();
+
+	//chop off translation
+	if (LLPipeline::sReflectionRender && origin.mV[2] > 256.f)
+	{
+		glTranslatef(origin.mV[0], origin.mV[1], 256.f-origin.mV[2]*0.5f);
+	}
+	else
+	{
+		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
+	}
+		
+
+	// the windlight sky dome works most conveniently in a coordinate system
+	// where Y is up, so permute our basis vectors accordingly.
+	glRotatef(120.f, 1.f / F_SQRT3, 1.f / F_SQRT3, 1.f / F_SQRT3);
+
+	glScalef(0.333f, 0.333f, 0.333f);
+
+	glTranslatef(0.f,-camHeightLocal, 0.f);
+	
+	// Draw WL Sky	
+	shader->uniform3f("camPosLocal", 0.f, camHeightLocal, 0.f);
+
+	gSky.mVOWLSkyp->drawDome();
+
+	glPopMatrix();
+}
+
+void LLDrawPoolWLSky::renderSkyHaze(F32 camHeightLocal) const
+{
+	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
+	{
+		LLGLSLShader* shader =
+			LLPipeline::sUnderWaterRender ?
+				&gObjectSimpleWaterProgram :
+				&gWLSkyProgram;
+
+		LLGLDisable blend(GL_BLEND);
+
+		shader->bind();
+
+		/// Render the skydome
+		renderDome(camHeightLocal, shader);	
+
+		shader->unbind();
+	}
+}
+
+void LLDrawPoolWLSky::renderStars(void) const
+{
+	LLGLSPipelineSkyBox gls_sky;
+	LLGLEnable blend(GL_BLEND);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	
+	// *NOTE: have to have bound the cloud noise texture already since register
+	// combiners blending below requires something to be bound
+	// and we might as well only bind once.
+	//LLGLEnable gl_texture_2d(GL_TEXTURE_2D);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+
+	gPipeline.disableLights();
+
+	if (!LLPipeline::sReflectionRender)
+	{
+		glPointSize(2.f);
+	}
+
+	// *NOTE: we divide by two here and GL_ALPHA_SCALE by two below to avoid
+	// clamping and allow the star_alpha param to brighten the stars.
+	bool error;
+	LLColor4 star_alpha(LLColor4::black);
+	star_alpha.mV[3] = LLWLParamManager::instance()->mCurParams.getFloat("star_brightness", error) / 2.f;
+	llassert_always(!error);
+
+	// gl_FragColor.rgb = gl_Color.rgb;
+	// gl_FragColor.a = gl_Color.a * star_alpha.a;
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
+	glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 2.0f);
+	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV);
+
+	gSky.mVOWLSkyp->drawStars();
+
+	glPointSize(1.f);
+
+	// and disable the combiner states
+	glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const
+{
+	if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))
+	{
+		LLGLSLShader* shader =
+			LLPipeline::sUnderWaterRender ?
+				&gObjectSimpleWaterProgram :
+				&gWLCloudProgram;
+
+		LLGLEnable blend(GL_BLEND);
+		LLGLSBlendFunc blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		glAlphaFunc(GL_GREATER, 0.01f);
+
+		sCloudNoiseTexture->bind();
+		shader->bind();
+
+		/// Render the skydome
+		renderDome(camHeightLocal, shader);
+
+		shader->unbind();
+	}
+}
+
+void LLDrawPoolWLSky::renderHeavenlyBodies()
+{
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	LLGLSPipelineSkyBox gls_skybox;
+	LLGLEnable blend_on(GL_BLEND);
+	gPipeline.disableLights();
+
+#if 0 // when we want to re-add a texture sun disc, here's where to do it.
+	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN];
+	if (gSky.mVOSkyp->getSun().getDraw() && face->getGeomCount())
+	{
+		LLImageGL * tex  = face->getTexture();
+		tex->bind();
+		LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor());
+		LLFacePool::LLOverrideFaceColor color_override(this, color);
+		face->renderIndexed();
+		mIndicesDrawn += face->getIndicesCount();
+	}
+#endif
+
+	LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON];
+
+	if (gSky.mVOSkyp->getMoon().getDraw() && face->getGeomCount())
+	{
+		// *NOTE: even though we already bound this texture above for the
+		// stars register combiners, we bind again here for defensive reasons,
+		// since LLImageGL::bind detects that it's a noop, and optimizes it out.
+		LLImageGL * tex  = face->getTexture();
+		tex->bind();
+		LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor());
+		F32 a = gSky.mVOSkyp->getMoon().getDirection().mV[2];
+		if (a > 0.f)
+		{
+			a = a*a*4.f;
+		}
+			
+		color.mV[3] = llclamp(a, 0.f, 1.f);
+		
+		LLFacePool::LLOverrideFaceColor color_override(this, color);
+		face->renderIndexed();
+		mIndicesDrawn += face->getIndicesCount();
+	}
+
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void LLDrawPoolWLSky::render(S32 pass)
+{
+	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
+	{
+		return;
+	}
+	LLFastTimer ftm(LLFastTimer::FTM_RENDER_WL_SKY);
+
+	const F32 camHeightLocal = LLWLParamManager::instance()->getDomeOffset() * LLWLParamManager::instance()->getDomeRadius();
+
+	LLGLSNoFog disableFog;
+	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+	LLGLDisable clip(GL_CLIP_PLANE0);
+
+	LLGLClampToFarClip far_clip(glh_get_current_projection());
+
+	renderSkyHaze(camHeightLocal);
+
+	LLVector3 const & origin = gCamera->getOrigin();
+	glPushMatrix();
+
+		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
+
+		// *NOTE: have to bind a texture here since register combiners blending in
+		// renderStars() requires something to be bound and we might as well only
+		// bind the moon's texture once.
+		LLImageGL * tex  = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture();
+		tex->bind();
+
+		renderHeavenlyBodies();
+
+		renderStars();
+		
+
+	glPopMatrix();
+
+	renderSkyClouds(camHeightLocal);
+
+	LLImageGL::unbindTexture(0);
+}
+
+void LLDrawPoolWLSky::prerender()
+{
+	//llinfos << "wlsky prerendering pass." << llendl;
+}
+
+LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool()
+{
+	return new LLDrawPoolWLSky();
+}
+
+LLViewerImage* LLDrawPoolWLSky::getTexture()
+{
+	return NULL;
+}
+
+void LLDrawPoolWLSky::resetDrawOrders()
+{
+}
+
+//static
+void LLDrawPoolWLSky::cleanupGL()
+{
+	sCloudNoiseTexture = NULL;
+}
+
+//static
+void LLDrawPoolWLSky::restoreGL()
+{
+	LLImageGL::create(sCloudNoiseTexture, sCloudNoiseRawImage, TRUE);
+}
diff --git a/indra/newview/lldrawpoolwlsky.h b/indra/newview/lldrawpoolwlsky.h
new file mode 100644
index 00000000000..7e2137ffeef
--- /dev/null
+++ b/indra/newview/lldrawpoolwlsky.h
@@ -0,0 +1,84 @@
+/** 
+ * @file lldrawpoolwlsky.h
+ * @brief LLDrawPoolWLSky class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_DRAWPOOLWLSKY_H
+#define LL_DRAWPOOLWLSKY_H
+
+#include "lldrawpool.h"
+
+class LLGLSLShader;
+
+class LLDrawPoolWLSky : public LLDrawPool {
+public:
+
+	static const U32 SKY_VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_TEXCOORD;
+	static const U32 STAR_VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_COLOR;
+
+	LLDrawPoolWLSky(void);
+	/*virtual*/ ~LLDrawPoolWLSky();
+
+	/*virtual*/ BOOL isDead() { return FALSE; }
+
+	/*virtual*/ LLViewerImage *getDebugTexture();
+	/*virtual*/ void beginRenderPass( S32 pass );
+	/*virtual*/ void endRenderPass( S32 pass );
+	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
+	/*virtual*/ U32 getVertexDataMask() { return SKY_VERTEX_DATA_MASK; }
+	/*virtual*/ BOOL verify() const { return TRUE; }		// Verify that all data in the draw pool is correct!
+	/*virtual*/ S32 getVertexShaderLevel() const { return mVertexShaderLevel; }
+	
+	//static LLDrawPool* createPool(const U32 type, LLViewerImage *tex0 = NULL);
+
+	// Create an empty new instance of the pool.
+	/*virtual*/ LLDrawPoolWLSky *instancePool();  ///< covariant override
+	/*virtual*/ LLViewerImage* getTexture();
+	/*virtual*/ BOOL isFacePool() { return FALSE; }
+	/*virtual*/ void resetDrawOrders();
+
+	static void cleanupGL();
+	static void restoreGL();
+private:
+	void renderDome(F32 camHeightLocal, LLGLSLShader * shader) const;
+	void renderSkyHaze(F32 camHeightLocal) const;
+	void renderStars(void) const;
+	void renderSkyClouds(F32 camHeightLocal) const;
+	void renderHeavenlyBodies();
+
+private:
+	static LLPointer<LLImageGL> sCloudNoiseTexture;
+	static LLPointer<LLImageRaw> sCloudNoiseRawImage;
+};
+
+#endif // LL_DRAWPOOLWLSKY_H
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 8f6b572a9d7..a4b3d259bb5 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -40,7 +40,10 @@
 #include "llviewercontrol.h"
 #include "llviewerimage.h"
 #include "llvertexbuffer.h"
+#include "llviewerdisplay.h"
+#include "llglimmediate.h"
 
+void render_ui_and_swap_if_needed();
 
 // static
 LLLinkedList<LLDynamicTexture> LLDynamicTexture::sInstances[ LLDynamicTexture::ORDER_COUNT ];
@@ -216,15 +219,22 @@ BOOL LLDynamicTexture::updateAllInstances()
 			dynamicTexture = LLDynamicTexture::sInstances[order].getNextData())
 		{
 			if (dynamicTexture->needsRender())
-			{	
+			{
+				render_ui_and_swap_if_needed();
+				glClear(GL_DEPTH_BUFFER_BIT);
+				gDisplaySwapBuffers = FALSE;
+				
+				LLVertexBuffer::startRender();
+				gGL.start();
+								
 				dynamicTexture->preRender();	// Must be called outside of startRender()
 
-				LLVertexBuffer::startRender();
 				if (dynamicTexture->render())
 				{
 					result = TRUE;
 					sNumRenders++;
 				}
+				gGL.stop();
 				LLVertexBuffer::stopRender();
 		
 				dynamicTexture->postRender(result);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index be19b30c7b7..3e8d518c023 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -40,9 +40,9 @@
 #include "m3math.h"
 #include "v3color.h"
 
-#include "lldrawpoolsimple.h"
 #include "lldrawpoolbump.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "lllightconstants.h"
 #include "llsky.h"
 #include "llviewercamera.h"
@@ -50,6 +50,7 @@
 #include "llvosky.h"
 #include "llvovolume.h"
 #include "pipeline.h"
+#include "llviewerregion.h"
 
 #define LL_MAX_INDICES_COUNT 1000000
 
@@ -140,19 +141,20 @@ void cylindricalProjection(LLVector2 &tc, const LLVolumeFace::VertexData &vd, co
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
 	mLastUpdateTime = gFrameTimeSeconds;
+	mLastMoveTime = 0.f;
 	mVSize = 0.f;
-	mPixelArea = 1024.f;
+	mPixelArea = 16.f;
 	mState      = GLOBAL;
 	mDrawPoolp  = NULL;
 	mPoolType = 0;
-	mGeomIndex  = -1;
-	// mCenterLocal
-	// mCenterAgent
+	mCenterLocal = objp->getPosition();
+	mCenterAgent = drawablep->getPositionAgent();
 	mDistance	= 0.f;
 
 	mGeomCount		= 0;
+	mGeomIndex		= 0;
 	mIndicesCount	= 0;
-	mIndicesIndex	= -1;
+	mIndicesIndex	= 0;
 	mTexture		= NULL;
 	mTEOffset		= -1;
 
@@ -160,7 +162,8 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mVObjp = objp;
 
 	mReferenceIndex = -1;
-	mAlphaFade = 0.f;
+
+	mTextureMatrix = NULL;
 
 	mFaceColor = LLColor4(1,0,0,1);
 
@@ -182,6 +185,12 @@ void LLFace::destroy()
 		mDrawPoolp->removeFace(this);
 		mDrawPoolp = NULL;
 	}
+
+	if (mTextureMatrix)
+	{
+		delete mTextureMatrix;
+		mTextureMatrix = NULL;
+	}
 }
 
 
@@ -216,7 +225,7 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerImage *texturep)
 				gPipeline.markRebuild(mDrawablep, LLDrawable::REBUILD_ALL, TRUE);
 			}
 		}
-		mGeomIndex = -1;
+		mGeomIndex = 0;
 
 		// Add to new pool
 		if (new_pool)
@@ -260,10 +269,9 @@ void LLFace::setSize(const S32 num_vertices, const S32 num_indices)
 
 //============================================================================
 
-S32 LLFace::getGeometryAvatar(
+U16 LLFace::getGeometryAvatar(
 						LLStrider<LLVector3> &vertices,
 						LLStrider<LLVector3> &normals,
-						LLStrider<LLVector3> &binormals,
 						LLStrider<LLVector2> &tex_coords,
 						LLStrider<F32>		 &vertex_weights,
 						LLStrider<LLVector4> &clothing_weights)
@@ -274,56 +282,19 @@ S32 LLFace::getGeometryAvatar(
 	{
 		mVertexBuffer->getVertexStrider      (vertices, mGeomIndex);
 		mVertexBuffer->getNormalStrider      (normals, mGeomIndex);
-		mVertexBuffer->getBinormalStrider    (binormals, mGeomIndex);
 		mVertexBuffer->getTexCoordStrider    (tex_coords, mGeomIndex);
 		mVertexBuffer->getWeightStrider(vertex_weights, mGeomIndex);
 		mVertexBuffer->getClothWeightStrider(clothing_weights, mGeomIndex);
 	}
-	else
-	{
-		mGeomIndex = -1;
-	}
-
-	return mGeomIndex;
-}
 
-S32 LLFace::getGeometryTerrain(
-						LLStrider<LLVector3> &vertices,
-						LLStrider<LLVector3> &normals,
-						LLStrider<LLColor4U> &colors,
-						LLStrider<LLVector2> &texcoords0,
-						LLStrider<LLVector2> &texcoords1,
-						LLStrider<U32> &indicesp)
-{
-	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
-	
-	if (mVertexBuffer.notNull())
-	{
-		mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
-		mVertexBuffer->getNormalStrider(normals, mGeomIndex);
-		mVertexBuffer->getColorStrider(colors, mGeomIndex);
-		mVertexBuffer->getTexCoordStrider(texcoords0, mGeomIndex);
-		mVertexBuffer->getTexCoord2Strider(texcoords1, mGeomIndex);
-		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
-	}
-	else
-	{
-		mGeomIndex = -1;
-	}
-	
 	return mGeomIndex;
 }
 
-S32 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals,
-					    LLStrider<LLVector2> &tex_coords, LLStrider<U32> &indicesp)
+U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals,
+					    LLStrider<LLVector2> &tex_coords, LLStrider<U16> &indicesp)
 {
 	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
 	
-	if (mGeomCount <= 0)
-	{
-		return -1;
-	}
-	
 	if (mVertexBuffer.notNull())
 	{
 		mVertexBuffer->getVertexStrider(vertices,   mGeomIndex);
@@ -338,26 +309,10 @@ S32 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no
 
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
 	}
-	else
-	{
-		mGeomIndex = -1;
-	}
 	
 	return mGeomIndex;
 }
 
-S32 LLFace::getGeometryColors(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals,
-							  LLStrider<LLVector2> &tex_coords, LLStrider<LLColor4U> &colors,
-							  LLStrider<U32> &indicesp)
-{
-	S32 res = getGeometry(vertices, normals, tex_coords, indicesp);
-	if (res >= 0)
-	{
-		getColors(colors);
-	}
-	return res;
-}
-
 void LLFace::updateCenterAgent()
 {
 	if (mDrawablep->isActive())
@@ -372,7 +327,13 @@ void LLFace::updateCenterAgent()
 
 void LLFace::renderForSelect(U32 data_mask)
 {
-	if(mGeomIndex < 0 || mDrawablep.isNull() || mVertexBuffer.isNull())
+	if(mDrawablep.isNull() || mVertexBuffer.isNull())
+	{
+		return;
+	}
+
+	LLSpatialGroup* group = mDrawablep->getSpatialGroup();
+	if (!group || group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		return;
 	}
@@ -407,7 +368,7 @@ void LLFace::renderForSelect(U32 data_mask)
 #if !LL_RELEASE_FOR_DOWNLOAD
 		LLGLState::checkClientArrays(data_mask);
 #endif
-		U32* indicesp = (U32*) mVertexBuffer->getIndicesPointer() + mIndicesIndex;
+		U16* indicesp = (U16*) mVertexBuffer->getIndicesPointer() + mIndicesIndex;
 
 		if (gPickFaces && mTEOffset != -1)
 		{
@@ -421,13 +382,23 @@ void LLFace::renderForSelect(U32 data_mask)
 		{
 			if (isState(GLOBAL))
 			{
-				glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); 
+				if (mDrawablep->getVOVolume())
+				{
+					glPushMatrix();
+					glMultMatrixf((float*) mDrawablep->getRegion()->mRenderMatrix.mMatrix);
+					glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, indicesp); 
+					glPopMatrix();
+				}
+				else
+				{
+					glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, indicesp); 
+				}
 			}
 			else
 			{
 				glPushMatrix();
 				glMultMatrixf((float*)getRenderMatrix().mMatrix);
-				glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); 
+				glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, indicesp); 
 				glPopMatrix();
 			}
 		}
@@ -450,7 +421,7 @@ void LLFace::renderForSelect(U32 data_mask)
 
 void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32 offset, const S32 count)
 {
-	if(mGeomIndex < 0 || mDrawablep.isNull() || mVertexBuffer.isNull())
+	if(mDrawablep.isNull() || mVertexBuffer.isNull())
 	{
 		return;
 	}
@@ -461,11 +432,15 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32
 		glColor4fv(color.mV);
 
 		LLViewerImage::bindTexture(imagep);
-		if (!isState(GLOBAL))
+	
+		glPushMatrix();
+		if (mDrawablep->isActive())
+		{
+			glMultMatrixf((GLfloat*)mDrawablep->getRenderMatrix().mMatrix);
+		}
+		else
 		{
-			// Apply the proper transform for non-global objects.
-			glPushMatrix();
-			glMultMatrixf((float*)getRenderMatrix().mMatrix);
+			glMultMatrixf((GLfloat*)mDrawablep->getRegion()->mRenderMatrix.mMatrix);
 		}
 
 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -476,24 +451,20 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color, const S32
 #if !LL_RELEASE_FOR_DOWNLOAD
 		LLGLState::checkClientArrays(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD);
 #endif
-		U32* indicesp = ((U32*) mVertexBuffer->getIndicesPointer()) + mIndicesIndex;
+		U16* indicesp = ((U16*) mVertexBuffer->getIndicesPointer()) + mIndicesIndex;
 
 		if (count)
 		{
-			glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, indicesp + offset); 
+			glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indicesp + offset); 
 		}
 		else
 		{
-			glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, indicesp); 
+			glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, indicesp); 
 		}
 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 		glDisableClientState(GL_NORMAL_ARRAY);
 		
-		if (!isState(GLOBAL))
-		{
-			// Restore the tranform for non-global objects
-			glPopMatrix();
-		}
+		glPopMatrix();
 	}
 }
 
@@ -507,8 +478,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 
 	LLGLSObjectSelect object_select;
 	LLGLEnable blend(GL_BLEND);
-	LLGLEnable texture(GL_TEXTURE_2D);
-
+	
 	if (!mDrawPoolp || !getIndicesCount() || getIndicesStart() < 0)
 	{
 		return;
@@ -519,7 +489,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 		static F32 factor = -10.f;
 		if (mGeomCount > 0)
 		{
-			glColor4fv(LLColor4::white.mV);
+			gGL.color4fv(LLColor4::white.mV);
 
 			if (pass == 0)
 			{
@@ -527,7 +497,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 			}
 			else // pass == 1
 			{
-				glBlendFunc(GL_ONE, GL_ONE);
+				gGL.blendFunc(GL_ONE, GL_ONE);
 				LLViewerImage::bindTexture(green_imagep);
 				glMatrixMode(GL_TEXTURE);
 				glPushMatrix();
@@ -549,15 +519,15 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 			glPolygonOffset(factor, bias);
 			if (sSafeRenderSelect)
 			{
-				glBegin(GL_TRIANGLES);
+				gGL.begin(GL_TRIANGLES);
 				if (count)
 				{
 					for (S32 i = offset; i < offset + count; i++)
 					{
 						LLVector2 tc = mDrawPoolp->getTexCoord(mDrawPoolp->getIndex(getIndicesStart() + i), 0);
-						glTexCoord2fv(tc.mV);
+						gGL.texCoord2fv(tc.mV);
 						LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i));
-						glVertex3fv(vertex.mV);
+						gGL.vertex3fv(vertex.mV);
 					}
 				}
 				else
@@ -565,12 +535,12 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 					for (U32 i = 0; i < getIndicesCount(); i++)
 					{
 						LLVector2 tc = mDrawPoolp->getTexCoord(mDrawPoolp->getIndex(getIndicesStart() + i), 0);
-						glTexCoord2fv(tc.mV);
+						gGL.texCoord2fv(tc.mV);
 						LLVector3 vertex = mDrawPoolp->getVertex(mDrawPoolp->getIndex(getIndicesStart() + i));
-						glVertex3fv(vertex.mV);
+						gGL.vertex3fv(vertex.mV);
 					}
 				}
-				glEnd();
+				gGL.end();
 			}
 			else
 			{
@@ -581,7 +551,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 				{
 					if (mIndicesCount > 0)
 					{
-						glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, getRawIndices() + offset); 
+						glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, getRawIndices() + offset); 
 					}
 					else
 					{
@@ -593,7 +563,7 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 				{
 					if (mIndicesCount > 0)
 					{
-						glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, getRawIndices()); 
+						glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, getRawIndices()); 
 					}
 					else
 					{
@@ -614,13 +584,13 @@ void LLFace::renderSelectedUV(const S32 offset, const S32 count)
 				glMatrixMode(GL_TEXTURE);
 				glPopMatrix();
 				glMatrixMode(GL_MODELVIEW);
-				glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
+				gGL.blendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
 			}
 		}
 	}
 	
 	//restore blend func
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 #endif
 }
 
@@ -804,34 +774,51 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 			}
 		}
 
+		if (!mDrawablep->isActive())
+		{
+			LLVector3 offset = mDrawablep->getRegion()->getOriginAgent();
+			newMin += offset;
+			newMax += offset;
+		}
+
 		mCenterLocal = (newMin+newMax)*0.5f;
+		
 		updateCenterAgent();
 	}
 
 	return TRUE;
 }
 
-
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
-							   S32 f,
-								LLStrider<LLVector3>& vertices, 
-								LLStrider<LLVector3>& normals,
-								LLStrider<LLVector2>& tex_coords,
-								LLStrider<LLVector2>& tex_coords2,
-								LLStrider<LLColor4U>& colors,
-								LLStrider<U32>& indicesp,
+							   const S32 &f,
 								const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
-								U32& index_offset)
+								const U16 &index_offset)
 {
 	const LLVolumeFace &vf = volume.getVolumeFace(f);
 	S32 num_vertices = (S32)vf.mVertices.size();
 	S32 num_indices = (S32)vf.mIndices.size();
 	
-	LLStrider<LLVector3> old_verts;
-	LLStrider<LLVector2> old_texcoords;
-	LLStrider<LLVector2> old_texcoords2;
-	LLStrider<LLVector3> old_normals;
-	LLStrider<LLColor4U> old_colors;
+	if (mVertexBuffer.notNull())
+	{
+		if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices())
+		{
+			llwarns << "Index buffer overflow!" << llendl;
+			return FALSE;
+		}
+
+		if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts())
+		{
+			llwarns << "Vertex buffer overflow!" << llendl;
+			return FALSE;
+		}
+	}
+
+	LLStrider<LLVector3> old_verts,vertices;
+	LLStrider<LLVector2> old_texcoords,tex_coords;
+	LLStrider<LLVector2> old_texcoords2,tex_coords2;
+	LLStrider<LLVector3> old_normals,normals;
+	LLStrider<LLColor4U> old_colors,colors;
+	LLStrider<U16> indicesp;
 
 	BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
 	BOOL moved = TRUE;
@@ -859,91 +846,49 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			{ //data is in same location in vertex buffer
 				moved = FALSE;
 			}
-
+			
 			if (!moved && !mDrawablep->isState(LLDrawable::REBUILD_ALL))
 			{ //nothing needs to be done
-				vertices += mGeomCount;
-				normals += mGeomCount;
-				tex_coords += mGeomCount;
-				colors += mGeomCount;
-				tex_coords2 += mGeomCount;
-				index_offset += mGeomCount;
-				indicesp += mIndicesCount;
 				return FALSE;
 			}
-
-			if (mLastGeomCount == mGeomCount)
-			{
-				if (mLastGeomIndex >= mGeomIndex && 
-					mLastGeomIndex + mGeomCount+1 < mVertexBuffer->getNumVerts())
-				{
-					//copy from further down the buffer
-					mVertexBuffer->getVertexStrider(old_verts, mLastGeomIndex);
-					mVertexBuffer->getTexCoordStrider(old_texcoords, mLastGeomIndex);
-					mVertexBuffer->getTexCoord2Strider(old_texcoords2, mLastGeomIndex);
-					mVertexBuffer->getNormalStrider(old_normals, mLastGeomIndex);
-					mVertexBuffer->getColorStrider(old_colors, mLastGeomIndex);
-
-					if (!mDrawablep->isState(LLDrawable::REBUILD_ALL))
-					{
-						//quick copy
-						for (S32 i = 0; i < mGeomCount; i++)
-						{
-							*vertices++ = *old_verts++;
-							*tex_coords++ = *old_texcoords++;
-							*tex_coords2++ = *old_texcoords2++;
-							*colors++ = *old_colors++;
-							*normals++ = *old_normals++;
-						}
-
-						for (U32 i = 0; i < mIndicesCount; i++)
-						{
-							*indicesp++ = vf.mIndices[i] + index_offset;
-						}
-
-						index_offset += mGeomCount;
-						mLastGeomIndex = mGeomIndex;
-						mLastIndicesCount = mIndicesCount;
-						mLastIndicesIndex = mIndicesIndex;
-
-						return TRUE;
-					}
-				}
-				else
-				{
-					full_rebuild = TRUE;
-				}
-			}
-			else
-			{
-				full_rebuild = TRUE;
-			}
-		}
-		else
-		{
-			full_rebuild = TRUE;
 		}
+		mLastMoveTime = gFrameTimeSeconds;
 	}
 	else
 	{
 		mLastUpdateTime = gFrameTimeSeconds;
 	}
+	
+	BOOL rebuild_pos = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
+	BOOL rebuild_color = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
+	BOOL rebuild_tcoord = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
 
+	const LLTextureEntry *tep = mVObjp->getTE(f);
+	U8  bump_code = tep ? tep->getBumpmap() : 0;
 
-	BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
-	BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
-	BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
+	if (rebuild_pos)
+	{
+		mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
+		mVertexBuffer->getNormalStrider(normals, mGeomIndex);
+	}
+	if (rebuild_tcoord)
+	{
+		mVertexBuffer->getTexCoordStrider(tex_coords, mGeomIndex);
+		if (bump_code)
+		{
+			mVertexBuffer->getTexCoord2Strider(tex_coords2, mGeomIndex);
+		}
+	}
+	if (rebuild_color)
+	{	
+		mVertexBuffer->getColorStrider(colors, mGeomIndex);
+	}
 
 	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
 	
 	BOOL is_static = mDrawablep->isStatic();
 	BOOL is_global = is_static;
 
-	if (index_offset == (U32) -1)
-	{
-		return TRUE;
-	}
-	
 	LLVector3 center_sum(0.f, 0.f, 0.f);
 	
 	if (is_global)
@@ -957,8 +902,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 	LLVector2 tmin, tmax;
 	
-	const LLTextureEntry *tep = mVObjp->getTE(f);
-	U8  bump_code = tep ? tep->getBumpmap() : 0;
+	
 
 	if (rebuild_tcoord)
 	{
@@ -983,14 +927,23 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 
+	U8 tex_mode = 0;
+	
 	if (isState(TEXTURE_ANIM))
 	{
-		LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;
-		U8 mode = vobj->mTexAnimMode;
-		if (!mode)
+		LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
+		tex_mode = vobj->mTexAnimMode;
+
+		if (!tex_mode)
 		{
 			clearState(TEXTURE_ANIM);
 		}
+		//else if (getVirtualSize() <= 512.f)
+		//{			
+		//	//vobj->mTextureAnimp->animateTextures(os, ot, ms, mt, r);
+		//	//cos_ang = cos(r);
+		//	//sin_ang = sin(r);
+		//}
 		else
 		{
 			os = ot = 0.f;
@@ -999,6 +952,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			sin_ang = 0.f;
 			ms = mt = 1.f;
 		}
+
+		if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
+		{ //don't override texture transform during tc bake
+			tex_mode = 0;
+		}
 	}
 
 	LLColor4U color = tep->getColor();
@@ -1013,7 +971,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			0.75f
 		};
 
-		if (gPipeline.getPoolTypeFromTE(tep, getTexture()) == LLDrawPool::POOL_BUMP)
+		if (getPoolType() != LLDrawPool::POOL_ALPHA && LLPipeline::sRenderBump && tep->getShiny())
 		{
 			color.mV[3] = U8 (alpha[tep->getShiny()] * 255);
 		}
@@ -1022,23 +980,28 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
     // INDICES
 	if (full_rebuild || moved)
 	{
-		for (S32 i = 0; i < num_indices; i++)
+		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
+		for (U16 i = 0; i < num_indices; i++)
 		{
 			*indicesp++ = vf.mIndices[i] + index_offset;
 		}
 	}
-	else
-	{
-		indicesp += num_indices;
-	}
+	
 	
 	//bump setup
 	LLVector3 binormal_dir( -sin_ang, cos_ang, 0 );
 	LLVector3 bump_s_primary_light_ray;
 	LLVector3 bump_t_primary_light_ray;
+
+	LLQuaternion bump_quat;
+	if (mDrawablep->isActive())
+	{
+		bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
+	}
 	
 	if (bump_code)
 	{
+		mVObjp->getVolume()->genBinormals(f);
 		F32 offset_multiple; 
 		switch( bump_code )
 		{
@@ -1073,14 +1036,22 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		{
 			tep->getScale( &s_scale, &t_scale );
 		}
-		LLVector3   sun_ray  = gSky.getSunDirection();
+		// Use the nudged south when coming from above sun angle, such
+		// that emboss mapping always shows up on the upward faces of cubes when 
+		// it's noon (since a lot of builders build with the sun forced to noon).
+		LLVector3   sun_ray  = gSky.mVOSkyp->mBumpSunDir;
 		LLVector3   moon_ray = gSky.getMoonDirection();
 		LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
+
 		bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray;
 		bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray;
 	}
 		
 	U8 texgen = getTextureEntry()->getTexGen();
+	if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+	{ //planar texgen needs binormals
+		mVObjp->getVolume()->genBinormals(f);
+	}
 
 	for (S32 i = 0; i < num_vertices; i++)
 	{
@@ -1110,20 +1081,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}		
 			}
 
-			xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+			if (tex_mode && mTextureMatrix)
+			{
+				LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+				tmp = tmp * *mTextureMatrix;
+				tc.mV[0] = tmp.mV[0];
+				tc.mV[1] = tmp.mV[1];
+			}
+			else
+			{
+				xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+			}
+
 			*tex_coords++ = tc;
 		
 			if (bump_code)
 			{
 				LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal;
+
 				LLMatrix3 tangent_to_object;
 				tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal);
 				LLVector3 binormal = binormal_dir * tangent_to_object;
-
 				binormal = binormal * mat_normal;
-				binormal.normVec();
+				
+				if (mDrawablep->isActive())
+				{
+					binormal *= bump_quat;
+				}
 
+				binormal.normVec();
 				tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal );
+				
 				*tex_coords2++ = tc;
 			}	
 		}
@@ -1161,26 +1149,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 
-	if (!rebuild_pos && !moved)
-	{
-		vertices += num_vertices;
-	}
-
-	if (!rebuild_tcoord && !moved)
-	{
-		tex_coords2 += num_vertices;
-		tex_coords += num_vertices;
-	}
-	else if (!bump_code)
-	{
-		tex_coords2 += num_vertices;
-	}
-
-	if (!rebuild_color && !moved)
-	{
-		colors += num_vertices;
-	}
-
 	if (rebuild_tcoord)
 	{
 		mTexExtents[0].setVec(0,0);
@@ -1189,8 +1157,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);		
 	}
 
-	index_offset += num_vertices;
-
 	mLastVertexBuffer = mVertexBuffer;
 	mLastGeomCount = mGeomCount;
 	mLastGeomIndex = mGeomIndex;
@@ -1200,136 +1166,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	return TRUE;
 }
 
-#if 0
-BOOL LLFace::genLighting(const LLVolume* volume, const LLDrawable* drawablep, S32 fstart, S32 fend, 
-						 const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL do_lighting)
-{
-	if (drawablep->isLight())
-	{
-		do_lighting = FALSE;
-	}
-	
-	if (!((mDrawPoolp->mDataMaskIL) & LLDrawPool::DATA_COLORS_MASK))
-	{
-		return FALSE;
-	}
-	if (mGeomIndex < 0)
-	{
-		return FALSE; // no geometry
-	}
-	LLStrider<LLColor4U> colorsp;
-	S32 idx = getColors(colorsp);
-	if (idx < 0)
-	{
-		return FALSE;
-	}
-	
-	for (S32 vol_face = fstart; vol_face <= fend; vol_face++)
-	{
-		const LLVolumeFace &vf = volume->getVolumeFace(vol_face);
-		S32 num_vertices = (S32)vf.mVertices.size();
-
-		if (isState(FULLBRIGHT) || !do_lighting)
-		{
-			for (S32 i = 0; i < num_vertices; i++)
-			{
-				(*colorsp++).setToBlack();
-			}
-		}
-		else
-		{
-			for (S32 i = 0; i < num_vertices; i++)
-			{
-				LLVector3 vertex = vf.mVertices[i].mPosition * mat_vert;
-				LLVector3 normal = vf.mVertices[i].mNormal * mat_normal;
-				normal.normVec();
-		
-				LLColor4 color;
-				for (LLDrawable::drawable_set_t::const_iterator iter = drawablep->mLightSet.begin();
-					 iter != drawablep->mLightSet.end(); ++iter)
-				{
-					LLDrawable* light_drawable = *iter;
-					LLVOVolume* light = light_drawable->getVOVolume();
-					if (!light)
-					{
-						continue;
-					}
-					LLColor4 light_color;
-					light->calcLightAtPoint(vertex, normal, light_color);
-					color += light_color;
-				}
-
-				color.mV[3] = 1.0f;
-
-				(*colorsp++).setVecScaleClamp(color);
-			}
-		}
-	}
-	return TRUE;
-}
-
-BOOL LLFace::genShadows(const LLVolume* volume, const LLDrawable* drawablep, S32 fstart, S32 fend, 
-						 const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL use_shadow_factor)
-{
-	if (drawablep->isLight())
-	{
-		return FALSE;
-	}
-	
-	if (!((mDrawPoolp->mDataMaskIL) & LLDrawPool::DATA_COLORS_MASK))
-	{
-		return FALSE;
-	}
-	if (mGeomIndex < 0)
-	{
-		return FALSE; // no geometry
-	}
-	LLStrider<LLColor4U> colorsp;
-	S32 idx = getColors(colorsp);
-	if (idx < 0)
-	{
-		return FALSE;
-	}
-	
-	for (S32 vol_face = fstart; vol_face <= fend; vol_face++)
-	{
-		const LLVolumeFace &vf = volume->getVolumeFace(vol_face);
-		S32 num_vertices = (S32)vf.mVertices.size();
-
-		if (isState(FULLBRIGHT))
-		{
-			continue;
-		}
-
-		for (S32 i = 0; i < num_vertices; i++)
-		{
-			LLVector3 vertex = vf.mVertices[i].mPosition * mat_vert;
-			LLVector3 normal = vf.mVertices[i].mNormal * mat_normal;
-			normal.normVec();
-				
-			U8 shadow;
-
-			if (use_shadow_factor)
-			{
-				shadow = (U8) (drawablep->getSunShadowFactor() * 255);
-			}
-			else
-			{
-				shadow = 255;
-			}
-		
-			(*colorsp++).mV[3] = shadow;	
-		}
-	}
-	return TRUE;
-}
-#endif
-
 BOOL LLFace::verify(const U32* indices_array) const
 {
 	BOOL ok = TRUE;
 	// First, check whether the face data fits within the pool's range.
-	if ((mGeomIndex < 0) || (mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts())
+	if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts())
 	{
 		ok = FALSE;
 		llinfos << "Face not within pool range!" << llendl;
@@ -1385,27 +1226,6 @@ void LLFace::setViewerObject(LLViewerObject* objp)
 	mVObjp = objp;
 }
 
-void LLFace::enableLights() const
-{
- 	if (isState(FULLBRIGHT|HUD_RENDER))
-	{
-		gPipeline.enableLightsFullbright(LLColor4::white);
-	}
-	else if (mDrawablep->isState(LLDrawable::LIGHTING_BUILT))
-	{
-		gPipeline.enableLightsStatic(1.f);
-	}
-	else
-	{
-		gPipeline.enableLightsDynamic(1.f);
-	}
-	if (isState(LIGHT))
-	{
-		const LLVOVolume* vovolume = (const LLVOVolume*)mDrawablep->getVObj();
-		gPipeline.setAmbient(vovolume->getLightColor());
-	}
-}
-
 const LLColor4& LLFace::getRenderColor() const
 {
 	if (isState(USE_FACE_COLOR))
@@ -1425,18 +1245,11 @@ void LLFace::renderSetColor() const
 	{
 		const LLColor4* color = &(getRenderColor());
 		
-		if ((mDrawPoolp->mVertexShaderLevel > 0) && (mDrawPoolp->getMaterialAttribIndex() != 0))
-		{
-			glVertexAttrib4fvARB(mDrawPoolp->getMaterialAttribIndex(), color->mV);
-		}
-		else
-		{
-			glColor4fv(color->mV);
-		}
+		glColor4fv(color->mV);
 	}
 }
 
-S32 LLFace::pushVertices(const U32* index_array) const
+S32 LLFace::pushVertices(const U16* index_array) const
 {
 	if (mIndicesCount)
 	{
@@ -1444,14 +1257,15 @@ S32 LLFace::pushVertices(const U32* index_array) const
 			mIndicesCount <= (U32) gGLManager.mGLMaxIndexRange)
 		{
 			glDrawRangeElements(GL_TRIANGLES, mGeomIndex, mGeomIndex + mGeomCount-1, mIndicesCount, 
-									GL_UNSIGNED_INT, index_array + mIndicesIndex); 
+									GL_UNSIGNED_SHORT, index_array + mIndicesIndex); 
 		}
 		else
 		{
-			glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_INT, index_array+mIndicesIndex);
+			glDrawElements(GL_TRIANGLES, mIndicesCount, GL_UNSIGNED_SHORT, index_array+mIndicesIndex);
 		}
+		gPipeline.addTrianglesDrawn(mIndicesCount/3);
 	}
-	
+
 	return mIndicesCount;
 }
 
@@ -1460,7 +1274,7 @@ const LLMatrix4& LLFace::getRenderMatrix() const
 	return mDrawablep->getRenderMatrix();
 }
 
-S32 LLFace::renderElements(const U32 *index_array) const
+S32 LLFace::renderElements(const U16 *index_array) const
 {
 	S32 ret = 0;
 	
@@ -1481,7 +1295,7 @@ S32 LLFace::renderElements(const U32 *index_array) const
 
 S32 LLFace::renderIndexed()
 {
-	if(mGeomIndex < 0 || mDrawablep.isNull() || mDrawPoolp == NULL)
+	if(mDrawablep.isNull() || mDrawPoolp == NULL)
 	{
 		return 0;
 	}
@@ -1497,28 +1311,13 @@ S32 LLFace::renderIndexed(U32 mask)
 	}
 
 	mVertexBuffer->setBuffer(mask);
-	U32* index_array = (U32*) mVertexBuffer->getIndicesPointer();
+	U16* index_array = (U16*) mVertexBuffer->getIndicesPointer();
 	return renderElements(index_array);
 }
 
 //============================================================================
 // From llface.inl
 
-S32 LLFace::getVertices(LLStrider<LLVector3> &vertices)
-{
-	if (!mGeomCount)
-	{
-		return -1;
-	}
-	
-	if (mGeomIndex >= 0) // flexible objects may not have geometry
-	{
-		mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
-		
-	}
-	return mGeomIndex;
-}
-
 S32 LLFace::getColors(LLStrider<LLColor4U> &colors)
 {
 	if (!mGeomCount)
@@ -1526,15 +1325,15 @@ S32 LLFace::getColors(LLStrider<LLColor4U> &colors)
 		return -1;
 	}
 	
-	llassert(mGeomIndex >= 0);
+	// llassert(mGeomIndex >= 0);
 	mVertexBuffer->getColorStrider(colors, mGeomIndex);
 	return mGeomIndex;
 }
 
-S32	LLFace::getIndices(LLStrider<U32> &indicesp)
+S32	LLFace::getIndices(LLStrider<U16> &indicesp)
 {
 	mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
-	llassert(mGeomIndex >= 0 && indicesp[0] != indicesp[1]);
+	llassert(indicesp[0] != indicesp[1]);
 	return mIndicesIndex;
 }
 
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 2a732ee51da..6142ba6672d 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -55,6 +55,9 @@ class LLVertexProgram;
 class LLViewerImage;
 class LLGeometryManager;
 
+const F32 MIN_ALPHA_SIZE = 1024.f;
+const F32 MIN_TEX_ANIM_SIZE = 512.f;
+
 class LLFace
 {
 public:
@@ -79,9 +82,9 @@ class LLFace
 	const LLMatrix4& getRenderMatrix() const;
 	U32				getIndicesCount()	const	{ return mIndicesCount; };
 	S32				getIndicesStart()	const	{ return mIndicesIndex; };
-	S32				getGeomCount()		const	{ return mGeomCount; }		// vertex count for this face
-	S32				getGeomIndex()		const	{ return mGeomIndex; }		// index into draw pool
-	U32				getGeomStart()		const	{ return mGeomIndex; }		// index into draw pool
+	U16				getGeomCount()		const	{ return mGeomCount; }		// vertex count for this face
+	U16				getGeomIndex()		const	{ return mGeomIndex; }		// index into draw pool
+	U16				getGeomStart()		const	{ return mGeomIndex; }		// index into draw pool
 	LLViewerImage*	getTexture()		const	{ return mTexture; }
 	void			setTexture(LLViewerImage* tex) { mTexture = tex; }
 	LLXformMatrix*	getXform()			const	{ return mXform; }
@@ -98,12 +101,11 @@ class LLFace
 	F32				getPixelArea() const { return mPixelArea; }
 	void			bindTexture(S32 stage = 0)		const	{ LLViewerImage::bindTexture(mTexture, stage); }
 
-	void			enableLights() const;
 	void			renderSetColor() const;
-	S32				renderElements(const U32 *index_array) const;
+	S32				renderElements(const U16 *index_array) const;
 	S32				renderIndexed ();
 	S32				renderIndexed (U32 mask);
-	S32				pushVertices(const U32* index_array) const;
+	S32				pushVertices(const U16* index_array) const;
 	
 	void			setWorldMatrix(const LLMatrix4& mat);
 	const LLTextureEntry* getTextureEntry()	const { return mVObjp->getTE(mTEOffset); }
@@ -130,49 +132,27 @@ class LLFace
 	const LLColor4& getRenderColor() const;
 	
 	//for volumes
-	S32 getGeometryVolume(const LLVolume& volume,
-						S32 f,
-						LLStrider<LLVector3>& vertices, 
-						LLStrider<LLVector3>& normals,
-						LLStrider<LLVector2>& texcoords,
-						LLStrider<LLVector2>& texcoords2,
-						LLStrider<LLColor4U>& colors,
-						LLStrider<U32>& indices,
+	BOOL getGeometryVolume(const LLVolume& volume,
+						const S32 &f,
 						const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
-						U32& index_offset);
+						const U16 &index_offset);
 
 	// For avatar
-	S32				 getGeometryAvatar(
+	U16			 getGeometryAvatar(
 									LLStrider<LLVector3> &vertices,
 									LLStrider<LLVector3> &normals,
-									LLStrider<LLVector3> &binormals,
 								    LLStrider<LLVector2> &texCoords,
 									LLStrider<F32>		 &vertex_weights,
 									LLStrider<LLVector4> &clothing_weights);
 
-	// For terrain
-	S32				getGeometryTerrain(LLStrider<LLVector3> &vertices,
-									   LLStrider<LLVector3> &normals,
-									   LLStrider<LLColor4U> &colors,
-									   LLStrider<LLVector2> &texCoords0,
-									   LLStrider<LLVector2> &texCoords1,
-									   LLStrider<U32> &indices);
-
 	// For volumes, etc.
-	S32				getGeometry(LLStrider<LLVector3> &vertices,  
+	U16				getGeometry(LLStrider<LLVector3> &vertices,  
 								LLStrider<LLVector3> &normals,
 								LLStrider<LLVector2> &texCoords, 
-								LLStrider<U32>  &indices);
+								LLStrider<U16>  &indices);
 
-	S32				getGeometryColors(LLStrider<LLVector3> &vertices,  
-									  LLStrider<LLVector3> &normals,
-									  LLStrider<LLVector2> &texCoords, 
-									  LLStrider<LLColor4U> &colors, 
-									  LLStrider<U32>  &indices);
-	
-	S32 getVertices(LLStrider<LLVector3> &vertices);
 	S32 getColors(LLStrider<LLColor4U> &colors);
-	S32 getIndices(LLStrider<U32> &indices);
+	S32 getIndices(LLStrider<U16> &indices);
 
 	void		setSize(const S32 numVertices, const S32 num_indices = 0);
 	
@@ -197,7 +177,7 @@ class LLFace
 	BOOL		verify(const U32* indices_array = NULL) const;
 	void		printDebugInfo() const;
 
-	void		setGeomIndex(S32 idx) { mGeomIndex = idx; }
+	void		setGeomIndex(U16 idx) { mGeomIndex = idx; }
 	void		setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
 	
 protected:
@@ -208,11 +188,11 @@ class LLFace
 	LLVector3		mExtents[2];
 	LLVector2		mTexExtents[2];
 	F32				mDistance;
-	F32				mAlphaFade;
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	LLPointer<LLVertexBuffer> mLastVertexBuffer;
 	F32			mLastUpdateTime;
-	LLMatrix4	mTextureMatrix;
+	F32			mLastMoveTime;
+	LLMatrix4*	mTextureMatrix;
 
 protected:
 	friend class LLGeometryManager;
@@ -223,16 +203,16 @@ class LLFace
 	U32			mPoolType;
 	LLColor4	mFaceColor;			// overrides material color if state |= USE_FACE_COLOR
 	
-	S32			mGeomCount;			// vertex count for this face
-	S32			mGeomIndex;			// index into draw pool
+	U16			mGeomCount;			// vertex count for this face
+	U16			mGeomIndex;			// index into draw pool
 	U32			mIndicesCount;
-	S32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
+	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
 
 	//previous rebuild's geometry info
-	S32			mLastGeomCount;
-	S32			mLastGeomIndex;
+	U16			mLastGeomCount;
+	U16			mLastGeomIndex;
 	U32			mLastIndicesCount;
-	S32			mLastIndicesIndex;
+	U32			mLastIndicesIndex;
 
 	LLXformMatrix* mXform;
 	LLPointer<LLViewerImage> mTexture;
@@ -264,12 +244,34 @@ class LLFace
 		}
 	};
 
+	struct CompareBatchBreaker
+	{
+		bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
+		{
+			const LLTextureEntry* lte = lhs->getTextureEntry();
+			const LLTextureEntry* rte = rhs->getTextureEntry();
+
+			if (lhs->getTexture() != rhs->getTexture())
+			{
+				return lhs->getTexture() < rhs->getTexture();
+			}
+			else if (lte->getBumpShinyFullbright() != rte->getBumpShinyFullbright())
+			{
+				return lte->getBumpShinyFullbright() < rte->getBumpShinyFullbright();
+			}
+			else 
+			{
+				return lte->getGlow() < rte->getGlow();
+			}
+		}
+	};
+
 	struct CompareTextureAndGeomCount
 	{
 		bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
 		{
 			return lhs->getTexture() == rhs->getTexture() ? 
-				lhs->getGeomCount() < rhs->getGeomCount() :
+				lhs->getGeomCount() < rhs->getGeomCount() :  //smallest = first
 				lhs->getTexture() > rhs->getTexture();
 		}
 	};
diff --git a/indra/newview/llface.inl b/indra/newview/llface.inl
index 71f0638d454..aa944931961 100644
--- a/indra/newview/llface.inl
+++ b/indra/newview/llface.inl
@@ -69,87 +69,6 @@ inline LLViewerObject* LLFace::getViewerObject() const
 	return mVObjp;
 }
 
-
-
-inline S32 LLFace::getVertices(LLStrider<LLVector3> &vertices)
-{
-	if (!mGeomCount)
-	{
-		return -1;
-	}
-	if (isState(BACKLIST))
-	{
-		if (!mBackupMem)
-		{
-			printDebugInfo();
-			llerrs << "No backup memory for face" << llendl;
-		}
-		vertices = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_VERTICES]);
-		vertices.setStride( mDrawPoolp->getStride());
-		return 0;
-	}
-	else
-	{
-		llassert(mGeomIndex >= 0);
-		mDrawPoolp->getVertexStrider(vertices, mGeomIndex);
-		mDrawPoolp->setDirty();
-		return mGeomIndex;
-	}
-}
-
-inline S32 LLFace::getNormals(LLStrider<LLVector3> &normals)
-{
-	if (!mGeomCount)
-	{
-		return -1;
-	}
-	if (isState(BACKLIST))
-	{
-		if (!mBackupMem)
-		{
-			printDebugInfo();
-			llerrs << "No backup memory for face" << llendl;
-		}
-		normals   = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_NORMALS]);
-		normals.setStride( mDrawPoolp->getStride());
-		return 0;
-	}
-	else
-	{
-		llassert(mGeomIndex >= 0);
-		mDrawPoolp->getNormalStrider(normals, mGeomIndex);
-		mDrawPoolp->setDirty();
-		return mGeomIndex;
-	}
-}
-
-inline S32 LLFace::getBinormals(LLStrider<LLVector3> &binormals)
-{
-	if (!mGeomCount)
-	{
-		return -1;
-	}
-	if (isState(BACKLIST))
-	{
-		if (!mBackupMem)
-		{
-			printDebugInfo();
-			llerrs << "No backup memory for face" << llendl;
-		}
-		binormals   = (LLVector3*)(mBackupMem + (4 * mIndicesCount) + mDrawPoolp->mDataOffsets[LLDrawPool::DATA_BINORMALS]);
-		binormals.setStride( mDrawPoolp->getStride());
-		return 0;
-	}
-	else
-	{
-		llassert(mGeomIndex >= 0);
-		mDrawPoolp->getBinormalStrider(binormals, mGeomIndex);
-		mDrawPoolp->setDirty();
-		return mGeomIndex;
-	}
-}
-
-
 inline S32	LLFace::getColors     (LLStrider<LLColor4U> &colors)
 {
 	if (!mGeomCount)
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 7c1ec514e56..e29d8fb40df 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -37,6 +37,7 @@
 #include "llrect.h"
 #include "llerror.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llmath.h"
 #include "llfontgl.h"
 
@@ -56,20 +57,20 @@ static const S32 LINE_GRAPH_HEIGHT = 240;
 struct ft_display_info {
 	int timer;
 	const char *desc;
-	LLColor4 *color;
+	const LLColor4 *color;
 	S32 disabled; // initialized to 0
 	int level; // calculated based on desc
 	int parent; // calculated
 };
 
-static LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f);
-static LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f);
-static LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f);
-static LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f);
+static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f);
+static const LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f);
+static const LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f);
+static const LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f);
 
-static LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f);
-static LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f);
-static LLColor4 green9(0.6f, 1.0f, 0.6f, 1.0f);
+static const LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f);
+static const LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f);
+static const LLColor4 green9(0.6f, 1.0f, 0.6f, 1.0f);
 
 // green(6), blue, yellow, orange, pink(2), cyan
 // red (5) magenta (4)
@@ -93,40 +94,14 @@ static struct ft_display_info ft_display_table[] =
 	{ LLFastTimer::FTM_WORLD_UPDATE,		"  World Update",		&LLColor4::blue1, 1 },
 	{ LLFastTimer::FTM_UPDATE_MOVE,			"   Move Objects",		&LLColor4::pink2, 0 },
 	{ LLFastTimer::FTM_OCTREE_BALANCE,		"    Octree Balance", &LLColor4::red3, 0 },
-// 	{ LLFastTimer::FTM_TEMP1,				"   Blur",			&LLColor4::red1, 0 },
-	{ LLFastTimer::FTM_CULL,				"   Object Cull",	&LLColor4::blue2, 1 },
-    { LLFastTimer::FTM_CULL_REBOUND,		"    Rebound",		&LLColor4::blue3, 0 },
-	{ LLFastTimer::FTM_FRUSTUM_CULL,		"    Frustum Cull",	&LLColor4::blue4, 0 },
-	{ LLFastTimer::FTM_OCCLUSION,			"    Object Occlude", &LLColor4::pink1, 0 },
-	{ LLFastTimer::FTM_OCCLUSION_READBACK,	"    Occlusion Read", &LLColor4::red2, 0 },
-	{ LLFastTimer::FTM_HUD_EFFECTS,			"   HUD Effects",	&LLColor4::orange1, 0 },
-	{ LLFastTimer::FTM_HUD_UPDATE,			"   HUD Update",	&LLColor4::orange2, 0 },
-	{ LLFastTimer::FTM_GEO_UPDATE,			"   Geo Update",	&LLColor4::blue3, 0 },
-	{ LLFastTimer::FTM_UPDATE_PRIMITIVES,	"    Volumes",		&LLColor4::blue4, 0 },
-	{ LLFastTimer::FTM_GEN_VOLUME,			"     Gen Volume",	&LLColor4::yellow3, 0 },
-	{ LLFastTimer::FTM_GEN_FLEX,			"     Flexible",	&LLColor4::yellow4, 0 },
-	{ LLFastTimer::FTM_GEN_TRIANGLES,		"     Triangles",	&LLColor4::yellow5, 0 },
-	{ LLFastTimer::FTM_UPDATE_AVATAR,		"    Avatar",		&LLColor4::yellow1, 0 },
-	{ LLFastTimer::FTM_UPDATE_TREE,			"    Tree",			&LLColor4::yellow2, 0 },
-	{ LLFastTimer::FTM_UPDATE_TERRAIN,		"    Terrain",		&LLColor4::yellow6, 0 },
-	{ LLFastTimer::FTM_UPDATE_CLOUDS,		"    Clouds",		&LLColor4::yellow7, 0 },
-	{ LLFastTimer::FTM_UPDATE_GRASS,		"    Grass",		&LLColor4::yellow8, 0 },
-	{ LLFastTimer::FTM_UPDATE_WATER,		"    Water",		&LLColor4::yellow9, 0 },
-	{ LLFastTimer::FTM_GEO_LIGHT,			"    Lighting",		&LLColor4::yellow1, 0 },
-	{ LLFastTimer::FTM_GEO_SHADOW,			"    Shadow",		&LLColor4::black, 0 },
-	{ LLFastTimer::FTM_UPDATE_PARTICLES,	"    Particles",	&LLColor4::blue5, 0 },
-	{ LLFastTimer::FTM_SIMULATE_PARTICLES,	"    Particle Sim",	&LLColor4::blue4, 0 },
-	{ LLFastTimer::FTM_GEO_RESERVE,			"    Reserve",		&LLColor4::blue6, 0 },
-	{ LLFastTimer::FTM_UPDATE_LIGHTS,		"    Lights",		&LLColor4::yellow2, 0 },
-	{ LLFastTimer::FTM_UPDATE_SKY,			"  Sky Update",		&LLColor4::cyan1, 0 },
+	{ LLFastTimer::FTM_SIMULATE_PARTICLES,	"   Particle Sim",	&LLColor4::blue4, 0 },
 	{ LLFastTimer::FTM_OBJECTLIST_UPDATE,	"  Object Update",	&LLColor4::purple1, 0 },
 	{ LLFastTimer::FTM_AVATAR_UPDATE,		"   Avatars",		&LLColor4::purple2, 0 },
 	{ LLFastTimer::FTM_JOINT_UPDATE,		"    Joints",		&LLColor4::purple3, 0 },
 	{ LLFastTimer::FTM_ATTACHMENT_UPDATE,	"    Attachments",	&LLColor4::purple4, 0 },
-	{ LLFastTimer::FTM_UPDATE_ANIMATION,	"    Animation",	&LLColor4::purple5, 0 },
+	{ LLFastTimer::FTM_UPDATE_ANIMATION,	"     Animation",	&LLColor4::purple5, 0 },
 	{ LLFastTimer::FTM_FLEXIBLE_UPDATE,		"   Flex Update",	&LLColor4::pink2, 0 },
 	{ LLFastTimer::FTM_LOD_UPDATE,			"   LOD Update",	&LLColor4::magenta1, 0 },
-// 	{ LLFastTimer::FTM_TEMP5,				"    Check",	&LLColor4::red1, 1},
 	{ LLFastTimer::FTM_REGION_UPDATE,		"  Region Update",	&LLColor4::cyan2, 0 },
 	{ LLFastTimer::FTM_NETWORK,				"  Network",		&LLColor4::orange1, 1 },
 	{ LLFastTimer::FTM_IDLE_NETWORK,		"   Decode Msgs",	&LLColor4::orange2, 0 },
@@ -145,23 +120,48 @@ static struct ft_display_info ft_display_table[] =
 	{ LLFastTimer::FTM_VFILE_WAIT,			"  VFile Wait",		&LLColor4::cyan6, 0 },
 //	{ LLFastTimer::FTM_IDLE_CB,				"  Callbacks",		&LLColor4::pink1, 0 },
 	{ LLFastTimer::FTM_RENDER,				" Render",			&green0, 1 },
-	{ LLFastTimer::FTM_REBUILD,				"  Rebuild",		&LLColor4::green1, 1 },
-	{ LLFastTimer::FTM_STATESORT,			"   State Sort",	&LLColor4::orange1, 1 },
-	{ LLFastTimer::FTM_STATESORT_DRAWABLE,	"    Drawable",		&LLColor4::orange2, 0 },
-	{ LLFastTimer::FTM_STATESORT_POSTSORT,	"    Post Sort",	&LLColor4::orange3, 0 },
-	{ LLFastTimer::FTM_REBUILD_OCCLUSION_VB,"     Occlusion",		&LLColor4::cyan5, 0 },
-	{ LLFastTimer::FTM_REBUILD_VBO,			"     VBO Rebuild",	&LLColor4::red4, 0 },
-	{ LLFastTimer::FTM_REBUILD_VOLUME_VB,	"      Volume",		&LLColor4::blue1, 0 },
-	{ LLFastTimer::FTM_REBUILD_NONE_VB,		"       Unknown",	&LLColor4::cyan5, 0 },
-	{ LLFastTimer::FTM_REBUILD_BRIDGE_VB,	"      Bridge",		&LLColor4::blue2, 0 },
-	{ LLFastTimer::FTM_REBUILD_HUD_VB,		"      HUD",			&LLColor4::blue3, 0 },
-	{ LLFastTimer::FTM_REBUILD_TERRAIN_VB,	"      Terrain",		&LLColor4::blue4, 0 },
-	{ LLFastTimer::FTM_REBUILD_WATER_VB,	"      Water",		&LLColor4::blue5, 0 },
-	{ LLFastTimer::FTM_REBUILD_TREE_VB,		"      Tree",		&LLColor4::cyan1, 0 },
-	{ LLFastTimer::FTM_REBUILD_PARTICLE_VB,	"      Particle",	&LLColor4::cyan2, 0 },
-	{ LLFastTimer::FTM_REBUILD_CLOUD_VB,	"      Cloud",		&LLColor4::cyan3, 0 },
-	{ LLFastTimer::FTM_REBUILD_GRASS_VB,	"      Grass",		&LLColor4::cyan4, 0 },
-	{ LLFastTimer::FTM_RENDER_GEOMETRY,		"  Geometry",		&LLColor4::green2, 1 },
+	{ LLFastTimer::FTM_HUD_EFFECTS,			"  HUD Effects",	&LLColor4::orange1, 0 },
+	{ LLFastTimer::FTM_HUD_UPDATE,			"  HUD Update",	&LLColor4::orange2, 0 },
+	{ LLFastTimer::FTM_UPDATE_SKY,			"  Sky Update",		&LLColor4::cyan1, 0 },
+	{ LLFastTimer::FTM_UPDATE_TEXTURES,		"  Textures",		&LLColor4::pink2, 0 },
+	{ LLFastTimer::FTM_GEO_UPDATE,			"  Geo Update",	&LLColor4::blue3, 0 },
+	{ LLFastTimer::FTM_UPDATE_PRIMITIVES,	"   Volumes",		&LLColor4::blue4, 0 },
+	{ LLFastTimer::FTM_GEN_VOLUME,			"    Gen Volume",	&LLColor4::yellow3, 0 },
+	{ LLFastTimer::FTM_GEN_FLEX,			"    Flexible",	&LLColor4::yellow4, 0 },
+	{ LLFastTimer::FTM_GEN_TRIANGLES,		"    Triangles",	&LLColor4::yellow5, 0 },
+	{ LLFastTimer::FTM_UPDATE_AVATAR,		"   Avatar",		&LLColor4::yellow1, 0 },
+	{ LLFastTimer::FTM_UPDATE_TREE,			"   Tree",			&LLColor4::yellow2, 0 },
+	{ LLFastTimer::FTM_UPDATE_TERRAIN,		"   Terrain",		&LLColor4::yellow6, 0 },
+	{ LLFastTimer::FTM_UPDATE_CLOUDS,		"   Clouds",		&LLColor4::yellow7, 0 },
+	{ LLFastTimer::FTM_UPDATE_GRASS,		"   Grass",		&LLColor4::yellow8, 0 },
+	{ LLFastTimer::FTM_UPDATE_WATER,		"   Water",		&LLColor4::yellow9, 0 },
+	{ LLFastTimer::FTM_GEO_LIGHT,			"   Lighting",		&LLColor4::yellow1, 0 },
+	{ LLFastTimer::FTM_GEO_SHADOW,			"   Shadow",		&LLColor4::black, 0 },
+	{ LLFastTimer::FTM_UPDATE_PARTICLES,	"   Particles",	&LLColor4::blue5, 0 },
+	{ LLFastTimer::FTM_GEO_RESERVE,			"   Reserve",		&LLColor4::blue6, 0 },
+	{ LLFastTimer::FTM_UPDATE_LIGHTS,		"   Lights",		&LLColor4::yellow2, 0 },
+	{ LLFastTimer::FTM_GEO_SKY,				"   Sky",			&LLColor4::yellow3, 0 },
+	{ LLFastTimer::FTM_UPDATE_WLPARAM,		"  Windlight Param",&LLColor4::magenta2, 0 },
+	{ LLFastTimer::FTM_CULL,				"  Object Cull",	&LLColor4::blue2, 1 },
+    { LLFastTimer::FTM_CULL_REBOUND,		"   Rebound",		&LLColor4::blue3, 0 },
+	{ LLFastTimer::FTM_FRUSTUM_CULL,		"   Frustum Cull",	&LLColor4::blue4, 0 },
+	{ LLFastTimer::FTM_OCCLUSION_READBACK,	"   Occlusion Read", &LLColor4::red2, 0 },
+	{ LLFastTimer::FTM_STATESORT,			"  State Sort",	&LLColor4::orange1, 1 },
+	{ LLFastTimer::FTM_STATESORT_DRAWABLE,	"   Drawable",		&LLColor4::orange2, 0 },
+	{ LLFastTimer::FTM_STATESORT_POSTSORT,	"   Post Sort",	&LLColor4::orange3, 0 },
+	{ LLFastTimer::FTM_REBUILD_OCCLUSION_VB,"    Occlusion",		&LLColor4::cyan5, 0 },
+	{ LLFastTimer::FTM_REBUILD_VBO,			"    VBO Rebuild",	&LLColor4::red4, 0 },
+	{ LLFastTimer::FTM_REBUILD_VOLUME_VB,	"     Volume",		&LLColor4::blue1, 0 },
+//	{ LLFastTimer::FTM_REBUILD_NONE_VB,		"      Unknown",	&LLColor4::cyan5, 0 },
+//	{ LLFastTimer::FTM_REBUILD_BRIDGE_VB,	"     Bridge",		&LLColor4::blue2, 0 },
+//	{ LLFastTimer::FTM_REBUILD_HUD_VB,		"     HUD",			&LLColor4::blue3, 0 },
+	{ LLFastTimer::FTM_REBUILD_TERRAIN_VB,	"     Terrain",		&LLColor4::blue4, 0 },
+//	{ LLFastTimer::FTM_REBUILD_WATER_VB,	"     Water",		&LLColor4::blue5, 0 },
+//	{ LLFastTimer::FTM_REBUILD_TREE_VB,		"     Tree",		&LLColor4::cyan1, 0 },
+	{ LLFastTimer::FTM_REBUILD_PARTICLE_VB,	"     Particle",	&LLColor4::cyan2, 0 },
+//	{ LLFastTimer::FTM_REBUILD_CLOUD_VB,	"     Cloud",		&LLColor4::cyan3, 0 },
+//	{ LLFastTimer::FTM_REBUILD_GRASS_VB,	"     Grass",		&LLColor4::cyan4, 0 },
+ 	{ LLFastTimer::FTM_RENDER_GEOMETRY,		"  Geometry",		&LLColor4::green2, 1 },
 	{ LLFastTimer::FTM_POOLS,				"   Pools",			&LLColor4::green3, 1 },
 	{ LLFastTimer::FTM_POOLRENDER,			"    RenderPool",	&LLColor4::green4, 1 },
 	{ LLFastTimer::FTM_RENDER_TERRAIN,		"     Terrain",		&LLColor4::green6, 0 },
@@ -179,13 +179,16 @@ static struct ft_display_info ft_display_table[] =
 	{ LLFastTimer::FTM_RENDER_ALPHA,		"     Alpha",		&LLColor4::yellow6, 0 },
 	{ LLFastTimer::FTM_RENDER_HUD,			"     HUD",			&LLColor4::yellow7, 0 },
 	{ LLFastTimer::FTM_RENDER_WATER,		"     Water",		&LLColor4::yellow9, 0 },
+	{ LLFastTimer::FTM_RENDER_WL_SKY,		"     WL Sky",		&LLColor4::blue3,	0 },
+	{ LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE,"     Fake VBO update",		&LLColor4::red2,	0 },
+	{ LLFastTimer::FTM_RENDER_BLOOM,		"   Bloom",			&LLColor4::blue4, 0 },
+	{ LLFastTimer::FTM_RENDER_BLOOM_FBO,		"    First FBO",			&LLColor4::blue, 0 },
 	{ LLFastTimer::FTM_RENDER_UI,			"  UI",				&LLColor4::cyan4, 1 },
 	{ LLFastTimer::FTM_RENDER_TIMER,		"   Timers",		&LLColor4::cyan5, 1, 0 },
 //	{ LLFastTimer::FTM_RENDER_FONTS,		"   Fonts",			&LLColor4::pink1, 0 },
-//	{ LLFastTimer::FTM_UPDATE_TEXTURES,		"  Textures",		&LLColor4::pink2, 0 },
 	{ LLFastTimer::FTM_SWAP,				"  Swap",			&LLColor4::pink1, 0 },
 	{ LLFastTimer::FTM_CLIENT_COPY,			"  Client Copy",	&LLColor4::red1, 1},
-	
+
 	{ LLFastTimer::FTM_TEMP1,				" Temp1",			&LLColor4::red1, 0 },
 	{ LLFastTimer::FTM_TEMP2,				" Temp2",			&LLColor4::magenta1, 0 },
 	{ LLFastTimer::FTM_TEMP3,				" Temp3",			&LLColor4::red2, 0 },
@@ -211,6 +214,7 @@ LLFastTimerView::LLFastTimerView(const std::string& name, const LLRect& rect)
 	mMaxCountTotal = 0;
 	mDisplayCenter = 1;
 	mDisplayCalls = 0;
+	mDisplayHz = 0;
 	mScrollIndex = 0;
 	mHoverIndex = -1;
 	mHoverBarIndex = -1;
@@ -322,9 +326,17 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask)
 	else if (mask & MASK_ALT)
 	{
 		if (mask & MASK_SHIFT)
+		{
 			mSubtractHidden = !mSubtractHidden;
+		}
+		else if (mask & MASK_CONTROL)
+		{
+			mDisplayHz = !mDisplayHz;	
+		}
 		else
+		{
 			mDisplayCalls = !mDisplayCalls;
+		}
 	}
 	else if (mask & MASK_SHIFT)
 	{
@@ -756,7 +768,7 @@ void LLFastTimerView::draw()
 		// Draw borders
 		{
 			LLGLSNoTexture gls_ui_no_texture;
-			glColor4f(0.5f,0.5f,0.5f,0.5f);
+			gGL.color4f(0.5f,0.5f,0.5f,0.5f);
 
 			S32 by = y + 2;
 			
@@ -921,7 +933,7 @@ void LLFastTimerView::draw()
 						color = lerp(color, LLColor4::grey, 0.8f);
 					}
 
-					glColor4fv(color.mV);
+					gGL.color4fv(color.mV);
 					F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
 					F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
 					gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getWidth(), box_imagep->getHeight(), 16, start_fragment, end_fragment);
@@ -948,6 +960,8 @@ void LLFastTimerView::draw()
 			//display y-axis range
 			LLString tdesc = mDisplayCalls ? 
 							llformat("%d calls", max_ticks) :
+							mDisplayHz ?
+							llformat("%d Hz", max_ticks) :
 							llformat("%4.2f ms", ms);
 							
 			x = graph_rect.mRight - LLFontGL::sMonospace->getWidth(tdesc)-5;
@@ -955,7 +969,7 @@ void LLFastTimerView::draw()
  
 			LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white,
 										 LLFontGL::LEFT, LLFontGL::TOP);
-			
+
 			//highlight visible range
 			{
 				S32 first_frame = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex;
@@ -966,7 +980,7 @@ void LLFastTimerView::draw()
 				F32 right = (F32) graph_rect.mLeft + frame_delta*first_frame;
 				F32 left = (F32) graph_rect.mLeft + frame_delta*last_frame;
 				
-				glColor4f(0.5f,0.5f,0.5f,0.3f);
+				gGL.color4f(0.5f,0.5f,0.5f,0.3f);
 				gl_rect_2d((S32) left, graph_rect.mTop, (S32) right, graph_rect.mBottom);
 				
 				if (mHoverBarIndex >= 0)
@@ -974,12 +988,12 @@ void LLFastTimerView::draw()
 					S32 bar_frame = first_frame - mHoverBarIndex;
 					F32 bar = (F32) graph_rect.mLeft + frame_delta*bar_frame;
 
-					glColor4f(0.5f,0.5f,0.5f,1);
+					gGL.color4f(0.5f,0.5f,0.5f,1);
 				
-					glBegin(GL_LINES);
-					glVertex2i((S32)bar, graph_rect.mBottom);
-					glVertex2i((S32)bar, graph_rect.mTop);
-					glEnd();
+					gGL.begin(GL_LINES);
+					gGL.vertex2i((S32)bar, graph_rect.mBottom);
+					gGL.vertex2i((S32)bar, graph_rect.mTop);
+					gGL.end();
 				}
 			}
 			
@@ -994,10 +1008,11 @@ void LLFastTimerView::draw()
 				//fatten highlighted timer
 				if (mHoverIndex == idx)
 				{
+					gGL.flush();
 					glLineWidth(3);
 				}
 			
-				F32* col = ft_display_table[idx].color->mV;
+				const F32 * col = ft_display_table[idx].color->mV;
 				
 				F32 alpha = 1.f;
 				
@@ -1010,30 +1025,38 @@ void LLFastTimerView::draw()
 					}
 				}
 
-				glColor4f(col[0], col[1], col[2], alpha);				
-				glBegin(GL_LINE_STRIP);
+				gGL.color4f(col[0], col[1], col[2], alpha);				
+				gGL.begin(GL_LINE_STRIP);
 				for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++)
 				{
 					U64 ticks = ticks_sum[j+1][idx];
-					if (mDisplayCalls)
+
+					if (mDisplayHz)
+					{
+						F64 tc = (F64) (ticks+1) * iclock_freq;
+						tc = 1000.f/tc;
+						ticks = llmin((U64) tc, (U64) 1024);
+					}
+					else if (mDisplayCalls)
 					{
 						S32 tidx = ft_display_table[idx].timer;
 						S32 hidx = (LLFastTimer::sLastFrameIndex + j) % LLFastTimer::FTM_HISTORY_NUM;
 						ticks = (S32)LLFastTimer::sCallHistory[hidx][tidx];
 					}
-					
+										
 					if (alpha == 1.f)
 					{ //normalize to highlighted timer
 						cur_max = llmax(cur_max, ticks);
 					}
 					F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1)*j;
 					F32 y = graph_rect.mBottom + (F32) graph_rect.getHeight()/max_ticks*ticks;
-					glVertex2f(x,y);
+					gGL.vertex2f(x,y);
 				}
-				glEnd();
+				gGL.end();
 				
 				if (mHoverIndex == idx)
 				{
+					gGL.flush();
 					glLineWidth(1);
 				}
 			}
@@ -1046,7 +1069,15 @@ void LLFastTimerView::draw()
 								llmin((F32) cur_max/ (F32) last_max - 1.f,1.f);
 			
 			alpha_interp = alpha_interp + (alpha_target-alpha_interp) * dt;
-								
+
+			if (mHoverIndex >= 0)
+			{
+				x = (graph_rect.mRight + graph_rect.mLeft)/2;
+				y = graph_rect.mBottom + 8;
+
+				LLFontGL::sMonospace->renderUTF8(ft_display_table[mHoverIndex].desc, 0, x, y, LLColor4::white,
+					LLFontGL::LEFT, LLFontGL::BOTTOM);
+			}					
 		}
 	}
 
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index 7e461ec778d..d47cc003ace 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -60,6 +60,7 @@ class LLFastTimerView : public LLFloater
 	S32 mDisplayMode;
 	S32 mDisplayCenter;
 	S32 mDisplayCalls;
+	S32 mDisplayHz;
 	U64 mAvgCountTotal;
 	U64 mMaxCountTotal;
 	LLRect mBarRect;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index d957a3783ac..561d96d2819 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -34,6 +34,8 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include <boost/regex.hpp>
+
 #include "llfeaturemanager.h"
 #include "lldir.h"
 
@@ -43,11 +45,13 @@
 
 #include "llviewercontrol.h"
 #include "llworld.h"
-#include "pipeline.h"
 #include "lldrawpoolterrain.h"
 #include "llviewerimagelist.h"
 #include "llwindow.h"
 #include "llui.h"
+#include "llcontrol.h"
+#include "llboost.h"
+#include "llweb.h"
 
 #if LL_WINDOWS
 #include "lldxhardware.h"
@@ -73,7 +77,7 @@ const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
 
 LLFeatureManager *gFeatureManagerp = NULL;
 
-LLFeatureInfo::LLFeatureInfo(const char *name, const BOOL available, const S32 level) : mValid(TRUE)
+LLFeatureInfo::LLFeatureInfo(const char *name, const BOOL available, const F32 level) : mValid(TRUE)
 {
 	mName = name;
 	mAvailable = available;
@@ -89,7 +93,7 @@ LLFeatureList::~LLFeatureList()
 {
 }
 
-void LLFeatureList::addFeature(const char *name, const BOOL available, const S32 level)
+void LLFeatureList::addFeature(const char *name, const BOOL available, const F32 level)
 {
 	if (mFeatures.count(name))
 	{
@@ -108,18 +112,21 @@ BOOL LLFeatureList::isFeatureAvailable(const char *name)
 	}
 
 	llwarns << "Feature " << name << " not on feature list!" << llendl;
-	return FALSE;
+	
+	// changing this to TRUE so you have to explicitly disable 
+	// something for it to be disabled
+	return TRUE;
 }
 
-S32 LLFeatureList::getRecommendedLevel(const char *name)
+F32 LLFeatureList::getRecommendedValue(const char *name)
 {
-	if (mFeatures.count(name))
+	if (mFeatures.count(name) && isFeatureAvailable(name))
 	{
 		return mFeatures[name].mRecommendedLevel;
 	}
 
-	llwarns << "Feature " << name << " not on feature list!" << llendl;
-	return -1;
+	llwarns << "Feature " << name << " not on feature list or not available!" << llendl;
+	return 0;
 }
 
 BOOL LLFeatureList::maskList(LLFeatureList &mask)
@@ -207,6 +214,14 @@ BOOL LLFeatureManager::maskFeatures(const char *name)
 
 BOOL LLFeatureManager::loadFeatureTables()
 {
+	// *TODO - if I or anyone else adds something else to the skipped list
+	// make this data driven.  Put it in the feature table and parse it
+	// correctly
+	mSkippedFeatures.insert("RenderAnisotropic");
+	mSkippedFeatures.insert("RenderGamma");
+	mSkippedFeatures.insert("RenderVBOEnable");
+	mSkippedFeatures.insert("RenderFogRatio");
+
 	std::string data_path = gDirUtilp->getAppRODataDir();
 
 	data_path += gDirUtilp->getDirDelimiter();
@@ -275,19 +290,8 @@ BOOL LLFeatureManager::loadFeatureTables()
 				llerrs << "Overriding mask " << name << ", this is invalid!" << llendl;
 			}
 
-			if (!flp)
-			{
-				//
-				// The first one is always the default
-				//
-				flp = this;
-			}
-			else
-			{
-				flp = new LLFeatureList(name);
-				mMaskList[name] = flp;
-			}
-
+			flp = new LLFeatureList(name);
+			mMaskList[name] = flp;
 		}
 		else
 		{
@@ -295,7 +299,8 @@ BOOL LLFeatureManager::loadFeatureTables()
 			{
 				llerrs << "Specified parameter before <list> keyword!" << llendl;
 			}
-			S32 available, recommended;
+			S32 available;
+			F32 recommended;
 			file >> available >> recommended;
 			flp->addFeature(name, available, recommended);
 		}
@@ -314,9 +319,10 @@ void LLFeatureManager::loadGPUClass()
 	data_path += GPU_TABLE_FILENAME;
 
 	// defaults
-	mGPUClass = 0;
+	mGPUClass = GPU_CLASS_UNKNOWN;
 	mGPUString = gGLManager.getRawGLString();
-	
+	mGPUSupported = FALSE;
+
 	llifstream file;
 		
 	file.open(data_path.c_str()); 		 /*Flawfinder: ignore*/
@@ -354,41 +360,50 @@ void LLFeatureManager::loadGPUClass()
 			continue;
 		}
 
-		char* cls, *label, *expr;
-		
-		label = strtok(buffer, "\t");
-		expr = strtok(NULL, "\t");
-		cls = strtok(NULL, "\t");
+		// setup the tokenizer
+		std::string buf(buffer);
+		std::string cls, label, expr, supported;
+		boost_tokenizer tokens(buf, boost::char_separator<char>("\t\n"));
+		boost_tokenizer::iterator token_iter = tokens.begin();
+
+		// grab the label, pseudo regular expression, and class
+		if(token_iter != tokens.end())
+		{
+			label = *token_iter++;
+		}
+		if(token_iter != tokens.end())
+		{
+			expr = *token_iter++;
+		}
+		if(token_iter != tokens.end())
+		{
+			cls = *token_iter++;
+		}
+		if(token_iter != tokens.end())
+		{
+			supported = *token_iter++;
+		}
 
-		if (label == NULL || expr == NULL || cls == NULL)
+		if (label.empty() || expr.empty() || cls.empty() || supported.empty())
 		{
 			continue;
 		}
 	
-		for (U32 i = 0; i < strlen(expr); i++)	 /*Flawfinder: ignore*/
+		for (U32 i = 0; i < expr.length(); i++)	 /*Flawfinder: ignore*/
 		{
 			expr[i] = tolower(expr[i]);
 		}
-		
-		char* ex = strtok(expr, ".*");
-		char* rnd = (char*) renderer.c_str();
 
-		while (ex != NULL && rnd != NULL)
-		{
-			rnd = strstr(rnd, ex);
-			if (rnd != NULL)
-			{
-				rnd += strlen(ex);
-			}
-			ex = strtok(NULL, ".*");
-		}
-		
-		if (rnd != NULL)
+		// run the regular expression against the renderer
+		boost::regex re(expr.c_str());
+		if(boost::regex_search(renderer, re))
 		{
+			// if we found it, stop!
 			file.close();
 			llinfos << "GPU is " << label << llendl;
 			mGPUString = label;
-			mGPUClass = (S32) strtol(cls, NULL, 10);	
+			mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10);
+			mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10);
 			file.close();
 			return;
 		}
@@ -404,33 +419,128 @@ void LLFeatureManager::cleanupFeatureTables()
 	mMaskList.clear();
 }
 
+void LLFeatureManager::init()
+{
+	// load the tables
+	loadFeatureTables();
+
+	// get the gpu class
+	loadGPUClass();
+
+	// apply the base masks, so we know if anything is disabled
+	applyBaseMasks();
+}
+
+void LLFeatureManager::applyRecommendedSettings()
+{
+	// apply saved settings
+	// cap the level at 2 (high)
+	S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2));
+
+	llinfos << "Applying Recommended Features" << llendl;
 
-void LLFeatureManager::initCPUFeatureMasks()
+	setGraphicsLevel(level, false);
+	gSavedSettings.setU32("RenderQualityPerformance", level);
+	gSavedSettings.setBOOL("RenderCustomSettings", FALSE);
+
+}
+
+void LLFeatureManager::applyFeatures(bool skipFeatures)
 {
-	if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024)
-	{
-		maskFeatures("RAM256MB");
-	}
-	
-#if LL_SOLARIS && defined(__sparc) 	//  even low MHz SPARCs are fast
-#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here?
-	if (gSysCPU.getMhz() < 800)
-#else
-	if (gSysCPU.getMhz() < 1100)
+	// see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	dump();
 #endif
+
+	// scroll through all of these and set their corresponding control value
+	for(feature_map_t::iterator mIt = mFeatures.begin(); 
+		mIt != mFeatures.end(); 
+		++mIt)
 	{
-		maskFeatures("CPUSlow");
+		// skip features you want to skip
+		// do this for when you don't want to change certain settings
+		if(skipFeatures)
+		{
+			if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end())
+			{
+				continue;
+			}
+		}
+
+		// get the control setting
+		LLControlBase* ctrl = gSavedSettings.getControl(mIt->first);
+		if(ctrl == NULL)
+		{
+			llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl;
+			continue;
+		}
+
+		// handle all the different types
+		if(ctrl->isType(TYPE_BOOLEAN))
+		{
+			gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first.c_str()));
+		}
+		else if (ctrl->isType(TYPE_S32))
+		{
+			gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first.c_str()));
+		}
+		else if (ctrl->isType(TYPE_U32))
+		{
+			gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first.c_str()));
+		}
+		else if (ctrl->isType(TYPE_F32))
+		{
+			gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first.c_str()));
+		}
+		else
+		{
+			llwarns << "AHHH! Control variable is not a numeric type!" << llendl;
+		}
 	}
-	if (isSafe())
+}
+
+void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures)
+{
+	applyBaseMasks();
+
+	switch (level)
 	{
-		maskFeatures("safe");
+		case 0:
+			maskFeatures("Low");			
+			break;
+		case 1:
+			maskFeatures("Mid");
+			break;
+		case 2:
+			maskFeatures("High");
+			break;
+		case 3:
+			maskFeatures("Ultra");
+			break;
+		default:
+			maskFeatures("Low");
+			break;
 	}
+
+	applyFeatures(skipFeatures);
 }
 
-void LLFeatureManager::initGraphicsFeatureMasks()
+void LLFeatureManager::applyBaseMasks()
 {
-	loadGPUClass();
-	
+	// reapply masks
+	mFeatures.clear();
+
+	LLFeatureList* maskp = findMask("all");
+	if(maskp == NULL)
+	{
+		llwarns << "AHH! No \"all\" in feature table!" << llendl;
+		return;
+	}
+
+	mFeatures = maskp->getFeatures();
+
+	// mask class
 	if (mGPUClass >= 0 && mGPUClass < 4)
 	{
 		const char* class_table[] =
@@ -444,7 +554,13 @@ void LLFeatureManager::initGraphicsFeatureMasks()
 		llinfos << "Setting GPU Class to " << class_table[mGPUClass] << llendl;
 		maskFeatures(class_table[mGPUClass]);
 	}
-	
+	else
+	{
+		llinfos << "Setting GPU Class to Unknown" << llendl;
+		maskFeatures("Unknown");
+	}
+
+	// now all those wacky ones
 	if (!gGLManager.mHasFragmentShader)
 	{
 		maskFeatures("NoPixelShaders");
@@ -477,6 +593,8 @@ void LLFeatureManager::initGraphicsFeatureMasks()
 	{
 		maskFeatures("OpenGLPre15");
 	}
+
+	// now mask by gpu string
 	// Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
 	std::string gpustr = mGPUString;
 	for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter)
@@ -486,94 +604,28 @@ void LLFeatureManager::initGraphicsFeatureMasks()
 			*iter = '_';
 		}
 	}
-// 	llinfos << "Masking features from gpu table match: " << gpustr << llendl;
+
+	//llinfos << "Masking features from gpu table match: " << gpustr << llendl;
 	maskFeatures(gpustr.c_str());
 
-	if (isSafe())
+	// now mask cpu type ones
+	if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024)
 	{
-		maskFeatures("safe");
+		maskFeatures("RAM256MB");
 	}
-}
-
-void LLFeatureManager::applyRecommendedFeatures()
-{
-	// see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt
-
-	llinfos << "Applying Recommended Features" << llendl;
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	dump();
-#endif
 	
-	// Enabling VBO
-	if (getRecommendedLevel("RenderVBO"))
-	{
-		gSavedSettings.setBOOL("RenderVBOEnable", TRUE);
-	}
-	else
+#if LL_SOLARIS && defined(__sparc) 	//  even low MHz SPARCs are fast
+#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here?
+	if (gSysCPU.getMhz() < 800)
+#else
+	if (gSysCPU.getMhz() < 1100)
+#endif
 	{
-		gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
+		maskFeatures("CPUSlow");
 	}
 
-	// Anisotropic rendering
-	BOOL aniso = getRecommendedLevel("RenderAniso");
-	LLImageGL::sGlobalUseAnisotropic	= aniso;
-	gSavedSettings.setBOOL("RenderAnisotropic", LLImageGL::sGlobalUseAnisotropic);
-
-	// Render Avatar Mode
-	BOOL avatar_vp = getRecommendedLevel("RenderAvatarVP");
-	S32 avatar_mode = getRecommendedLevel("RenderAvatarMode");
-	if (avatar_vp == FALSE)
-		avatar_mode = 0;
-	gSavedSettings.setBOOL("RenderAvatarVP", avatar_vp);
-	gSavedSettings.setS32("RenderAvatarMode", avatar_mode);
-	
-	// Render Distance
-	S32 far_clip = getRecommendedLevel("RenderDistance");
-	gSavedSettings.setF32("RenderFarClip", (F32)far_clip);
-
-	// Lighting
-	S32 lighting = getRecommendedLevel("RenderLighting");
-	gSavedSettings.setS32("RenderLightingDetail", lighting);
-
-	// ObjectBump
-	BOOL bump = getRecommendedLevel("RenderObjectBump");
-	gSavedSettings.setBOOL("RenderObjectBump", bump);
-	
-	// Particle Count
-	S32 max_parts = getRecommendedLevel("RenderParticleCount");
-	gSavedSettings.setS32("RenderMaxPartCount", max_parts);
-	LLViewerPartSim::setMaxPartCount(max_parts);
-
-	// RippleWater
-	BOOL ripple = getRecommendedLevel("RenderRippleWater");
-	gSavedSettings.setBOOL("RenderRippleWater", ripple);
-
-	// Occlusion Culling
-	BOOL occlusion = getRecommendedLevel("UseOcclusion");
-	gSavedSettings.setBOOL("UseOcclusion", occlusion);
-	
-	// Vertex Shaders
-	S32 shaders = getRecommendedLevel("VertexShaderEnable");
-	gSavedSettings.setBOOL("VertexShaderEnable", shaders);
-
-	// Terrain
-	S32 terrain = getRecommendedLevel("RenderTerrainDetail");
-	gSavedSettings.setS32("RenderTerrainDetail", terrain);
-	LLDrawPoolTerrain::sDetailMode = terrain;
-
-	// Set the amount of VRAM we have available
 	if (isSafe())
 	{
-		gSavedSettings.setS32("GraphicsCardMemorySetting", 1);  // 32 MB in 'safe' mode
-	}
-	else
-	{
-		S32 idx = gSavedSettings.getS32("GraphicsCardMemorySetting");
-		// -1 indicates use default (max), don't change
-		if (idx != -1)
-		{
-			idx = LLViewerImageList::getMaxVideoRamSetting(-2); // get max recommended setting
-			gSavedSettings.setS32("GraphicsCardMemorySetting", idx);
-		}
+		maskFeatures("safe");
 	}
 }
diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h
index 21d1ee0f913..26d491b96f8 100644
--- a/indra/newview/llfeaturemanager.h
+++ b/indra/newview/llfeaturemanager.h
@@ -38,11 +38,20 @@
 #include "llskipmap.h"
 #include <map>
 
+typedef enum EGPUClass
+{
+	GPU_CLASS_UNKNOWN = -1,
+	GPU_CLASS_0 = 0,
+	GPU_CLASS_1 = 1,
+	GPU_CLASS_2 = 2,
+	GPU_CLASS_3 = 3
+} EGPUClass; 
+
 class LLFeatureInfo
 {
 public:
 	LLFeatureInfo() : mValid(FALSE), mAvailable(FALSE), mRecommendedLevel(-1) {}
-	LLFeatureInfo(const char *name, const BOOL available, const S32 level);
+	LLFeatureInfo(const char *name, const BOOL available, const F32 level);
 
 	BOOL isValid() const	{ return mValid; };
 
@@ -50,32 +59,38 @@ class LLFeatureInfo
 	BOOL		mValid;
 	LLString	mName;
 	BOOL		mAvailable;
-	S32			mRecommendedLevel;
+	F32			mRecommendedLevel;
 };
 
 
 class LLFeatureList
 {
 public:
+	typedef std::map<LLString, LLFeatureInfo> feature_map_t;
+
 	LLFeatureList(const char *name = "default");
 	virtual ~LLFeatureList();
 
 	BOOL isFeatureAvailable(const char *name);
-	S32 getRecommendedLevel(const char *name);
+	F32 getRecommendedValue(const char *name);
 
 	void setFeatureAvailable(const char *name, const BOOL available);
-	void setRecommendedLevel(const char *name, const S32 level);
+	void setRecommendedLevel(const char *name, const F32 level);
 
 	BOOL loadFeatureList(FILE *fp);
 
 	BOOL maskList(LLFeatureList &mask);
 
-	void addFeature(const char *name, const BOOL available, const S32 level);
+	void addFeature(const char *name, const BOOL available, const F32 level);
+
+	feature_map_t& getFeatures()
+	{
+		return mFeatures;
+	}
 
 	void dump();
 protected:
 	LLString	mName;
-	typedef std::map<LLString, LLFeatureInfo> feature_map_t;
 	feature_map_t	mFeatures;
 };
 
@@ -83,14 +98,19 @@ class LLFeatureList
 class LLFeatureManager : public LLFeatureList
 {
 public:
-	LLFeatureManager() : mInited(FALSE), mTableVersion(0), mSafe(FALSE), mGPUClass(0) {}
+	LLFeatureManager() : mInited(FALSE), mTableVersion(0), mSafe(FALSE), mGPUClass(GPU_CLASS_UNKNOWN) {}
+	~LLFeatureManager() {cleanupFeatureTables();}
+
+	// initialize this by loading feature table and gpu table
+	void init();
 
 	void maskCurrentList(const char *name); // Mask the current feature list with the named list
 
 	BOOL loadFeatureTables();
 
-	S32	getGPUClass() 					{ return mGPUClass; }
+	EGPUClass getGPUClass() 			{ return mGPUClass; }
 	std::string& getGPUString() 		{ return mGPUString; }
+	BOOL isGPUSupported()				{ return mGPUSupported; }
 	
 	void cleanupFeatureTables();
 
@@ -101,22 +121,32 @@ class LLFeatureManager : public LLFeatureList
 	LLFeatureList *findMask(const char *name);
 	BOOL maskFeatures(const char *name);
 
-
-	void initCPUFeatureMasks();
-	void initGraphicsFeatureMasks();
+	// set the graphics to low, medium, high, or ultra.
+	// skipFeatures forces skipping of mostly hardware settings
+	// that we don't want to change when we change graphics
+	// settings
+	void setGraphicsLevel(S32 level, bool skipFeatures);
 	
-	void applyRecommendedFeatures();
+	void applyBaseMasks();
+	void applyRecommendedSettings();
+
+	// apply the basic masks.  Also, skip one saved
+	// in the skip list if true
+	void applyFeatures(bool skipFeatures);
 
 protected:
 	void loadGPUClass();
 	void initBaseMask();
 
+
 	std::map<LLString, LLFeatureList *> mMaskList;
+	std::set<LLString> mSkippedFeatures;
 	BOOL		mInited;
 	S32			mTableVersion;
 	BOOL		mSafe;					// Reinitialize everything to the "safe" mask
-	S32			mGPUClass;
+	EGPUClass	mGPUClass;
 	std::string	mGPUString;
+	BOOL		mGPUSupported;
 };
 
 extern LLFeatureManager *gFeatureManagerp;
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index 757cbccb59a..f69f66bce2f 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -47,6 +47,7 @@
 #include "llviewerobjectlist.h"
 #include "llviewerregion.h"
 #include "llworld.h"
+#include "llvoavatar.h"
 
 /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f;
 
@@ -66,6 +67,11 @@ LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectD
 	mSimulateRes = 0;
 	mFrameNum = 0;
 	mRenderRes = 1;
+
+	if(mVO->mDrawable.notNull())
+	{
+		mVO->mDrawable->makeActive() ;
+	}
 }//-----------------------------------------------
 
 LLVector3 LLVolumeImplFlexible::getFramePosition() const
@@ -240,12 +246,7 @@ void LLVolumeImplFlexible::setAttributesOfAllSections()
 
 void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail)
 {
-	/*doIdleUpdate(gAgent, *gWorldp, 0.0);
-	if (mVO && mVO->mDrawable.notNull())
-	{
-		gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
-		gPipeline.markMoved(mVO->mDrawable);
-	}*/
+	
 }
 
 //---------------------------------------------------------------------------------
@@ -255,13 +256,14 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons
 //---------------------------------------------------------------------------------
 BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
-
 	if (mVO->mDrawable.isNull())
 	{
 		// Don't do anything until we have a drawable
 		return FALSE; // (we are not initialized or updated)
 	}
 
+	BOOL force_update = mSimulateRes == 0 ? TRUE : FALSE;
+
 	//flexible objects never go static
 	mVO->mDrawable->mQuietCount = 0;
 	if (!mVO->mDrawable->isRoot())
@@ -307,7 +309,11 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6
 		return FALSE; // (we are not initialized or updated)
 	}
 
-	if (mVO->mDrawable->isVisible() &&
+	if (force_update)
+	{
+		gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
+	}
+	else if	(mVO->mDrawable->isVisible() &&
 		!mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) &&
 		mVO->getPixelArea() > 256.f)
 	{
@@ -332,7 +338,7 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6
 		}
 	}
 	
-	return TRUE;
+	return force_update;
 }
 
 inline S32 log2(S32 x)
@@ -348,7 +354,8 @@ inline S32 log2(S32 x)
 
 void LLVolumeImplFlexible::doFlexibleUpdate()
 {
-	LLPath *path = &mVO->getVolume()->getPath();
+	LLVolume* volume = mVO->getVolume();
+	LLPath *path = &volume->getPath();
 	if (mSimulateRes == 0)
 	{
 		mVO->markForUpdate(TRUE);
@@ -568,7 +575,11 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 
 	// Create points
 	S32 num_render_sections = 1<<mRenderRes;
-	path->resizePath(num_render_sections+1);
+	if (path->getPathLength() != num_render_sections+1)
+	{
+		((LLVOVolume*) mVO)->mVolumeChanged = TRUE;
+		volume->resizePath(num_render_sections+1);
+	}
 
 	LLPath::PathPt *new_point;
 
@@ -600,7 +611,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 		LLVector3 pos = newSection[i].mPosition * rel_xform;
 		LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot;
 		
-		if (!mUpdated || (new_point->mPos-pos).magVecSquared() > 0.000001f)
+		if (!mUpdated || (new_point->mPos-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f)
 		{
 			new_point->mPos = newSection[i].mPosition * rel_xform;
 			mUpdated = FALSE;
@@ -614,9 +625,19 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 	mLastSegmentRotation = parentSegmentRotation;
 }
 
+void LLVolumeImplFlexible::preRebuild()
+{
+	if (!mUpdated)
+	{
+		doFlexibleRebuild();
+	}
+}
+
 void LLVolumeImplFlexible::doFlexibleRebuild()
 {
-	mVO->getVolume()->regen();
+	LLVolume* volume = mVO->getVolume();
+	volume->regen();
+	
 	mUpdated = TRUE;
 }
 
@@ -631,7 +652,26 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 {
 	LLVOVolume *volume = (LLVOVolume*)mVO;
 
-	if (volume->mDrawable.isNull()) // Not sure why this is happening, but it is...
+	if (mVO->isAttachment())
+	{	//don't update flexible attachments for impostored avatars unless the 
+		//impostor is being updated this frame (w00!)
+		LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
+		while (parent && !parent->isAvatar())
+		{
+			parent = (LLViewerObject*) parent->getParent();
+		}
+		
+		if (parent)
+		{
+			LLVOAvatar* avatar = (LLVOAvatar*) parent;
+			if (avatar->isImpostor() && !avatar->needsImpostorUpdate())
+			{
+				return TRUE;
+			}
+		}
+	}
+
+	if (volume->mDrawable.isNull())
 	{
 		return TRUE; // No update to complete
 	}
@@ -660,11 +700,14 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 	{
 		volume->regenFaces();
 		volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME);
+		volume->dirtySpatialGroup();
+		doFlexibleRebuild();
+		volume->genBBoxes(isVolumeGlobal());
 	}
-
-	if (!mUpdated || volume->mFaceMappingChanged || volume->mVolumeChanged || rotated)
+	else if (!mUpdated || rotated)
 	{
-		doFlexibleRebuild();
+		volume->mDrawable->setState(LLDrawable::REBUILD_POSITION);
+		volume->dirtyMesh();
 		volume->genBBoxes(isVolumeGlobal());
 	}
 			
@@ -672,7 +715,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 	volume->mLODChanged = FALSE;
 	volume->mFaceMappingChanged = FALSE;
 
-
 	// clear UV flag
 	drawable->clearState(LLDrawable::UV);
 	
diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h
index fe20235feb9..d4b79fb536b 100644
--- a/indra/newview/llflexibleobject.h
+++ b/indra/newview/llflexibleobject.h
@@ -98,7 +98,8 @@ class LLVolumeImplFlexible : public LLVolumeInterface
 		void updateRelativeXform();
 		void doFlexibleUpdate(); // Called to update the simulation
 		void doFlexibleRebuild(); // Called to rebuild the geometry
-		
+		void preRebuild();
+
 		//void				setAttributes( LLFlexibleObjectData );
 		void				setParentPositionAndRotationDirectly( LLVector3 p, LLQuaternion r );
 		void				setUsingCollisionSphere( bool u );
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 2eddb45f236..d966f0d3c8e 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -46,6 +46,7 @@
 #include "llcombobox.h"
 #include "lldrawable.h"
 #include "lldrawpoolavatar.h"
+#include "llglimmediate.h"
 #include "llface.h"
 #include "llkeyframemotion.h"
 #include "lllineeditor.h"
@@ -349,21 +350,21 @@ void LLFloaterAnimPreview::draw()
 
 	if (mMotionID.notNull() && mAnimPreview)
 	{
-		glColor3f(1.f, 1.f, 1.f);
+		gGL.color3f(1.f, 1.f, 1.f);
 		mAnimPreview->bindTexture();
 
-		glBegin( GL_QUADS );
+		gGL.begin( GL_QUADS );
 		{
-			glTexCoord2f(0.f, 1.f);
-			glVertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
-			glTexCoord2f(0.f, 0.f);
-			glVertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-			glTexCoord2f(1.f, 0.f);
-			glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-			glTexCoord2f(1.f, 1.f);
-			glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+			gGL.texCoord2f(0.f, 1.f);
+			gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+			gGL.texCoord2f(0.f, 0.f);
+			gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+			gGL.texCoord2f(1.f, 0.f);
+			gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+			gGL.texCoord2f(1.f, 1.f);
+			gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
 		}
-		glEnd();
+		gGL.end();
 
 		mAnimPreview->unbindTexture();
 
@@ -1040,25 +1041,27 @@ BOOL	LLPreviewAnimation::render()
 	LLVOAvatar* avatarp = mDummyAvatar;
 	
 	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 	glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f);
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 
 	LLGLSUIDefault def;
 	LLGLSNoTexture gls_no_texture;
-	glColor4f(0.15f, 0.2f, 0.3f, 1.f);
+	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
 	gl_rect_2d_simple( mWidth, mHeight );
 
 	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	gGL.popMatrix();
 
 	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
+	gGL.popMatrix();
+
+	gGL.stop();
 
 	LLVector3 target_pos = avatarp->mRoot.getWorldPosition();
 
@@ -1105,7 +1108,8 @@ BOOL	LLPreviewAnimation::render()
 		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool();
 		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
 	}
-	
+
+	gGL.start();
 	return TRUE;
 }
 
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 094cbb6c337..f1bba7d9c5e 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -176,7 +176,7 @@ void LLFloaterAuction::onClickSnapshot(void* data)
 	BOOL success = gViewerWindow->rawSnapshot(raw,
 											  gViewerWindow->getWindowWidth(),
 											  gViewerWindow->getWindowHeight(),
-											  TRUE,
+											  TRUE, FALSE,
 											  FALSE, FALSE);
 	gForceRenderLandFence = FALSE;
 
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 137b35c3eef..19793550cc8 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -39,6 +39,7 @@
 #include "llfontgl.h"
 #include "llsys.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v3dmath.h"
 #include "lldir.h"
 #include "llui.h"
@@ -544,37 +545,37 @@ void LLFloaterColorPicker::draw()
 	{
 		LLGLSNoTexture no_texture;
 		LLGLEnable(GL_CULL_FACE);
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		{
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-			glVertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-			glVertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-			glVertex2i(local_rect.mRight, local_rect.mTop);
-			glVertex2i(local_rect.mLeft, local_rect.mTop);
-
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-			glVertex2i(local_rect.mLeft, local_rect.mTop);
-			glVertex2i(local_rect.mLeft, local_rect.mBottom);
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-			glVertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
-			glVertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-			glVertex2i(local_rect.mRight, local_rect.mBottom);
-			glVertex2i(local_rect.mRight, local_rect.mTop);
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-			glVertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			glVertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-			glVertex2i(local_rect.mLeft, local_rect.mBottom);
-			glVertex2i(local_rect.mRight, local_rect.mBottom);
-			glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-			glVertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-			glVertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
+
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
+
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+			gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
 		}
-		glEnd();
+		gGL.end();
 	}
 
 	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
@@ -672,9 +673,9 @@ void LLFloaterColorPicker::draw()
 
 //////////////////////////////////////////////////////////////////////////////
 // find a complimentary color to the one passed in that can be used to highlight
-LLColor4&
+const LLColor4&
 LLFloaterColorPicker::
-getComplimentaryColor ( LLColor4& backgroundColor )
+getComplimentaryColor ( const LLColor4& backgroundColor )
 {
 	// going to base calculation on luminance
 	F32 hVal, sVal, lVal;
@@ -1162,7 +1163,7 @@ void
 LLFloaterColorPicker::
 cancelSelection ()
 {
-	// restore the previous colour selection
+	// restore the previous color selection
 	setCurRgb ( getOrigR (), getOrigG (), getOrigB () );
 
 	// 	we're going away and when we do and the entry widgets lose focus, they do bad things so turn them off
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index abfe4c16793..a0f378053b3 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -134,7 +134,7 @@ class LLFloaterColorPicker
 		void drawPalette ();
 
 		// find a complimentary color to the one passed in that can be used to highlight 
-		LLColor4& getComplimentaryColor ( LLColor4& backgroundColor );
+		const LLColor4& getComplimentaryColor ( const LLColor4& backgroundColor );
 
 		// original RGB values
 		F32 origR, origG, origB;
diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp
new file mode 100644
index 00000000000..67694f49c23
--- /dev/null
+++ b/indra/newview/llfloaterdaycycle.cpp
@@ -0,0 +1,612 @@
+/** 
+ * @file llfloaterdaycycle.cpp
+ * @brief LLFloaterDayCycle class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterdaycycle.h"
+
+#include "pipeline.h"
+#include "llsky.h"
+
+#include "llsliderctrl.h"
+#include "llmultislider.h"
+#include "llmultisliderctrl.h"
+#include "llspinctrl.h"
+#include "llcheckboxctrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewercamera.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llwlanimator.h"
+
+#include "v4math.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+
+#include "llwlparamset.h"
+#include "llwlparammanager.h"
+#include "llpostprocess.h"
+#include "llfloaterwindlight.h"
+
+
+LLFloaterDayCycle* LLFloaterDayCycle::sDayCycle = NULL;
+std::map<LLString, LLWLSkyKey> LLFloaterDayCycle::sSliderToKey;
+const F32 LLFloaterDayCycle::sHoursPerDay = 24.0f;
+
+LLFloaterDayCycle::LLFloaterDayCycle() : LLFloater("Day Cycle Floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_day_cycle_options.xml");
+	
+	// add the combo boxes
+	LLComboBox* keyCombo = LLUICtrlFactory::getComboBoxByName(this, "WLKeyPresets");
+
+	if(keyCombo != NULL) 
+	{
+		std::map<std::string, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::instance()->mParamList.begin();
+		for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) 
+		{
+			keyCombo->add(LLString(mIt->first));
+		}
+
+		// set defaults on combo boxes
+		keyCombo->selectFirstItem();
+	}
+
+	// add the time slider
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(this, 
+		"WLTimeSlider");
+
+	sldr->addSlider();
+
+	// load it up
+	initCallbacks();
+}
+
+LLFloaterDayCycle::~LLFloaterDayCycle()
+{
+}
+
+void LLFloaterDayCycle::onClickHelp(void* data)
+{
+
+	LLFloaterDayCycle* self = LLFloaterDayCycle::instance();
+
+	const char* xml_alert = (const char*) data;
+	LLAlertDialog* dialogp = gViewerWindow->alertXml(xml_alert);
+	if (dialogp)
+	{
+		LLFloater* root_floater = gFloaterView->getParentFloater(self);
+		if (root_floater)
+		{
+			root_floater->addDependentFloater(dialogp);
+		}
+	}
+}
+
+void LLFloaterDayCycle::initHelpBtn(const char* name, const char* xml_alert)
+{
+	childSetAction(name, onClickHelp, (void*)xml_alert);
+}
+
+void LLFloaterDayCycle::initCallbacks(void) 
+{
+	initHelpBtn("WLDayCycleHelp", "HelpDayCycle");
+
+	// WL Day Cycle
+	childSetCommitCallback("WLTimeSlider", onTimeSliderMoved, NULL);
+	childSetCommitCallback("WLDayCycleKeys", onKeyTimeMoved, NULL);
+	childSetCommitCallback("WLCurKeyHour", onKeyTimeChanged, NULL);
+	childSetCommitCallback("WLCurKeyMin", onKeyTimeChanged, NULL);
+	childSetCommitCallback("WLKeyPresets", onKeyPresetChanged, NULL);
+
+	childSetCommitCallback("WLLengthOfDayHour", onTimeRateChanged, NULL);
+	childSetCommitCallback("WLLengthOfDayMin", onTimeRateChanged, NULL);
+	childSetCommitCallback("WLLengthOfDaySec", onTimeRateChanged, NULL);
+	childSetAction("WLUseLindenTime", onUseLindenTime, NULL);
+	childSetAction("WLAnimSky", onRunAnimSky, NULL);
+	childSetAction("WLStopAnimSky", onStopAnimSky, NULL);
+
+	childSetAction("WLLoadDayCycle", onLoadDayCycle, NULL);
+	childSetAction("WLSaveDayCycle", onSaveDayCycle, NULL);
+
+	childSetAction("WLAddKey", onAddKey, NULL);
+	childSetAction("WLDeleteKey", onDeleteKey, NULL);
+}
+
+void LLFloaterDayCycle::syncMenu()
+{
+//	std::map<std::string, LLVector4> & currentParams = LLWLParamManager::instance()->mCurParams.mParamValues;
+	
+	// set time
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(LLFloaterDayCycle::sDayCycle, 
+		"WLTimeSlider");
+	sldr->setCurSliderValue((F32)LLWLParamManager::instance()->mAnimator.getDayTime() * sHoursPerDay);
+
+	LLSpinCtrl* secSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDaySec");
+	LLSpinCtrl* minSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDayMin");
+	LLSpinCtrl* hourSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDayHour");
+
+	F32 curRate;
+	F32 hours, min, sec;
+
+	// get the current rate
+	curRate = LLWLParamManager::instance()->mDay.mDayRate;
+	hours = (F32)((int)(curRate / 60 / 60));
+	curRate -= (hours * 60 * 60);
+	min = (F32)((int)(curRate / 60));
+	curRate -= (min * 60);
+	sec = curRate;
+
+	hourSpin->setValue(hours);
+	minSpin->setValue(min);
+	secSpin->setValue(sec);
+
+	// turn off Use Estate Time button if it's already being used
+	if(	LLWLParamManager::instance()->mAnimator.mUseLindenTime == true)
+	{
+		LLFloaterDayCycle::sDayCycle->childDisable("WLUseLindenTime");
+	} 
+	else 
+	{
+		LLFloaterDayCycle::sDayCycle->childEnable("WLUseLindenTime");
+	}
+}
+
+void LLFloaterDayCycle::syncSliderTrack()
+{
+	// clear the slider
+	LLMultiSliderCtrl* kSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+
+	kSldr->clear();
+	sSliderToKey.clear();
+
+	// add sliders
+	std::map<F32, std::string>::iterator mIt = 
+		LLWLParamManager::instance()->mDay.mTimeMap.begin();
+	for(; mIt != LLWLParamManager::instance()->mDay.mTimeMap.end(); mIt++) 
+	{
+		addSliderKey(mIt->first * sHoursPerDay, mIt->second.c_str());
+	}
+}
+
+void LLFloaterDayCycle::syncTrack()
+{
+	// if no keys, do nothing
+	if(sSliderToKey.size() == 0) 
+	{
+		return;
+	}
+	
+	LLMultiSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+	llassert_always(sSliderToKey.size() == sldr->getValue().size());
+	
+	LLMultiSliderCtrl* tSldr;
+	tSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLTimeSlider");
+
+	// create a new animation track
+	LLWLParamManager::instance()->mDay.clearKeys();
+	
+	// add the keys one by one
+	std::map<LLString, LLWLSkyKey>::iterator mIt = sSliderToKey.begin();
+	for(; mIt != sSliderToKey.end(); mIt++) 
+	{
+		LLWLParamManager::instance()->mDay.addKey(mIt->second.time / sHoursPerDay, 
+			mIt->second.presetName);
+	}
+	
+	// set the param manager's track to the new one
+	LLWLParamManager::instance()->resetAnimator(
+		tSldr->getCurSliderValue() / sHoursPerDay, false);
+
+	LLWLParamManager::instance()->mAnimator.update(
+		LLWLParamManager::instance()->mCurParams);
+}
+
+// static
+LLFloaterDayCycle* LLFloaterDayCycle::instance()
+{
+	if (!sDayCycle)
+	{
+		sDayCycle = new LLFloaterDayCycle();
+		sDayCycle->open();
+		sDayCycle->setFocus(TRUE);
+	}
+	return sDayCycle;
+}
+
+bool LLFloaterDayCycle::isOpen()
+{
+	if (sDayCycle != NULL) 
+	{
+		return true;
+	}
+	return false;
+}
+
+void LLFloaterDayCycle::show()
+{
+	LLFloaterDayCycle* dayCycle = instance();
+	dayCycle->syncMenu();
+	syncSliderTrack();
+
+	// comment in if you want the menu to rebuild each time
+	//gUICtrlFactory->buildFloater(dayCycle, "floater_day_cycle_options.xml");
+	//dayCycle->initCallbacks();
+
+	dayCycle->open();
+}
+
+// virtual
+void LLFloaterDayCycle::onClose(bool app_quitting)
+{
+	if (sDayCycle)
+	{
+		sDayCycle->setVisible(FALSE);
+	}
+}
+
+void LLFloaterDayCycle::onRunAnimSky(void* userData)
+{
+	// if no keys, do nothing
+	if(sSliderToKey.size() == 0) 
+	{
+		return;
+	}
+	
+	LLMultiSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+	llassert_always(sSliderToKey.size() == sldr->getValue().size());
+
+	LLMultiSliderCtrl* tSldr;
+	tSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLTimeSlider");
+
+	// turn off linden time
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+	// set the param manager's track to the new one
+	LLWLParamManager::instance()->resetAnimator(
+		tSldr->getCurSliderValue() / sHoursPerDay, true);
+
+	llassert_always(LLWLParamManager::instance()->mAnimator.mTimeTrack.size() == sldr->getValue().size());
+}
+
+void LLFloaterDayCycle::onStopAnimSky(void* userData)
+{
+	// if no keys, do nothing
+	if(sSliderToKey.size() == 0) {
+		return;
+	}
+
+	// turn off animation and using linden time
+	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+}
+
+void LLFloaterDayCycle::onUseLindenTime(void* userData)
+{
+	LLFloaterWindLight* wl = LLFloaterWindLight::instance();
+	LLComboBox* box = LLUICtrlFactory::getComboBoxByName(wl, "WLPresetsCombo");
+	box->selectByValue("");	
+
+	LLWLParamManager::instance()->mAnimator.mIsRunning = true;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;	
+}
+
+void LLFloaterDayCycle::onLoadDayCycle(void* userData)
+{
+	LLWLParamManager::instance()->mDay.loadDayCycle("Default.xml");
+	
+	// sync it all up
+	syncSliderTrack();
+	syncMenu();
+
+	// set the param manager's track to the new one
+	LLMultiSliderCtrl* tSldr;
+	tSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLTimeSlider");
+	LLWLParamManager::instance()->resetAnimator(
+		tSldr->getCurSliderValue() / sHoursPerDay, false);
+
+	// and draw it
+	LLWLParamManager::instance()->mAnimator.update(
+		LLWLParamManager::instance()->mCurParams);
+}
+
+void LLFloaterDayCycle::onSaveDayCycle(void* userData)
+{
+	LLWLParamManager::instance()->mDay.saveDayCycle("Default.xml");
+}
+
+
+void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLTimeSlider");
+
+	/// get the slider value
+	F32 val = sldr->getCurSliderValue() / sHoursPerDay;
+	
+	// set the value, turn off animation
+	LLWLParamManager::instance()->mAnimator.setDayTime((F64)val);
+	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+	// then call update once
+	LLWLParamManager::instance()->mAnimator.update(
+		LLWLParamManager::instance()->mCurParams);
+}
+
+void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sDayCycle, 
+		"WLKeyPresets");
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+	LLSpinCtrl* hourSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyHour");
+	LLSpinCtrl* minSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyMin");
+
+	if(sldr->getValue().size() == 0) {
+		return;
+	}
+
+	// make sure we have a slider
+	const LLString& curSldr = sldr->getCurSlider();
+	if(curSldr == "") {
+		return;
+	}
+
+	F32 time = sldr->getCurSliderValue();
+
+	// check to see if a key exists
+	LLString presetName = sSliderToKey[curSldr].presetName;
+	sSliderToKey[curSldr].time = time;
+
+	// if it exists, turn on check box
+	comboBox->selectByValue(presetName);
+
+	// now set the spinners
+	F32 hour = (F32)((S32)time);
+	F32 min = (time - hour) * 60;
+
+	// handle imprecision
+	if(min >= 59) {
+		min = 0;
+		hour += 1;
+	}
+
+	hourSpin->set(hour);
+	minSpin->set(min);
+
+	syncTrack();
+
+}
+
+void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl, void* userData)
+{
+	// if no keys, skipped
+	if(sSliderToKey.size() == 0) {
+		return;
+	}
+
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+	LLSpinCtrl* hourSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyHour");
+	LLSpinCtrl* minSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyMin");
+
+	F32 hour = hourSpin->get();
+	F32 min = minSpin->get();
+	F32 val = hour + min / 60.0f;
+
+	const LLString& curSldr = sldr->getCurSlider();
+	sldr->setCurSliderValue(val, TRUE);
+	F32 time = sldr->getCurSliderValue() / sHoursPerDay;
+
+	// now set the key's time in the sliderToKey map
+	LLString presetName = sSliderToKey[curSldr].presetName;
+	sSliderToKey[curSldr].time = time;
+
+	syncTrack();
+}
+
+void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl, void* userData)
+{
+	// get the time
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sDayCycle, 
+		"WLKeyPresets");
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+
+	// do nothing if no sliders
+	if(sldr->getValue().size() == 0) {
+		return;
+	}
+
+	// change the map
+	LLString newPreset(comboBox->getSelectedValue().asString());
+	const LLString& curSldr = sldr->getCurSlider();
+
+	// if null, don't use
+	if(curSldr == "") {
+		return;
+	}
+
+	sSliderToKey[curSldr].presetName = newPreset;
+
+	syncTrack();
+}
+
+void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl, void* userData)
+{
+	// get the time
+	LLSpinCtrl* secSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDaySec");
+
+	LLSpinCtrl* minSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDayMin");
+
+	LLSpinCtrl* hourSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLLengthOfDayHour");
+
+	F32 hour;
+	hour = (F32)hourSpin->getValue().asReal();
+	F32 min;
+	min = (F32)minSpin->getValue().asReal();
+	F32 sec;
+	sec = (F32)secSpin->getValue().asReal();
+
+	F32 time = 60.0f * 60.0f * hour + 60.0f * min + sec;
+	if(time <= 0) {
+		time = 1;
+	}
+	LLWLParamManager::instance()->mDay.mDayRate = time;
+
+	syncTrack();
+}
+
+void LLFloaterDayCycle::onAddKey(void* userData)
+{
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sDayCycle, 
+		"WLKeyPresets");
+	LLMultiSliderCtrl* kSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+	LLMultiSliderCtrl* tSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLTimeSlider");
+	
+	llassert_always(sSliderToKey.size() == kSldr->getValue().size());
+
+	// get the values
+	LLString newPreset(comboBox->getSelectedValue().asString());
+
+	// add the slider key
+	addSliderKey(tSldr->getCurSliderValue(), newPreset);
+
+	syncTrack();
+}
+
+void LLFloaterDayCycle::addSliderKey(F32 time, const LLString & presetName)
+{
+	LLMultiSliderCtrl* kSldr = LLUICtrlFactory::getMultiSliderByName(sDayCycle, 
+		"WLDayCycleKeys");
+
+	// make a slider
+	const LLString& sldrName = kSldr->addSlider(time);
+	if(sldrName == "") {
+		return;
+	}
+
+	// set the key
+	LLWLSkyKey newKey;
+	newKey.presetName = presetName;
+	newKey.time = kSldr->getCurSliderValue();
+
+	llassert_always(sldrName != LLString::null);
+
+	// add to map
+	sSliderToKey.insert(std::pair<LLString, LLWLSkyKey>(sldrName, newKey));
+
+	llassert_always(sSliderToKey.size() == kSldr->getValue().size());
+
+}
+
+void LLFloaterDayCycle::deletePreset(LLString& presetName)
+{
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(
+		sDayCycle, "WLDayCycleKeys");
+
+	/// delete any reference
+	std::map<LLString, LLWLSkyKey>::iterator curr_preset, next_preset;
+	for(curr_preset = sSliderToKey.begin(); curr_preset != sSliderToKey.end(); curr_preset = next_preset)
+	{
+		next_preset = curr_preset;
+		++next_preset;
+		if (curr_preset->second.presetName == presetName)
+		{
+			sldr->deleteSlider(curr_preset->first);
+			sSliderToKey.erase(curr_preset);
+		}
+	}
+}
+
+void LLFloaterDayCycle::onDeleteKey(void* userData)
+{
+	if(sSliderToKey.size() == 0) {
+		return;
+	}
+
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sDayCycle, 
+		"WLKeyPresets");
+	LLMultiSliderCtrl* sldr = LLUICtrlFactory::getMultiSliderByName(
+		sDayCycle, "WLDayCycleKeys");
+
+	// delete from map
+	const LLString& sldrName = sldr->getCurSlider();
+	std::map<LLString, LLWLSkyKey>::iterator mIt = sSliderToKey.find(sldrName);
+	sSliderToKey.erase(mIt);
+
+	sldr->deleteCurSlider();
+
+	if(sSliderToKey.size() == 0) {
+		return;
+	}
+
+	const LLString& name = sldr->getCurSlider();
+	comboBox->selectByValue(sSliderToKey[name].presetName);
+	F32 time = sSliderToKey[name].time;
+
+	LLSpinCtrl* hourSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyHour");
+	LLSpinCtrl* minSpin = LLUICtrlFactory::getSpinnerByName(sDayCycle, 
+		"WLCurKeyMin");
+
+	// now set the spinners
+	F32 hour = (F32)((S32)time);
+	F32 min = (time - hour) / 60;
+	hourSpin->set(hour);
+	minSpin->set(min);
+
+	syncTrack();
+
+}
diff --git a/indra/newview/llfloaterdaycycle.h b/indra/newview/llfloaterdaycycle.h
new file mode 100644
index 00000000000..91a649b97c6
--- /dev/null
+++ b/indra/newview/llfloaterdaycycle.h
@@ -0,0 +1,146 @@
+/** 
+ * @file llfloaterdaycycle.h
+ * @brief LLFloaterDayCycle class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERDAYCYCLE_H
+#define LL_LLFLOATERDAYCYCLE_H
+
+#include "llfloater.h"
+
+#include <vector>
+#include "llwlparamset.h"
+#include "llwlanimator.h"
+
+struct WLColorControl;
+struct WLFloatControl;
+
+/// convenience class for holding keys mapped to sliders
+struct LLWLSkyKey
+{
+public:
+	LLString presetName;
+	F32 time;
+};
+
+/// Menu for all of windlight's functionality.
+/// Menuing system for adjusting the atmospheric settings of the world.
+class LLFloaterDayCycle : public LLFloater
+{
+public:
+
+	LLFloaterDayCycle();
+	virtual ~LLFloaterDayCycle();
+
+	/// help button stuff
+	static void onClickHelp(void* data);
+	void initHelpBtn(const char* name, const char* xml_alert);
+
+	/// initialize all
+	void initCallbacks(void);
+
+	/// one and one instance only
+	static LLFloaterDayCycle* instance();
+
+	/// on time slider moved
+	static void onTimeSliderMoved(LLUICtrl* ctrl, void* userData);
+
+	/// what happens when you move the key frame
+	static void onKeyTimeMoved(LLUICtrl* ctrl, void* userData);
+
+	/// what happens when you change the key frame's time
+	static void onKeyTimeChanged(LLUICtrl* ctrl, void* userData);
+
+	/// if you change the combo box, change the frame
+	static void onKeyPresetChanged(LLUICtrl* ctrl, void* userData);
+	
+	/// run this when user says to run the sky animation
+	static void onRunAnimSky(void* userData);
+
+	/// run this when user says to stop the sky animation
+	static void onStopAnimSky(void* userData);
+
+	/// if you change the combo box, change the frame
+	static void onTimeRateChanged(LLUICtrl* ctrl, void* userData);
+
+	/// add a new key on slider
+	static void onAddKey(void* userData);
+
+	/// delete any and all reference to a preset
+	void deletePreset(LLString& presetName);
+
+	/// delete a key frame
+	static void onDeleteKey(void* userData);
+
+	/// button to load day
+	static void onLoadDayCycle(void* userData);
+
+	/// button to save day
+	static void onSaveDayCycle(void* userData);
+
+	/// toggle for Linden time
+	static void onUseLindenTime(void* userData);
+
+
+	//// menu management
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up sliders with day cycle structure
+	static void syncMenu();
+
+	// 	makes sure key slider has what's in day cycle
+	static void syncSliderTrack();
+
+	/// makes sure day cycle data structure has what's in menu
+	static void syncTrack();
+
+	/// add a slider to the track
+	static void addSliderKey(F32 time, const LLString& presetName);
+
+private:
+
+	// one instance on the inside
+	static LLFloaterDayCycle* sDayCycle;
+
+	// map of sliders to parameters
+	static std::map<LLString, LLWLSkyKey> sSliderToKey;
+
+	static const F32 sHoursPerDay;
+};
+
+
+#endif
diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp
new file mode 100644
index 00000000000..197e2ba15ed
--- /dev/null
+++ b/indra/newview/llfloaterenvsettings.cpp
@@ -0,0 +1,384 @@
+/** 
+ * @file llfloaterenvsettings.cpp
+ * @brief LLFloaterEnvSettings class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterenvsettings.h"
+
+#include "llfloaterwindlight.h"
+#include "llfloaterwater.h"
+#include "llvieweruictrlfactory.h"
+#include "llsliderctrl.h"
+#include "llcombobox.h"
+#include "llcolorswatch.h"
+#include "llwlanimator.h"
+
+#include "llwlparamset.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llmath.h"
+#include "llviewerwindow.h"
+
+#include "pipeline.h"
+
+#include <sstream>
+
+LLFloaterEnvSettings* LLFloaterEnvSettings::sEnvSettings = NULL;
+
+LLFloaterEnvSettings::LLFloaterEnvSettings() : LLFloater("Environment Settings Floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_env_settings.xml");
+	
+	// load it up
+	initCallbacks();
+}
+
+LLFloaterEnvSettings::~LLFloaterEnvSettings()
+{
+}
+
+void LLFloaterEnvSettings::onClickHelp(void* data)
+{
+	LLFloaterEnvSettings* self = static_cast<LLFloaterEnvSettings*>(data);
+
+	const char* xml_alert = "EnvSettingsHelpButton";
+	LLAlertDialog* dialogp = gViewerWindow->alertXml(xml_alert);
+	if (dialogp)
+	{
+		LLFloater* root_floater = gFloaterView->getParentFloater(self);
+		if (root_floater)
+		{
+			root_floater->addDependentFloater(dialogp);
+		}
+	}
+}
+
+void LLFloaterEnvSettings::initCallbacks(void) 
+{
+	// our three sliders
+	childSetCommitCallback("EnvTimeSlider", onChangeDayTime, NULL);
+	childSetCommitCallback("EnvCloudSlider", onChangeCloudCoverage, NULL);
+	childSetCommitCallback("EnvWaterFogSlider", onChangeWaterFogDensity, 
+		&LLWaterParamManager::instance()->mFogDensity);	
+
+	// color picker
+	childSetCommitCallback("EnvWaterColor", onChangeWaterColor, 
+		&LLWaterParamManager::instance()->mFogColor);
+
+	// WL Top
+	childSetAction("EnvAdvancedSkyButton", onOpenAdvancedSky, NULL);
+	childSetAction("EnvAdvancedWaterButton", onOpenAdvancedWater, NULL);
+	childSetAction("EnvUseEstateTimeButton", onUseEstateTime, NULL);
+	childSetAction("EnvSettingsHelpButton", onClickHelp, this);
+}
+
+
+// menu maintenance functions
+
+void LLFloaterEnvSettings::syncMenu()
+{
+	LLSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getSliderByName(sEnvSettings, 
+		"EnvTimeSlider");
+	if(NULL == sldr)
+	{
+		return;
+	}
+
+	// sync the clock
+	F32 val = (F32)LLWLParamManager::instance()->mAnimator.getDayTime();
+	LLString timeStr = timeToString(val);
+
+	LLTextBox* textBox;
+	textBox = LLUICtrlFactory::getTextBoxByName(sEnvSettings, 
+		"EnvTimeText");
+	if(NULL == textBox)
+	{
+		return;
+	}
+
+	textBox->setValue(timeStr);
+	
+	// sync time slider which starts at 6 AM	
+	val -= 0.25;
+	if(val < 0) 
+	{
+		val++;
+	}
+	sldr->setValue(val);
+
+	// sync cloud coverage
+	bool err;
+	childSetValue("EnvCloudSlider", LLWLParamManager::instance()->mCurParams.getFloat("cloud_shadow", err));
+
+	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+	// sync water params
+	LLColor4 col = param_mgr->getFogColor();
+	LLColorSwatchCtrl* colCtrl = sEnvSettings->getChild<LLColorSwatchCtrl>("EnvWaterColor");
+	col.mV[3] = 1.0f;
+	colCtrl->set(col);
+
+	childSetValue("EnvWaterFogSlider", param_mgr->mFogDensity.mExp);
+	param_mgr->setDensitySliderValue(param_mgr->mFogDensity.mExp);
+
+	// turn off Use Estate Time button if it's already being used
+	if(LLWLParamManager::instance()->mAnimator.mUseLindenTime)
+	{
+		childDisable("EnvUseEstateTimeButton");
+	} else {
+		childEnable("EnvUseEstateTimeButton");
+	}
+
+	if(!gPipeline.canUseVertexShaders())
+	{
+		childDisable("EnvWaterColor");
+		childDisable("EnvWaterColorText");
+		//childDisable("EnvAdvancedWaterButton");		
+	}
+	else
+	{
+		childEnable("EnvWaterColor");
+		childEnable("EnvWaterColorText");
+		//childEnable("EnvAdvancedWaterButton");		
+	}
+
+	// only allow access to these if they are using windlight
+	if(!gPipeline.canUseWindLightShaders())
+	{
+
+		childDisable("EnvCloudSlider");
+		childDisable("EnvCloudText");
+		//childDisable("EnvAdvancedSkyButton");
+	}
+	else
+	{
+		childEnable("EnvCloudSlider");
+		childEnable("EnvCloudText");
+		//childEnable("EnvAdvancedSkyButton");
+	}
+}
+
+
+// static instance of it
+LLFloaterEnvSettings* LLFloaterEnvSettings::instance()
+{
+	if (!sEnvSettings)
+	{
+		sEnvSettings = new LLFloaterEnvSettings();
+		sEnvSettings->open();
+		sEnvSettings->setFocus(TRUE);
+	}
+	return sEnvSettings;
+}
+void LLFloaterEnvSettings::show()
+{
+	LLFloaterEnvSettings* envSettings = instance();
+	envSettings->syncMenu();
+
+	// comment in if you want the menu to rebuild each time
+	//gUICtrlFactory->buildFloater(envSettings, "floater_env_settings.xml");
+	//envSettings->initCallbacks();
+
+	envSettings->open();
+}
+
+bool LLFloaterEnvSettings::isOpen()
+{
+	if (sEnvSettings != NULL) 
+	{
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterEnvSettings::onClose(bool app_quitting)
+{
+	if (sEnvSettings)
+	{
+		sEnvSettings->setVisible(FALSE);
+	}
+}
+
+
+void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getSliderByName(sEnvSettings, 
+		"EnvTimeSlider");
+
+	// deactivate animator
+	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+	F32 val = sldr->getValueF32() + 0.25f;
+	if(val > 1.0) 
+	{
+		val--;
+	}
+
+	LLWLParamManager::instance()->mAnimator.setDayTime((F64)val);
+	LLWLParamManager::instance()->mAnimator.update(
+		LLWLParamManager::instance()->mCurParams);
+}
+
+void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getSliderByName(sEnvSettings, 
+		"EnvCloudSlider");
+	
+	// deactivate animator
+	//LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+	//LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+	F32 val = sldr->getValueF32();
+	LLWLParamManager::instance()->mCurParams.set("cloud_shadow", val);
+}
+
+void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldr;
+	sldr = LLUICtrlFactory::getSliderByName(sEnvSettings, 
+		"EnvWaterFogSlider");
+	
+	if(NULL == sldr || NULL == userData)
+	{
+		return;
+	}
+
+	WaterExpFloatControl * expFloatControl = static_cast<WaterExpFloatControl *>(userData);
+	
+	F32 val = sldr->getValueF32();
+	expFloatControl->mExp = val;
+	LLWaterParamManager::instance()->setDensitySliderValue(val);
+
+	expFloatControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, void* userData)
+{
+	LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);	
+	*colorControl = swatch->get();
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+
+void LLFloaterEnvSettings::onOpenAdvancedSky(void* userData)
+{
+	LLFloaterWindLight::show();
+}
+
+void LLFloaterEnvSettings::onOpenAdvancedWater(void* userData)
+{
+	LLFloaterWater::show();
+}
+
+
+void LLFloaterEnvSettings::onUseEstateTime(void* userData)
+{
+	if(LLFloaterWindLight::isOpen())
+	{
+		// select the blank value in 
+		LLFloaterWindLight* wl = LLFloaterWindLight::instance();
+		LLComboBox* box = LLUICtrlFactory::getComboBoxByName(wl, "WLPresetsCombo");
+		box->selectByValue("");
+	}
+
+	LLWLParamManager::instance()->mAnimator.mIsRunning = true;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;
+}
+
+LLString LLFloaterEnvSettings::timeToString(F32 curTime)
+{
+	S32 hours;
+	S32 min;
+	bool isPM = false;
+
+	// get hours and minutes
+	hours = (S32) (24.0 * curTime);
+	curTime -= ((F32) hours / 24.0f);
+	min = llround(24.0f * 60.0f * curTime);
+
+	// handle case where it's 60
+	if(min == 60) 
+	{
+		hours++;
+		min = 0;
+	}
+
+	// set for PM
+	if(hours >= 12 && hours < 24)
+	{
+		isPM = true;
+	}
+
+	// convert to non-military notation
+	if(hours >= 24) 
+	{
+		hours = 12;
+	} 
+	else if(hours > 12) 
+	{
+		hours -= 12;
+	} 
+	else if(hours == 0) 
+	{
+		hours = 12;
+	}
+
+	// make the string
+	std::stringstream newTime;
+	newTime << hours << ":";
+	
+	// double 0
+	if(min < 10) 
+	{
+		newTime << 0;
+	}
+	
+	// finish it
+	newTime << min << " ";
+	if(isPM) 
+	{
+		newTime << "PM";
+	} 
+	else 
+	{
+		newTime << "AM";
+	}
+
+	return newTime.str();
+}
diff --git a/indra/newview/llfloaterenvsettings.h b/indra/newview/llfloaterenvsettings.h
new file mode 100644
index 00000000000..2ac555083eb
--- /dev/null
+++ b/indra/newview/llfloaterenvsettings.h
@@ -0,0 +1,106 @@
+/** 
+ * @file llfloaterskysettings.h
+ * @brief LLFloaterEnvSettings class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/*
+ * Simple menu for adjusting the atmospheric settings of the world
+ */
+
+#ifndef LL_LLFLOATERENVSETTINGS_H
+#define LL_LLFLOATERENVSETTINGS_H
+
+#include "llfloater.h"
+
+
+/// Menuing system for all of windlight's functionality
+class LLFloaterEnvSettings : public LLFloater
+{
+public:
+
+	LLFloaterEnvSettings();
+	virtual ~LLFloaterEnvSettings();
+	
+	/// initialize all the callbacks for the menu
+	void initCallbacks(void);
+
+	/// one and one instance only
+	static LLFloaterEnvSettings* instance();
+	
+	/// callback for the menus help button
+	static void onClickHelp(void* data);
+	
+	/// handle if time of day is changed
+	static void onChangeDayTime(LLUICtrl* ctrl, void* userData);
+
+	/// handle if cloud coverage is changed
+	static void onChangeCloudCoverage(LLUICtrl* ctrl, void* userData);
+
+	/// handle change in water fog density
+	static void onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData);
+
+	/// handle change in under water fog density
+	static void onChangeUnderWaterFogMod(LLUICtrl* ctrl, void* userData);
+
+	/// handle change in water fog color
+	static void onChangeWaterColor(LLUICtrl* ctrl, void* userData);
+
+	/// open the advanced sky settings menu
+	static void onOpenAdvancedSky(void* userData);
+
+	/// open the advanced water settings menu
+	static void onOpenAdvancedWater(void* userData);
+
+	/// sync time with the server
+	static void onUseEstateTime(void* userData);
+
+	//// menu management
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up sliders with parameters
+	void syncMenu();
+
+	/// convert the present time to a digital clock time
+	LLString timeToString(F32 curTime);
+
+private:
+	// one instance on the inside
+	static LLFloaterEnvSettings* sEnvSettings;
+};
+
+
+#endif
diff --git a/indra/newview/llfloaterhardwaresettings.cpp b/indra/newview/llfloaterhardwaresettings.cpp
new file mode 100644
index 00000000000..00dcf674538
--- /dev/null
+++ b/indra/newview/llfloaterhardwaresettings.cpp
@@ -0,0 +1,207 @@
+/** 
+ * @file llfloaterhardwaresettings.cpp
+ * @brief Menu of all the different graphics hardware settings
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterhardwaresettings.h"
+#include "llfloaterpreference.h"
+#include "llviewerwindow.h"
+#include "llviewercontrol.h"
+#include "llviewerimagelist.h"
+#include "llfeaturemanager.h"
+#include "llstartup.h"
+
+#include "llradiogroup.h"
+#include "llvieweruictrlfactory.h"
+
+#include "llimagegl.h"
+#include "pipeline.h"
+
+LLFloaterHardwareSettings* LLFloaterHardwareSettings::sHardwareSettings = NULL;
+
+LLFloaterHardwareSettings::LLFloaterHardwareSettings() : LLFloater("Hardware Settings Floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_hardware_settings.xml");
+	
+	// load it up
+	initCallbacks();
+}
+
+LLFloaterHardwareSettings::~LLFloaterHardwareSettings()
+{
+}
+
+void LLFloaterHardwareSettings::onClickHelp(void* data)
+{
+	const char* xml_alert = "HardwareSettingsHelpButton";
+	gViewerWindow->alertXml(xml_alert);
+}
+
+void LLFloaterHardwareSettings::initCallbacks(void) 
+{
+}
+
+// menu maintenance functions
+
+void LLFloaterHardwareSettings::refresh()
+{
+	LLPanel::refresh();
+
+	mUseVBO = gSavedSettings.getBOOL("RenderVBOEnable");
+	mUseAniso = gSavedSettings.getBOOL("RenderAnisotropic");
+	mGamma = gSavedSettings.getF32("RenderGamma");
+	mVideoCardMem = gSavedSettings.getS32("TextureMemory");
+	mFogRatio = gSavedSettings.getF32("RenderFogRatio");
+	mProbeHardwareOnStartup = gSavedSettings.getBOOL("ProbeHardwareOnStartup");
+
+	refreshEnabledState();
+}
+
+void LLFloaterHardwareSettings::refreshEnabledState()
+{
+	S32 min_tex_mem = LLViewerImageList::getMinVideoRamSetting();
+	S32 max_tex_mem = LLViewerImageList::getMaxVideoRamSetting();
+	childSetMinValue("GrapicsCardTextureMemory", min_tex_mem);
+	childSetMaxValue("GrapicsCardTextureMemory", max_tex_mem);
+
+	if (!gFeatureManagerp->isFeatureAvailable("RenderVBOEnable") ||
+		!gGLManager.mHasVertexBufferObject)
+	{
+		childSetEnabled("vbo", FALSE);
+	}
+
+	// if no windlight shaders, turn off nighttime brightness, gamma, and fog distance
+	childSetEnabled("gamma", !gPipeline.canUseWindLightShaders());
+	childSetEnabled("(brightness, lower is brighter)", !gPipeline.canUseWindLightShaders());
+	childSetEnabled("fog", !gPipeline.canUseWindLightShaders());
+
+}
+
+// static instance of it
+LLFloaterHardwareSettings* LLFloaterHardwareSettings::instance()
+{
+	if (!sHardwareSettings)
+	{
+		sHardwareSettings = new LLFloaterHardwareSettings();
+		sHardwareSettings->close();
+	}
+	return sHardwareSettings;
+}
+void LLFloaterHardwareSettings::show()
+{
+	LLFloaterHardwareSettings* hardSettings = instance();
+	hardSettings->refresh();
+	hardSettings->center();
+
+	// comment in if you want the menu to rebuild each time
+	//gUICtrlFactory->buildFloater(hardSettings, "floater_hardware_settings.xml");
+	//hardSettings->initCallbacks();
+
+	hardSettings->open();
+}
+
+bool LLFloaterHardwareSettings::isOpen()
+{
+	if (sHardwareSettings != NULL) 
+	{
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterHardwareSettings::onClose(bool app_quitting)
+{
+	if (sHardwareSettings)
+	{
+		sHardwareSettings->setVisible(FALSE);
+	}
+}
+
+
+//============================================================================
+
+BOOL LLFloaterHardwareSettings::postBuild()
+{
+	requires("ani", WIDGET_TYPE_CHECKBOX);
+	requires("gamma", WIDGET_TYPE_SPINNER);
+	requires("vbo", WIDGET_TYPE_CHECKBOX);
+	requires("GrapicsCardTextureMemory", WIDGET_TYPE_SLIDER);
+	requires("fog", WIDGET_TYPE_SPINNER);
+
+	if (!checkRequirements())
+	{
+		return FALSE;
+	}
+
+	childSetAction("OK", onBtnOK, this);
+
+	refresh();
+
+	return TRUE;
+}
+
+
+void LLFloaterHardwareSettings::apply()
+{
+	// Anisotropic rendering
+	BOOL old_anisotropic = LLImageGL::sGlobalUseAnisotropic;
+	LLImageGL::sGlobalUseAnisotropic = childGetValue("ani");
+	if (old_anisotropic != LLImageGL::sGlobalUseAnisotropic)
+	{
+		BOOL logged_in = (LLStartUp::getStartupState() >= STATE_STARTED);
+		gViewerWindow->restartDisplay(logged_in);
+	}
+
+	refresh();
+}
+
+
+void LLFloaterHardwareSettings::cancel()
+{
+	gSavedSettings.setBOOL("RenderVBOEnable", mUseVBO);
+	gSavedSettings.setBOOL("RenderAnisotropic", mUseAniso);
+	gSavedSettings.setF32("RenderGamma", mGamma);
+	gSavedSettings.setS32("TextureMemory", mVideoCardMem);
+	gSavedSettings.setF32("RenderFogRatio", mFogRatio);
+	gSavedSettings.setBOOL("ProbeHardwareOnStartup", mProbeHardwareOnStartup );
+
+	close();
+}
+
+// static 
+void LLFloaterHardwareSettings::onBtnOK( void* userdata )
+{
+	LLFloaterHardwareSettings *fp =(LLFloaterHardwareSettings *)userdata;
+	fp->apply();
+	fp->close(false);
+}
+
diff --git a/indra/newview/llfloaterhardwaresettings.h b/indra/newview/llfloaterhardwaresettings.h
new file mode 100644
index 00000000000..0f5f2fee054
--- /dev/null
+++ b/indra/newview/llfloaterhardwaresettings.h
@@ -0,0 +1,102 @@
+/** 
+ * @file llfloaterhardwaresettings.h
+ * @brief Menu of all the different graphics hardware settings
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATER_HARDWARE_SETTINGS_H
+#define LL_LLFLOATER_HARDWARE_SETTINGS_H
+
+#include "llfloater.h"
+
+class LLSliderCtrl;
+
+/// Menuing system for all of windlight's functionality
+class LLFloaterHardwareSettings : public LLFloater
+{
+	friend class LLPreferenceCore;
+
+public:
+
+	LLFloaterHardwareSettings();
+	virtual ~LLFloaterHardwareSettings();
+	
+	virtual BOOL postBuild();
+
+	/// initialize all the callbacks for the menu
+	void initCallbacks(void);
+
+	/// one and one instance only
+	static LLFloaterHardwareSettings* instance();
+	
+	/// callback for the menus help button
+	static void onClickHelp(void* data);
+
+	/// OK button
+	static void onBtnOK( void* userdata );
+	
+	//// menu management
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up menu with parameters
+	void refresh();
+
+	/// Apply the changed values.
+	void apply();
+	
+	/// don't apply the changed values
+	void cancel();
+
+	/// refresh the enabled values
+	void refreshEnabledState();
+
+protected:
+	LLSliderCtrl*	mCtrlVideoCardMem;
+
+	BOOL mUseVBO;
+	BOOL mUseAniso;
+	F32 mGamma;
+	S32 mVideoCardMem;
+	F32 mFogRatio;
+	BOOL mProbeHardwareOnStartup;
+
+private:
+	// one instance on the inside
+	static LLFloaterHardwareSettings* sHardwareSettings;
+};
+
+#endif
+
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 53779b69709..eb5ee352b98 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -43,6 +43,7 @@
 #include "llcombobox.h"
 #include "lldrawable.h"
 #include "lldrawpoolavatar.h"
+#include "llglimmediate.h"
 #include "llface.h"
 #include "lltextbox.h"
 #include "lltoolmgr.h"
@@ -258,19 +259,19 @@ void LLFloaterImagePreview::draw()
 				}
 			}
 
-			glColor3f(1.f, 1.f, 1.f);
-			glBegin( GL_QUADS );
+			gGL.color3f(1.f, 1.f, 1.f);
+			gGL.begin( GL_QUADS );
 			{
-				glTexCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop);
-				glVertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
-				glTexCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mBottom);
-				glVertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-				glTexCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom);
-				glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-				glTexCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mTop);
-				glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+				gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop);
+				gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+				gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mBottom);
+				gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+				gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom);
+				gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+				gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mTop);
+				gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
 			}
-			glEnd();
+			gGL.end();
 
 			LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
 
@@ -280,25 +281,25 @@ void LLFloaterImagePreview::draw()
 		{
 			if ((mAvatarPreview) && (mSculptedPreview))
 			{
-				glColor3f(1.f, 1.f, 1.f);
+				gGL.color3f(1.f, 1.f, 1.f);
 
 				if (selected == 9)
 					mSculptedPreview->bindTexture();
 				else
 					mAvatarPreview->bindTexture();
 
-				glBegin( GL_QUADS );
+				gGL.begin( GL_QUADS );
 				{
-					glTexCoord2f(0.f, 1.f);
-					glVertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
-					glTexCoord2f(0.f, 0.f);
-					glVertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-					glTexCoord2f(1.f, 0.f);
-					glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
-					glTexCoord2f(1.f, 1.f);
-					glVertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+					gGL.texCoord2f(0.f, 1.f);
+					gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
+					gGL.texCoord2f(0.f, 0.f);
+					gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+					gGL.texCoord2f(1.f, 0.f);
+					gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
+					gGL.texCoord2f(1.f, 1.f);
+					gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
 				}
-				glEnd();
+				gGL.end();
 
 				if (selected == 9)
 					mSculptedPreview->unbindTexture();
@@ -615,7 +616,7 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLDynamicTex
 	mDummyAvatar->slamPosition();
 	mDummyAvatar->updateJointLODs();
 	mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
-	gPipeline.markVisible(mDummyAvatar->mDrawable, *gCamera);
+	// gPipeline.markVisible(mDummyAvatar->mDrawable, *gCamera);
 
 	mTextureName = 0;
 }
@@ -669,25 +670,26 @@ BOOL LLImagePreviewAvatar::render()
 	LLVOAvatar* avatarp = mDummyAvatar;
 
 	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 	glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f);
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 
 	LLGLSUIDefault def;
-	glColor4f(0.15f, 0.2f, 0.3f, 1.f);
+	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
 	gl_rect_2d_simple( mWidth, mHeight );
 
 	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	gGL.popMatrix();
 
 	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
+	gGL.popMatrix();
 
+	gGL.stop();
 	LLVector3 target_pos = mTargetJoint->getWorldPosition();
 
 	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * 
@@ -720,6 +722,8 @@ BOOL LLImagePreviewAvatar::render()
 		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
 	}
 
+	gGL.start();
+
 	return TRUE;
 }
 
@@ -826,23 +830,23 @@ BOOL LLImagePreviewSculpted::render()
 	LLGLDepthTest depth(GL_TRUE);
 
 	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 	glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f);
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 		
-	glColor4f(0.15f, 0.2f, 0.3f, 1.f);
+	gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
 
 	gl_rect_2d_simple( mWidth, mHeight );
 
 	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	gGL.popMatrix();
 
 	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
+	gGL.popMatrix();
 
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 	
@@ -863,31 +867,55 @@ BOOL LLImagePreviewSculpted::render()
 	gCamera->setView(gCamera->getDefaultFOV() / mCameraZoom);
 	gCamera->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE);
 
-	gPipeline.enableLightsAvatar(0.0);
-
+	gPipeline.enableLightsAvatar();
 		
-	glPushMatrix();
+	gGL.pushMatrix();
 	glScalef(0.5, 0.5, 0.5);
 	
-	glBegin(GL_TRIANGLES);
-	glColor3f(0.8f, 0.8f, 0.8f);
-
 	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
-	S32 num_indices = (S32)vf.mIndices.size();
-	for (U32 i = 0; (S32)i < num_indices; i++)
+	U32 num_indices = vf.mIndices.size();
+	U32 num_vertices = vf.mVertices.size();
+
+	if (num_vertices > 0 && num_indices > 0)
 	{
-		LLVector3 normal = vf.mVertices[vf.mIndices[i]].mNormal;
-		normal.normVec();
-		glNormal3f(normal.mV[VX], normal.mV[VY], normal.mV[VZ]);
+		glEnableClientState(GL_NORMAL_ARRAY);
+		// build vertices and normals
+		F32* vertices = new F32[num_vertices * 3];
+		F32* normals = new F32[num_vertices * 3];
 
-		LLVector3 position = vf.mVertices[vf.mIndices[i]].mPosition;
-		glVertex3f(position.mV[VX], position.mV[VY], position.mV[VZ]);
-	}
+		for (U32 i = 0; (S32)i < num_vertices; i++)
+		{
+			LLVector3 position = vf.mVertices[i].mPosition;
+			vertices[i*3]   = position.mV[VX];
+			vertices[i*3+1] = position.mV[VY];
+			vertices[i*3+2] = position.mV[VZ];
+			
+			LLVector3 normal = vf.mVertices[i].mNormal;
+			normals[i*3]   = normal.mV[VX];
+			normals[i*3+1] = normal.mV[VY];
+			normals[i*3+2] = normal.mV[VZ];
+		}
+
+		// build indices
+		U16* indices = new U16[num_indices];
+		for (U16 i = 0; i < num_indices; i++)
+		{
+			indices[i] = vf.mIndices[i];
+		}
+
+		gGL.color3f(0.4f, 0.4f, 0.4f);
+		glVertexPointer(3, GL_FLOAT, 0, (void *)vertices);
+		glNormalPointer(GL_FLOAT, 0, (void *)normals);
+		glDrawRangeElements(GL_TRIANGLES, 0, num_indices-1, num_indices, GL_UNSIGNED_SHORT, (void *)indices);
 		
-	glEnd();
-	
-	glPopMatrix();
-	
+		gGL.popMatrix();
+		glDisableClientState(GL_NORMAL_ARRAY);
+
+		delete [] indices;
+		delete [] vertices;
+		delete [] normals;
+	}
+
 	return TRUE;
 }
 
diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp
new file mode 100644
index 00000000000..33704fc720b
--- /dev/null
+++ b/indra/newview/llfloaterpostprocess.cpp
@@ -0,0 +1,273 @@
+/** 
+ * @file llfloaterpostprocess.cpp
+ * @brief LLFloaterPostProcess class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterpostprocess.h"
+
+#include "llsliderctrl.h"
+#include "llcheckboxctrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewerdisplay.h"
+#include "llpostprocess.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llviewerwindow.h"
+
+
+LLFloaterPostProcess* LLFloaterPostProcess::sPostProcess = NULL;
+
+
+LLFloaterPostProcess::LLFloaterPostProcess() : LLFloater("Post-Process Floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_post_process.xml");
+
+	/// Color Filter Callbacks
+	childSetCommitCallback("ColorFilterToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_color_filter");
+	//childSetCommitCallback("ColorFilterGamma", &LLFloaterPostProcess::onFloatControlMoved, &(gPostProcess->tweaks.gamma()));
+	childSetCommitCallback("ColorFilterBrightness", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness");
+	childSetCommitCallback("ColorFilterSaturation", &LLFloaterPostProcess::onFloatControlMoved, (char*)"saturation");
+	childSetCommitCallback("ColorFilterContrast", &LLFloaterPostProcess::onFloatControlMoved, (char*)"contrast");
+
+	childSetCommitCallback("ColorFilterBaseR", &LLFloaterPostProcess::onColorControlRMoved, (char*)"contrast_base");
+	childSetCommitCallback("ColorFilterBaseG", &LLFloaterPostProcess::onColorControlGMoved, (char*)"contrast_base");
+	childSetCommitCallback("ColorFilterBaseB", &LLFloaterPostProcess::onColorControlBMoved, (char*)"contrast_base");
+	childSetCommitCallback("ColorFilterBaseI", &LLFloaterPostProcess::onColorControlIMoved, (char*)"contrast_base");
+
+	/// Night Vision Callbacks
+	childSetCommitCallback("NightVisionToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_night_vision");
+	childSetCommitCallback("NightVisionBrightMult", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness_multiplier");
+	childSetCommitCallback("NightVisionNoiseSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_size");
+	childSetCommitCallback("NightVisionNoiseStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_strength");
+
+	/// Bloom Callbacks
+	childSetCommitCallback("BloomToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_bloom");
+	childSetCommitCallback("BloomExtract", &LLFloaterPostProcess::onFloatControlMoved, (char*)"extract_low");
+	childSetCommitCallback("BloomSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_width");
+	childSetCommitCallback("BloomStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_strength");
+
+	// Effect loading and saving.
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "PPEffectsCombo");
+	childSetAction("PPLoadEffect", &LLFloaterPostProcess::onLoadEffect, comboBox);
+	comboBox->setCommitCallback(onChangeEffectName);
+
+	LLLineEditor* editBox = LLUICtrlFactory::getLineEditorByName(this, "PPEffectNameEditor");
+	childSetAction("PPSaveEffect", &LLFloaterPostProcess::onSaveEffect, editBox);
+
+	syncMenu();
+	
+}
+
+LLFloaterPostProcess::~LLFloaterPostProcess()
+{
+
+
+}
+
+LLFloaterPostProcess* LLFloaterPostProcess::instance()
+{
+	// if we don't have our singleton instance, create it
+	if (!sPostProcess)
+	{
+		sPostProcess = new LLFloaterPostProcess();
+		sPostProcess->open();
+		sPostProcess->setFocus(TRUE);
+	}
+	return sPostProcess;
+}
+
+// Bool Toggle
+void LLFloaterPostProcess::onBoolToggle(LLUICtrl* ctrl, void* userData)
+{
+	char const * boolVariableName = (char const *)userData;
+	
+	// check the bool
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+	gPostProcess->tweaks[boolVariableName] = cbCtrl->getValue();
+}
+
+// Float Moved
+void LLFloaterPostProcess::onFloatControlMoved(LLUICtrl* ctrl, void* userData)
+{
+	char const * floatVariableName = (char const *)userData;
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	gPostProcess->tweaks[floatVariableName] = sldrCtrl->getValue();
+}
+
+// Color Moved
+void LLFloaterPostProcess::onColorControlRMoved(LLUICtrl* ctrl, void* userData)
+{
+	char const * floatVariableName = (char const *)userData;
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	gPostProcess->tweaks[floatVariableName][0] = sldrCtrl->getValue();
+}
+
+// Color Moved
+void LLFloaterPostProcess::onColorControlGMoved(LLUICtrl* ctrl, void* userData)
+{
+	char const * floatVariableName = (char const *)userData;
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	gPostProcess->tweaks[floatVariableName][1] = sldrCtrl->getValue();
+}
+
+// Color Moved
+void LLFloaterPostProcess::onColorControlBMoved(LLUICtrl* ctrl, void* userData)
+{
+	char const * floatVariableName = (char const *)userData;
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	gPostProcess->tweaks[floatVariableName][2] = sldrCtrl->getValue();
+}
+
+// Color Moved
+void LLFloaterPostProcess::onColorControlIMoved(LLUICtrl* ctrl, void* userData)
+{
+	char const * floatVariableName = (char const *)userData;
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	gPostProcess->tweaks[floatVariableName][3] = sldrCtrl->getValue();
+}
+
+void LLFloaterPostProcess::onLoadEffect(void* userData)
+{
+	LLComboBox* comboBox = static_cast<LLComboBox*>(userData);
+
+	LLSD::String effectName(comboBox->getSelectedValue().asString());
+
+	gPostProcess->setSelectedEffect(effectName);
+
+	sPostProcess->syncMenu();
+}
+
+void LLFloaterPostProcess::onSaveEffect(void* userData)
+{
+	LLLineEditor* editBox = static_cast<LLLineEditor*>(userData);
+
+	LLSD::String effectName(editBox->getValue().asString());
+
+	if (gPostProcess->mAllEffects.has(effectName))
+	{
+		gViewerWindow->alertXml("PPSaveEffectAlert", &LLFloaterPostProcess::saveAlertCallback, userData);
+	}
+	else
+	{
+		gPostProcess->saveEffect(effectName);
+		sPostProcess->syncMenu();
+	}
+}
+
+void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl, void * userData)
+{
+	// get the combo box and name
+	LLComboBox * comboBox = static_cast<LLComboBox*>(ctrl);
+	LLLineEditor* editBox = LLUICtrlFactory::getLineEditorByName(sPostProcess, 
+		"PPEffectNameEditor");
+
+	// set the parameter's new name
+	editBox->setValue(comboBox->getSelectedValue());
+}
+
+void LLFloaterPostProcess::saveAlertCallback(S32 option, void* userData)
+{
+	LLLineEditor* editBox = static_cast<LLLineEditor*>(userData);
+
+	// if they choose save, do it.  Otherwise, don't do anything
+	if (option == 0)
+	{
+		LLSD::String effectName(editBox->getValue().asString());
+
+		gPostProcess->saveEffect(effectName);
+
+		sPostProcess->syncMenu();
+	}
+
+}
+
+void LLFloaterPostProcess::show()
+{
+	// get the instance, make sure the values are synced
+	// and open the menu
+	LLFloaterPostProcess* postProcess = instance();
+	postProcess->syncMenu();
+	postProcess->open();
+}
+
+// virtual
+void LLFloaterPostProcess::onClose(bool app_quitting)
+{
+	// just set visibility to false, don't get fancy yet
+	if (sPostProcess)
+	{
+		sPostProcess->setVisible(FALSE);
+	}
+}
+
+void LLFloaterPostProcess::syncMenu()
+{
+	// add the combo boxe contents
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "PPEffectsCombo");
+
+	if(comboBox != NULL) {
+		comboBox->removeall();
+	
+		LLSD::map_const_iterator currEffect;
+		for(currEffect = gPostProcess->mAllEffects.beginMap();
+			currEffect != gPostProcess->mAllEffects.endMap();
+			++currEffect) 
+		{
+			comboBox->add(currEffect->first);
+		}
+
+		// set the current effect as selected.
+		comboBox->selectByValue(gPostProcess->getSelectedEffect());
+	}
+
+	/// Sync Color Filter Menu
+	childSetValue("ColorFilterToggle", gPostProcess->tweaks.useColorFilter());
+	//childSetValue("ColorFilterGamma", gPostProcess->tweaks.gamma());
+	childSetValue("ColorFilterBrightness", gPostProcess->tweaks.brightness());
+	childSetValue("ColorFilterSaturation", gPostProcess->tweaks.saturation());
+	childSetValue("ColorFilterContrast", gPostProcess->tweaks.contrast());
+	childSetValue("ColorFilterBaseR", gPostProcess->tweaks.contrastBaseR());
+	childSetValue("ColorFilterBaseG", gPostProcess->tweaks.contrastBaseG());
+	childSetValue("ColorFilterBaseB", gPostProcess->tweaks.contrastBaseB());
+	childSetValue("ColorFilterBaseI", gPostProcess->tweaks.contrastBaseIntensity());
+	
+	/// Sync Night Vision Menu
+	childSetValue("NightVisionToggle", gPostProcess->tweaks.useNightVisionShader());
+	childSetValue("NightVisionBrightMult", gPostProcess->tweaks.brightMult());
+	childSetValue("NightVisionNoiseSize", gPostProcess->tweaks.noiseSize());
+	childSetValue("NightVisionNoiseStrength", gPostProcess->tweaks.noiseStrength());
+
+	/// Sync Bloom Menu
+	childSetValue("BloomToggle", LLSD(gPostProcess->tweaks.useBloomShader()));
+	childSetValue("BloomExtract", gPostProcess->tweaks.extractLow());
+	childSetValue("BloomSize", gPostProcess->tweaks.bloomWidth());
+	childSetValue("BloomStrength", gPostProcess->tweaks.bloomStrength());
+}
diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h
new file mode 100644
index 00000000000..8b590f8b8ef
--- /dev/null
+++ b/indra/newview/llfloaterpostprocess.h
@@ -0,0 +1,90 @@
+/** 
+ * @file llfloaterpostprocess.h
+ * @brief LLFloaterPostProcess class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERPOSTPROCESS_H
+#define LL_LLFLOATERPOSTPROCESS_H
+
+#include "llfloater.h"
+
+class LLButton;
+class LLSliderCtrl;
+class LLTabContainer;
+class LLPanelPermissions;
+class LLPanelObject;
+class LLPanelVolume;
+class LLPanelContents;
+class LLPanelFace;
+
+/**
+ * Menu for adjusting the post process settings of the world
+ */
+class LLFloaterPostProcess : public LLFloater
+{
+public:
+
+	LLFloaterPostProcess();
+	virtual ~LLFloaterPostProcess();
+
+	/// one and one instance only
+	static LLFloaterPostProcess* instance();
+
+	/// post process callbacks
+	static void onBoolToggle(LLUICtrl* ctrl, void* userData);
+	static void onFloatControlMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlRMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlGMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlBMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlIMoved(LLUICtrl* ctrl, void* userData);
+	static void onLoadEffect(void* userData);
+	static void onSaveEffect(void* userData);
+	static void onChangeEffectName(LLUICtrl* ctrl, void * userData);
+
+	/// prompts a user when overwriting an effect
+	static void saveAlertCallback(S32 option, void* userData);
+
+	/// show off our menu
+	static void show();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up sliders
+	void syncMenu();
+
+/*
+	void refresh();
+*/
+public:
+	
+	static LLFloaterPostProcess* sPostProcess;
+};
+
+#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index cac2d0a0b6c..584d7479e42 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -73,6 +73,7 @@
 #include "llviewerwindow.h"
 #include "llkeyboard.h"
 #include "llscrollcontainer.h"
+#include "llfloaterhardwaresettings.h"
 
 #if LL_WINDOWS
 // for Logitech LCD keyboards / speakers
@@ -133,7 +134,6 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def
 	mInputPanel(NULL),
 	mNetworkPanel(NULL),
 	mDisplayPanel(NULL),
-	mDisplayPanel2(NULL),
 	mAudioPanel(NULL),
 	mMsgPanel(NULL),
 	mLCDPanel(NULL)
@@ -158,14 +158,6 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def
 	mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel(), FALSE, onTabChanged, mTabContainer);
 	mDisplayPanel->setDefaultBtn(default_btn);
 
-	mDisplayPanel3 = new LLPanelDisplay3();
-	mTabContainer->addTabPanel(mDisplayPanel3, mDisplayPanel3->getLabel(), FALSE, onTabChanged, mTabContainer);
-	mDisplayPanel3->setDefaultBtn(default_btn);
-
-	mDisplayPanel2 = new LLPanelDisplay2();
-	mTabContainer->addTabPanel(mDisplayPanel2, mDisplayPanel2->getLabel(), FALSE, onTabChanged, mTabContainer);
-	mDisplayPanel2->setDefaultBtn(default_btn);
-
 	mAudioPanel = new LLPanelAudioPrefs();
 	mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel(), FALSE, onTabChanged, mTabContainer);
 	mAudioPanel->setDefaultBtn(default_btn);
@@ -225,16 +217,7 @@ LLPreferenceCore::~LLPreferenceCore()
 		delete mDisplayPanel;
 		mDisplayPanel = NULL;
 	}
-	if (mDisplayPanel2)
-	{
-		delete mDisplayPanel2;
-		mDisplayPanel2 = NULL;
-	}
-	if (mDisplayPanel3)
-	{
-		delete mDisplayPanel3;
-		mDisplayPanel3 = NULL;
-	}
+
 	if (mAudioPanel)
 	{
 		delete mAudioPanel;
@@ -269,12 +252,14 @@ void LLPreferenceCore::apply()
 	mInputPanel->apply();
 	mNetworkPanel->apply();
 	mDisplayPanel->apply();
-	mDisplayPanel2->apply();
-	mDisplayPanel3->apply();
 	mPrefsChat->apply();
 	mPrefsVoice->apply();
 	mPrefsIM->apply();
 	mMsgPanel->apply();
+
+	// hardware menu apply
+	LLFloaterHardwareSettings::instance()->apply();
+
 	mWebPanel->apply();
 #if LL_WINDOWS && LL_LCD_COMPILE
 	// only add this option if we actually have a logitech keyboard / speaker set
@@ -293,13 +278,15 @@ void LLPreferenceCore::cancel()
 	mInputPanel->cancel();
 	mNetworkPanel->cancel();
 	mDisplayPanel->cancel();
-	mDisplayPanel2->cancel();
-	mDisplayPanel3->cancel();
 	mAudioPanel->cancel();
 	mPrefsChat->cancel();
 	mPrefsVoice->cancel();
 	mPrefsIM->cancel();
 	mMsgPanel->cancel();
+
+	// cancel hardware menu
+	LLFloaterHardwareSettings::instance()->cancel();
+
 	mWebPanel->cancel();
 #if LL_WINDOWS && LL_LCD_COMPILE
 	// only add this option if we actually have a logitech keyboard / speaker set
@@ -328,6 +315,12 @@ void LLPreferenceCore::setPersonalInfo(
 	mPrefsIM->setPersonalInfo(visibility, im_via_email, email);
 }
 
+void LLPreferenceCore::refreshEnabledGraphics()
+{
+	LLFloaterHardwareSettings::instance()->refreshEnabledState();
+	mDisplayPanel->refreshEnabledState();
+}
+
 //////////////////////////////////////////////
 // LLFloaterPreference
 
@@ -521,3 +514,8 @@ void LLFloaterPreference::updateUserInfo(
 			visibility, im_via_email, email);
 	}
 }
+
+void LLFloaterPreference::refreshEnabledGraphics()
+{
+	sInstance->mPreferenceCore->refreshEnabledGraphics();
+}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 7396467d8ce..52592c0bad8 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -45,8 +45,6 @@ class LLPanelGeneral;
 class LLPanelInput;
 class LLPanelLCD;
 class LLPanelDisplay;
-class LLPanelDisplay2;
-class LLPanelDisplay3;
 class LLPanelAudioPrefs;
 class LLPanelDebug;
 class LLPanelNetwork;
@@ -76,6 +74,9 @@ class LLPreferenceCore
 		const char* email);
 
 	static void onTabChanged(void* user_data, bool from_click);
+	
+	// refresh all the graphics preferences menus
+	void refreshEnabledGraphics();
 
 private:
 	LLTabContainer	*mTabContainer;
@@ -83,8 +84,6 @@ class LLPreferenceCore
 	LLPanelInput			*mInputPanel;
 	LLPanelNetwork	        *mNetworkPanel;
 	LLPanelDisplay	        *mDisplayPanel;
-	LLPanelDisplay2			*mDisplayPanel2;
-	LLPanelDisplay3			*mDisplayPanel3;
 	LLPanelAudioPrefs		*mAudioPanel;
 //	LLPanelDebug			*mDebugPanel;
 	LLPrefsChat				*mPrefsChat;
@@ -113,6 +112,9 @@ class LLFloaterPreference : public LLFloater
 		BOOL im_via_email,
 		const char* email);
 
+	// refresh all the graphics preferences menus
+	static void refreshEnabledGraphics();
+
 protected:
 	LLPreferenceCore		*mPreferenceCore;
 
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 4a3b2192c06..375523cc398 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -52,10 +52,12 @@
 #include "llcheckboxctrl.h"
 #include "llcombobox.h"
 #include "llfilepicker.h"
+#include "llfloaterdaycycle.h"
 #include "llfloatergodtools.h"	// for send_sim_wide_deletes()
 #include "llfloatertopobjects.h" // added to fix SL-32336
 #include "llfloatergroups.h"
 #include "llfloatertelehub.h"
+#include "llfloaterwindlight.h"
 #include "lllineeditor.h"
 #include "llalertdialog.h"
 #include "llnamelistctrl.h"
@@ -1436,9 +1438,21 @@ void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data)
 	}
 }
 
+
+
+
 //---------------------------------------------------------------------------
 // Add/Remove estate access button callbacks
 //---------------------------------------------------------------------------
+void LLPanelEstateInfo::onClickEditSky(void* user_data)
+{
+	LLFloaterWindLight::show();
+}
+
+void LLPanelEstateInfo::onClickEditDayCycle(void* user_data)
+{
+	LLFloaterDayCycle::show();
+}
 
 // static
 void LLPanelEstateInfo::onClickAddAllowedAgent(void* user_data)
@@ -2010,6 +2024,9 @@ BOOL LLPanelEstateInfo::postBuild()
 	initHelpBtn("estate_manager_help",			"HelpEstateEstateManager");
 	initHelpBtn("use_global_time_help",			"HelpEstateUseGlobalTime");
 	initHelpBtn("fixed_sun_help",				"HelpEstateFixedSun");
+	initHelpBtn("WLEditSkyHelp",				"HelpEditSky");
+	initHelpBtn("WLEditDayCycleHelp",			"HelpEditDayCycle");
+
 	initHelpBtn("externally_visible_help",		"HelpEstateExternallyVisible");
 	initHelpBtn("allow_direct_teleport_help",	"HelpEstateAllowDirectTeleport");
 	initHelpBtn("allow_resident_help",			"HelpEstateAllowResident");
@@ -2069,6 +2086,9 @@ BOOL LLPanelEstateInfo::postBuild()
 	childSetAction("message_estate_btn", onClickMessageEstate, this);
 	childSetAction("kick_user_from_estate_btn", onClickKickUser, this);
 
+	childSetAction("WLEditSky", onClickEditSky, this);
+	childSetAction("WLEditDayCycle", onClickEditDayCycle, this);
+
 	return LLPanelRegionInfo::postBuild();
 }
 
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index cdda7e532c6..6ef276a739a 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -257,6 +257,11 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
 	static void onChangeFixedSun(LLUICtrl* ctrl, void* user_data);
 	static void onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data);
 	
+	static void onClickEditSky(void* userdata);
+	static void onClickEditSkyHelp(void* userdata);	
+	static void onClickEditDayCycle(void* userdata);
+	static void onClickEditDayCycleHelp(void* userdata);	
+
 	static void onClickAddAllowedAgent(void* user_data);
 	static void onClickRemoveAllowedAgent(void* user_data);
 	static void onClickAddAllowedGroup(void* user_data);
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 63d7d7b9584..7dc404cab11 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -861,7 +861,7 @@ void LLFloaterReporter::takeScreenshot()
 	const S32 IMAGE_HEIGHT = 768;
 
 	LLPointer<LLImageRaw> raw = new LLImageRaw;
-	if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, TRUE, FALSE))
+	if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE))
 	{
 		llwarns << "Unable to take screenshot" << llendl;
 		return;
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index d2f3bc7cf5f..d9694a7b3f8 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -36,7 +36,9 @@
 #include "llfontgl.h"
 #include "llsys.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v3dmath.h"
+#include "llmath.h"
 #include "lldir.h"
 #include "llsdserialize.h"
 
@@ -86,7 +88,7 @@ F32 FALL_TIME = 0.6f;
 S32 BORDER_WIDTH = 6;
 
 const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
-
+#define MAX_TEXTURE_SIZE 512 //max upload texture size 512 * 512
 ///----------------------------------------------------------------------------
 /// Class LLSnapshotLivePreview 
 ///----------------------------------------------------------------------------
@@ -112,6 +114,8 @@ class LLSnapshotLivePreview : public LLView
 	void setSize(S32 w, S32 h);
 	void getSize(S32& w, S32& h) const;
 	S32 getDataSize() const { return mDataSize; }
+	void setMaxImageSize(S32 size) ;
+	S32  getMaxImageSize() {return mMaxImageSize ;}
 	
 	ESnapshotType getSnapshotType() const { return mSnapshotType; }
 	BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; }
@@ -138,7 +142,8 @@ class LLSnapshotLivePreview : public LLView
 	S32							mWidth[2];
 	S32							mHeight[2];
 	BOOL						mImageScaled[2];
-
+	S32                         mMaxImageSize ;
+	
 	S32							mCurImageIndex;
 	LLPointer<LLImageRaw>		mRawImage;
 	LLPointer<LLImageRaw>		mRawImageEncoded;
@@ -161,6 +166,7 @@ class LLSnapshotLivePreview : public LLView
 
 public:
 	static std::set<LLSnapshotLivePreview*> sList;
+	BOOL                        mKeepAspectRatio ;
 };
 
 std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList;
@@ -195,6 +201,9 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) :
 	mHeight[1] = gViewerWindow->getWindowDisplayHeight();
 	mImageScaled[0] = FALSE;
 	mImageScaled[1] = FALSE;
+
+	mMaxImageSize = MAX_IMAGE_SIZE ;
+	mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
 }
 
 LLSnapshotLivePreview::~LLSnapshotLivePreview()
@@ -208,6 +217,18 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview()
 	sList.erase(this);
 }
 
+void LLSnapshotLivePreview::setMaxImageSize(S32 size) 
+{
+	if(size < MAX_IMAGE_SIZE)
+	{
+		mMaxImageSize = size;
+	}
+	else
+	{
+		mMaxImageSize = MAX_IMAGE_SIZE ;
+	}
+}
+
 LLImageGL* LLSnapshotLivePreview::getCurrentImage()
 {
 	return mViewerImage[mCurImageIndex];
@@ -223,7 +244,7 @@ F32 LLSnapshotLivePreview::getImageAspect()
 	F32 image_aspect_ratio = ((F32)mWidth[mCurImageIndex]) / ((F32)mHeight[mCurImageIndex]);
 	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
 
-	if (gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
 	{
 		return image_aspect_ratio;
 	}
@@ -267,7 +288,7 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot)
 	F32 image_aspect_ratio = ((F32)mWidth[mCurImageIndex]) / ((F32)mHeight[mCurImageIndex]);
 	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
 
-	if (gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+	if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
 	{
 		if (image_aspect_ratio > window_aspect_ratio)
 		{
@@ -320,9 +341,8 @@ void LLSnapshotLivePreview::draw()
 			shadow_rect.stretch(BORDER_WIDTH);
 			gl_drop_shadow(shadow_rect.mLeft, shadow_rect.mTop, shadow_rect.mRight, shadow_rect.mBottom, LLColor4(0.f, 0.f, 0.f, mNeedsFlash ? 0.f :0.5f), 10);
 
-			LLGLSTexture set_texture;
 			LLColor4 image_color(1.f, 1.f, 1.f, 1.f);
-			glColor4fv(image_color.mV);
+			gGL.color4fv(image_color.mV);
 			LLViewerImage::bindTexture(mViewerImage[mCurImageIndex]);
 			// calculate UV scale
 			F32 uv_width = mImageScaled[mCurImageIndex] ? 1.f : llmin((F32)mWidth[mCurImageIndex] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f);
@@ -330,25 +350,25 @@ void LLSnapshotLivePreview::draw()
 			glPushMatrix();
 			{
 				glTranslatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f);
-				glBegin(GL_QUADS);
+				gGL.begin(GL_QUADS);
 				{
-					glTexCoord2f(uv_width, uv_height);
-					glVertex2i(rect.getWidth(), rect.getHeight() );
+					gGL.texCoord2f(uv_width, uv_height);
+					gGL.vertex2i(rect.getWidth(), rect.getHeight() );
 
-					glTexCoord2f(0.f, uv_height);
-					glVertex2i(0, rect.getHeight() );
+					gGL.texCoord2f(0.f, uv_height);
+					gGL.vertex2i(0, rect.getHeight() );
 
-					glTexCoord2f(0.f, 0.f);
-					glVertex2i(0, 0);
+					gGL.texCoord2f(0.f, 0.f);
+					gGL.vertex2i(0, 0);
 
-					glTexCoord2f(uv_width, 0.f);
-					glVertex2i(rect.getWidth(), 0);
+					gGL.texCoord2f(uv_width, 0.f);
+					gGL.vertex2i(rect.getWidth(), 0);
 				}
-				glEnd();
+				gGL.end();
 			}
 			glPopMatrix();
 
-			glColor4f(1.f, 1.f, 1.f, mFlashAlpha);
+			gGL.color4f(1.f, 1.f, 1.f, mFlashAlpha);
 			gl_rect_2d(getRect());
 			if (mNeedsFlash)
 			{
@@ -393,23 +413,23 @@ void LLSnapshotLivePreview::draw()
 					S32 y2 = gViewerWindow->getWindowHeight();
 
 					LLGLSNoTexture no_texture;
-					glBegin(GL_QUADS);
+					gGL.begin(GL_QUADS);
 					{
-						glColor4f(1.f, 1.f, 1.f, 0.f);
-						glVertex2i(x1, y1);
-						glVertex2i(x1 + gViewerWindow->getWindowWidth(), y2);
-						glColor4f(1.f, 1.f, 1.f, SHINE_OPACITY);
-						glVertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
-						glVertex2i(x2, y1);
-
-						glColor4f(1.f, 1.f, 1.f, SHINE_OPACITY);
-						glVertex2i(x2, y1);
-						glVertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
-						glColor4f(1.f, 1.f, 1.f, 0.f);
-						glVertex2i(x3 + gViewerWindow->getWindowWidth(), y2);
-						glVertex2i(x3, y1);
+						gGL.color4f(1.f, 1.f, 1.f, 0.f);
+						gGL.vertex2i(x1, y1);
+						gGL.vertex2i(x1 + gViewerWindow->getWindowWidth(), y2);
+						gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
+						gGL.vertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
+						gGL.vertex2i(x2, y1);
+
+						gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
+						gGL.vertex2i(x2, y1);
+						gGL.vertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
+						gGL.color4f(1.f, 1.f, 1.f, 0.f);
+						gGL.vertex2i(x3 + gViewerWindow->getWindowWidth(), y2);
+						gGL.vertex2i(x3, y1);
 					}
-					glEnd();
+					gGL.end();
 				}
 
 				if (mShineAnimTimer.getElapsedTimeF32() > SHINE_TIME)
@@ -422,31 +442,31 @@ void LLSnapshotLivePreview::draw()
 		// draw framing rectangle
 		{
 			LLGLSNoTexture no_texture;
-			glColor4f(1.f, 1.f, 1.f, 1.f);
+			gGL.color4f(1.f, 1.f, 1.f, 1.f);
 			LLRect outline_rect = mImageRect[mCurImageIndex];
-			glBegin(GL_QUADS);
+			gGL.begin(GL_QUADS);
 			{
-				glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
-				glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
-				glVertex2i(outline_rect.mRight, outline_rect.mTop);
-				glVertex2i(outline_rect.mLeft, outline_rect.mTop);
-
-				glVertex2i(outline_rect.mLeft, outline_rect.mBottom);
-				glVertex2i(outline_rect.mRight, outline_rect.mBottom);
-				glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
-				glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
-
-				glVertex2i(outline_rect.mLeft, outline_rect.mTop);
-				glVertex2i(outline_rect.mLeft, outline_rect.mBottom);
-				glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
-				glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
-
-				glVertex2i(outline_rect.mRight, outline_rect.mBottom);
-				glVertex2i(outline_rect.mRight, outline_rect.mTop);
-				glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
-				glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
+				gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
+
+				gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
+				gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
+				gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
+
+				gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
+				gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
+				gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
+
+				gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
+				gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
+				gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
+				gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
 			}
-			glEnd();
+			gGL.end();
 		}
 
 		// draw old image dropping away
@@ -455,12 +475,10 @@ void LLSnapshotLivePreview::draw()
 			S32 old_image_index = (mCurImageIndex + 1) % 2;
 			if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME)
 			{
-				LLGLSTexture texture_set;
-
 				F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME;
 				F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f);
 				LLColor4 image_color(1.f, 1.f, 1.f, alpha);
-				glColor4fv(image_color.mV);
+				gGL.color4fv(image_color.mV);
 				LLViewerImage::bindTexture(mViewerImage[old_image_index]);
 				// calculate UV scale
 				// *FIX get this to work with old image
@@ -472,21 +490,21 @@ void LLSnapshotLivePreview::draw()
 					LLRect& rect = mImageRect[old_image_index];
 					glTranslatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f);
 					glRotatef(-45.f * fall_interp, 0.f, 0.f, 1.f);
-					glBegin(GL_QUADS);
+					gGL.begin(GL_QUADS);
 					{
-						glTexCoord2f(uv_width, uv_height);
-						glVertex2i(rect.getWidth(), rect.getHeight() );
+						gGL.texCoord2f(uv_width, uv_height);
+						gGL.vertex2i(rect.getWidth(), rect.getHeight() );
 
-						glTexCoord2f(0.f, uv_height);
-						glVertex2i(0, rect.getHeight() );
+						gGL.texCoord2f(0.f, uv_height);
+						gGL.vertex2i(0, rect.getHeight() );
 
-						glTexCoord2f(0.f, 0.f);
-						glVertex2i(0, 0);
+						gGL.texCoord2f(0.f, 0.f);
+						gGL.vertex2i(0, 0);
 
-						glTexCoord2f(uv_width, 0.f);
-						glVertex2i(rect.getWidth(), 0);
+						gGL.texCoord2f(uv_width, 0.f);
+						gGL.vertex2i(rect.getWidth(), 0);
 					}
-					glEnd();
+					gGL.end();
 				}
 				glPopMatrix();
 			}
@@ -552,10 +570,12 @@ void LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 		if(gViewerWindow->rawSnapshot(previewp->mRawImage,
 								previewp->mWidth[previewp->mCurImageIndex],
 								previewp->mHeight[previewp->mCurImageIndex],
-								!gSavedSettings.getBOOL("KeepAspectForSnapshot"),
+								previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
+								previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE,
 								gSavedSettings.getBOOL("RenderUIInSnapshot"),
 								FALSE,
-								previewp->mSnapshotBufferType))
+								previewp->mSnapshotBufferType,
+								previewp->getMaxImageSize()))
 		{
 			previewp->mRawImageEncoded->resize(previewp->mRawImage->getWidth(), previewp->mRawImage->getHeight(), previewp->mRawImage->getComponents());
 
@@ -726,6 +746,9 @@ class LLFloaterSnapshot::Impl
 	static void onClickKeep(void* data);
 	static void onClickNewSnapshot(void* data);
 	static void onClickAutoSnap(LLUICtrl *ctrl, void* data);
+	//static void onClickAdvanceSnap(LLUICtrl *ctrl, void* data);
+	static void onClickLess(void* data) ;
+	static void onClickMore(void* data) ;
 	static void onClickUICheck(LLUICtrl *ctrl, void* data);
 	static void onClickHUDCheck(LLUICtrl *ctrl, void* data);
 	static void onClickKeepOpenCheck(LLUICtrl *ctrl, void* data);
@@ -736,6 +759,7 @@ class LLFloaterSnapshot::Impl
 	static void onCommitLayerTypes(LLUICtrl* ctrl, void*data);
 	static void onCommitSnapshotType(LLUICtrl* ctrl, void* data);
 	static void onCommitCustomResolution(LLUICtrl *ctrl, void* data);
+	static void checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value);
 
 	static LLSnapshotLivePreview* getPreviewView(LLFloaterSnapshot *floater);
 	static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname);
@@ -743,12 +767,14 @@ class LLFloaterSnapshot::Impl
 	static void updateLayout(LLFloaterSnapshot* floater);
 
 	static LLHandle<LLView> sPreviewHandle;
+	static BOOL         sAspectRatioCheckOff ;
 	
 private:
 	static LLSnapshotLivePreview::ESnapshotType getTypeIndex(LLFloaterSnapshot* floater);
 	static LLViewerWindow::ESnapshotType getLayerType(LLFloaterSnapshot* floater);
 	static void comboSetCustom(LLFloaterSnapshot *floater, const std::string& comboname);
 	static void checkAutoSnapshot(LLSnapshotLivePreview* floater);
+	static void checkAspectRatio(LLFloaterSnapshot *view, S32 index) ;
 
 public:
 	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
@@ -759,6 +785,8 @@ class LLFloaterSnapshot::Impl
 // static
 LLHandle<LLView> LLFloaterSnapshot::Impl::sPreviewHandle;
 
+//static 
+BOOL LLFloaterSnapshot::Impl::sAspectRatioCheckOff = FALSE ;
 // static
 LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater)
 {
@@ -811,13 +839,37 @@ void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const st
 void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
 {
 	LLSnapshotLivePreview* previewp = getPreviewView(floaterp);
+
+	S32 delta_height = gSavedSettings.getBOOL("AdvanceSnapshot") ? 0 : -230 ;
+
+	LLComboBox* combo;
+	if(!gSavedSettings.getBOOL("AdvanceSnapshot")) //set to original window resolution
+	{
+		previewp->mKeepAspectRatio = TRUE ;
+
+		combo = LLUICtrlFactory::getComboBoxByName(floaterp, "postcard_size_combo");
+		combo->setCurrentByIndex(0) ;
+		gSavedSettings.setS32("SnapshotPostcardLastResolution", 0) ;
+
+		combo = LLUICtrlFactory::getComboBoxByName(floaterp, "texture_size_combo");
+		combo->setCurrentByIndex(0) ;
+		gSavedSettings.setS32("SnapshotTextureLastResolution", 0) ;
+
+		combo = LLUICtrlFactory::getComboBoxByName(floaterp, "local_size_combo");
+		combo->setCurrentByIndex(0) ;
+		gSavedSettings.setS32("SnapshotLocalLastResolution", 0) ;
+
+		LLSnapshotLivePreview* previewp = getPreviewView(floaterp);
+		previewp->setSize(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
+	}
+
 	if (floaterp->childGetValue("freeze_frame_check").asBoolean())
 	{
 		// stop all mouse events at fullscreen preview layer
 		floaterp->getParent()->setMouseOpaque(TRUE);
 		
 		// shrink to smaller layout
-		floaterp->reshape(floaterp->getRect().getWidth(), 410);
+		floaterp->reshape(floaterp->getRect().getWidth(), 526 + delta_height);
 
 		// can see and interact with fullscreen preview now
 		if (previewp)
@@ -850,7 +902,7 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
 	else // turning off freeze frame mode
 	{
 		floaterp->getParent()->setMouseOpaque(FALSE);
-		floaterp->reshape(floaterp->getRect().getWidth(), 510);
+		floaterp->reshape(floaterp->getRect().getWidth(), 526 + delta_height);
 		if (previewp)
 		{
 			previewp->setVisible(FALSE);
@@ -878,6 +930,8 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
 // static
 void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 {
+	BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot") ;
+
 	LLRadioGroup* snapshot_type_radio = LLUICtrlFactory::getRadioGroupByName(floater, "snapshot_type_radio");
 	snapshot_type_radio->setSelectedIndex(gSavedSettings.getS32("LastSnapshotType"));
 	LLSnapshotLivePreview::ESnapshotType shot_type = getTypeIndex(floater);
@@ -895,19 +949,29 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 	combo = LLUICtrlFactory::getComboBoxByName(floater, "local_size_combo");
 	if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution"));
 
-
 	floater->childSetVisible("upload_btn", FALSE);
 	floater->childSetVisible("send_btn", FALSE);
 	floater->childSetVisible("save_btn", FALSE);
-	
+	floater->childSetEnabled("keep_aspect_check", FALSE) ;
+
 	switch(shot_type)
 	{
 	  case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
 		layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
 		floater->childSetValue("layer_types", "colors");
 		floater->childSetEnabled("layer_types", FALSE);
-		floater->childSetEnabled("image_quality_slider", TRUE);
-		setResolution(floater, "postcard_size_combo");
+		
+		if(is_advance)
+		{			
+			floater->childSetEnabled("image_quality_slider", TRUE);
+			setResolution(floater, "postcard_size_combo");
+
+			if(!sAspectRatioCheckOff)
+			{
+				floater->childSetEnabled("keep_aspect_check", TRUE) ;
+			}
+		}
+
 		floater->childSetVisible("send_btn", TRUE);
 		break;
 	  case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
@@ -915,18 +979,69 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 		floater->childSetValue("layer_types", "colors");
 		floater->childSetEnabled("layer_types", FALSE);
 		floater->childSetEnabled("image_quality_slider", FALSE);
-		setResolution(floater, "texture_size_combo");
+
+		if(is_advance)
+		{
+			setResolution(floater, "texture_size_combo");			
+		}
+
 		floater->childSetVisible("upload_btn", TRUE);
 		break;
 	  case LLSnapshotLivePreview::SNAPSHOT_BITMAP:
 		floater->childSetEnabled("layer_types", TRUE);
 		floater->childSetEnabled("image_quality_slider", FALSE);
-		setResolution(floater, "local_size_combo");
+		
+		if(is_advance)
+		{
+			setResolution(floater, "local_size_combo");
+
+			if(!sAspectRatioCheckOff)
+			{
+				floater->childSetEnabled("keep_aspect_check", TRUE) ;
+			}
+		}
+
 		floater->childSetVisible("save_btn", TRUE);
 		break;
 	  default:
 		break;
 	}
+
+	if(is_advance)
+	{
+		floater->childSetVisible("type_label2", TRUE) ;
+		floater->childSetVisible("layer_types", TRUE) ;
+		floater->childSetVisible("layer_type_label", TRUE) ;
+		floater->childSetVisible("snapshot_width", TRUE) ;
+		floater->childSetVisible("snapshot_height", TRUE) ;
+		floater->childSetVisible("keep_aspect_check", TRUE) ;
+		floater->childSetVisible("ui_check", TRUE) ;
+		floater->childSetVisible("hud_check", TRUE) ;
+		floater->childSetVisible("keep_open_check", TRUE) ;
+		floater->childSetVisible("freeze_frame_check", TRUE) ;
+		floater->childSetVisible("auto_snapshot_check", TRUE) ;
+		floater->childSetVisible("image_quality_slider", TRUE);
+		floater->childSetVisible("more_btn", FALSE);
+		floater->childSetVisible("less_btn", TRUE);
+	}
+	else
+	{
+		floater->childSetVisible("type_label2", FALSE) ;
+		floater->childSetVisible("layer_types", FALSE) ;
+		floater->childSetVisible("layer_type_label", FALSE) ;
+		floater->childSetVisible("snapshot_width", FALSE) ;
+		floater->childSetVisible("snapshot_height", FALSE) ;
+		floater->childSetVisible("keep_aspect_check", FALSE) ;
+		floater->childSetVisible("ui_check", FALSE) ;
+		floater->childSetVisible("hud_check", FALSE) ;
+		floater->childSetVisible("keep_open_check", FALSE) ;
+		floater->childSetVisible("freeze_frame_check", FALSE) ;
+		floater->childSetVisible("auto_snapshot_check", FALSE) ;
+		floater->childSetVisible("image_quality_slider", FALSE);
+		floater->childSetVisible("more_btn", TRUE);
+		floater->childSetVisible("less_btn", FALSE);
+	}
+
 	LLSnapshotLivePreview* previewp = getPreviewView(floater);
 	if (previewp)
 	{
@@ -939,7 +1054,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 void LLFloaterSnapshot::Impl::checkAutoSnapshot(LLSnapshotLivePreview* previewp)
 {
 	if (previewp)
-	{
+	{		
 		previewp->updateSnapshot(gSavedSettings.getBOOL("AutoSnapshot"));
 	}
 }
@@ -1026,6 +1141,59 @@ void LLFloaterSnapshot::Impl::onClickAutoSnap(LLUICtrl *ctrl, void* data)
 	}
 }
 
+void LLFloaterSnapshot::Impl::onClickMore(void* data)
+{
+	//floater->childSetVisible("more_btn", FALSE);
+	//floater->childSetVisible("less_btn", TRUE);
+
+	gSavedSettings.setBOOL( "AdvanceSnapshot", TRUE );
+	
+	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;		
+	if (view)
+	{
+		view->translate( 0, -230 );
+		view->reshape(view->getRect().getWidth(), 526);
+
+		updateControls(view) ;
+		updateLayout(view) ;
+	}
+}
+void LLFloaterSnapshot::Impl::onClickLess(void* data)
+{
+	//floater->childSetVisible("less_btn", FALSE);
+	//floater->childSetVisible("more_btn", TRUE);
+
+	gSavedSettings.setBOOL( "AdvanceSnapshot", FALSE );
+	
+	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;		
+	if (view)
+	{
+		view->translate( 0, 230 );
+		view->reshape(view->getRect().getWidth(), 294);
+
+		updateControls(view) ;
+		updateLayout(view) ;
+	}
+}
+
+//void LLFloaterSnapshot::Impl::onClickAdvanceSnap(LLUICtrl *ctrl, void* data)
+//{
+//	LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
+//	gSavedSettings.setBOOL( "AdvanceSnapshot", check->get() );
+//	
+//	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;		
+//	if (view)
+//	{
+//		S32 delta_height = gSavedSettings.getBOOL("AdvanceSnapshot") ? 0 : -230 ;
+//
+//		view->translate( 0, delta_height ? 230 : -230 );
+//		view->reshape(view->getRect().getWidth(), 526 + delta_height);
+//
+//		updateControls(view) ;
+//		updateLayout(view) ;
+//	}
+//}
+
 // static
 void LLFloaterSnapshot::Impl::onClickUICheck(LLUICtrl *ctrl, void* data)
 {
@@ -1069,7 +1237,31 @@ void LLFloaterSnapshot::Impl::onClickKeepAspectCheck(LLUICtrl* ctrl, void* data)
 	LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
 	if (view)
 	{
-		checkAutoSnapshot(getPreviewView(view));
+		LLSnapshotLivePreview* previewp = getPreviewView(view) ;
+		if(previewp)
+		{
+			previewp->mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
+
+			S32 w, h ;
+			previewp->getSize(w, h) ;
+			checkImageSize(previewp, w, h, TRUE, previewp->getMaxImageSize()) ;
+			previewp->setSize(w, h) ;
+
+			//update textbox
+			LLSpinCtrl *sctrl = LLViewerUICtrlFactory::getSpinnerByName(view, "snapshot_width") ;
+			if(sctrl)
+			{
+				sctrl->setValue(w) ;
+			}
+
+			sctrl = LLViewerUICtrlFactory::getSpinnerByName(view, "snapshot_height") ;
+			if(sctrl)
+			{
+				sctrl->setValue(h) ;
+			}
+
+			checkAutoSnapshot(previewp);
+		}
 	}
 }
 
@@ -1103,6 +1295,48 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)
 	updateLayout(view);
 }
 
+// static
+void LLFloaterSnapshot::Impl::checkAspectRatio(LLFloaterSnapshot *view, S32 index)
+{
+	LLSnapshotLivePreview *previewp = getPreviewView(view) ;
+	
+	if(!index) //current window size
+	{
+		sAspectRatioCheckOff = TRUE ;
+		view->childSetEnabled("keep_aspect_check", FALSE) ;
+
+		if(previewp)
+		{
+			previewp->mKeepAspectRatio = TRUE ;
+		}
+	}
+	else if(-1 == index) //custom
+	{
+		sAspectRatioCheckOff = FALSE ;
+		if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE != gSavedSettings.getS32("LastSnapshotType"))
+		{
+			view->childSetEnabled("keep_aspect_check", TRUE) ;
+
+			if(previewp)
+			{
+				previewp->mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
+			}
+		}
+	}
+	else
+	{
+		sAspectRatioCheckOff = TRUE ;
+		view->childSetEnabled("keep_aspect_check", FALSE) ;
+
+		if(previewp)
+		{
+			previewp->mKeepAspectRatio = FALSE ;
+		}
+	}
+
+	return ;
+}
+
 // static
 void LLFloaterSnapshot::Impl::onCommitResolution(LLUICtrl* ctrl, void* data)
 {
@@ -1148,7 +1382,12 @@ void LLFloaterSnapshot::Impl::onCommitResolution(LLUICtrl* ctrl, void* data)
 			previewp->setSize(width, height);
 		}
 
+		checkAspectRatio(view, width) ;
+
 		previewp->getSize(width, height);
+		checkImageSize(previewp, width, height, TRUE, previewp->getMaxImageSize()) ;
+		previewp->setSize(width, height);
+
 		view->childSetValue("snapshot_width", width);
 		view->childSetValue("snapshot_height", height);
 		// hide old preview as the aspect ratio could be wrong
@@ -1193,7 +1432,74 @@ void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const s
 	if (combo)
 	{
 		combo->setCurrentByIndex(combo->getItemCount() - 1);
+
+		checkAspectRatio(floater, -1);//combo->getCurrentIndex()) ;
+	}
+}
+
+
+
+//static
+void LLFloaterSnapshot::Impl::checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value)
+{
+	//if texture, ignore aspect ratio setting, round image size to power of 2.
+	if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE == gSavedSettings.getS32("LastSnapshotType"))
+	{
+		if(width > max_value)
+		{
+			width = max_value ;
+		}
+		if(height > max_value)
+		{
+			height = max_value ;
+		}
+
+		//round to nearest power of 2
+		width = get_nearest_power_two(width, MAX_TEXTURE_SIZE) ;
+		height = get_nearest_power_two(height, MAX_TEXTURE_SIZE) ;
+
+		return ;
 	}
+
+	if(previewp && previewp->mKeepAspectRatio)
+	{
+		if(gViewerWindow->getWindowDisplayWidth() < 1 || gViewerWindow->getWindowDisplayHeight() < 1)
+		{
+			return ;
+		}
+
+		//aspect ratio of the current window
+		F32 aspect_ratio = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight() ;
+
+		//change another value proportionally
+		if(isWidthChanged)
+		{
+			height = (S32)(width / aspect_ratio) ;
+		}
+		else
+		{
+			width = (S32)(height * aspect_ratio) ;
+		}
+
+		//bound w/h by the max_value
+		if(width > max_value || height > max_value)
+		{
+			if(width > height)
+			{
+				width = max_value ;
+				height = (S32)(width / aspect_ratio) ;
+			}
+			else
+			{
+				height = max_value ;
+				width = (S32)(height * aspect_ratio) ;
+			}
+		}
+	}
+	else
+	{
+	}
+	return ;
 }
 
 //static
@@ -1216,6 +1522,33 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat
 			
 			if (w != curw || h != curh)
 			{
+				S32 width = w ;
+				S32 height = h ;
+				
+				previewp->setMaxImageSize((S32)((LLSpinCtrl *)ctrl)->getMaxValue()) ;
+				checkImageSize(previewp, width, height, width != curw, previewp->getMaxImageSize()) ;
+
+				if(width != w || height != h)
+				{
+					LLSpinCtrl *sctrl = LLViewerUICtrlFactory::getSpinnerByName(view, "snapshot_width") ;
+					if(sctrl)
+					{
+						sctrl->setValue(width) ;
+					}
+
+					sctrl = LLViewerUICtrlFactory::getSpinnerByName(view, "snapshot_height") ;
+					if(sctrl)
+					{
+						sctrl->setValue(height) ;
+					}
+
+					w = width ;
+					h = height ;
+
+					gSavedSettings.setS32("LastSnapshotWidth", w);
+					gSavedSettings.setS32("LastSnapshotHeight", h);
+				}
+
 				previewp->setSize(w,h);
 				checkAutoSnapshot(previewp);
 				comboSetCustom(view, "postcard_size_combo");
@@ -1269,7 +1602,12 @@ BOOL LLFloaterSnapshot::postBuild()
 
 	childSetValue("auto_snapshot_check", gSavedSettings.getBOOL("AutoSnapshot"));
 	childSetCommitCallback("auto_snapshot_check", Impl::onClickAutoSnap, this);
-	
+
+	//childSetValue("advance_snapshot_check", gSavedSettings.getBOOL("AdvanceSnapshot"));
+	//childSetCommitCallback("advance_snapshot_check", Impl::onClickAdvanceSnap, this);
+	childSetAction("more_btn", Impl::onClickMore, this);
+	childSetAction("less_btn", Impl::onClickLess, this);
+
 	childSetAction("upload_btn", Impl::onClickKeep, this);
 	childSetAction("send_btn", Impl::onClickKeep, this);
 	childSetAction("save_btn", Impl::onClickKeep, this);
@@ -1354,7 +1692,7 @@ void LLFloaterSnapshot::draw()
 			if (previewp->getSnapshotUpToDate())
 			{
 				LLString bytes_string;
-				gResMgr->getIntegerString(bytes_string, previewp->getDataSize());
+				gResMgr->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
 				childSetTextArg("file_size_label", "[SIZE]", bytes_string);
 			}
 			else
@@ -1382,7 +1720,7 @@ void LLFloaterSnapshot::draw()
 	LLFloater::draw();
 
 	// draw snapshot thumbnail if not in fullscreen preview mode
-	if (!gSavedSettings.getBOOL("UseFreezeFrame") && previewp && previewp->getCurrentImage() && previewp->getSnapshotUpToDate())
+	if (/*!gSavedSettings.getBOOL("UseFreezeFrame") &&*/ previewp && previewp->getCurrentImage() && previewp->getSnapshotUpToDate())
 	{
 		F32 aspect = previewp->getImageAspect();
 		// UI size for thumbnail
@@ -1414,7 +1752,7 @@ void LLFloaterSnapshot::draw()
 				glScalef(llmin(1.f, (F32)image_width / (F32)previewp->getCurrentImage()->getWidth()), llmin(1.f, (F32)image_height / (F32)previewp->getCurrentImage()->getHeight()), 1.f);
 			}
 			glMatrixMode(GL_MODELVIEW);
-			gl_draw_scaled_image((getRect().getWidth() - img_render_width) / 2, 35 + (max_height - img_render_height) / 2, img_render_width, img_render_height, previewp->getCurrentImage(), LLColor4::white);
+			gl_draw_scaled_image((getRect().getWidth() - img_render_width) / 2, getRect().getHeight() - 205 + (max_height - img_render_height) / 2, img_render_width, img_render_height, previewp->getCurrentImage(), LLColor4::white);
 		}
 		glMatrixMode(GL_TEXTURE);
 		glPopMatrix();
diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp
new file mode 100644
index 00000000000..0b02ea26231
--- /dev/null
+++ b/indra/newview/llfloaterwater.cpp
@@ -0,0 +1,735 @@
+/** 
+ * @file llfloaterwater.cpp
+ * @brief LLFloaterWater class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterwater.h"
+
+#include "pipeline.h"
+#include "llsky.h"
+
+#include "llsliderctrl.h"
+#include "llspinctrl.h"
+#include "llcolorswatch.h"
+#include "llcheckboxctrl.h"
+#include "lltexturectrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewercamera.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llfloaterdaycycle.h"
+#include "llboost.h"
+
+#include "v4math.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "llsavedsettingsglue.h"
+
+#include "llwaterparamset.h"
+#include "llwaterparammanager.h"
+#include "llpostprocess.h"
+
+#undef max
+
+LLFloaterWater* LLFloaterWater::sWaterMenu = NULL;
+
+std::set<std::string> LLFloaterWater::sDefaultPresets;
+
+LLFloaterWater::LLFloaterWater() : LLFloater("water floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_water.xml");
+	
+	// add the combo boxes
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "WaterPresetsCombo");
+
+	if(comboBox != NULL) {
+		
+		std::map<std::string, LLWaterParamSet>::iterator mIt = 
+			LLWaterParamManager::instance()->mParamList.begin();
+		for(; mIt != LLWaterParamManager::instance()->mParamList.end(); mIt++) 
+		{
+			comboBox->add(mIt->first);
+		}
+
+		// set defaults on combo boxes
+		comboBox->selectByValue(LLSD("Default"));
+	}
+
+	LLString def_water = getString("WLDefaultWaterNames");
+
+	// no editing or deleting of the blank string
+	sDefaultPresets.insert("");
+	boost_tokenizer tokens(def_water, boost::char_separator<char>(":"));
+	for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+	{
+		LLString tok(*token_iter);
+		sDefaultPresets.insert(tok);
+	}
+
+	// load it up
+	initCallbacks();
+}
+
+LLFloaterWater::~LLFloaterWater()
+{
+}
+
+void LLFloaterWater::initCallbacks(void) {
+
+	// help buttons
+	initHelpBtn("WaterFogColorHelp", "HelpWaterFogColor");
+	initHelpBtn("WaterFogDensityHelp", "HelpWaterFogDensity");
+	initHelpBtn("WaterUnderWaterFogModHelp", "HelpUnderWaterFogMod");
+	initHelpBtn("WaterGlowHelp", "HelpWaterGlow");	
+	initHelpBtn("WaterNormalScaleHelp", "HelpWaterNormalScale");
+	initHelpBtn("WaterFresnelScaleHelp", "HelpWaterFresnelScale");
+	initHelpBtn("WaterFresnelOffsetHelp", "HelpWaterFresnelOffset");
+
+	initHelpBtn("WaterBlurMultiplierHelp", "HelpWaterBlurMultiplier");
+	initHelpBtn("WaterScaleBelowHelp", "HelpWaterScaleBelow");
+	initHelpBtn("WaterScaleAboveHelp", "HelpWaterScaleAbove");
+
+	initHelpBtn("WaterNormalMapHelp", "HelpWaterNormalMap");
+	initHelpBtn("WaterWave1Help", "HelpWaterWave1");
+	initHelpBtn("WaterWave2Help", "HelpWaterWave2");
+
+	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+
+	childSetCommitCallback("WaterFogColor", onWaterFogColorMoved, &param_mgr->mFogColor);
+
+	// 
+	childSetCommitCallback("WaterGlow", onColorControlAMoved, &param_mgr->mFogColor);
+
+	// fog density
+	childSetCommitCallback("WaterFogDensity", onExpFloatControlMoved, &param_mgr->mFogDensity);
+	childSetCommitCallback("WaterUnderWaterFogMod", onFloatControlMoved, &param_mgr->mUnderWaterFogMod);
+
+	// blue density
+	childSetCommitCallback("WaterNormalScaleX", onVector3ControlXMoved, &param_mgr->mNormalScale);
+	childSetCommitCallback("WaterNormalScaleY", onVector3ControlYMoved, &param_mgr->mNormalScale);
+	childSetCommitCallback("WaterNormalScaleZ", onVector3ControlZMoved, &param_mgr->mNormalScale);
+
+	// fresnel
+	childSetCommitCallback("WaterFresnelScale", onFloatControlMoved, &param_mgr->mFresnelScale);
+	childSetCommitCallback("WaterFresnelOffset", onFloatControlMoved, &param_mgr->mFresnelOffset);
+
+	// scale above/below
+	childSetCommitCallback("WaterScaleAbove", onFloatControlMoved, &param_mgr->mScaleAbove);
+	childSetCommitCallback("WaterScaleBelow", onFloatControlMoved, &param_mgr->mScaleBelow);
+
+	// blur mult
+	childSetCommitCallback("WaterBlurMult", onFloatControlMoved, &param_mgr->mBlurMultiplier);
+
+	// Load/save
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "WaterPresetsCombo");
+
+	//childSetAction("WaterLoadPreset", onLoadPreset, comboBox);
+	childSetAction("WaterNewPreset", onNewPreset, comboBox);
+	childSetAction("WaterSavePreset", onSavePreset, comboBox);
+	childSetAction("WaterDeletePreset", onDeletePreset, comboBox);
+
+	// wave direction
+	childSetCommitCallback("WaterWave1DirX", onVector2ControlXMoved, &param_mgr->mWave1Dir);
+	childSetCommitCallback("WaterWave1DirY", onVector2ControlYMoved, &param_mgr->mWave1Dir);
+	childSetCommitCallback("WaterWave2DirX", onVector2ControlXMoved, &param_mgr->mWave2Dir);
+	childSetCommitCallback("WaterWave2DirY", onVector2ControlYMoved, &param_mgr->mWave2Dir);
+
+	comboBox->setCommitCallback(onChangePresetName);
+
+	LLTextureCtrl* textCtrl = getChild<LLTextureCtrl>("WaterNormalMap");
+	textCtrl->setDefaultImageAssetID(LLUUID(gViewerArt.getString("water_normal.tga")));
+	childSetCommitCallback("WaterNormalMap", onNormalMapPicked, NULL);	
+}
+
+void LLFloaterWater::onClickHelp(void* data)
+{
+	LLFloaterWater* self = LLFloaterWater::instance();
+
+	const char* xml_alert = (const char*) data;
+	LLAlertDialog* dialogp = gViewerWindow->alertXml(xml_alert);
+	if (dialogp)
+	{
+		LLFloater* root_floater = gFloaterView->getParentFloater(self);
+		if (root_floater)
+		{
+			root_floater->addDependentFloater(dialogp);
+		}
+	}
+}
+
+void LLFloaterWater::initHelpBtn(const char* name, const char* xml_alert)
+{
+	childSetAction(name, onClickHelp, (void*)xml_alert);
+}
+
+void LLFloaterWater::newPromptCallback(S32 option, const LLString& text, void* userData)
+{
+	if(text == "")
+	{
+		return;
+	}
+
+	if(option == 0) {
+		LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sWaterMenu, 
+			"WaterPresetsCombo");
+
+		LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+
+		// add the current parameters to the list
+		// see if it's there first
+		std::map<std::string, LLWaterParamSet>::iterator mIt = 
+			param_mgr->mParamList.find(text.c_str());
+
+		// if not there, add a new one
+		if(mIt == param_mgr->mParamList.end()) 
+		{
+			param_mgr->addParamSet(text.c_str(), 
+				param_mgr->mCurParams);
+			comboBox->add(text);
+			comboBox->sortByName();
+
+			comboBox->setSelectedByValue(text, true);
+
+			param_mgr->savePreset(text);
+
+		// otherwise, send a message to the user
+		} 
+		else 
+		{
+			gViewerWindow->alertXml("ExistsWaterPresetAlert");
+		}
+	}
+}
+
+void LLFloaterWater::syncMenu()
+{
+	bool err;
+
+	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+
+	LLWaterParamSet & current_params = param_mgr->mCurParams;
+
+	// blue horizon
+	param_mgr->mFogColor = current_params.getVector4(param_mgr->mFogColor.mName, err);
+
+	LLColor4 col = param_mgr->getFogColor();
+	childSetValue("WaterGlow", col.mV[3]);
+	col.mV[3] = 1.0f;
+	LLColorSwatchCtrl* colCtrl = sWaterMenu->getChild<LLColorSwatchCtrl>("WaterFogColor");
+
+	colCtrl->set(col);
+
+	// fog and wavelets
+	param_mgr->mFogDensity.mExp = 
+		log(current_params.getFloat(param_mgr->mFogDensity.mName, err)) / 
+		log(param_mgr->mFogDensity.mBase);
+	param_mgr->setDensitySliderValue(param_mgr->mFogDensity.mExp);
+	childSetValue("WaterFogDensity", param_mgr->mFogDensity.mExp);
+	
+	param_mgr->mUnderWaterFogMod.mX = 
+		current_params.getFloat(param_mgr->mUnderWaterFogMod.mName, err);
+	childSetValue("WaterUnderWaterFogMod", param_mgr->mUnderWaterFogMod.mX);
+
+	param_mgr->mNormalScale = current_params.getVector3(param_mgr->mNormalScale.mName, err);
+	childSetValue("WaterNormalScaleX", param_mgr->mNormalScale.mX);
+	childSetValue("WaterNormalScaleY", param_mgr->mNormalScale.mY);
+	childSetValue("WaterNormalScaleZ", param_mgr->mNormalScale.mZ);
+
+	// Fresnel
+	param_mgr->mFresnelScale.mX = current_params.getFloat(param_mgr->mFresnelScale.mName, err);
+	childSetValue("WaterFresnelScale", param_mgr->mFresnelScale.mX);
+	param_mgr->mFresnelOffset.mX = current_params.getFloat(param_mgr->mFresnelOffset.mName, err);
+	childSetValue("WaterFresnelOffset", param_mgr->mFresnelOffset.mX);
+
+	// Scale Above/Below
+	param_mgr->mScaleAbove.mX = current_params.getFloat(param_mgr->mScaleAbove.mName, err);
+	childSetValue("WaterScaleAbove", param_mgr->mScaleAbove.mX);
+	param_mgr->mScaleBelow.mX = current_params.getFloat(param_mgr->mScaleBelow.mName, err);
+	childSetValue("WaterScaleBelow", param_mgr->mScaleBelow.mX);
+
+	// blur mult
+	param_mgr->mBlurMultiplier.mX = current_params.getFloat(param_mgr->mBlurMultiplier.mName, err);
+	childSetValue("WaterBlurMult", param_mgr->mBlurMultiplier.mX);
+
+	// wave directions
+	param_mgr->mWave1Dir = current_params.getVector2(param_mgr->mWave1Dir.mName, err);
+	childSetValue("WaterWave1DirX", param_mgr->mWave1Dir.mX);
+	childSetValue("WaterWave1DirY", param_mgr->mWave1Dir.mY);
+
+	param_mgr->mWave2Dir = current_params.getVector2(param_mgr->mWave2Dir.mName, err);
+	childSetValue("WaterWave2DirX", param_mgr->mWave2Dir.mX);
+	childSetValue("WaterWave2DirY", param_mgr->mWave2Dir.mY);
+
+	LLTextureCtrl* textCtrl = sWaterMenu->getChild<LLTextureCtrl>("WaterNormalMap");
+	textCtrl->setImageAssetID(param_mgr->getNormalMapID());
+}
+
+
+// static
+LLFloaterWater* LLFloaterWater::instance()
+{
+	if (!sWaterMenu)
+	{
+		sWaterMenu = new LLFloaterWater();
+		sWaterMenu->open();
+		sWaterMenu->setFocus(TRUE);
+	}
+	return sWaterMenu;
+}
+void LLFloaterWater::show()
+{
+	LLFloaterWater* water = instance();
+	water->syncMenu();
+
+	// comment in if you want the menu to rebuild each time
+	//gUICtrlFactory->buildFloater(water, "floater_water.xml");
+	//water->initCallbacks();
+
+	water->open();
+}
+
+bool LLFloaterWater::isOpen()
+{
+	if (sWaterMenu != NULL) {
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterWater::onClose(bool app_quitting)
+{
+	if (sWaterMenu)
+	{
+		sWaterMenu->setVisible(FALSE);
+	}
+}
+
+// vector control callbacks
+void LLFloaterWater::onVector3ControlXMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterVector3Control * vectorControl = static_cast<WaterVector3Control *>(userData);
+
+	vectorControl->mX = sldrCtrl->getValueF32();
+
+	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+// vector control callbacks
+void LLFloaterWater::onVector3ControlYMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterVector3Control * vectorControl = static_cast<WaterVector3Control *>(userData);
+
+	vectorControl->mY = sldrCtrl->getValueF32();
+
+	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+// vector control callbacks
+void LLFloaterWater::onVector3ControlZMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterVector3Control * vectorControl = static_cast<WaterVector3Control *>(userData);
+
+	vectorControl->mZ = sldrCtrl->getValueF32();
+
+	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+
+// vector control callbacks
+void LLFloaterWater::onVector2ControlXMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterVector2Control * vectorControl = static_cast<WaterVector2Control *>(userData);
+
+	vectorControl->mX = sldrCtrl->getValueF32();
+
+	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+// vector control callbacks
+void LLFloaterWater::onVector2ControlYMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterVector2Control * vectorControl = static_cast<WaterVector2Control *>(userData);
+
+	vectorControl->mY = sldrCtrl->getValueF32();
+
+	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+// color control callbacks
+void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);
+
+	colorControl->mR = sldrCtrl->getValueF32();
+
+	// move i if it's the max
+	if(colorControl->mR >= colorControl->mG 
+		&& colorControl->mR >= colorControl->mB 
+		&& colorControl->mHasSliderName)
+	{
+		colorControl->mI = colorControl->mR;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+		
+		sWaterMenu->childSetValue(name, colorControl->mR);
+	}
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);
+
+	colorControl->mG = sldrCtrl->getValueF32();
+
+	// move i if it's the max
+	if(colorControl->mG >= colorControl->mR 
+		&& colorControl->mG >= colorControl->mB
+		&& colorControl->mHasSliderName)
+	{
+		colorControl->mI = colorControl->mG;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+
+		sWaterMenu->childSetValue(name, colorControl->mG);
+
+	}
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);
+
+	colorControl->mB = sldrCtrl->getValueF32();
+
+	// move i if it's the max
+	if(colorControl->mB >= colorControl->mR
+		&& colorControl->mB >= colorControl->mG
+		&& colorControl->mHasSliderName)
+	{
+		colorControl->mI = colorControl->mB;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+
+		sWaterMenu->childSetValue(name, colorControl->mB);
+	}
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);
+
+	colorControl->mA = sldrCtrl->getValueF32();
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+
+void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);
+
+	colorControl->mI = sldrCtrl->getValueF32();
+	
+	// only for sliders where we pass a name
+	if(colorControl->mHasSliderName) 
+	{
+		// set it to the top
+		F32 maxVal = std::max(std::max(colorControl->mR, colorControl->mG), colorControl->mB);
+		F32 iVal;
+
+		iVal = colorControl->mI;
+
+		// get the names of the other sliders
+		std::string rName = colorControl->mSliderName;
+		rName.append("R");
+		std::string gName = colorControl->mSliderName;
+		gName.append("G");
+		std::string bName = colorControl->mSliderName;
+		bName.append("B");
+
+		// handle if at 0
+		if(iVal == 0)
+		{
+			colorControl->mR = 0;
+			colorControl->mG = 0;
+			colorControl->mB = 0;
+		
+		// if all at the start
+		// set them all to the intensity
+		}
+		else if (maxVal == 0)
+		{
+			colorControl->mR = iVal;
+			colorControl->mG = iVal;
+			colorControl->mB = iVal;
+		}
+		else
+		{
+			// add delta amounts to each
+			F32 delta = (iVal - maxVal) / maxVal;
+			colorControl->mR *= (1.0f + delta);
+			colorControl->mG *= (1.0f + delta);
+			colorControl->mB *= (1.0f + delta);
+		}
+
+		// set the sliders to the new vals
+		sWaterMenu->childSetValue(rName.c_str(), colorControl->mR);
+		sWaterMenu->childSetValue(gName.c_str(), colorControl->mG);
+		sWaterMenu->childSetValue(bName.c_str(), colorControl->mB);
+	}
+
+	// now update the current parameters and send them to shaders
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterExpFloatControl * expFloatControl = static_cast<WaterExpFloatControl *>(userData);
+
+	F32 val = sldrCtrl->getValueF32();
+	expFloatControl->mExp = val;
+	LLWaterParamManager::instance()->setDensitySliderValue(val);
+
+	expFloatControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onFloatControlMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WaterFloatControl * floatControl = static_cast<WaterFloatControl *>(userData);
+
+	floatControl->mX = sldrCtrl->getValueF32() / floatControl->mMult;
+
+	floatControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+void LLFloaterWater::onWaterFogColorMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);	
+	*colorControl = swatch->get();
+
+	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	LLWaterParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWater::onBoolToggle(LLUICtrl* ctrl, void* userData)
+{
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+
+	bool value = cbCtrl->get();
+	(*(static_cast<BOOL *>(userData))) = value;
+}
+
+void LLFloaterWater::onNormalMapPicked(LLUICtrl* ctrl, void* userData)
+{
+	LLTextureCtrl* textCtrl = static_cast<LLTextureCtrl*>(ctrl);
+	LLUUID textID = textCtrl->getImageAssetID();
+	LLWaterParamManager::instance()->setNormalMapID(textID);
+}
+
+void LLFloaterWater::onNewPreset(void* userData)
+{
+	gViewerWindow->alertXmlEditText("NewWaterPreset", LLString::format_map_t(), 
+		NULL, NULL, newPromptCallback, NULL);
+}
+
+void LLFloaterWater::onSavePreset(void* userData)
+{
+	// get the name
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sWaterMenu, 
+		"WaterPresetsCombo");
+
+	// don't save the empty name
+	if(comboBox->getSelectedItemLabel() == "")
+	{
+		return;
+	}
+
+	LLWaterParamManager::instance()->mCurParams.mName = 
+		comboBox->getSelectedItemLabel();
+
+	// check to see if it's a default and shouldn't be overwritten
+	std::set<std::string>::iterator sIt = sDefaultPresets.find(
+		comboBox->getSelectedItemLabel().c_str());
+	if(sIt != sDefaultPresets.end() && !gSavedSettings.getBOOL("WaterEditPresets")) 
+	{
+		gViewerWindow->alertXml("WLNoEditDefault");
+		return;
+	}
+
+	gViewerWindow->alertXml("WLSavePresetAlert", saveAlertCallback, sWaterMenu);
+}
+
+void LLFloaterWater::saveAlertCallback(S32 option, void* userdata)
+{
+	// if they choose save, do it.  Otherwise, don't do anything
+	if(option == 0) 
+	{
+		LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+
+		param_mgr->setParamSet(
+			param_mgr->mCurParams.mName, 
+			param_mgr->mCurParams);
+
+		// comment this back in to save to file
+		param_mgr->savePreset(param_mgr->mCurParams.mName);
+	}
+
+}
+
+void LLFloaterWater::onDeletePreset(void* userData)
+{
+	LLComboBox* combo_box = LLUICtrlFactory::getComboBoxByName(sWaterMenu, 
+		"WaterPresetsCombo");
+
+	if(combo_box->getSelectedValue().asString() == "")
+	{
+		return;
+	}
+
+	LLString::format_map_t args;
+	args["[SKY]"] = combo_box->getSelectedValue().asString();
+	gViewerWindow->alertXml("WLDeletePresetAlert", args, deleteAlertCallback, sWaterMenu);
+}
+
+void LLFloaterWater::deleteAlertCallback(S32 option, void* userdata)
+{
+	// if they choose delete, do it.  Otherwise, don't do anything
+	if(option == 0) 
+	{
+		LLComboBox* combo_box = LLUICtrlFactory::getComboBoxByName(sWaterMenu, 
+			"WaterPresetsCombo");
+		LLFloaterDayCycle* day_cycle = NULL;
+		LLComboBox* key_combo = NULL;
+		LLMultiSliderCtrl* mult_sldr = NULL;
+
+		if(LLFloaterDayCycle::isOpen()) 
+		{
+			day_cycle = LLFloaterDayCycle::instance();
+			key_combo = LLUICtrlFactory::getComboBoxByName(day_cycle, 
+				"WaterKeyPresets");
+			mult_sldr = LLUICtrlFactory::getMultiSliderByName(day_cycle, 
+				"WaterDayCycleKeys");
+		}
+
+		LLString name = combo_box->getSelectedValue().asString();
+
+		// check to see if it's a default and shouldn't be deleted
+		std::set<std::string>::iterator sIt = sDefaultPresets.find(name.c_str());
+		if(sIt != sDefaultPresets.end()) 
+		{
+			gViewerWindow->alertXml("WaterNoEditDefault");
+			return;
+		}
+
+		LLWaterParamManager::instance()->removeParamSet(name, true);
+		
+		// remove and choose another
+		S32 new_index = combo_box->getCurrentIndex();
+
+		combo_box->remove(name);
+
+		if(key_combo != NULL) 
+		{
+			key_combo->remove(name);
+
+			// remove from slider, as well
+			day_cycle->deletePreset(name);
+		}
+
+		// pick the previously selected index after delete
+		if(new_index > 0) 
+		{
+			new_index--;
+		}
+		
+		if(combo_box->getItemCount() > 0) 
+		{
+			combo_box->setCurrentByIndex(new_index);
+		}
+	}
+}
+
+
+void LLFloaterWater::onChangePresetName(LLUICtrl* ctrl, void * userData)
+{
+	LLComboBox * combo_box = static_cast<LLComboBox*>(ctrl);
+	
+	if(combo_box->getSimple() == "")
+	{
+		return;
+	}
+	
+	LLWaterParamManager::instance()->loadPreset(
+		combo_box->getSelectedValue().asString());
+	sWaterMenu->syncMenu();
+}
+
diff --git a/indra/newview/llfloaterwater.h b/indra/newview/llfloaterwater.h
new file mode 100644
index 00000000000..311ef9a75e1
--- /dev/null
+++ b/indra/newview/llfloaterwater.h
@@ -0,0 +1,133 @@
+/** 
+ * @file llfloaterwindlight.h
+ * @brief LLFloaterWater class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/*
+ * Menu for adjusting the atmospheric settings of the world
+ */
+
+#ifndef LL_LLFLOATER_WATER_H
+#define LL_LLFLOATER_WATER_H
+
+#include "llfloater.h"
+
+#include <vector>
+#include "llwlparamset.h"
+
+struct WaterColorControl;
+struct WaterloatControl;
+
+
+/// Menuing system for all of windlight's functionality
+class LLFloaterWater : public LLFloater
+{
+public:
+
+	LLFloaterWater();
+	virtual ~LLFloaterWater();
+	
+	/// initialize all
+	void initCallbacks(void);
+
+	/// one and one instance only
+	static LLFloaterWater* instance();
+
+	// help button stuff
+	static void onClickHelp(void* data);
+	void initHelpBtn(const char* name, const char* xml_alert);
+
+	static void newPromptCallback(S32 option, const LLString& text, void* userData);
+
+	/// general purpose callbacks for dealing with color controllers
+	static void onColorControlRMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlGMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlBMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlAMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlIMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onVector3ControlXMoved(LLUICtrl* ctrl, void* userData);
+	static void onVector3ControlYMoved(LLUICtrl* ctrl, void* userData);
+	static void onVector3ControlZMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onVector2ControlXMoved(LLUICtrl* ctrl, void* userData);
+	static void onVector2ControlYMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onFloatControlMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onExpFloatControlMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onWaterFogColorMoved(LLUICtrl* ctrl, void* userData);
+
+	static void onBoolToggle(LLUICtrl* ctrl, void* userData);
+
+	/// handle if they choose a new normal map
+	static void onNormalMapPicked(LLUICtrl* ctrl, void* userData);
+
+	/// when user hits the load preset button
+	static void onNewPreset(void* userData);
+
+	/// when user hits the save preset button
+	static void onSavePreset(void* userData);
+
+	/// prompts a user when overwriting a preset
+	static void saveAlertCallback(S32 option, void* userdata);
+
+	/// when user hits the save preset button
+	static void onDeletePreset(void* userData);
+
+	/// prompts a user when overwriting a preset
+	static void deleteAlertCallback(S32 option, void* userdata);
+
+	/// what to do when you change the preset name
+	static void onChangePresetName(LLUICtrl* ctrl, void* userData);
+
+	//// menu management
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up sliders with parameters
+	void syncMenu();
+
+private:
+	// one instance on the inside
+	static LLFloaterWater* sWaterMenu;
+
+	static std::set<std::string> sDefaultPresets;
+};
+
+
+#endif
diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp
new file mode 100644
index 00000000000..2627ea37056
--- /dev/null
+++ b/indra/newview/llfloaterwindlight.cpp
@@ -0,0 +1,998 @@
+/** 
+ * @file llfloaterwindlight.cpp
+ * @brief LLFloaterWindLight class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterwindlight.h"
+
+#include "pipeline.h"
+#include "llsky.h"
+
+#include "llsliderctrl.h"
+#include "llmultislider.h"
+#include "llmultisliderctrl.h"
+#include "llspinctrl.h"
+#include "llcheckboxctrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewercamera.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llfloaterdaycycle.h"
+#include "llboost.h"
+
+#include "v4math.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "llsavedsettingsglue.h"
+
+#include "llwlparamset.h"
+#include "llwlparammanager.h"
+#include "llpostprocess.h"
+
+#undef max
+
+LLFloaterWindLight* LLFloaterWindLight::sWindLight = NULL;
+
+std::set<std::string> LLFloaterWindLight::sDefaultPresets;
+
+static const F32 WL_SUN_AMBIENT_SLIDER_SCALE = 3.0f;
+
+LLFloaterWindLight::LLFloaterWindLight() : LLFloater("windlight floater")
+{
+	gUICtrlFactory->buildFloater(this, "floater_windlight_options.xml");
+	
+	// add the combo boxes
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "WLPresetsCombo");
+
+	if(comboBox != NULL) {
+		
+		std::map<std::string, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::instance()->mParamList.begin();
+		for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) 
+		{
+			comboBox->add(mIt->first);
+		}
+
+		// entry for when we're in estate time
+		comboBox->add("");
+
+		// set defaults on combo boxes
+		comboBox->selectByValue(LLSD("Default"));
+	}
+
+	// add the list of presets
+	LLString def_days = getString("WLDefaultSkyNames");
+
+	// no editing or deleting of the blank string
+	sDefaultPresets.insert("");
+	boost_tokenizer tokens(def_days, boost::char_separator<char>(":"));
+	for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+	{
+		LLString tok(*token_iter);
+		sDefaultPresets.insert(tok);
+	}
+
+	// load it up
+	initCallbacks();
+}
+
+LLFloaterWindLight::~LLFloaterWindLight()
+{
+}
+
+void LLFloaterWindLight::initCallbacks(void) {
+
+	// help buttons
+	initHelpBtn("WLBlueHorizonHelp", "HelpBlueHorizon");
+	initHelpBtn("WLHazeHorizonHelp", "HelpHazeHorizon");
+	initHelpBtn("WLBlueDensityHelp", "HelpBlueDensity");
+	initHelpBtn("WLHazeDensityHelp", "HelpHazeDensity");
+
+	initHelpBtn("WLDensityMultHelp", "HelpDensityMult");
+	initHelpBtn("WLDistanceMultHelp", "HelpDistanceMult");
+	initHelpBtn("WLMaxAltitudeHelp", "HelpMaxAltitude");
+
+	initHelpBtn("WLSunlightColorHelp", "HelpSunlightColor");
+	initHelpBtn("WLAmbientHelp", "HelpSunAmbient");
+	initHelpBtn("WLSunGlowHelp", "HelpSunGlow");
+	initHelpBtn("WLTimeOfDayHelp", "HelpTimeOfDay");
+	initHelpBtn("WLEastAngleHelp", "HelpEastAngle");
+
+	initHelpBtn("WLSceneGammaHelp", "HelpSceneGamma");
+	initHelpBtn("WLStarBrightnessHelp", "HelpStarBrightness");
+
+	initHelpBtn("WLCloudColorHelp", "HelpCloudColor");
+	initHelpBtn("WLCloudDetailHelp", "HelpCloudDetail");
+	initHelpBtn("WLCloudDensityHelp", "HelpCloudDensity");
+	initHelpBtn("WLCloudCoverageHelp", "HelpCloudCoverage");
+
+	initHelpBtn("WLCloudScaleHelp", "HelpCloudScale");
+	initHelpBtn("WLCloudScrollXHelp", "HelpCloudScrollX");
+	initHelpBtn("WLCloudScrollYHelp", "HelpCloudScrollY");
+
+	initHelpBtn("WLClassicCloudsHelp", "HelpClassicClouds");
+
+	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+
+	// blue horizon
+	childSetCommitCallback("WLBlueHorizonR", onColorControlRMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonG", onColorControlGMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonB", onColorControlBMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonI", onColorControlIMoved, &param_mgr->mBlueHorizon);
+
+	// haze density, horizon, mult, and altitude
+	childSetCommitCallback("WLHazeDensity", onColorControlRMoved, &param_mgr->mHazeDensity);
+	childSetCommitCallback("WLHazeHorizon", onColorControlRMoved, &param_mgr->mHazeHorizon);
+	childSetCommitCallback("WLDensityMult", onFloatControlMoved, &param_mgr->mDensityMult);
+	childSetCommitCallback("WLMaxAltitude", onFloatControlMoved, &param_mgr->mMaxAlt);
+
+	// blue density
+	childSetCommitCallback("WLBlueDensityR", onColorControlRMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityG", onColorControlGMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityB", onColorControlBMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityI", onColorControlIMoved, &param_mgr->mBlueDensity);
+
+	// Lighting
+	
+	// sunlight
+	childSetCommitCallback("WLSunlightR", onColorControlRMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightG", onColorControlGMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightB", onColorControlBMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightI", onColorControlIMoved, &param_mgr->mSunlight);
+
+	// glow
+	childSetCommitCallback("WLGlowR", onGlowRMoved, &param_mgr->mGlow);
+	childSetCommitCallback("WLGlowB", onGlowBMoved, &param_mgr->mGlow);
+
+	// ambient
+	childSetCommitCallback("WLAmbientR", onColorControlRMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientG", onColorControlGMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientB", onColorControlBMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientI", onColorControlIMoved, &param_mgr->mAmbient);
+
+	// time of day
+	childSetCommitCallback("WLSunAngle", onSunMoved, &param_mgr->mLightnorm);
+	childSetCommitCallback("WLEastAngle", onSunMoved, &param_mgr->mLightnorm);
+
+	// Clouds
+
+	// Cloud Color
+	childSetCommitCallback("WLCloudColorR", onColorControlRMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorG", onColorControlGMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorB", onColorControlBMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorI", onColorControlIMoved, &param_mgr->mCloudColor);
+
+	// Cloud
+	childSetCommitCallback("WLCloudX", onColorControlRMoved, &param_mgr->mCloudMain);
+	childSetCommitCallback("WLCloudY", onColorControlGMoved, &param_mgr->mCloudMain);
+	childSetCommitCallback("WLCloudDensity", onColorControlBMoved, &param_mgr->mCloudMain);
+
+	// Cloud Detail
+	childSetCommitCallback("WLCloudDetailX", onColorControlRMoved, &param_mgr->mCloudDetail);
+	childSetCommitCallback("WLCloudDetailY", onColorControlGMoved, &param_mgr->mCloudDetail);
+	childSetCommitCallback("WLCloudDetailDensity", onColorControlBMoved, &param_mgr->mCloudDetail);
+
+	// Cloud extras
+	childSetCommitCallback("WLCloudCoverage", onFloatControlMoved, &param_mgr->mCloudCoverage);
+	childSetCommitCallback("WLCloudScale", onFloatControlMoved, &param_mgr->mCloudScale);
+	childSetCommitCallback("WLCloudLockX", onCloudScrollXToggled, NULL);
+	childSetCommitCallback("WLCloudLockY", onCloudScrollYToggled, NULL);
+	childSetCommitCallback("WLCloudScrollX", onCloudScrollXMoved, NULL);
+	childSetCommitCallback("WLCloudScrollY", onCloudScrollYMoved, NULL);
+	childSetCommitCallback("WLDistanceMult", onFloatControlMoved, &param_mgr->mDistanceMult);
+	childSetCommitCallback("DrawClassicClouds", LLSavedSettingsGlue::setBOOL, (void*)"SkyUseClassicClouds");
+
+	// WL Top
+	childSetAction("WLDayCycleMenuButton", onOpenDayCycle, NULL);
+	// Load/save
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(this, "WLPresetsCombo");
+
+	//childSetAction("WLLoadPreset", onLoadPreset, comboBox);
+	childSetAction("WLNewPreset", onNewPreset, comboBox);
+	childSetAction("WLSavePreset", onSavePreset, comboBox);
+	childSetAction("WLDeletePreset", onDeletePreset, comboBox);
+
+	comboBox->setCommitCallback(onChangePresetName);
+
+
+	// Dome
+	childSetCommitCallback("WLGamma", onFloatControlMoved, &param_mgr->mWLGamma);
+	childSetCommitCallback("WLStarAlpha", onStarAlphaMoved, NULL);
+}
+
+void LLFloaterWindLight::onClickHelp(void* data)
+{
+	LLFloaterWindLight* self = LLFloaterWindLight::instance();
+
+	const char* xml_alert = (const char*) data;
+	LLAlertDialog* dialogp = gViewerWindow->alertXml(xml_alert);
+	if (dialogp)
+	{
+		LLFloater* root_floater = gFloaterView->getParentFloater(self);
+		if (root_floater)
+		{
+			root_floater->addDependentFloater(dialogp);
+		}
+	}		
+	
+}
+
+void LLFloaterWindLight::initHelpBtn(const char* name, const char* xml_alert)
+{
+	childSetAction(name, onClickHelp, (void*)xml_alert);
+}
+
+void LLFloaterWindLight::newPromptCallback(S32 option, const LLString& text, void* userData)
+{
+	if(text == "")
+	{
+		return;
+	}
+
+	if(option == 0) {
+		LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sWindLight, 
+			"WLPresetsCombo");
+
+		LLFloaterDayCycle* sDayCycle = NULL;
+		LLComboBox* keyCombo = NULL;
+		if(LLFloaterDayCycle::isOpen()) 
+		{
+			sDayCycle = LLFloaterDayCycle::instance();
+			keyCombo = LLUICtrlFactory::getComboBoxByName(sDayCycle, 
+				"WLKeyPresets");
+		}
+
+		// add the current parameters to the list
+		// see if it's there first
+		std::map<std::string, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::instance()->mParamList.find(text.c_str());
+
+		// if not there, add a new one
+		if(mIt == LLWLParamManager::instance()->mParamList.end()) 
+		{
+			LLWLParamManager::instance()->addParamSet(text.c_str(), 
+				LLWLParamManager::instance()->mCurParams);
+			comboBox->add(text);
+			comboBox->sortByName();
+
+			// add a blank to the bottom
+			comboBox->selectFirstItem();
+			if(comboBox->getSimple() == "")
+			{
+				comboBox->remove(0);
+			}
+			comboBox->add("");
+
+			comboBox->setSelectedByValue(text, true);
+			if(LLFloaterDayCycle::isOpen()) 
+			{
+				keyCombo->add(text);
+				keyCombo->sortByName();
+			}
+			LLWLParamManager::instance()->savePreset(text);
+
+		// otherwise, send a message to the user
+		} 
+		else 
+		{
+			gViewerWindow->alertXml("ExistsSkyPresetAlert");
+		}
+	}
+}
+
+void LLFloaterWindLight::syncMenu()
+{
+	bool err;
+
+	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+
+	LLWLParamSet& currentParams = param_mgr->mCurParams;
+	//std::map<std::string, LLVector4> & currentParams = param_mgr->mCurParams.mParamValues;
+
+	// blue horizon
+	param_mgr->mBlueHorizon = currentParams.getVector(param_mgr->mBlueHorizon.name, err);
+	childSetValue("WLBlueHorizonR", param_mgr->mBlueHorizon.r / 2.0);
+	childSetValue("WLBlueHorizonG", param_mgr->mBlueHorizon.g / 2.0);
+	childSetValue("WLBlueHorizonB", param_mgr->mBlueHorizon.b / 2.0);
+	childSetValue("WLBlueHorizonI", 
+		std::max(param_mgr->mBlueHorizon.r / 2.0, 
+			std::max(param_mgr->mBlueHorizon.g / 2.0, 
+				param_mgr->mBlueHorizon.b / 2.0)));
+
+	// haze density, horizon, mult, and altitude
+	param_mgr->mHazeDensity = currentParams.getVector(param_mgr->mHazeDensity.name, err);
+	childSetValue("WLHazeDensity", param_mgr->mHazeDensity.r);
+	param_mgr->mHazeHorizon = currentParams.getVector(param_mgr->mHazeHorizon.name, err);
+	childSetValue("WLHazeHorizon", param_mgr->mHazeHorizon.r);
+	param_mgr->mDensityMult = currentParams.getVector(param_mgr->mDensityMult.name, err);
+	childSetValue("WLDensityMult", param_mgr->mDensityMult.x * 
+		param_mgr->mDensityMult.mult);
+	param_mgr->mMaxAlt = currentParams.getVector(param_mgr->mMaxAlt.name, err);
+	childSetValue("WLMaxAltitude", param_mgr->mMaxAlt.x);
+
+	// blue density
+	param_mgr->mBlueDensity = currentParams.getVector(param_mgr->mBlueDensity.name, err);
+	childSetValue("WLBlueDensityR", param_mgr->mBlueDensity.r / 2.0);
+	childSetValue("WLBlueDensityG", param_mgr->mBlueDensity.g / 2.0);
+	childSetValue("WLBlueDensityB", param_mgr->mBlueDensity.b / 2.0);
+	childSetValue("WLBlueDensityI", 
+		std::max(param_mgr->mBlueDensity.r / 2.0, 
+		std::max(param_mgr->mBlueDensity.g / 2.0, param_mgr->mBlueDensity.b / 2.0)));
+
+	// Lighting
+	
+	// sunlight
+	param_mgr->mSunlight = currentParams.getVector(param_mgr->mSunlight.name, err);
+	childSetValue("WLSunlightR", param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightG", param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightB", param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightI", 
+		std::max(param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE, 
+		std::max(param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE, param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE)));
+
+	// glow
+	param_mgr->mGlow = currentParams.getVector(param_mgr->mGlow.name, err);
+	childSetValue("WLGlowR", 2 - param_mgr->mGlow.r / 20.0f);
+	childSetValue("WLGlowB", -param_mgr->mGlow.b / 5.0f);
+		
+	// ambient
+	param_mgr->mAmbient = currentParams.getVector(param_mgr->mAmbient.name, err);
+	childSetValue("WLAmbientR", param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientG", param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientB", param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientI", 
+		std::max(param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE, 
+		std::max(param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE, param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE)));		
+
+	childSetValue("WLSunAngle", param_mgr->mCurParams.getFloat("sun_angle",err) / F_TWO_PI);
+	childSetValue("WLEastAngle", param_mgr->mCurParams.getFloat("east_angle",err) / F_TWO_PI);
+
+	// Clouds
+
+	// Cloud Color
+	param_mgr->mCloudColor = currentParams.getVector(param_mgr->mCloudColor.name, err);
+	childSetValue("WLCloudColorR", param_mgr->mCloudColor.r);
+	childSetValue("WLCloudColorG", param_mgr->mCloudColor.g);
+	childSetValue("WLCloudColorB", param_mgr->mCloudColor.b);
+	childSetValue("WLCloudColorI", 
+		std::max(param_mgr->mCloudColor.r, 
+		std::max(param_mgr->mCloudColor.g, param_mgr->mCloudColor.b)));
+
+	// Cloud
+	param_mgr->mCloudMain = currentParams.getVector(param_mgr->mCloudMain.name, err);
+	childSetValue("WLCloudX", param_mgr->mCloudMain.r);
+	childSetValue("WLCloudY", param_mgr->mCloudMain.g);
+	childSetValue("WLCloudDensity", param_mgr->mCloudMain.b);
+
+	// Cloud Detail
+	param_mgr->mCloudDetail = currentParams.getVector(param_mgr->mCloudDetail.name, err);
+	childSetValue("WLCloudDetailX", param_mgr->mCloudDetail.r);
+	childSetValue("WLCloudDetailY", param_mgr->mCloudDetail.g);
+	childSetValue("WLCloudDetailDensity", param_mgr->mCloudDetail.b);
+
+	// Cloud extras
+	param_mgr->mCloudCoverage = currentParams.getVector(param_mgr->mCloudCoverage.name, err);
+	param_mgr->mCloudScale = currentParams.getVector(param_mgr->mCloudScale.name, err);
+	childSetValue("WLCloudCoverage", param_mgr->mCloudCoverage.x);
+	childSetValue("WLCloudScale", param_mgr->mCloudScale.x);
+
+	// cloud scrolling
+	bool lockX = !param_mgr->mCurParams.getEnableCloudScrollX();
+	bool lockY = !param_mgr->mCurParams.getEnableCloudScrollY();
+	childSetValue("WLCloudLockX", lockX);
+	childSetValue("WLCloudLockY", lockY);
+	childSetValue("DrawClassicClouds", gSavedSettings.getBOOL("SkyUseClassicClouds"));
+	
+	// disable if locked, enable if not
+	if(lockX) 
+	{
+		childDisable("WLCloudScrollX");
+	} else {
+		childEnable("WLCloudScrollX");
+	}
+	if(lockY)
+	{
+		childDisable("WLCloudScrollY");
+	} else {
+		childEnable("WLCloudScrollY");
+	}
+
+	// *HACK cloud scrolling is off my an additive of 10
+	childSetValue("WLCloudScrollX", param_mgr->mCurParams.getCloudScrollX() - 10.0f);
+	childSetValue("WLCloudScrollY", param_mgr->mCurParams.getCloudScrollY() - 10.0f);
+
+	param_mgr->mDistanceMult = currentParams.getVector(param_mgr->mDistanceMult.name, err);
+	childSetValue("WLDistanceMult", param_mgr->mDistanceMult.x);
+
+	// Tweak extras
+
+	param_mgr->mWLGamma = currentParams.getVector(param_mgr->mWLGamma.name, err);
+	childSetValue("WLGamma", param_mgr->mWLGamma.x);
+
+	childSetValue("WLStarAlpha", param_mgr->mCurParams.getStarBrightness());
+}
+
+
+// static
+LLFloaterWindLight* LLFloaterWindLight::instance()
+{
+	if (!sWindLight)
+	{
+		sWindLight = new LLFloaterWindLight();
+		sWindLight->open();
+		sWindLight->setFocus(TRUE);
+	}
+	return sWindLight;
+}
+void LLFloaterWindLight::show()
+{
+	LLFloaterWindLight* windLight = instance();
+	windLight->syncMenu();
+
+	// comment in if you want the menu to rebuild each time
+	//gUICtrlFactory->buildFloater(windLight, "floater_windlight_options.xml");
+	//windLight->initCallbacks();
+
+	windLight->open();
+}
+
+bool LLFloaterWindLight::isOpen()
+{
+	if (sWindLight != NULL) {
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterWindLight::onClose(bool app_quitting)
+{
+	if (sWindLight)
+	{
+		sWindLight->setVisible(FALSE);
+	}
+}
+
+// color control callbacks
+void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	colorControl->r = sldrCtrl->getValueF32();
+	if(colorControl->isSunOrAmbientColor) {
+		colorControl->r *= 3;
+	}
+	if(colorControl->isBlueHorizonOrDensity) {
+		colorControl->r *= 2;
+	}	
+
+	// move i if it's the max
+	if(colorControl->r >= colorControl->g && colorControl->r >= colorControl->b 
+		&& colorControl->hasSliderName) {
+		colorControl->i = colorControl->r;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+		
+		if(colorControl->isSunOrAmbientColor) {
+			sWindLight->childSetValue(name, colorControl->r / 3);
+		} else if(colorControl->isBlueHorizonOrDensity) {
+			sWindLight->childSetValue(name, colorControl->r / 2);
+		} else {
+			sWindLight->childSetValue(name, colorControl->r);
+		}
+	}
+
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	colorControl->g = sldrCtrl->getValueF32();
+	if(colorControl->isSunOrAmbientColor) {
+		colorControl->g *= 3;
+	}
+	if(colorControl->isBlueHorizonOrDensity) {
+		colorControl->g *= 2;
+	}	
+
+	// move i if it's the max
+	if(colorControl->g >= colorControl->r && colorControl->g >= colorControl->b
+		&& colorControl->hasSliderName) {
+		colorControl->i = colorControl->g;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+
+		if(colorControl->isSunOrAmbientColor) {
+			sWindLight->childSetValue(name, colorControl->g / 3);
+		} else if(colorControl->isBlueHorizonOrDensity) {
+			sWindLight->childSetValue(name, colorControl->g / 2);
+		} else {
+			sWindLight->childSetValue(name, colorControl->g);
+		}
+	}
+
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	colorControl->b = sldrCtrl->getValueF32();
+	if(colorControl->isSunOrAmbientColor) {
+		colorControl->b *= 3;
+	}
+	if(colorControl->isBlueHorizonOrDensity) {
+		colorControl->b *= 2;
+	}	
+
+	// move i if it's the max
+	if(colorControl->b >= colorControl->r && colorControl->b >= colorControl->g
+		&& colorControl->hasSliderName) {
+		colorControl->i = colorControl->b;
+		std::string name = colorControl->mSliderName;
+		name.append("I");
+
+		if(colorControl->isSunOrAmbientColor) {
+			sWindLight->childSetValue(name, colorControl->b / 3);
+		} else if(colorControl->isBlueHorizonOrDensity) {
+			sWindLight->childSetValue(name, colorControl->b / 2);
+		} else {
+			sWindLight->childSetValue(name, colorControl->b);
+		}
+	}
+
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	colorControl->i = sldrCtrl->getValueF32();
+	
+	// only for sliders where we pass a name
+	if(colorControl->hasSliderName) {
+		
+		// set it to the top
+		F32 maxVal = std::max(std::max(colorControl->r, colorControl->g), colorControl->b);
+		F32 iVal;
+
+		if(colorControl->isSunOrAmbientColor)
+		{
+			iVal = colorControl->i * 3;
+		} 
+		else if(colorControl->isBlueHorizonOrDensity)
+		{
+			iVal = colorControl->i * 2;
+		} 
+		else 
+		{
+			iVal = colorControl->i;
+		}
+
+		// get the names of the other sliders
+		std::string rName = colorControl->mSliderName;
+		rName.append("R");
+		std::string gName = colorControl->mSliderName;
+		gName.append("G");
+		std::string bName = colorControl->mSliderName;
+		bName.append("B");
+
+		// handle if at 0
+		if(iVal == 0) {
+			colorControl->r = 0;
+			colorControl->g = 0;
+			colorControl->b = 0;
+		
+		// if all at the start
+		// set them all to the intensity
+		} else if (maxVal == 0) {
+			colorControl->r = iVal;
+			colorControl->g = iVal;
+			colorControl->b = iVal;
+
+		} else {
+
+			// add delta amounts to each
+			F32 delta = (iVal - maxVal) / maxVal;
+			colorControl->r *= (1.0f + delta);
+			colorControl->g *= (1.0f + delta);
+			colorControl->b *= (1.0f + delta);
+		}
+
+		// divide sun color vals by three
+		if(colorControl->isSunOrAmbientColor) 
+		{
+			sWindLight->childSetValue(rName.c_str(), colorControl->r/3);
+			sWindLight->childSetValue(gName.c_str(), colorControl->g/3);
+			sWindLight->childSetValue(bName.c_str(), colorControl->b/3);	
+		
+		} 
+		else if(colorControl->isBlueHorizonOrDensity) 
+		{
+			sWindLight->childSetValue(rName.c_str(), colorControl->r/2);
+			sWindLight->childSetValue(gName.c_str(), colorControl->g/2);
+			sWindLight->childSetValue(bName.c_str(), colorControl->b/2);	
+		
+		} 
+		else 
+		{
+			// set the sliders to the new vals
+			sWindLight->childSetValue(rName.c_str(), colorControl->r);
+			sWindLight->childSetValue(gName.c_str(), colorControl->g);
+			sWindLight->childSetValue(bName.c_str(), colorControl->b);
+		}
+	}
+
+	// now update the current parameters and send them to shaders
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+/// GLOW SPECIFIC CODE
+void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	// scaled by 20
+	colorControl->r = (2 - sldrCtrl->getValueF32()) * 20;
+
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+/// \NOTE that we want NEGATIVE (-) B
+void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+
+	/// \NOTE that we want NEGATIVE (-) B and NOT by 20 as 20 is too big
+	colorControl->b = -sldrCtrl->getValueF32() * 5;
+
+	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLFloatControl * floatControl = static_cast<WLFloatControl *>(userData);
+
+	floatControl->x = sldrCtrl->getValueF32() / floatControl->mult;
+
+	floatControl->update(LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onBoolToggle(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+
+	bool value = cbCtrl->get();
+	(*(static_cast<BOOL *>(userData))) = value;
+}
+
+
+// Lighting callbacks
+
+// time of day
+void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sunSldr = LLUICtrlFactory::getSliderByName(sWindLight, 
+		"WLSunAngle");
+	LLSliderCtrl* eastSldr = LLUICtrlFactory::getSliderByName(sWindLight, 
+		"WLEastAngle");
+
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+	
+	// get the two angles
+	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+
+	param_mgr->mCurParams.setSunAngle(F_TWO_PI * sunSldr->getValueF32());
+	param_mgr->mCurParams.setEastAngle(F_TWO_PI * eastSldr->getValueF32());
+
+	// set the sun vector
+	colorControl->r = -sin(param_mgr->mCurParams.getEastAngle()) * 
+		cos(param_mgr->mCurParams.getSunAngle());
+	colorControl->g = sin(param_mgr->mCurParams.getSunAngle());
+	colorControl->b = cos(param_mgr->mCurParams.getEastAngle()) * 
+		cos(param_mgr->mCurParams.getSunAngle());
+	colorControl->i = 1.f;
+
+	colorControl->update(param_mgr->mCurParams);
+	param_mgr->propagateParameters();
+}
+
+void LLFloaterWindLight::onFloatTweakMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	F32 * tweak = static_cast<F32 *>(userData);
+
+	(*tweak) = sldrCtrl->getValueF32();
+	LLWLParamManager::instance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+
+	LLWLParamManager::instance()->mCurParams.setStarBrightness(sldrCtrl->getValueF32());
+}
+
+void LLFloaterWindLight::onNewPreset(void* userData)
+{
+	gViewerWindow->alertXmlEditText("NewSkyPreset", LLString::format_map_t(), 
+		NULL, NULL, newPromptCallback, NULL);
+}
+
+void LLFloaterWindLight::onSavePreset(void* userData)
+{
+	// get the name
+	LLComboBox* comboBox = LLUICtrlFactory::getComboBoxByName(sWindLight, 
+		"WLPresetsCombo");
+
+	// don't save the empty name
+	if(comboBox->getSelectedItemLabel() == "")
+	{
+		return;
+	}
+
+	// check to see if it's a default and shouldn't be overwritten
+	std::set<std::string>::iterator sIt = sDefaultPresets.find(
+		comboBox->getSelectedItemLabel().c_str());
+	if(sIt != sDefaultPresets.end() && !gSavedSettings.getBOOL("SkyEditPresets")) 
+	{
+		gViewerWindow->alertXml("WLNoEditDefault");
+		return;
+	}
+
+	LLWLParamManager::instance()->mCurParams.mName = 
+		comboBox->getSelectedItemLabel();
+
+	gViewerWindow->alertXml("WLSavePresetAlert", saveAlertCallback, sWindLight);
+}
+
+void LLFloaterWindLight::saveAlertCallback(S32 option, void* userdata)
+{
+	// if they choose save, do it.  Otherwise, don't do anything
+	if(option == 0) 
+	{
+		LLWLParamManager * param_mgr = LLWLParamManager::instance();
+
+		param_mgr->setParamSet(param_mgr->mCurParams.mName, param_mgr->mCurParams);
+		
+		// comment this back in to save to file
+		param_mgr->savePreset(param_mgr->mCurParams.mName);
+	}
+
+}
+
+void LLFloaterWindLight::onDeletePreset(void* userData)
+{
+	LLComboBox* combo_box = LLUICtrlFactory::getComboBoxByName(sWindLight, 
+		"WLPresetsCombo");
+
+	if(combo_box->getSelectedValue().asString() == "")
+	{
+		return;
+	}
+
+	LLString::format_map_t args;
+	args["[SKY]"] = combo_box->getSelectedValue().asString();
+	gViewerWindow->alertXml("WLDeletePresetAlert", args, deleteAlertCallback, sWindLight);
+}
+
+void LLFloaterWindLight::deleteAlertCallback(S32 option, void* userdata)
+{
+	// if they choose delete, do it.  Otherwise, don't do anything
+	if(option == 0) 
+	{
+		LLComboBox* combo_box = LLUICtrlFactory::getComboBoxByName(sWindLight, 
+			"WLPresetsCombo");
+		LLFloaterDayCycle* day_cycle = NULL;
+		LLComboBox* key_combo = NULL;
+		LLMultiSliderCtrl* mult_sldr = NULL;
+
+		if(LLFloaterDayCycle::isOpen()) 
+		{
+			day_cycle = LLFloaterDayCycle::instance();
+			key_combo = LLUICtrlFactory::getComboBoxByName(day_cycle, 
+				"WLKeyPresets");
+			mult_sldr = LLUICtrlFactory::getMultiSliderByName(day_cycle, 
+				"WLDayCycleKeys");
+		}
+
+		LLString name(combo_box->getSelectedValue().asString());
+
+		// check to see if it's a default and shouldn't be deleted
+		std::set<std::string>::iterator sIt = sDefaultPresets.find(name.c_str());
+		if(sIt != sDefaultPresets.end()) 
+		{
+			gViewerWindow->alertXml("WLNoEditDefault");
+			return;
+		}
+
+		LLWLParamManager::instance()->removeParamSet(name, true);
+		
+		// remove and choose another
+		S32 new_index = combo_box->getCurrentIndex();
+
+		combo_box->remove(name);
+		if(key_combo != NULL) 
+		{
+			key_combo->remove(name);
+
+			// remove from slider, as well
+			day_cycle->deletePreset(name);
+		}
+
+		// pick the previously selected index after delete
+		if(new_index > 0) 
+		{
+			new_index--;
+		}
+		
+		if(combo_box->getItemCount() > 0) 
+		{
+			combo_box->setCurrentByIndex(new_index);
+		}
+	}
+}
+
+
+void LLFloaterWindLight::onChangePresetName(LLUICtrl* ctrl, void * userData)
+{
+	deactivateAnimator();
+
+	LLComboBox * combo_box = static_cast<LLComboBox*>(ctrl);
+	
+	if(combo_box->getSimple() == "")
+	{
+		return;
+	}
+	
+	LLWLParamManager::instance()->loadPreset(
+		combo_box->getSelectedValue().asString());
+	sWindLight->syncMenu();
+}
+
+void LLFloaterWindLight::onOpenDayCycle(void* userData)
+{
+	LLFloaterDayCycle::show();
+}
+
+// Clouds
+void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	// *HACK  all cloud scrolling is off by an additive of 10. 
+	LLWLParamManager::instance()->mCurParams.setCloudScrollX(sldrCtrl->getValueF32() + 10.0f);
+}
+
+void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+
+	// *HACK  all cloud scrolling is off by an additive of 10. 
+	LLWLParamManager::instance()->mCurParams.setCloudScrollY(sldrCtrl->getValueF32() + 10.0f);
+}
+
+void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+
+	bool lock = cbCtrl->get();
+	LLWLParamManager::instance()->mCurParams.setEnableCloudScrollX(!lock);
+
+	LLSliderCtrl* sldr = LLUICtrlFactory::getSliderByName(sWindLight, 
+		"WLCloudScrollX");
+
+	if(cbCtrl->get()) 
+	{
+		sldr->setEnabled(false);
+	} 
+	else 
+	{
+		sldr->setEnabled(true);
+	}
+
+}
+
+void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl, void* userData)
+{
+	deactivateAnimator();
+
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+	bool lock = cbCtrl->get();
+	LLWLParamManager::instance()->mCurParams.setEnableCloudScrollY(!lock);
+
+	LLSliderCtrl* sldr = LLUICtrlFactory::getSliderByName(sWindLight, 
+		"WLCloudScrollY");
+
+	if(cbCtrl->get()) 
+	{
+		sldr->setEnabled(false);
+	} 
+	else 
+	{
+		sldr->setEnabled(true);
+	}
+}
+
+void LLFloaterWindLight::deactivateAnimator()
+{
+	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+}
diff --git a/indra/newview/llfloaterwindlight.h b/indra/newview/llfloaterwindlight.h
new file mode 100644
index 00000000000..9bb7f1371c3
--- /dev/null
+++ b/indra/newview/llfloaterwindlight.h
@@ -0,0 +1,142 @@
+/** 
+ * @file llfloaterwindlight.h
+ * @brief LLFloaterWindLight class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/*
+ * Menu for adjusting the atmospheric settings of the world
+ */
+
+#ifndef LL_LLFLOATERWINDLIGHT_H
+#define LL_LLFLOATERWINDLIGHT_H
+
+#include "llfloater.h"
+
+#include <vector>
+#include "llwlparamset.h"
+
+struct WLColorControl;
+struct WLFloatControl;
+
+
+/// Menuing system for all of windlight's functionality
+class LLFloaterWindLight : public LLFloater
+{
+public:
+
+	LLFloaterWindLight();
+	virtual ~LLFloaterWindLight();
+	
+	/// initialize all
+	void initCallbacks(void);
+
+	/// one and one instance only
+	static LLFloaterWindLight* instance();
+
+	// help button stuff
+	static void onClickHelp(void* data);
+	void initHelpBtn(const char* name, const char* xml_alert);
+
+	static void newPromptCallback(S32 option, const LLString& text, void* userData);
+
+	/// general purpose callbacks for dealing with color controllers
+	static void onColorControlRMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlGMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlBMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlIMoved(LLUICtrl* ctrl, void* userData);
+	static void onFloatControlMoved(LLUICtrl* ctrl, void* userData);
+	static void onBoolToggle(LLUICtrl* ctrl, void* userData);
+
+	/// lighting callbacks for glow
+	static void onGlowRMoved(LLUICtrl* ctrl, void* userData);
+	//static void onGlowGMoved(LLUICtrl* ctrl, void* userData);
+	static void onGlowBMoved(LLUICtrl* ctrl, void* userData);
+
+	/// lighting callbacks for sun
+	static void onSunMoved(LLUICtrl* ctrl, void* userData);
+
+	/// handle if float is changed
+	static void onFloatTweakMoved(LLUICtrl* ctrl, void* userData);
+
+	/// for handling when the star slider is moved to adjust the alpha
+	static void onStarAlphaMoved(LLUICtrl* ctrl, void* userData);
+
+	/// when user hits the load preset button
+	static void onNewPreset(void* userData);
+
+	/// when user hits the save preset button
+	static void onSavePreset(void* userData);
+
+	/// prompts a user when overwriting a preset
+	static void saveAlertCallback(S32 option, void* userdata);
+
+	/// when user hits the save preset button
+	static void onDeletePreset(void* userData);
+
+	/// prompts a user when overwriting a preset
+	static void deleteAlertCallback(S32 option, void* userdata);
+
+	/// what to do when you change the preset name
+	static void onChangePresetName(LLUICtrl* ctrl, void* userData);
+
+	/// when user hits the save preset button
+	static void onOpenDayCycle(void* userData);
+
+	/// handle cloud scrolling
+	static void onCloudScrollXMoved(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollYMoved(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollXToggled(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollYToggled(LLUICtrl* ctrl, void* userData);
+
+	//// menu management
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
+	/// sync up sliders with parameters
+	void syncMenu();
+
+	/// turn off animated skies
+	static void deactivateAnimator();
+
+private:
+	// one instance on the inside
+	static LLFloaterWindLight* sWindLight;
+
+	static std::set<std::string> sDefaultPresets;
+};
+
+
+#endif
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index a710d1688d6..9ec76761951 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -40,6 +40,7 @@
 #include "llfocusmgr.h"
 #include "llfontgl.h"
 #include "llgl.h" 
+#include "llglimmediate.h"
 #include "llinventory.h"
 
 #include "llcallbacklist.h"
@@ -809,7 +810,6 @@ void LLFolderViewItem::draw()
 	}
 	if(/*mControlLabel[0] != '\0' && */possibly_has_children)
 	{
-		LLGLSTexture gls_texture;
 		if (mArrowImage)
 		{
 			gl_draw_scaled_rotated_image(mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD,
@@ -962,7 +962,7 @@ void LLFolderViewItem::draw()
 				S32 top = getRect().getHeight();
 
 				LLViewerImage::bindTexture(mBoxImage);
-				glColor4fv(sFilterBGColor.mV);
+				gGL.color4fv(sFilterBGColor.mV);
 				gl_segmented_rect_2d_tex(left, top, right, bottom, mBoxImage->getWidth(), mBoxImage->getHeight(), 16);
 				F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset);
 				F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD;
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index a291f1da492..6459cd50336 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -39,6 +39,7 @@
 #include "llviewercontrol.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llglheaders.h"
 #include "llparcel.h"
 #include "llui.h"
@@ -65,6 +66,7 @@
 #include "llpreviewtexture.h"
 #include "llresmgr.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
  
 BOOL LLAgent::setLookAt(ELookAtType target_type, LLViewerObject *object, LLVector3 position)
 {
@@ -137,7 +139,7 @@ void LLAgent::renderAutoPilotTarget()
 		LLVector3d target_global;
 
 		glMatrixMode(GL_MODELVIEW);
-		glPushMatrix();
+		gGL.pushMatrix();
 
 		// not textured
 		LLGLSNoTexture no_texture;
@@ -147,31 +149,15 @@ void LLAgent::renderAutoPilotTarget()
 
 		target_global = mAutoPilotTargetGlobal;
 
-		glTranslatef((F32)(target_global.mdV[VX]), (F32)(target_global.mdV[VY]), (F32)(target_global.mdV[VZ]));
+		gGL.translatef((F32)(target_global.mdV[VX]), (F32)(target_global.mdV[VY]), (F32)(target_global.mdV[VZ]));
 
-		/*
-		LLVector3 offset = target_global - mCamera.getOrigin();
-		F32 range = offset.magVec();
-		if (range > 0.001f)
-		{
-			// range != zero
-			F32 fraction_of_fov = height_pixels / (F32) mCamera.getViewHeightInPixels();
-			F32 apparent_angle = fraction_of_fov * mCamera.getView();
-			height_meters = range * tan(apparent_angle);
-		}
-		else
-		{
-			// range == zero
-			height_meters = 1.0f;
-		}
-		*/
 		height_meters = 1.f;
 
 		glScalef(height_meters, height_meters, height_meters);
 
 		gSphere.render(1500.f);
 
-		glPopMatrix();
+		gGL.popMatrix();
 	}
 }
 
@@ -227,7 +213,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 
 	// save drawing mode
 	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
+	gGL.pushMatrix();
 
 	BOOL limit_select_distance = gSavedSettings.getBOOL("LimitSelectDistance");
 	if (limit_select_distance)
@@ -284,14 +270,18 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 	if (grow_selection)
 	{
 		std::vector<LLDrawable*> potentials;
-		
-		
-		for (U32 i = 0; i < LLPipeline::NUM_PARTITIONS-1; i++)
+				
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			LLSpatialPartition* part = gPipeline.getSpatialPartition(i);
-			if (part)
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 			{
-				part->cull(*gCamera, &potentials, TRUE);
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{	
+					part->cull(*gCamera, &potentials, TRUE);
+				}
 			}
 		}
 		
@@ -338,7 +328,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 
 	// restore drawing mode
 	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	gGL.popMatrix();
 	glMatrixMode(GL_MODELVIEW);
 
 	// restore camera
@@ -358,35 +348,35 @@ void LLCompass::draw()
 	if (!getVisible()) return;
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 
 	S32 width = 32;
 	S32 height = 32;
 
 	LLGLSUIDefault gls_ui;
 
-	glTranslatef( COMPASS_SIZE/2.f, COMPASS_SIZE/2.f, 0.f);
+	gGL.translatef( COMPASS_SIZE/2.f, COMPASS_SIZE/2.f, 0.f);
 
 	if (mBkgndTexture)
 	{
 		mBkgndTexture->bind();
-		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+		gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f);
 		
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		
-		glTexCoord2f(1.f, 1.f);
-		glVertex2i(width, height);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex2i(width, height);
 		
-		glTexCoord2f(0.f, 1.f);
-		glVertex2i(-width, height);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex2i(-width, height);
 		
-		glTexCoord2f(0.f, 0.f);
-		glVertex2i(-width, -height);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex2i(-width, -height);
 		
-		glTexCoord2f(1.f, 0.f);
-		glVertex2i(width, -height);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex2i(width, -height);
 		
-		glEnd();
+		gGL.end();
 	}
 
 	// rotate subsequent draws to agent rotation
@@ -396,26 +386,26 @@ void LLCompass::draw()
 	if (mTexture)
 	{
 		mTexture->bind();
-		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+		gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f);
 		
-		glBegin(GL_QUADS);
+		gGL.begin(GL_QUADS);
 		
-		glTexCoord2f(1.f, 1.f);
-		glVertex2i(width, height);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex2i(width, height);
 		
-		glTexCoord2f(0.f, 1.f);
-		glVertex2i(-width, height);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex2i(-width, height);
 		
-		glTexCoord2f(0.f, 0.f);
-		glVertex2i(-width, -height);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex2i(-width, -height);
 		
-		glTexCoord2f(1.f, 0.f);
-		glVertex2i(width, -height);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex2i(width, -height);
 		
-		glEnd();
+		gGL.end();
 	}
 
-	glPopMatrix();
+	gGL.popMatrix();
 
 }
 
@@ -443,28 +433,28 @@ void LLHorizontalCompass::draw()
 		F32 right = center + COMPASS_RANGE;
 
 		mTexture->bind();
-		glColor4f(1.0f, 1.0f, 1.0f, 1.0f );
-		glBegin( GL_QUADS );
+		gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f );
+		gGL.begin( GL_QUADS );
 
-		glTexCoord2f(right, 1.f);
-		glVertex2i(width, height);
+		gGL.texCoord2f(right, 1.f);
+		gGL.vertex2i(width, height);
 
-		glTexCoord2f(left, 1.f);
-		glVertex2i(0, height);
+		gGL.texCoord2f(left, 1.f);
+		gGL.vertex2i(0, height);
 
-		glTexCoord2f(left, 0.f);
-		glVertex2i(0, 0);
+		gGL.texCoord2f(left, 0.f);
+		gGL.vertex2i(0, 0);
 
-		glTexCoord2f(right, 0.f);
-		glVertex2i(width, 0);
+		gGL.texCoord2f(right, 0.f);
+		gGL.vertex2i(width, 0);
 
-		glEnd();
+		gGL.end();
 	}
 
 	// Draw the focus line
 	{
 		LLGLSNoTexture gls_no_texture;
-		glColor4fv( mFocusColor.mV );
+		gGL.color4fv( mFocusColor.mV );
 		gl_line_2d( half_width, 0, half_width, height );
 	}
 }
@@ -482,31 +472,31 @@ void LLWind::renderVectors()
 	F32 region_width_meters = gWorldPointer->getRegionWidthInMeters();
 
 	LLGLSNoTexture gls_no_texture;
-	glPushMatrix();
+	gGL.pushMatrix();
 	LLVector3 origin_agent;
 	origin_agent = gAgent.getPosAgentFromGlobal(mOriginGlobal);
-	glTranslatef(origin_agent.mV[VX], origin_agent.mV[VY], WIND_ALTITUDE);
+	gGL.translatef(origin_agent.mV[VX], origin_agent.mV[VY], WIND_ALTITUDE);
 	for (j = 0; j < mSize; j++)
 	{
 		for (i = 0; i < mSize; i++)
 		{
 			x = mCloudVelX[i + j*mSize] * WIND_SCALE_HACK;
 			y = mCloudVelY[i + j*mSize] * WIND_SCALE_HACK;
-			glPushMatrix();
-			glTranslatef((F32)i * region_width_meters/mSize, (F32)j * region_width_meters/mSize, 0.0);
-			glColor3f(0,1,0);
-			glBegin(GL_POINTS);
-				glVertex3f(0,0,0);
-			glEnd();
-			glColor3f(1,0,0);
-			glBegin(GL_LINES);
-				glVertex3f(x * 0.1f, y * 0.1f ,0.f);
-				glVertex3f(x, y, 0.f);
-			glEnd();
-			glPopMatrix();
+			gGL.pushMatrix();
+			gGL.translatef((F32)i * region_width_meters/mSize, (F32)j * region_width_meters/mSize, 0.0);
+			gGL.color3f(0,1,0);
+			gGL.begin(GL_POINTS);
+				gGL.vertex3f(0,0,0);
+			gGL.end();
+			gGL.color3f(1,0,0);
+			gGL.begin(GL_LINES);
+				gGL.vertex3f(x * 0.1f, y * 0.1f ,0.f);
+				gGL.vertex3f(x, y, 0.f);
+			gGL.end();
+			gGL.popMatrix();
 		}
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 
@@ -545,49 +535,49 @@ void LLViewerParcelMgr::renderRect(const LLVector3d &west_south_bottom_global,
 	F32 nw_top = nw_bottom + PARCEL_POST_HEIGHT;
 
 	LLUI::setLineWidth(2.f);
-	glColor4f(1.f, 1.f, 0.f, 1.f);
+	gGL.color4f(1.f, 1.f, 0.f, 1.f);
 
 	// Cheat and give this the same pick-name as land
-	glBegin(GL_LINES);
+	gGL.begin(GL_LINES);
 
-	glVertex3f(west, north, nw_bottom);
-	glVertex3f(west, north, nw_top);
+	gGL.vertex3f(west, north, nw_bottom);
+	gGL.vertex3f(west, north, nw_top);
 
-	glVertex3f(east, north, ne_bottom);
-	glVertex3f(east, north, ne_top);
+	gGL.vertex3f(east, north, ne_bottom);
+	gGL.vertex3f(east, north, ne_top);
 
-	glVertex3f(east, south, se_bottom);
-	glVertex3f(east, south, se_top);
+	gGL.vertex3f(east, south, se_bottom);
+	gGL.vertex3f(east, south, se_top);
 
-	glVertex3f(west, south, sw_bottom);
-	glVertex3f(west, south, sw_top);
+	gGL.vertex3f(west, south, sw_bottom);
+	gGL.vertex3f(west, south, sw_top);
 
-	glEnd();
+	gGL.end();
 
-	glColor4f(1.f, 1.f, 0.f, 0.2f);
-	glBegin(GL_QUADS);
+	gGL.color4f(1.f, 1.f, 0.f, 0.2f);
+	gGL.begin(GL_QUADS);
 
-	glVertex3f(west, north, nw_bottom);
-	glVertex3f(west, north, nw_top);
-	glVertex3f(east, north, ne_top);
-	glVertex3f(east, north, ne_bottom);
+	gGL.vertex3f(west, north, nw_bottom);
+	gGL.vertex3f(west, north, nw_top);
+	gGL.vertex3f(east, north, ne_top);
+	gGL.vertex3f(east, north, ne_bottom);
 
-	glVertex3f(east, north, ne_bottom);
-	glVertex3f(east, north, ne_top);
-	glVertex3f(east, south, se_top);
-	glVertex3f(east, south, se_bottom);
+	gGL.vertex3f(east, north, ne_bottom);
+	gGL.vertex3f(east, north, ne_top);
+	gGL.vertex3f(east, south, se_top);
+	gGL.vertex3f(east, south, se_bottom);
 
-	glVertex3f(east, south, se_bottom);
-	glVertex3f(east, south, se_top);
-	glVertex3f(west, south, sw_top);
-	glVertex3f(west, south, sw_bottom);
+	gGL.vertex3f(east, south, se_bottom);
+	gGL.vertex3f(east, south, se_top);
+	gGL.vertex3f(west, south, sw_top);
+	gGL.vertex3f(west, south, sw_bottom);
 
-	glVertex3f(west, south, sw_bottom);
-	glVertex3f(west, south, sw_top);
-	glVertex3f(west, north, nw_top);
-	glVertex3f(west, north, nw_bottom);
+	gGL.vertex3f(west, south, sw_bottom);
+	gGL.vertex3f(west, south, sw_top);
+	gGL.vertex3f(west, north, nw_top);
+	gGL.vertex3f(west, north, nw_bottom);
 
-	glEnd();
+	gGL.end();
 
 	LLUI::setLineWidth(1.f);
 }
@@ -629,49 +619,49 @@ void LLViewerParcelMgr::renderParcel(LLParcel* parcel )
 		LLGLDepthTest gls_depth(GL_TRUE);
 
 		LLUI::setLineWidth(2.f);
-		glColor4f(0.f, 1.f, 1.f, 1.f);
+		gGL.color4f(0.f, 1.f, 1.f, 1.f);
 
 		// Cheat and give this the same pick-name as land
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 
-		glVertex3f(west, north, nw_bottom);
-		glVertex3f(west, north, nw_top);
+		gGL.vertex3f(west, north, nw_bottom);
+		gGL.vertex3f(west, north, nw_top);
 
-		glVertex3f(east, north, ne_bottom);
-		glVertex3f(east, north, ne_top);
+		gGL.vertex3f(east, north, ne_bottom);
+		gGL.vertex3f(east, north, ne_top);
 
-		glVertex3f(east, south, se_bottom);
-		glVertex3f(east, south, se_top);
+		gGL.vertex3f(east, south, se_bottom);
+		gGL.vertex3f(east, south, se_top);
 
-		glVertex3f(west, south, sw_bottom);
-		glVertex3f(west, south, sw_top);
+		gGL.vertex3f(west, south, sw_bottom);
+		gGL.vertex3f(west, south, sw_top);
 
-		glEnd();
+		gGL.end();
 
-		glColor4f(0.f, 1.f, 1.f, 0.2f);
-		glBegin(GL_QUADS);
+		gGL.color4f(0.f, 1.f, 1.f, 0.2f);
+		gGL.begin(GL_QUADS);
 
-		glVertex3f(west, north, nw_bottom);
-		glVertex3f(west, north, nw_top);
-		glVertex3f(east, north, ne_top);
-		glVertex3f(east, north, ne_bottom);
+		gGL.vertex3f(west, north, nw_bottom);
+		gGL.vertex3f(west, north, nw_top);
+		gGL.vertex3f(east, north, ne_top);
+		gGL.vertex3f(east, north, ne_bottom);
 
-		glVertex3f(east, north, ne_bottom);
-		glVertex3f(east, north, ne_top);
-		glVertex3f(east, south, se_top);
-		glVertex3f(east, south, se_bottom);
+		gGL.vertex3f(east, north, ne_bottom);
+		gGL.vertex3f(east, north, ne_top);
+		gGL.vertex3f(east, south, se_top);
+		gGL.vertex3f(east, south, se_bottom);
 
-		glVertex3f(east, south, se_bottom);
-		glVertex3f(east, south, se_top);
-		glVertex3f(west, south, sw_top);
-		glVertex3f(west, south, sw_bottom);
+		gGL.vertex3f(east, south, se_bottom);
+		gGL.vertex3f(east, south, se_top);
+		gGL.vertex3f(west, south, sw_top);
+		gGL.vertex3f(west, south, sw_bottom);
 
-		glVertex3f(west, south, sw_bottom);
-		glVertex3f(west, south, sw_top);
-		glVertex3f(west, north, nw_top);
-		glVertex3f(west, north, nw_bottom);
+		gGL.vertex3f(west, south, sw_bottom);
+		gGL.vertex3f(west, south, sw_top);
+		gGL.vertex3f(west, north, nw_top);
+		gGL.vertex3f(west, north, nw_bottom);
 
-		glEnd();
+		gGL.end();
 
 		LLUI::setLineWidth(1.f);
 	}
@@ -714,14 +704,14 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei
 	if (height < 1.f)
 	{
 		z = z1+height;
-		glVertex3f(x1, y1, z);
+		gGL.vertex3f(x1, y1, z);
 
-		glVertex3f(x1, y1, z1);
+		gGL.vertex3f(x1, y1, z1);
 
-		glVertex3f(x2, y2, z2);
+		gGL.vertex3f(x2, y2, z2);
 
 		z = z2+height;
-		glVertex3f(x2, y2, z);
+		gGL.vertex3f(x2, y2, z);
 	}
 	else
 	{
@@ -750,19 +740,19 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei
 		}
 
 
-		glTexCoord2f(tex_coord1*0.5f+0.5f, z1*0.5f);
-		glVertex3f(x1, y1, z1);
+		gGL.texCoord2f(tex_coord1*0.5f+0.5f, z1*0.5f);
+		gGL.vertex3f(x1, y1, z1);
 
-		glTexCoord2f(tex_coord2*0.5f+0.5f, z2*0.5f);
-		glVertex3f(x2, y2, z2);
+		gGL.texCoord2f(tex_coord2*0.5f+0.5f, z2*0.5f);
+		gGL.vertex3f(x2, y2, z2);
 
 		// top edge stairsteps
 		z = llmax(z2+height, z1+height);
-		glTexCoord2f(tex_coord2*0.5f+0.5f, z*0.5f);
-		glVertex3f(x2, y2, z);
+		gGL.texCoord2f(tex_coord2*0.5f+0.5f, z*0.5f);
+		gGL.vertex3f(x2, y2, z);
 
-		glTexCoord2f(tex_coord1*0.5f+0.5f, z*0.5f);
-		glVertex3f(x1, y1, z);
+		gGL.texCoord2f(tex_coord1*0.5f+0.5f, z*0.5f);
+		gGL.vertex3f(x1, y1, z);
 	}
 }
 
@@ -772,17 +762,19 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi
 	S32 x, y;
 	F32 x1, y1;	// start point
 	F32 x2, y2;	// end point
+	bool has_segments = false;
 
 	LLGLSUIDefault gls_ui;
 	LLGLSNoTexture gls_no_texture;
 	LLGLDepthTest gls_depth(GL_TRUE);
 
-	glColor4f(1.f, 1.f, 0.f, 0.2f);
-
-	// Cheat and give this the same pick-name as land
-	glBegin(GL_QUADS);
+	gGL.color4f(1.f, 1.f, 0.f, 0.2f);
 
 	const S32 STRIDE = (mParcelsPerEdge+1);
+
+	// Cheat and give this the same pick-name as land
+	
+	
 	for (y = 0; y < STRIDE; y++)
 	{
 		for (x = 0; x < STRIDE; x++)
@@ -796,7 +788,12 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi
 
 				x2 = x1 + PARCEL_GRID_STEP_METERS;
 				y2 = y1;
-
+				
+				if (!has_segments)
+				{
+					has_segments = true;
+					gGL.begin(GL_QUADS);
+				}
 				renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, SOUTH_MASK, regionp);
 			}
 
@@ -808,12 +805,20 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi
 				x2 = x1;
 				y2 = y1 + PARCEL_GRID_STEP_METERS;
 
+				if (!has_segments)
+				{
+					has_segments = true;
+					gGL.begin(GL_QUADS);
+				}
 				renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, WEST_MASK, regionp);
 			}
 		}
 	}
 
-	glEnd();
+	if (has_segments)
+	{
+		gGL.end();
+	}
 }
 
 
@@ -858,7 +863,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 		LLViewerImage::bindTexture( getBlockedImage() );
 	}
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 
 	for (y = 0; y < STRIDE; y++)
 	{
@@ -882,7 +887,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 				if (gRenderForSelect)
 				{
 					LLColor4U color((U8)(GL_NAME_PARCEL_WALL >> 16), (U8)(GL_NAME_PARCEL_WALL >> 8), (U8)GL_NAME_PARCEL_WALL);
-					glColor4ubv(color.mV);
+					gGL.color4ubv(color.mV);
 				}
 				else
 				{
@@ -906,7 +911,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 
 					alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
 
-					glColor4f(1.f, 1.f, 1.f, alpha);
+					gGL.color4f(1.f, 1.f, 1.f, alpha);
 				}
 
 				if ((pos_y - y1) < 0) direction = SOUTH_MASK;
@@ -928,7 +933,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 				if (gRenderForSelect)
 				{
 					LLColor4U color((U8)(GL_NAME_PARCEL_WALL >> 16), (U8)(GL_NAME_PARCEL_WALL >> 8), (U8)GL_NAME_PARCEL_WALL);
-					glColor4ubv(color.mV);
+					gGL.color4ubv(color.mV);
 				}
 				else
 				{					
@@ -952,7 +957,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 
 					alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
 
-					glColor4f(1.f, 1.f, 1.f, alpha);
+					gGL.color4f(1.f, 1.f, 1.f, alpha);
 				}
 
 				if ((pos_x - x1) > 0) direction = WEST_MASK;
@@ -965,43 +970,48 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
 		}
 	}
 
-	glEnd();
+	gGL.end();
 }
 
 void draw_line_cube(F32 width, const LLVector3& center)
 {
 	width = 0.5f * width;
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
-
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
-
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
-	glVertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
+
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
+
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] + width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] + width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] - width ,center.mV[VY] - width,center.mV[VZ] - width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] + width);
+	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
 }
 
 
 void LLViewerObjectList::renderObjectBeacons()
 {
+	if (mDebugBeacons.empty())
+	{
+		return;
+	}
+
 	S32 i;
 	//const LLFontGL *font = gResMgr->getRes(LLFONT_SANSSERIF);
 
@@ -1011,7 +1021,7 @@ void LLViewerObjectList::renderObjectBeacons()
 	
 	{
 		LLGLSNoTexture gls_ui_no_texture;
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		for (i = 0; i < mDebugBeacons.count(); i++)
 		{
 			const LLDebugBeacon &debug_beacon = mDebugBeacons[i];
@@ -1020,31 +1030,32 @@ void LLViewerObjectList::renderObjectBeacons()
 			S32 line_width = debug_beacon.mLineWidth;
 			if (line_width != last_line_width)
 			{
-				glEnd();
+				gGL.end();
+				gGL.flush();
 				glLineWidth( (F32)line_width );
 				last_line_width = line_width;
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 			}
 
 			const LLVector3 &thisline = debug_beacon.mPositionAgent;
-			glColor4fv(color.mV);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 50.f);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 50.f);
-			glVertex3f(thisline.mV[VX] - 2.f,thisline.mV[VY],thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX] + 2.f,thisline.mV[VY],thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY] - 2.f,thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY] + 2.f,thisline.mV[VZ]);
+			gGL.color4fv(color.mV);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 50.f);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 50.f);
+			gGL.vertex3f(thisline.mV[VX] - 2.f,thisline.mV[VY],thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX] + 2.f,thisline.mV[VY],thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] - 2.f,thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] + 2.f,thisline.mV[VZ]);
 
 			draw_line_cube(0.10f, thisline);
 		}
-		glEnd();
+		gGL.end();
 	}
 
 	{
 		LLGLSNoTexture gls_ui_no_texture;
 		LLGLDepthTest gls_depth(GL_TRUE);
 		
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		last_line_width = -1;
 		for (i = 0; i < mDebugBeacons.count(); i++)
 		{
@@ -1053,25 +1064,27 @@ void LLViewerObjectList::renderObjectBeacons()
 			S32 line_width = debug_beacon.mLineWidth;
 			if (line_width != last_line_width)
 			{
-				glEnd();
+				gGL.end();
+				gGL.flush();
 				glLineWidth( (F32)line_width );
 				last_line_width = line_width;
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 			}
 
 			const LLVector3 &thisline = debug_beacon.mPositionAgent;
-			glColor4fv(debug_beacon.mColor.mV);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 0.5f);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 0.5f);
-			glVertex3f(thisline.mV[VX] - 0.5f,thisline.mV[VY],thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX] + 0.5f,thisline.mV[VY],thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY] - 0.5f,thisline.mV[VZ]);
-			glVertex3f(thisline.mV[VX],thisline.mV[VY] + 0.5f,thisline.mV[VZ]);
+			gGL.color4fv(debug_beacon.mColor.mV);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] - 0.5f);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY],thisline.mV[VZ] + 0.5f);
+			gGL.vertex3f(thisline.mV[VX] - 0.5f,thisline.mV[VY],thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX] + 0.5f,thisline.mV[VY],thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] - 0.5f,thisline.mV[VZ]);
+			gGL.vertex3f(thisline.mV[VX],thisline.mV[VY] + 0.5f,thisline.mV[VZ]);
 
 			draw_line_cube(0.10f, thisline);
 		}
-		glEnd();
+		gGL.end();
 	
+		gGL.flush();
 		glLineWidth(1.f);
 
 		for (i = 0; i < mDebugBeacons.count(); i++)
diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp
index 22aa7bebd22..236fdaf70f1 100644
--- a/indra/newview/llhudeffectbeam.cpp
+++ b/indra/newview/llhudeffectbeam.cpp
@@ -274,51 +274,6 @@ void LLHUDEffectBeam::render()
 
 	// Init the color of the particles
 	LLColor4U coloru = mColor;
-
-	/*
-	// This is disabled for now - DJS
-
-	// Fade the alpha
-	coloru.mV[3] = mFadeInterp.getCurVal()*mColor.mV[3];
-
-	// Draw a regular "beam" that connects the source and target
-
-	// First, figure out start and end positions relative to the camera
-	LLVector3 start_pos_agent;
-	if (mSourceObject->getPCode() == LL_PCODE_LEGACY_AVATAR)
-	{
-		LLViewerObject *objp = mSourceObject;
-		LLVOAvatar *avatarp = (LLVOAvatar *)objp;
-		LLVector3d hand_pos_global = gAgent.getPosGlobalFromAgent(avatarp->mWristLeftp->getWorldPosition());
-		start_pos_agent = gAgent.getPosAgentFromGlobal(hand_pos_global);
-	}
-	else
-	{
-		start_pos_agent = mSourceObject->getPositionAgent();
-	}
-	LLVector3 start_pos_camera = (start_pos_agent - gAgent.getCameraPositionAgent());
-	LLVector3 target_pos_agent = gAgent.getPosAgentFromGlobal(mTargetPos);
-	LLVector3 target_pos_camera = target_pos_agent - gAgent.getCameraPositionAgent();
-
-	// Generate the right "up" vector which is perpendicular to the beam, make it 1/10 meter wide, going to a point.
-	LLVector3 camera_up = gCamera->getUpAxis();
-	LLVector3 camera_at = gCamera->getAtAxis();
-	LLVector3 up = target_pos_camera % start_pos_camera;
-	up.normVec();
-	up *= 0.1f;
-
-	// Draw the triangle for the beam.
-	LLVector3 vertex;
-	glColor4ubv(coloru.mV);
-	glBegin(GL_TRIANGLE_STRIP);
-	vertex = start_pos_agent + up;
-	glVertex3fv(vertex.mV);
-	vertex = start_pos_agent - up;
-	glVertex3fv(vertex.mV);
-	vertex = target_pos_agent;
-	glVertex3fv(vertex.mV);
-	glEnd();
-	*/
 	
 	// Draw the particles
 	S32 i;
diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp
index 16c77149d53..920a1caaf36 100644
--- a/indra/newview/llhudeffectlookat.cpp
+++ b/indra/newview/llhudeffectlookat.cpp
@@ -33,6 +33,8 @@
 
 #include "llhudeffectlookat.h"
 
+#include "llglimmediate.h"
+
 #include "message.h"
 #include "llagent.h"
 #include "llvoavatar.h"
@@ -498,19 +500,19 @@ void LLHUDEffectLookAt::render()
 		glPushMatrix();
 		glTranslatef(target.mV[VX], target.mV[VY], target.mV[VZ]);
 		glScalef(0.3f, 0.3f, 0.3f);
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		{
 			LLColor3 color = (*mAttentions)[mTargetType].mColor;
-			glColor3f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
-			glVertex3f(-1.f, 0.f, 0.f);
-			glVertex3f(1.f, 0.f, 0.f);
+			gGL.color3f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
+			gGL.vertex3f(-1.f, 0.f, 0.f);
+			gGL.vertex3f(1.f, 0.f, 0.f);
 
-			glVertex3f(0.f, -1.f, 0.f);
-			glVertex3f(0.f, 1.f, 0.f);
+			gGL.vertex3f(0.f, -1.f, 0.f);
+			gGL.vertex3f(0.f, 1.f, 0.f);
 
-			glVertex3f(0.f, 0.f, -1.f);
-			glVertex3f(0.f, 0.f, 1.f);
-		} glEnd();
+			gGL.vertex3f(0.f, 0.f, -1.f);
+			gGL.vertex3f(0.f, 0.f, 1.f);
+		} gGL.end();
 		glPopMatrix();
 	}
 }
diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp
index fbb5ba5d62c..2679ed5fbb8 100644
--- a/indra/newview/llhudeffectpointat.cpp
+++ b/indra/newview/llhudeffectpointat.cpp
@@ -34,6 +34,7 @@
 #include "llhudeffectpointat.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 
 #include "llagent.h"
 #include "lldrawable.h"
@@ -329,18 +330,18 @@ void LLHUDEffectPointAt::render()
 		glPushMatrix();
 		glTranslatef(target.mV[VX], target.mV[VY], target.mV[VZ]);
 		glScalef(0.3f, 0.3f, 0.3f);
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		{
-			glColor3f(1.f, 0.f, 0.f);
-			glVertex3f(-1.f, 0.f, 0.f);
-			glVertex3f(1.f, 0.f, 0.f);
+			gGL.color3f(1.f, 0.f, 0.f);
+			gGL.vertex3f(-1.f, 0.f, 0.f);
+			gGL.vertex3f(1.f, 0.f, 0.f);
 
-			glVertex3f(0.f, -1.f, 0.f);
-			glVertex3f(0.f, 1.f, 0.f);
+			gGL.vertex3f(0.f, -1.f, 0.f);
+			gGL.vertex3f(0.f, 1.f, 0.f);
 
-			glVertex3f(0.f, 0.f, -1.f);
-			glVertex3f(0.f, 0.f, 1.f);
-		} glEnd();
+			gGL.vertex3f(0.f, 0.f, -1.f);
+			gGL.vertex3f(0.f, 0.f, 1.f);
+		} gGL.end();
 		glPopMatrix();
 	}
 }
diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp
index 248ee8136e3..da734d61041 100644
--- a/indra/newview/llhudeffecttrail.cpp
+++ b/indra/newview/llhudeffecttrail.cpp
@@ -250,7 +250,7 @@ void LLHUDEffectSpiral::triggerLocal()
 			psb->setColor(color);
 			if (mTargetObject.isNull())
 			{
-				psb->mLKGTargetPosGlobal = mPositionGlobal;				
+				psb->mLKGTargetPosGlobal = mPositionGlobal;
 			}
 		}
 		else
@@ -277,10 +277,10 @@ void LLHUDEffectSpiral::render()
 {
 	F32 time = mTimer.getElapsedTimeF32();
 
-	if (!mSourceObject.isNull() && mSourceObject->isDead() ||
-		!mTargetObject.isNull() && mTargetObject->isDead() ||
-		mKillTime < time ||
-		!gSavedSettings.getBOOL("ShowSelectionBeam"))
+	if ((!mSourceObject.isNull() && mSourceObject->isDead()) ||
+	    (!mTargetObject.isNull() && mTargetObject->isDead()) ||
+	    mKillTime < time ||
+		(!mPartSourcep.isNull() && !gSavedSettings.getBOOL("ShowSelectionBeam")) )
 	{
 		markDead();
 		return;
diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp
index 229228f4da8..1260a268e31 100644
--- a/indra/newview/llhudicon.cpp
+++ b/indra/newview/llhudicon.cpp
@@ -34,6 +34,7 @@
 #include "llhudicon.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 
 #include "llviewerobject.h"
 #include "lldrawable.h"
@@ -83,8 +84,11 @@ void LLHUDIcon::renderIcon(BOOL for_select)
 {
 	LLGLSUIDefault texture_state;
 	LLGLDepthTest gls_depth(GL_TRUE);
-	LLGLState no_texture(GL_TEXTURE_2D, for_select ? FALSE : TRUE);
-
+	if (for_select)
+	{
+		LLViewerImage::unbindTexture(0);
+	}
+	
 	if (mHidden)
 		return;
 
@@ -152,28 +156,28 @@ void LLHUDIcon::renderIcon(BOOL for_select)
 	{
 		// set color to unique color id for picking
 		LLColor4U coloru((U8)(mPickID >> 16), (U8)(mPickID >> 8), (U8)mPickID);
-		glColor4ubv(coloru.mV);
+		gGL.color4ubv(coloru.mV);
 	}
 	else
 	{
 		LLColor4 icon_color = LLColor4::white;
 		icon_color.mV[VALPHA] = alpha_factor;
-		glColor4fv(icon_color.mV);
+		gGL.color4fv(icon_color.mV);
 		LLViewerImage::bindTexture(mImagep);
 	}
 
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
-		glTexCoord2f(0.f, 1.f);
-		glVertex3fv(upper_left.mV);
-		glTexCoord2f(0.f, 0.f);
-		glVertex3fv(lower_left.mV);
-		glTexCoord2f(1.f, 0.f);
-		glVertex3fv(lower_right.mV);
-		glTexCoord2f(1.f, 1.f);
-		glVertex3fv(upper_right.mV);
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex3fv(upper_left.mV);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex3fv(lower_left.mV);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex3fv(lower_right.mV);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex3fv(upper_right.mV);
 	}
-	glEnd();
+	gGL.end();
 }
 
 void LLHUDIcon::setImage(LLViewerImage* imagep)
diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp
index c08e9552fc4..30a09a96d33 100644
--- a/indra/newview/llhudmanager.cpp
+++ b/indra/newview/llhudmanager.cpp
@@ -37,7 +37,6 @@
 #include "object_flags.h"
 
 #include "llagent.h"
-#include "llhudconnector.h"
 #include "llhudeffect.h"
 #include "pipeline.h"
 #include "llviewercontrol.h"
@@ -91,7 +90,7 @@ void LLHUDManager::sendEffects()
 			llwarns << "Trying to send dead effect!" << llendl;
 			continue;
 		}
-		if (hep->mType <= LLHUDObject::LL_HUD_CONNECTOR)
+		if (hep->mType < LLHUDObject::LL_HUD_EFFECT_BEAM)
 		{
 			llwarns << "Trying to send effect of type " << hep->mType << " which isn't really an effect and shouldn't be in this list!" << llendl;
 			continue;
diff --git a/indra/newview/llhudmanager.h b/indra/newview/llhudmanager.h
index 2f8c1a1ec7b..934bcf44a1c 100644
--- a/indra/newview/llhudmanager.h
+++ b/indra/newview/llhudmanager.h
@@ -36,9 +36,6 @@
 
 #include "llhudobject.h"
 #include "lldarray.h"
-#include "llanimalcontrols.h"
-#include "lllocalanimationobject.h"
-#include "llcape.h"
 
 class LLViewerObject;
 class LLHUDEffect;
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 6271f0f3777..d6bafa9b585 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -39,17 +39,11 @@
 
 #include "llhudtext.h"
 #include "llhudicon.h"
-#include "llhudconnector.h"
 #include "llhudeffectbeam.h"
 #include "llhudeffecttrail.h"
 #include "llhudeffectlookat.h"
 
-//Ventrella
 #include "llvoicevisualizer.h"
-#include "llanimalcontrols.h"
-#include "lllocalanimationobject.h"
-#include "llcape.h"
-// End Ventrella
 
 #include "llagent.h"
 
@@ -155,9 +149,6 @@ LLHUDObject *LLHUDObject::addHUDObject(const U8 type)
 	case LL_HUD_ICON:
 		hud_objectp = new LLHUDIcon(type);
 		break;
-	case LL_HUD_CONNECTOR:
-		hud_objectp = new LLHUDConnector(type);
-		break;
 	default:
 		llwarns << "Unknown type of hud object:" << (U32) type << llendl;
 	}
diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp
index df1fdf175fe..bdbc849dc2a 100644
--- a/indra/newview/llhudrender.cpp
+++ b/indra/newview/llhudrender.cpp
@@ -100,16 +100,10 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
 	LLVector3 render_pos = pos_agent + (floorf(x_offset) * right_axis) + (floorf(y_offset) * up_axis);
 
 	//get the render_pos in screen space
-	F64 modelview[16];
-	F64 projection[16];
-	GLint viewport[4];
-	glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
-	glGetDoublev(GL_PROJECTION_MATRIX, projection);
-	glGetIntegerv(GL_VIEWPORT, viewport);
-
+	
 	F64 winX, winY, winZ;
 	gluProject(render_pos.mV[0], render_pos.mV[1], render_pos.mV[2],
-				modelview, projection, viewport,
+				gGLModelView, gGLProjection, (GLint*) gGLViewport,
 				&winX, &winY, &winZ);
 		
 	//fonts all render orthographically, set up projection
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 1d684412315..0468ae5a1ad 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -33,6 +33,8 @@
 
 #include "llhudtext.h"
 
+#include "llglimmediate.h"
+
 #include "llagent.h"
 #include "llviewercontrol.h"
 #include "llchatbar.h"
@@ -262,7 +264,7 @@ void LLHUDText::renderText(BOOL for_select)
 				LLGLSNoTexture no_texture_state;
 				S32 name = mSourceObject->mGLName;
 				LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name);
-				glColor4ubv(coloru.mV);
+				gGL.color4ubv(coloru.mV);
 				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
 				LLUI::popMatrix();
 				return;
@@ -271,14 +273,14 @@ void LLHUDText::renderText(BOOL for_select)
 			{
 				LLViewerImage::bindTexture(imagep);
 				
-				glColor4fv(bg_color.mV);
+				gGL.color4fv(bg_color.mV);
 				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec);
 		
 				if ( mLabelSegments.size())
 				{
 					LLUI::pushMatrix();
 					{
-						glColor4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
+						gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);
 						LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec;
 						LLVector3 label_offset = height_vec - label_height;
 						LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]);
@@ -296,7 +298,7 @@ void LLHUDText::renderText(BOOL for_select)
 			{
 				LLUI::pushMatrix();
 				{
-					glColor4fv(bg_color.mV);
+					gGL.color4fv(bg_color.mV);
 					LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec);
 					target_pos += (width_vec / 2.f);
 					target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero;
@@ -308,15 +310,15 @@ void LLHUDText::renderText(BOOL for_select)
 				LLUI::popMatrix();
 
 				
-				LLGLDisable gls_texture_2d(GL_TEXTURE_2D);
+				LLImageGL::unbindTexture(0);
 				LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE);
 				
 				LLVector3 box_center_offset;
 				box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f);
 				LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]);
-				glColor4fv(bg_color.mV);
+				gGL.color4fv(bg_color.mV);
 				LLUI::setLineWidth(2.0);
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
 					if (outside_width)
 					{
@@ -326,20 +328,20 @@ void LLHUDText::renderText(BOOL for_select)
 						{
 							// start at right edge
 							vert = width_vec * 0.5f;
-							glVertex3fv(vert.mV);
+							gGL.vertex3fv(vert.mV);
 						}
 						else
 						{
 							// start at left edge
 							vert = width_vec * -0.5f;
-							glVertex3fv(vert.mV);
+							gGL.vertex3fv(vert.mV);
 						}
 						vert = -mPositionOffset.mV[VX] * x_pixel_vec;
-						glVertex3fv(vert.mV);
-						glVertex3fv(vert.mV);
+						gGL.vertex3fv(vert.mV);
+						gGL.vertex3fv(vert.mV);
 						vert -= mPositionOffset.mV[VY] * y_pixel_vec;
 						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
-						glVertex3fv(vert.mV);
+						gGL.vertex3fv(vert.mV);
 					}
 					else
 					{
@@ -349,20 +351,20 @@ void LLHUDText::renderText(BOOL for_select)
 						{
 							// start at top edge
 							vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec);
-							glVertex3fv(vert.mV);
+							gGL.vertex3fv(vert.mV);
 						}
 						else
 						{
 							// start at bottom edge
 							vert = (height_vec * -0.5f)  - (mPositionOffset.mV[VX] * x_pixel_vec);
-							glVertex3fv(vert.mV);
+							gGL.vertex3fv(vert.mV);
 						}
 						vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec;
 						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero);
-						glVertex3fv(vert.mV);
+						gGL.vertex3fv(vert.mV);
 					}
 				}
-				glEnd();
+				gGL.end();
 				LLUI::setLineWidth(1.0);
 
 			}
@@ -441,6 +443,8 @@ void LLHUDText::renderText(BOOL for_select)
 			hud_render_text(segment_iter->getText(), render_position, *fontp, style, x_offset, y_offset, text_color, mOnHUDAttachment);
 		}
 	}
+	/// Reset the default color to white.  The renderer expects this to be the default. 
+	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 }
 
 void LLHUDText::setStringUTF8(const std::string &wtext)
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index 9e0fa26f255..0027036b36b 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -36,6 +36,7 @@
 // Library includes
 #include "llcoord.h"
 #include "indra_constants.h"
+#include "llglimmediate.h"
 
 // Project includes
 #include "llui.h"
@@ -652,23 +653,23 @@ void LLJoystickCameraRotate::drawRotatedImage( const LLImageGL* image, S32 rotat
 
 	image->bind();
 
-	glColor4fv(UI_VERTEX_COLOR.mV);
+	gGL.color4fv(UI_VERTEX_COLOR.mV);
 	
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
-		glTexCoord2fv( uv[ (rotations + 0) % 4]);
-		glVertex2i(width, height );
+		gGL.texCoord2fv( uv[ (rotations + 0) % 4]);
+		gGL.vertex2i(width, height );
 
-		glTexCoord2fv( uv[ (rotations + 1) % 4]);
-		glVertex2i(0, height );
+		gGL.texCoord2fv( uv[ (rotations + 1) % 4]);
+		gGL.vertex2i(0, height );
 
-		glTexCoord2fv( uv[ (rotations + 2) % 4]);
-		glVertex2i(0, 0);
+		gGL.texCoord2fv( uv[ (rotations + 2) % 4]);
+		gGL.vertex2i(0, 0);
 
-		glTexCoord2fv( uv[ (rotations + 3) % 4]);
-		glVertex2i(width, 0);
+		gGL.texCoord2fv( uv[ (rotations + 3) % 4]);
+		gGL.vertex2i(width, 0);
 	}
-	glEnd();
+	gGL.end();
 }
 
 
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index 44b919aa616..9b6ef2d0790 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -35,8 +35,8 @@
 
 #include "llmath.h"
 #include "v3math.h"
-//#include "llquaternion.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llprimitive.h"
 #include "llview.h"
 #include "llviewerimagelist.h"
@@ -78,11 +78,13 @@ void LLManip::rebuild(LLViewerObject* vobj)
 	{
 		
 		gPipeline.markRebuild(drawablep,LLDrawable::REBUILD_VOLUME, TRUE);
-		//gPipeline.markMoved(drawablep, FALSE);
-		//gPipeline.updateMoveNormalAsync(vobj->mDrawable);
-
 		drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
 		drawablep->updateMove();
+		LLSpatialGroup* group = drawablep->getSpatialGroup();
+		if (group)
+		{
+			group->dirtyGeom();
+		}
 	}
 }
 
@@ -388,29 +390,29 @@ void LLManip::renderGuidelines(BOOL draw_x, BOOL draw_y, BOOL draw_z)
 
 		if (draw_x)
 		{
-			glColor4f(1.f, 0.f, 0.f, LINE_ALPHA);
-			glBegin(GL_LINES);
-			glVertex3f( -region_size, 0.f, 0.f );
-			glVertex3f(  region_size, 0.f, 0.f );
-			glEnd();
+			gGL.color4f(1.f, 0.f, 0.f, LINE_ALPHA);
+			gGL.begin(GL_LINES);
+			gGL.vertex3f( -region_size, 0.f, 0.f );
+			gGL.vertex3f(  region_size, 0.f, 0.f );
+			gGL.end();
 		}
 
 		if (draw_y)
 		{
-			glColor4f(0.f, 1.f, 0.f, LINE_ALPHA);
-			glBegin(GL_LINES);
-			glVertex3f( 0.f, -region_size, 0.f );
-			glVertex3f( 0.f,  region_size, 0.f );
-			glEnd();
+			gGL.color4f(0.f, 1.f, 0.f, LINE_ALPHA);
+			gGL.begin(GL_LINES);
+			gGL.vertex3f( 0.f, -region_size, 0.f );
+			gGL.vertex3f( 0.f,  region_size, 0.f );
+			gGL.end();
 		}
 
 		if (draw_z)
 		{
-			glColor4f(0.f, 0.f, 1.f, LINE_ALPHA);
-			glBegin(GL_LINES);
-			glVertex3f( 0.f, 0.f, -region_size );
-			glVertex3f( 0.f, 0.f,  region_size );
-			glEnd();
+			gGL.color4f(0.f, 0.f, 1.f, LINE_ALPHA);
+			gGL.begin(GL_LINES);
+			gGL.vertex3f( 0.f, 0.f, -region_size );
+			gGL.vertex3f( 0.f, 0.f,  region_size );
+			gGL.end();
 		}
 		LLUI::setLineWidth(1.0f);
 	}
@@ -435,7 +437,7 @@ void LLManip::renderXYZ(const LLVector3 &vec)
 		gViewerWindow->setup2DRender();
 		const LLVector2& display_scale = gViewerWindow->getDisplayScale();
 		glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
-		glColor4f(0.f, 0.f, 0.f, 0.7f);
+		gGL.color4f(0.f, 0.f, 0.f, 0.7f);
 
 		gl_draw_scaled_image_with_border(window_center_x - 115, 
 			window_center_y + vertical_offset - PAD, 
@@ -453,7 +455,6 @@ void LLManip::renderXYZ(const LLVector3 &vec)
 	{
 		LLLocale locale(LLLocale::USER_LOCALE);
 		LLGLDepthTest gls_depth(GL_FALSE);
-		LLGLEnable tex(GL_TEXTURE_2D);
 		// render drop shadowed text
 		snprintf(feedback_string, sizeof(feedback_string), "X: %.3f", vec.mV[VX]);			/* Flawfinder: ignore */
 		hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *gResMgr->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, -102.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE);
@@ -497,7 +498,6 @@ void LLManip::renderTickText(const LLVector3& pos, const char* text, const LLCol
 
 	// render shadow first
 	LLColor4 shadow_color = LLColor4::black;
-	LLGLEnable tex(GL_TEXTURE_2D);
 	shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f;
 	gViewerWindow->setupViewport(1, -1);
 	hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(text), 3.f, shadow_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
@@ -557,7 +557,6 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const char* suffi
 	LLColor4 shadow_color = LLColor4::black;
 	shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f;
 
-	LLGLEnable tex(GL_TEXTURE_2D);
 	if (fractional_portion != 0)
 	{
 		snprintf(fraction_string, sizeof(fraction_string), "%c%02d%s", gResMgr->getDecimalPoint(), fractional_portion, suffix);			/* Flawfinder: ignore */
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 2e4f66c9290..fb85c81d017 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -36,6 +36,7 @@
 // library includes
 #include "llmath.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v4color.h"
 #include "llprimitive.h"
 #include "llview.h"
@@ -205,7 +206,7 @@ void LLManipRotate::render()
 
 				if (mManipPart == LL_NO_PART)
 				{
-					glColor4f( 0.7f, 0.7f, 0.7f, 0.3f );
+					gGL.color4f( 0.7f, 0.7f, 0.7f, 0.3f );
 					gl_circle_2d( 0, 0,  mRadiusMeters, CIRCLE_STEPS, TRUE );
 				}
 				
@@ -839,7 +840,7 @@ void LLManipRotate::renderSnapGuides()
 
 			LLColor4 line_color = setupSnapGuideRenderPass(pass);
 
-			glColor4fv(line_color.mV);
+			gGL.color4fv(line_color.mV);
 
 			if (mCamEdgeOn)
 			{
@@ -868,7 +869,7 @@ void LLManipRotate::renderSnapGuides()
 				LLVector3 outer_point;
 				LLVector3 text_point;
 				LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis);
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
 					inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center;
 					F32 tick_length = 0.f;
@@ -921,10 +922,10 @@ void LLManipRotate::renderSnapGuides()
 
 					text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot;
 
-					glVertex3fv(inner_point.mV);
-					glVertex3fv(outer_point.mV);
+					gGL.vertex3fv(inner_point.mV);
+					gGL.vertex3fv(outer_point.mV);
 				}
-				glEnd();
+				gGL.end();
 
 				//RN: text rendering does own shadow pass, so only render once
 				if (pass == 1 && render_text && i % 16 == 0)
@@ -1029,7 +1030,7 @@ void LLManipRotate::renderSnapGuides()
 						}
 					}
 				}
-				glColor4fv(line_color.mV);
+				gGL.color4fv(line_color.mV);
 			}
 
 			// now render projected object axis
@@ -1046,15 +1047,15 @@ void LLManipRotate::renderSnapGuides()
 				object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center;
 				LLVector3 line_start = center;
 
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
-					glVertex3fv(line_start.mV);
-					glVertex3fv(object_axis.mV);
+					gGL.vertex3fv(line_start.mV);
+					gGL.vertex3fv(object_axis.mV);
 				}
-				glEnd();
+				gGL.end();
 
 				// draw snap guide arrow
-				glBegin(GL_TRIANGLES);
+				gGL.begin(GL_TRIANGLES);
 				{
 					LLVector3 arrow_dir;
 					LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
@@ -1066,23 +1067,23 @@ void LLManipRotate::renderSnapGuides()
 					{
 						arrow_dir *= -1.f;
 					}
-					glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
-					glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
-					glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
+					gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
+					gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
+					gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
 				}
-				glEnd();
+				gGL.end();
 
 				{
 					LLGLDepthTest gls_depth(GL_TRUE);
-					glBegin(GL_LINES);
+					gGL.begin(GL_LINES);
 					{
-						glVertex3fv(line_start.mV);
-						glVertex3fv(object_axis.mV);
+						gGL.vertex3fv(line_start.mV);
+						gGL.vertex3fv(object_axis.mV);
 					}
-					glEnd();
+					gGL.end();
 
 					// draw snap guide arrow
-					glBegin(GL_TRIANGLES);
+					gGL.begin(GL_TRIANGLES);
 					{
 						LLVector3 arrow_dir;
 						LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
@@ -1095,11 +1096,11 @@ void LLManipRotate::renderSnapGuides()
 							arrow_dir *= -1.f;
 						}
 
-						glVertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
-						glVertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
-						glVertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
+						gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
+						gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
+						gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
 					}
-					glEnd();
+					gGL.end();
 				}
 			}
 		}
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index a67e3fcce60..457682a1547 100644
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -38,6 +38,7 @@
 #include "v3math.h"
 #include "llquaternion.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v4color.h"
 #include "llprimitive.h"
 
@@ -47,7 +48,6 @@
 #include "llbox.h"
 #include "llviewercontrol.h"
 #include "llcriticaldamp.h"
-#include "llcylinder.h"
 #include "lldrawable.h"
 #include "llfloatertools.h"
 #include "llglheaders.h"
@@ -145,15 +145,15 @@ inline void LLManipScale::conditionalHighlight( U32 part, const LLColor4* highli
 	mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale;
 	if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part)
 	{
-		glColor4fv( invisible.mV );
+		gGL.color4fv( invisible.mV );
 	}
 	else if( mHighlightedPart == (S32)part )
 	{
-		glColor4fv( highlight ? highlight->mV : default_highlight.mV );
+		gGL.color4fv( highlight ? highlight->mV : default_highlight.mV );
 	}
 	else
 	{
-		glColor4fv( normal ? normal->mV : default_normal.mV  );
+		gGL.color4fv( normal ? normal->mV : default_normal.mV  );
 	}
 }
 
@@ -600,47 +600,47 @@ void LLManipScale::renderFaces( const LLBBox& bbox )
 
 	if (mManipPart == LL_NO_PART)
 	{
-		glColor4fv( default_normal_color.mV );
+		gGL.color4fv( default_normal_color.mV );
 		LLGLDepthTest gls_depth(GL_FALSE);
-		glBegin(GL_QUADS); 
+		gGL.begin(GL_QUADS); 
 		{
 			// Face 0
-			glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
-			glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
-			glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
 
 			// Face 1
-			glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
-			glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
 
 			// Face 2
-			glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
-			glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
 
 			// Face 3
-			glVertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
-			glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
-			glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
-			glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
 
 			// Face 4
-			glVertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
-			glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
 
 			// Face 5
-			glVertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
-			glVertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
-			glVertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
+			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
 		}
-		glEnd();
+		gGL.end();
 	}
 
 	// Find nearest vertex
@@ -763,7 +763,7 @@ void LLManipScale::renderCorners( const LLBBox& bbox )
 
 void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z )
 {
-	LLGLDisable gls_tex(GL_TEXTURE_2D);
+	LLImageGL::unbindTexture(0);
 	LLGLDepthTest gls_depth(GL_FALSE);
 
 	glPushMatrix();
@@ -1536,29 +1536,29 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
 	{
 		LLColor4 tick_color = setupSnapGuideRenderPass(pass);
 
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		LLVector3 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset);
 		LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
 		LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f));
 		
-		glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
-		glVertex3fv(line_start.mV);
-		glColor4fv(tick_color.mV);
-		glVertex3fv(line_mid.mV);
-		glVertex3fv(line_mid.mV);
-		glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
-		glVertex3fv(line_end.mV);
+		gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
+		gGL.vertex3fv(line_start.mV);
+		gGL.color4fv(tick_color.mV);
+		gGL.vertex3fv(line_mid.mV);
+		gGL.vertex3fv(line_mid.mV);
+		gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
+		gGL.vertex3fv(line_end.mV);
 
 		line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset);
 		line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
 		line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f));
-		glVertex3fv(line_start.mV);
-		glColor4fv(tick_color.mV);
-		glVertex3fv(line_mid.mV);
-		glVertex3fv(line_mid.mV);
-		glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
-		glVertex3fv(line_end.mV);
-		glEnd();
+		gGL.vertex3fv(line_start.mV);
+		gGL.color4fv(tick_color.mV);
+		gGL.vertex3fv(line_mid.mV);
+		gGL.vertex3fv(line_mid.mV);
+		gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
+		gGL.vertex3fv(line_end.mV);
+		gGL.end();
 	}
 
 	{
@@ -1587,41 +1587,41 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
 		if (mInSnapRegime)
 		{
 			// draw snap guide line
-			glBegin(GL_LINES);
+			gGL.begin(GL_LINES);
 			LLVector3 snap_line_center = mScaleCenter + (mScaleSnapValue * mScaleDir);
 
 			LLVector3 snap_line_start = snap_line_center + (mSnapGuideDir1 * mSnapRegimeOffset);
 			LLVector3 snap_line_end = snap_line_center + (mSnapGuideDir2 * mSnapRegimeOffset);
 
-			glColor4f(1.f, 1.f, 1.f, grid_alpha);
-			glVertex3fv(snap_line_start.mV);
-			glVertex3fv(snap_line_center.mV);
-			glVertex3fv(snap_line_center.mV);
-			glVertex3fv(snap_line_end.mV);
-			glEnd();
+			gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
+			gGL.vertex3fv(snap_line_start.mV);
+			gGL.vertex3fv(snap_line_center.mV);
+			gGL.vertex3fv(snap_line_center.mV);
+			gGL.vertex3fv(snap_line_end.mV);
+			gGL.end();
 
 			// draw snap guide arrow
-			glBegin(GL_TRIANGLES);
+			gGL.begin(GL_TRIANGLES);
 			{
 				//gGLSNoCullFaces.set();
-				glColor4f(1.f, 1.f, 1.f, grid_alpha);
+				gGL.color4f(1.f, 1.f, 1.f, grid_alpha);
 
 				LLVector3 arrow_dir;
 				LLVector3 arrow_span = mScaleDir;
 
 				arrow_dir = snap_line_start - snap_line_center;
 				arrow_dir.normVec();
-				glVertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV);
-				glVertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV);
-				glVertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV);
 
 				arrow_dir = snap_line_end - snap_line_center;
 				arrow_dir.normVec();
-				glVertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV);
-				glVertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV);
-				glVertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV);
+				gGL.vertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV);
 			}
-			glEnd();
+			gGL.end();
 		}
 	
 		LLVector2 screen_translate_axis(llabs(mScaleDir * gCamera->getLeftAxis()), llabs(mScaleDir * gCamera->getUpAxis()));
@@ -1636,7 +1636,7 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
 			start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1));
 			stop_tick = llmin(max_ticks1, num_ticks_per_side1);
 
-			glBegin(GL_LINES);
+			gGL.begin(GL_LINES);
 			// draw first row of ticks
 			for (S32 i = start_tick; i <= stop_tick; i++)
 			{
@@ -1660,16 +1660,17 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
 					tick_scale *= 0.7f;
 				}
 
-				glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
+				gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
 				LLVector3 tick_start = tick_pos + (mSnapGuideDir1 * mSnapRegimeOffset);
 				LLVector3 tick_end = tick_start + (mSnapGuideDir1 * mSnapRegimeOffset * tick_scale);
-				glVertex3fv(tick_start.mV);
-				glVertex3fv(tick_end.mV);
+				gGL.vertex3fv(tick_start.mV);
+				gGL.vertex3fv(tick_end.mV);
 			}
 
 			// draw opposite row of ticks
 			start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2));
 			stop_tick = llmin(max_ticks2, num_ticks_per_side2);
+
 			for (S32 i = start_tick; i <= stop_tick; i++)
 			{
 				F32 alpha = (1.f - (1.f *  ((F32)llabs(i) / (F32)num_ticks_per_side2)));
@@ -1692,13 +1693,13 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
 					tick_scale *= 0.7f;
 				}
 
-				glColor4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
+				gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * alpha);
 				LLVector3 tick_start = tick_pos + (mSnapGuideDir2 * mSnapRegimeOffset);
 				LLVector3 tick_end = tick_start + (mSnapGuideDir2 * mSnapRegimeOffset * tick_scale);
-				glVertex3fv(tick_start.mV);
-				glVertex3fv(tick_end.mV);
+				gGL.vertex3fv(tick_start.mV);
+				gGL.vertex3fv(tick_end.mV);
 			}
-			glEnd();
+			gGL.end();
 		}
 
 		// render tick labels
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 2f5f154b772..3182f149517 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -38,6 +38,7 @@
 #include "llmaniptranslate.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 
 #include "llagent.h"
 #include "llbbox.h"
@@ -140,7 +141,6 @@ void LLManipTranslate::restoreGL()
 	U32 mip = 0;
 
 	GLuint* d = new GLuint[rez*rez];
-	LLGLEnable tex2d(GL_TEXTURE_2D);
 	glGenTextures(1, &sGridTex);
 	glBindTexture(GL_TEXTURE_2D, sGridTex);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
@@ -1057,7 +1057,7 @@ BOOL LLManipTranslate::handleMouseUp(S32 x, S32 y, MASK mask)
 void LLManipTranslate::render()
 {
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 	{
 		F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
@@ -1071,7 +1071,7 @@ void LLManipTranslate::render()
 		renderTranslationHandles();
 		renderSnapGuides();
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 
 	renderText();
 }
@@ -1257,31 +1257,31 @@ void LLManipTranslate::renderSnapGuides()
 		{
 			LLColor4 line_color = setupSnapGuideRenderPass(pass);
 
-			glBegin(GL_LINES);
+			gGL.begin(GL_LINES);
 			{
 				LLVector3 line_start = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) + (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit));
 				LLVector3 line_end = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) - (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit));
 				LLVector3 line_mid = (line_start + line_end) * 0.5f;
 
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
-				glVertex3fv(line_start.mV);
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
-				glVertex3fv(line_mid.mV);
-				glVertex3fv(line_mid.mV);
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
-				glVertex3fv(line_end.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
+				gGL.vertex3fv(line_start.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
+				gGL.vertex3fv(line_mid.mV);
+				gGL.vertex3fv(line_mid.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
+				gGL.vertex3fv(line_end.mV);
 
 				line_start.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) + (translate_axis * guide_size_meters * 0.5f));
 				line_end.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) - (translate_axis * guide_size_meters * 0.5f));
 				line_mid = (line_start + line_end) * 0.5f;
 
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
-				glVertex3fv(line_start.mV);
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
-				glVertex3fv(line_mid.mV);
-				glVertex3fv(line_mid.mV);
-				glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
-				glVertex3fv(line_end.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
+				gGL.vertex3fv(line_start.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
+				gGL.vertex3fv(line_mid.mV);
+				gGL.vertex3fv(line_mid.mV);
+				gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f);
+				gGL.vertex3fv(line_end.mV);
 
 				for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++)
 				{
@@ -1314,53 +1314,53 @@ void LLManipTranslate::renderSnapGuides()
 
 					tick_end = tick_start + (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale);
 
-					glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
-					glVertex3fv(tick_start.mV);
-					glVertex3fv(tick_end.mV);
+					gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
+					gGL.vertex3fv(tick_start.mV);
+					gGL.vertex3fv(tick_end.mV);
 
 					tick_start = selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) +
 						(translate_axis * (getMinGridScale() / (F32)(max_subdivisions) * (F32)i - offset_nearest_grid_unit));
 					tick_end = tick_start - (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale);
 
-					glVertex3fv(tick_start.mV);
-					glVertex3fv(tick_end.mV);
+					gGL.vertex3fv(tick_start.mV);
+					gGL.vertex3fv(tick_end.mV);
 				}
 			}
-			glEnd();
+			gGL.end();
 
 			if (mInSnapRegime)
 			{
 				LLVector3 line_start = selection_center - mSnapOffsetAxis * mSnapOffsetMeters;
 				LLVector3 line_end = selection_center + mSnapOffsetAxis * mSnapOffsetMeters;
 
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
-					glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
+					gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
 
-					glVertex3fv(line_start.mV);
-					glVertex3fv(line_end.mV);
+					gGL.vertex3fv(line_start.mV);
+					gGL.vertex3fv(line_end.mV);
 				}
-				glEnd();
+				gGL.end();
 
 				// draw snap guide arrow
-				glBegin(GL_TRIANGLES);
+				gGL.begin(GL_TRIANGLES);
 				{
-					glColor4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
+					gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]);
 
 					LLVector3 arrow_dir;
 					LLVector3 arrow_span = translate_axis;
 
 					arrow_dir = -mSnapOffsetAxis;
-					glVertex3fv((line_start + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV);
-					glVertex3fv((line_start + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
-					glVertex3fv((line_start - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_start + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_start + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_start - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
 
 					arrow_dir = mSnapOffsetAxis;
-					glVertex3fv((line_end + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV);
-					glVertex3fv((line_end + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
-					glVertex3fv((line_end - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_end + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_end + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
+					gGL.vertex3fv((line_end - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV);
 				}
-				glEnd();
+				gGL.end();
 			}
 		}
 
@@ -1444,7 +1444,6 @@ void LLManipTranslate::renderSnapGuides()
 				LLVector3 help_text_pos = selection_center_start + (snap_offset_meters_up * 3.f * mSnapOffsetAxis);
 				const LLFontGL* big_fontp = LLFontGL::sSansSerif;
 
-				LLGLSTexture gls_texture;
 				std::string help_text = "Move mouse cursor over ruler to snap";
 				LLColor4 help_text_color = LLColor4::white;
 				help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f);
@@ -1498,19 +1497,20 @@ void LLManipTranslate::renderSnapGuides()
 			break;
 		}
 
+		LLImageGL::unbindTexture(0);
 		highlightIntersection(normal, selection_center, grid_rotation, inner_color);
 
-		glPushMatrix();
+		gGL.pushMatrix();
 
 		F32 x,y,z,angle_radians;
 		grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
-		glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
+		gGL.translatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
 		glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
 		
 		F32 sz = mGridSizeMeters;
 		F32 tiles = sz;
 		glMatrixMode(GL_TEXTURE);
-		glPushMatrix();
+		gGL.pushMatrix();
 		usc = 1.0f/usc;
 		vsc = 1.0f/vsc;
 		
@@ -1524,37 +1524,41 @@ void LLManipTranslate::renderSnapGuides()
 		}
 
 		glScalef(usc, vsc, 1.0f);
-		glTranslatef(u, v, 0);
+		gGL.translatef(u, v, 0);
 		
 		float a = line_alpha;
 
 		LLColor4 col = gColors.getColor("SilhouetteChildColor");
 		{
 			//draw grid behind objects
-			LLGLSTexture tex2d;
 			LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
 
 			{
-				LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER);
-				glBindTexture(GL_TEXTURE_2D, sGridTex);
-				glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
-				renderGrid(u,v,tiles,0.9f, 0.9f, 0.9f,a*0.15f);
-				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-			}
-			
-			{
-				LLGLDisable alpha_test(GL_ALPHA_TEST);
-				//draw black overlay
-				glBindTexture(GL_TEXTURE_2D, 0);
-				renderGrid(u,v,tiles,0.0f, 0.0f, 0.0f,a*0.16f);
-
-				//draw grid top
-				glBindTexture(GL_TEXTURE_2D, sGridTex);
-				renderGrid(u,v,tiles,1,1,1,a);
-
-				glPopMatrix();
-				glMatrixMode(GL_MODELVIEW);
-				glPopMatrix();
+				LLGLDisable stencil(GL_STENCIL_TEST);
+				{
+					LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER);
+					glBindTexture(GL_TEXTURE_2D, sGridTex);
+					gGL.flush();
+					gGL.blendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
+					renderGrid(u,v,tiles,0.9f, 0.9f, 0.9f,a*0.15f);
+					gGL.flush();
+					gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				}
+				
+				{
+					LLGLDisable alpha_test(GL_ALPHA_TEST);
+					//draw black overlay
+					LLImageGL::unbindTexture(0);
+					renderGrid(u,v,tiles,0.0f, 0.0f, 0.0f,a*0.16f);
+
+					//draw grid top
+					glBindTexture(GL_TEXTURE_2D, sGridTex);
+					renderGrid(u,v,tiles,1,1,1,a);
+
+					gGL.popMatrix();
+					glMatrixMode(GL_MODELVIEW);
+					gGL.popMatrix();
+				}
 
 				{
 					LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
@@ -1564,6 +1568,7 @@ void LLManipTranslate::renderSnapGuides()
 				{
 					LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER);
 					LLGLEnable stipple(GL_LINE_STIPPLE);
+					gGL.flush();
 					glLineStipple(1, 0x3333);
 		
 					switch (mManipPart)
@@ -1580,6 +1585,7 @@ void LLManipTranslate::renderSnapGuides()
 					  default:
 						break;
 					}
+					gGL.flush();
 				}
 			}
 		}
@@ -1592,32 +1598,32 @@ void LLManipTranslate::renderGrid(F32 x, F32 y, F32 size, F32 r, F32 g, F32 b, F
 
 	for (F32 xx = -size-d; xx < size+d; xx += d)
 	{
-		glBegin(GL_TRIANGLE_STRIP);
+		gGL.begin(GL_TRIANGLE_STRIP);
 		for (F32 yy = -size-d; yy < size+d; yy += d)
 		{
 			float dx, dy, da;
 
 			dx = xx; dy = yy;
 			da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a;
-			glTexCoord2f(dx, dy);
+			gGL.texCoord2f(dx, dy);
 			renderGridVert(dx,dy,r,g,b,da);
 
 			dx = xx+d; dy = yy;
 			da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a;
-			glTexCoord2f(dx, dy);
+			gGL.texCoord2f(dx, dy);
 			renderGridVert(dx,dy,r,g,b,da);
 			
 			dx = xx; dy = yy+d;
 			da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a;
-			glTexCoord2f(dx, dy);
+			gGL.texCoord2f(dx, dy);
 			renderGridVert(dx,dy,r,g,b,da);
 
 			dx = xx+d; dy = yy+d;
 			da = sqrtf(llmax(0.0f, 1.0f-sqrtf(dx*dx+dy*dy)/size))*a;
-			glTexCoord2f(dx, dy);
+			gGL.texCoord2f(dx, dy);
 			renderGridVert(dx,dy,r,g,b,da);
 		}
-		glEnd();
+		gGL.end();
 	}
 
 	
@@ -1633,10 +1639,12 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 		return;
 	}
 	
-	U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_ALPHA, LLRenderPass::PASS_FULLBRIGHT };
+	U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_ALPHA, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY };
+	U32 num_types = sizeof(types)/sizeof(U32);
 
 	GLuint stencil_mask = 0xFFFFFFFF;
 	//stencil in volumes
+	gGL.stop();
 	{
 		glStencilMask(stencil_mask);
 		glClearStencil(1);
@@ -1646,7 +1654,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 		LLGLDepthTest depth (GL_TRUE, GL_FALSE, GL_ALWAYS);
 		glStencilFunc(GL_ALWAYS, 0, stencil_mask);
 		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-        LLGLDisable tex(GL_TEXTURE_2D);
+		LLImageGL::unbindTexture(0);
 		glColor4f(1,1,1,1);
 
 		//setup clip plane
@@ -1675,14 +1683,14 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 		//stencil in volumes
 		glStencilOp(GL_INCR, GL_INCR, GL_INCR);
 		glCullFace(GL_FRONT);
-		for (U32 i = 0; i < 3; i++)
+		for (U32 i = 0; i < num_types; i++)
 		{
 			gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
 		}
 
 		glStencilOp(GL_DECR, GL_DECR, GL_DECR);
 		glCullFace(GL_BACK);
-		for (U32 i = 0; i < 3; i++)
+		for (U32 i = 0; i < num_types; i++)
 		{
 			gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
 		}
@@ -1698,12 +1706,13 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 
 		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
 	}
+	gGL.start();
 
-	glPushMatrix();
+	gGL.pushMatrix();
 
 	F32 x,y,z,angle_radians;
 	grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
-	glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
+	gGL.translatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
 	glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
 	
 	F32 sz = mGridSizeMeters;
@@ -1711,7 +1720,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 
 	//draw volume/plane intersections
 	{
-		LLGLDisable tex(GL_TEXTURE_2D);
+		LLImageGL::unbindTexture(0);
 		LLGLDepthTest depth(GL_FALSE);
 		LLGLEnable stencil(GL_STENCIL_TEST);
 		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
@@ -1719,7 +1728,11 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 		renderGrid(0,0,tiles,inner_color.mV[0], inner_color.mV[1], inner_color.mV[2], 0.25f);
 	}
 
-	glPopMatrix();
+	glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
+	glStencilMask(0xFFFFFFFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+	gGL.popMatrix();
 }
 
 void LLManipTranslate::renderText()
@@ -1830,9 +1843,9 @@ void LLManipTranslate::renderTranslationHandles()
 	mConeSize = mArrowLengthMeters / 4.f;
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
-		glTranslatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
+		gGL.translatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]);
 
 		F32 angle_radians, x, y, z;
 		grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
@@ -1884,9 +1897,9 @@ void LLManipTranslate::renderTranslationHandles()
 			if ((mManipPart == LL_NO_PART || mManipPart == LL_YZ_PLANE) && llabs(relative_camera_dir.mV[VX]) > MIN_PLANE_MANIP_DOT_PRODUCT)
 			{
 				// render YZ plane manipulator
-				glPushMatrix();
+				gGL.pushMatrix();
 				glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]);
-				glTranslatef(0.f, mPlaneManipOffsetMeters, mPlaneManipOffsetMeters);
+				gGL.translatef(0.f, mPlaneManipOffsetMeters, mPlaneManipOffsetMeters);
 				glScalef(mPlaneScales.mV[VX], mPlaneScales.mV[VX], mPlaneScales.mV[VX]);
 				if (mHighlightedPart == LL_YZ_PLANE)
 				{
@@ -1898,49 +1911,49 @@ void LLManipTranslate::renderTranslationHandles()
 					color1.setVec(0.f, 1.f, 0.f, 0.6f);
 					color2.setVec(0.f, 0.f, 1.f, 0.6f);
 				}
-				glBegin(GL_TRIANGLES);
+				gGL.begin(GL_TRIANGLES);
 				{
-					glColor4fv(color1.mV);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f));
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
-
-					glColor4fv(color2.mV);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
+					gGL.color4fv(color1.mV);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f));
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+
+					gGL.color4fv(color2.mV);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
 				}
-				glEnd();
+				gGL.end();
 
 				LLUI::setLineWidth(3.0f);
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
-					glColor4f(0.f, 0.f, 0.f, 0.3f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f);
-
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f,  mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f,  mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
+					gGL.color4f(0.f, 0.f, 0.f, 0.3f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f);
+
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f,  mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f,  mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
 				}
-				glEnd();
+				gGL.end();
 				LLUI::setLineWidth(1.0f);
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 
 			if ((mManipPart == LL_NO_PART || mManipPart == LL_XZ_PLANE) && llabs(relative_camera_dir.mV[VY]) > MIN_PLANE_MANIP_DOT_PRODUCT)
 			{
 				// render XZ plane manipulator
-				glPushMatrix();
+				gGL.pushMatrix();
 				glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]);
-				glTranslatef(mPlaneManipOffsetMeters, 0.f, mPlaneManipOffsetMeters);
+				gGL.translatef(mPlaneManipOffsetMeters, 0.f, mPlaneManipOffsetMeters);
 				glScalef(mPlaneScales.mV[VY], mPlaneScales.mV[VY], mPlaneScales.mV[VY]);
 				if (mHighlightedPart == LL_XZ_PLANE)
 				{
@@ -1953,48 +1966,48 @@ void LLManipTranslate::renderTranslationHandles()
 					color2.setVec(1.f, 0.f, 0.f, 0.6f);
 				}
 
-				glBegin(GL_TRIANGLES);
+				gGL.begin(GL_TRIANGLES);
 				{
-					glColor4fv(color1.mV);
-					glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
-
-					glColor4fv(color2.mV);
-					glVertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
-					glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f),	0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f));
-					glVertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f),	0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+					gGL.color4fv(color1.mV);
+					gGL.vertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), 0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
+
+					gGL.color4fv(color2.mV);
+					gGL.vertex3f(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f));
+					gGL.vertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f),	0.f, mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f));
+					gGL.vertex3f(mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f),	0.f, mPlaneManipOffsetMeters * (PLANE_TICK_SIZE * 0.25f));
 				}
-				glEnd();
+				gGL.end();
 
 				LLUI::setLineWidth(3.0f);
-				glBegin(GL_LINES);
+				gGL.begin(GL_LINES);
 				{
-					glColor4f(0.f, 0.f, 0.f, 0.3f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f);
-					glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f);
+					gGL.color4f(0.f, 0.f, 0.f, 0.3f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * PLANE_TICK_SIZE  * 0.1f,   0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f);
 																				
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f,   0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
-					glVertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f,   0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.1f,   0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.25f,  0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.25f);
+					gGL.vertex3f(mPlaneManipOffsetMeters * -PLANE_TICK_SIZE * 0.4f,   0.f, mPlaneManipOffsetMeters * PLANE_TICK_SIZE * 0.1f);
 				}
-				glEnd();
+				gGL.end();
 				LLUI::setLineWidth(1.0f);
 
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 
 			if ((mManipPart == LL_NO_PART || mManipPart == LL_XY_PLANE) && llabs(relative_camera_dir.mV[VZ]) > MIN_PLANE_MANIP_DOT_PRODUCT)
 			{
 				// render XY plane manipulator
-				glPushMatrix();
+				gGL.pushMatrix();
 				glScalef(mPlaneManipPositions.mV[VX], mPlaneManipPositions.mV[VY], mPlaneManipPositions.mV[VZ]);
 				
 /*				 			  Y
@@ -2008,13 +2021,13 @@ void LLManipTranslate::renderTranslationHandles()
 					LLVector3 v0,v1,v2,v3;
 #if 0
 					// This should theoretically work but looks off; could be tuned later -SJB
-					glTranslatef(-mPlaneManipOffsetMeters, -mPlaneManipOffsetMeters, 0.f);
+					gGL.translatef(-mPlaneManipOffsetMeters, -mPlaneManipOffsetMeters, 0.f);
 					v0 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), 0.f);
 					v1 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.75f), 0.f);
 					v2 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f);
 					v3 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.75f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f);
 #else
-					glTranslatef(mPlaneManipOffsetMeters, mPlaneManipOffsetMeters, 0.f);
+					gGL.translatef(mPlaneManipOffsetMeters, mPlaneManipOffsetMeters, 0.f);
 					v0 = LLVector3(mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.25f), 0.f);
 					v1 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * (-PLANE_TICK_SIZE * 0.75f), 0.f);
 					v2 = LLVector3(mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), mPlaneManipOffsetMeters * ( PLANE_TICK_SIZE * 0.25f), 0.f);
@@ -2032,44 +2045,44 @@ void LLManipTranslate::renderTranslationHandles()
 						color2.setVec(0.f, 0.8f, 0.f, 0.6f);
 					}
 				
-					glBegin(GL_TRIANGLES);
+					gGL.begin(GL_TRIANGLES);
 					{
-						glColor4fv(color1.mV);
-						glVertex3fv(v0.mV);
-						glVertex3fv(v1.mV);
-						glVertex3fv(v2.mV);
-
-						glColor4fv(color2.mV);
-						glVertex3fv(v2.mV);
-						glVertex3fv(v3.mV);
-						glVertex3fv(v0.mV);
+						gGL.color4fv(color1.mV);
+						gGL.vertex3fv(v0.mV);
+						gGL.vertex3fv(v1.mV);
+						gGL.vertex3fv(v2.mV);
+
+						gGL.color4fv(color2.mV);
+						gGL.vertex3fv(v2.mV);
+						gGL.vertex3fv(v3.mV);
+						gGL.vertex3fv(v0.mV);
 					}
-					glEnd();
+					gGL.end();
 
 					LLUI::setLineWidth(3.0f);
-					glBegin(GL_LINES);
+					gGL.begin(GL_LINES);
 					{
-						glColor4f(0.f, 0.f, 0.f, 0.3f);
+						gGL.color4f(0.f, 0.f, 0.f, 0.3f);
 						LLVector3 v12 = (v1 + v2) * .5f;
-						glVertex3fv(v0.mV);
-						glVertex3fv(v12.mV);
-						glVertex3fv(v12.mV);
-						glVertex3fv((v12 + (v0-v12)*.3f + (v2-v12)*.3f).mV);
-						glVertex3fv(v12.mV);
-						glVertex3fv((v12 + (v0-v12)*.3f + (v1-v12)*.3f).mV);
+						gGL.vertex3fv(v0.mV);
+						gGL.vertex3fv(v12.mV);
+						gGL.vertex3fv(v12.mV);
+						gGL.vertex3fv((v12 + (v0-v12)*.3f + (v2-v12)*.3f).mV);
+						gGL.vertex3fv(v12.mV);
+						gGL.vertex3fv((v12 + (v0-v12)*.3f + (v1-v12)*.3f).mV);
 
 						LLVector3 v23 = (v2 + v3) * .5f;
-						glVertex3fv(v0.mV);
-						glVertex3fv(v23.mV);
-						glVertex3fv(v23.mV);
-						glVertex3fv((v23 + (v0-v23)*.3f + (v3-v23)*.3f).mV);
-						glVertex3fv(v23.mV);
-						glVertex3fv((v23 + (v0-v23)*.3f + (v2-v23)*.3f).mV);
+						gGL.vertex3fv(v0.mV);
+						gGL.vertex3fv(v23.mV);
+						gGL.vertex3fv(v23.mV);
+						gGL.vertex3fv((v23 + (v0-v23)*.3f + (v3-v23)*.3f).mV);
+						gGL.vertex3fv(v23.mV);
+						gGL.vertex3fv((v23 + (v0-v23)*.3f + (v2-v23)*.3f).mV);
 					}
-					glEnd();
+					gGL.end();
 					LLUI::setLineWidth(1.0f);
 
-				glPopMatrix();
+				gGL.popMatrix();
 			}
 		}
 		{
@@ -2141,7 +2154,7 @@ void LLManipTranslate::renderTranslationHandles()
 			}
 		}
 	}
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 
@@ -2150,11 +2163,11 @@ void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_
 	LLGLSNoTexture gls_ui_no_texture;
 	LLGLEnable gls_blend(GL_BLEND);
 	LLGLEnable gls_color_material(GL_COLOR_MATERIAL);
-	
+
 	for (S32 pass = 1; pass <= 2; pass++)
 	{	
 		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, pass == 1 ? GL_LEQUAL : GL_GREATER);
-		glPushMatrix();
+		gGL.pushMatrix();
 			
 		S32 index = 0;
 	
@@ -2175,27 +2188,23 @@ void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_
 			color.mV[index] = pass == 1 ? .8f : .35f ;			// red, green, or blue
 			color.mV[VALPHA] = 0.6f;
 		}
-		glColor4fv( color.mV );
+		gGL.color4fv( color.mV );
 
 		LLVector3 vec;
 
 		{
-//			Stipple looks OK, but not great - SJB
-// 			LLGLEnable stipple(GL_LINE_STIPPLE);
-// 			glLineStipple(1, 0x3333);
-
 			LLUI::setLineWidth(2.0f);
-			glBegin(GL_LINES);
+			gGL.begin(GL_LINES);
 				vec.mV[index] = box_size;
-				glVertex3f(vec.mV[0], vec.mV[1], vec.mV[2]);
+				gGL.vertex3f(vec.mV[0], vec.mV[1], vec.mV[2]);
 
 				vec.mV[index] = arrow_size;
-				glVertex3f(vec.mV[0], vec.mV[1], vec.mV[2]);
-			glEnd();
+				gGL.vertex3f(vec.mV[0], vec.mV[1], vec.mV[2]);
+			gGL.end();
 			LLUI::setLineWidth(1.0f);
 		}
 		
-		glTranslatef(vec.mV[0], vec.mV[1], vec.mV[2]);
+		gGL.translatef(vec.mV[0], vec.mV[1], vec.mV[2]);
 		glScalef(handle_size, handle_size, handle_size);
 
 		F32 rot = 0.0f;
@@ -2220,31 +2229,32 @@ void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_
 			break;
 		}
 
+		glColor4fv(color.mV);
 		glRotatef(rot, axis.mV[0], axis.mV[1], axis.mV[2]);
 		glScalef(mArrowScales.mV[index], mArrowScales.mV[index], mArrowScales.mV[index] * 1.5f);
 
 		gCone.render(CONE_LOD_HIGHEST);
 
-		glPopMatrix();
+		gGL.popMatrix();
 	}
 }
 
 void LLManipTranslate::renderGridVert(F32 x_trans, F32 y_trans, F32 r, F32 g, F32 b, F32 alpha)
 {
-	glColor4f(r, g, b, alpha);
+	gGL.color4f(r, g, b, alpha);
 	switch (mManipPart)
 	{
 	case LL_YZ_PLANE:
-		glVertex3f(0, x_trans, y_trans);
+		gGL.vertex3f(0, x_trans, y_trans);
 		break;
 	case LL_XZ_PLANE:
-		glVertex3f(x_trans, 0, y_trans);
+		gGL.vertex3f(x_trans, 0, y_trans);
 		break;
 	case LL_XY_PLANE:
-		glVertex3f(x_trans, y_trans, 0);
+		gGL.vertex3f(x_trans, y_trans, 0);
 		break;
 	default:
-		glVertex3f(0,0,0);
+		gGL.vertex3f(0,0,0);
 		break;
 	}
 
diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp
index 616fabebf7f..d554c272eed 100644
--- a/indra/newview/llmemoryview.cpp
+++ b/indra/newview/llmemoryview.cpp
@@ -107,12 +107,12 @@ BOOL LLMemoryView::handleHover(S32 x, S32 y, MASK mask)
 struct mtv_display_info {
 	S32 memtype;
 	const char *desc;
-	LLColor4 *color;
+	const LLColor4 *color;
 };
 
-static LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f);
+static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f);
 
-static struct mtv_display_info mtv_display_table[] =
+static const struct mtv_display_info mtv_display_table[] =
 {
 	{ LLMemType::MTYPE_INIT,			"Init", 			&LLColor4::white },
 	{ LLMemType::MTYPE_STARTUP,			"Startup", 			&LLColor4::cyan1 },
@@ -194,7 +194,6 @@ void LLMemoryView::draw()
 	
 	// Labels
 	{
-		LLGLSTexture gls_texture;
 		y = ytop;
 		S32 peak = 0;
 		for (S32 i=0; i<MTV_DISPLAY_NUM; i++)
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 257e87171ac..0a078e10585 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -39,6 +39,7 @@
 #include "linked_lists.h"
 #include "llmath.h"		// clampf()
 #include "llfocusmgr.h"
+#include "llglimmediate.h"
 
 #include "llagent.h"
 #include "llcallingcard.h"
@@ -117,9 +118,11 @@ LLNetMap::LLNetMap(
 	mTextBoxEast->setColor( minor_color );
 	addChild( mTextBoxEast );
 	
+	major_dir_rect.mRight += 1 ;
 	mTextBoxWest =	new LLTextBox( "W", major_dir_rect );
 	mTextBoxWest->setColor( minor_color );
 	addChild( mTextBoxWest );
+	major_dir_rect.mRight -= 1 ;
 
 	mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
 	mTextBoxSouth->setColor( minor_color );
@@ -256,7 +259,7 @@ void LLNetMap::draw()
 			glMatrixMode(GL_MODELVIEW);
 
 			// Draw background rectangle
-			glColor4fv( mBackgroundColor.mV );
+			gGL.color4fv( mBackgroundColor.mV );
 			gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0);
 		}
 
@@ -264,9 +267,9 @@ void LLNetMap::draw()
 		S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPanX);
 		S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPanY);
 
-		glPushMatrix();
+		gGL.pushMatrix();
 
-		glTranslatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
+		gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
 
 		if( LLNetMap::sRotateMap )
 		{
@@ -296,31 +299,31 @@ void LLNetMap::draw()
 
 			if (regionp == gAgent.getRegion())
 			{
-				glColor4f(1.f, 1.f, 1.f, 1.f);
+				gGL.color4f(1.f, 1.f, 1.f, 1.f);
 			}
 			else
 			{
-				glColor4f(0.8f, 0.8f, 0.8f, 1.f);
+				gGL.color4f(0.8f, 0.8f, 0.8f, 1.f);
 			}
 
 			if (!regionp->mAlive)
 			{
-				glColor4f(1.f, 0.5f, 0.5f, 1.f);
+				gGL.color4f(1.f, 0.5f, 0.5f, 1.f);
 			}
 
 
 			// Draw using texture.
 			LLViewerImage::bindTexture(regionp->getLand().getSTexture());
-			glBegin(GL_QUADS);
-				glTexCoord2f(0.f, 1.f);
-				glVertex2f(left, top);
-				glTexCoord2f(0.f, 0.f);
-				glVertex2f(left, bottom);
-				glTexCoord2f(1.f, 0.f);
-				glVertex2f(right, bottom);
-				glTexCoord2f(1.f, 1.f);
-				glVertex2f(right, top);
-			glEnd();
+			gGL.begin(GL_QUADS);
+				gGL.texCoord2f(0.f, 1.f);
+				gGL.vertex2f(left, top);
+				gGL.texCoord2f(0.f, 0.f);
+				gGL.vertex2f(left, bottom);
+				gGL.texCoord2f(1.f, 0.f);
+				gGL.vertex2f(right, bottom);
+				gGL.texCoord2f(1.f, 1.f);
+				gGL.vertex2f(right, top);
+			gGL.end();
 
 			// Draw water
 			glAlphaFunc(GL_GREATER, ABOVE_WATERLINE_ALPHA / 255.f );
@@ -328,16 +331,16 @@ void LLNetMap::draw()
 				if (regionp->getLand().getWaterTexture())
 				{
 					LLViewerImage::bindTexture(regionp->getLand().getWaterTexture());
-					glBegin(GL_QUADS);
-						glTexCoord2f(0.f, 1.f);
-						glVertex2f(left, top);
-						glTexCoord2f(0.f, 0.f);
-						glVertex2f(left, bottom);
-						glTexCoord2f(1.f, 0.f);
-						glVertex2f(right, bottom);
-						glTexCoord2f(1.f, 1.f);
-						glVertex2f(right, top);
-					glEnd();
+					gGL.begin(GL_QUADS);
+						gGL.texCoord2f(0.f, 1.f);
+						gGL.vertex2f(left, top);
+						gGL.texCoord2f(0.f, 0.f);
+						gGL.vertex2f(left, bottom);
+						gGL.texCoord2f(1.f, 0.f);
+						gGL.vertex2f(right, bottom);
+						gGL.texCoord2f(1.f, 1.f);
+						gGL.vertex2f(right, top);
+					gGL.end();
 				}
 			}
 			glAlphaFunc(GL_GREATER,0.01f);
@@ -378,18 +381,18 @@ void LLNetMap::draw()
 		F32 image_half_width = 0.5f*mObjectMapPixels;
 		F32 image_half_height = 0.5f*mObjectMapPixels;
 
-		glBegin(GL_QUADS);
-			glTexCoord2f(0.f, 1.f);
-			glVertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
-			glTexCoord2f(0.f, 0.f);
-			glVertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
-			glTexCoord2f(1.f, 0.f);
-			glVertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
-			glTexCoord2f(1.f, 1.f);
-			glVertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
-		glEnd();
+		gGL.begin(GL_QUADS);
+			gGL.texCoord2f(0.f, 1.f);
+			gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
+			gGL.texCoord2f(0.f, 0.f);
+			gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
+			gGL.texCoord2f(1.f, 0.f);
+			gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
+			gGL.texCoord2f(1.f, 1.f);
+			gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
+		gGL.end();
 
-		glPopMatrix();
+		gGL.popMatrix();
 
 		LLVector3d pos_global;
 		LLVector3 pos_map;
@@ -486,28 +489,28 @@ void LLNetMap::draw()
 
 		if( LLNetMap::sRotateMap )
 		{
-			glColor4fv(gFrustumMapColor.mV);
+			gGL.color4fv(gFrustumMapColor.mV);
 
-			glBegin( GL_TRIANGLES  );
-				glVertex2f( ctr_x, ctr_y );
-				glVertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
-				glVertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
-			glEnd();
+			gGL.begin( GL_TRIANGLES  );
+				gGL.vertex2f( ctr_x, ctr_y );
+				gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
+				gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
+			gGL.end();
 		}
 		else
 		{
-			glColor4fv(gRotatingFrustumMapColor.mV);
+			gGL.color4fv(gRotatingFrustumMapColor.mV);
 			
 			// If we don't rotate the map, we have to rotate the frustum.
-			glPushMatrix();
-				glTranslatef( ctr_x, ctr_y, 0 );
+			gGL.pushMatrix();
+				gGL.translatef( ctr_x, ctr_y, 0 );
 				glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
-				glBegin( GL_TRIANGLES  );
-					glVertex2f( 0, 0 );
-					glVertex2f( -half_width_pixels, far_clip_pixels );
-					glVertex2f(  half_width_pixels, far_clip_pixels );
-				glEnd();
-			glPopMatrix();
+				gGL.begin( GL_TRIANGLES  );
+					gGL.vertex2f( 0, 0 );
+					gGL.vertex2f( -half_width_pixels, far_clip_pixels );
+					gGL.vertex2f(  half_width_pixels, far_clip_pixels );
+				gGL.end();
+			gGL.popMatrix();
 		}
 	}
 	
diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp
index 53066aa52df..cda921ab8f2 100644
--- a/indra/newview/lloverlaybar.cpp
+++ b/indra/newview/lloverlaybar.cpp
@@ -37,6 +37,7 @@
 #include "lloverlaybar.h"
 
 #include "audioengine.h"
+#include "llglimmediate.h"
 #include "llagent.h"
 #include "llbutton.h"
 #include "llchatbar.h"
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 24b055b0a63..b87d18a545a 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -80,6 +80,9 @@ BOOL	LLPanelFace::postBuild()
 	LLTextBox*		mLabelColorTransp;
 	LLSpinCtrl*		mCtrlColorTransp;		// transparency = 1 - alpha
 
+	LLTextBox*      mLabelGlow;
+	LLSpinCtrl*     mCtrlGlow;
+
 	setMouseOpaque(FALSE);
 	mTextureCtrl = getChild<LLTextureCtrl>("texture control");
 	if(mTextureCtrl)
@@ -156,6 +159,15 @@ BOOL	LLPanelFace::postBuild()
 		mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP);	
 		mComboTexGen->setCallbackUserData( this );
 	}
+
+	mLabelGlow = LLUICtrlFactory::getTextBoxByName(this,"glow label");
+	mCtrlGlow = LLUICtrlFactory::getSpinnerByName(this,"glow");
+	if(mCtrlGlow)
+	{
+		mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow);
+		mCtrlGlow->setCallbackUserData(this);
+	}
+	
 	childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this);
 	childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this);
 	childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this);
@@ -254,6 +266,15 @@ void LLPanelFace::sendAlpha()
 }
 
 
+void LLPanelFace::sendGlow()
+{
+	LLSpinCtrl*	mCtrlGlow = LLViewerUICtrlFactory::getSpinnerByName(this,"glow");
+	if(!mCtrlGlow)return;
+	F32 glow = mCtrlGlow->get();
+
+	gSelectMgr->selectionSetGlow( glow );
+}
+
 struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor
 {
 	LLPanelFaceSetTEFunctor(LLPanelFace* panel) : mPanel(panel) {}
@@ -363,7 +384,8 @@ void LLPanelFace::getState()
 	LLViewerObject* objectp = gSelectMgr->getSelection()->getFirstObject();
 
 	if( objectp
-		&& objectp->getPCode() == LL_PCODE_VOLUME)
+		&& objectp->getPCode() == LL_PCODE_VOLUME
+		&& objectp->permModify())
 	{
 		BOOL editable = objectp->permModify();
 
@@ -578,10 +600,28 @@ void LLPanelFace::getState()
 			childSetEnabled("ColorTrans",editable);
 		}
 
+		{
+			F32 glow = 0.f;
+			struct f8 : public LLSelectedTEGetFunctor<F32>
+			{
+				F32 get(LLViewerObject* object, S32 face)
+				{
+					return object->getTE(face)->getGlow();
+				}
+			} func;
+			identical = gSelectMgr->getSelection()->getSelectedTEValue( &func, glow );
+
+			childSetValue("glow",glow);
+			childSetEnabled("glow",editable);
+			childSetTentative("glow",!identical);
+			childSetEnabled("glow label",editable);
+
+		}
+
 		// Bump
 		{
 			F32 shinyf = 0.f;
-			struct f8 : public LLSelectedTEGetFunctor<F32>
+			struct f9 : public LLSelectedTEGetFunctor<F32>
 			{
 				F32 get(LLViewerObject* object, S32 face)
 				{
@@ -606,7 +646,7 @@ void LLPanelFace::getState()
 
 		{
 			F32 bumpf = 0.f;
-			struct f9 : public LLSelectedTEGetFunctor<F32>
+			struct f10 : public LLSelectedTEGetFunctor<F32>
 			{
 				F32 get(LLViewerObject* object, S32 face)
 				{
@@ -631,7 +671,7 @@ void LLPanelFace::getState()
 
 		{
 			F32 genf = 0.f;
-			struct f10 : public LLSelectedTEGetFunctor<F32>
+			struct f11 : public LLSelectedTEGetFunctor<F32>
 			{
 				F32 get(LLViewerObject* object, S32 face)
 				{
@@ -669,7 +709,7 @@ void LLPanelFace::getState()
 
 		{
 			F32 fullbrightf = 0.f;
-			struct f11 : public LLSelectedTEGetFunctor<F32>
+			struct f12 : public LLSelectedTEGetFunctor<F32>
 			{
 				F32 get(LLViewerObject* object, S32 face)
 				{
@@ -691,7 +731,7 @@ void LLPanelFace::getState()
 		// Repeats per meter
 		{
 			F32 repeats = 1.f;
-			struct f12 : public LLSelectedTEGetFunctor<F32>
+			struct f13 : public LLSelectedTEGetFunctor<F32>
 			{
 				F32 get(LLViewerObject* object, S32 face)
 				{
@@ -761,6 +801,12 @@ void LLPanelFace::refresh()
 // Static functions
 //
 
+// static
+F32 LLPanelFace::valueGlow(LLViewerObject* object, S32 face)
+{
+	return (F32)(object->getTE(face)->getGlow());
+}
+
 
 // static
 void LLPanelFace::onCommitColor(LLUICtrl* ctrl, void* userdata)
@@ -818,6 +864,13 @@ void LLPanelFace::onCommitFullbright(LLUICtrl* ctrl, void* userdata)
 	self->sendFullbright();
 }
 
+// static
+void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	self->sendGlow();
+}
+
 // static
 BOOL LLPanelFace::onDragTexture(LLUICtrl*, LLInventoryItem* item, void*)
 {
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index d6801299899..ddef5a1b5f2 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -67,6 +67,7 @@ class LLPanelFace : public LLPanel
 	void			sendTexGen();				// applies and sends bump map
 	void			sendShiny();			// applies and sends shininess
 	void			sendFullbright();		// applies and sends full bright
+	void            sendGlow();
 
 	// this function is to return TRUE if the dra should succeed.
 	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item, void* ud);
@@ -83,9 +84,11 @@ class LLPanelFace : public LLPanel
 	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
 	static void		onCommitShiny(			LLUICtrl* ctrl, void* userdata);
 	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
+	static void     onCommitGlow(           LLUICtrl* ctrl, void *userdata);
 
 	static void		onClickApply(void*);
 	static void		onClickAutoFix(void*);
+	static F32      valueGlow(LLViewerObject* object, S32 face);
 };
 
 #endif
diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp
index c6aae2dd889..b19d3723a78 100644
--- a/indra/newview/llpanelgrouplandmoney.cpp
+++ b/indra/newview/llpanelgrouplandmoney.cpp
@@ -311,7 +311,6 @@ void LLPanelGroupLandMoney::impl::setYourContributionTextField(int contrib)
 	if ( mYourContributionEditorp )
 	{
 		mYourContributionEditorp->setText(buffer);
-		mYourContributionEditorp->draw();
 	}
 }
 
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index f717088de67..2ebbc075009 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -913,12 +913,15 @@ void LLPanelObject::getState( )
 		mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y);
 		break;
 	default:
-		mSpinScaleX->set( 1.f - scale_x );
-		mSpinScaleY->set( 1.f - scale_y );
-		mSpinScaleX->setMinValue(-1.f);
-		mSpinScaleX->setMaxValue(1.f);
-		mSpinScaleY->setMinValue(-1.f);
-		mSpinScaleY->setMaxValue(1.f);
+		if (editable)
+		{
+			mSpinScaleX->set( 1.f - scale_x );
+			mSpinScaleY->set( 1.f - scale_y );
+			mSpinScaleX->setMinValue(-1.f);
+			mSpinScaleX->setMaxValue(1.f);
+			mSpinScaleY->setMinValue(-1.f);
+			mSpinScaleY->setMaxValue(1.f);
+		}
 		break;
 	}
 
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 83a2a5e0bd9..a9198cd6b43 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -232,6 +232,10 @@ void LLPanelVolume::getState( )
 	}
 	else
 	{
+		((LLPanel *) getChildByName ("Light Intensity", true))->clear();
+		((LLPanel *) getChildByName ("Light Radius", true))->clear();
+		((LLPanel *) getChildByName ("Light Falloff", true))->clear();
+
 		childSetEnabled("label color",false);	
 		LLColorSwatchCtrl* LightColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
 		if(LightColorSwatch)
@@ -288,6 +292,15 @@ void LLPanelVolume::getState( )
 	}
 	else
 	{
+		((LLPanel *) getChildByName ("FlexNumSections", true))->clear();
+		((LLPanel *) getChildByName ("FlexGravity", true))->clear();
+		((LLPanel *) getChildByName ("FlexTension", true))->clear();
+		((LLPanel *) getChildByName ("FlexFriction", true))->clear();
+		((LLPanel *) getChildByName ("FlexWind", true))->clear();
+		((LLPanel *) getChildByName ("FlexForceX", true))->clear();
+		((LLPanel *) getChildByName ("FlexForceY", true))->clear();
+		((LLPanel *) getChildByName ("FlexForceZ", true))->clear();
+
 		childSetEnabled("FlexNumSections",false);
 		childSetEnabled("FlexGravity",false);
 		childSetEnabled("FlexTension",false);
diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp
index ba96ba088bd..105103d10b0 100644
--- a/indra/newview/llpreviewanim.cpp
+++ b/indra/newview/llpreviewanim.cpp
@@ -180,33 +180,6 @@ void LLPreviewAnim::auditionAnim( void *userdata )
 	}
 }
 
-void LLPreviewAnim::saveAnim( void *userdata )
-{
-	LLPreviewAnim* self = (LLPreviewAnim*) userdata;
-	const LLInventoryItem *item = self->getItem();
-
-	if(item)
-	{
-		LLKeyframeMotion* motionp = (LLKeyframeMotion*)gAgent.getAvatarObject()->createMotion( item->getAssetUUID() );
-		if (motionp && motionp->isLoaded())
-		{
-			LLFilePicker& picker = LLFilePicker::instance();
-			LLString proposed_name = item->getName() + LLString(".xaf");
-			if (picker.getSaveFile(LLFilePicker::FFSAVE_ANIM, proposed_name.c_str()))
-			{
-					apr_file_t* fp = ll_apr_file_open(picker.getFirstFile(), LL_APR_W);
-					if (!fp)
-					{
-						llwarns << "Unable to open file " << picker.getFirstFile() << llendl;
-						return;
-					}
-					motionp->writeCAL3D(fp);
-					apr_file_close(fp);
-			}
-		}
-	}
-}
-
 void LLPreviewAnim::onClose(bool app_quitting)
 {
 	const LLInventoryItem *item = getItem();
diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h
index 37cbd497254..28b09a49ddb 100644
--- a/indra/newview/llpreviewanim.h
+++ b/indra/newview/llpreviewanim.h
@@ -45,7 +45,6 @@ class LLPreviewAnim : public LLPreview
 
 	static void playAnim( void* userdata );
 	static void auditionAnim( void* userdata );
-	static void saveAnim( void* userdata );
 	static void endAnimCallback( void *userdata );
 
 protected:
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 20737eb7f10..e1a9636fd07 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -214,7 +214,6 @@ void LLPreviewTexture::draw()
 
 			if ( mImage.notNull() )
 			{
-				LLGLSTexture gls_no_texture;
 				// Draw the texture
 				glColor3f( 1.f, 1.f, 1.f );
 				gl_draw_scaled_image(interior.mLeft,
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index 9e437df2d13..101f7ace5d4 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -36,6 +36,7 @@
 #include "indra_constants.h"
 #include "llmath.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llui.h"
 #include "llfontgl.h"
 #include "llimagegl.h"
@@ -175,7 +176,7 @@ void LLProgressView::draw()
 		{
 			LLGLSUIDefault gls_ui;
 			LLViewerImage::bindTexture(gStartImageGL);
-			glColor4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f);
+			gGL.color4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f);
 			F32 image_aspect = (F32)gStartImageWidth / (F32)gStartImageHeight;
 			F32 view_aspect = (F32)width / (F32)height;
 			// stretch image to maintain aspect ratio
@@ -195,7 +196,7 @@ void LLProgressView::draw()
 		else
 		{
 			LLGLSNoTexture gls_no_texture;
-			glColor4f(0.f, 0.f, 0.f, 1.f);
+			gGL.color4f(0.f, 0.f, 0.f, 1.f);
 			gl_rect_2d(getRect());
 		}
 		glPopMatrix();
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index ffc53f0dd5d..d2e3dc1ed93 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -39,6 +39,7 @@
 #include "lldbstrings.h"
 #include "lleconomy.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llpermissions.h"
 #include "llpermissionsflags.h"
 #include "llptrskiplist.h"
@@ -1730,6 +1731,37 @@ void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string&
 	getSelection()->applyToObjects(&sendfunc);
 }
 
+void LLSelectMgr::selectionSetGlow(F32 glow)
+{
+	struct f1 : public LLSelectedTEFunctor
+	{
+		F32 mGlow;
+		f1(F32 glow) : mGlow(glow) {};
+		bool apply(LLViewerObject* object, S32 face)
+		{
+			if (object->permModify())
+			{
+				// update viewer side color in anticipation of update from simulator
+				object->setTEGlow(face, mGlow);
+			}
+			return true;
+		}
+	} func1(glow);
+	mSelectedObjects->applyToTEs( &func1 );
+
+	struct f2 : public LLSelectedObjectFunctor
+	{
+		virtual bool apply(LLViewerObject* object)
+		{
+			if (object->permModify())
+			{
+				object->sendTEUpdate();
+			}
+			return true;
+		}
+	} func2;
+	mSelectedObjects->applyToObjects( &func2 );
+}
 
 
 //-----------------------------------------------------------------------------
@@ -1751,6 +1783,26 @@ LLPermissions* LLSelectMgr::findObjectPermissions(const LLViewerObject* object)
 }
 
 
+//-----------------------------------------------------------------------------
+// selectionGetGlow()
+//-----------------------------------------------------------------------------
+BOOL LLSelectMgr::selectionGetGlow(F32 *glow)
+{
+	BOOL identical;
+	F32 lglow = 0.f;
+	struct f1 : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			return object->getTE(face)->getGlow();
+		}
+	} func;
+	identical = mSelectedObjects->getSelectedTEValue( &func, lglow );
+
+	*glow = lglow;
+	return identical;
+}
+
 //-----------------------------------------------------------------------------
 // selectionSetMaterial()
 //-----------------------------------------------------------------------------
@@ -5161,7 +5213,8 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 
 		if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
 		{
-			glBlendFunc(GL_SRC_COLOR, GL_ONE);
+			gGL.flush();
+			gGL.blendFunc(GL_SRC_COLOR, GL_ONE);
 			LLGLEnable fog(GL_FOG);
 			glFogi(GL_FOG_MODE, GL_LINEAR);
 			float d = (gCamera->getPointOfInterest()-gCamera->getOrigin()).magVec();
@@ -5172,7 +5225,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 
 			LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
 			glAlphaFunc(GL_GREATER, 0.01f);
-			glBegin(GL_LINES);
+			gGL.begin(GL_LINES);
 			{
 				S32 i = 0;
 				for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
@@ -5181,18 +5234,19 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 					{
 						u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
 
-						glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
-						glTexCoord2f( u_coord, v_coord );
-						glVertex3fv( mSilhouetteVertices[i].mV );
+						gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
+						gGL.texCoord2f( u_coord, v_coord );
+						gGL.vertex3fv( mSilhouetteVertices[i].mV );
 					}
 				}
 			}
-            glEnd();
+            gGL.end();
 			u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f);
 		}
 
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		glBegin(GL_TRIANGLES);
+		gGL.flush();
+		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		gGL.begin(GL_TRIANGLES);
 		{
 			S32 i = 0;
 			for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
@@ -5208,15 +5262,15 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 					    LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
 						vert += mSilhouetteVertices[i];
 
-						glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
-						glTexCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
-						glVertex3fv( vert.mV ); 
+						gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
+						gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
+						gGL.vertex3fv( vert.mV ); 
 						
 						u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
 
-						glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
-						glTexCoord2f( u_coord, v_coord );
-						glVertex3fv( mSilhouetteVertices[i].mV );
+						gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+						gGL.texCoord2f( u_coord, v_coord );
+						gGL.vertex3fv( mSilhouetteVertices[i].mV );
 
 						v = mSilhouetteVertices[i];
 						t = LLVector2(u_coord, v_coord);
@@ -5225,24 +5279,24 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
                         LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
 						vert += mSilhouetteVertices[i];
 
-						glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
-						glTexCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
-						glVertex3fv( vert.mV ); 
-						glVertex3fv( vert.mV ); 
+						gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
+						gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
+						gGL.vertex3fv( vert.mV ); 
+						gGL.vertex3fv( vert.mV ); 
 						
-						glTexCoord2fv(t.mV);
+						gGL.texCoord2fv(t.mV);
 						u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
-						glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
-						glVertex3fv(v.mV);
-						glTexCoord2f( u_coord, v_coord );
-						glVertex3fv( mSilhouetteVertices[i].mV );
+						gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+						gGL.vertex3fv(v.mV);
+						gGL.texCoord2f( u_coord, v_coord );
+						gGL.vertex3fv( mSilhouetteVertices[i].mV );
 
 					}
 				}
 			}
 		}
-		glEnd();
-
+		gGL.end();
+		gGL.flush();
 	}
 	glPopMatrix();
 }
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 32c7f7617e5..68c1d4d9f82 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -486,6 +486,7 @@ class LLSelectMgr : public LLEditMenuHandler
 	BOOL selectionAllPCode(LLPCode code);		// all objects have this PCode
 	BOOL selectionGetClickAction(U8 *out_action);
 	bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same
+	BOOL selectionGetGlow(F32 *glow);
 
 	void selectionSetMaterial(U8 material);
 	void selectionSetImage(const LLUUID& imageid); // could be item or asset id
@@ -501,6 +502,7 @@ class LLSelectMgr : public LLEditMenuHandler
 	void selectionSetMediaTypeAndURL( U8 media_type, const std::string& media_url );
 	void selectionSetClickAction(U8 action);
 	void selectionSetIncludeInSearch(bool include_in_search);
+	void selectionSetGlow(const F32 glow);
 
 	void selectionSetObjectPermissions(U8 perm_field, BOOL set, U32 perm_mask, BOOL override = FALSE);
 	void selectionSetObjectName(const LLString& name);
diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp
index ee3890e50af..1ba4adf4d2a 100644
--- a/indra/newview/llsky.cpp
+++ b/indra/newview/llsky.cpp
@@ -55,11 +55,10 @@
 #include "lldrawpool.h"
 
 #include "llvosky.h"
-#include "llvostars.h"
 #include "llcubemap.h"
 #include "llviewercontrol.h"
 
-extern LLPipeline gPipeline;
+#include "llvowlsky.h"
 
 F32 azimuth_from_vector(const LLVector3 &v);
 F32 elevation_from_vector(const LLVector3 &v);
@@ -92,7 +91,7 @@ LLSky::~LLSky()
 void LLSky::cleanup()
 {
 	mVOSkyp = NULL;
-	mVOStarsp = NULL;
+	mVOWLSkyp = NULL;
 	mVOGroundp = NULL;
 }
 
@@ -102,6 +101,10 @@ void LLSky::destroyGL()
 	{
 		mVOSkyp->cleanupGL();
 	}
+	if (mVOWLSkyp.notNull())
+	{
+		mVOWLSkyp->cleanupGL();
+	}
 }
 
 void LLSky::restoreGL()
@@ -110,6 +113,27 @@ void LLSky::restoreGL()
 	{
 		mVOSkyp->restoreGL();
 	}
+	if (mVOWLSkyp)
+	{
+		mVOWLSkyp->restoreGL();
+	}
+}
+
+void LLSky::resetVertexBuffers()
+{
+	if (gSky.mVOSkyp.notNull())
+	{
+		gPipeline.resetVertexBuffers(gSky.mVOSkyp->mDrawable);
+		gPipeline.resetVertexBuffers(gSky.mVOGroundp->mDrawable);
+		gPipeline.markRebuild(gSky.mVOSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+		gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+	}
+	if (gSky.mVOWLSkyp.notNull())
+	{
+		gSky.mVOWLSkyp->resetVertexBuffers();
+		gPipeline.resetVertexBuffers(gSky.mVOWLSkyp->mDrawable);
+		gPipeline.markRebuild(gSky.mVOWLSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+	}
 }
 
 void LLSky::setOverrideSun(BOOL override)
@@ -127,7 +151,9 @@ void LLSky::setOverrideSun(BOOL override)
 
 void LLSky::setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity)
 {
-	mVOSkyp->setSunDirection(sun_direction, sun_ang_velocity);
+	if(mVOSkyp.notNull()) {
+		mVOSkyp->setSunDirection(sun_direction, sun_ang_velocity);
+	}
 }
 
 
@@ -175,6 +201,18 @@ LLColor4 LLSky::getSunDiffuseColor() const
 	}
 }
 
+LLColor4 LLSky::getSunAmbientColor() const
+{
+	if (mVOSkyp)
+	{
+		return LLColor4(mVOSkyp->getSunAmbientColor());
+	}
+	else
+	{
+		return LLColor4(0.f, 0.f, 0.f, 1.f);
+	}
+}
+
 
 LLColor4 LLSky::getMoonDiffuseColor() const
 {
@@ -188,42 +226,41 @@ LLColor4 LLSky::getMoonDiffuseColor() const
 	}
 }
 
-
-LLColor4 LLSky::getTotalAmbientColor() const
+LLColor4 LLSky::getMoonAmbientColor() const
 {
 	if (mVOSkyp)
 	{
-		return mVOSkyp->getTotalAmbientColor();
+		return LLColor4(mVOSkyp->getMoonAmbientColor());
 	}
 	else
 	{
-		return LLColor4(1.f, 1.f, 1.f, 1.f);
+		return LLColor4(0.f, 0.f, 0.f, 0.f);
 	}
 }
 
 
-BOOL LLSky::sunUp() const
+LLColor4 LLSky::getTotalAmbientColor() const
 {
 	if (mVOSkyp)
 	{
-		return mVOSkyp->isSunUp();
+		return mVOSkyp->getTotalAmbientColor();
 	}
 	else
 	{
-		return TRUE;
+		return LLColor4(1.f, 1.f, 1.f, 1.f);
 	}
 }
 
 
-LLColor4 LLSky::calcInScatter(LLColor4& transp, const LLVector3 &point, F32 exag) const
+BOOL LLSky::sunUp() const
 {
 	if (mVOSkyp)
 	{
-		return mVOSkyp->calcInScatter(transp, point, exag);
+		return mVOSkyp->isSunUp();
 	}
 	else
 	{
-		return LLColor4(1.f, 1.f, 1.f, 1.f);
+		return TRUE;
 	}
 }
 
@@ -245,22 +282,23 @@ LLColor4U LLSky::getFadeColor() const
 // Public Methods
 //////////////////////////////////////////////////////////////////////
 
-
 void LLSky::init(const LLVector3 &sun_direction)
 {
+	mVOWLSkyp = static_cast<LLVOWLSky*>(gObjectList.createObjectViewer(LLViewerObject::LL_VO_WL_SKY, gAgent.getRegion()));
+	mVOWLSkyp->initSunDirection(sun_direction, LLVector3::zero);
+	gPipeline.addObject(mVOWLSkyp.get());
+
 	mVOSkyp = (LLVOSky *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SKY, gAgent.getRegion());
 	mVOSkyp->initSunDirection(sun_direction, LLVector3());
 	gPipeline.addObject((LLViewerObject *)mVOSkyp);
 
-	mVOStarsp = (LLVOStars *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_STARS, gAgent.getRegion());
-	gPipeline.addObject((LLViewerObject *)mVOStarsp);
-	
+
 	mVOGroundp = (LLVOGround*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_GROUND, gAgent.getRegion());
 	LLVOGround *groundp = mVOGroundp;
 	gPipeline.addObject((LLViewerObject *)groundp);
 
-	gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio"));
-	
+	gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio"));	
+
 	////////////////////////////
 	//
 	// Legacy code, ignore
@@ -279,7 +317,8 @@ void LLSky::init(const LLVector3 &sun_direction)
 	{
 		setSunDirection(sun_direction, LLVector3(0.f, 0.f, 0.f));
 	}
-	
+
+
 	mUpdatedThisFrame = TRUE;
 }
 
@@ -349,7 +388,6 @@ LLColor4 LLSky::getFogColor() const
 	return LLColor4(1.f, 1.f, 1.f, 1.f);
 }
 
-
 void LLSky::updateFog(const F32 distance)
 {
 	if (mVOSkyp)
@@ -369,19 +407,12 @@ void LLSky::updateCull()
 		llinfos << "No sky drawable!" << llendl;
 	}*/
 
-	if (mVOStarsp.notNull() && mVOStarsp->mDrawable.notNull())
-	{
-		gPipeline.markVisible(mVOStarsp->mDrawable, *gCamera);
-	}
-	else
-	{
-		llinfos << "No stars drawable!" << llendl;
-	}
-
 	/*if (mVOGroundp.notNull() && mVOGroundp->mDrawable.notNull())
 	{
 		gPipeline.markVisible(mVOGroundp->mDrawable);
 	}*/
+
+	// *TODO: do culling for wl sky properly -Brad
 }
 
 void LLSky::updateSky()
@@ -394,13 +425,6 @@ void LLSky::updateSky()
 	{
 		mVOSkyp->updateSky();
 	}
-	if (mVOStarsp)
-	{
-		//if (mVOStarsp->mDrawable)
-		//{
-		//	gPipeline.markRebuild(mVOStarsp->mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
-		//}
-	}
 }
 
 
diff --git a/indra/newview/llsky.h b/indra/newview/llsky.h
index 690b54a59e8..e9e9999ff9e 100644
--- a/indra/newview/llsky.h
+++ b/indra/newview/llsky.h
@@ -39,7 +39,6 @@
 #include "v4color.h"
 #include "v4coloru.h"
 #include "llvosky.h"
-#include "llvostars.h"
 #include "llvoground.h"
 
 const F32 NIGHTTIME_ELEVATION			= -8.0f;	// degrees
@@ -47,6 +46,9 @@ const F32 NIGHTTIME_ELEVATION_COS		= (F32)sin(NIGHTTIME_ELEVATION*DEG_TO_RAD);
 
 class LLViewerCamera;
 
+class LLVOWLSky;
+class LLVOWLClouds;
+
 
 class LLSky  
 {
@@ -64,10 +66,8 @@ class LLSky
 	void setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity);
 	void setSunTargetDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity);
 
-
 	LLColor4 getFogColor() const;
 
-
 	void setCloudDensityAtAgent(F32 cloud_density);
 	void setWind(const LLVector3& wind);
 
@@ -88,21 +88,24 @@ class LLSky
 	LLVector3 getMoonDirection() const;
 	LLColor4 getSunDiffuseColor() const;
 	LLColor4 getMoonDiffuseColor() const;
+	LLColor4 getSunAmbientColor() const;
+	LLColor4 getMoonAmbientColor() const;
 	LLColor4 getTotalAmbientColor() const;
 	BOOL sunUp() const;
-	LLColor4 calcInScatter(LLColor4& transp, const LLVector3 &point, F32 exag) const;
 
 	F32 getSunPhase() const;
 	void setSunPhase(const F32 phase);
 
 	void destroyGL();
 	void restoreGL();
+	void resetVertexBuffers();
 
 public:
 	LLPointer<LLVOSky>		mVOSkyp;	// Pointer to the LLVOSky object (only one, ever!)
-	LLPointer<LLVOStars>	mVOStarsp;	// Pointer to the LLVOStars object (only one, ever!)
 	LLPointer<LLVOGround>	mVOGroundp;
 
+	LLPointer<LLVOWLSky>	mVOWLSkyp;
+
 	LLVector3 mSunTargDir;
 
 	// Legacy stuff
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index abb8d973aa3..84e14ef3418 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -43,25 +43,47 @@
 #include "llviewerregion.h"
 #include "llcamera.h"
 #include "pipeline.h"
-
-static GLuint sBoxList = 0;
+#include "llglimmediate.h"
+#include "lloctree.h"
 
 const F32 SG_OCCLUSION_FUDGE = 1.01f;
-//const S32 SG_LOD_PERIOD = 16;
-
-#define SG_DISCARD_TOLERANCE 0.25f
+#define SG_DISCARD_TOLERANCE 0.01f
 
 #if LL_OCTREE_PARANOIA_CHECK
 #define assert_octree_valid(x) x->validate()
+#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
 #else
 #define assert_octree_valid(x)
+#define assert_states_valid(x)
 #endif
 
+
 static U32 sZombieGroups = 0;
+U32 LLSpatialGroup::sNodeCount = 0;
 
 static F32 sLastMaxTexPriority = 1.f;
 static F32 sCurMaxTexPriority = 1.f;
 
+class LLOcclusionQueryPool : public LLGLNamePool
+{
+protected:
+	virtual GLuint allocateName()
+	{
+		GLuint name;
+		glGenQueriesARB(1, &name);
+		return name;
+	}
+
+	virtual void releaseName(GLuint name)
+	{
+		glDeleteQueriesARB(1, &name);
+	}
+};
+
+static LLOcclusionQueryPool sQueryPool;
+
+BOOL LLSpatialPartition::sFreezeState = FALSE;
+
 //static counter for frame to switch LOD on
 
 void sg_assert(BOOL expr)
@@ -90,6 +112,134 @@ void validate_drawable(LLDrawable* drawablep)
 #define validate_drawable(x)
 #endif
 
+
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
+{
+	F32 d = 0.f;
+	F32 t;
+	F32 r = rad*rad;
+
+	if ((min-origin).magVecSquared() < r &&
+		(max-origin).magVecSquared() < r)
+	{
+		return 2;
+	}
+
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (origin.mV[i] < min.mV[i])
+		{
+			t = min.mV[i] - origin.mV[i];
+			d += t*t;
+		}
+		else if (origin.mV[i] > max.mV[i])
+		{
+			t = origin.mV[i] - max.mV[i];
+			d += t*t;
+		}
+
+		if (d > r)
+		{
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+typedef enum
+{
+	b000 = 0x00,
+	b001 = 0x01,
+	b010 = 0x02,
+	b011 = 0x03,
+	b100 = 0x04,
+	b101 = 0x05,
+	b110 = 0x06,
+	b111 = 0x07,
+} eLoveTheBits;
+
+//contact Runitai Linden for a copy of the SL object used to write this table
+//basically, you give the table a bitmask of the look-at vector to a node and it
+//gives you a triangle fan index array
+static U8 sOcclusionIndices[] =
+{
+	 // 000
+		b111, b110, b010, b011, b001, b101, b100, b110,
+	//001 
+		b110, b000, b010, b011, b111, b101, b100, b000,
+	 //010
+		b101, b100, b110, b111, b011, b001, b000, b100,
+	 //011 
+		b100, b010, b110, b111, b101, b001, b000, b010,
+	//100 
+		b011, b010, b000, b001, b101, b111, b110, b010,
+	 //101 
+		b010, b100, b000, b001, b011, b111, b110, b100,
+	 //110
+		b001, b000, b100, b101, b111, b011, b010, b000,
+	 //111
+		b000, b110, b100, b101, b001, b011, b010, b110,
+};
+
+U8* get_occlusion_indices(LLCamera* camera, const LLVector3& center)
+{
+	LLVector3 d = center - camera->getOrigin();
+
+	U8 cypher = 0;
+	if (d.mV[0] > 0)
+	{
+		cypher |= b100;
+	}
+	if (d.mV[1] > 0)
+	{
+		cypher |= b010;
+	}
+	if (d.mV[2] > 0)
+	{
+		cypher |= b001;
+	}
+
+	return sOcclusionIndices+cypher*8;
+}
+						
+void LLSpatialGroup::buildOcclusion()
+{
+	if (!mOcclusionVerts)
+	{
+		mOcclusionVerts = new F32[8*3];
+	}
+
+	LLVector3 r = mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.1f,0.1f,0.1f);
+
+	for (U32 k = 0; k < 3; k++)
+	{
+		r.mV[k] = llmin(mBounds[1].mV[k]+0.25f, r.mV[k]);
+	}
+
+	F32* v = mOcclusionVerts;
+	F32* c = mBounds[0].mV;
+	F32* s = r.mV;
+	
+	//vertex positions are encoded so the 3 bits of their vertex index 
+	//correspond to their axis facing, with bit position 3,2,1 matching
+	//axis facing x,y,z, bit set meaning positive facing, bit clear 
+	//meaning negative facing
+	v[0] = c[0]-s[0]; v[1]  = c[1]-s[1]; v[2]  = c[2]-s[2];  // 0 - 0000 
+	v[3] = c[0]-s[0]; v[4]  = c[1]-s[1]; v[5]  = c[2]+s[2];  // 1 - 0001
+	v[6] = c[0]-s[0]; v[7]  = c[1]+s[1]; v[8]  = c[2]-s[2];  // 2 - 0010
+	v[9] = c[0]-s[0]; v[10] = c[1]+s[1]; v[11] = c[2]+s[2];  // 3 - 0011
+																					   
+	v[12] = c[0]+s[0]; v[13] = c[1]-s[1]; v[14] = c[2]-s[2]; // 4 - 0100
+	v[15] = c[0]+s[0]; v[16] = c[1]-s[1]; v[17] = c[2]+s[2]; // 5 - 0101
+	v[18] = c[0]+s[0]; v[19] = c[1]+s[1]; v[20] = c[2]-s[2]; // 6 - 0110
+	v[21] = c[0]+s[0]; v[22] = c[1]+s[1]; v[23] = c[2]+s[2]; // 7 - 0111
+
+	clearState(LLSpatialGroup::OCCLUSION_DIRTY);
+}
+
+
 BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
 
 BOOL LLLineSegmentAABB(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
@@ -150,6 +300,15 @@ LLSpatialGroup::~LLSpatialGroup()
 		sZombieGroups--;
 	}
 	
+	sNodeCount--;
+
+	if (gGLManager.mHasOcclusionQuery && mOcclusionQuery)
+	{
+		sQueryPool.release(mOcclusionQuery);
+	}
+
+	delete [] mOcclusionVerts;
+
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	clearDrawMap();
 }
@@ -159,55 +318,16 @@ void LLSpatialGroup::clearDrawMap()
 	mDrawMap.clear();
 }
 
-class LLRelightPainter : public LLSpatialGroup::OctreeTraveler
+BOOL LLSpatialGroup::isVisible() const
 {
-public:
-	LLVector3 mOrigin, mDir;
-	F32 mRadius;
-
-	LLRelightPainter(LLVector3 origin, LLVector3 dir, F32 radius)
-		: mOrigin(origin), mDir(dir), mRadius(radius) 
-	{ }
-
-	virtual void traverse(const LLSpatialGroup::TreeNode* n)
-	{
-		LLSpatialGroup::OctreeNode* node = (LLSpatialGroup::OctreeNode*) n;
-		
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		group->setState(LLSpatialGroup::RESHADOW);
-		
-		for (U32 i = 0; i < node->getChildCount(); i++)
-		{
-			const LLSpatialGroup::OctreeNode* child = node->getChild(i);
-			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
-			
-			LLVector3 res;
-			
-			LLVector3 center, size;
-			
-			center = group->mBounds[0];
-			size = group->mBounds[1];
-			
-			if (child->isInside(LLVector3d(mOrigin)) || LLRayAABB(center, size, mOrigin, mDir, res, mRadius))
-			{
-				traverse(child);
-			}
-		}	
-	}
-
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
-
-};
+	return mVisible == LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+}
 
-BOOL LLSpatialGroup::isVisible()
+void LLSpatialGroup::setVisible()
 {
-	if (LLPipeline::sUseOcclusion)
-	{
-		return !isState(CULLED | OCCLUDED);
-	}
-	else
+	if (!LLSpatialPartition::sFreezeState)
 	{
-		return !isState(CULLED); 
+		mVisible = LLDrawable::getCurrentFrame();
 	}
 }
 
@@ -232,7 +352,7 @@ void LLSpatialGroup::validate()
 			sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
 		}
 
-		if (drawable->isSpatialBridge())
+		/*if (drawable->isSpatialBridge())
 		{
 			LLSpatialPartition* part = drawable->asPartition();
 			if (!part)
@@ -241,7 +361,7 @@ void LLSpatialGroup::validate()
 			}
 			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
 			group->validate();
-		}
+		}*/
 	}
 
 	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
@@ -267,6 +387,71 @@ void LLSpatialGroup::validate()
 #endif
 }
 
+
+
+class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+{
+public:
+	U32 mInheritedMask;
+
+	LLOctreeStateCheck(): mInheritedMask(0) { }
+
+	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		node->accept(this);
+
+		U32 temp = mInheritedMask;
+		mInheritedMask |= group->getState() & 
+			(LLSpatialGroup::OCCLUDED);
+
+		for (U32 i = 0; i < node->getChildCount(); i++)
+		{
+			traverse(node->getChild(i));
+		}
+
+		mInheritedMask = temp;
+	}
+
+	virtual void visit(const LLOctreeNode<LLDrawable>* state)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+
+		if (mInheritedMask && !group->isState(mInheritedMask))
+		{
+			llerrs << "Spatial group failed inherited mask test." << llendl;
+		}
+
+		if (group->isState(LLSpatialGroup::DIRTY))
+		{
+			assert_parent_state(group, LLSpatialGroup::DIRTY);
+		}
+	}
+
+	void assert_parent_state(LLSpatialGroup* group, U32 state)
+	{
+		LLSpatialGroup* parent = group->getParent();
+		while (parent)
+		{
+			if (!parent->isState(state))
+			{
+				llerrs << "Spatial group failed parent state check." << llendl;
+			}
+			parent = parent->getParent();
+		}
+	}	
+};
+
+
+void LLSpatialGroup::checkStates()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	LLOctreeStateCheck checker;
+	checker.traverse(mOctreeNode);
+#endif
+}
+
 void validate_draw_info(LLDrawInfo& params)
 {
 #if LL_OCTREE_PARANOIA_CHECK
@@ -316,8 +501,8 @@ void LLSpatialGroup::validateDrawMap()
 #if LL_OCTREE_PARANOIA_CHECK
 	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
 	{
-		std::vector<LLDrawInfo*>& draw_vec = i->second;
-		for (std::vector<LLDrawInfo*>::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
 		{
 			LLDrawInfo& params = **j;
 			
@@ -327,32 +512,6 @@ void LLSpatialGroup::validateDrawMap()
 #endif
 }
 
-void LLSpatialGroup::makeStatic()
-{
-#if !LL_DARWIN
-	if (isState(GEOM_DIRTY | ALPHA_DIRTY))
-	{
-		return;
-	}
-	
-	if (mSpatialPartition->mRenderByGroup && mBufferUsage != GL_STATIC_DRAW_ARB)
-	{
-		mBufferUsage = GL_STATIC_DRAW_ARB;
-		if (mVertexBuffer.notNull())
-		{
-			mVertexBuffer->makeStatic();
-		}
-		
-		for (buffer_map_t::iterator i = mBufferMap.begin(); i != mBufferMap.end(); ++i)
-		{
-			i->second->makeStatic();
-		}
-		
-		mBuilt = 1.f;
-	}
-#endif
-}
-
 BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -369,7 +528,7 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 	{
 		unbound();
 		setState(OBJECT_DIRTY);
-		setState(GEOM_DIRTY);
+		//setState(GEOM_DIRTY);
 		validate_drawable(drawablep);
 		return TRUE;
 	}
@@ -389,8 +548,7 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
 	{
 		drawablep->setSpatialGroup(this);
 		validate_drawable(drawablep);
-		setState(OBJECT_DIRTY | GEOM_DIRTY);
-		mLastAddTime = gFrameTimeSeconds;
+		setState(OBJECT_DIRTY | GEOM_DIRTY | DISCARD_QUERY);
 		if (drawablep->isSpatialBridge())
 		{
 			mBridgeList.push_back((LLSpatialBridge*) drawablep);
@@ -431,32 +589,27 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	group->clearDrawMap();
 	
 	//get geometry count
-	group->mIndexCount = 0;
-	group->mVertexCount = 0;
-
-	addGeometryCount(group, group->mVertexCount, group->mIndexCount);
+	U32 index_count = 0;
+	U32 vertex_count = 0;
+	
+	addGeometryCount(group, vertex_count, index_count);
 
-	if (group->mVertexCount > 0 && group->mIndexCount > 0)
+	if (vertex_count > 0 && index_count > 0)
 	{ //create vertex buffer containing volume geometry for this node
 		group->mBuilt = 1.f;
 		if (group->mVertexBuffer.isNull() || (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
 		{
-			//LLFastTimer ftm(LLFastTimer::FTM_REBUILD_NONE_VB);
 			group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
-			group->mVertexBuffer->allocateBuffer(group->mVertexCount, group->mIndexCount, true);
+			group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
 			stop_glerror();
 		}
 		else
 		{
-			//LLFastTimer ftm(LLFastTimer::FTM_REBUILD_NONE_VB);
-			group->mVertexBuffer->resizeBuffer(group->mVertexCount, group->mIndexCount);
+			group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
 			stop_glerror();
 		}
 		
-		{
-			LLFastTimer ftm((LLFastTimer::EFastTimerType) ((U32) LLFastTimer::FTM_REBUILD_VOLUME_VB + mPartitionType));
-			getGeometry(group);
-		}
+		getGeometry(group);
 	}
 	else
 	{
@@ -465,12 +618,12 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	}
 
 	group->mLastUpdateTime = gFrameTimeSeconds;
-	group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MATRIX_DIRTY);
+	group->clearState(LLSpatialGroup::GEOM_DIRTY);
 }
 
 BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
 {	
-	const OctreeState* node = mOctreeNode->getOctState();
+	const OctreeNode* node = mOctreeNode;
 
 	if (node->getData().empty())
 	{	//don't do anything if there are no objects
@@ -489,7 +642,7 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 		clearState(OBJECT_DIRTY);
 
 		//initialize bounding box to first element
-		OctreeState::const_element_iter i = node->getData().begin();
+		OctreeNode::const_element_iter i = node->getData().begin();
 		LLDrawable* drawablep = *i;
 		const LLVector3* minMax = drawablep->getSpatialExtents();
 
@@ -612,6 +765,11 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 				}
 			}
 		}
+
+		if (getElementCount() == 0)
+		{ //delete draw map on last element removal since a rebuild might never happen
+			clearDrawMap();
+		}
 	}
 	return TRUE;
 }
@@ -629,7 +787,21 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
 	mObjectExtents[0] += offset;
 	mObjectExtents[1] += offset;
 
-	setState(GEOM_DIRTY | MATRIX_DIRTY | OCCLUSION_DIRTY);
+	if (!mSpatialPartition->mRenderByGroup)
+	{
+		setState(GEOM_DIRTY);
+	}
+
+	if (mOcclusionVerts)
+	{
+		for (U32 i = 0; i < 8; i++)
+		{
+			F32* v = mOcclusionVerts+i*3;
+			v[0] += offset.mV[0];
+			v[1] += offset.mV[1];
+			v[2] += offset.mV[2];
+		}
+	}
 }
 
 class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
@@ -637,7 +809,7 @@ class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
 public:
 	U32 mState;
 	LLSpatialSetState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
 };
 
 class LLSpatialSetStateDiff : public LLSpatialSetState
@@ -656,9 +828,22 @@ class LLSpatialSetStateDiff : public LLSpatialSetState
 	}
 };
 
+void LLSpatialGroup::setState(U32 state) 
+{ 
+	if (!LLSpatialPartition::sFreezeState)
+	{
+		mState |= state; 
+	}
+}	
+
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	if (LLSpatialPartition::sFreezeState)
+	{
+		return;
+	}
+
 	if (mode > STATE_MODE_SINGLE)
 	{
 		if (mode == STATE_MODE_DIFF)
@@ -683,7 +868,7 @@ class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
 public:
 	U32 mState;
 	LLSpatialClearState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
 };
 
 class LLSpatialClearStateDiff : public LLSpatialClearState
@@ -695,17 +880,29 @@ class LLSpatialClearStateDiff : public LLSpatialClearState
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 		
-		if (!group->isState(mState))
+		if (group->isState(mState))
 		{
 			LLSpatialGroup::OctreeTraveler::traverse(n);
 		}
 	}
 };
 
+void LLSpatialGroup::clearState(U32 state)
+{
+	if (!LLSpatialPartition::sFreezeState)
+	{
+		mState &= ~state; 
+	}
+}
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	if (LLSpatialPartition::sFreezeState)
+	{
+		return;
+	}
+
 	if (mode > STATE_MODE_SINGLE)
 	{
 		if (mode == STATE_MODE_DIFF)
@@ -723,20 +920,6 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)
 	{
 		mState &= ~state;
 	}
-
-#if LL_OCTREE_PARANOIA_CHECK
-	if (state & LLSpatialGroup::ACTIVE_OCCLUSION)
-	{
-		LLSpatialPartition* part = mSpatialPartition;
-		for (U32 i = 0; i < part->mOccludedList.size(); i++)
-		{
-			if (part->mOccludedList[i] == this)
-			{
-				llerrs << "LLSpatialGroup state error: " << mState << llendl;
-			}
-		}
-	}
-#endif
 }
 
 //======================================
@@ -750,15 +933,15 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	mSpatialPartition(part),
 	mVertexBuffer(NULL), 
 	mBufferUsage(GL_STATIC_DRAW_ARB),
+	mVisible(0),
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
 	mLastUpdateTime(gFrameTimeSeconds),
-	mLastAddTime(gFrameTimeSeconds),
-	mLastRenderTime(gFrameTimeSeconds),
 	mViewAngle(0.f),
 	mLastUpdateViewAngle(-1.f)
 {
+	sNodeCount++;
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
 	sg_assert(mOctreeNode->getListenerCount() == 0);
@@ -771,6 +954,9 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
 	mLODHash = part->mLODSeed;
 	
+	mOcclusionQuery = 0;
+	mOcclusionVerts = NULL;
+
 	mRadius = 1;
 	mPixelArea = 1024.f;
 }
@@ -783,7 +969,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 		llerrs << "Spatial group dirty on distance update." << llendl;
 	}
 #endif
-	if (!getData().empty())
+	if (!getData().empty() && !LLSpatialPartition::sFreezeState)
 	{
 		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() :
 						(F32) mOctreeNode->getSize().magVec();
@@ -805,19 +991,22 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 
 		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
 		{
-			LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0),
-											eye * LLVector3(0,1,0),
-											eye * LLVector3(0,0,1));
-
-			if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f)
+			if (!group->mSpatialPartition->isBridge())
 			{
-				group->mViewAngle = view_angle;
-				group->mLastUpdateViewAngle = view_angle;
-				//for occasional alpha sorting within the group
-				//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
-				//not setting this node to dirty would be a very good thing
-				group->setState(LLSpatialGroup::ALPHA_DIRTY);
-			}		
+				LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0),
+												 eye * LLVector3(0,1,0),
+												 eye * LLVector3(0,0,1));
+
+				if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f)
+				{
+					group->mViewAngle = view_angle;
+					group->mLastUpdateViewAngle = view_angle;
+					//for occasional alpha sorting within the group
+					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
+					//not setting this node to dirty would be a very good thing
+					group->setState(LLSpatialGroup::ALPHA_DIRTY);
+				}
+			}
 		}
 
 		//calculate depth of node for alpha sorting
@@ -831,17 +1020,6 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 		}
 
 		group->mDepth = v * at;
-
-		F32 water_height = gAgent.getRegion()->getWaterHeight();
-		//figure out if this node is above or below water
-		if (group->mObjectBounds[0].mV[2] < water_height)
-		{
-			group->setState(LLSpatialGroup::BELOW_WATER);
-		}
-		else
-		{
-			group->clearState(LLSpatialGroup::BELOW_WATER);
-		}
 	}
 	else
 	{
@@ -863,6 +1041,11 @@ F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
 	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
 }
 
+BOOL LLSpatialGroup::needsUpdate()
+{
+	return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
+}
+
 BOOL LLSpatialGroup::changeLOD()
 {
 	if (isState(ALPHA_DIRTY))
@@ -885,7 +1068,7 @@ BOOL LLSpatialGroup::changeLOD()
 		}
 	}
 	
-	if (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash)
+	if (needsUpdate())
 	{
 		return TRUE;
 	}
@@ -923,7 +1106,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 	}
 	
 	clearDrawMap();
-	mOcclusionVerts = NULL;
 	mVertexBuffer = NULL;
 	mBufferMap.clear();
 	sZombieGroups++;
@@ -954,6 +1136,8 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 	}
 
 	unbound();
+
+	assert_states_valid(this);
 }
 
 void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
@@ -963,17 +1147,23 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo
 
 void LLSpatialGroup::destroyGL() 
 {
-	setState(LLSpatialGroup::GEOM_DIRTY | 
-					LLSpatialGroup::OCCLUSION_DIRTY |
-					LLSpatialGroup::IMAGE_DIRTY);
+	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
 	mLastUpdateTime = gFrameTimeSeconds;
 	mVertexBuffer = NULL;
 	mBufferMap.clear();
 
-	mOcclusionVerts = NULL;
 	mReflectionMap = NULL;
 	clearDrawMap();
 
+	if (mOcclusionQuery)
+	{
+		sQueryPool.release(mOcclusionQuery);
+		mOcclusionQuery = 0;
+	}
+
+	delete [] mOcclusionVerts;
+	mOcclusionVerts = NULL;
+
 	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
 	{
 		LLDrawable* drawable = *i;
@@ -993,15 +1183,6 @@ BOOL LLSpatialGroup::rebound()
 		return TRUE;
 	}
 	
-	LLVector3 oldBounds[2];
-	
-	if (mSpatialPartition->isVolatile() && isState(QUERY_OUT))
-	{	//a query has been issued, if our bounding box changes significantly
-		//we need to discard the issued query
-		oldBounds[0] = mBounds[0];
-		oldBounds[1] = mBounds[1];
-	}
-	
 	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
@@ -1015,7 +1196,7 @@ BOOL LLSpatialGroup::rebound()
 		
 		group->setState(SKIP_FRUSTUM_CHECK);
 	}
-	else if (mOctreeNode->hasLeafState())
+	else if (mOctreeNode->isLeaf())
 	{ //copy object bounding box if this is a leaf
 		boundObjects(TRUE, mExtents[0], mExtents[1]);
 		mBounds[0] = mObjectBounds[0];
@@ -1060,19 +1241,6 @@ BOOL LLSpatialGroup::rebound()
 		mBounds[1] = (newMax - newMin)*0.5f;
 	}
 	
-	if (mSpatialPartition->isVolatile() && isState(QUERY_OUT))
-	{
-		for (U32 i = 0; i < 3 && !isState(DISCARD_QUERY); i++)
-		{
-			if (fabsf(mBounds[0].mV[i]-oldBounds[0].mV[i]) > SG_DISCARD_TOLERANCE ||
-				fabsf(mBounds[1].mV[i]-oldBounds[1].mV[i]) > SG_DISCARD_TOLERANCE)
-			{	//bounding box changed significantly, discard last issued
-				//occlusion query
-				setState(DISCARD_QUERY);
-			}
-		}
-	}
-	
 	setState(OCCLUSION_DIRTY);
 	
 	clearState(DIRTY);
@@ -1080,38 +1248,117 @@ BOOL LLSpatialGroup::rebound()
 	return TRUE;
 }
 
-//==============================================
-
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL is_volatile, U32 buffer_usage)
+void LLSpatialGroup::checkOcclusion()
 {
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	mDrawableType = 0;
-	mPartitionType = LLPipeline::PARTITION_NONE;
-	mVolatile = is_volatile;
-	mLODSeed = 0;
-	mLODPeriod = 1;
-	mVertexDataMask = data_mask;
-	mBufferUsage = buffer_usage;
-	mDepthMask = FALSE;
-	mSlopRatio = 0.25f;
-	mRenderByGroup = TRUE;
-	mImageEnabled = FALSE;
+	if (LLPipeline::sUseOcclusion > 1)
+	{
+		LLSpatialGroup* parent = getParent();
+		if (parent && parent->isState(LLSpatialGroup::OCCLUDED))
+		{	//if the parent has been marked as occluded, the child is implicitly occluded
+			clearState(QUERY_PENDING | DISCARD_QUERY);
+		}
+		else if (isState(QUERY_PENDING))
+		{	//otherwise, if a query is pending, read it back
+			LLFastTimer t(LLFastTimer::FTM_OCCLUSION_READBACK);
+			GLuint res = 1;
+			if (!isState(DISCARD_QUERY) && mOcclusionQuery)
+			{
+				glGetQueryObjectuivARB(mOcclusionQuery, GL_QUERY_RESULT_ARB, &res);	
+			}
 
-	mOctree = new LLSpatialGroup::OctreeNode(LLVector3d(0,0,0), 
-											LLVector3d(1,1,1), 
-											new LLSpatialGroup::OctreeRoot(), NULL);
-	new LLSpatialGroup(mOctree, this);
-}
+			if (res > 0)
+			{
+				assert_states_valid(this);
+				clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+				assert_states_valid(this);
+			}
+			else
+			{
+				assert_states_valid(this);
+				setState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+				assert_states_valid(this);
+			}
 
+			clearState(QUERY_PENDING | DISCARD_QUERY);
+		}
+		else if (mSpatialPartition->mOcclusionEnabled)
+		{
+			assert_states_valid(this);
+			clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+			assert_states_valid(this);
+		}
+	}
+}
 
-LLSpatialPartition::~LLSpatialPartition()
+void LLSpatialGroup::doOcclusion(LLCamera* camera)
 {
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	
-	for (U32 i = 0; i < mOcclusionQueries.size(); i++)
+	if (mSpatialPartition->mOcclusionEnabled && LLPipeline::sUseOcclusion > 1)
 	{
-		glDeleteQueriesARB(1, (GLuint*)(&(mOcclusionQueries[i])));
+		if (earlyFail(camera, this))
+		{
+			setState(LLSpatialGroup::DISCARD_QUERY);
+			assert_states_valid(this);
+			clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+			assert_states_valid(this);
+		}
+		else
+		{
+			{
+				LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION);
+
+				if (!mOcclusionQuery)
+				{
+					mOcclusionQuery = sQueryPool.allocate();
+				}
+
+				if (!mOcclusionVerts || isState(LLSpatialGroup::OCCLUSION_DIRTY))
+				{
+					buildOcclusion();
+				}
+
+				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery);					
+				glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
+				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+							GL_UNSIGNED_BYTE, get_occlusion_indices(camera, mBounds[0]));
+				glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+			}
+
+			setState(LLSpatialGroup::QUERY_PENDING);
+			clearState(LLSpatialGroup::DISCARD_QUERY);
+		}
 	}
+}
+
+//==============================================
+
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, U32 buffer_usage)
+{
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	mOcclusionEnabled = TRUE;
+	mDrawableType = 0;
+	mPartitionType = LLViewerRegion::PARTITION_NONE;
+	mLODSeed = 0;
+	mLODPeriod = 1;
+	mVertexDataMask = data_mask;
+	mBufferUsage = buffer_usage;
+	mDepthMask = FALSE;
+	mSlopRatio = 0.25f;
+	mRenderByGroup = TRUE;
+	mImageEnabled = FALSE;
+	mInfiniteFarClip = FALSE;
+
+	LLGLNamePool::registerPool(&sQueryPool);
+
+	mOctree = new LLSpatialGroup::OctreeRoot(LLVector3d(0,0,0), 
+											LLVector3d(1,1,1), 
+											NULL);
+	new LLSpatialGroup(mOctree, this);
+}
+
+
+LLSpatialPartition::~LLSpatialPartition()
+{
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	
 	delete mOctree;
 	mOctree = NULL;
@@ -1121,22 +1368,6 @@ LLSpatialPartition::~LLSpatialPartition()
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	const F32 MAX_MAG = 1000000.f*1000000.f; // 1 million
-			
-	if (drawablep->getPositionGroup().magVecSquared() > MAX_MAG)
-	{
-#if 0 //ndef LL_RELEASE_FOR_DOWNLOAD
-		llwarns << "LLSpatialPartition::put Object out of range!" << llendl;
-		llinfos << drawablep->getPositionGroup() << llendl;
-
-		if (drawablep->getVObj())
-		{
-			llwarns << "Dumping debugging info: " << llendl;
-			drawablep->getVObj()->dump(); 
-		}
-#endif
-		return NULL;
-	}
 		
 	drawablep->updateSpatialExtents();
 	validate_drawable(drawablep);
@@ -1147,11 +1378,10 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 	assert_octree_valid(mOctree);
 	mOctree->insert(drawablep);
 	assert_octree_valid(mOctree);
-
-	LLSpatialGroup::OctreeNode* node = mOctree->getNodeAt(drawablep);
 	
-	LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-	if (was_visible && group->isState(LLSpatialGroup::QUERY_OUT))
+	LLSpatialGroup* group = drawablep->getSpatialGroup();
+
+	if (group && was_visible && group->isState(LLSpatialGroup::QUERY_PENDING))
 	{
 		group->setState(LLSpatialGroup::DISCARD_QUERY);
 	}
@@ -1178,11 +1408,11 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE);
-
+		
 	// sanity check submitted by open source user bushing Spatula
 	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
-	if (!drawablep) {
+	if (!drawablep)
+	{
 		OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl;
 		return;
 	}
@@ -1225,7 +1455,7 @@ class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
 {
 public:
 	LLSpatialShift(LLVector3 offset) : mOffset(offset) { }
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) 
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 	{ 
 		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
 	}
@@ -1234,39 +1464,27 @@ class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
 };
 
 void LLSpatialPartition::shift(const LLVector3 &offset)
-{
+{ //shift octree node bounding boxes by offset
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	llinfos << "Shifting octree: " << offset << llendl;
 	LLSpatialShift shifter(offset);
 	shifter.traverse(mOctree);
 }
 
-BOOL LLSpatialPartition::checkOcclusion(LLSpatialGroup* group, LLCamera* camera)
-{
-	if (LLPipeline::sUseOcclusion &&
-		!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION | LLSpatialGroup::OCCLUDED) &&
-		(!camera || !earlyFail(camera, group)))
-	{
-		group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
-		mQueryQueue.push(group);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
 class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 {
 public:
 	LLOctreeCull(LLCamera* camera)
 		: mCamera(camera), mRes(0) { }
 
-	virtual bool earlyFail(const LLSpatialGroup* group)
+	virtual bool earlyFail(LLSpatialGroup* group)
 	{
+		group->checkOcclusion();
+
 		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
-			LLPipeline::sUseOcclusion &&			//never occlusion cull selection
+			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 			group->isState(LLSpatialGroup::OCCLUDED))
 		{
+			gPipeline.markOccluder(group);
 			return true;
 		}
 		
@@ -1289,31 +1507,39 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 		}
 		else
 		{
-			mRes = mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+			mRes = frustumCheck(group);
 				
 			if (mRes)
 			{ //at least partially in, run on down
 				LLSpatialGroup::OctreeTraveler::traverse(n);
 			}
-			else
-			{
-				lateFail(group);
-			}
+
 			mRes = 0;
 		}
 	}
 	
-	virtual void lateFail(LLSpatialGroup* group)
+	virtual S32 frustumCheck(const LLSpatialGroup* group)
 	{
-		if (!group->isState(LLSpatialGroup::CULLED))
-		{ //totally culled, so are all its children
-			group->setState(LLSpatialGroup::CULLED, LLSpatialGroup::STATE_MODE_DIFF);
+		S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
 		}
+		return res;
 	}
 
-	virtual bool checkObjects(const LLSpatialGroup::OctreeState* branch, const LLSpatialGroup* group)
+	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	{
+		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+		}
+		return res;
+	}
+
+	virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
 	{
-			
 		if (branch->getElementCount() == 0) //no elements
 		{
 			return false;
@@ -1322,7 +1548,7 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 		{
 			return true;
 		}
-		else if (mRes == 1 && !mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1])) //no objects in frustum
+		else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
 		{
 			return false;
 		}
@@ -1332,20 +1558,9 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 
 	virtual void preprocess(LLSpatialGroup* group)
 	{
-		if (group->isState(LLSpatialGroup::CULLED))
-		{	//this is the first frame this node is visible
-			group->clearState(LLSpatialGroup::CULLED);
-			if (group->mOctreeNode->hasLeafState())
-			{	//if it's a leaf, force it onto the active occlusion list to prevent
-				//massive frame stutters
-				group->mSpatialPartition->checkOcclusion(group, mCamera);
-			}
-		}
-
 		if (LLPipeline::sDynamicReflections &&
 			group->mOctreeNode->getSize().mdV[0] == 16.0 && 
-			group->mDistance < 64.f &&
-			group->mLastAddTime < gFrameTimeSeconds - 2.f)
+			group->mDistance < 64.f)
 		{
 			group->mSpatialPartition->markReimage(group);
 		}
@@ -1353,10 +1568,15 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 	
 	virtual void processGroup(LLSpatialGroup* group)
 	{
+		if (group->needsUpdate() ||
+			group->mVisible < LLDrawable::getCurrentFrame() - 1)
+		{
+			group->doOcclusion(mCamera);
+		}
 		gPipeline.markNotCulled(group, *mCamera);
 	}
 	
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) 
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 	{	
 		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 
@@ -1372,6 +1592,17 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 	S32 mRes;
 };
 
+class LLOctreeCullNoFarClip : public LLOctreeCull
+{
+public: 
+	LLOctreeCullNoFarClip(LLCamera* camera) 
+		: LLOctreeCull(camera) { }
+
+	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	{
+		return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+	}
+};
 
 class LLOctreeSelect : public LLOctreeCull
 {
@@ -1379,15 +1610,14 @@ class LLOctreeSelect : public LLOctreeCull
 	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
 		: LLOctreeCull(camera), mResults(results) { }
 
-	virtual bool earlyFail(const LLSpatialGroup* group) { return false; }
-	virtual void lateFail(LLSpatialGroup* group) { }
+	virtual bool earlyFail(LLSpatialGroup* group) { return false; }
 	virtual void preprocess(LLSpatialGroup* group) { }
 
 	virtual void processGroup(LLSpatialGroup* group)
 	{
-		LLSpatialGroup::OctreeState* branch = group->mOctreeNode->getOctState();
+		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
 
-		for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 		{
 			LLDrawable* drawable = *i;
 			
@@ -1408,67 +1638,41 @@ class LLOctreeSelect : public LLOctreeCull
 	std::vector<LLDrawable*>* mResults;
 };
 
-
-void genBoxList()
+void drawBox(const LLVector3& c, const LLVector3& r)
 {
-	if (sBoxList != 0)
-	{
-		return;
-	}
-
-	sBoxList = glGenLists(1);
-	glNewList(sBoxList, GL_COMPILE);
-	
-	LLVector3 c,r;
-	c = LLVector3(0,0,0);
-	r = LLVector3(1,1,1);
-
-	glBegin(GL_TRIANGLE_STRIP);
+	gGL.begin(GL_TRIANGLE_STRIP);
 	//left front
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
 	//right front
-	glVertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
 	//right back
- 	glVertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+ 	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
 	//left back
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
 	//left front
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
-	glEnd();
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	gGL.end();
 	
 	//bottom
-	glBegin(GL_TRIANGLE_STRIP);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
-	glEnd();
+	gGL.begin(GL_TRIANGLE_STRIP);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+	gGL.end();
 
 	//top
-	glBegin(GL_TRIANGLE_STRIP);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
-	glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
-	glEnd();	
-
-	glEndList();
-}
-
-void drawBox(const LLVector3& c, const LLVector3& r)
-{
-	genBoxList();
-
-	glPushMatrix();
-	glTranslatef(c.mV[0], c.mV[1], c.mV[2]);
-	glScalef(r.mV[0], r.mV[1], r.mV[2]);
-	glCallList(sBoxList);
-	glPopMatrix();
+	gGL.begin(GL_TRIANGLE_STRIP);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+	gGL.end();	
 }
 
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
@@ -1478,44 +1682,49 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
 	LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
 	LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
 
-	glBegin(GL_LINE_LOOP); //top
-	glVertex3fv((pos+v1).mV);
-	glVertex3fv((pos+v2).mV);
-	glVertex3fv((pos+v3).mV);
-	glVertex3fv((pos+v4).mV);
-	glEnd();
-
-	glBegin(GL_LINE_LOOP); //bottom
-	glVertex3fv((pos-v1).mV);
-	glVertex3fv((pos-v2).mV);
-	glVertex3fv((pos-v3).mV);
-	glVertex3fv((pos-v4).mV);
-	glEnd();
-
-
-	glBegin(GL_LINES);
-
+	gGL.begin(GL_LINES); 
+	
+	//top
+	gGL.vertex3fv((pos+v1).mV);
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos+v1).mV);
+	
+	//bottom
+	gGL.vertex3fv((pos-v1).mV);
+	gGL.vertex3fv((pos-v2).mV);
+	gGL.vertex3fv((pos-v2).mV);
+	gGL.vertex3fv((pos-v3).mV);
+	gGL.vertex3fv((pos-v3).mV);
+	gGL.vertex3fv((pos-v4).mV);
+	gGL.vertex3fv((pos-v4).mV);
+	gGL.vertex3fv((pos-v1).mV);
+	
 	//right
-	glVertex3fv((pos+v1).mV);
-	glVertex3fv((pos-v3).mV);
+	gGL.vertex3fv((pos+v1).mV);
+	gGL.vertex3fv((pos-v3).mV);
 			
-	glVertex3fv((pos+v4).mV);
-	glVertex3fv((pos-v2).mV);
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos-v2).mV);
 
 	//left
-	glVertex3fv((pos+v2).mV);
-	glVertex3fv((pos-v4).mV);
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos-v4).mV);
 
-	glVertex3fv((pos+v3).mV);
-	glVertex3fv((pos-v1).mV);
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos-v1).mV);
 
-	glEnd();
+	gGL.end();
 }
 
 class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 {
 public:
-	virtual void visit(const LLOctreeState<LLDrawable>* state)
+	virtual void visit(const LLOctreeNode<LLDrawable>* state)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 		group->destroyGL();
@@ -1540,47 +1749,45 @@ class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 void LLSpatialPartition::restoreGL()
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	mOcclusionQueries.clear();
-	sBoxList = 0;
-
-	//generate query ids
-	while (mOcclusionQueries.size() < mOccludedList.size())
-	{
-		GLuint id;
-		glGenQueriesARB(1, &id);
-		mOcclusionQueries.push_back(id);
-	}
-
-	for (U32 i = 0; i < mOccludedList.size(); i++)
-	{	//previously issued queries are now invalid
-		mOccludedList[i]->setState(LLSpatialGroup::DISCARD_QUERY);
-	}
-	
-	genBoxList();
 }
 
 void LLSpatialPartition::resetVertexBuffers()
 {
 	LLOctreeDirty dirty;
 	dirty.traverse(mOctree);
-
-	mOcclusionIndices = NULL;
 }
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
 	{
+		BOOL temp = sFreezeState;
+		sFreezeState = FALSE;
 		LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
+		sFreezeState = temp;
 	}
+
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
 	
 	if (for_select)
 	{
 		LLOctreeSelect selecter(&camera, results);
 		selecter.traverse(mOctree);
 	}
+	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+	{
+		LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL);		
+		LLOctreeCullNoFarClip culler(&camera);
+		culler.traverse(mOctree);
+	}
 	else
 	{
 		LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL);		
@@ -1591,61 +1798,13 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	return 0;
 }
 
-class LLOctreeClearOccludedNotActive : public LLSpatialGroup::OctreeTraveler
-{
-public:
-	LLOctreeClearOccludedNotActive() { }
-
-	virtual void traverse(const LLSpatialGroup::TreeNode* n)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-		if ((!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION)) //|| group->isState(LLSpatialGroup::QUERY_PENDING)
-			|| group->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION))
-		{	//the children are all occluded or culled as well
-			group->clearState(LLSpatialGroup::OCCLUDED);
-			for (U32 i = 0; i < group->mOctreeNode->getChildCount(); i++)
-			{
-				traverse(group->mOctreeNode->getChild(i));
-			}
-		}
-	}
-
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
-};
-
-class LLQueueNonCulled : public LLSpatialGroup::OctreeTraveler
-{
-public:
-	std::queue<LLSpatialGroup*>* mQueue;
-	LLQueueNonCulled(std::queue<LLSpatialGroup*> *queue) : mQueue(queue) { }
-
-	virtual void traverse(const LLSpatialGroup::TreeNode* n)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-		if (group->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED))
-		{	//the children are all occluded or culled as well
-			return;
-		}
-
-		if (!group->isState(LLSpatialGroup::IN_QUEUE))
-		{
-			group->setState(LLSpatialGroup::IN_QUEUE);
-			mQueue->push(group);
-		}
-
-		LLSpatialGroup::OctreeTraveler::traverse(n);
-	}
-
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
-};
-
 BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 {
+	const F32 vel = (gCamera->getVelocityStat()->getCurrent()+0.2f);
 	LLVector3 c = group->mBounds[0];
-	LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.2f,0.2f,0.2f);
+	LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(vel,vel,vel);
     
-	//if (group->isState(LLSpatialGroup::CULLED)) // || 
-	if (!camera->AABBInFrustum(c, r))
+	if (r.magVecSquared() > 1024.0*1024.0)
 	{
 		return TRUE;
 	}
@@ -1687,633 +1846,63 @@ void LLSpatialPartition::processImagery(LLCamera* camera)
 
 	U32 process_count = 1;
 
-	while (process_count > 0 && !mImageQueue.empty())
+	S32 pull_count = (S32) mImageQueue.size();
+
+	while (process_count > 0 && pull_count > 0 && !mImageQueue.empty())
 	{
+		pull_count--;
 		LLPointer<LLSpatialGroup> group = mImageQueue.front();
 		mImageQueue.pop();
-	
-		group->clearState(LLSpatialGroup::IN_IMAGE_QUEUE);
-
-		if (group->isDead())
-		{
-			continue;
-		}
-
-		if (LLPipeline::sDynamicReflections)
-		{
-			process_count--;
-			LLVector3 origin = group->mBounds[0];
-			
-			LLCamera cube_cam;
-			cube_cam.setOrigin(origin);
-			cube_cam.setFar(64.f);
-
-			LLPointer<LLCubeMap> cube_map = group->mReflectionMap;
-			group->mReflectionMap = NULL;
-			if (cube_map.isNull())
-			{
-				cube_map = new LLCubeMap();
-				cube_map->initGL();
-			}
-
-			if (gPipeline.mCubeBuffer.isNull())
-			{
-				gPipeline.mCubeBuffer = new LLCubeMap();
-				gPipeline.mCubeBuffer->initGL();
-			}
-
-			S32 res = gSavedSettings.getS32("RenderReflectionRes");
-			gPipeline.generateReflectionMap(gPipeline.mCubeBuffer, cube_cam, 128);
-			gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, res);
-			group->mReflectionMap = cube_map;
-			group->setState(LLSpatialGroup::GEOM_DIRTY);
-		}
-
-		group->clearState(LLSpatialGroup::IMAGE_DIRTY);
-	}
-}
-
-void validate_occlusion_list(std::vector<LLPointer<LLSpatialGroup> >& occluded_list)
-{
-#if !LL_RELEASE_FOR_DOWNLOAD
-	for (U32 i = 0; i < occluded_list.size(); i++)
-	{
-		LLSpatialGroup* group = occluded_list[i];
-		for (U32 j = i+1; j < occluded_list.size(); j++)
-		{
-			if (occluded_list[i] == occluded_list[j])
-			{
-				llerrs << "Duplicate node in occlusion list." << llendl;
-			}
-		}
-
-		LLSpatialGroup::OctreeNode* parent = group->mOctreeNode->getOctParent();
-		while (parent)
-		{
-			LLSpatialGroup* parent_group = (LLSpatialGroup*) parent->getListener(0);
-			if (parent_group->isState(LLSpatialGroup::OCCLUDED))
-			{
-				llerrs << "Child node of occluded node in occlusion list (redundant query)." << llendl;
-			}
-			parent = parent->getOctParent();
-		}
-	}
-#endif
-}
-
-void LLSpatialPartition::processOcclusion(LLCamera* camera)
-{
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	LLSpatialGroup* rootGroup = (LLSpatialGroup*) mOctree->getListener(0);
-	{
-		LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);	
-		rootGroup->rebound();
-	}
-	
-	//update potentials 
-	if (!rootGroup->isState(LLSpatialGroup::IN_QUEUE))
-	{
-		rootGroup->setState(LLSpatialGroup::IN_QUEUE);
-		mOcclusionQueue.push(rootGroup);
-	}
-
-	const U32 MAX_PULLED = 32;
-	const U32 MAX_PUSHED = mOcclusionQueue.size();
-	U32 count = 0;
-	U32 pcount = 0;
-	
-	while (pcount < MAX_PUSHED && count < MAX_PULLED && !mOcclusionQueue.empty())
-	{
-		LLFastTimer t(LLFastTimer::FTM_OCCLUSION);
-
-		LLPointer<LLSpatialGroup> group = mOcclusionQueue.front();
-		if (!group->isState(LLSpatialGroup::IN_QUEUE))
-		{
-			OCT_ERRS << "Spatial Group State Error.  Group in queue not tagged as such." << llendl;
-		}
-
-		mOcclusionQueue.pop();
-		group->clearState(LLSpatialGroup::IN_QUEUE);
-
-		if (group->isDead())
-		{
-			continue;
-		}
-
-		if (group->isState(LLSpatialGroup::CULLED | LLSpatialGroup::OCCLUDED))
-		{	//already culled, skip it
-			continue;
-		}
-
-		//before we process, enqueue this group's children
-		for (U32 i = 0; i < group->mOctreeNode->getChildCount(); i++)
-		{
-			LLSpatialGroup* child = (LLSpatialGroup*) group->mOctreeNode->getChild(i)->getListener(0);
-
-			//if (!child->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED)
-			if (!child->isState(LLSpatialGroup::IN_QUEUE | LLSpatialGroup::ACTIVE_OCCLUSION))
-			{
-				child->setState(LLSpatialGroup::IN_QUEUE);
-				mOcclusionQueue.push(child);
-			}
-		}
-		
-		if (earlyFail(camera, group))
-		{
-			sg_assert(!group->isState(LLSpatialGroup::OCCLUDED));
-			group->setState(LLSpatialGroup::IN_QUEUE);
-			mOcclusionQueue.push(group);
-			pcount++;
-			continue;
-		}
-		
-		//add to pending queue
-		if (!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
-		{
-#if LL_OCTREE_PARANOIA_CHECK
-			for (U32 i = 0; i < mOccludedList.size(); ++i)
-			{
-				sg_assert(mOccludedList[i] != group);
-			}
-#endif
-			group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
-			mQueryQueue.push(group);
-			count++;
-		}
-	}
-
-	//read back results from last frame
-	for (U32 i = 0; i < mOccludedList.size(); i++)
-	{
-	 	LLFastTimer t(LLFastTimer::FTM_OCCLUSION_READBACK);
-
-		if (mOccludedList[i]->isDead() || mOccludedList[i]->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION))
-		{
-			continue;
-		}
-		GLuint res = 0;
-			
-		if (mOccludedList[i]->isState(LLSpatialGroup::EARLY_FAIL | LLSpatialGroup::DISCARD_QUERY) ||
-			!mOccludedList[i]->isState(LLSpatialGroup::QUERY_OUT))
-		{
-			mOccludedList[i]->clearState(LLSpatialGroup::EARLY_FAIL);
-			mOccludedList[i]->clearState(LLSpatialGroup::DISCARD_QUERY);
-			res = 1;
-		}
-		else
-		{	
-			glGetQueryObjectuivARB(mOcclusionQueries[i], GL_QUERY_RESULT_ARB, &res);	
-			stop_glerror();
-		}
-		
-		if (res) //NOT OCCLUDED
-		{	
-			if (mOccludedList[i]->isState(LLSpatialGroup::OCCLUDED))
-			{	//this node was occluded last frame
-				LLSpatialGroup::OctreeNode* node = mOccludedList[i]->mOctreeNode;
-				//add any immediate children to the queue that are not already there
-				for (U32 j = 0; j < node->getChildCount(); j++)
-				{
-					LLSpatialGroup* group = (LLSpatialGroup*) node->getChild(j)->getListener(0);
-					checkOcclusion(group, camera);
-				}
-			}
-			
-			//clear occlusion status for everything not on the active list
-			LLOctreeClearOccludedNotActive clear_occluded;
-			mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
-			mOccludedList[i]->clearState(LLSpatialGroup::OCCLUDED);
-			mOccludedList[i]->clearState(LLSpatialGroup::OCCLUDING);
-			clear_occluded.traverse(mOccludedList[i]->mOctreeNode);
-		}
-		else
-		{ //OCCLUDED
-			if (mOccludedList[i]->isState(LLSpatialGroup::OCCLUDING))
-			{
-				if (!mOccludedList[i]->isState(LLSpatialGroup::OCCLUDED))
-				{
-					LLSpatialGroup::OctreeNode* oct_parent = (LLSpatialGroup::OctreeNode*) mOccludedList[i]->mOctreeNode->getParent();
-					if (oct_parent)
-					{
-						LLSpatialGroup* parent = (LLSpatialGroup*) oct_parent->getListener(0);
-						
-						if (checkOcclusion(parent, camera))
-						{	//force a guess on the parent and siblings		
-							for (U32 i = 0; i < parent->mOctreeNode->getChildCount(); i++)
-							{
-								LLSpatialGroup* child = (LLSpatialGroup*) parent->mOctreeNode->getChild(i)->getListener(0);
-								checkOcclusion(child, camera);	
-							}
-						}
-					}
-
-					//take children off the active list
-					mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_BRANCH);
-					mOccludedList[i]->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
-				}
-				mOccludedList[i]->setState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
-			}
-			else
-			{
-				//take children off the active list
-				mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_BRANCH);
-							
-				//keep this node on the active list
-				mOccludedList[i]->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
-
-				//this node is a top level occluder
-				mOccludedList[i]->setState(LLSpatialGroup::OCCLUDING);
-			}
-		}
-
-		mOccludedList[i]->clearState(LLSpatialGroup::QUERY_OUT);
-	}
-
-	//remove non-occluded groups from occluded list
-	for (U32 i = 0; i < mOccludedList.size(); )
-	{
-		if (mOccludedList[i]->isDead() || //needs to be deleted
-			!mOccludedList[i]->isState(LLSpatialGroup::OCCLUDING) || //is not occluding
-			mOccludedList[i]->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION)) //parent is occluded
-		{
-			LLSpatialGroup* groupp = mOccludedList[i];
-			if (!groupp->isDead())
-			{
-				groupp->clearState(LLSpatialGroup::ACTIVE_OCCLUSION);
-				groupp->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
-				groupp->clearState(LLSpatialGroup::OCCLUDING);
-			}
-			mOccludedList.erase(mOccludedList.begin()+i);
-		}
-		else
-		{
-			i++;
-		}
-	}
-
-	validate_occlusion_list(mOccludedList);
-
-	//pump some non-culled items onto the occlusion list
-	//count = MAX_PULLED;
-	while (!mQueryQueue.empty())
-	{
-		LLPointer<LLSpatialGroup> group = mQueryQueue.front();
-		mQueryQueue.pop();
-        //group->clearState(LLSpatialGroup::QUERY_PENDING);
-		mOccludedList.push_back(group);
-	}
-
-	//generate query ids
-	while (mOcclusionQueries.size() < mOccludedList.size())
-	{
-		GLuint id;
-		glGenQueriesARB(1, &id);
-		mOcclusionQueries.push_back(id);
-	}
-}
-
-class LLOcclusionIndexBuffer : public LLVertexBuffer
-{
-public:
-	LLOcclusionIndexBuffer(U32 size)
-		: LLVertexBuffer(0, GL_STREAM_DRAW_ARB)
-	{
-		allocateBuffer(0, size, TRUE);
-
-		LLStrider<U32> idx;
-
-		getIndexStrider(idx);
-
-		//12 triangles' indices
-		idx[0] = 1; idx[1] = 0; idx[2] = 2; //front
-		idx[3] = 3; idx[4] = 2; idx[5] = 0;
-
-		idx[6] = 4; idx[7] = 5; idx[8] = 1; //top
-		idx[9] = 0; idx[10] = 1; idx[11] = 5; 
-
-		idx[12] = 5; idx[13] = 4; idx[14] = 6; //back
-		idx[15] = 7; idx[16] = 6; idx[17] = 4;
-
-		idx[18] = 6; idx[19] = 7; idx[20] = 3; //bottom
-		idx[21] = 2; idx[22] = 3; idx[23] = 7;
-
-		idx[24] = 0; idx[25] = 5; idx[26] = 3; //left
-		idx[27] = 6; idx[28] = 3; idx[29] = 5;
-
-		idx[30] = 4; idx[31] = 1; idx[32] = 7; //right
-		idx[33] = 2; idx[34] = 7; idx[35] = 1;
-	}
-
-	//virtual BOOL useVBOs() const { return FALSE; }
-
-	void setBuffer(U32 data_mask)
-	{
-		if (useVBOs())
-		{
-			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
-			sIBOActive = TRUE;
-			unmapBuffer();
-		}
-		else if (sIBOActive)
-		{
-			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
-			sIBOActive = FALSE;
-		}
 		
-		sGLRenderIndices = mGLIndices;
-	}
-};
-
-class LLOcclusionVertexBuffer : public LLVertexBuffer
-{
-public:
-	LLOcclusionVertexBuffer(S32 usage)
-		: LLVertexBuffer(MAP_VERTEX, usage)
-	{
-		allocateBuffer(8, 0, TRUE);
-	}
-
-	//virtual BOOL useVBOs() const { return FALSE; }
-
-	void setBuffer(U32 data_mask)
-	{
-		if (useVBOs())
-		{
-			glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
-			sVBOActive = TRUE;
-			unmapBuffer();
-		}
-		else if (sVBOActive)
-		{
-			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-			sVBOActive = FALSE;
-		}
-		
-		if (data_mask)
-		{
-			glVertexPointer(3,GL_FLOAT, 0, useVBOs() ? 0 : mMappedData);
-		}
-		
-		sGLRenderBuffer = mGLBuffer;
-	}
-};
-
-void LLSpatialPartition::buildOcclusion()
-{
-	if (mOccludedList.empty())
-	{
-		return;
-	}
-
-	BOOL reset_all = FALSE;
-	if (mOcclusionIndices.isNull())
-	{
-		mOcclusionIndices = new LLOcclusionIndexBuffer(36);
-		reset_all = TRUE;
-	}
-	
-	//fill occlusion vertex buffers
-	for (U32 i = 0; i < mOccludedList.size(); i++)
-	{
-		LLSpatialGroup* group = mOccludedList[i];
-
-		if (group->isState(LLSpatialGroup::OCCLUSION_DIRTY) || reset_all)
-		{
-			LLFastTimer ftm(LLFastTimer::FTM_REBUILD_OCCLUSION_VB);
-
-			if (group->mOcclusionVerts.isNull())
-			{
-				group->mOcclusionVerts = new LLOcclusionVertexBuffer(GL_STREAM_DRAW_ARB);
-			}
-	
-			group->clearState(LLSpatialGroup::OCCLUSION_DIRTY);
-			
-			LLStrider<LLVector3> vert;
-
-			group->mOcclusionVerts->getVertexStrider(vert);
-
-			LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.1f,0.1f,0.1f);
-
-			for (U32 k = 0; k < 3; k++)
-			{
-				r.mV[k] = llmin(group->mBounds[1].mV[k]+0.25f, r.mV[k]);
-			}
-
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,1,1)); //   0 - left top front
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,1,1));  //   1 - right top front
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,-1,1)); //   2 - right bottom front
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,-1,1)); //  3 - left bottom front
-
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,1,-1)); //  4 - left top back
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,1,-1)); //   5 - right top back
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(-1,-1,-1)); //  6 - right bottom back
-			*vert++ = group->mBounds[0] + r.scaledVec(LLVector3(1,-1,-1)); // 7 -left bottom back
-		}
-	}
-
-/*	for (U32 i = 0; i < mOccludedList.size(); i++)
-	{
-		LLSpatialGroup* group = mOccludedList[i];
-		if (!group->mOcclusionVerts.isNull() && group->mOcclusionVerts->isLocked())
-		{
-			LLFastTimer ftm(LLFastTimer::FTM_REBUILD_OCCLUSION_VB);
-			group->mOcclusionVerts->setBuffer(0);
-		}
-	}*/
-}
-
-void LLSpatialPartition::doOcclusion(LLCamera* camera)
-{
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
-	LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION);
-
-#if LL_OCTREE_PARANOIA_CHECK  
-	LLSpatialGroup* check = (LLSpatialGroup*) mOctree->getListener(0);
-	check->validate();
-#endif
-
-	stop_glerror();
-	
-	U32 num_verts = mOccludedList.size() * 8;
-
-	if (num_verts == 0)
-	{
-		return;
-	}
-
-	//actually perform the occlusion queries
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
-	LLGLDisable(GL_TEXTURE_2D);
-	gPipeline.disableLights();
-	LLGLEnable cull_face(GL_CULL_FACE);
-	LLGLDisable blend(GL_BLEND);
-	LLGLDisable alpha_test(GL_ALPHA_TEST);
-	LLGLDisable fog(GL_FOG);
-	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-	glColor4f(1,1,1,1);
-
-	mOcclusionIndices->setBuffer(0);
-
-	U32* indicesp = (U32*) mOcclusionIndices->getIndicesPointer();
-
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-#if !LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkClientArrays(LLVertexBuffer::MAP_VERTEX);
-#endif
-	for (U32 i = 0; i < mOccludedList.size(); i++)
-	{
-#if LL_OCTREE_PARANOIA_CHECK
-		for (U32 j = i+1; j < mOccludedList.size(); j++)
-		{
-			sg_assert(mOccludedList[i] != mOccludedList[j]);
-		}
-#endif
-		LLSpatialGroup* group = mOccludedList[i];
 		if (group->isDead())
 		{
 			continue;
 		}
 
-		if (earlyFail(camera, group))
-		{
-			group->setState(LLSpatialGroup::EARLY_FAIL);
-		}
-		else
-		{ //early rejection criteria passed, send some geometry to the query
-			group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
-			glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQueries[i]);					
-			glDrawRangeElements(GL_TRIANGLES, 0, 7, 36,
-							GL_UNSIGNED_INT, indicesp);
-			glEndQueryARB(GL_SAMPLES_PASSED_ARB);
-
-			group->setState(LLSpatialGroup::QUERY_OUT);
-			group->clearState(LLSpatialGroup::DISCARD_QUERY);
-		}		
-	}
-	stop_glerror();
-	
-	gPipeline.mTrianglesDrawn += mOccludedList.size()*12;
-
-	glFlush();
-
-	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-}
-
-class LLOctreeGet : public LLSpatialGroup::OctreeTraveler
-{
-public:
-	LLOctreeGet(LLVector3 pos, F32 rad, LLDrawable::drawable_set_t* results, BOOL lights)
-		: mPosition(pos), mRad(rad), mResults(results), mLights(lights), mRes(0)
-	{
-
-	}
-
-	virtual void traverse(const LLSpatialGroup::TreeNode* n)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
-		if (mRes == 2) 
-		{ //fully in, just add everything
-			LLSpatialGroup::OctreeTraveler::traverse(n);
-		}
-		else
-		{
-			LLVector3 center, size;
-			
-			center = group->mBounds[0];
-			size = group->mBounds[1];
-						
-			mRes = LLSphereAABB(center, size, mPosition, mRad);		
-			if (mRes > 0)
-			{
-				LLSpatialGroup::OctreeTraveler::traverse(n);
-			}
-			mRes = 0;
-		}
-	}
-
-	static BOOL skip(LLDrawable* drawable, BOOL get_lights)
-	{
-		if (get_lights != drawable->isLight())
-		{
-			return TRUE;
-		}
-		if (get_lights && drawable->getVObj()->isHUDAttachment())
-		{
-			return TRUE; // no lighting from HUD objects
-		}
-		if (get_lights && drawable->isState(LLDrawable::ACTIVE))
-		{
-			return TRUE; // ignore active lights
+		if (group->isState(LLSpatialGroup::GEOM_DIRTY))
+		{ //put it back
+			mImageQueue.push(group);	
+			continue;
 		}
-		return FALSE;
-	}
 
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) 
-	{ 
-		for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		group->clearState(LLSpatialGroup::IN_IMAGE_QUEUE);
+		if (LLPipeline::sDynamicReflections)
 		{
-			LLDrawable* drawable = *i;
-			if (!skip(drawable, mLights))
-			{
-				if (mRes == 2)
-				{
-					mResults->insert(drawable);
-				}
-				else
-				{
-					LLVector3 v = LLVector3(drawable->getPositionGroup())-mPosition;
-					float dsq = v.magVecSquared();
-					float maxd = mRad + drawable->getVisibilityRadius();
-					if (dsq <= maxd*maxd)
-					{
-						mResults->insert(drawable);
-					}
-				}
-			}
-		}
-	}
-
-	LLVector3 mPosition;
-	F32 mRad;
-	LLDrawable::drawable_set_t* mResults;
-	BOOL mLights;
-	U32 mRes;
-};
-
-S32 LLSpatialPartition::getDrawables(const LLVector3& pos, F32 rad,
-									 LLDrawable::drawable_set_t &results,
-									 BOOL get_lights)
-{
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	
-	LLOctreeGet getter(pos, rad, &results, get_lights);
-	getter.traverse(mOctree);
+			process_count--;
+			LLVector3 origin = group->mBounds[0];
+			/*LLVector3 at = camera->getOrigin()-origin;
+			at.normVec();
+			origin += at* (at * group->mBounds[1]);*/
 
-	return results.size();
-}
+			LLCamera cube_cam;
+			cube_cam.setOrigin(origin);
+			cube_cam.setFar(64.f);
 
-S32 LLSpatialPartition::getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results)
-{
-	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-	group->rebound();
-	return getDrawables(pos, rad, results, FALSE);
-}
+			LLPointer<LLCubeMap> cube_map = group->mReflectionMap;
+			group->mReflectionMap = NULL;
+			if (cube_map.isNull())
+			{
+				cube_map = new LLCubeMap();
+				cube_map->initGL();
+			}
 
-S32 LLSpatialPartition::getLights(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results)
-{
-	return getDrawables(pos, rad, results, TRUE);
+			gPipeline.generateReflectionMap(gPipeline.mCubeBuffer, cube_cam);
+			gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map);
+			group->mReflectionMap = cube_map;
+			group->setState(LLSpatialGroup::GEOM_DIRTY);
+		}
+
+		group->clearState(LLSpatialGroup::IMAGE_DIRTY);
+	}
 }
 
 void pushVerts(LLDrawInfo* params, U32 mask)
 {
+	LLRenderPass::applyModelMatrix(*params);
 	params->mVertexBuffer->setBuffer(mask);
-	U32* indicesp = (U32*) params->mVertexBuffer->getIndicesPointer();
+	U16* indicesp = (U16*) params->mVertexBuffer->getIndicesPointer();
 	glDrawRangeElements(params->mParticle ? GL_POINTS : GL_TRIANGLES, params->mStart, params->mEnd, params->mCount,
-					GL_UNSIGNED_INT, indicesp+params->mOffset);
+					GL_UNSIGNED_SHORT, indicesp+params->mOffset);
 }
 
 void pushVerts(LLSpatialGroup* group, U32 mask)
@@ -2330,6 +1919,54 @@ void pushVerts(LLSpatialGroup* group, U32 mask)
 	}
 }
 
+void pushVerts(LLFace* face, U32 mask)
+{
+	LLVertexBuffer* buffer = face->mVertexBuffer;
+
+	if (buffer)
+	{
+		buffer->setBuffer(mask);
+		U16* indicesp = (U16*) buffer->getIndicesPointer();
+		U16 start = face->getGeomStart();
+		U16 end = start + face->getGeomCount()-1;
+		U32 count = face->getIndicesCount();
+		U16 offset = face->getIndicesStart();
+
+		glDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, indicesp + offset);
+	}
+
+}
+
+void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
+{
+	if (buffer)
+	{
+		buffer->setBuffer(mask);
+		U16* indicesp = (U16*) buffer->getIndicesPointer();
+		glDrawRangeElements(GL_TRIANGLES, 0, buffer->getRequestedVerts(), buffer->getRequestedIndices(),
+							GL_UNSIGNED_SHORT, indicesp);
+	}
+}
+
+void pushBufferVerts(LLSpatialGroup* group, U32 mask)
+{
+	if (!group->mDrawMap.empty())
+	{
+		LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
+		LLRenderPass::applyModelMatrix(*params);
+	
+		pushBufferVerts(group->mVertexBuffer, mask);
+
+		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+		{
+			for (LLSpatialGroup::buffer_list_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+			{
+				pushBufferVerts(*j, mask);
+			}
+		}
+	}
+}
+
 void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
 {
 	LLDrawInfo* params = NULL;
@@ -2353,11 +1990,12 @@ void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
 		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) 
 		{
 			params = *j;
+			LLRenderPass::applyModelMatrix(*params);
 			glColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
 			params->mVertexBuffer->setBuffer(mask);
-			U32* indicesp = (U32*) params->mVertexBuffer->getIndicesPointer();
+			U16* indicesp = (U16*) params->mVertexBuffer->getIndicesPointer();
 			glDrawRangeElements(params->mParticle ? GL_POINTS : GL_TRIANGLES, params->mStart, params->mEnd, params->mCount,
-							GL_UNSIGNED_INT, indicesp+params->mOffset);
+							GL_UNSIGNED_SHORT, indicesp+params->mOffset);
 			col = (col+1)%col_count;
 		}
 	}
@@ -2368,7 +2006,7 @@ void renderOctree(LLSpatialGroup* group)
 	//render solid object bounding box, color
 	//coded by buffer usage and activity
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
 	LLVector4 col;
 	if (group->mBuilt > 0.f)
 	{
@@ -2385,34 +2023,59 @@ void renderOctree(LLSpatialGroup* group)
 
 		if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
 		{
-			if (group->mBufferUsage == GL_DYNAMIC_DRAW_ARB)
-			{
-				glColor4f(1,0,0,group->mBuilt);
-			}
-			else
-			{
-				glColor4f(1,1,0,group->mBuilt);
-			}
-
 			LLGLDepthTest gl_depth(FALSE, FALSE);
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+			gGL.color4f(1,0,0,group->mBuilt);
+			gGL.flush();
+			glLineWidth(5.f);
+			drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+			gGL.flush();
+			glLineWidth(1.f);
+			gGL.stop();
 			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 			{
 				LLDrawable* drawable = *i;
+				if (!group->mSpatialPartition->isBridge())
+				{
+					glPushMatrix();
+					LLVector3 trans = drawable->getRegion()->getOriginAgent();
+					glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+				}
+				
 				for (S32 j = 0; j < drawable->getNumFaces(); j++)
 				{
 					LLFace* face = drawable->getFace(j);
-					if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f && face->mVertexBuffer.notNull())
-					{ 
+					if (face->mVertexBuffer.notNull())
+					{
+						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
+						{
+							glColor4f(0, 1, 0, group->mBuilt);
+						}
+						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
+						{
+							glColor4f(1, 0, 0, group->mBuilt);
+						}
+						else
+						{
+							continue;
+						}
+
 						face->mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
 						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
 						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
-						glDrawElements(GL_TRIANGLES, face->getIndicesCount(), GL_UNSIGNED_INT, 
-							((U32*) face->mVertexBuffer->getIndicesPointer())+face->getIndicesStart());
+						glDrawElements(GL_TRIANGLES, face->getIndicesCount(), GL_UNSIGNED_SHORT, 
+							((U16*) face->mVertexBuffer->getIndicesPointer())+face->getIndicesStart());
 					}
 				}
+
+				if (!group->mSpatialPartition->isBridge())
+				{
+					glPopMatrix();
+				}
 			}
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+			gGL.start();
 		}
 	}
 	else
@@ -2428,50 +2091,80 @@ void renderOctree(LLSpatialGroup* group)
 		}
 	}
 
-	glColor4fv(col.mV);
+	gGL.color4fv(col.mV);
 	drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+	
 	glDepthMask(GL_TRUE);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-	//draw opaque outline
-	glColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
-	drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-	if (group->mOctreeNode->hasLeafState())
+	if (group->mBuilt <= 0.f)
 	{
-		glColor4f(1,1,1,1);
-	}
-	else
-	{
-		glColor4f(0,1,1,1);
+		//draw opaque outline
+		gGL.color4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
+		drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+
+		if (group->mOctreeNode->isLeaf())
+		{
+			gGL.color4f(1,1,1,1);
+		}
+		else
+		{
+			gGL.color4f(0,1,1,1);
+		}
+						
+		drawBoxOutline(group->mBounds[0],group->mBounds[1]);
 	}
-					
-	drawBoxOutline(group->mBounds[0],group->mBounds[1]);
 	
 //	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
-//	glColor4f(0,1,0,1);
+//	gGL.color4f(0,1,0,1);
 //	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
 }
 
-void renderVisibility(LLSpatialGroup* group)
+void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 {
 	LLGLEnable blend(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	LLGLEnable cull(GL_CULL_FACE);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+							!group->getData().empty();
+	if (render_objects)
 	{
 		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
 		glColor4f(0, 0.5f, 0, 0.5f);
-		pushVerts(group, LLVertexBuffer::MAP_VERTEX);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 	}
 
 	{
 		LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
-		pushVertsColorCoded(group, LLVertexBuffer::MAP_VERTEX);
+
+		if (render_objects)
+		{
+			glColor4f(0.f, 0.5f, 0.f,1.f);
+			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+		}
 
 		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 
-		pushVertsColorCoded(group, LLVertexBuffer::MAP_VERTEX);
+		if (render_objects)
+		{
+			glColor4f(0.f, 0.75f, 0.f,0.5f);
+			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+		}
+		else if (camera && group->mOcclusionVerts)
+		{
+			LLVertexBuffer::unbind();
+			glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts);
+
+			glColor4f(1.0f, 0.f, 0.f, 0.5f);
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+			
+			glColor4f(1.0f, 1.f, 1.f, 1.0f);
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+		}
 	}
 }
 
@@ -2479,17 +2172,17 @@ void renderBoundingBox(LLDrawable* drawable)
 {
 	if (drawable->isSpatialBridge())
 	{
-		glColor4f(1,0.5f,0,1);
+		gGL.color4f(1,0.5f,0,1);
 	}
 	else if (drawable->getVOVolume())
 	{
 		if (drawable->isRoot())
 		{
-			glColor4f(1,1,0,1);
+			gGL.color4f(1,1,0,1);
 		}
 		else
 		{
-			glColor4f(0,1,0,1);
+			gGL.color4f(0,1,0,1);
 		}
 	}
 	else if (drawable->getVObj())
@@ -2497,27 +2190,27 @@ void renderBoundingBox(LLDrawable* drawable)
 		switch (drawable->getVObj()->getPCode())
 		{
 			case LLViewerObject::LL_VO_SURFACE_PATCH:
-					glColor4f(0,1,1,1);
+					gGL.color4f(0,1,1,1);
 					break;
 			case LLViewerObject::LL_VO_CLOUDS:
-					glColor4f(0.5f,0.5f,0.5f,1.0f);
+					gGL.color4f(0.5f,0.5f,0.5f,1.0f);
 					break;
 			case LLViewerObject::LL_VO_PART_GROUP:
-					glColor4f(0,0,1,1);
+					gGL.color4f(0,0,1,1);
 					break;
 			case LLViewerObject::LL_VO_WATER:
-					glColor4f(0,0.5f,1,1);
+					gGL.color4f(0,0.5f,1,1);
 					break;
 			case LL_PCODE_LEGACY_TREE:
-					glColor4f(0,0.5f,0,1);
+					gGL.color4f(0,0.5f,0,1);
 			default:
-					glColor4f(1,0,1,1);
+					gGL.color4f(1,0,1,1);
 					break;
 		}
 	}
 	else 
 	{
-		glColor4f(1,0,0,1);
+		gGL.color4f(1,0,0,1);
 	}
 
 	const LLVector3* ext;
@@ -2545,7 +2238,20 @@ void renderBoundingBox(LLDrawable* drawable)
 	pos = (ext[0] + ext[1]) * 0.5f;
 	size = (ext[1] - ext[0]) * 0.5f;
 	
-	drawBoxOutline(pos,size);
+	LLViewerObject* vobj = drawable->getVObj();
+	if (vobj && vobj->onActiveList())
+	{
+		gGL.flush();
+		glLineWidth(4.f*sinf(gFrameTimeSeconds*2.f)+1.f);
+		drawBoxOutline(pos,size);
+		gGL.flush();
+		glLineWidth(1.f);
+	}
+	else
+	{
+		drawBoxOutline(pos,size);
+	}
+	
 }
 
 void renderTexturePriority(LLDrawable* drawable)
@@ -2578,14 +2284,12 @@ void renderTexturePriority(LLDrawable* drawable)
 			F32 t = vsize/sLastMaxTexPriority;
 			
 			LLVector4 col = lerp(cold, hot, t);
-			glColor4fv(col.mV);
+			gGL.color4fv(col.mV);
 		}
 		//else
 		//{
-		//	glColor4f(1,0,1,1);
+		//	gGL.color4f(1,0,1,1);
 		//}
-
-		
 		
 		LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f;
 		LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f);
@@ -2597,10 +2301,10 @@ void renderTexturePriority(LLDrawable* drawable)
 			F32 t = (F32) boost / (F32) (LLViewerImage::BOOST_MAX_LEVEL-1);
 			LLVector4 col = lerp(boost_cold, boost_hot, t);
 			LLGLEnable blend_on(GL_BLEND);
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-			glColor4fv(col.mV);
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
+			gGL.color4fv(col.mV);
 			drawBox(center, size);
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 		}*/
 	}
 }
@@ -2608,14 +2312,17 @@ void renderTexturePriority(LLDrawable* drawable)
 void renderPoints(LLDrawable* drawablep)
 {
 	LLGLDepthTest depth(GL_FALSE, GL_FALSE);
-	glBegin(GL_POINTS);
-	glColor3f(1,1,1);
-	LLVector3 center(drawablep->getPositionGroup());
-	for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+	if (drawablep->getNumFaces())
 	{
-		glVertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
+		gGL.begin(GL_POINTS);
+		gGL.color3f(1,1,1);
+		LLVector3 center(drawablep->getPositionGroup());
+		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+		{
+			gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
+		}
+		gGL.end();
 	}
-	glEnd();
 }
 
 void renderTextureAnim(LLDrawInfo* params)
@@ -2626,29 +2333,67 @@ void renderTextureAnim(LLDrawInfo* params)
 	}
 	
 	LLGLEnable blend(GL_BLEND);
-	glColor4f(1,1,0,0.5f);
+	gGL.color4f(1,1,0,0.5f);
+	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderBatchSize(LLDrawInfo* params)
+{
+	glColor3ubv((GLubyte*) &(params->mDebugColor));
 	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 }
 
+void renderLights(LLDrawable* drawablep)
+{
+	if (!drawablep->isLight())
+	{
+		return;
+	}
+
+	if (drawablep->getNumFaces())
+	{
+		LLGLEnable blend(GL_BLEND);
+		glColor4f(0,1,1,0.5f);
+
+		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+		{
+			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+		}
+
+		const LLVector3* ext = drawablep->getSpatialExtents();
+
+		LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
+		LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+
+		{
+			LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+			gGL.color4f(1,1,1,1);
+			drawBoxOutline(pos, size);
+		}
+
+		gGL.color4f(1,1,0,1);
+		F32 rad = drawablep->getVOVolume()->getLightRadius();
+		drawBoxOutline(pos, LLVector3(rad,rad,rad));
+	}
+}
+
 class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 {
 public:
-	LLOctreeRenderNonOccluded() {}
+	LLCamera* mCamera;
+	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
 	
 	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
 	{
-		const LLSpatialGroup::OctreeState* state = node->getOctState();
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
-	
-		if ((!gPipeline.sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) &&
-			!group->isState(LLSpatialGroup::CULLED))
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
 		{
-			state->accept(this);
+			node->accept(this);
 
-			for (U32 i = 0; i < state->getChildCount(); i++)
+			for (U32 i = 0; i < node->getChildCount(); i++)
 			{
-				traverse(state->getChild(i));
+				traverse(node->getChild(i));
 			}
 			
 			//draw tight fit bounding boxes for spatial group
@@ -2659,19 +2404,25 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 
 			//render visibility wireframe
 			if (group->mSpatialPartition->mRenderByGroup &&
-				gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) &&
-				!group->isState(LLSpatialGroup::GEOM_DIRTY))
+				gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 			{
-				renderVisibility(group);
+				gGL.stop();
+				glPushMatrix();
+				gGLLastMatrix = NULL;
+				glLoadMatrixd(gGLModelView);
+				renderVisibility(group, mCamera);
+				gGLLastMatrix = NULL;
+				glPopMatrix();
+				gGL.start();
 			}
 		}
 	}
 
-	virtual void visit(const LLSpatialGroup::OctreeState* branch)
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 
-		if (group->isState(LLSpatialGroup::CULLED | LLSpatialGroup::OCCLUDED))
+		if (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
 		{
 			return;
 		}
@@ -2679,7 +2430,7 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 		LLVector3 nodeCenter = group->mBounds[0];
 		LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
 
-		for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 		{
 			LLDrawable* drawable = *i;
 						
@@ -2697,6 +2448,11 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			{
 				renderPoints(drawable);
 			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
+			{
+				renderLights(drawable);
+			}
 		}
 		
 		for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
@@ -2709,6 +2465,10 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 				{
 					renderTextureAnim(draw_info);
 				}
+				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
+				{
+					renderBatchSize(draw_info);
+				}
 			}
 		}
 	}
@@ -2718,6 +2478,8 @@ void LLSpatialPartition::renderDebug()
 {
 	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
 									  LLPipeline::RENDER_DEBUG_OCCLUSION |
+									  LLPipeline::RENDER_DEBUG_LIGHTS |
+									  LLPipeline::RENDER_DEBUG_BATCH_SIZE |
 									  LLPipeline::RENDER_DEBUG_BBOXES |
 									  LLPipeline::RENDER_DEBUG_POINTS |
 									  LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
@@ -2737,57 +2499,23 @@ void LLSpatialPartition::renderDebug()
 	
 	LLGLDisable cullface(GL_CULL_FACE);
 	LLGLEnable blend(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	LLGLDisable tex(GL_TEXTURE_2D);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	LLImageGL::unbindTexture(0);
 	gPipeline.disableLights();
-		
-	LLOctreeRenderNonOccluded render_debug;
-	render_debug.traverse(mOctree);
 
-	LLGLDisable cull_face(GL_CULL_FACE);
+	LLSpatialBridge* bridge = asBridge();
+	LLCamera* camera = gCamera;
 	
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && !mOccludedList.empty() &&
-		mOcclusionIndices.notNull())
+	if (bridge)
 	{
-		LLGLDisable fog(GL_FOG);
-		LLGLDepthTest gls_depth(GL_FALSE);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-		mOcclusionIndices->setBuffer(0);
-		U32* indicesp = (U32*) mOcclusionIndices->getIndicesPointer();
-
-		LLGLEnable blend(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		LLGLEnable cull(GL_CULL_FACE);
-		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
-		for (U32 i = 0; i < mOccludedList.size(); i++)
-		{	//draw occluded nodes
-			LLSpatialGroup* node = mOccludedList[i];
-			if (node->isDead() ||
-				!node->isState(LLSpatialGroup::OCCLUDED) ||
-				node->mOcclusionVerts.isNull())
-			{
-				continue;
-			}
-			
-			node->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
-			{
-				LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
-				glColor4f(0.5, 0.5f, 0, 0.25f);
-				glDrawRangeElements(GL_TRIANGLES, 0, 7, 36,
-							GL_UNSIGNED_INT, indicesp);
-			}
+		camera = NULL;
+	}
 
-			{
-				LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
-				glColor4f(0.0,1.0f,1.0f,1.0f);
-				glDrawRangeElements(GL_TRIANGLES, 0, 7, 36,
-							GL_UNSIGNED_INT, indicesp);
-			}
-		}
+	LLOctreeStateCheck checker;
+	checker.traverse(mOctree);
 
-		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-	}	
+	LLOctreeRenderNonOccluded render_debug(camera);
+	render_debug.traverse(mOctree);
 }
 
 
@@ -2816,8 +2544,7 @@ class LLOctreePick : public LLSpatialGroup::OctreeTraveler
 
 	virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
 	{
-		const LLSpatialGroup::OctreeState* state = node->getOctState();
-		state->accept(this);
+		node->accept(this);
 	
 		for (U32 i = 0; i < node->getChildCount(); i++)
 		{
@@ -2841,9 +2568,9 @@ class LLOctreePick : public LLSpatialGroup::OctreeTraveler
 		return mRet;
 	}
 
-	virtual void visit(const LLSpatialGroup::OctreeState* branch) 
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 	{	
-		for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 		{
 			check(*i);
 		}
@@ -2869,13 +2596,14 @@ LLDrawable*	LLSpatialPartition::pickDrawable(const LLVector3& start, const LLVec
 	return ret;
 }
 
-LLDrawInfo::LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, 
+LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
 					   LLViewerImage* texture, LLVertexBuffer* buffer,
 					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
 :
 	mVertexBuffer(buffer),
 	mTexture(texture),
 	mTextureMatrix(NULL),
+	mModelMatrix(NULL),
 	mStart(start),
 	mEnd(end),
 	mCount(count),
@@ -2884,8 +2612,10 @@ LLDrawInfo::LLDrawInfo(U32 start, U32 end, U32 count, U32 offset,
 	mBump(bump),
 	mParticle(particle),
 	mPartSize(part_size),
-	mVSize(0.f)
+	mVSize(0.f),
+	mGroup(NULL)
 {
+	mDebugColor = (rand() << 16) + rand();
 }
 
 LLDrawInfo::~LLDrawInfo()	
@@ -2897,3 +2627,190 @@ LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
 {
 	return new LLVertexBuffer(type_mask, usage);
 }
+
+LLCullResult::LLCullResult() 
+{
+	clear();
+}
+
+void LLCullResult::clear()
+{
+	mVisibleGroupsSize = 0;
+	mAlphaGroupsSize = 0;
+	mOcclusionGroupsSize = 0;
+	mDrawableGroupsSize = 0;
+	mVisibleListSize = 0;
+	mVisibleBridgeSize = 0;
+
+	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+	{
+		mRenderMapSize[i] = 0;
+	}
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
+{
+	return mVisibleGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
+{
+	return mVisibleGroups.begin() + mVisibleGroupsSize;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
+{
+	return mAlphaGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
+{
+	return mAlphaGroups.begin() + mAlphaGroupsSize;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
+{
+	return mOcclusionGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
+{
+	return mOcclusionGroups.begin() + mOcclusionGroupsSize;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
+{
+	return mDrawableGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
+{
+	return mDrawableGroups.begin() + mDrawableGroupsSize;
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
+{
+	return mVisibleList.begin();
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
+{
+	return mVisibleList.begin() + mVisibleListSize;
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
+{
+	return mVisibleBridge.begin();
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
+{
+	return mVisibleBridge.begin() + mVisibleBridgeSize;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
+{
+	return mRenderMap[type].begin();
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
+{
+	return mRenderMap[type].begin() + mRenderMapSize[type];
+}
+
+void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
+{
+	if (mVisibleGroupsSize < mVisibleGroups.size())
+	{
+		mVisibleGroups[mVisibleGroupsSize] = group;
+	}
+	else
+	{
+		mVisibleGroups.push_back(group);
+	}
+	++mVisibleGroupsSize;
+}
+
+void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
+{
+	if (mAlphaGroupsSize < mAlphaGroups.size())
+	{
+		mAlphaGroups[mAlphaGroupsSize] = group;
+	}
+	else
+	{
+		mAlphaGroups.push_back(group);
+	}
+	++mAlphaGroupsSize;
+}
+
+void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
+{
+	if (mOcclusionGroupsSize < mOcclusionGroups.size())
+	{
+		mOcclusionGroups[mOcclusionGroupsSize] = group;
+	}
+	else
+	{
+		mOcclusionGroups.push_back(group);
+	}
+	++mOcclusionGroupsSize;
+}
+
+void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
+{
+	if (mDrawableGroupsSize < mDrawableGroups.size())
+	{
+		mDrawableGroups[mDrawableGroupsSize] = group;
+	}
+	else
+	{
+		mDrawableGroups.push_back(group);
+	}
+	++mDrawableGroupsSize;
+}
+
+void LLCullResult::pushDrawable(LLDrawable* drawable)
+{
+	if (mVisibleListSize < mVisibleList.size())
+	{
+		mVisibleList[mVisibleListSize] = drawable;
+	}
+	else
+	{
+		mVisibleList.push_back(drawable);
+	}
+	++mVisibleListSize;
+}
+
+void LLCullResult::pushBridge(LLSpatialBridge* bridge)
+{
+	if (mVisibleBridgeSize < mVisibleBridge.size())
+	{
+		mVisibleBridge[mVisibleBridgeSize] = bridge;
+	}
+	else
+	{
+		mVisibleBridge.push_back(bridge);
+	}
+	++mVisibleBridgeSize;
+}
+
+void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
+{
+	if (mRenderMapSize[type] < mRenderMap[type].size())
+	{
+		mRenderMap[type][mRenderMapSize[type]] = draw_info;
+	}
+	else
+	{
+		mRenderMap[type].push_back(draw_info);
+	}
+	++mRenderMapSize[type];
+}
+
+
+
+
+
+
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 53764930f85..7e1175a000b 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -40,14 +40,18 @@
 #include "llvertexbuffer.h"
 #include "llgltypes.h"
 #include "llcubemap.h"
+#include "lldrawpool.h"
 
 #include <queue>
 
-#define SG_STATE_INHERIT_MASK (CULLED | OCCLUDED)
-#define SG_INITIAL_STATE_MASK (OCCLUSION_DIRTY | DIRTY | GEOM_DIRTY)
+#define SG_STATE_INHERIT_MASK (OCCLUDED)
+#define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY)
 
 class LLSpatialPartition;
 class LLSpatialBridge;
+class LLSpatialGroup;
+
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 
 class LLDrawInfo : public LLRefCount 
 {
@@ -55,7 +59,7 @@ class LLDrawInfo : public LLRefCount
 	~LLDrawInfo();	
 	
 public:
-	LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, 
+	LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
 				LLViewerImage* image, LLVertexBuffer* buffer, 
 				BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0);
 	
@@ -64,9 +68,11 @@ class LLDrawInfo : public LLRefCount
 	LLPointer<LLViewerImage> mTexture;
 	LLPointer<LLCubeMap> mReflectionMap;
 	LLColor4U mGlowColor;
+	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
-	U32 mStart;
-	U32 mEnd;
+	const LLMatrix4* mModelMatrix;
+	U16 mStart;
+	U16 mEnd;
 	U32 mCount;
 	U32 mOffset;
 	BOOL mFullbright;
@@ -74,7 +80,8 @@ class LLDrawInfo : public LLRefCount
 	BOOL mParticle;
 	F32 mPartSize;
 	F32 mVSize;
-	
+	LLSpatialGroup* mGroup;
+
 	struct CompareTexture
 	{
 		bool operator()(const LLDrawInfo& lhs, const LLDrawInfo& rhs)
@@ -84,7 +91,7 @@ class LLDrawInfo : public LLRefCount
 	};
 
 	struct CompareTexturePtr
-	{
+	{ //sort by texture
 		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)	
 		{
 			// sort by pointer, sort NULL down to the end
@@ -93,6 +100,17 @@ class LLDrawInfo : public LLRefCount
 		}
 	};
 
+	struct CompareTexturePtrMatrix
+	{
+		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)	
+		{
+			return lhs.get() != rhs.get() 
+						&& (lhs.isNull() || (rhs.notNull() && (lhs->mTexture.get() > rhs->mTexture.get() ||
+															   (lhs->mTexture.get() == rhs->mTexture.get() && lhs->mModelMatrix > rhs->mModelMatrix))));
+		}
+
+	};
+
 	struct CompareBump
 	{
 		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs) 
@@ -108,23 +126,24 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 {
 	friend class LLSpatialPartition;
 public:
+	static U32 sNodeCount;
 
 	typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t;
 	typedef std::set<LLPointer<LLSpatialGroup> > sg_set_t;
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t;
 	typedef std::vector<LLPointer<LLDrawInfo> > drawmap_elem_t; 
 	typedef std::map<U32, drawmap_elem_t > draw_map_t;	
-	typedef std::map<LLPointer<LLViewerImage>, LLPointer<LLVertexBuffer> > buffer_map_t;
+	typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t;
+	typedef std::map<LLPointer<LLViewerImage>, buffer_list_t> buffer_map_t;
 
 	typedef LLOctreeListener<LLDrawable>	BaseType;
 	typedef LLOctreeListener<LLDrawable>	OctreeListener;
 	typedef LLTreeNode<LLDrawable>			TreeNode;
 	typedef LLOctreeNode<LLDrawable>		OctreeNode;
 	typedef LLOctreeRoot<LLDrawable>		OctreeRoot;
-	typedef LLOctreeState<LLDrawable>		OctreeState;
 	typedef LLOctreeTraveler<LLDrawable>	OctreeTraveler;
-	typedef LLOctreeState<LLDrawable>::element_iter element_iter;
-	typedef LLOctreeState<LLDrawable>::element_list element_list;
+	typedef LLOctreeNode<LLDrawable>::element_iter element_iter;
+	typedef LLOctreeNode<LLDrawable>::element_list element_list;
 
 	struct CompareDistanceGreater
 	{
@@ -144,29 +163,22 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	typedef enum
 	{
-		IN_QUEUE				= 0x00000001,
-		QUERY_PENDING			= 0x00000002,
-		CULLED					= 0x00000004,
-		OCCLUDED				= 0x00000008,
-		DEAD					= 0x00000010,
-		ACTIVE_OCCLUSION		= 0x00000020,
+		OCCLUDED				= 0x00000001,
+		IN_QUEUE				= 0x00000002,
+		QUERY_PENDING			= 0x00000004,
+		ACTIVE_OCCLUSION		= 0x00000008,
+		DISCARD_QUERY			= 0x00000010,
+		DEAD					= 0x00000020,
 		EARLY_FAIL				= 0x00000040,
-		DEACTIVATE_OCCLUSION	= 0x00000080,
-		RESHADOW				= 0x00000100,
-		RESHADOW_QUEUE			= 0x00000200,
-		DIRTY					= 0x00000400,
-		OBJECT_DIRTY			= 0x00000800,
-		GEOM_DIRTY				= 0x00001000,
-		MATRIX_DIRTY			= 0x00002000,
-		ALPHA_DIRTY				= 0x00004000,
-		DISCARD_QUERY			= 0x00008000,
-		QUERY_OUT				= 0x00010000,
-		OCCLUDING				= 0x00020000,
-		SKIP_FRUSTUM_CHECK		= 0x00040000,
-		OCCLUSION_DIRTY			= 0x00080000,
-		BELOW_WATER				= 0x00100000,
-		IN_IMAGE_QUEUE			= 0x00200000,
-		IMAGE_DIRTY				= 0x00400000,
+		DIRTY					= 0x00000080,
+		OBJECT_DIRTY			= 0x00000100,
+		GEOM_DIRTY				= 0x00000200,
+		ALPHA_DIRTY				= 0x00000800,
+		SKIP_FRUSTUM_CHECK		= 0x00001000,
+		IN_IMAGE_QUEUE			= 0x00002000,
+		IMAGE_DIRTY				= 0x00004000,
+		OCCLUSION_DIRTY			= 0x00008000,
+		MESH_DIRTY				= 0x00010000,
 	} eSpatialState;
 
 	typedef enum
@@ -181,11 +193,12 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL isDead()							{ return isState(DEAD); }
 	BOOL isState(U32 state) const			{ return mState & state ? TRUE : FALSE; }
 	U32 getState()							{ return mState; }
-	void setState(U32 state)				{ mState |= state; }
-	void clearState(U32 state)				{ mState &= ~state; }
+	void setState(U32 state);	
+	void clearState(U32 state);	
 	
 	void clearDrawMap();
 	void validate();
+	void checkStates();
 	void validateDrawMap();
 	
 	void setState(U32 state, S32 mode);
@@ -196,20 +209,26 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE);
 	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
 	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
-	BOOL isVisible();
+	BOOL isVisible() const;
+	void setVisible();
 	void shift(const LLVector3 &offset);
 	BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax);
 	void unbound();
 	BOOL rebound();
+	void buildOcclusion(); //rebuild mOcclusionVerts
+	void checkOcclusion(); //read back last occlusion query (if any)
+	void doOcclusion(LLCamera* camera); //issue occlusion query
 	void destroyGL();
 	
 	void updateDistance(LLCamera& camera);
+	BOOL needsUpdate();
 	BOOL changeLOD();
 	void rebuildGeom();
-	void makeStatic();
-	
+
 	void dirtyGeom() { setState(GEOM_DIRTY); }
-	element_list& getData() { return mOctreeNode->getOctState()->getData(); }
+	void dirtyMesh() { setState(MESH_DIRTY); }
+	element_list& getData() { return mOctreeNode->getData(); }
+	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
 
 	 //LISTENER FUNCTIONS
 	virtual void handleInsertion(const TreeNode* node, LLDrawable* face);
@@ -235,25 +254,24 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	LLSpatialPartition* mSpatialPartition;
 	LLVector3 mBounds[2];
 	LLVector3 mExtents[2];
+	
 	LLVector3 mObjectExtents[2];
 	LLVector3 mObjectBounds[2];
 
 	LLPointer<LLVertexBuffer> mVertexBuffer;
-	LLPointer<LLVertexBuffer> mOcclusionVerts;
+	F32*					mOcclusionVerts;
+	GLuint					mOcclusionQuery;
 	LLPointer<LLCubeMap>	mReflectionMap;
 
 	U32 mBufferUsage;
 	draw_map_t mDrawMap;
 	
-	U32 mVertexCount;
-	U32 mIndexCount;
+	S32 mVisible;
 	F32 mDistance;
 	F32 mDepth;
 	F32 mLastUpdateDistance;
 	F32 mLastUpdateTime;
-	F32 mLastAddTime;
-	F32 mLastRenderTime;
-	
+			
 	LLVector3 mViewAngle;
 	LLVector3 mLastUpdateViewAngle;
 	
@@ -275,7 +293,9 @@ class LLGeometryManager
 class LLSpatialPartition: public LLGeometryManager
 {
 public:
-	LLSpatialPartition(U32 data_mask, BOOL is_volatile = FALSE, U32 mBufferUsage = GL_STATIC_DRAW_ARB);
+	static BOOL sFreezeState; //if true, no spatialgroup state updates will be made
+
+	LLSpatialPartition(U32 data_mask, U32 mBufferUsage = GL_STATIC_DRAW_ARB);
 	virtual ~LLSpatialPartition();
 
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
@@ -293,63 +313,42 @@ class LLSpatialPartition: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 
 	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum
-	BOOL checkOcclusion(LLSpatialGroup* group, LLCamera* camera);
 	void markReimage(LLSpatialGroup* group);
 	void processImagery(LLCamera* camera);
-	void processOcclusion(LLCamera* camera);
-	void buildOcclusion();
-	void doOcclusion(LLCamera* camera);
+	
 	BOOL isVisible(const LLVector3& v);
-	BOOL isVolatile() const { return mVolatile; }
-
+	
 	virtual LLSpatialBridge* asBridge() { return NULL; }
 	virtual BOOL isBridge() { return asBridge() != NULL; }
 
-	S32 getObjects(const LLVector3& pos,  F32 rad,  LLDrawable::drawable_set_t &results );
-	S32 getLights(const LLVector3& pos,  F32 rad,  LLDrawable::drawable_set_t &results );
-	
 	void renderDebug();
 	void restoreGL();
 	void resetVertexBuffers();
 	
 protected:
-	S32 getDrawables(const LLVector3& pos,  F32 rad,  LLDrawable::drawable_set_t &results, BOOL get_lights );
 	
 	typedef std::set<LLPointer<LLSpatialGroup> > spatial_group_set_t;
 	spatial_group_set_t mSpatialGroups;
 
-	//things that might be occluded
 	typedef std::queue<LLPointer<LLSpatialGroup> > spatial_group_queue_t;
-	spatial_group_queue_t mOcclusionQueue;
-
+	
 	//things that need an image update
 	spatial_group_queue_t mImageQueue;
 
-	//things awaiting query
-	spatial_group_queue_t mQueryQueue;
-
-	std::vector<LLGLuint> mOcclusionQueries;	
-
 public:
 	LLSpatialGroup::OctreeNode* mOctree;
-
+	BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
+	BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
 	U32 mBufferUsage;
 	BOOL mRenderByGroup;
 	BOOL mImageEnabled;
 	U32 mLODSeed;
-	U32 mLODPeriod;
+	U32 mLODPeriod;	//number of frames between LOD updates for a given spatial group (staggered by mLODSeed)
 	U32 mVertexDataMask;
 	F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25);
-	BOOL mVolatile; //if TRUE, occlusion queries will be discarded when nodes change size
 	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering
 	U32 mDrawableType;
 	U32 mPartitionType;
-
-	//index buffer for occlusion verts
-	LLPointer<LLVertexBuffer> mOcclusionIndices;
-
-	//things that are occluded
-	std::vector<LLPointer<LLSpatialGroup> > mOccludedList;
 };
 
 // class for creating bridges between spatial partitions
@@ -370,7 +369,6 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 	virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
 	virtual void updateDistance(LLCamera& camera_in);
 	virtual void makeActive();
-	virtual void makeStatic();
 	virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE);
 	virtual BOOL updateMove();
 	virtual void shiftPos(const LLVector3& vec);
@@ -383,6 +381,72 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 	LLDrawable* mDrawable;
 };
 
+class LLCullResult 
+{
+public:
+	LLCullResult();
+
+	typedef std::vector<LLSpatialGroup*> sg_list_t;
+	typedef std::vector<LLDrawable*> drawable_list_t;
+	typedef std::vector<LLSpatialBridge*> bridge_list_t;
+	typedef std::vector<LLDrawInfo*> drawinfo_list_t;
+
+	void clear();
+	
+	sg_list_t::iterator beginVisibleGroups();
+	sg_list_t::iterator endVisibleGroups();
+
+	sg_list_t::iterator beginAlphaGroups();
+	sg_list_t::iterator endAlphaGroups();
+
+	sg_list_t::iterator beginOcclusionGroups();
+	sg_list_t::iterator endOcclusionGroups();
+
+	sg_list_t::iterator beginDrawableGroups();
+	sg_list_t::iterator endDrawableGroups();
+
+	drawable_list_t::iterator beginVisibleList();
+	drawable_list_t::iterator endVisibleList();
+
+	bridge_list_t::iterator beginVisibleBridge();
+	bridge_list_t::iterator endVisibleBridge();
+
+	drawinfo_list_t::iterator beginRenderMap(U32 type);
+	drawinfo_list_t::iterator endRenderMap(U32 type);
+
+	void pushVisibleGroup(LLSpatialGroup* group);
+	void pushAlphaGroup(LLSpatialGroup* group);
+	void pushOcclusionGroup(LLSpatialGroup* group);
+	void pushDrawableGroup(LLSpatialGroup* group);
+	void pushDrawable(LLDrawable* drawable);
+	void pushBridge(LLSpatialBridge* bridge);
+	void pushDrawInfo(U32 type, LLDrawInfo* draw_info);
+
+	U32 getVisibleGroupsSize()		{ return mVisibleGroupsSize; }
+	U32	getAlphaGroupsSize()		{ return mAlphaGroupsSize; }
+	U32	getDrawableGroupsSize()		{ return mDrawableGroupsSize; }
+	U32	getVisibleListSize()		{ return mVisibleListSize; }
+	U32	getVisibleBridgeSize()		{ return mVisibleBridgeSize; }
+	U32	getRenderMapSize(U32 type)	{ return mRenderMapSize[type]; }
+
+private:
+	U32					mVisibleGroupsSize;
+	U32					mAlphaGroupsSize;
+	U32					mOcclusionGroupsSize;
+	U32					mDrawableGroupsSize;
+	U32					mVisibleListSize;
+	U32					mVisibleBridgeSize;
+	U32					mRenderMapSize[LLRenderPass::NUM_RENDER_TYPES];
+
+	sg_list_t			mVisibleGroups;
+	sg_list_t			mAlphaGroups;
+	sg_list_t			mOcclusionGroups;
+	sg_list_t			mDrawableGroups;
+	drawable_list_t		mVisibleList;
+	bridge_list_t		mVisibleBridge;
+	drawinfo_list_t		mRenderMap[LLRenderPass::NUM_RENDER_TYPES];
+};
+
 //spatial partition for water (implemented in LLVOWater.cpp)
 class LLWaterPartition : public LLSpatialPartition
 {
@@ -500,5 +564,6 @@ extern const F32 SG_BOX_RAD;
 extern const F32 SG_OBJ_SIDE;
 extern const F32 SG_MAX_OBJ_RAD;
 
+
 #endif //LL_LLSPATIALPARTITION_H
 
diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp
index 827493d1b52..92fcbb6e6c0 100644
--- a/indra/newview/llsprite.cpp
+++ b/indra/newview/llsprite.cpp
@@ -199,8 +199,8 @@ void LLSprite::updateFace(LLFace &face)
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> tex_coordsp;
-	LLStrider<U32> indicesp;
-	S32 index_offset;
+	LLStrider<U16> indicesp;
+	U16 index_offset;
 
 	// Setup face
 	if (face.mVertexBuffer.isNull())
@@ -214,10 +214,6 @@ void LLSprite::updateFace(LLFace &face)
 	}
 		
 	index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp);
-	if (-1 == index_offset)
-	{
-		return;
-	}
 
 	*tex_coordsp = LLVector2(0.f, 0.f);
 	*verticesp = mC;
@@ -263,7 +259,7 @@ void LLSprite::updateFace(LLFace &face)
 		*indicesp++ = 3 + index_offset;
 	}
 
-	//face.mVertexBuffer->setBuffer(0);
+	face.mVertexBuffer->setBuffer(0);
 	face.mCenterAgent = mPosition;
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 455fcc7bc01..461730b947f 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -170,6 +170,9 @@
 #include "llnamelistctrl.h"
 #include "llnamebox.h"
 #include "llnameeditor.h"
+#include "llpostprocess.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
 
 #if LL_WINDOWS
 #include "llwindebug.h"
@@ -1540,6 +1543,11 @@ BOOL idle_startup()
 
 		LLDrawable::initClass();
 
+		// init the shader managers
+		LLPostProcess::initClass();
+		LLWLParamManager::initClass();
+		LLWaterParamManager::initClass();
+
 		// RN: don't initialize VO classes in drone mode, they are too closely tied to rendering
 		LLViewerObject::initVOClasses();
 
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index e9aa9b0232b..dc1102eba73 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -663,83 +663,6 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
 	return did_update;
 }
 
-// TODO -- move this to LLViewerRegion class
-void LLSurface::renderSurfaceBounds()
-{
-	//  Shows the edge of the surface, so that visibility across regions can be seen
-	LLVector3 origin_agent = getOriginAgent();
-	
-	glPushMatrix();
-	LLGLSNoTexture no_texture;
-	
-	F32 region_width_meters = gWorldPointer->getRegionWidthInMeters();
-	glTranslatef(origin_agent.mV[VX] + (region_width_meters * 0.005f),
-					origin_agent.mV[VY] + (region_width_meters * 0.005f), 0.f);
-
-	glColor4ub(0, 128, 0, 64); 
-
-	F32 length = region_width_meters * 0.995f;
-	F32 height = length/8.0f;
-
-	glBegin(GL_QUADS);
-		glVertex3f(length, 0, 0);
-		glVertex3f(0,0, 0);
-		glVertex3f(0,0, height);
-		glVertex3f(length,0, height);
-
-		glVertex3f(length,0, height);
-		glVertex3f(0,0, height);
-		glVertex3f(0,0, 0);
-		glVertex3f(length, 0, 0);
-	glEnd();
-
-	glTranslatef(length, 0, 0);
-	glRotated(90, 0, 0, 1);
-	glBegin(GL_QUADS);
-		glVertex3f(length, 0, 0);
-		glVertex3f(0,0, 0);
-		glVertex3f(0,0, height);
-		glVertex3f(length,0, height);
-
-		glVertex3f(length,0, height);
-		glVertex3f(0,0, height);
-		glVertex3f(0,0, 0);
-		glVertex3f(length, 0, 0);
-
-	glEnd();
-	glTranslatef(length, 0, 0);
-	glRotated(90, 0, 0, 1);
-	glBegin(GL_QUADS);
-		glVertex3f(length, 0, 0);
-		glVertex3f(0,0, 0);
-		glVertex3f(0,0, height);
-		glVertex3f(length,0, height);
-
-		glVertex3f(length,0, height);
-		glVertex3f(0,0, height);
-		glVertex3f(0,0, 0);
-		glVertex3f(length, 0, 0);
-	glEnd();
-	glTranslatef(length, 0, 0);
-	glRotated(90, 0, 0, 1);
-	glBegin(GL_QUADS);
-		glVertex3f(length, 0, 0);
-		glVertex3f(0,0, 0);
-		glVertex3f(0,0, height);
-		glVertex3f(length,0, height);
-
-		glVertex3f(length,0, height);
-		glVertex3f(0,0, height);
-		glVertex3f(0,0, 0);
-		glVertex3f(length, 0, 0);
-	glEnd();
-	glTranslatef(length, 0, 0);
-	glRotated(90, 0, 0, 1);
- 
-	glPopMatrix();
-}
-
-
 void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch) 
 {
 
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 8fecd2d97e4..c806d804f1b 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -120,8 +120,6 @@ class LLSurface
 	// Update methods (called during idle, normally)
 	BOOL idleUpdate(F32 max_update_time);
 
-	void renderSurfaceBounds();
-	
 	BOOL containsPosition(const LLVector3 &position);
 
 	void moveZ(const S32 x, const S32 y, const F32 delta);	
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 58f67786465..502ff07b3c5 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -364,9 +364,17 @@ const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const
 
 void LLSurfacePatch::updateCameraDistanceRegion(const LLVector3 &pos_region)
 {
-	LLVector3 dv = pos_region;
-	dv -= mCenterRegion;
-	mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius));
+	if (LLPipeline::sDynamicLOD)
+	{
+		LLVector3 dv = pos_region;
+		dv -= mCenterRegion;
+		mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/
+			llmax(LLVOSurfacePatch::sLODFactor, 0.1f);
+	}
+	else
+	{
+		mVisInfo.mDistance = 0.f;
+	}
 }
 
 F32 LLSurfacePatch::getDistance() const
@@ -833,8 +841,11 @@ void LLSurfacePatch::updateVisibility()
 	F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid();
 	U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
 
+	LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent();
+	LLVector3 radius = LLVector3(mRadius, mRadius, mRadius);
+
 	// sphere in frustum on global coordinates
-	if (gCamera->sphereInFrustum(mCenterRegion + mSurfacep->getOriginAgent(), mRadius) )
+	if (gCamera->AABBInFrustumNoFarClip(center, radius))
 	{
 		// We now need to calculate the render stride based on patchp's distance 
 		// from LLCamera render_stride is governed by a relation something like this...
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 5330e8dfac6..78cb53c2a51 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -52,6 +52,7 @@
 #include "llxmltree.h"
 #include "pipeline.h"
 #include "v4coloru.h"
+#include "llglimmediate.h"
 
 //#include "../tools/imdebug/imdebug.h"
 
@@ -176,22 +177,22 @@ void LLTexLayerSetBuffer::cancelUpload()
 void LLTexLayerSetBuffer::pushProjection()
 {
 	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 	glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f);
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
+	gGL.pushMatrix();
 	glLoadIdentity();
 }
 
 void LLTexLayerSetBuffer::popProjection()
 {
 	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	gGL.popMatrix();
 
 	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
+	gGL.popMatrix();
 }
 
 BOOL LLTexLayerSetBuffer::needsRender()
@@ -274,6 +275,7 @@ BOOL LLTexLayerSetBuffer::render()
 	// Composite the color data
 	LLGLSUIDefault gls_ui;
 	success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mWidth, mHeight );
+	gGL.flush();
 
 	if( upload_now )
 	{
@@ -291,7 +293,7 @@ BOOL LLTexLayerSetBuffer::render()
 
 	// reset GL state
 	glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
-	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );  
+	gGL.blendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );  
 
 	// we have valid texture data now
 	mInitialized = TRUE;
@@ -761,7 +763,9 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
 		LLTexLayer* layer = *iter;
 		if( layer->getRenderPass() == RP_COLOR )
 		{
+			gGL.flush();
 			success &= layer->render( x, y, width, height );
+			gGL.flush();
 		}
 	}
 
@@ -769,8 +773,9 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
 	if( !getInfo()->mStaticAlphaFileName.empty() )
 	{
 		LLGLSNoAlphaTest gls_no_alpha_test;
+		gGL.flush();
 		glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE );
-		glBlendFunc( GL_ONE, GL_ZERO );
+		gGL.blendFunc( GL_ONE, GL_ZERO );
 
 		{
 			LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticAlphaFileName, TRUE );
@@ -787,19 +792,22 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
 		}
 		LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
 
+		gGL.flush();
 		glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
-		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+		gGL.blendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 	}
 	else 
 	if( getInfo()->mClearAlpha )
 	{
 		// Set the alpha channel to one (clean up after previous blending)
 		LLGLSNoTextureNoAlphaTest gls_no_alpha;
-		glColor4f( 0.f, 0.f, 0.f, 1.f );
+		gGL.color4f( 0.f, 0.f, 0.f, 1.f );
+		gGL.flush();
 		glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE );
 
 		gl_rect_2d_simple( width, height );
 		
+		gGL.flush();
 		glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
 	}
 	stop_glerror();
@@ -827,7 +835,7 @@ BOOL LLTexLayerSet::renderBump( S32 x, S32 y, S32 width, S32 height )
 
 	// Set the alpha channel to one (clean up after previous blending)
 	LLGLSNoTextureNoAlphaTest gls_no_texture_no_alpha;
-	glColor4f( 0.f, 0.f, 0.f, 1.f );
+	gGL.color4f( 0.f, 0.f, 0.f, 1.f );
 	glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE );
 
 	gl_rect_2d_simple( width, height );
@@ -1321,14 +1329,16 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height )
 
 		renderAlphaMasks( x, y, width, height, &net_color );
 		alpha_mask_specified = TRUE;
-		glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA );
+		gGL.flush();
+		gGL.blendFunc( GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA );
 	}
 
-	glColor4fv( net_color.mV);
+	gGL.color4fv( net_color.mV);
 
 	if( getInfo()->mWriteAllChannels )
 	{
-		glBlendFunc( GL_ONE, GL_ZERO );
+		gGL.flush();
+		gGL.blendFunc( GL_ONE, GL_ZERO );
 	}
 
 	if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly )
@@ -1383,14 +1393,15 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height )
 		color_specified )
 	{
 		LLGLSNoTextureNoAlphaTest gls;
-		glColor4fv( net_color.mV);
+		gGL.color4fv( net_color.mV);
 		gl_rect_2d_simple( width, height );
 	}
 
 	if( alpha_mask_specified || getInfo()->mWriteAllChannels )
 	{
 		// Restore standard blend func value
-		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+		gGL.flush();
+		gGL.blendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 		stop_glerror();
 	}
 
@@ -1506,15 +1517,16 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
 		LLGLSNoTextureNoAlphaTest gls_no_texture_no_alpha_test;
 	
 		// Clear the alpha
-		glBlendFunc( GL_ONE, GL_ZERO );
+		gGL.flush();
+		gGL.blendFunc( GL_ONE, GL_ZERO );
 
-		glColor4f( 0.f, 0.f, 0.f, 0.f );
+		gGL.color4f( 0.f, 0.f, 0.f, 0.f );
 		gl_rect_2d_simple( width, height );
 	}
 
 	// Accumulate alphas
 	LLGLSNoAlphaTest gls_no_alpha_test;
-	glColor4f( 1.f, 1.f, 1.f, 1.f );
+	gGL.color4f( 1.f, 1.f, 1.f, 1.f );
 
 	for( iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ )
 	{
@@ -1523,7 +1535,8 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
 	}
 
 	// Approximates a min() function
-	glBlendFunc( GL_DST_ALPHA, GL_ZERO );
+	gGL.flush();
+	gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
 
 	// Accumulate the alpha component of the texture
 	if( getInfo()->mLocalTexture != -1 )
@@ -1577,11 +1590,11 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
 	}
 
 	// Draw a rectangle with the layer color to multiply the alpha by that color's alpha.
-	// Note: we're still using glBlendFunc( GL_DST_ALPHA, GL_ZERO );
+	// Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
 	if( colorp->mV[VW] != 1.f )
 	{
 		LLGLSNoTextureNoAlphaTest gls_no_texture_no_alpha_test;
-		glColor4fv( colorp->mV );
+		gGL.color4fv( colorp->mV );
 		gl_rect_2d_simple( width, height );
 	}
 
@@ -1947,13 +1960,14 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
 		return success;
 	}
 
+	gGL.flush();
 	if( getInfo()->mMultiplyBlend )
 	{
-		glBlendFunc( GL_DST_ALPHA, GL_ZERO ); // Multiplication: approximates a min() function
+		gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); // Multiplication: approximates a min() function
 	}
 	else
 	{
-		glBlendFunc( GL_ONE, GL_ONE );  // Addition: approximates a max() function
+		gGL.blendFunc( GL_ONE, GL_ONE );  // Addition: approximates a max() function
 	}
 
 	if( !getInfo()->mStaticImageFileName.empty() && !mStaticImageInvalid)
@@ -2069,7 +2083,7 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
 	else
 	{
 		LLGLSNoTextureNoAlphaTest gls_no_texture_no_alpha_test;
-		glColor4f( 0.f, 0.f, 0.f, effective_weight );
+		gGL.color4f( 0.f, 0.f, 0.f, effective_weight );
 		gl_rect_2d_simple( width, height );
 	}
 
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 7368ac9fdb5..4f8e562baf5 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -34,6 +34,7 @@
 
 #include "lltexturectrl.h"
 
+#include "llglimmediate.h"
 #include "llagent.h"
 #include "llviewerimagelist.h"
 #include "llcheckboxctrl.h"
@@ -483,38 +484,38 @@ void LLFloaterTexturePicker::draw()
 		{
 			LLGLSNoTexture no_texture;
 			LLGLEnable(GL_CULL_FACE);
-			glBegin(GL_QUADS);
+			gGL.begin(GL_QUADS);
 			{
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				glVertex2i(owner_rect.mLeft, owner_rect.mTop);
-				glVertex2i(owner_rect.mRight, owner_rect.mTop);
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				glVertex2i(local_rect.mRight, local_rect.mTop);
-				glVertex2i(local_rect.mLeft, local_rect.mTop);
-
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				glVertex2i(local_rect.mLeft, local_rect.mTop);
-				glVertex2i(local_rect.mLeft, local_rect.mBottom);
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				glVertex2i(owner_rect.mLeft, owner_rect.mBottom);
-				glVertex2i(owner_rect.mLeft, owner_rect.mTop);
-
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				glVertex2i(local_rect.mRight, local_rect.mBottom);
-				glVertex2i(local_rect.mRight, local_rect.mTop);
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				glVertex2i(owner_rect.mRight, owner_rect.mTop);
-				glVertex2i(owner_rect.mRight, owner_rect.mBottom);
-
-
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				glVertex2i(local_rect.mLeft, local_rect.mBottom);
-				glVertex2i(local_rect.mRight, local_rect.mBottom);
-				glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				glVertex2i(owner_rect.mRight, owner_rect.mBottom);
-				glVertex2i(owner_rect.mLeft, owner_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
 			}
-			glEnd();
+			gGL.end();
 		}
 	}
 
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 031492e0e9c..b5d4818fbaf 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -40,6 +40,7 @@
 #include "lllfsthread.h"
 #include "llui.h"
 #include "llimageworker.h"
+#include "llglimmediate.h"
 
 #include "llhoverview.h"
 #include "llselectmgr.h"
@@ -257,7 +258,7 @@ void LLTextureBar::draw()
 	left = bar_left;
 	right = left + bar_width;
 
-	glColor4f(0.f, 0.f, 0.f, 0.75f);
+	gGL.color4f(0.f, 0.f, 0.f, 0.75f);
 	gl_rect_2d(left, top, right, bottom);
 
 	F32 data_progress = mImagep->mDownloadProgress;
@@ -268,7 +269,7 @@ void LLTextureBar::draw()
 		right = left + llfloor(data_progress * (F32)bar_width);
 		if (right > left)
 		{
-			glColor4f(0.f, 0.f, 1.f, 0.75f);
+			gGL.color4f(0.f, 0.f, 1.f, 0.75f);
 			gl_rect_2d(left, top, right, bottom);
 		}
 	}
@@ -302,7 +303,7 @@ void LLTextureBar::draw()
 	if (last_event < 1.f)
 	{
 		clr.setAlpha(1.f - last_event);
-		glColor4fv(clr.mV);
+		gGL.color4fv(clr.mV);
 		gl_rect_2d(pip_x, top, pip_x + pip_width, bottom);
 	}
 	pip_x += pip_width + pip_space;
@@ -316,7 +317,7 @@ void LLTextureBar::draw()
 		{
 			clr = mImagep->getMissed() ? LLColor4::red : LLColor4::magenta1;
 			clr.setAlpha(1.f - last_event);
-			glColor4fv(clr.mV);
+			gGL.color4fv(clr.mV);
 			gl_rect_2d(pip_x, top, pip_x + pip_width, bottom);
 		}
 	}
@@ -422,7 +423,7 @@ void LLGLTexMemBar::draw()
 	
 	LLGLSNoTexture gls_no_texture;
 	
-	glColor4f(0.5f, 0.5f, 0.5f, 0.75f);
+	gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f);
 	gl_rect_2d(left, top, right, bottom);
 
 	
@@ -430,15 +431,15 @@ void LLGLTexMemBar::draw()
 	right = left + llfloor(bound_mem * bar_scale);
 	if (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale))
 	{
-		glColor4f(0.f, 1.f, 0.f, 0.75f);
+		gGL.color4f(0.f, 1.f, 0.f, 0.75f);
 	}
 	else if (bound_mem < max_bound_mem)
 	{
-		glColor4f(1.f, 1.f, 0.f, 0.75f);
+		gGL.color4f(1.f, 1.f, 0.f, 0.75f);
 	}
 	else
 	{
-		glColor4f(1.f, 0.f, 0.f, 0.75f);
+		gGL.color4f(1.f, 0.f, 0.f, 0.75f);
 	}
 	gl_rect_2d(left, top, right, bottom);
 
@@ -450,22 +451,20 @@ void LLGLTexMemBar::draw()
 	right = left + llfloor(total_mem * bar_scale);
 	if (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale))
 	{
-		glColor4f(0.f, 1.f, 0.f, 0.75f);
+		gGL.color4f(0.f, 1.f, 0.f, 0.75f);
 	}
 	else if (total_mem < max_total_mem)
 	{
-		glColor4f(1.f, 1.f, 0.f, 0.75f);
+		gGL.color4f(1.f, 1.f, 0.f, 0.75f);
 	}
 	else
 	{
-		glColor4f(1.f, 0.f, 0.f, 0.75f);
+		gGL.color4f(1.f, 0.f, 0.f, 0.75f);
 	}
 	gl_rect_2d(left, top, right, bottom);
 
 	//----------------------------------------------------------------------------
 
-	LLGLEnable tex(GL_TEXTURE_2D);
-	
 	text = llformat("Textures: Count: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d(%d) RAW:%d",
 					gImageList.getNumImages(),
 					LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp
index 189996e8710..5a637a6346a 100644
--- a/indra/newview/lltoolbrush.cpp
+++ b/indra/newview/lltoolbrush.cpp
@@ -35,6 +35,7 @@
 #include "lltoolselectland.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 
 #include "message.h"
 
@@ -476,29 +477,25 @@ void LLToolBrushLand::renderOverlay(LLSurface& land, const LLVector3& pos_region
 	LLGLSNoTexture gls_no_texture;
 	LLGLDepthTest mDepthTest(GL_TRUE);
 	glPushMatrix();
-	glColor4fv(OVERLAY_COLOR.mV);
+	gGL.color4fv(OVERLAY_COLOR.mV);
 	glTranslatef(0.0f, 0.0f, 1.0f);
-	//glPushMatrix();
-	//glTranslatef(spot.mV[VX], spot.mV[VY], 100.0f);
-	//gl_rect_2d(0, 10, 10, 0);
-	//glPopMatrix();
+	
 	S32 i = (S32) pos_region.mV[VX];
 	S32 j = (S32) pos_region.mV[VY];
 	S32 half_edge = llfloor(LAND_BRUSH_SIZE[mBrushIndex]);
-	//F32 dz = 0.0f;
-	//S32 dist = 0;
-	glBegin(GL_POINTS);
+	
+	gGL.begin(GL_POINTS);
 	for(S32 di = -half_edge; di <= half_edge; di++)
 	{
 		if((i+di) < 0 || (i+di) >= (S32)land.mGridsPerEdge) continue;
 		for(S32 dj = -half_edge; dj <= half_edge; dj++)
 		{
 			if( (j+dj) < 0 || (j+dj) >= (S32)land.mGridsPerEdge ) continue;
-			glVertex3f(pos_world.mV[VX] + di, pos_world.mV[VY] + dj,
+			gGL.vertex3f(pos_world.mV[VX] + di, pos_world.mV[VY] + dj,
 					   land.getZ((i+di)+(j+dj)*land.mGridsPerEdge));
 		}
 	}
-	glEnd();
+	gGL.end();
 	glPopMatrix();
 }
 
diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp
index ebe22fc43c4..ffa921125ad 100644
--- a/indra/newview/lltoolgun.cpp
+++ b/indra/newview/lltoolgun.cpp
@@ -37,6 +37,7 @@
 #include "llagent.h"
 #include "llviewercontrol.h"
 #include "llsky.h"
+#include "llappviewer.h"
 #include "llresmgr.h"
 #include "llfontgl.h"
 #include "llui.h"
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 3a56a9fd637..e32f9bfcc17 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -33,6 +33,7 @@
 
 // File includes
 #include "lltoolmorph.h" 
+#include "llglimmediate.h"
 
 // Library includes
 #include "audioengine.h"
@@ -180,7 +181,7 @@ BOOL LLVisualParamHint::render()
 	LLGLSUIDefault gls_ui;
 	//LLGLState::verify(TRUE);
 	LLViewerImage::bindTexture(mBackgroundp);
-	glColor4f(1.f, 1.f, 1.f, 1.f);
+	gGL.color4f(1.f, 1.f, 1.f, 1.f);
 	gl_rect_2d_simple_tex( mWidth, mHeight );
 	mBackgroundp->unbindTexture(0, GL_TEXTURE_2D);
 
@@ -227,6 +228,7 @@ BOOL LLVisualParamHint::render()
 		mVisualParam->getCameraElevation() );
 	LLVector3 camera_pos = target_joint_pos + (camera_snapshot_offset * avatar_rotation);
 	
+	gGL.stop();
 	gCamera->setAspect((F32)mWidth / (F32)mHeight);
 	gCamera->setOriginAndLookAt(
 		camera_pos,		// camera
@@ -242,7 +244,7 @@ BOOL LLVisualParamHint::render()
 		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
 	}
 	avatarp->setVisualParamWeight(mVisualParam, mLastParamWeight);
-	
+	gGL.start();
 	return TRUE;
 }
 
@@ -256,21 +258,21 @@ void LLVisualParamHint::draw()
 
 	bindTexture();
 
-	glColor4f(1.f, 1.f, 1.f, 1.f);
+	gGL.color4f(1.f, 1.f, 1.f, 1.f);
 
 	LLGLSUIDefault gls_ui;
-	glBegin(GL_QUADS);
+	gGL.begin(GL_QUADS);
 	{
-		glTexCoord2i(0, 1);
-		glVertex2i(0, mHeight);
-		glTexCoord2i(0, 0);
-		glVertex2i(0, 0);
-		glTexCoord2i(1, 0);
-		glVertex2i(mWidth, 0);
-		glTexCoord2i(1, 1);
-		glVertex2i(mWidth, mHeight);
+		gGL.texCoord2i(0, 1);
+		gGL.vertex2i(0, mHeight);
+		gGL.texCoord2i(0, 0);
+		gGL.vertex2i(0, 0);
+		gGL.texCoord2i(1, 0);
+		gGL.vertex2i(mWidth, 0);
+		gGL.texCoord2i(1, 1);
+		gGL.vertex2i(mWidth, mHeight);
 	}
-	glEnd();
+	gGL.end();
 
 	LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
 }
diff --git a/indra/newview/lltoolselectrect.cpp b/indra/newview/lltoolselectrect.cpp
index dd1a01f8dd6..3b68751740c 100644
--- a/indra/newview/lltoolselectrect.cpp
+++ b/indra/newview/lltoolselectrect.cpp
@@ -36,6 +36,7 @@
 
 // Library includes
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "lldarray.h"
 
 // Viewer includes
@@ -160,11 +161,11 @@ void LLToolSelectRect::draw()
 	{
 		if (gKeyboard->currentMask(TRUE) == MASK_CONTROL)
 		{
-			glColor4f(1.f, 0.f, 0.f, 1.f);
+			gGL.color4f(1.f, 0.f, 0.f, 1.f);
 		}
 		else
 		{
-			glColor4f(1.f, 1.f, 0.f, 1.f);
+			gGL.color4f(1.f, 1.f, 0.f, 1.f);
 		}
 		LLGLSNoTexture gls_no_texture;
 		gl_rect_2d(
@@ -175,11 +176,11 @@ void LLToolSelectRect::draw()
 			FALSE);
 		if (gKeyboard->currentMask(TRUE) == MASK_CONTROL)
 		{
-			glColor4f(1.f, 0.f, 0.f, 0.1f);
+			gGL.color4f(1.f, 0.f, 0.f, 0.1f);
 		}
 		else
 		{
-			glColor4f(1.f, 1.f, 0.f, 0.1f);
+			gGL.color4f(1.f, 1.f, 0.f, 0.1f);
 		}
 		gl_rect_2d(
 			llmin(mDragStartX, mDragEndX),
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 594ecb5591b..cc45b121ae1 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -36,6 +36,7 @@
 #include "lldarray.h"
 #include "llfontgl.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llinventory.h"
 #include "llmemory.h"
 #include "llstring.h"
@@ -50,7 +51,6 @@
 #include "llagent.h"
 #include "llcallingcard.h"
 #include "llcolorscheme.h"
-#include "llcylinder.h"
 #include "llfloaterworldmap.h"
 #include "llhudtext.h"
 #include "llhudview.h"
@@ -448,24 +448,24 @@ void draw_shockwave(F32 center_z, F32 t, S32 steps, LLColor4 color)
 	F32 y = 0.f;
 
 	LLColor4 ccol = LLColor4(1,1,1,(1.f-t)*0.25f);
-	glBegin(GL_TRIANGLE_FAN);
-	glColor4fv(ccol.mV);
-	glVertex3f(0.f, 0.f, center_z);
+	gGL.begin(GL_TRIANGLE_FAN);
+	gGL.color4fv(ccol.mV);
+	gGL.vertex3f(0.f, 0.f, center_z);
 	// make sure circle is complete
 	steps += 1;
 	
 	color.mV[3] = (1.f-t*t);
 	
-	glColor4fv(color.mV);
+	gGL.color4fv(color.mV);
 	while( steps-- )
 	{
 		// Successive rotations
-		glVertex3f( x, y, center_z );
+		gGL.vertex3f( x, y, center_z );
 		F32 x_new = x * cos_delta - y * sin_delta;
 		y = x * sin_delta +  y * cos_delta;
 		x = x_new;
 	}
-	glEnd();
+	gGL.end();
 }
 
 
@@ -508,8 +508,7 @@ void LLTracker::renderBeacon(LLVector3d pos_global,
 		
 		draw_shockwave(1024.f, gRenderStartTime.getElapsedTimeF32(), 32, fogged_color);
 
-		//glScalef(1.f, 1.f, 1000.f);
-		glColor4fv(fogged_color.mV);
+		gGL.color4fv(fogged_color.mV);
 		const U32 BEACON_VERTS = 256;
 		const F32 step = 1024.0f/BEACON_VERTS;
 		
@@ -539,23 +538,23 @@ void LLTracker::renderBeacon(LLVector3d pos_global,
 			an *= 2.f;
 			an += 1.0f+dr;
 		
-			glBegin(GL_TRIANGLE_STRIP);
-			glColor4fv(col_edge.mV);
-			glVertex3f(-x*a, -y*a, z);
-			glColor4fv(col_edge_next.mV);
-			glVertex3f(-x*an, -y*an, z_next);
+			gGL.begin(GL_TRIANGLE_STRIP);
+			gGL.color4fv(col_edge.mV);
+			gGL.vertex3f(-x*a, -y*a, z);
+			gGL.color4fv(col_edge_next.mV);
+			gGL.vertex3f(-x*an, -y*an, z_next);
 			
-			glColor4fv(c_col.mV);
-			glVertex3f(0, 0, z);
-			glColor4fv(col_next.mV);
-			glVertex3f(0, 0, z_next);
+			gGL.color4fv(c_col.mV);
+			gGL.vertex3f(0, 0, z);
+			gGL.color4fv(col_next.mV);
+			gGL.vertex3f(0, 0, z_next);
 			
-			glColor4fv(col_edge.mV);
-			glVertex3f(x*a,y*a,z);
-			glColor4fv(col_edge_next.mV);
-			glVertex3f(x*an,y*an,z_next);
+			gGL.color4fv(col_edge.mV);
+			gGL.vertex3f(x*a,y*a,z);
+			gGL.color4fv(col_edge_next.mV);
+			gGL.vertex3f(x*an,y*an,z_next);
 			
-			glEnd();
+			gGL.end();
 		}
 							
 		//gCylinder.render(1000);
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index b71d9d954ba..3e8ceaba1be 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -48,16 +48,46 @@
 #include "llvovolume.h"
 #include "llworld.h"
 
+GLfloat gGLZFar;
+GLfloat gGLZNear;
+
 LLViewerCamera *gCamera = NULL;
 
+//glu pick matrix implementation borrowed from Mesa3D
+glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport)
+{
+	GLfloat m[16];
+	GLfloat sx, sy;
+	GLfloat tx, ty;
+
+	sx = viewport[2] / width;
+	sy = viewport[3] / height;
+	tx = (viewport[2] + 2.f * (viewport[0] - x)) / width;
+	ty = (viewport[3] + 2.f * (viewport[1] - y)) / height;
+
+	#define M(row,col) m[col*4+row]
+	M(0,0) = sx; M(0,1) = 0.f; M(0,2) = 0.f; M(0,3) = tx;
+	M(1,0) = 0.f; M(1,1) = sy; M(1,2) = 0.f; M(1,3) = ty;
+	M(2,0) = 0.f; M(2,1) = 0.f; M(2,2) = 1.f; M(2,3) = 0.f;
+	M(3,0) = 0.f; M(3,1) = 0.f; M(3,2) = 0.f; M(3,3) = 1.f;
+	#undef M
+
+	return glh::matrix4f(m);
+}
+
+glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
+{
+	GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f);
+
+	return glh::matrix4f(f/aspect, 0, 0, 0,
+						 0, f, 0, 0,
+						 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar),
+						 0, 0, -1.f, 0);
+}
+
 LLViewerCamera::LLViewerCamera() : LLCamera()
 {
 	calcProjection(getFar());
-	S32 i;
-	for (i = 0; i < 16; i++)
-	{
-		mGLProjectionMatrix[i] = 0.f;
-	}
 	mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
 	mPixelMeterRatio = 0.f;
 	mScreenPixelArea = 0;
@@ -79,7 +109,20 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
 	// constrain to max distance from avatar
 	LLVector3 camera_offset = center - gAgent.getPositionAgent();
 
-	setOriginAndLookAt(center, up_direction, point_of_interest);
+	LLViewerRegion * regp = gAgent.getRegion();
+	F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f;
+
+	LLVector3 origin = center;
+	if (origin.mV[2] > water_height)
+	{
+		origin.mV[2] = llmax(origin.mV[2], water_height+0.20f);
+	}
+	else
+	{
+		origin.mV[2] = llmin(origin.mV[2], water_height-0.20f);
+	}
+
+	setOriginAndLookAt(origin, up_direction, point_of_interest);
 
 	F32 dpos = (center - last_position).magVec();
 	LLQuaternion rotation;
@@ -98,6 +141,7 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
 
 // Handy copies of last good GL matrices
 F64	gGLModelView[16];
+F64	gGLLastModelView[16];
 F64 gGLProjection[16];
 S32	gGLViewport[4];
 
@@ -139,46 +183,70 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const
 // The picking region is centered on x,y and has the specified width and
 // height.
 
-LLMatrix4 gProjectionMat;
-
 //static
-void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho)
+void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip)
 {
-	GLint viewport[4];
-	GLdouble model[16];
-	GLdouble proj[16];
+	GLint* viewport = (GLint*) gGLViewport;
+	GLdouble* model = gGLModelView;
+	GLdouble* proj = gGLProjection;
 	GLdouble objX,objY,objZ;
 
 	LLVector3 frust[8];
 
-	glGetIntegerv(GL_VIEWPORT, viewport);
-	glGetDoublev(GL_MODELVIEW_MATRIX, model);
-	glGetDoublev(GL_PROJECTION_MATRIX,proj);
-
-	gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
-	frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
-	gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
-	frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
-	gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
-	frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
-	gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
-	frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
-	
-	if (ortho)
+	if (zflip)
 	{
-		LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
+
+		gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[4].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[5].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[6].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);
+
 		for (U32 i = 0; i < 4; i++)
 		{
-			frust[i+4] = frust[i] + far_shift;
+			frust[i+4] = frust[i+4]-frust[i];
+			frust[i+4].normVec();
+			frust[i+4] = frust[i] + frust[i+4]*camera.getFar();
 		}
 	}
 	else
 	{
-		for (U32 i = 0; i < 4; i++)
+		gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
+		
+		if (ortho)
 		{
-			LLVector3 vec = frust[i] - camera.getOrigin();
-			vec.normVec();
-			frust[i+4] = camera.getOrigin() + vec*camera.getFar()*2.0f;
+			LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0);
+			for (U32 i = 0; i < 4; i++)
+			{
+				frust[i+4] = frust[i] + far_shift;
+			}
+		}
+		else
+		{
+			for (U32 i = 0; i < 4; i++)
+			{
+				LLVector3 vec = frust[i] - camera.getOrigin();
+				vec.normVec();
+				frust[i+4] = camera.getOrigin() + vec*camera.getFar();
+			}
 		}
 	}
 
@@ -209,14 +277,15 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 	glMatrixMode( GL_PROJECTION );
 	glLoadIdentity();
 
+	glh::matrix4f proj_mat;
+
 	if (for_selection)
 	{
 		// make a tiny little viewport
 		// anything drawn into this viewport will be "selected"
-		const U8	VIEWPORT_VECTOR_LEN = 4;
-		GLint		viewport[VIEWPORT_VECTOR_LEN];
-		glGetIntegerv(GL_VIEWPORT, viewport);
-		gluPickMatrix(x + width / 2, y_from_bot + height / 2, width, height, viewport);
+		GLint*		viewport = (GLint*) gGLViewport;
+		
+		proj_mat = gl_pick_matrix(x+width/2.f, y_from_bot+height/2.f, (GLfloat) width, (GLfloat) height, viewport);
 
 		if (limit_select_distance)
 		{
@@ -236,6 +305,10 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 			z_far = MAX_FAR_CLIP;
 		}
 		glViewport(x, y_from_bot, width, height);
+		gGLViewport[0] = x;
+		gGLViewport[1] = y_from_bot;
+		gGLViewport[2] = width;
+		gGLViewport[3] = height;
 	}
 	
 	if (mZoomFactor > 1.f)
@@ -243,27 +316,41 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 		float offset = mZoomFactor - 1.f;
 		int pos_y = mZoomSubregion / llceil(mZoomFactor);
 		int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor));
-		glTranslatef(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f);
-		glScalef(mZoomFactor, mZoomFactor, 1.f);
+		glh::matrix4f translate;
+		translate.set_translate(glh::vec3f(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f));
+		glh::matrix4f scale;
+		scale.set_scale(glh::vec3f(mZoomFactor, mZoomFactor, 1.f));
+
+		proj_mat = scale*proj_mat;
+		proj_mat = translate*proj_mat;
 	}
 
 	calcProjection(z_far); // Update the projection matrix cache
 
-	gluPerspective(fov_y,
-				   aspect,
-				   z_near,
-				   z_far);
-	glGetDoublev(GL_PROJECTION_MATRIX, gGLProjection);
-	glGetFloatv(GL_PROJECTION_MATRIX, (float*)&gProjectionMat);
-	
+	proj_mat *= gl_perspective(fov_y,aspect,z_near,z_far);
+
+	glLoadMatrixf(proj_mat.m);
+
+	for (U32 i = 0; i < 16; i++)
+	{
+		gGLProjection[i] = proj_mat.m[i];
+	}
+
+	gGLZNear = z_near;
+	gGLZFar = z_far;
+
 	glMatrixMode( GL_MODELVIEW );
 
-	glLoadMatrixf(OGL_TO_CFR_ROTATION);		// Load Cory's favorite reference frame
+	glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION);
 
 	GLfloat			ogl_matrix[16];
+
 	getOpenGLTransform(ogl_matrix);
-	glMultMatrixf(ogl_matrix);
 
+	modelview *= glh::matrix4f(ogl_matrix);
+	
+	glLoadMatrixf(modelview.m);
+	
 	if (for_selection && (width > 1 || height > 1))
 	{
 		calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidth() - 0.5f,
@@ -277,9 +364,11 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 	if (!for_selection && mZoomFactor == 1.f)
 	{
 		// Save GL matrices for access elsewhere in code, especially project_world_to_screen
-		glGetDoublev(GL_PROJECTION_MATRIX, mGLProjectionMatrix);
-		glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView);
-		glGetIntegerv(GL_VIEWPORT, (GLint*)gGLViewport);
+		//glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView);
+		for (U32 i = 0; i < 16; i++)
+		{
+			gGLModelView[i] = modelview.m[i];
+		}
 	}
 
 	updateFrustumPlanes(*this);
@@ -302,7 +391,7 @@ void LLViewerCamera::projectScreenToPosAgent(const S32 screen_x, const S32 scree
 	GLdouble x, y, z;
 	gluUnProject(
 		GLdouble(screen_x), GLdouble(screen_y), 0.0,
-		gGLModelView, mGLProjectionMatrix, (GLint*)gGLViewport,
+		gGLModelView, gGLProjection, (GLint*)gGLViewport,
 		&x,
 		&y,
 		&z );
@@ -333,7 +422,7 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord
 	}
 
 	if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ],
-								gGLModelView, mGLProjectionMatrix, (GLint*)gGLViewport,
+								gGLModelView, gGLProjection, (GLint*)gGLViewport,
 								&x, &y, &z))
 	{
 		// convert screen coordinates to virtual UI coordinates
@@ -431,7 +520,7 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent,
 	GLdouble	x, y, z;			// object's window coords, GL-style
 	if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY],
 							  pos_agent.mV[VZ], gGLModelView,
-							  mGLProjectionMatrix, (GLint*)gGLViewport,
+							  gGLProjection, (GLint*)gGLViewport,
 							  &x, &y, &z))
 	{
 		x /= gViewerWindow->getDisplayScale().mV[VX];
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index 5a655cba1a3..c4a0f7ea530 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -62,7 +62,7 @@ class LLViewerCamera : public LLCamera
 								const LLVector3 &up_direction,
 								const LLVector3 &point_of_interest);
 
-	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE);
+	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE);
 	void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0);
 
 	const LLMatrix4 &getProjection() const;
@@ -109,13 +109,14 @@ class LLViewerCamera : public LLCamera
 	S16					mZoomSubregion;
 
 public:
-	F64		mGLProjectionMatrix[16];
-	
 };
 
 extern LLViewerCamera *gCamera;
 extern F64 gGLModelView[16];
+extern F64 gGLLastModelView[16];
 extern F64 gGLProjection[16];
 extern S32 gGLViewport[4];
+extern F32 gGLZNear;
+extern F32 gGLZFar;
 
 #endif // LL_LLVIEWERCAMERA_H
diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h
index 8a3191d3bb5..c2a9dc90960 100644
--- a/indra/newview/llviewercontrol.h
+++ b/indra/newview/llviewercontrol.h
@@ -70,6 +70,9 @@ void declare_settings();
 void fixup_settings();
 void settings_setup_listeners();
 
+// for the graphics settings
+void create_graphics_group(LLControlGroup& group);
+
 // saved at end of session
 extern LLControlGroup gSavedSettings;
 extern LLControlGroup gSavedPerAccountSettings;
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 60184312a7f..cf5d7b406ee 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -31,6 +31,11 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include "llviewerdisplay.h"
+
+#include "llgl.h"
+#include "llglimmediate.h"
+#include "llglheaders.h"
 #include "llagent.h"
 #include "llviewercontrol.h"
 #include "llcoord.h"
@@ -40,8 +45,6 @@
 #include "lldrawpoolalpha.h"
 #include "llfeaturemanager.h"
 #include "llframestats.h"
-#include "llgl.h"
-#include "llglheaders.h"
 #include "llhudmanager.h"
 #include "llimagebmp.h"
 #include "llimagegl.h"
@@ -62,6 +65,7 @@
 #include "llvograss.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llappviewer.h"
 #include "llstartup.h"
 #include "llfasttimer.h"
@@ -71,6 +75,9 @@
 #include "llcubemap.h"
 #include "llviewerregion.h"
 #include "lldrawpoolwater.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llpostprocess.h"
 
 extern LLPointer<LLImageGL> gStartImageGL;
 extern BOOL gDisplaySwapBuffers;
@@ -87,15 +94,19 @@ const F32		RESTORE_GL_TIME = 5.f;	// Wait this long while reloading textures bef
 
 BOOL gForceRenderLandFence = FALSE;
 BOOL gDisplaySwapBuffers = FALSE;
+BOOL gResizeScreenTexture = FALSE;
+BOOL gSnapshot = FALSE;
 
 // Rendering stuff
 void pre_show_depth_buffer();
 void post_show_depth_buffer();
 void render_ui_and_swap();
+void render_ui_and_swap_if_needed();
+void render_hud_attachments();
 void render_ui_3d();
 void render_ui_2d();
 void render_disconnected_background();
-
+void render_hud_elements();
 void process_keystrokes_async();
 
 void display_startup()
@@ -108,22 +119,43 @@ void display_startup()
 		return; 
 	}
 
+	LLGLSDefault gls_default;
+
 	// Required for HTML update in login screen
 	static S32 frame_count = 0;
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+#endif
+
 	if (frame_count++ > 1) // make sure we have rendered a frame first
 	{
 		LLDynamicTexture::updateAllInstances();
 	}
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+#endif
+
 	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-	LLGLSDefault gls_default;
 	LLGLSUIDefault gls_ui;
 	gPipeline.disableLights();
 
 	gViewerWindow->setup2DRender();
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
+	gGL.start();
 	gViewerWindow->draw();
+	gGL.stop();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+#endif
+
 	gViewerWindow->mWindow->swapBuffers();
+	glClear(GL_DEPTH_BUFFER_BIT);
 }
 
 
@@ -141,6 +173,10 @@ void display_update_camera()
 	}
 	gCamera->setFar(final_far);
 	gViewerWindow->setup3DRender();
+	
+	// update all the sky/atmospheric/water settings
+	LLWLParamManager::instance()->update(gCamera);
+	LLWaterParamManager::instance()->update(gCamera);
 
 	// Update land visibility too
 	if (gWorldp)
@@ -151,15 +187,24 @@ void display_update_camera()
 
 
 // Paint the display!
-void display(BOOL rebuild, F32 zoom_factor, int subfield)
+void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER);
 
+	if (LLPipeline::sRenderFrameTest)
+	{
+		send_agent_pause();
+	}
+
+	gSnapshot = for_snapshot;
+
 	LLGLSDefault gls_default;
 	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
 
 	// No clue where this is getting unset, but safe enough to reset it here.
-	LLGLState::resetTextureStates();
+	//this causes frame stalls, try real hard not to uncomment this line - DaveP
+	//LLGLState::resetTextureStates();
+	
 	
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkStates();
@@ -167,7 +212,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 #endif
 	
 	gPipeline.disableLights();
-
+	
 	// Don't draw if the window is hidden or minimized.
 	// In fact, must explicitly check the minimized state before drawing.
 	// Attempting to draw into a minimized window causes a GL error. JC
@@ -185,7 +230,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 	}
 
 	gViewerWindow->checkSettings();
+	
 	gViewerWindow->performPick();
+	
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkStates();
@@ -235,7 +282,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 	stop_glerror();
 
 	LLImageGL::updateStats(gFrameTimeSeconds);
-
+	
 	LLVOAvatar::sRenderName = gSavedSettings.getS32("RenderName");
 	LLVOAvatar::sRenderGroupTitles = gSavedSettings.getBOOL("RenderGroupTitleAll");
 	gPipeline.mBackfaceCull = TRUE;
@@ -369,18 +416,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 	// Prepare for the next frame
 	//
 
-	// Hmm...  Should this be moved elsewhere? - djs 09/09/02
-	// do render-to-texture stuff here
-	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
-	{
-// 		LLFastTimer t(LLFastTimer::FTM_UPDATE_TEXTURES);
-		if (LLDynamicTexture::updateAllInstances())
-		{
-			glClear(GL_COLOR_BUFFER_BIT);
-		}
-	}
-
-
 	/////////////////////////////
 	//
 	// Update the camera
@@ -398,18 +433,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 
 	if (gDisconnected)
 	{
-		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		render_ui_and_swap_if_needed();
+		gDisplaySwapBuffers = TRUE;
+		
 		render_disconnected_background();
 	}
-	else if (!gViewerWindow->isPickPending())
-	{
-		glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
-		//DEBUG TEMPORARY
-		glClear(GL_COLOR_BUFFER_BIT);
-	}
-	gViewerWindow->setupViewport();
-
-
+	
 	//////////////////////////
 	//
 	// Set rendering options
@@ -421,18 +450,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 		pre_show_depth_buffer();
 	}
 
-	if(gUseWireframe)//gSavedSettings.getBOOL("UseWireframe"))
-	{
-		glClearColor(0.5f, 0.5f, 0.5f, 0.f);
-		glClear(GL_COLOR_BUFFER_BIT);
-		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-		LLPipeline::sUseOcclusion = FALSE;
-	}
-	else
-	{
-		LLPipeline::sUseOcclusion = gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery && gFeatureManagerp->isFeatureAvailable("UseOcclusion");
-	}
-
 	stop_glerror();
 
 	///////////////////////////////////////
@@ -444,16 +461,27 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 	F32 one[4] =	{1.f, 1.f, 1.f, 1.f};
 	glLightModelfv (GL_LIGHT_MODEL_AMBIENT,one);
 	stop_glerror();
-	
-	//Increment drawable frame counter
-	LLDrawable::incrementVisible();
-
+		
 	/////////////////////////////////////
 	//
 	// Render
 	//
 	// Actually push all of our triangles to the screen.
 	//
+
+	// do render-to-texture stuff here
+	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
+	{
+		LLFastTimer t(LLFastTimer::FTM_UPDATE_TEXTURES);
+		if (LLDynamicTexture::updateAllInstances())
+		{
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		}
+	}
+
+	gViewerWindow->setupViewport();
+	
 	if (!gDisconnected)
 	{
 		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
@@ -461,30 +489,106 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
 		}
 		
-		LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE);
+		//upkeep gl name pools
+		LLGLNamePool::upkeepPools();
+		
 		stop_glerror();
 		display_update_camera();
 		stop_glerror();
-		
+				
 		// *TODO: merge these two methods
 		gHUDManager->updateEffects();
 		LLHUDObject::updateAll();
 		stop_glerror();
 		
 		gFrameStats.start(LLFrameStats::UPDATE_GEOM);
-		const F32 max_geom_update_time = 0.005f; // 5 ms update time
+		const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
 		gPipeline.updateGeom(max_geom_update_time);
 		stop_glerror();
 		
-		LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME);
-		part->processImagery(gCamera);
+		gFrameStats.start(LLFrameStats::UPDATE_CULL);
+		S32 water_clip = 0;
+		if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT) > 1)
+		{
+			if (gCamera->cameraUnderWater())
+			{
+				water_clip = -1;
+			}
+			else
+			{
+				water_clip = 1;
+			}
+		}
 
-		display_update_camera();
+		//Increment drawable frame counter
+		LLDrawable::incrementVisible();
+
+		LLPipeline::sUseOcclusion = 
+				(!gUseWireframe
+				&& gFeatureManagerp->isFeatureAvailable("UseOcclusion") 
+				&& gSavedSettings.getBOOL("UseOcclusion") 
+				&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
+		LLPipeline::sFastAlpha = gSavedSettings.getBOOL("RenderFastAlpha");
+		LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
+		LLVOAvatar::sMaxVisible = gSavedSettings.getS32("RenderAvatarMaxVisible");
+		
+		S32 occlusion = LLPipeline::sUseOcclusion;
+		if (!gDisplaySwapBuffers)
+		{ //depth buffer is invalid, don't overwrite occlusion state
+			LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+		}
 
-		gFrameStats.start(LLFrameStats::UPDATE_CULL);
-		gPipeline.updateCull(*gCamera);
+		static LLCullResult result;
+		gPipeline.updateCull(*gCamera, result, water_clip);
 		stop_glerror();
-		
+
+		BOOL to_texture = !for_snapshot &&
+						gPipeline.canUseVertexShaders() &&
+						LLPipeline::sRenderGlow &&
+						gGLManager.mHasFramebufferObject;
+
+		// now do the swap buffer (just before rendering to framebuffer)
+		{ //swap and flush state from previous frame
+			{
+ 				LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY);
+				LLVertexBuffer::clientCopy(0.016);
+			}
+
+			if (gResizeScreenTexture)
+			{
+				gResizeScreenTexture = FALSE;
+				gPipeline.resizeScreenTexture();
+			}
+
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+			glClearColor(0,0,0,0);
+			
+			if (!for_snapshot)
+			{
+				render_ui_and_swap_if_needed();
+				gDisplaySwapBuffers = TRUE;
+				
+				glh::matrix4f proj = glh_get_current_projection();
+				glh::matrix4f mod = glh_get_current_modelview();
+				glViewport(0,0,128,256);
+				LLVOAvatar::updateImpostors();
+				glh_set_current_projection(proj);
+				glh_set_current_modelview(mod);
+				glMatrixMode(GL_PROJECTION);
+				glLoadMatrixf(proj.m);
+				glMatrixMode(GL_MODELVIEW);
+				glLoadMatrixf(mod.m);
+				gViewerWindow->setupViewport();
+			}
+			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		}
+
+		if (!for_snapshot)
+		{
+			gPipeline.processImagery(*gCamera);
+			gPipeline.generateWaterReflection(*gCamera);
+		}
+
 		///////////////////////////////////
 		//
 		// StateSort
@@ -494,10 +598,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 		// Also creates special lists for outlines and selected face rendering.
 		//
 		{
-			LLFastTimer t(LLFastTimer::FTM_REBUILD);
-			
 			gFrameStats.start(LLFrameStats::STATE_SORT);
-			gPipeline.stateSort(*gCamera);
+			gPipeline.stateSort(*gCamera, result);
 			stop_glerror();
 				
 			if (rebuild)
@@ -512,67 +614,133 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 				stop_glerror();
 			}
 		}
+
+		LLPipeline::sUseOcclusion = occlusion;
+
+		{
+			LLFastTimer t(LLFastTimer::FTM_UPDATE_SKY);	
+			gSky.updateSky();
+		}
+
+		if(gUseWireframe)
+		{
+			glClearColor(0.5f, 0.5f, 0.5f, 0.f);
+			glClear(GL_COLOR_BUFFER_BIT);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+		}
+
+		//// render frontmost floater opaque for occlusion culling purposes
+		//LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
+		//// assumes frontmost floater with focus is opaque
+		//if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
+		//{
+		//	glMatrixMode(GL_MODELVIEW);
+		//	glPushMatrix();
+		//	{
+		//		LLGLSNoTexture gls_no_texture;
+
+		//		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+		//		glLoadIdentity();
+
+		//		LLRect floater_rect = frontmost_floaterp->getScreenRect();
+		//		// deflate by one pixel so rounding errors don't occlude outside of floater extents
+		//		floater_rect.stretch(-1);
+		//		LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidth(), 
+		//								(F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeight(),
+		//								(F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidth(),
+		//								(F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeight());
+		//		floater_3d_rect.translate(-0.5f, -0.5f);
+		//		glTranslatef(0.f, 0.f, -gCamera->getNear());
+		//		glScalef(gCamera->getNear() * gCamera->getAspect() / sinf(gCamera->getView()), gCamera->getNear() / sinf(gCamera->getView()), 1.f);
+		//		gGL.color4fv(LLColor4::white.mV);
+		//		gGL.begin(GL_QUADS);
+		//		{
+		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
+		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
+		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
+		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
+		//		}
+		//		gGL.end();
+		//		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+		//	}
+		//	glPopMatrix();
+		//}
+
+		if (to_texture)
+		{
+			glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+			gPipeline.mScreen.bindTarget();
+			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+			glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+		}
+
+		if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
+				&& !gRestoreGL)
+		{
+			glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+			LLPipeline::sUnderWaterRender = gCamera->cameraUnderWater() ? TRUE : FALSE;
+			gPipeline.renderGeom(*gCamera, TRUE);
+			LLPipeline::sUnderWaterRender = FALSE;
+			glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+			//store this frame's modelview matrix for use
+			//when rendering next frame's occlusion queries
+			for (U32 i = 0; i < 16; i++)
+			{
+				gGLLastModelView[i] = gGLModelView[i];
+			}
+			stop_glerror();
+		}
+	
+		render_hud_attachments();
+		
+		if (to_texture)
+		{
+			gPipeline.mScreen.flush();
+		}
+
+		/// We copy the frame buffer straight into a texture here,
+		/// and then display it again with compositor effects.
+		/// Using render to texture would be faster/better, but I don't have a 
+		/// grasp of their full display stack just yet.
+		// gPostProcess->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
 	}
+	gFrameStats.start(LLFrameStats::RENDER_UI);
 
-	//// render frontmost floater opaque for occlusion culling purposes
-	//LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
-	//// assumes frontmost floater with focus is opaque
-	//if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
-	//{
-	//	glMatrixMode(GL_MODELVIEW);
-	//	glPushMatrix();
-	//	{
-	//		LLGLSNoTexture gls_no_texture;
-
-	//		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
-	//		glLoadIdentity();
-
-	//		LLRect floater_rect = frontmost_floaterp->getScreenRect();
-	//		// deflate by one pixel so rounding errors don't occlude outside of floater extents
-	//		floater_rect.stretch(-1);
-	//		LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidth(), 
-	//								(F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeight(),
-	//								(F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidth(),
-	//								(F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeight());
-	//		floater_3d_rect.translate(-0.5f, -0.5f);
-	//		glTranslatef(0.f, 0.f, -gCamera->getNear());
-	//		glScalef(gCamera->getNear() * gCamera->getAspect() / sinf(gCamera->getView()), gCamera->getNear() / sinf(gCamera->getView()), 1.f);
-	//		glColor4fv(LLColor4::white.mV);
-	//		glBegin(GL_QUADS);
-	//		{
-	//			glVertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
-	//			glVertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
-	//			glVertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
-	//			glVertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
-	//		}
-	//		glEnd();
-	//		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-	//	}
-	//	glPopMatrix();
-	//}
-
-	if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) 
-			&& !gRestoreGL
-			&& !gDisconnected)
+	if (gHandleKeysAsync)
 	{
-		gPipeline.renderGeom(*gCamera);
+		process_keystrokes_async();
 		stop_glerror();
 	}
 
-	//render hud attachments
+	gFrameStats.start(LLFrameStats::MISC_END);
+	stop_glerror();
+
+	if (LLPipeline::sRenderFrameTest)
+	{
+		send_agent_resume();
+		LLPipeline::sRenderFrameTest = FALSE;
+	}
+}
+
+void render_hud_attachments()
+{
 	glMatrixMode(GL_PROJECTION);
 	glPushMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPushMatrix();
-	
+		
+	glh::matrix4f current_proj = glh_get_current_projection();
+	glh::matrix4f current_mod = glh_get_current_modelview();
+
 	if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices(FALSE))
 	{
 		LLCamera hud_cam = *gCamera;
-		glClear(GL_DEPTH_BUFFER_BIT);
 		LLVector3 origin = hud_cam.getOrigin();
 		hud_cam.setOrigin(-1.f,0,0);
 		hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
 		LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
+		
 		//only render hud objects
 		U32 mask = gPipeline.getRenderTypeMask();
 		gPipeline.setRenderTypeMask(0);
@@ -584,22 +752,22 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
 		}
 
-		BOOL use_occlusion = gSavedSettings.getBOOL("UseOcclusion");
-		gSavedSettings.setBOOL("UseOcclusion", FALSE);
+		S32 use_occlusion = LLPipeline::sUseOcclusion;
+		LLPipeline::sUseOcclusion = 0;
+		LLPipeline::sDisableShaders = TRUE;
 
 		//cull, sort, and render hud objects
-		gPipeline.updateCull(hud_cam);
+		static LLCullResult result;
+		gPipeline.updateCull(hud_cam, result);
 
-		gPipeline.toggleRenderType(LLDrawPool::POOL_ALPHA_POST_WATER);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_GLOW);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
 		
-		{
-			LLFastTimer ftm(LLFastTimer::FTM_REBUILD);
-			gPipeline.stateSort(hud_cam);
-		}
-				
+		gPipeline.stateSort(hud_cam, result);
+
 		gPipeline.renderGeom(hud_cam);
 
 		//restore type mask
@@ -608,33 +776,16 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 		{
 			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
 		}
-		gSavedSettings.setBOOL("UseOcclusion", use_occlusion);
+		LLPipeline::sUseOcclusion = use_occlusion;
+		LLPipeline::sDisableShaders = FALSE;
 	}
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
-
-	gFrameStats.start(LLFrameStats::RENDER_UI);
-
-	if (gHandleKeysAsync)
-	{
-		process_keystrokes_async();
-		stop_glerror();
-	}
-
 	
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkStates();
-#endif
-	render_ui_and_swap();
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	LLGLState::checkStates();
-#endif
-
-	gFrameStats.start(LLFrameStats::MISC_END);
-	stop_glerror();
-
+	glh_set_current_projection(current_proj);
+	glh_set_current_modelview(current_mod);
 }
 
 BOOL setup_hud_matrices(BOOL for_select)
@@ -654,22 +805,22 @@ BOOL setup_hud_matrices(BOOL for_select)
 		// clear z buffer and set up transform for hud
 		if (!for_select)
 		{
-			glClear(GL_DEPTH_BUFFER_BIT);
+			//glClear(GL_DEPTH_BUFFER_BIT);
 		}
 		LLBBox hud_bbox = my_avatarp->getHUDBBox();
 
 		
 		// set up transform to encompass bounding box of HUD
 		glMatrixMode(GL_PROJECTION);
-		glLoadIdentity();
 		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
 		if (for_select)
 		{
 			//RN: reset viewport to window extents so ortho screen is calculated with proper reference frame
 			gViewerWindow->setupViewport();
 		}
-		glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
-
+		glh::matrix4f proj = gl_ortho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
+		proj.element(2,2) = -0.01f;
+		
 		// apply camera zoom transform (for high res screenshots)
 		F32 zoom_factor = gCamera->getZoomFactor();
 		S16 sub_region = gCamera->getZoomSubRegion();
@@ -678,16 +829,26 @@ BOOL setup_hud_matrices(BOOL for_select)
 			float offset = zoom_factor - 1.f;
 			int pos_y = sub_region / llceil(zoom_factor);
 			int pos_x = sub_region - (pos_y*llceil(zoom_factor));
-			glTranslatef(gCamera->getAspect() * 0.5f * (offset - (F32)pos_x * 2.f), 0.5f * (offset - (F32)pos_y * 2.f), 0.f);
-			glScalef(zoom_factor, zoom_factor, 1.f);
+			glh::matrix4f mat;
+			mat.set_scale(glh::vec3f(zoom_factor, zoom_factor, 1.f));
+			mat.set_translate(glh::vec3f(gCamera->getAspect() * 0.5f * (offset - (F32)pos_x * 2.f), 0.5f * (offset - (F32)pos_y * 2.f), 0.f));
+			proj *= mat;
 		}
 
+		glLoadMatrixf(proj.m);
+		glh_set_current_projection(proj);
+
 		glMatrixMode(GL_MODELVIEW);
-		glLoadIdentity();
-		glLoadMatrixf(OGL_TO_CFR_ROTATION);		// Load Cory's favorite reference frame
-		glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f);
-		glScalef(zoom_level, zoom_level, zoom_level);
+		glh::matrix4f model((GLfloat*) OGL_TO_CFR_ROTATION);
 		
+		glh::matrix4f mat;
+		mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
+		mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
+
+		model *= mat;
+		glLoadMatrixf(model.m);
+		glh_set_current_modelview(model);
+
 		return TRUE;
 	}
 	else
@@ -702,15 +863,31 @@ void render_ui_and_swap()
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 	LLGLState::checkStates();
 #endif
+	
+	{
+		BOOL to_texture = gPipeline.canUseVertexShaders() &&
+							LLPipeline::sRenderGlow &&
+							gGLManager.mHasFramebufferObject;
+
+		if (to_texture)
+		{
+			gPipeline.renderBloom(gSnapshot);
+		}
+	}
 
 	LLGLSDefault gls_default;
+	LLGLSUIDefault gls_ui;
 	{
-		LLGLSUIDefault gls_ui;
 		gPipeline.disableLights();
+	}
+
+	{
 		LLVertexBuffer::startRender();
+		gGL.start();
 		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 		{
 			LLFastTimer t(LLFastTimer::FTM_RENDER_UI);
+
 			if (!gDisconnected)
 			{
 				render_ui_3d();
@@ -724,71 +901,78 @@ void render_ui_and_swap()
 			LLGLState::checkStates();
 #endif
 		}
-		LLVertexBuffer::stopRender();
-		glFlush();
+		gGL.stop();
 
-		// now do the swap buffer
-		if (gDisplaySwapBuffers)
 		{
-			LLFastTimer t(LLFastTimer::FTM_SWAP);
-			gViewerWindow->mWindow->swapBuffers();
+			gViewerWindow->setup2DRender();
+			gViewerWindow->updateDebugText();
+			gViewerWindow->drawDebugText();
 		}
 
+		LLVertexBuffer::stopRender();
+	}
+}
+
+void render_ui_and_swap_if_needed()
+{
+	if (gDisplaySwapBuffers)
+	{
+		render_ui_and_swap();
+		
 		{
- 			LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY);
-			LLVertexBuffer::clientCopy(0.016);
+			LLFastTimer t(LLFastTimer::FTM_SWAP);
+			gViewerWindow->mWindow->swapBuffers();
 		}
-
 	}
 }
 
 void renderCoordinateAxes()
 {
 	LLGLSNoTexture gls_no_texture;
-	glBegin(GL_LINES);
-		glColor3f(1.0f, 0.0f, 0.0f);   // i direction = X-Axis = red
-		glVertex3f(0.0f, 0.0f, 0.0f);
-		glVertex3f(2.0f, 0.0f, 0.0f);
-		glVertex3f(3.0f, 0.0f, 0.0f);
-		glVertex3f(5.0f, 0.0f, 0.0f);
-		glVertex3f(6.0f, 0.0f, 0.0f);
-		glVertex3f(8.0f, 0.0f, 0.0f);
+	gGL.begin(GL_LINES);
+		gGL.color3f(1.0f, 0.0f, 0.0f);   // i direction = X-Axis = red
+		gGL.vertex3f(0.0f, 0.0f, 0.0f);
+		gGL.vertex3f(2.0f, 0.0f, 0.0f);
+		gGL.vertex3f(3.0f, 0.0f, 0.0f);
+		gGL.vertex3f(5.0f, 0.0f, 0.0f);
+		gGL.vertex3f(6.0f, 0.0f, 0.0f);
+		gGL.vertex3f(8.0f, 0.0f, 0.0f);
 		// Make an X
-		glVertex3f(11.0f, 1.0f, 1.0f);
-		glVertex3f(11.0f, -1.0f, -1.0f);
-		glVertex3f(11.0f, 1.0f, -1.0f);
-		glVertex3f(11.0f, -1.0f, 1.0f);
-
-		glColor3f(0.0f, 1.0f, 0.0f);   // j direction = Y-Axis = green
-		glVertex3f(0.0f, 0.0f, 0.0f);
-		glVertex3f(0.0f, 2.0f, 0.0f);
-		glVertex3f(0.0f, 3.0f, 0.0f);
-		glVertex3f(0.0f, 5.0f, 0.0f);
-		glVertex3f(0.0f, 6.0f, 0.0f);
-		glVertex3f(0.0f, 8.0f, 0.0f);
+		gGL.vertex3f(11.0f, 1.0f, 1.0f);
+		gGL.vertex3f(11.0f, -1.0f, -1.0f);
+		gGL.vertex3f(11.0f, 1.0f, -1.0f);
+		gGL.vertex3f(11.0f, -1.0f, 1.0f);
+
+		gGL.color3f(0.0f, 1.0f, 0.0f);   // j direction = Y-Axis = green
+		gGL.vertex3f(0.0f, 0.0f, 0.0f);
+		gGL.vertex3f(0.0f, 2.0f, 0.0f);
+		gGL.vertex3f(0.0f, 3.0f, 0.0f);
+		gGL.vertex3f(0.0f, 5.0f, 0.0f);
+		gGL.vertex3f(0.0f, 6.0f, 0.0f);
+		gGL.vertex3f(0.0f, 8.0f, 0.0f);
 		// Make a Y
-		glVertex3f(1.0f, 11.0f, 1.0f);
-		glVertex3f(0.0f, 11.0f, 0.0f);
-		glVertex3f(-1.0f, 11.0f, 1.0f);
-		glVertex3f(0.0f, 11.0f, 0.0f);
-		glVertex3f(0.0f, 11.0f, 0.0f);
-		glVertex3f(0.0f, 11.0f, -1.0f);
-
-		glColor3f(0.0f, 0.0f, 1.0f);   // Z-Axis = blue
-		glVertex3f(0.0f, 0.0f, 0.0f);
-		glVertex3f(0.0f, 0.0f, 2.0f);
-		glVertex3f(0.0f, 0.0f, 3.0f);
-		glVertex3f(0.0f, 0.0f, 5.0f);
-		glVertex3f(0.0f, 0.0f, 6.0f);
-		glVertex3f(0.0f, 0.0f, 8.0f);
+		gGL.vertex3f(1.0f, 11.0f, 1.0f);
+		gGL.vertex3f(0.0f, 11.0f, 0.0f);
+		gGL.vertex3f(-1.0f, 11.0f, 1.0f);
+		gGL.vertex3f(0.0f, 11.0f, 0.0f);
+		gGL.vertex3f(0.0f, 11.0f, 0.0f);
+		gGL.vertex3f(0.0f, 11.0f, -1.0f);
+
+		gGL.color3f(0.0f, 0.0f, 1.0f);   // Z-Axis = blue
+		gGL.vertex3f(0.0f, 0.0f, 0.0f);
+		gGL.vertex3f(0.0f, 0.0f, 2.0f);
+		gGL.vertex3f(0.0f, 0.0f, 3.0f);
+		gGL.vertex3f(0.0f, 0.0f, 5.0f);
+		gGL.vertex3f(0.0f, 0.0f, 6.0f);
+		gGL.vertex3f(0.0f, 0.0f, 8.0f);
 		// Make a Z
-		glVertex3f(-1.0f, 1.0f, 11.0f);
-		glVertex3f(1.0f, 1.0f, 11.0f);
-		glVertex3f(1.0f, 1.0f, 11.0f);
-		glVertex3f(-1.0f, -1.0f, 11.0f);
-		glVertex3f(-1.0f, -1.0f, 11.0f);
-		glVertex3f(1.0f, -1.0f, 11.0f);
-	glEnd();
+		gGL.vertex3f(-1.0f, 1.0f, 11.0f);
+		gGL.vertex3f(1.0f, 1.0f, 11.0f);
+		gGL.vertex3f(1.0f, 1.0f, 11.0f);
+		gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+		gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+		gGL.vertex3f(1.0f, -1.0f, 11.0f);
+	gGL.end();
 }
 
 
@@ -798,11 +982,11 @@ void draw_axes()
 	LLGLSNoTexture gls_no_texture;
 	// A vertical white line at origin
 	LLVector3 v = gAgent.getPositionAgent();
-	glBegin(GL_LINES);
-		glColor3f(1.0f, 1.0f, 1.0f); 
-		glVertex3f(0.0f, 0.0f, 0.0f);
-		glVertex3f(0.0f, 0.0f, 40.0f);
-	glEnd();
+	gGL.begin(GL_LINES);
+		gGL.color3f(1.0f, 1.0f, 1.0f); 
+		gGL.vertex3f(0.0f, 0.0f, 0.0f);
+		gGL.vertex3f(0.0f, 0.0f, 40.0f);
+	gGL.end();
 	// Some coordinate axes
 	glPushMatrix();
 		glTranslatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
@@ -822,9 +1006,9 @@ void render_ui_3d()
 	//
 
 	// Render selections
-	glDisableClientState(GL_COLOR_ARRAY);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
+	//glDisableClientState(GL_COLOR_ARRAY);
+	//glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	//glDisableClientState(GL_NORMAL_ARRAY);
 
 	/////////////////////////////////////////////////////////////
 	//
@@ -891,7 +1075,7 @@ void render_ui_2d()
 		glTranslatef((F32)half_width, (F32)half_height, 0.f);
 		F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
 		glScalef(zoom,zoom,1.f);
-		glColor4fv(LLColor4::white.mV);
+		gGL.color4fv(LLColor4::white.mV);
 		gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
 		glPopMatrix();
 		stop_glerror();
@@ -909,6 +1093,7 @@ void render_ui_2d()
 
 void render_disconnected_background()
 {
+	gGL.start();
 	if (!gDisconnectedImagep && gDisconnected)
 	{
 		llinfos << "Loading last bitmap..." << llendl;
@@ -951,7 +1136,7 @@ void render_disconnected_background()
 			rawp++;
 		}
 
-
+		
 		raw->expandToPowerOfTwo();
 		gDisconnectedImagep->createGLTexture(0, raw);
 		gStartImageGL = gDisconnectedImagep;
@@ -975,12 +1160,13 @@ void render_disconnected_background()
 			glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
 
 			LLViewerImage::bindTexture(gDisconnectedImagep);
-			glColor4f(1.f, 1.f, 1.f, 1.f);
+			gGL.color4f(1.f, 1.f, 1.f, 1.f);
 			gl_rect_2d_simple_tex(width, height);
 			LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
 		}
 		glPopMatrix();
 	}
+	gGL.stop();
 }
 
 void display_cleanup()
diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h
index 2bf784c575d..2190021fe4d 100644
--- a/indra/newview/llviewerdisplay.h
+++ b/indra/newview/llviewerdisplay.h
@@ -32,14 +32,17 @@
 #ifndef LL_LLVIEWERDISPLAY_H
 #define LL_LLVIEWERDISPLAY_H
 
+class LLPostProcess;
+
 void display_startup();
 void display_cleanup();
 
-void display(BOOL rebuild = TRUE, F32 zoom_factor = 1.f, int subfield = 0);
+void display(BOOL rebuild = TRUE, F32 zoom_factor = 1.f, int subfield = 0, BOOL for_snapshot = FALSE);
 
 extern BOOL gDisplaySwapBuffers;
 extern BOOL	gTeleportDisplay;
 extern LLFrameTimer	gTeleportDisplayTimer;
 extern BOOL			gForceRenderLandFence;
+extern BOOL gResizeScreenTexture;
 
 #endif // LL_LLVIEWERDISPLAY_H
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index 093aca66f35..365bfa70107 100644
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -37,6 +37,7 @@
 #include "llviewerjoint.h"
 
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llmath.h"
 #include "llglheaders.h"
 #include "llsphere.h"
@@ -147,19 +148,19 @@ void LLViewerJoint::renderSkeleton(BOOL recursive)
 	//----------------------------------------------------------------
 	if (mComponents & SC_AXES)
 	{
-		glBegin(GL_LINES);
-		glColor3f( 1.0f, 0.0f, 0.0f );
-		glVertex3f( 0.0f,            0.0f, 0.0f );
-		glVertex3f( 0.1f, 0.0f, 0.0f );
-
-		glColor3f( 0.0f, 1.0f, 0.0f );
-		glVertex3f( 0.0f, 0.0f,            0.0f );
-		glVertex3f( 0.0f, 0.1f, 0.0f );
-
-		glColor3f( 0.0f, 0.0f, 1.0f );
-		glVertex3f( 0.0f, 0.0f, 0.0f );
-		glVertex3f( 0.0f, 0.0f, 0.1f );
-		glEnd();
+		gGL.begin(GL_LINES);
+		gGL.color3f( 1.0f, 0.0f, 0.0f );
+		gGL.vertex3f( 0.0f,            0.0f, 0.0f );
+		gGL.vertex3f( 0.1f, 0.0f, 0.0f );
+
+		gGL.color3f( 0.0f, 1.0f, 0.0f );
+		gGL.vertex3f( 0.0f, 0.0f,            0.0f );
+		gGL.vertex3f( 0.0f, 0.1f, 0.0f );
+
+		gGL.color3f( 0.0f, 0.0f, 1.0f );
+		gGL.vertex3f( 0.0f, 0.0f, 0.0f );
+		gGL.vertex3f( 0.0f, 0.0f, 0.1f );
+		gGL.end();
 	}
 
 	//----------------------------------------------------------------
@@ -167,53 +168,53 @@ void LLViewerJoint::renderSkeleton(BOOL recursive)
 	//----------------------------------------------------------------
 	if (mComponents & SC_JOINT)
 	{
-		glColor3f( 1.0f, 1.0f, 0.0f );
+		gGL.color3f( 1.0f, 1.0f, 0.0f );
 
-		glBegin(GL_TRIANGLES);
+		gGL.begin(GL_TRIANGLES);
 
 		// joint top half
 		glNormal3f(nc, nc, nc);
-		glVertex3f(0.0f,             0.0f, 0.05f);
-		glVertex3f(0.05f,       0.0f,       0.0f);
-		glVertex3f(0.0f,       0.05f,       0.0f);
+		gGL.vertex3f(0.0f,             0.0f, 0.05f);
+		gGL.vertex3f(0.05f,       0.0f,       0.0f);
+		gGL.vertex3f(0.0f,       0.05f,       0.0f);
 
 		glNormal3f(-nc, nc, nc);
-		glVertex3f(0.0f,             0.0f, 0.05f);
-		glVertex3f(0.0f,       0.05f,       0.0f);
-		glVertex3f(-0.05f,      0.0f,       0.0f);
+		gGL.vertex3f(0.0f,             0.0f, 0.05f);
+		gGL.vertex3f(0.0f,       0.05f,       0.0f);
+		gGL.vertex3f(-0.05f,      0.0f,       0.0f);
 		
 		glNormal3f(-nc, -nc, nc);
-		glVertex3f(0.0f,             0.0f, 0.05f);
-		glVertex3f(-0.05f,      0.0f,      0.0f);
-		glVertex3f(0.0f,      -0.05f,      0.0f);
+		gGL.vertex3f(0.0f,             0.0f, 0.05f);
+		gGL.vertex3f(-0.05f,      0.0f,      0.0f);
+		gGL.vertex3f(0.0f,      -0.05f,      0.0f);
 
 		glNormal3f(nc, -nc, nc);
-		glVertex3f(0.0f,              0.0f, 0.05f);
-		glVertex3f(0.0f,       -0.05f,       0.0f);
-		glVertex3f(0.05f,        0.0f,       0.0f);
+		gGL.vertex3f(0.0f,              0.0f, 0.05f);
+		gGL.vertex3f(0.0f,       -0.05f,       0.0f);
+		gGL.vertex3f(0.05f,        0.0f,       0.0f);
 		
 		// joint bottom half
 		glNormal3f(nc, nc, -nc);
-		glVertex3f(0.0f,             0.0f, -0.05f);
-		glVertex3f(0.0f,       0.05f,        0.0f);
-		glVertex3f(0.05f,       0.0f,        0.0f);
+		gGL.vertex3f(0.0f,             0.0f, -0.05f);
+		gGL.vertex3f(0.0f,       0.05f,        0.0f);
+		gGL.vertex3f(0.05f,       0.0f,        0.0f);
 
 		glNormal3f(-nc, nc, -nc);
-		glVertex3f(0.0f,             0.0f, -0.05f);
-		glVertex3f(-0.05f,      0.0f,        0.0f);
-		glVertex3f(0.0f,       0.05f,        0.0f);
+		gGL.vertex3f(0.0f,             0.0f, -0.05f);
+		gGL.vertex3f(-0.05f,      0.0f,        0.0f);
+		gGL.vertex3f(0.0f,       0.05f,        0.0f);
 		
 		glNormal3f(-nc, -nc, -nc);
-		glVertex3f(0.0f,              0.0f, -0.05f);
-		glVertex3f(0.0f,       -0.05f,        0.0f);
-		glVertex3f(-0.05f,       0.0f,        0.0f);
+		gGL.vertex3f(0.0f,              0.0f, -0.05f);
+		gGL.vertex3f(0.0f,       -0.05f,        0.0f);
+		gGL.vertex3f(-0.05f,       0.0f,        0.0f);
 
 		glNormal3f(nc, -nc, -nc);
-		glVertex3f(0.0f,             0.0f,  -0.05f);
-		glVertex3f(0.05f,       0.0f,         0.0f);
-		glVertex3f(0.0f,      -0.05f,         0.0f);
+		gGL.vertex3f(0.0f,             0.0f,  -0.05f);
+		gGL.vertex3f(0.05f,       0.0f,         0.0f);
+		gGL.vertex3f(0.0f,      -0.05f,         0.0f);
 		
-		glEnd();
+		gGL.end();
 	}
 
 	//----------------------------------------------------------------
@@ -258,7 +259,7 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass )
 		{
 			triangle_count += drawShape( pixelArea, first_pass );
 		}
-		else if ( isTransparent() )
+		else if ( isTransparent() && !LLPipeline::sReflectionRender)
 		{
 			// Hair and Skirt
 			if ((pixelArea > MIN_PIXEL_AREA_3PASS_HAIR))
@@ -357,27 +358,27 @@ void LLViewerJoint::drawBone()
 	glMultMatrixf( &rotateMat.mMatrix[0][0] );
 
 	// render the bone
-	glColor3f( 0.5f, 0.5f, 0.0f );
+	gGL.color3f( 0.5f, 0.5f, 0.0f );
 
-	glBegin(GL_TRIANGLES);
+	gGL.begin(GL_TRIANGLES);
 
-	glVertex3f( length,     0.0f,       0.0f);
-	glVertex3f( 0.0f,       boneSize,  0.0f);
-	glVertex3f( 0.0f,       0.0f,       boneSize);
+	gGL.vertex3f( length,     0.0f,       0.0f);
+	gGL.vertex3f( 0.0f,       boneSize,  0.0f);
+	gGL.vertex3f( 0.0f,       0.0f,       boneSize);
 
-	glVertex3f( length,     0.0f,        0.0f);
-	glVertex3f( 0.0f,       0.0f,        -boneSize);
-	glVertex3f( 0.0f,       boneSize,   0.0f);
+	gGL.vertex3f( length,     0.0f,        0.0f);
+	gGL.vertex3f( 0.0f,       0.0f,        -boneSize);
+	gGL.vertex3f( 0.0f,       boneSize,   0.0f);
 
-	glVertex3f( length,     0.0f,        0.0f);
-	glVertex3f( 0.0f,       -boneSize,  0.0f);
-	glVertex3f( 0.0f,       0.0f,        -boneSize);
+	gGL.vertex3f( length,     0.0f,        0.0f);
+	gGL.vertex3f( 0.0f,       -boneSize,  0.0f);
+	gGL.vertex3f( 0.0f,       0.0f,        -boneSize);
 
-	glVertex3f( length,     0.0f,        0.0f);
-	glVertex3f( 0.0f,       0.0f,        boneSize);
-	glVertex3f( 0.0f,       -boneSize,  0.0f);
+	gGL.vertex3f( length,     0.0f,        0.0f);
+	gGL.vertex3f( 0.0f,       0.0f,        boneSize);
+	gGL.vertex3f( 0.0f,       -boneSize,  0.0f);
 
-	glEnd();
+	gGL.end();
 
 	// restore matrix
 	glPopMatrix();
@@ -422,16 +423,7 @@ void LLViewerJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pix
 		 iter != mChildren.end(); ++iter)
 	{
 		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		//F32 jointLOD = joint->getLOD();
-		//if (pixel_area >= jointLOD || sDisableLOD)
-		{
-			joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
-
-		//	if (jointLOD != DEFAULT_LOD)
-		//	{
-		//		break;
-		//	}
-		}
+		joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
 	}
 }
 
@@ -441,16 +433,7 @@ void LLViewerJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind)
 		 iter != mChildren.end(); ++iter)
 	{
 		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		//F32 jointLOD = joint->getLOD();
-		//if (pixel_area >= jointLOD || sDisableLOD)
-		{
-			joint->updateFaceData(face, pixel_area, damp_wind);
-
-		//	if (jointLOD != DEFAULT_LOD)
-		//	{
-		//		break;
-		//	}
-		}
+		joint->updateFaceData(face, pixel_area, damp_wind);
 	}
 }
 
@@ -522,76 +505,6 @@ void LLViewerJoint::setVisible(BOOL visible, BOOL recursive)
 	}
 }
 
-void LLViewerJoint::writeCAL3D(apr_file_t* fp)
-{
-	LLVector3 bone_pos = mXform.getPosition();
-	if (mParent)
-	{
-		bone_pos.scaleVec(mParent->getScale());
-		bone_pos *= 100.f;
-	}
-	else
-	{
-		bone_pos.clearVec();
-	}
-	
-	LLQuaternion bone_rot;
-
-	S32 num_children = 0;
-	for (child_list_t::iterator iter = mChildren.begin();
-		 iter != mChildren.end(); ++iter)
-	{
-		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		if (joint->mJointNum != -1)
-		{
-			num_children++;
-		}
-	}
-
-	LLJoint* cur_joint = this;
-	LLVector3 rootSkinOffset;
-	if (mParent)
-	{
-		while (cur_joint)
-		{
-			rootSkinOffset -= cur_joint->getSkinOffset();
-			cur_joint = (LLViewerJoint*)cur_joint->getParent();
-		}
-
-		rootSkinOffset *= 100.f;
-	}
-
-	apr_file_printf(fp, "	<BONE ID=\"%d\" NAME=\"%s\" NUMCHILDS=\"%d\">\n", mJointNum + 1, mName.c_str(), num_children);
-	apr_file_printf(fp, "		<TRANSLATION>%.6f %.6f %.6f</TRANSLATION>\n", bone_pos.mV[VX], bone_pos.mV[VY], bone_pos.mV[VZ]);
-	apr_file_printf(fp, "		<ROTATION>%.6f %.6f %.6f %.6f</ROTATION>\n", bone_rot.mQ[VX], bone_rot.mQ[VY], bone_rot.mQ[VZ], bone_rot.mQ[VW]);
-	apr_file_printf(fp, "		<LOCALTRANSLATION>%.6f %.6f %.6f</LOCALTRANSLATION>\n", rootSkinOffset.mV[VX], rootSkinOffset.mV[VY], rootSkinOffset.mV[VZ]);
-	apr_file_printf(fp, "		<LOCALROTATION>0 0 0 1</LOCALROTATION>\n");
-	apr_file_printf(fp, "		<PARENTID>%d</PARENTID>\n", mParent ? mParent->mJointNum + 1 : -1);
-	
-	for (child_list_t::iterator iter = mChildren.begin();
-		 iter != mChildren.end(); ++iter)
-	{
-		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		if (joint->mJointNum != -1)
-		{
-			apr_file_printf(fp, "		<CHILDID>%d</CHILDID>\n", joint->mJointNum + 1);
-		}
-	}
-	apr_file_printf(fp, "	</BONE>\n");
-
-	// recurse
-	for (child_list_t::iterator iter = mChildren.begin();
-		 iter != mChildren.end(); ++iter)
-	{
-		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		if (joint->mJointNum != -1)
-		{
-			joint->writeCAL3D(fp);
-		}
-	}
-
-}
-
 //-----------------------------------------------------------------------------
 // LLViewerJointCollisionVolume()
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h
index e432258f888..5aa49aee7e8 100644
--- a/indra/newview/llviewerjoint.h
+++ b/indra/newview/llviewerjoint.h
@@ -131,7 +131,6 @@ class LLViewerJoint :
 	virtual void dump();
 
 	void setVisible( BOOL visible, BOOL recursive );
-	virtual void writeCAL3D(apr_file_t* fp);
 
 public:
 	static BOOL	sDisableLOD;
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 18c99f74530..8b653b64300 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -38,9 +38,11 @@
 #include "llviewercontrol.h"
 #include "lldrawable.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "llvoavatar.h"
 #include "llvolume.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llinventorymodel.h"
 #include "llviewerobjectlist.h"
 #include "llface.h"
@@ -56,7 +58,6 @@ extern LLPipeline gPipeline;
 LLViewerJointAttachment::LLViewerJointAttachment() :
 mJoint(NULL),
 mAttachedObject(NULL),
-mAttachmentDirty(FALSE),
 mVisibleInFirst(FALSE),
 mGroup(0),
 mIsHUDAttachment(FALSE),
@@ -90,36 +91,18 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass )
 	{
 		LLGLDisable cull_face(GL_CULL_FACE);
 		
-		glColor4f(1.f, 1.f, 1.f, 1.f);
-		glBegin(GL_QUADS);
+		gGL.color4f(1.f, 1.f, 1.f, 1.f);
+		gGL.begin(GL_QUADS);
 		{
-			glVertex3f(-0.1f, 0.1f, 0.f);
-			glVertex3f(-0.1f, -0.1f, 0.f);
-			glVertex3f(0.1f, -0.1f, 0.f);
-			glVertex3f(0.1f, 0.1f, 0.f);
-		}glEnd();
+			gGL.vertex3f(-0.1f, 0.1f, 0.f);
+			gGL.vertex3f(-0.1f, -0.1f, 0.f);
+			gGL.vertex3f(0.1f, -0.1f, 0.f);
+			gGL.vertex3f(0.1f, 0.1f, 0.f);
+		}gGL.end();
 	}
 	return 0;
 }
 
-//-----------------------------------------------------------------------------
-// lazyAttach()
-//-----------------------------------------------------------------------------
-void LLViewerJointAttachment::lazyAttach()
-{
-	if (!mAttachedObject)
-	{
-		return;
-	}
-	LLDrawable *drawablep = mAttachedObject->mDrawable;
-
-	if (mAttachmentDirty && drawablep)
-	{
-		setupDrawable(drawablep);
-		mAttachmentDirty = FALSE;
-	}
-}
-
 void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep)
 {
 	drawablep->mXform.setParent(&mXform); // LLViewerJointAttachment::lazyAttach
@@ -211,13 +194,14 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
 
 	if (drawablep)
 	{
+		//if object is active, make it static
+		if(drawablep->isActive())
+		{
+			drawablep->makeStatic() ;
+		}
+
 		setupDrawable(drawablep);
 	}
-	else
-	{
-		// do lazy update once we have a drawable for this object
-		mAttachmentDirty = TRUE;
-	}
 
 	if (mIsHUDAttachment)
 	{
@@ -251,6 +235,12 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 
 	if (object->mDrawable.notNull())
 	{
+		//if object is active, make it static
+		if(object->mDrawable->isActive())
+		{
+			object->mDrawable->makeStatic() ;
+		}
+
 		LLVector3 cur_position = object->getRenderPosition();
 		LLQuaternion cur_rotation = object->getRenderRotation();
 
diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h
index a834e68986b..aa41252ab9d 100644
--- a/indra/newview/llviewerjointattachment.h
+++ b/indra/newview/llviewerjointattachment.h
@@ -82,7 +82,6 @@ class LLViewerJointAttachment :
 
 	S32 getGroup() { return mGroup; }
 	S32 getPieSlice() { return mPieSlice; }
-	BOOL getAttachmentDirty() { return mAttachmentDirty && mAttachedObject; }
 	LLViewerObject *getObject() { return mAttachedObject; }
 	S32	getNumObjects() { return (mAttachedObject ? 1 : 0); }
 	const LLUUID& getItemID() { return mItemID; }
@@ -93,7 +92,6 @@ class LLViewerJointAttachment :
 	BOOL addObject(LLViewerObject* object);
 	void removeObject(LLViewerObject *object);
 
-	void lazyAttach();
 	void setupDrawable(LLDrawable* drawable);
 	void clampObjectPosition();
 
@@ -104,7 +102,6 @@ class LLViewerJointAttachment :
 	LLJoint*		mJoint;
 	// Backlink only; don't make this an LLPointer.
 	LLViewerObject*	mAttachedObject;
-	BOOL			mAttachmentDirty;	// does attachment drawable need to be fixed up?
 	BOOL			mVisibleInFirst;
 	LLVector3		mOriginalPos;
 	S32				mGroup;
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index dfd9ec1d126..2677b33af84 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -192,48 +192,6 @@ BOOL LLViewerJointMesh::allocateSkinData( U32 numSkinJoints )
 	return TRUE;
 }
 
-//-----------------------------------------------------------------------------
-// getSkinJointByIndex()
-//-----------------------------------------------------------------------------
-S32 LLViewerJointMesh::getBoundJointsByIndex(S32 index, S32 &joint_a, S32& joint_b)
-{
-	S32 num_joints = 0;
-	if (mNumSkinJoints == 0)
-	{
-		return num_joints;
-	}
-
-	joint_a = -1;
-	joint_b = -1;
-
-	LLPolyMesh *reference_mesh = mMesh->getReferenceMesh();
-
-	if (index < reference_mesh->mJointRenderData.count())
-	{
-		LLJointRenderData* render_datap = reference_mesh->mJointRenderData[index];
-		if (render_datap->mSkinJoint)
-		{
-			joint_a = render_datap->mSkinJoint->mJoint->mJointNum;
-		}
-		num_joints++;
-	}
-	if (index + 1 < reference_mesh->mJointRenderData.count())
-	{
-		LLJointRenderData* render_datap = reference_mesh->mJointRenderData[index + 1];
-		if (render_datap->mSkinJoint)
-		{
-			joint_b = render_datap->mSkinJoint->mJoint->mJointNum;
-
-			if (joint_a == -1)
-			{
-				joint_a = render_datap->mSkinJoint->mJoint->getParent()->mJointNum;
-			}
-		}
-		num_joints++;
-	}
-	return num_joints;
-}
-
 //-----------------------------------------------------------------------------
 // LLViewerJointMesh::freeSkinData()
 //-----------------------------------------------------------------------------
@@ -554,6 +512,8 @@ void llDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, G
 	{
 		glDrawRangeElements(mode,start,end,count,type,indices);
 	}
+
+	gPipeline.addTrianglesDrawn(count/3);
 }
 
 //--------------------------------------------------------------------
@@ -577,32 +537,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 	//----------------------------------------------------------------
 	if (!gRenderForSelect)
 	{
-		if ((mFace->getPool()->getVertexShaderLevel() > 0))
-		{
-			glColor4f(0,0,0,1);
-			
-			if (gMaterialIndex > 0)
-			{
-				glVertexAttrib4fvARB(gMaterialIndex, mColor.mV);
-			}
-			
-			if (mShiny && gSpecularIndex > 0)
-			{
-				glVertexAttrib4fARB(gSpecularIndex, 1,1,1,1);
-			}
-		}
-		else
-		{
-			glColor4fv(mColor.mV);
-		}
+		glColor4fv(mColor.mV);
 	}
 
 	stop_glerror();
 	
 	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), gRenderForSelect ? 0.0f : mShiny && !(mFace->getPool()->getVertexShaderLevel() > 0));
 
-	LLGLEnable texture_2d((gRenderForSelect && isTransparent()) ? GL_TEXTURE_2D : 0);
-	
 	//----------------------------------------------------------------
 	// setup current texture
 	//----------------------------------------------------------------
@@ -660,8 +601,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 		gImageList.getImage(IMG_DEFAULT_AVATAR)->bind();
 	}
 	
-	LLGLDisable tex(gRenderForSelect && !isTransparent() ? GL_TEXTURE_2D : 0);
-
 	if (gRenderForSelect)
 	{
 		if (isTransparent())
@@ -676,92 +615,18 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_TEXTURE);  // GL_TEXTURE_ENV_COLOR is set in renderPass1
 			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
 		}
-	}
-	else
-	{
-		//----------------------------------------------------------------
-		// by default, backface culling is enabled
-		//----------------------------------------------------------------
-		/*if (sRenderPass == AVATAR_RENDER_PASS_CLOTHING_INNER)
+		else
 		{
-			LLImageGL::bindExternalTexture( sClothingMaskImageName, 1, GL_TEXTURE_2D );
-
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-			glActiveTextureARB(GL_TEXTURE0_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_MODULATE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_REPLACE);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB,		GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB,		GL_SRC_COLOR);
-
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glEnable(GL_TEXTURE_2D); // Texture unit 1
-			glActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
-			glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,	sClothingInnerColor.mV);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_INTERPOLATE_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_REPLACE);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_PREVIOUS_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_CONSTANT_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB,		GL_PREVIOUS_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB,		GL_SRC_COLOR);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB,		GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB,		GL_SRC_ALPHA);
+			LLImageGL::unbindTexture(0);
 		}
-		else if (sRenderPass == AVATAR_RENDER_PASS_CLOTHING_OUTER)
-		{
-			glAlphaFunc(GL_GREATER, 0.1f);
-			LLImageGL::bindExternalTexture( sClothingMaskImageName, 1, GL_TEXTURE_2D );
-
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-			glActiveTextureARB(GL_TEXTURE0_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_MODULATE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_REPLACE);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB,		GL_PRIMARY_COLOR_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB,		GL_SRC_COLOR);
-
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glEnable(GL_TEXTURE_2D); // Texture unit 1
-			glActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,		GL_COMBINE_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_REPLACE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,		GL_MODULATE);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,		GL_PREVIOUS_ARB);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,		GL_SRC_COLOR);
-
-			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,		GL_TEXTURE);
-			glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB,	GL_SRC_ALPHA);
-		}*/
 	}
-
+	
 	mFace->mVertexBuffer->setBuffer(sRenderMask);
 
 	U32 start = mMesh->mFaceVertexOffset;
 	U32 end = start + mMesh->mFaceVertexCount - 1;
 	U32 count = mMesh->mFaceIndexCount;
-	U32* indicesp = ((U32*) mFace->mVertexBuffer->getIndicesPointer()) + mMesh->mFaceIndexOffset;
+	U16* indicesp = ((U16*) mFace->mVertexBuffer->getIndicesPointer()) + mMesh->mFaceIndexOffset;
 
 	if (mMesh->hasWeights())
 	{
@@ -771,11 +636,11 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 			{
 				uploadJointMatrices();
 			}
-			llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp);
+			llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, indicesp);
 		}
 		else
 		{
-			llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp);
+			llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, indicesp);
 		}
 	}
 	else
@@ -783,7 +648,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 		glPushMatrix();
 		LLMatrix4 jointToWorld = getWorldMatrix();
 		glMultMatrixf((GLfloat*)jointToWorld.mMatrix);
-		llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_INT, indicesp);
+		llDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, indicesp);
 		glPopMatrix();
 	}
 
@@ -794,21 +659,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	}
 
-	/*if (sRenderPass != AVATAR_RENDER_PASS_SINGLE)
-	{
-		LLImageGL::unbindTexture(1, GL_TEXTURE_2D);
-		glActiveTextureARB(GL_TEXTURE1_ARB);
-		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_MODULATE);
-
-		// Return to the default texture.
-		LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
-		glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		glActiveTextureARB(GL_TEXTURE0_ARB);
-
-		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,		GL_MODULATE);
-		glAlphaFunc(GL_GREATER, 0.01f);
-	}*/
-
 	if (mTexture.notNull()) {
 		if (!mTexture->getClampS()) {
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -846,37 +696,36 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32
 //-----------------------------------------------------------------------------
 void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind)
 {
-	U32 i;
-	
 	mFace = face;
 
+	if (mFace->mVertexBuffer.isNull())
+	{
+		return;
+	}
+
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
-	LLStrider<LLVector3> binormalsp;
 	LLStrider<LLVector2> tex_coordsp;
 	LLStrider<F32>		 vertex_weightsp;
 	LLStrider<LLVector4> clothing_weightsp;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 
 	// Copy data into the faces from the polymesh data.
 	if (mMesh && mValid)
 	{
 		if (mMesh->getNumVertices())
 		{
-			S32 index = face->getGeometryAvatar(verticesp, normalsp, binormalsp, tex_coordsp, vertex_weightsp, clothing_weightsp);
+			stop_glerror();
+			face->getGeometryAvatar(verticesp, normalsp, tex_coordsp, vertex_weightsp, clothing_weightsp);
+			stop_glerror();
 			face->mVertexBuffer->getIndexStrider(indicesp);
+			stop_glerror();
 
-			if (-1 == index)
-			{
-				return;
-			}
-
-			for (i = 0; i < mMesh->getNumVertices(); i++)
+			for (U16 i = 0; i < mMesh->getNumVertices(); i++)
 			{
 				verticesp[mMesh->mFaceVertexOffset + i] = *(mMesh->getCoords() + i);
 				tex_coordsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getTexCoords() + i);
 				normalsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getNormals() + i);
-				binormalsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getBinormals() + i);
 				vertex_weightsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getWeights() + i);
 				if (damp_wind)
 				{
@@ -1001,6 +850,8 @@ void LLViewerJointMesh::updateGeometryOriginal(LLFace *mFace, LLPolyMesh *mMesh)
 		
 		o_normals[bidx] = normals[index] * gBlendRotMat;
 	}
+
+	buffer->setBuffer(0);
 }
 
 const U32 UPDATE_GEOMETRY_CALL_MASK			= 0x1FFF; // 8K samples before overflow
@@ -1166,99 +1017,4 @@ void LLViewerJointMesh::dump()
 	}
 }
 
-void LLViewerJointMesh::writeCAL3D(apr_file_t* fp, S32 material_num, LLCharacter* characterp)
-{
-	apr_file_printf(fp, "\t<SUBMESH NUMVERTICES=\"%d\" NUMFACES=\"%d\" MATERIAL=\"%d\" NUMLODSTEPS=\"0\" NUMSPRINGS=\"0\" NUMTEXCOORDS=\"1\">\n", mMesh->getNumVertices(), mMesh->getNumFaces(), material_num);
-
-	const LLVector3* mesh_coords = mMesh->getCoords();
-	const LLVector3* mesh_normals = mMesh->getNormals();
-	const LLVector2* mesh_uvs = mMesh->getTexCoords();
-	const F32* mesh_weights = mMesh->getWeights();
-	LLVector3 mesh_offset;
-	LLVector3 scale(1.f, 1.f, 1.f);
-	S32 joint_a = -1;
-	S32 joint_b = -1;
-	S32 num_bound_joints = 0;
-	
-	if(!mMesh->hasWeights())
-	{
-		num_bound_joints = 1;
-		LLJoint* cur_joint = this;
-		while(cur_joint)
-		{
-			if (cur_joint->mJointNum != -1 && joint_a == -1)
-			{
-				joint_a = cur_joint->mJointNum;
-			}
-			mesh_offset += cur_joint->getSkinOffset();
-			cur_joint = cur_joint->getParent();
-		}
-	}
-
-	for (S32 i = 0; i < (S32)mMesh->getNumVertices(); i++)
-	{
-		LLVector3 coord = mesh_coords[i];
-
-		if (mMesh->hasWeights())
-		{
-			// calculate joint to which this skinned vertex is bound
-			num_bound_joints = getBoundJointsByIndex(llfloor(mesh_weights[i]), joint_a, joint_b);
-			LLJoint* first_joint = characterp->getCharacterJoint(joint_a);
-			LLJoint* second_joint = characterp->getCharacterJoint(joint_b);
-
-			LLVector3 first_joint_offset;
-			LLJoint* cur_joint = first_joint;
-			while(cur_joint)
-			{
-				first_joint_offset += cur_joint->getSkinOffset();
-				cur_joint = cur_joint->getParent();
-			}
-
-			LLVector3 second_joint_offset;
-			cur_joint = second_joint;
-			while(cur_joint)
-			{
-				second_joint_offset += cur_joint->getSkinOffset();
-				cur_joint = cur_joint->getParent();
-			}
-
-			LLVector3 first_coord = coord - first_joint_offset;
-			first_coord.scaleVec(first_joint->getScale());
-			LLVector3 second_coord = coord - second_joint_offset;
-			if (second_joint)
-			{
-				second_coord.scaleVec(second_joint->getScale());
-			}
-			
-			coord = lerp(first_joint_offset + first_coord, second_joint_offset + second_coord, fmodf(mesh_weights[i], 1.f));
-		}
-
-		// add offset to move rigid mesh to target location
-		coord += mesh_offset;
-		coord *= 100.f;
-
-		apr_file_printf(fp, "		<VERTEX ID=\"%d\" NUMINFLUENCES=\"%d\">\n", i, num_bound_joints);
-		apr_file_printf(fp, "			<POS>%.4f %.4f %.4f</POS>\n", coord.mV[VX], coord.mV[VY], coord.mV[VZ]);
-		apr_file_printf(fp, "			<NORM>%.6f %.6f %.6f</NORM>\n", mesh_normals[i].mV[VX], mesh_normals[i].mV[VY], mesh_normals[i].mV[VZ]);
-		apr_file_printf(fp, "			<TEXCOORD>%.6f %.6f</TEXCOORD>\n", mesh_uvs[i].mV[VX], 1.f - mesh_uvs[i].mV[VY]);
-		if (num_bound_joints >= 1)
-		{
-			apr_file_printf(fp, "			<INFLUENCE ID=\"%d\">%.2f</INFLUENCE>\n", joint_a + 1, 1.f - fmod(mesh_weights[i], 1.f));
-		}
-		if (num_bound_joints == 2)
-		{
-			apr_file_printf(fp, "			<INFLUENCE ID=\"%d\">%.2f</INFLUENCE>\n", joint_b + 1, fmod(mesh_weights[i], 1.f));
-		}
-		apr_file_printf(fp, "		</VERTEX>\n");
-	}
-
-	LLPolyFace* mesh_faces = mMesh->getFaces();
-	for (S32 i = 0; i < mMesh->getNumFaces(); i++)
-	{
-		apr_file_printf(fp, "		<FACE VERTEXID=\"%d %d %d\" />\n", mesh_faces[i][0], mesh_faces[i][1], mesh_faces[i][2]);
-	}
-	
-	apr_file_printf(fp, "	</SUBMESH>\n");
-}
-
 // End
diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h
index 8a3cc1ae289..8e1ee514ff0 100644
--- a/indra/newview/llviewerjointmesh.h
+++ b/indra/newview/llviewerjointmesh.h
@@ -148,8 +148,7 @@ class LLViewerJointMesh : public LLViewerJoint
 	void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; }
 
 	/*virtual*/ BOOL isAnimatable() { return FALSE; }
-	void writeCAL3D(apr_file_t* fp, S32 material_num, LLCharacter* characterp);
-
+	
 	// Avatar vertex skinning is a significant performance issue on computers
 	// with avatar vertex programs turned off (for example, most Macs).  We
 	// therefore have custom versions that use SIMD instructions.
@@ -169,8 +168,6 @@ class LLViewerJointMesh : public LLViewerJoint
 	// Allocate skin data
 	BOOL allocateSkinData( U32 numSkinJoints );
 
-	S32 getBoundJointsByIndex(S32 index, S32 &joint_a, S32& joint_b);
-
 	// Free skin data
 	void freeSkinData();
 };
diff --git a/indra/newview/llviewerjointmesh_sse.cpp b/indra/newview/llviewerjointmesh_sse.cpp
index 7a0d4756cac..d3083fc1c7f 100644
--- a/indra/newview/llviewerjointmesh_sse.cpp
+++ b/indra/newview/llviewerjointmesh_sse.cpp
@@ -105,6 +105,8 @@ void LLViewerJointMesh::updateGeometrySSE(LLFace *face, LLPolyMesh *mesh)
 		blend_mat.multiply(coords[index], o_vertices[index]);
 		((LLV4Matrix3)blend_mat).multiply(normals[index], o_normals[index]);
 	}
+
+	buffer->setBuffer(0);
 }
 
 #else
diff --git a/indra/newview/llviewerjointmesh_sse2.cpp b/indra/newview/llviewerjointmesh_sse2.cpp
index 129f06c40a1..8e890637c17 100644
--- a/indra/newview/llviewerjointmesh_sse2.cpp
+++ b/indra/newview/llviewerjointmesh_sse2.cpp
@@ -112,6 +112,8 @@ void LLViewerJointMesh::updateGeometrySSE2(LLFace *face, LLPolyMesh *mesh)
 		blend_mat.multiply(coords[index], o_vertices[index]);
 		((LLV4Matrix3)blend_mat).multiply(normals[index], o_normals[index]);
 	}
+	
+	//setBuffer(0) called in LLVOAvatar::renderSkinned
 }
 
 #else
diff --git a/indra/newview/llviewerjointmesh_vec.cpp b/indra/newview/llviewerjointmesh_vec.cpp
index c7be7ce0921..ad0e15a42a8 100644
--- a/indra/newview/llviewerjointmesh_vec.cpp
+++ b/indra/newview/llviewerjointmesh_vec.cpp
@@ -95,4 +95,6 @@ void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh)
 		blend_mat.multiply(coords[index], o_vertices[index]);
 		((LLV4Matrix3)blend_mat).multiply(normals[index], o_normals[index]);
 	}
+
+	buffer->setBuffer(0);
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index fc9b765525a..546c52a070c 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -94,6 +94,7 @@
 #include "llfloaterbuyland.h"
 #include "llfloaterchat.h"
 #include "llfloatercustomize.h"
+#include "llfloaterdaycycle.h"
 #include "llfloaterdirectory.h"
 #include "llfloatereditui.h"
 #include "llfloaterchatterbox.h"
@@ -113,12 +114,16 @@
 #include "llfloatermute.h"
 #include "llfloateropenobject.h"
 #include "llfloaterpermissionsmgr.h"
+#include "llfloaterpostprocess.h"
 #include "llfloaterpreference.h"
 #include "llfloaterregioninfo.h"
 #include "llfloaterreporter.h"
 #include "llfloaterscriptdebug.h"
+#include "llfloaterenvsettings.h"
 #include "llfloatertest.h"
 #include "llfloatertools.h"
+#include "llfloaterwater.h"
+#include "llfloaterwindlight.h"
 #include "llfloaterworldmap.h"
 #include "llframestats.h"
 #include "llframestatview.h"
@@ -193,6 +198,9 @@
 #include "llappviewer.h"
 #include "roles_constants.h"
 #include "llviewerjoystick.h"
+#include "llwlanimator.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
 
 #include "lltexlayer.h"
 
@@ -1112,12 +1120,14 @@ void init_client_menu(LLMenuGL* menu)
 
 void init_debug_world_menu(LLMenuGL* menu)
 {
+/* REMOVE mouse move sun from menu options
 	menu->append(new LLMenuItemCheckGL("Mouse Moves Sun", 
 									   &menu_toggle_control,
 									   NULL, 
 									   &menu_check_control,
 									   (void*)"MouseSun", 
 									   'M', MASK_CONTROL|MASK_ALT));
+*/
 	menu->append(new LLMenuItemCheckGL("Sim Sun Override", 
 									   &menu_toggle_control,
 									   NULL, 
@@ -1186,6 +1196,7 @@ void init_debug_ui_menu(LLMenuGL* menu)
 	menu->appendSeparator();
 	menu->append(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime"));
 	menu->append(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo"));
+	menu->append(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor"));
 	
 	menu->createJumpKeys();
 }
@@ -1329,6 +1340,9 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	sub_menu->append(new LLMenuItemCheckGL("Occlusion",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_OCCLUSION));
+	sub_menu->append(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL,
+													&LLPipeline::toggleRenderDebugControl,
+													(void*)LLPipeline::RENDER_DEBUG_BATCH_SIZE));
 	sub_menu->append(new LLMenuItemCheckGL("Animated Textures",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_TEXTURE_ANIM));
@@ -1344,18 +1358,15 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	sub_menu->append(new LLMenuItemCheckGL("Pick Render",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_PICKING));
+	sub_menu->append(new LLMenuItemCheckGL("Lights",	&LLPipeline::toggleRenderDebug, NULL,
+													&LLPipeline::toggleRenderDebugControl,
+													(void*)LLPipeline::RENDER_DEBUG_LIGHTS));
 	sub_menu->append(new LLMenuItemCheckGL("Particles",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_PARTICLES));
 	sub_menu->append(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_COMPOSITION));
-	sub_menu->append(new LLMenuItemCheckGL("ShadowMap", &LLPipeline::toggleRenderDebug, NULL,
-													&LLPipeline::toggleRenderDebugControl,
-													(void*)LLPipeline::RENDER_DEBUG_SHADOW_MAP));
-	sub_menu->append(new LLMenuItemCheckGL("LightTrace",&LLPipeline::toggleRenderDebug, NULL,
-													&LLPipeline::toggleRenderDebugControl,
-													(void*)LLPipeline::RENDER_DEBUG_LIGHT_TRACE));
 	sub_menu->append(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_GLOW));
@@ -1380,6 +1391,9 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	sub_menu->append(new LLMenuItemToggleGL("Randomize Framerate", &gRandomizeFramerate));
 
 	sub_menu->append(new LLMenuItemToggleGL("Periodic Slow Frame", &gPeriodicSlowFrame));
+
+	sub_menu->append(new LLMenuItemToggleGL("Frame Test", &LLPipeline::sRenderFrameTest));
+
 	sub_menu->createJumpKeys();
 
 	menu->appendMenu( sub_menu );
@@ -1403,6 +1417,8 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	item->setEnabled(gGLManager.mHasOcclusionQuery && gFeatureManagerp->isFeatureAvailable("UseOcclusion"));
 	menu->append(item);
 	
+	item = new LLMenuItemCheckGL("Fast Alpha", menu_toggle_control, NULL, menu_check_control, (void*)"RenderFastAlpha");
+	menu->append(item);
 	
 	item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures");
 	menu->append(item);
@@ -5203,40 +5219,6 @@ void handle_force_unlock(void*)
 	gSelectMgr->getSelection()->applyToObjects(&func);
 }
 
-class LLWorldForceSun : public view_listener_t
-{
-	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
-	{
-		LLString tod = userdata.asString();
-		LLVector3 sun_direction;
-		if (tod == "sunrise")
-		{
-			sun_direction.setVec(1.0f, 0.f, 0.2f);
-		}
-		else if (tod == "noon")
-		{
-			sun_direction.setVec(0.0f, 0.3f, 1.0f);
-		}
-		else if (tod == "sunset")
-		{
-			sun_direction.setVec(-1.0f, 0.f, 0.2f);
-		}
-		else if (tod == "midnight")
-		{
-			sun_direction.setVec(0.0f, 0.3f, -1.0f);
-		}
-		else
-		{
-			gSky.setOverrideSun(FALSE);
-			return true;
-		}
-		sun_direction.normVec();
-		gSky.setOverrideSun(TRUE);
-		gSky.setSunDirection( sun_direction, LLVector3(0.f, 0.f, 0.f));
-		return true;
-	}
-};
-
 void handle_dump_followcam(void*)
 {
 	LLFollowCamMgr::dump();
@@ -7225,6 +7207,33 @@ class LLViewCheckHighlightTransparent : public view_listener_t
 	}
 };
 
+class LLViewBeaconWidth : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		LLString width = userdata.asString();
+		if(width == "1")
+		{
+			gSavedSettings.setS32("DebugBeaconLineWidth", 1);
+		}
+		else if(width == "4")
+		{
+			gSavedSettings.setS32("DebugBeaconLineWidth", 4);
+		}
+		else if(width == "16")
+		{
+			gSavedSettings.setS32("DebugBeaconLineWidth", 16);
+		}
+		else if(width == "32")
+		{
+			gSavedSettings.setS32("DebugBeaconLineWidth", 32);
+		}
+
+		return true;
+	}
+};
+
+
 class LLViewToggleBeacon : public view_listener_t
 {
 	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -7531,6 +7540,125 @@ class LLToolsSelectTool : public view_listener_t
 	}
 };
 
+/// WINDLIGHT callbacks
+class LLWorldEnvSettings : public view_listener_t
+{	
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		LLString tod = userdata.asString();
+		LLVector3 sun_direction;
+		
+		if (tod == "editor")
+		{
+			// if not there or is hidden, show it
+			if(	!LLFloaterEnvSettings::isOpen() || 
+				!LLFloaterEnvSettings::instance()->getVisible()) {
+				LLFloaterEnvSettings::show();
+				
+			// otherwise, close it button acts like a toggle
+			} 
+			else 
+			{
+				LLFloaterEnvSettings::instance()->close();
+			}
+			return true;
+		}
+		
+		if (tod == "sunrise")
+		{
+			// set the value, turn off animation
+			LLWLParamManager::instance()->mAnimator.setDayTime(0.25);
+			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+			// then call update once
+			LLWLParamManager::instance()->mAnimator.update(
+				LLWLParamManager::instance()->mCurParams);
+		}
+		else if (tod == "noon")
+		{
+			// set the value, turn off animation
+			LLWLParamManager::instance()->mAnimator.setDayTime(0.567);
+			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+			// then call update once
+			LLWLParamManager::instance()->mAnimator.update(
+				LLWLParamManager::instance()->mCurParams);
+		}
+		else if (tod == "sunset")
+		{
+			// set the value, turn off animation
+			LLWLParamManager::instance()->mAnimator.setDayTime(0.75);
+			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+			// then call update once
+			LLWLParamManager::instance()->mAnimator.update(
+				LLWLParamManager::instance()->mCurParams);
+		}
+		else if (tod == "midnight")
+		{
+			// set the value, turn off animation
+			LLWLParamManager::instance()->mAnimator.setDayTime(0.0);
+			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+			// then call update once
+			LLWLParamManager::instance()->mAnimator.update(
+				LLWLParamManager::instance()->mCurParams);
+		}
+		else
+		{
+			LLWLParamManager::instance()->mAnimator.mIsRunning = true;
+			LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;	
+		}
+		return true;
+	}
+};
+
+/// Water Menu callbacks
+class LLWorldWaterSettings : public view_listener_t
+{	
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		// if not there or is hidden, show it
+		if(	!LLFloaterWater::isOpen() || 
+			!LLFloaterWater::instance()->getVisible()) {
+			LLFloaterWater::show();
+				
+		// otherwise, close it button acts like a toggle
+		} 
+		else 
+		{
+			LLFloaterWater::instance()->close();
+		}
+		return true;
+	}
+};
+
+/// Post-Process callbacks
+class LLWorldPostProcess : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		LLFloaterPostProcess::show();
+		return true;
+	}
+};
+
+/// Day Cycle callbacks
+class LLWorldDayCycle : public view_listener_t
+{
+	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
+	{
+		LLFloaterDayCycle::show();
+		return true;
+	}
+};
+
+
+
 static void addMenu(view_listener_t *menu, const char *name)
 {
 	sMenus.push_back(menu);
@@ -7575,6 +7703,7 @@ void initialize_menus()
 	addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips");
 	addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent");
 	addMenu(new LLViewToggleBeacon(), "View.ToggleBeacon");
+	addMenu(new LLViewBeaconWidth(), "View.BeaconWidth");
 	addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType");
 	addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments");
 	addMenu(new LLViewZoomOut(), "View.ZoomOut");
@@ -7610,8 +7739,11 @@ void initialize_menus()
 	addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand");
 
 	addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun");
-
-	addMenu(new LLWorldForceSun(), "World.ForceSun");
+	
+	(new LLWorldEnvSettings())->registerListener(gMenuHolder, "World.EnvSettings");
+	(new LLWorldWaterSettings())->registerListener(gMenuHolder, "World.WaterSettings");
+	(new LLWorldPostProcess())->registerListener(gMenuHolder, "World.PostProcess");
+	(new LLWorldDayCycle())->registerListener(gMenuHolder, "World.DayCycle");
 
 	// Tools menu
 	addMenu(new LLToolsSelectTool(), "Tools.SelectTool");
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 291e3da13df..8a7f7e047f3 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -39,7 +39,6 @@
 #include "llfloateranimpreview.h"
 #include "llfloaterbuycurrency.h"
 #include "llfloaterimagepreview.h"
-#include "llfloaterimport.h"
 #include "llfloaternamedesc.h"
 #include "llfloatersnapshot.h"
 #include "llinventorymodel.h"	// gInventory
@@ -53,6 +52,7 @@
 #include "llviewerstats.h"
 #include "llviewerwindow.h"
 #include "llappviewer.h"
+#include "lluploaddialog.h"
 
 
 // linden libraries
@@ -210,18 +210,6 @@ const char* upload_pick(void* data)
 	return filename;
 }
 
-/*
-void handle_upload_object(void* data)
-{
-	const char* filename = upload_pick(data);
-	if (filename)
-	{
-		// start the import
-		LLFloaterImport* floaterp = new LLFloaterImport(filename);
-		gUICtrlFactory->buildFloater(floaterp, "floater_import.xml");
-	}
-}*/
-
 class LLFileUploadImage : public view_listener_t
 {
 	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -410,6 +398,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
 									   width,
 									   height,
 									   TRUE,
+									   FALSE,
 									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
 									   FALSE))
 		{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index cf71694e13a..8aa2b8224a1 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -47,7 +47,6 @@
 #include "lldbstrings.h"
 #include "lleconomy.h"
 #include "llfilepicker.h"
-#include "llfloaterimport.h"
 #include "llfocusmgr.h"
 #include "llfollowcamparams.h"
 #include "llfloaterreleasemsg.h"
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 3a0daba8aab..602b60bc9d4 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -86,7 +86,6 @@
 #include "llvolumemessage.h"
 #include "llvopartgroup.h"
 #include "llvosky.h"
-#include "llvostars.h"
 #include "llvosurfacepatch.h"
 #include "llvotextbubble.h"
 #include "llvotree.h"
@@ -96,6 +95,7 @@
 #include "llui.h"
 #include "pipeline.h"
 #include "llappviewer.h"
+#include "llvowlsky.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -143,14 +143,14 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
 	  res = new LLVOSurfacePatch(id, pcode, regionp); break;
 	case LL_VO_SKY:
 	  res = new LLVOSky(id, pcode, regionp); break;
-	case LL_VO_STARS:
-	  res = new LLVOStars(id, pcode, regionp); break;
 	case LL_VO_WATER:
 	  res = new LLVOWater(id, pcode, regionp); break;
 	case LL_VO_GROUND:
 	  res = new LLVOGround(id, pcode, regionp); break;
 	case LL_VO_PART_GROUP:
 	  res = new LLVOPartGroup(id, pcode, regionp); break;
+	case LL_VO_WL_SKY:
+	  res = new LLVOWLSky(id, pcode, regionp); break;
 	default:
 	  llwarns << "Unknown object pcode " << (S32)pcode << llendl;
 	  res = NULL; break;
@@ -193,7 +193,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mOnMap(FALSE),
 	mStatic(FALSE),
 	mNumFaces(0),
-	mLastUpdateFrame(0),
 	mTimeDilation(1.f),
 	mRotTime(0.f),
 	mJointInfo(NULL),
@@ -631,17 +630,19 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp)
 	
 	BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
-	if (old_parent || (parentp && parentp->isActive()))
+	if(	old_parent != parentp &&
+		old_parent || (parentp && parentp->isActive()))
 	{
+		// *TODO we should not be relying on setDrawable parent to call markMoved
 		gPipeline.markMoved(mDrawable, FALSE);
 	}
-	else
+	else if (!mDrawable->isAvatar())
 	{
 		mDrawable->updateXform(TRUE);
-		if (!mDrawable->getSpatialGroup())
+		/*if (!mDrawable->getSpatialGroup())
 		{
 			mDrawable->movePartition();
-		}
+		}*/
 	}
 	
 	return ret;
@@ -677,7 +678,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					 LLDataPacker *dp)
 {
 	LLMemType mt(LLMemType::MTYPE_OBJECT);
-	
 	U32 retval = 0x0;
 	
 	// Coordinates of objects on simulators are region-local.
@@ -3063,6 +3063,11 @@ const LLVector3 &LLViewerObject::getPositionRegion() const
 		LLViewerObject *parent = (LLViewerObject *)getParent();
 		mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation());
 	}
+	else
+	{
+		mPositionRegion = getPosition();
+	}
+
 	return mPositionRegion;
 }
 
@@ -3088,18 +3093,6 @@ const LLVector3 LLViewerObject::getRenderPosition() const
 	}
 	else
 	{
-		if (isAvatar())
-		{
-			if (isRoot())
-			{
-				return mDrawable->getPositionAgent();
-			}
-			else
-			{
-				return getPosition() * mDrawable->getParent()->getRenderMatrix();
-			}
-		}
-
 		return mDrawable->getPositionAgent();
 	}
 }
@@ -3771,6 +3764,26 @@ S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags)
 	return retval;
 }
 
+S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow)
+{
+	S32 retval = 0;
+	const LLTextureEntry *tep = getTE(te);
+	if (!tep)
+	{
+		llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
+	}
+	else if (glow != tep->getGlow())
+	{
+		retval = LLPrimitive::setTEGlow(te, glow);
+		setChanged(TEXTURE);
+		if (mDrawable.notNull() && retval)
+		{
+			gPipeline.markTextured(mDrawable);
+		}
+	}
+	return retval;
+}
+
 
 S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t)
 {
@@ -4166,10 +4179,8 @@ void LLViewerObject::updateDrawable(BOOL force_damped)
 {
 	if (mDrawable.notNull() && 
 		!mDrawable->isState(LLDrawable::ON_MOVE_LIST) &&
-		isChanged(MOVED) && 
-		!isAvatar())
+		isChanged(MOVED))
 	{
-		mLastUpdateFrame = LLFrameTimer::getFrameCount();
 		BOOL damped_motion = 
 			!isChanged(SHIFTED) &&										// not shifted between regions this frame and...
 				(force_damped ||										// ...forced into damped motion by application logic or...
@@ -4826,12 +4837,31 @@ void LLViewerObject::resetRot()
 
 U32 LLViewerObject::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_NONE; 
+	return LLViewerRegion::PARTITION_NONE; 
 }
 
-BOOL LLAlphaObject::isParticle()
+void LLViewerObject::dirtySpatialGroup() const
 {
-	return FALSE;
+	if (mDrawable)
+	{
+		LLSpatialGroup* group = mDrawable->getSpatialGroup();
+		if (group)
+		{
+			group->dirtyGeom();
+		}
+	}
+}
+
+void LLViewerObject::dirtyMesh() const
+{
+	if (mDrawable)
+	{
+		LLSpatialGroup* group = mDrawable->getSpatialGroup();
+		if (group)
+		{
+			group->dirtyMesh();
+		}
+	}
 }
 
 F32 LLAlphaObject::getPartSize(S32 idx)
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 42124610eb9..c11c3c891e8 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -194,7 +194,6 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	virtual void		updateFaceSize(S32 idx);
 	virtual BOOL		updateLOD();
 	virtual BOOL		setDrawableParent(LLDrawable* parentp);
-	virtual BOOL		updateLighting(BOOL do_lighting) { return TRUE; };
 	F32					getRotTime() { return mRotTime; }
 	void				resetRot();
 	void				applyAngularVelocity(F32 dt);
@@ -248,11 +247,11 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	//closest to start.
 	virtual BOOL lineSegmentIntersect(const LLVector3& start, LLVector3& end) const;
 	
-	const LLVector3d getPositionGlobal() const;
-	const LLVector3 &getPositionRegion() const;
-	const LLVector3 getPositionEdit() const;
-	const LLVector3 &getPositionAgent() const;
-	const LLVector3 getRenderPosition() const;
+	virtual const LLVector3d getPositionGlobal() const;
+	virtual const LLVector3 &getPositionRegion() const;
+	virtual const LLVector3 getPositionEdit() const;
+	virtual const LLVector3 &getPositionAgent() const;
+	virtual const LLVector3 getRenderPosition() const;
 
 	virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not
 
@@ -295,6 +294,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	/*virtual*/	S32		setTEShiny(const U8 te, const U8 shiny );
 	/*virtual*/	S32		setTEFullbright(const U8 te, const U8 fullbright );
 	/*virtual*/	S32		setTEMediaFlags(const U8 te, const U8 media_flags );
+	/*virtual*/ S32     setTEGlow(const U8 te, const F32 glow);
 	/*virtual*/	BOOL	setMaterial(const U8 material);
 	virtual		void	setTEImage(const U8 te, LLViewerImage *imagep); // Not derived from LLPrimitive
 	LLViewerImage		*getTEImage(const U8 te) const;
@@ -323,6 +323,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 
 	 // Create if necessary
 	LLAudioSource *getAudioSource(const LLUUID& owner_id);
+	bool isAudioSource() {return mAudioSourcep != NULL;}
 
 	U8 getMediaType() const;
 	void setMediaType(U8 media_type);
@@ -452,6 +453,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 
 	virtual S32 getLOD() const { return 3; } 
 	virtual U32 getPartitionType() const;
+	virtual void dirtySpatialGroup() const;
+	virtual void dirtyMesh() const;
 
 	virtual LLNetworkData* getParameterEntry(U16 param_type) const;
 	virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin);
@@ -478,13 +481,14 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	{
 		LL_VO_CLOUDS =				LL_PCODE_APP | 0x20,
 		LL_VO_SURFACE_PATCH =		LL_PCODE_APP | 0x30,
-		LL_VO_STARS =				LL_PCODE_APP | 0x40,
+		//LL_VO_STARS =				LL_PCODE_APP | 0x40,
 		LL_VO_SQUARE_TORUS =		LL_PCODE_APP | 0x50,
 		LL_VO_SKY =					LL_PCODE_APP | 0x60,
 		LL_VO_WATER =				LL_PCODE_APP | 0x70,
 		LL_VO_GROUND =				LL_PCODE_APP | 0x80,
 		LL_VO_PART_GROUP =			LL_PCODE_APP | 0x90,
 		LL_VO_TRIANGLE_TORUS =		LL_PCODE_APP | 0xa0,
+		LL_VO_WL_SKY =				LL_PCODE_APP | 0xb0, // should this be moved to 0x40?
 	} EVOType;
 
 	child_list_t	mChildList;
@@ -601,9 +605,6 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	BOOL			mStatic;					// Object doesn't move.
 	S32				mNumFaces;
 
-	S32				mLastUpdateFrame;			// frames in which an object had last moved for smart coalescing of drawables 
-												// (child objects not moving relative to parent)
-
 	F32				mTimeDilation;				// Time dilation sent with the object.
 	F32				mRotTime;					// Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega)
 	LLQuaternion	mLastRot;					// last rotation received from the simulator
@@ -669,14 +670,13 @@ class LLAlphaObject : public LLViewerObject
 	: LLViewerObject(id,type,regionp) 
 	{ mDepth = 0.f; }
 
-	virtual BOOL isParticle();
 	virtual F32 getPartSize(S32 idx);
 	virtual void getGeometry(S32 idx,
 								LLStrider<LLVector3>& verticesp,
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp) = 0;
+								LLStrider<U16>& indicesp) = 0;
 
 	F32 mDepth;
 };
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 012bdb08434..8d1867cc315 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -36,6 +36,7 @@
 #include "message.h"
 #include "timing.h"
 #include "llfasttimer.h"
+#include "llglimmediate.h"
 
 #include "llviewercontrol.h"
 #include "llface.h"
@@ -45,6 +46,7 @@
 #include "llnetmap.h"
 #include "llagent.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llhoverview.h"
 #include "llworld.h"
 #include "llstring.h"
@@ -206,30 +208,28 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
 
 	// ignore returned flags
 	objectp->processUpdateMessage(msg, user_data, i, update_type, dpp);
-
+		
 	if (objectp->isDead())
 	{
 		// The update failed
 		return;
 	}
-	updateActive(objectp);
-
-	// Also sets the approx. pixel area
-	objectp->setPixelAreaAndAngle(gAgent);
 
-	// Update the image levels of textures for this object.
-	objectp->updateTextures(gAgent);
+	updateActive(objectp);
 
 	if (just_created) 
 	{
 		gPipeline.addObject(objectp);
 	}
 
+	// Also sets the approx. pixel area
+	objectp->setPixelAreaAndAngle(gAgent);
+
 	// RN: this must be called after we have a drawable 
 	// (from gPipeline.addObject)
 	// so that the drawable parent is set properly
 	findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort());
-
+	
 	// If we're just wandering around, don't create new objects selected.
 	if (just_created 
 		&& update_type != OUT_TERSE_IMPROVED 
@@ -528,18 +528,6 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
 	processObjectUpdate(mesgsys, user_data, update_type, true, false);
 }	
 
-void LLViewerObjectList::relightAllObjects()
-{
-	for (S32 i = 0; i < mObjects.count(); i++)
-	{
-		LLDrawable *drawable = mObjects[i]->mDrawable;
-		if (drawable)
-		{
-			gPipeline.markRelight(drawable);
-		}
-	}
-}
-
 void LLViewerObjectList::dirtyAllObjectInventory()
 {
 	S32 count = mObjects.count();
@@ -1008,7 +996,7 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 	}
 
 	gPipeline.shiftObjects(offset);
-	gWorldPointer->mPartSim.shift(offset);
+	gWorldp->shiftRegions(offset);
 }
 
 void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
@@ -1109,12 +1097,17 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce
 
 		std::vector<LLDrawable*> pick_drawables;
 
-		for (i = 0; i < LLPipeline::NUM_PARTITIONS-1; i++)
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			LLSpatialPartition* part = gPipeline.getSpatialPartition(i);
-			if (part)
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 			{
-				part->cull(camera, &pick_drawables, TRUE);
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{	
+					part->cull(camera, &pick_drawables, TRUE);
+				}
 			}
 		}
 
@@ -1213,10 +1206,12 @@ U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parce
 	//
 	// Render pass for selected objects
 	//
+	gGL.start();	
 	gViewerWindow->renderSelections( TRUE, pick_parcel_wall, FALSE );
 
 	// render pickable ui elements, like names, etc.
 	LLHUDObject::renderAllForSelect();
+	gGL.stop();
 
 	gRenderForSelect = FALSE;
 
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index f73a0941973..95c65d15ce8 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -104,7 +104,6 @@ class LLViewerObjectList
 	void renderObjectBeacons();
 	void resetObjectBeacons();
 
-	void relightAllObjects();
 	void dirtyAllObjectInventory();
 
 	void updateActive(LLViewerObject *objectp);
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index d9ab2bcd8a4..3dc14caa2da 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -36,6 +36,7 @@
 // indra includes
 #include "llparcel.h"
 #include "llgl.h"
+#include "llglimmediate.h"
 #include "v4color.h"
 #include "v2math.h"
 
@@ -829,14 +830,12 @@ S32 LLViewerParcelOverlay::renderPropertyLines	()
 			continue;
 		}
 
-		glBegin(GL_TRIANGLE_STRIP);
+		gGL.begin(GL_TRIANGLE_STRIP);
 
 		for (j = 0; j < vertex_per_edge; j++)
 		{
-			// JC - This doesn't work
-			//glTexCoord2fv(mTexCoordArray + FLOATS_PER_TEX_COORD*offset);
-			glColor4ubv(colorp);
-			glVertex3fv(vertexp);
+			gGL.color4ubv(colorp);
+			gGL.vertex3fv(vertexp);
 
 			colorp  += BYTES_PER_COLOR;
 			vertexp += FLOATS_PER_VERTEX;			
@@ -844,7 +843,34 @@ S32 LLViewerParcelOverlay::renderPropertyLines	()
 
 		drawn += vertex_per_edge;
 
-		glEnd();
+		gGL.end();
+
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+		
+		colorp  = mColorArray  + BYTES_PER_COLOR   * i;
+		vertexp = mVertexArray + FLOATS_PER_VERTEX * i;
+
+		gGL.begin(GL_TRIANGLE_STRIP);
+
+		for (j = 0; j < vertex_per_edge; j++)
+		{
+			U8 color[4];
+			color[0] = colorp[0];
+			color[1] = colorp[1];
+			color[2] = colorp[2];
+			color[3] = colorp[3]/4;
+
+			gGL.color4ubv(color);
+			gGL.vertex3fv(vertexp);
+
+			colorp  += BYTES_PER_COLOR;
+			vertexp += FLOATS_PER_VERTEX;			
+		}
+
+		drawn += vertex_per_edge;
+
+		gGL.end();
+		
 	}
 
 	glPopMatrix();
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index acae8d333fe..93e3ad29197 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -43,8 +43,7 @@
 #include "llvopartgroup.h"
 #include "llworld.h"
 #include "pipeline.h"
-
-const S32 MAX_PART_COUNT = 8192; // VWR-1105
+#include "llspatialpartition.h"
 
 const F32 PART_SIM_BOX_SIDE = 16.f;
 const F32 PART_SIM_BOX_OFFSET = 0.5f*PART_SIM_BOX_SIDE;
@@ -53,6 +52,18 @@ const F32 PART_SIM_BOX_RAD = 0.5f*F_SQRT3*PART_SIM_BOX_SIDE;
 //static
 S32 LLViewerPartSim::sMaxParticleCount = 0;
 S32 LLViewerPartSim::sParticleCount = 0;
+// This controls how greedy individual particle burst sources are allowed to be, and adapts according to how near the particle-count limit we are.
+F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
+F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
+
+//static
+const S32 LLViewerPartSim::MAX_PART_COUNT = 8192;
+const F32 LLViewerPartSim::PART_THROTTLE_THRESHOLD = 0.9f;
+const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT = 2.0f;
+
+//static
+const F32 LLViewerPartSim::PART_THROTTLE_RESCALE = PART_THROTTLE_THRESHOLD / (1.0f-PART_THROTTLE_THRESHOLD);
+const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT_RECIP = 1.0f/PART_ADAPT_RATE_MULT;
 
 
 U32 LLViewerPart::sNextPartID = 1;
@@ -76,36 +87,6 @@ LLViewerPart::~LLViewerPart()
 	mPartSourcep = NULL;
 }
 
-LLViewerPart &LLViewerPart::operator=(const LLViewerPart &part)
-{
-	LLMemType mt(LLMemType::MTYPE_PARTICLES);
-	mPartID = part.mPartID;
-	mFlags = part.mFlags;
-	mMaxAge = part.mMaxAge;
-
-	mStartColor = part.mStartColor;
-	mEndColor = part.mEndColor;
-	mStartScale = part.mStartScale;
-	mEndScale = part.mEndScale;
-
-	mPosOffset = part.mPosOffset;
-	mParameter = part.mParameter;
-
-	mLastUpdateTime = part.mLastUpdateTime;
-	mVPCallback = part.mVPCallback;
-	mPartSourcep = part.mPartSourcep;
-	
-	mImagep = part.mImagep;
-	mPosAgent = part.mPosAgent;
-	mVelocity = part.mVelocity;
-	mAccel = part.mAccel;
-	mColor = part.mColor;
-	mScale = part.mScale;
-
-
-	return *this;
-}
-
 void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep, LLViewerImage *imagep, LLVPCallback cb)
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
@@ -114,6 +95,7 @@ void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep, LLViewerImage *im
 	mFlags = 0x00f;
 	mLastUpdateTime = 0.f;
 	mMaxAge = 10.f;
+	mSkipOffset = 0.0f;
 
 	mVPCallback = cb;
 	mPartSourcep = sourcep;
@@ -155,11 +137,23 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 bo
 
 	LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup();
 
-	LLVector3 center(group->mOctreeNode->getCenter());
-	LLVector3 size(group->mOctreeNode->getSize());
-	size += LLVector3(0.01f, 0.01f, 0.01f);
-	mMinObjPos = center - size;
-	mMaxObjPos = center + size;
+	if (group != NULL)
+	{
+		LLVector3 center(group->mOctreeNode->getCenter());
+		LLVector3 size(group->mOctreeNode->getSize());
+		size += LLVector3(0.01f, 0.01f, 0.01f);
+		mMinObjPos = center - size;
+		mMaxObjPos = center + size;
+	}
+	else 
+	{
+		// Not sure what else to set the obj bounds to when the drawable has no spatial group.
+		LLVector3 extents(mBoxRadius, mBoxRadius, mBoxRadius);
+		mMinObjPos = center_agent - extents;
+		mMaxObjPos = center_agent + extents;
+	}
+
+	mSkippedTime = 0.f;
 
 	static U32 id_seed = 0;
 	mID = ++id_seed;
@@ -233,27 +227,17 @@ BOOL LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size)
 	gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 	
 	mParticles.push_back(part);
+	part->mSkipOffset=mSkippedTime;
 	LLViewerPartSim::incPartCount(1);
 	return TRUE;
 }
 
 
-void LLViewerPartGroup::removePart(const S32 part_num)
-{
-	LLMemType mt(LLMemType::MTYPE_PARTICLES);
-	// Remove the entry for the particle we just deleted.
-	mParticles.erase(mParticles.begin() + part_num);
-	if (mVOPartGroupp.notNull())
-	{
-		gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-	}
-	LLViewerPartSim::decPartCount(1);
-}
-
-void LLViewerPartGroup::updateParticles(const F32 dt)
+void LLViewerPartGroup::updateParticles(const F32 lastdt)
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
 	S32 i;
+	F32 dt;
 	
 	LLVector3 gravity(0.f, 0.f, -9.8f);
 
@@ -264,6 +248,9 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 		LLVector3 a(0.f, 0.f, 0.f);
 		LLViewerPart& part = *((LLViewerPart*) mParticles[i]);
 
+		dt=lastdt+mSkippedTime-part.mSkipOffset;
+		part.mSkipOffset=0.f;
+
 		// Update current time
 		const F32 cur_time = part.mLastUpdateTime + dt;
 		const F32 frac = cur_time/part.mMaxAge;
@@ -347,10 +334,11 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 		if (part.mFlags & LLPartData::LL_PART_INTERP_COLOR_MASK)
 		{
 			part.mColor.setVec(part.mStartColor);
-			part.mColor *= 1.f - frac;
-			part.mColor.mV[3] *= (1.f - frac)*part.mStartColor.mV[3];
-			part.mColor += frac*part.mEndColor;
-			part.mColor.mV[3] += frac*part.mEndColor.mV[3];
+			// note: LLColor4's v%k means multiply-alpha-only,
+			//       LLColor4's v*k means multiply-rgb-only
+			part.mColor *= 1.f - frac; // rgb*k
+			part.mColor %= 1.f - frac; // alpha*k
+			part.mColor += frac%(frac*part.mEndColor); // rgb,alpha
 		}
 
 		// Do scale interpolation
@@ -370,6 +358,8 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 		{
 			end--;
 			LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
+			// be sure to process the particle we just swapped-in
+			i--;
 		}
 		else 
 		{
@@ -380,6 +370,8 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 				gWorldPointer->mPartSim.put(&part);
 				end--;
 				LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
+				// be sure to process the particle we just swapped-in
+				i--;
 			}
 		}
 	}
@@ -470,12 +462,12 @@ LLViewerPartSim::~LLViewerPartSim()
 BOOL LLViewerPartSim::shouldAddPart()
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
-	if (sParticleCount > 0.75f*sMaxParticleCount)
+	if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
 	{
 
 		F32 frac = (F32)sParticleCount/(F32)sMaxParticleCount;
-		frac -= 0.75;
-		frac *= 3.f;
+		frac -= PART_THROTTLE_THRESHOLD;
+		frac *= PART_THROTTLE_RESCALE;
 		if (ll_frand() < frac)
 		{
 			// Skip...
@@ -573,21 +565,13 @@ void LLViewerPartSim::shift(const LLVector3 &offset)
 	}
 }
 
-S32 dist_rate_func(F32 distance)
-{
-	//S32 dist = (S32) sqrtf(distance);
-	//dist /= 2;
-	//return llmax(dist,1);
-	return 1;
-}
-
 void LLViewerPartSim::updateSimulation()
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
 	
 	static LLFrameTimer update_timer;
 
-	const F32 dt = update_timer.getElapsedTimeAndResetF32();
+	const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f);
 
  	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
 	{
@@ -605,9 +589,11 @@ void LLViewerPartSim::updateSimulation()
 	S32 count = (S32) mViewerPartSources.size();
 	S32 start = (S32)ll_frand((F32)count);
 	S32 dir = 1;
+	S32 deldir = 0;
 	if (ll_frand() > 0.5f)
 	{
 		dir = -1;
+		deldir = -1;
 	}
 
 	S32 num_updates = 0;
@@ -624,25 +610,14 @@ void LLViewerPartSim::updateSimulation()
 
 		if (!mViewerPartSources[i]->isDead())
 		{
-			LLViewerObject* source_object = mViewerPartSources[i]->mSourceObjectp;
-			if (source_object && source_object->mDrawable.notNull())
-			{
-                S32 dist = dist_rate_func(source_object->mDrawable->mDistanceWRTCamera);
-				if ((LLDrawable::getCurrentFrame()+mViewerPartSources[i]->mID)%dist == 0)
-				{
-					mViewerPartSources[i]->update(dt*dist);
-				}
-			}
-			else
-			{
-				mViewerPartSources[i]->update(dt);
-			}
+			mViewerPartSources[i]->update(dt);
 		}
 
 		if (mViewerPartSources[i]->isDead())
 		{
 			mViewerPartSources.erase(mViewerPartSources.begin() + i);
 			count--;
+			i+=deldir;
 		}
 		else
         {
@@ -657,24 +632,24 @@ void LLViewerPartSim::updateSimulation()
 	{
 		LLViewerObject* vobj = mViewerPartGroups[i]->mVOPartGroupp;
 
-		S32 dist = vobj && !vobj->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) ? 
-				dist_rate_func(vobj->mDrawable->mDistanceWRTCamera) : 1;
+		S32 visirate = 1;
 		if (vobj)
 		{
 			LLSpatialGroup* group = vobj->mDrawable->getSpatialGroup();
 			if (group && !group->isVisible()) // && !group->isState(LLSpatialGroup::OBJECT_DIRTY))
 			{
-				dist *= 8;
+				visirate = 8;
 			}
 		}
 
-		if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%dist == 0)
+		if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%visirate == 0)
 		{
 			if (vobj)
 			{
 				gPipeline.markRebuild(vobj->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 			}
-			mViewerPartGroups[i]->updateParticles(dt*dist);
+			mViewerPartGroups[i]->updateParticles(dt * visirate);
+			mViewerPartGroups[i]->mSkippedTime=0.0f;
 			if (!mViewerPartGroups[i]->getCount())
 			{
 				delete mViewerPartGroups[i];
@@ -683,10 +658,64 @@ void LLViewerPartSim::updateSimulation()
 				count--;
 			}
 		}
+		else
+		{	
+			mViewerPartGroups[i]->mSkippedTime+=dt;
+		}
+
+	}
+	if (LLDrawable::getCurrentFrame()%16==0)
+	{
+		if (sParticleCount > sMaxParticleCount * 0.875f
+		    && sParticleAdaptiveRate < 2.0f)
+		{
+			sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT;
+		}
+		else
+		{
+			if (sParticleCount < sMaxParticleCount * 0.5f
+			    && sParticleAdaptiveRate > 0.03125f)
+			{
+				sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT_RECIP;
+			}
+		}
 	}
-	//llinfos << "Particles: " << sParticleCount << llendl;
+
+	updatePartBurstRate() ;
+
+	//llinfos << "Particles: " << sParticleCount << " Adaptive Rate: " << sParticleAdaptiveRate << llendl;
 }
 
+void LLViewerPartSim::updatePartBurstRate()
+{
+	if (!(LLDrawable::getCurrentFrame() & 0xf))
+	{
+		if (sParticleCount >= MAX_PART_COUNT) //set rate to zero
+		{
+			sParticleBurstRate = 0.0f ;
+		}
+		else if(sParticleCount > 0)
+		{
+			if(sParticleBurstRate > 0.0000001f)
+			{				
+				F32 total_particles = sParticleCount / sParticleBurstRate ; //estimated
+				F32 new_rate = llclamp(0.9f * sMaxParticleCount / total_particles, 0.0f, 1.0f) ;
+				F32 delta_rate_threshold = llmin(0.1f * llmax(new_rate, sParticleBurstRate), 0.1f) ;
+				F32 delta_rate = llclamp(new_rate - sParticleBurstRate, -1.0f * delta_rate_threshold, delta_rate_threshold) ;
+
+				sParticleBurstRate = llclamp(sParticleBurstRate + 0.5f * delta_rate, 0.0f, 1.0f) ;
+			}
+			else
+			{
+				sParticleBurstRate += 0.0000001f ;
+			}
+		}
+		else
+		{
+			sParticleBurstRate += 0.00125f ;
+		}
+	}
+}
 
 void LLViewerPartSim::addPartSource(LLPointer<LLViewerPartSource> sourcep)
 {
@@ -696,6 +725,7 @@ void LLViewerPartSim::addPartSource(LLPointer<LLViewerPartSource> sourcep)
 		llwarns << "Null part source!" << llendl;
 		return;
 	}
+	sourcep->setStart() ;
 	mViewerPartSources.push_back(sourcep);
 }
 
diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h
index c915468c3bc..51b8e5a42a1 100644
--- a/indra/newview/llviewerpartsim.h
+++ b/indra/newview/llviewerpartsim.h
@@ -61,13 +61,12 @@ class LLViewerPart : public LLPartData, public LLRefCount
 public:
 	LLViewerPart();
 
-	LLViewerPart &operator=(const LLViewerPart &part);
 	void init(LLPointer<LLViewerPartSource> sourcep, LLViewerImage *imagep, LLVPCallback cb);
 
 
 	U32					mPartID;					// Particle ID used primarily for moving between groups
 	F32					mLastUpdateTime;			// Last time the particle was updated
-
+	F32					mSkipOffset;				// Offset against current group mSkippedTime
 
 	LLVPCallback		mVPCallback;				// Callback function for more complicated behaviors
 	LLPointer<LLViewerPartSource> mPartSourcep;		// Particle source used for this object
@@ -97,7 +96,7 @@ class LLViewerPartGroup
 
 	BOOL addPart(LLViewerPart* part, const F32 desired_size = -1.f);
 	
-	void updateParticles(const F32 dt);
+	void updateParticles(const F32 lastdt);
 
 	BOOL posInGroup(const LLVector3 &pos, const F32 desired_size = -1.f);
 
@@ -117,8 +116,7 @@ class LLViewerPartGroup
 	BOOL mUniformParticles;
 	U32 mID;
 
-protected:
-	void removePart(const S32 part_num);
+	F32 mSkippedTime;
 
 protected:
 	LLVector3 mCenterAgent;
@@ -131,7 +129,6 @@ class LLViewerPartGroup
 
 class LLViewerPartSim
 {
-
 public:
 	LLViewerPartSim();
 	virtual ~LLViewerPartSim();
@@ -148,7 +145,22 @@ class LLViewerPartSim
 	void cleanupRegion(LLViewerRegion *regionp);
 
 	BOOL shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping)
+	F32 maxRate() // Return maximum particle generation rate
+	{
+		if (sParticleCount >= MAX_PART_COUNT)
+		{
+			return 1.f;
+		}
+		if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
+		{
+			return (((F32)sParticleCount/(F32)sMaxParticleCount)-PART_THROTTLE_THRESHOLD)*PART_THROTTLE_RESCALE;
+		}
+		return 0.f;
+	}
+	F32 getRefRate() { return sParticleAdaptiveRate; }
+	F32 getBurstRate() {return sParticleBurstRate; }
 	void addPart(LLViewerPart* part);
+	void updatePartBurstRate() ;
 	void clearParticlesByID(const U32 system_id);
 	void clearParticlesByOwnerID(const LLUUID& task_id);
 	void removeLastCreatedSource();
@@ -170,12 +182,20 @@ class LLViewerPartSim
 	LLViewerPartGroup *createViewerPartGroup(const LLVector3 &pos_agent, const F32 desired_size);
 	LLViewerPartGroup *put(LLViewerPart* part);
 
-protected:
 	group_list_t mViewerPartGroups;
 	source_list_t mViewerPartSources;
 	LLFrameTimer mSimulationTimer;
+
 	static S32 sMaxParticleCount;
 	static S32 sParticleCount;
+	static F32 sParticleAdaptiveRate;
+	static F32 sParticleBurstRate;
+
+	static const S32 MAX_PART_COUNT;
+	static const F32 PART_THROTTLE_THRESHOLD;
+	static const F32 PART_THROTTLE_RESCALE;
+	static const F32 PART_ADAPT_RATE_MULT;
+	static const F32 PART_ADAPT_RATE_MULT_RECIP;
 };
 
 #endif // LL_LLVIEWERPARTSIM_H
diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp
index a69fc51fe06..d81b688abf8 100644
--- a/indra/newview/llviewerpartsource.cpp
+++ b/indra/newview/llviewerpartsource.cpp
@@ -36,6 +36,7 @@
 
 #include "llagent.h"
 #include "lldrawable.h"
+#include "llviewercamera.h"
 #include "llviewerimagelist.h"
 #include "llviewerobject.h"
 #include "llviewerobjectlist.h"
@@ -53,6 +54,8 @@ LLViewerPartSource::LLViewerPartSource(const U32 type) :
 	mIsSuspended = FALSE;
 	static U32 id_seed = 0;
 	mID = ++id_seed;
+
+	mDelay = 0 ;
 }
 
 void LLViewerPartSource::setDead()
@@ -79,6 +82,10 @@ LLUUID LLViewerPartSource::getImageUUID() const
 	}
 	return LLUUID::null;
 }
+void LLViewerPartSource::setStart()
+{
+	mDelay = 99 ;
+}
 
 LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp) :
 	LLViewerPartSource(LL_PART_SOURCE_SCRIPT)
@@ -111,6 +118,8 @@ void LLViewerPartSourceScript::update(const F32 dt)
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
 	F32 old_update_time = mLastUpdateTime;
 	mLastUpdateTime += dt;
+
+	F32 ref_rate_travelspeed = llmin(gWorldPointer->mPartSim.getRefRate(), 1.f);
 	
 	F32 dt_update = mLastUpdateTime - mLastPartTime;
 
@@ -199,21 +208,71 @@ void LLViewerPartSourceScript::update(const F32 dt)
 			// No angular velocity.  Reset our rotation.
 			mRotation.setQuat(0, 0, 0);
 		}
-
+		
 		if (gWorldPointer->mPartSim.aboveParticleLimit())
 		{
 			// Don't bother doing any more updates if we're above the particle limit,
 			// just give up.
 			mLastPartTime = mLastUpdateTime;
+            break;
+
+		}
+		
+		// find the greatest length that the shortest side of a system
+		// particle is expected to have
+		F32 max_short_side =
+			llmax(
+			      llmax(llmin(mPartSysData.mPartData.mStartScale[0],
+					  mPartSysData.mPartData.mStartScale[1]),
+				    llmin(mPartSysData.mPartData.mEndScale[0],
+					  mPartSysData.mPartData.mEndScale[1])),
+			      llmin((mPartSysData.mPartData.mStartScale[0]
+				     + mPartSysData.mPartData.mEndScale[0])/2,
+				    (mPartSysData.mPartData.mStartScale[1]
+				     + mPartSysData.mPartData.mEndScale[1])/2));
+		
+		F32 pixel_meter_ratio = gCamera->getPixelMeterRatio();
+
+		// Maximum distance at which spawned particles will be viewable
+		F32 max_dist = max_short_side * pixel_meter_ratio; 
+
+		if (max_dist < 0.25f)
+		{
+			// < 1 pixel wide at a distance of >=25cm.  Particles
+			// this tiny are useless and mostly spawned by buggy
+			// sources
+			mLastPartTime = mLastUpdateTime;
 			break;
 		}
 
+		// Distance from camera
+		F32 dist = (mPosAgent - gCamera->getOrigin()).magVec();
+
+		// Particle size vs distance vs maxage throttling
+
+		F32 limited_rate=0.f;
+		if (dist - max_dist > 0.f)
+		{
+			if((dist - max_dist) * ref_rate_travelspeed > mPartSysData.mPartData.mMaxAge - 0.2f )
+			{
+				// You need to travel faster than 1 divided by reference rate m/s directly towards these particles to see them at least 0.2s
+				mLastPartTime = mLastUpdateTime;
+				break;
+			}
+			limited_rate = ((dist - max_dist) * ref_rate_travelspeed) / mPartSysData.mPartData.mMaxAge;
+		}
+		
+		if(mDelay)
+		{
+			limited_rate = llmax(limited_rate, 0.01f * mDelay--) ;
+		}
+
 		S32 i;
 		for (i = 0; i < mPartSysData.mBurstPartCount; i++)
 		{
-			if (!gWorldPointer->mPartSim.shouldAddPart())
+			if (ll_frand() < llmax(1.0f - gWorldPointer->mPartSim.getBurstRate(), limited_rate))
 			{
-				// Particle simulation says we have too many particles, skip all this
+				// Limit particle generation
 				continue;
 			}
 
diff --git a/indra/newview/llviewerpartsource.h b/indra/newview/llviewerpartsource.h
index 3e3e63c2fb9..7a49a919bc9 100644
--- a/indra/newview/llviewerpartsource.h
+++ b/indra/newview/llviewerpartsource.h
@@ -73,6 +73,7 @@ class LLViewerPartSource : public LLRefCount
 	LLUUID getOwnerUUID() const { return mOwnerUUID; }
 	U32	getID() const { return mID; }
 	LLUUID getImageUUID() const;
+	void  setStart() ;
 
 	LLVector3	mPosAgent; // Location of the particle source
 	LLVector3	mTargetPosAgent; // Location of the target position
@@ -91,6 +92,7 @@ class LLViewerPartSource : public LLRefCount
 
 	// Particle information
 	U32			mPartFlags; // Flags for the particle
+	U32         mDelay ; //delay to start particles
 };
 
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 9f343abdaeb..3f0f5bee980 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -64,6 +64,7 @@
 #include "llvocache.h"
 #include "llvoclouds.h"
 #include "llworld.h"
+#include "llspatialpartition.h"
 
 // Viewer object cache version, change if object update
 // format changes. JC
@@ -105,6 +106,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mWidth = region_width_meters;
 
 	mOriginGlobal = from_region_handle(handle); 
+	updateRenderMatrix();
 
 	mLandp = new LLSurface('l', NULL);
 	if (!gNoRender)
@@ -138,6 +140,19 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 
 	mCacheStart.append(mCacheEnd);
 	
+	//create object partitions
+	//MUST MATCH declaration of eObjectPartitions
+	mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD
+	mObjectPartition.push_back(new LLTerrainPartition());	//PARTITION_TERRAIN
+	mObjectPartition.push_back(new LLWaterPartition());		//PARTITION_WATER
+	mObjectPartition.push_back(new LLTreePartition());		//PARTITION_TREE
+	mObjectPartition.push_back(new LLParticlePartition());	//PARTITION_PARTICLE
+	mObjectPartition.push_back(new LLCloudPartition());		//PARTITION_CLOUD
+	mObjectPartition.push_back(new LLGrassPartition());		//PARTITION_GRASS
+	mObjectPartition.push_back(new LLVolumePartition());	//PARTITION_VOLUME
+	mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE
+	mObjectPartition.push_back(NULL);						//PARTITION_NONE
+	
 }
 
 
@@ -176,6 +191,8 @@ LLViewerRegion::~LLViewerRegion()
 	LLHTTPSender::clearSender(mHost);
 	
 	saveCache();
+
+	std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer());
 }
 
 
@@ -381,12 +398,17 @@ void LLViewerRegion::setRegionFlags(U32 flags)
 void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) 
 { 
 	mOriginGlobal = origin_global; 
+	updateRenderMatrix();
 	mLandp->setOriginGlobal(origin_global);
 	mWind.setOriginGlobal(origin_global);
 	mCloudLayer.setOriginGlobal(origin_global);
 	calculateCenterGlobal();
 }
 
+void LLViewerRegion::updateRenderMatrix()
+{
+	mRenderMatrix.setTranslation(getOriginAgent());
+}
 
 void LLViewerRegion::setTimeDilation(F32 time_dilation)
 {
@@ -952,8 +974,7 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
 		//		<< " Z: " << (S32)(z_pos * 4)
 		//		<< llendl;
 
-		// treat the target specially for the map, and don't add you
-		// or the target
+		// treat the target specially for the map
 		if(i == target_index)
 		{
 			LLVector3d global_pos(mOriginGlobal);
@@ -962,7 +983,9 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
 			global_pos.mdV[VZ] += (F64)(z_pos) * 4.0;
 			LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
 		}
-		else if( i != agent_index)
+		
+		//don't add you
+		if( i != agent_index)
 		{
 			pos = 0x0;
 			pos |= x_pos;
@@ -1431,4 +1454,12 @@ void LLViewerRegion::logActiveCapabilities() const
 	llinfos << "Dumped " << count << " entries." << llendl;
 }
 
+LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)
+{
+	if (type < mObjectPartition.size())
+	{
+		return mObjectPartition[type];
+	}
+	return NULL;
+}
 
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index e42c0015df4..3d5334cd188 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -64,10 +64,27 @@ class LLViewerParcelOverlay;
 class LLSurface;
 class LLVOCache;
 class LLVOCacheEntry;
+class LLSpatialPartition;
 
 class LLViewerRegion 
 {
 public:
+	//MUST MATCH THE ORDER OF DECLARATION IN CONSTRUCTOR
+	typedef enum 
+	{
+		PARTITION_HUD=0,
+		PARTITION_TERRAIN,
+		PARTITION_WATER,
+		PARTITION_TREE,
+		PARTITION_PARTICLE,
+		PARTITION_CLOUD,
+		PARTITION_GRASS,
+		PARTITION_VOLUME,
+		PARTITION_BRIDGE,
+		PARTITION_NONE,
+		NUM_PARTITIONS
+	} eObjectPartitions;
+
 	LLViewerRegion(const U64 &handle,
 				   const LLHost &host,
 				   const U32 surface_grid_width,
@@ -84,7 +101,8 @@ class LLViewerRegion
 	void sendReliableMessage(); // Send the current message to this region's simulator
 
 	void setOriginGlobal(const LLVector3d &origin);
-	void setAgentOffset(const LLVector3d &offset);
+	//void setAgentOffset(const LLVector3d &offset);
+	void updateRenderMatrix();
 
 	void setAllowDamage(BOOL b) { setFlags(b, REGION_FLAGS_ALLOW_DAMAGE); }
 	void setAllowLandmark(BOOL b) { setFlags(b, REGION_FLAGS_ALLOW_LANDMARK); }
@@ -245,6 +263,7 @@ class LLViewerRegion
 	// used by LCD to get details for debug screen
 	U32 getNetDetailsForLCD();
 
+	LLSpatialPartition* getSpatialPartition(U32 type);
 public:
 	struct CompareDistance
 	{
@@ -270,6 +289,8 @@ class LLViewerRegion
 	LLStat	mPacketsStat;
 	LLStat	mPacketsLostStat;
 
+	LLMatrix4 mRenderMatrix;
+
 	// These arrays are maintained in parallel. Ideally they'd be combined into a
 	// single array of an aggrigate data type but for compatibility with the old
 	// messaging system in which the previous message only sends and parses the 
@@ -348,6 +369,10 @@ class LLViewerRegion
 	CapabilityMap mCapabilities;
 	
 	LLEventPoll* mEventPoll;
+
+private:
+	//spatial partitions for objects in this region
+	std::vector<LLSpatialPartition*> mObjectPartition;
 };
 
 inline BOOL LLViewerRegion::getAllowDamage() const
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index ec4f66d6811..93919fba051 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -537,7 +537,7 @@ void update_statistics(U32 frame_count)
 	gViewerStats->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs);
 	gViewerStats->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs);
 	gViewerStats->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IMAGE_UPDATE));
-	gViewerStats->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_REBUILD));
+	gViewerStats->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_STATESORT ));
 	gViewerStats->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_RENDER_GEOMETRY));
 		
 	LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost());
@@ -704,11 +704,11 @@ void send_stats()
 	std::string gpu_desc = llformat(
 		"%-6s Class %d ",
 		gGLManager.mGLVendorShort.substr(0,6).c_str(),
-		gFeatureManagerp->getGPUClass())
+		(S32)gFeatureManagerp->getGPUClass())
 		+ gFeatureManagerp->getGPUString();
 
 	system["gpu"] = gpu_desc;
-	system["gpu_class"] = gFeatureManagerp->getGPUClass();
+	system["gpu_class"] = (S32)gFeatureManagerp->getGPUClass();
 	system["gpu_vendor"] = gGLManager.mGLVendorShort;
 	system["gpu_version"] = gGLManager.mDriverVersionVendorString;
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 9e8a7c2a9b9..2ab11bf5076 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -42,7 +42,7 @@
 #include "llviewquery.h"
 #include "llxmltree.h"
 //#include "llviewercamera.h"
-//#include "imdebug.h"
+#include "llglimmediate.h"
 
 #include "llvoiceclient.h"	// for push-to-talk button handling
 
@@ -183,6 +183,7 @@
 #include "llappviewer.h"
 #include "llurlsimstring.h"
 #include "llviewerdisplay.h"
+#include "llspatialpartition.h"
 
 #if LL_WINDOWS
 #include "llwindebug.h"
@@ -192,11 +193,13 @@
 //
 // Globals
 //
-
+void render_ui_and_swap_if_needed();
+void render_ui_and_swap();
 LLBottomPanel* gBottomPanel = NULL;
 
 extern BOOL gDebugClicks;
 extern BOOL gDisplaySwapBuffers;
+extern BOOL gResizeScreenTexture;
 extern S32 gJamesInt;
 
 LLViewerWindow	*gViewerWindow = NULL;
@@ -531,13 +534,68 @@ class LLDebugText
 			addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
 			ypos += y_inc;
 
-			addText(xpos, ypos, llformat("%d Pending Lock", LLVertexBuffer::sLockedList.size()));
+			addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
 			ypos += y_inc;
 
-			addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
+			addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
+            ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
 			ypos += y_inc;
-		}
 
+			gPipeline.mTextureMatrixOps = 0;
+			gPipeline.mMatrixOpCount = 0;
+
+			if (gPipeline.mBatchCount > 0)
+			{
+				addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize, 
+					gPipeline.mMeanBatchSize));
+
+				gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
+				gPipeline.mMaxBatchSize = 0;
+				gPipeline.mBatchCount = 0;
+			}
+            ypos += y_inc;
+
+			addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
+			
+			ypos += y_inc;
+
+
+			addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
+			
+			ypos += y_inc;
+
+			LLVertexBuffer::sBindCount = LLImageGL::sBindCount = 
+				LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = 
+				gPipeline.mNumVisibleNodes = 0;
+		}
+		if (gSavedSettings.getBOOL("DebugShowColor"))
+		{
+			U8 color[4];
+			LLCoordGL coord = gViewerWindow->getCurrentMouse();
+			glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
+			addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
+			ypos += y_inc;
+		}
 		// only display these messages if we are actually rendering beacons at this moment
 		if (LLPipeline::getRenderBeacons(NULL) && LLPipeline::getProcessBeacons(NULL))
 		{
@@ -1509,63 +1567,39 @@ LLViewerWindow::LLViewerWindow(
 	
 	LLFontManager::initClass();
 
-	// Initialize OpenGL Renderer
+	//
+	// We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
+	// stuff like AGP if we think that it'll crash the viewer.
+	//
+	llinfos << "Loading feature tables." << llendl;
+
+	gFeatureManagerp->init();
 
-	if (!gFeatureManagerp->isFeatureAvailable("RenderVBO") ||
+	// Initialize OpenGL Renderer
+	if (!gFeatureManagerp->isFeatureAvailable("RenderVBOEnable") ||
 		!gGLManager.mHasVertexBufferObject)
 	{
 		gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
 	}
 	LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"));
 
-	//
-	// We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
-	// stuff like AGP if we think that it'll crash the viewer.
-	//
-	gFeatureManagerp->initGraphicsFeatureMasks();
 	if (gFeatureManagerp->isSafe()
-		|| (gSavedSettings.getS32("LastFeatureVersion") != gFeatureManagerp->getVersion()))
-	{
-		gFeatureManagerp->applyRecommendedFeatures();
-	}
-
-	S32 idx = gSavedSettings.getS32("GraphicsCardMemorySetting");
-	// -1 indicates use default (max)
-	if (idx == -1)
+		|| (gSavedSettings.getS32("LastFeatureVersion") != gFeatureManagerp->getVersion())
+		|| (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
 	{
-		idx = LLViewerImageList::getMaxVideoRamSetting(-2); // get max recommended setting
-		gSavedSettings.setS32("GraphicsCardMemorySetting", idx);
+		gFeatureManagerp->applyRecommendedSettings();
+		gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
 	}
 
 	// If we crashed while initializng GL stuff last time, disable certain features
 	if (gSavedSettings.getBOOL("RenderInitError"))
 	{
 		mInitAlert = "DisplaySettingsNoShaders";
-		gSavedSettings.setBOOL("VertexShaderEnable", FALSE);
-	}
+		gFeatureManagerp->setGraphicsLevel(0, false);
+		gSavedSettings.setU32("RenderQualityPerformance", 0);		
 		
-	if (!gNoRender)
-	{
-		//
-		// Initialize GL stuff
-		//
-
-		// Set this flag in case we crash while initializing GL
-		gSavedSettings.setBOOL("RenderInitError", TRUE);
-		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
-	
-		gPipeline.init();
-		stop_glerror();
-		initGLDefaults();
-
-		gSavedSettings.setBOOL("RenderInitError", FALSE);
-		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
 	}
-
-	//
-	// Done initing GL stuff.
-	//
-
+		
 	// set callbacks
 	mWindow->setCallbacks(this);
 
@@ -1609,11 +1643,7 @@ LLViewerWindow::LLViewerWindow(
 
 void LLViewerWindow::initGLDefaults()
 {
-	//LLGLState::reset();
-	//gGLSDefault.set();
-	//LLGLState::verify(TRUE);
-
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
 
 	F32 ambient[4] = {0.f,0.f,0.f,0.f };
@@ -1624,10 +1654,14 @@ void LLViewerWindow::initGLDefaults()
 	glPixelStorei(GL_PACK_ALIGNMENT,1);
 	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 
+	glEnable(GL_TEXTURE_2D);
+
 	// lights for objects
 	glShadeModel( GL_SMOOTH );
 
 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+	
+	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
 	glCullFace(GL_BACK);
 
@@ -1636,8 +1670,6 @@ void LLViewerWindow::initGLDefaults()
 	gBox.prerender();
 	gSphere.prerender();
 	gCylinder.prerender();
-
-	LLVOAvatar::initVertexPrograms();
 }
 
 void LLViewerWindow::initBase()
@@ -2157,6 +2189,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 
 		gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
 		gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
+		gResizeScreenTexture = TRUE;
 	}
 }
 
@@ -2222,11 +2255,20 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
 
 void LLViewerWindow::drawDebugText()
 {
-	mDebugText->draw();
+	gGL.start();
+	gGL.pushMatrix();
+	{
+		// scale view by UI global scale factor and aspect ratio correction factor
+		glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+		mDebugText->draw();
+	}
+	gGL.popMatrix();
+	gGL.stop();
 }
 
 void LLViewerWindow::draw()
 {
+	
 #if LL_DEBUG
 	LLView::sIsDrawing = TRUE;
 #endif
@@ -2268,7 +2310,7 @@ void LLViewerWindow::draw()
 	// Draw all nested UI views.
 	// No translation needed, this view is glued to 0,0
 
-	glPushMatrix();
+	gGL.pushMatrix();
 	{
 		// scale view by UI global scale factor and aspect ratio correction factor
 		glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
@@ -2293,11 +2335,6 @@ void LLViewerWindow::draw()
 			}
 		}
 
-		{
-			LLGLSTexture gls_texture;
-			drawDebugText();
-		}
-		
 		if (gToolMgr)
 		{
 			// Draw tool specific overlay on world
@@ -2358,7 +2395,6 @@ void LLViewerWindow::draw()
 		{
 			// Used for special titles such as "Second Life - Special E3 2003 Beta"
 			const S32 DIST_FROM_TOP = 20;
-			LLGLSTexture gls_texture;
 			LLFontGL::sSansSerifBig->renderUTF8(
 				mOverlayTitle, 0,
 				llround( gViewerWindow->getWindowWidth() * 0.5f),
@@ -2369,8 +2405,7 @@ void LLViewerWindow::draw()
 
 		LLUI::sGLScaleFactor = old_scale_factor;
 	}
-	glPopMatrix();
-
+	gGL.popMatrix();
 
 #if LL_DEBUG
 	LLView::sIsDrawing = FALSE;
@@ -3201,11 +3236,12 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
 		}
 
 		// Render light for editing
-		if (LLSelectMgr::sRenderLightRadius)
+		if (LLSelectMgr::sRenderLightRadius && gToolMgr->inEdit())
 		{
+			LLImageGL::unbindTexture(0);
 			LLGLEnable gls_blend(GL_BLEND);
 			LLGLEnable gls_cull(GL_CULL_FACE);
-			LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+			LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
 			glMatrixMode(GL_MODELVIEW);
 			glPushMatrix();
 			if (selection->getSelectType() == SELECT_TYPE_HUD)
@@ -3368,6 +3404,10 @@ void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask
 	{
 		return;
 	}
+	
+	render_ui_and_swap_if_needed();
+	glClear(GL_DEPTH_BUFFER_BIT);
+	gDisplaySwapBuffers = FALSE;
 
 	S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
 	S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
@@ -3408,6 +3448,8 @@ void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask
 	pick_camera.setAspect(1.f);
 
 	// save our drawing state
+	// *TODO: should we be saving using the new method here using
+	// glh_get_current_projection/glh_set_current_projection? -brad
 	glMatrixMode(GL_MODELVIEW);
 	glPushMatrix();
 	glLoadIdentity();
@@ -3421,13 +3463,18 @@ void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask
 	// Don't limit the select distance for this pick.
 	// make viewport big enough to handle antialiased frame buffers
 	gCamera->setPerspective(FOR_SELECTION, scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4, FALSE);
-	pick_camera.calcAgentFrustumPlanes(gCamera->mAgentFrustum);
 	// make viewport big enough to handle antialiased frame buffers
-	glViewport(scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
+	gGLViewport[0] = scaled_x - (PICK_HALF_WIDTH + 2);
+	gGLViewport[1] = scaled_y - (PICK_HALF_WIDTH + 2);
+	gGLViewport[2] = PICK_DIAMETER + 4;
+	gGLViewport[3] = PICK_DIAMETER + 4;
+	glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+	LLViewerCamera::updateFrustumPlanes(pick_camera);
 	stop_glerror();
 
 	glClearColor(0.f, 0.f, 0.f, 0.f);
 	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+	//glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
 	// Draw the objects so the user can select them.
 	// The starting ID is 1, since land is zero.
@@ -4285,7 +4332,7 @@ BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S3
 	llinfos << "Saving snapshot to: " << filepath << llendl;
 
 	LLPointer<LLImageRaw> raw = new LLImageRaw;
-	BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, show_ui, do_rebuild);
+	BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
 
 	if (success)
 	{
@@ -4318,10 +4365,10 @@ void LLViewerWindow::playSnapshotAnimAndSound()
 
 // Saves the image from the screen to the specified filename and path.
 BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, 
-								 BOOL keep_window_aspect, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
+								 BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
 {
-	F32 image_aspect_ratio = ((F32)image_width) / ((F32)image_height);
-	F32 window_aspect_ratio = ((F32)getWindowWidth()) / ((F32)getWindowHeight());
+	//F32 image_aspect_ratio = ((F32)image_width) / ((F32)image_height);
+	//F32 window_aspect_ratio = ((F32)getWindowWidth()) / ((F32)getWindowHeight());
 
 	if ((!gWorldPointer) ||
 		(!raw))
@@ -4330,7 +4377,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 	}
 
 	// PRE SNAPSHOT
-
+	render_ui_and_swap_if_needed();
+	gDisplaySwapBuffers = FALSE;
+	
 	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 	setCursor(UI_CURSOR_WAIT);
 
@@ -4342,7 +4391,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
 	}
 
-
 	BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
 	if (hide_hud)
 	{
@@ -4354,20 +4402,81 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 	// from window
 	S32 snapshot_width = mWindowRect.getWidth();
 	S32 snapshot_height =  mWindowRect.getHeight();
-	if (!keep_window_aspect)
+	F32 scale_factor = 1.0f ;
+	if (keep_window_aspect || is_texture) //map the entire window to snapshot
+	{
+	}
+	else //scale or crop
 	{
-		if (image_aspect_ratio > window_aspect_ratio)
+		if(snapshot_width > image_width) //crop
 		{
-			snapshot_height  = llround((F32)snapshot_width / image_aspect_ratio);
+			snapshot_width = image_width ;
 		}
-		else if (image_aspect_ratio < window_aspect_ratio)
+		if(snapshot_height > image_height)//crop
+		{
+			snapshot_height = image_height ;
+		}
+
+		//if (image_aspect_ratio > window_aspect_ratio)
+		//{
+		//	snapshot_height  = llround((F32)snapshot_width / image_aspect_ratio);
+		//}
+		//else if (image_aspect_ratio < window_aspect_ratio)
+		//{
+		//	snapshot_width = llround((F32)snapshot_height  * image_aspect_ratio);
+		//}
+	}
+
+	LLRenderTarget target;
+	
+	scale_factor = llmax(1.f, (F32)image_width / snapshot_width, (F32)image_height / snapshot_height); 
+	
+	// SNAPSHOT
+	S32 window_width = mWindowRect.getWidth();
+	S32 window_height = mWindowRect.getHeight();
+	
+	LLRect window_rect = mWindowRect;
+
+	BOOL use_fbo = FALSE;
+	
+	if (gGLManager.mHasFramebufferObject && 
+		(image_width > window_width ||
+		image_height > window_height) &&
+		 !show_ui &&
+		 keep_window_aspect)
+	{
+		GLint max_size = 0;
+		glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
+		
+		if (image_width <= max_size && image_height <= max_size)
 		{
-			snapshot_width = llround((F32)snapshot_height  * image_aspect_ratio);
+			use_fbo = TRUE;
+			
+			snapshot_width = image_width;
+			snapshot_height = image_height;
+			target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB, TRUE);
+			window_width = snapshot_width;
+			window_height = snapshot_height;
+			scale_factor = 1.f;
+			mWindowRect.set(0, 0, snapshot_width, snapshot_height);
+			target.bindTarget();
+
+			
 		}
 	}
+	
+	S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
+	S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
 
-	F32 scale_factor = llmax(1.f, (F32)image_width / snapshot_width, (F32)image_height / snapshot_height);
-	raw->resize(llfloor(snapshot_width*scale_factor), llfloor(snapshot_height *scale_factor), type == SNAPSHOT_TYPE_DEPTH ? 4 : 3);
+	S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+	S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+	if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
+	{
+		scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
+		image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+		image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+	}
+	raw->resize(image_buffer_x, image_buffer_y, type == SNAPSHOT_TYPE_DEPTH ? 4 : 3);
 
 	BOOL high_res = scale_factor > 1.f;
 	if (high_res)
@@ -4378,12 +4487,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		LLHUDText::reshape();
 	}
 
-	// SNAPSHOT
-	S32 window_width = mWindowRect.getWidth();
-	S32 window_height = mWindowRect.getHeight();
-	S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
-	S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
-
 	S32 output_buffer_offset_y = 0;
 
 	F32 depth_conversion_factor_1 = (gCamera->getFar() + gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear());
@@ -4414,9 +4517,10 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 			}
 			else
 			{
-				display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
+				display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)), use_fbo);
+				render_ui_and_swap();
 			}
-			glFlush();
+
 			S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
 			// handle fractional rows
 			U32 read_width = llmax(0, (window_width - subimage_x_offset) -
@@ -4475,6 +4579,14 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		output_buffer_offset_y += subimage_y_offset;
 	}
 
+	if (use_fbo)
+	{
+		mWindowRect = window_rect;
+		target.flush();
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	}
+	gDisplaySwapBuffers = FALSE;
+
 	// POST SNAPSHOT
 	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 	{
@@ -4492,14 +4604,20 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		LLHUDText::reshape();
 	}
 
-	gDisplaySwapBuffers = TRUE;
-
 	// Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
-	// Note: this formula depends on the number of components being 3.  Not obvious, but it's correct.
-	image_width += (image_width * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4; 	
+	// Note: this formula depends on the number of components being 3.  Not obvious, but it's correct.	
+	image_width += (image_width * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4 ;	
 
 	// Resize image
-	raw->scale( image_width, image_height );  
+	if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
+	{
+		raw->scale( image_width, image_height );  
+	}
+	else if(image_width != image_buffer_x || image_height != image_buffer_y)
+	{
+		raw->scale( image_width, image_height, FALSE );  
+	}
+	
 
 	setCursor(UI_CURSOR_ARROW);
 
@@ -4547,7 +4665,7 @@ void LLViewerWindow::drawMouselookInstructions()
 
 	{
 		LLGLSNoTexture gls_no_texture;
-		glColor4f( 0.9f, 0.9f, 0.9f, 1.0f );
+		gGL.color4f( 0.9f, 0.9f, 0.9f, 1.0f );
 		gl_rect_2d( instructions_rect );
 	}
 	
@@ -4630,12 +4748,16 @@ void LLViewerWindow::setTopCtrl(LLUICtrl* new_top)
 
 void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset)
 {
-	glViewport(x_offset, y_offset, mWindowRect.getWidth(), mWindowRect.getHeight());
+	gGLViewport[0] = x_offset;
+	gGLViewport[1] = y_offset;
+	gGLViewport[2] = mWindowRect.getWidth();
+	gGLViewport[3] = mWindowRect.getHeight();
+	glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 }
 
 void LLViewerWindow::setup3DRender()
 {
-	gCamera->setPerspective(NOT_FOR_SELECTION, 0, 0,  mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, gCamera->getNear(), MAX_FAR_PLANE);
+	gCamera->setPerspective(NOT_FOR_SELECTION, 0, 0,  mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, gCamera->getNear(), MAX_FAR_CLIP*2.f);
 }
 
 void LLViewerWindow::setup2DRender()
@@ -4764,7 +4886,10 @@ void LLViewerWindow::stopGL(BOOL save_state)
 		LLDynamicTexture::destroyGL();
 		stop_glerror();
 
-		gPipeline.destroyGL();
+		if (gPipeline.isInit())
+		{
+			gPipeline.destroyGL();
+		}
 		
 		gCone.cleanupGL();
 		gBox.cleanupGL();
@@ -4799,6 +4924,8 @@ void LLViewerWindow::restoreGL(const LLString& progress_message)
 		LLDynamicTexture::restoreGL();
 		LLVOAvatar::restoreGL();
 
+		gResizeScreenTexture = TRUE;
+
 		if (gFloaterCustomize && gFloaterCustomize->getVisible())
 		{
 			LLVisualParamHint::requestHintUpdates();
@@ -4893,11 +5020,20 @@ BOOL LLViewerWindow::checkSettings()
 			return FALSE;
 		}
 		
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+#endif
 		gViewerWindow->changeDisplaySettings(TRUE, 
 											 LLCoordScreen(gSavedSettings.getS32("FullScreenWidth"),
 														   gSavedSettings.getS32("FullScreenHeight")),
 											 gSavedSettings.getBOOL("DisableVerticalSync"),
 											 mShowFullscreenProgress);
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+#endif
 		return TRUE;
 	}
 	return FALSE;
@@ -4924,6 +5060,8 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 	mShowFullscreenProgress = show_progress_bar;
 	gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
 
+	gResizeScreenTexture = TRUE;
+
 	BOOL old_fullscreen = mWindow->getFullscreen();
 	if (!old_fullscreen && fullscreen && !LLStartUp::canGoFullscreen())
 	{
@@ -5067,6 +5205,8 @@ void LLViewerWindow::drawPickBuffer() const
 {
 	if (mPickBuffer)
 	{
+		gGL.start();
+		gGL.pushMatrix();
 		LLGLDisable no_blend(GL_BLEND);
 		LLGLDisable no_alpha_test(GL_ALPHA_TEST);
 		LLGLSNoTexture no_texture;
@@ -5075,7 +5215,7 @@ void LLViewerWindow::drawPickBuffer() const
 			((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
 		glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
 		glPixelZoom(1.f, 1.f);
-		glColor4fv(LLColor4::white.mV);
+		gGL.color4fv(LLColor4::white.mV);
 		gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)), 
 			llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
 			llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
@@ -5089,7 +5229,7 @@ void LLViewerWindow::drawPickBuffer() const
 			llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
 			llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f), 
 			llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
-		glTranslatef(10.f, 10.f, 0.f);
+		gGL.translatef(10.f, 10.f, 0.f);
 		gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), 
 			llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f),
 			llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f),
@@ -5100,7 +5240,8 @@ void LLViewerWindow::drawPickBuffer() const
 			llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX + 1) * 10.f),
 			llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH  + mPickOffset.mY) * 10.f),
 			FALSE);
-		glPopMatrix();
+		gGL.popMatrix();
+		gGL.stop();
 	}
 }
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 1053234e8fb..f040ca62d31 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -61,6 +61,8 @@ class LLTextBox;
 class LLImageRaw;
 class LLHUDIcon;
 
+#define MAX_IMAGE_SIZE 6144 //6 * 1024, max snapshot image size 6144 * 6144
+
 class LLViewerWindow : public LLWindowCallbacks
 {
 public:
@@ -219,8 +221,8 @@ class LLViewerWindow : public LLWindowCallbacks
 	} ESnapshotType;
 
 	BOOL			saveSnapshot(const LLString&  filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR);
-	BOOL			rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, 
-								BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR );
+	BOOL			rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE,
+								BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_IMAGE_SIZE );
 	BOOL		    saveImageNumbered(LLImageRaw *raw, const LLString& extension = LLString());
 
 	void			playSnapshotAnimAndSound();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 90e61426e96..99cf3a80460 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -37,6 +37,7 @@
 
 #include "llvoavatar.h"
 
+#include "llglimmediate.h"
 #include "audioengine.h"
 #include "imageids.h"
 #include "indra_constants.h"
@@ -113,6 +114,7 @@
 #include "llwearablelist.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llglslshader.h"
 #include "llappviewer.h"
 #include "lscript_byteformat.h"
@@ -255,6 +257,7 @@ S32 LLVOAvatar::sMaxOtherAvatarsToComposite = 1;  // Only this many avatars (oth
 LLMap< LLGLenum, LLGLuint*> LLVOAvatar::sScratchTexNames;
 LLMap< LLGLenum, F32*> LLVOAvatar::sScratchTexLastBindTime;
 S32 LLVOAvatar::sScratchTexBytes = 0;
+F32 LLVOAvatar::sRenderDistance = 256.f;
 S32	LLVOAvatar::sNumVisibleAvatars = 0;
 S32	LLVOAvatar::sNumLODChangesThisFrame = 0;
 
@@ -279,8 +282,8 @@ BOOL LLVOAvatar::sShowAnimationDebug = FALSE;
 BOOL LLVOAvatar::sShowFootPlane = FALSE;
 BOOL LLVOAvatar::sShowCollisionVolumes = FALSE;
 BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
-BOOL LLVOAvatar::sAvatarLoadTest = FALSE;
 F32 LLVOAvatar::sLODFactor = 1.f;
+BOOL LLVOAvatar::sUseImpostors = TRUE;
 BOOL LLVOAvatar::sJointDebug = FALSE;
 
 S32 LLVOAvatar::sCurJoint = 0;
@@ -679,7 +682,9 @@ LLVOAvatar::LLVOAvatar(
 	mCulled( FALSE ),
 	mTexSkinColor( NULL ),
 	mTexHairColor( NULL ),
-	mTexEyeColor( NULL )
+	mTexEyeColor( NULL ),
+	mNeedsSkin(FALSE),
+	mUpdatePeriod(1)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
 	
@@ -730,6 +735,11 @@ LLVOAvatar::LLVOAvatar(
 		mIsSelf = FALSE;
 	}
 
+	mNeedsImpostorUpdate = TRUE;
+	mNeedsAnimUpdate = TRUE;
+
+	mImpostorDistance = 0;
+
 	setNumTEs(TEX_NUM_ENTRIES);
 
 	mbCanSelect = TRUE;
@@ -1270,16 +1280,6 @@ void LLVOAvatar::dumpBakedStatus()
 	}
 }
 
-//static
-void LLVOAvatar::cleanupVertexPrograms()
-{
-}
-
-//static
-void LLVOAvatar::initVertexPrograms()
-{
-}
-
 //static
 void LLVOAvatar::restoreGL()
 {
@@ -1301,7 +1301,19 @@ void LLVOAvatar::restoreGL()
 void LLVOAvatar::destroyGL()
 {
 	deleteCachedImages();
-	cleanupVertexPrograms();
+
+	resetImpostors();
+}
+
+//static
+void LLVOAvatar::resetImpostors()
+{
+	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+		iter != LLCharacter::sInstances.end(); ++iter)
+	{
+		LLVOAvatar* avatar = (LLVOAvatar*) *iter;
+		avatar->mImpostor.release();
+	}
 }
 
 // static
@@ -1454,17 +1466,106 @@ void LLVOAvatar::cleanupClass()
 	sXMLTree.cleanup();
 }
 
+const LLVector3 LLVOAvatar::getRenderPosition() const
+{
+	if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
+	{
+		return getPositionAgent();
+	}
+	else if (isRoot())
+	{
+		return mDrawable->getPositionAgent();
+	}
+	else
+	{
+		return getPosition() * mDrawable->getParent()->getRenderMatrix();
+	}
+}
+
+void LLVOAvatar::updateDrawable(BOOL force_damped)
+{
+	clearChanged(SHIFTED);
+}
+
+void LLVOAvatar::onShift(const LLVector3& shift_vector)
+{
+	mLastAnimExtents[0] += shift_vector;
+	mLastAnimExtents[1] += shift_vector;
+	mNeedsImpostorUpdate = TRUE;
+	mNeedsAnimUpdate = TRUE;
+}
 
 void LLVOAvatar::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
 {
-	LLVector3 center = getRenderPosition();
-	LLVector3 size = getScale();
-	//maximum amount an animation can move avatar from drawable position
-	LLVector3 animation_buffer(5, 5, 5);
+	if (isImpostor() && !needsImpostorUpdate())
+	{
+		LLVector3 delta = getRenderPosition() -
+			((LLVector3(mDrawable->getPositionGroup())-mImpostorOffset));
+		
+		newMin = mLastAnimExtents[0] + delta;
+		newMax = mLastAnimExtents[1] + delta;
+	}
+	else
+	{
+		getSpatialExtents(newMin,newMax);
+		mLastAnimExtents[0] = newMin;
+		mLastAnimExtents[1] = newMax;
+		LLVector3 pos_group = (newMin+newMax)*0.5f;
+		mImpostorOffset = pos_group-getRenderPosition();
+		mDrawable->setPositionGroup(pos_group);
+	}
+}
+
+void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+{
+	LLVector3 buffer(0.25f, 0.25f, 0.25f);
+	LLVector3 pos = getRenderPosition();
+	newMin = pos - buffer;
+	newMax = pos + buffer;
+	
+	//stretch bounding box by joint positions
+	for (mesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i)
+	{
+		LLPolyMesh* mesh = i->second;
+		for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
+		{
+			update_min_max(newMin, newMax, 
+							mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation());
+		}
+	}
 
-	newMin.setVec((center-size)-animation_buffer);
-	newMax.setVec(center+size+animation_buffer);
-	mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+	//stretch bounding box by attachments
+	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
+		iter != mAttachmentPoints.end();
+		++iter)
+	{
+		LLViewerJointAttachment* attachment = iter->second;
+
+		if(!attachment->getValid())
+		{
+			continue ;
+		}
+
+		LLViewerObject* object = attachment->getObject();
+		if (object && !object->isHUDAttachment())
+		{
+			LLDrawable* drawable = object->mDrawable;
+			if (drawable)
+			{
+				LLSpatialBridge* bridge = drawable->getSpatialBridge();
+				if (bridge)
+				{
+					const LLVector3* ext = bridge->getSpatialExtents();
+					update_min_max(newMin,newMax,ext[0]);
+					update_min_max(newMin,newMax,ext[1]);
+				}
+			}
+		}
+	}
+
+	//pad bounding box	
+	newMin -= buffer;
+	newMax += buffer;
 }
 
 
@@ -2080,6 +2181,7 @@ void LLVOAvatar::updateMeshData()
 {
 	if (mDrawable.notNull())
 	{
+		stop_glerror();
 		LLFace* facep = mDrawable->getFace(0);
 
 		U32 num_vertices = 0;
@@ -2102,6 +2204,7 @@ void LLVOAvatar::updateMeshData()
 
 		facep->mVertexBuffer = new LLVertexBufferAvatar();
 		facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE);
+
 		facep->setGeomIndex(0);
 		facep->setIndicesIndex(0);
 		
@@ -2120,6 +2223,9 @@ void LLVOAvatar::updateMeshData()
 		mSkirtLOD.updateFaceData(facep, mAdjustedPixelArea);
 		mUpperBodyLOD.updateFaceData(facep, mAdjustedPixelArea);
 		mHairLOD.updateFaceData(facep, mAdjustedPixelArea, TRUE);
+
+		stop_glerror();
+		facep->mVertexBuffer->setBuffer(0);
 	}
 }
 
@@ -2286,9 +2392,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	// force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
 	setPixelAreaAndAngle(gAgent);
 
-	// Update the LOD of the joints
-	//static const F32 UPDATE_TIME = .5f;
- 	
 	// force asynchronous drawable update
 	if(mDrawable.notNull() && !gNoRender)
 	{	
@@ -2346,86 +2449,87 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	// store off last frame's root position to be consistent with camera position
 	LLVector3 root_pos_last = mRoot.getWorldPosition();
 
-	updateCharacter(agent);
-	
-	//Ventrella
-	bool voiceEnabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel();
-	// disable voice visualizer when in mouselook
-	mVoiceVisualizer->setVoiceEnabled( voiceEnabled && !(mIsSelf && gAgent.cameraMouselook()) );
-	if ( voiceEnabled )
-	{		
-		//----------------------------------------------------------------
-		// Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
-		//----------------------------------------------------------------
-		if( mIsSelf )
-		{
-			//----------------------------------------------------------------------------------------
-			// The following takes the voice signal and uses that to trigger gesticulations. 
-			//----------------------------------------------------------------------------------------
-			int lastGesticulationLevel = mCurrentGesticulationLevel;
-			mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel();
-			
-			//---------------------------------------------------------------------------------------------------
-			// If "current gesticulation level" changes, we catch this, and trigger the new gesture
-			//---------------------------------------------------------------------------------------------------
-			if ( lastGesticulationLevel != mCurrentGesticulationLevel )
+	BOOL detailed_update = updateCharacter(agent);
+
+	{
+		//Ventrella
+		bool voiceEnabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel();
+		// disable voice visualizer when in mouselook
+		mVoiceVisualizer->setVoiceEnabled( voiceEnabled && !(mIsSelf && gAgent.cameraMouselook()) );
+		if ( voiceEnabled )
+		{		
+			//----------------------------------------------------------------
+			// Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
+			//----------------------------------------------------------------
+			if( mIsSelf )
 			{
-				if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF )
+				//----------------------------------------------------------------------------------------
+				// The following takes the voice signal and uses that to trigger gesticulations. 
+				//----------------------------------------------------------------------------------------
+				int lastGesticulationLevel = mCurrentGesticulationLevel;
+				mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel();
+				
+				//---------------------------------------------------------------------------------------------------
+				// If "current gesticulation level" changes, we catch this, and trigger the new gesture
+				//---------------------------------------------------------------------------------------------------
+				if ( lastGesticulationLevel != mCurrentGesticulationLevel )
 				{
-					LLString gestureString = "unInitialized";
-							if ( mCurrentGesticulationLevel == 0 )	{ gestureString = "/voicelevel1";	}
-					else	if ( mCurrentGesticulationLevel == 1 )	{ gestureString = "/voicelevel2";	}
-					else	if ( mCurrentGesticulationLevel == 2 )	{ gestureString = "/voicelevel3";	}
-					else	{ printf( "oops - CurrentGesticulationLevel can be only 0, 1, or 2\n" ); }
-					
-					// this is the call that Karl S. created for triggering gestures from within the code.
-					gGestureManager.triggerAndReviseString( gestureString );
+					if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF )
+					{
+						LLString gestureString = "unInitialized";
+								if ( mCurrentGesticulationLevel == 0 )	{ gestureString = "/voicelevel1";	}
+						else	if ( mCurrentGesticulationLevel == 1 )	{ gestureString = "/voicelevel2";	}
+						else	if ( mCurrentGesticulationLevel == 2 )	{ gestureString = "/voicelevel3";	}
+						else	{ llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2"  << llendl; }
+						
+						// this is the call that Karl S. created for triggering gestures from within the code.
+						gGestureManager.triggerAndReviseString( gestureString );
+					}
 				}
-			}
-			
-		} //if( mIsSelf )
-
-		//-----------------------------------------------------------------------------------------------------------------
-		// If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer.
-		// Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol.
-		//
-		// Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
-		// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. 
-		//-----------------------------------------------------------------------------------------------------------------
-		if ( gVoiceClient->getIsSpeaking( mID ) )
-		{
-			if ( ! mVoiceVisualizer->getCurrentlySpeaking() )
-			{
-				mVoiceVisualizer->setStartSpeaking();
 				
-				//printf( "gAwayTimer.reset();\n" );
-			}
+			} //if( mIsSelf )
+
+			//-----------------------------------------------------------------------------------------------------------------
+			// If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer.
+			// Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol.
+			//
+			// Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
+			// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. 
+			//-----------------------------------------------------------------------------------------------------------------
+			if ( gVoiceClient->getIsSpeaking( mID ) )
+			{
+				if ( ! mVoiceVisualizer->getCurrentlySpeaking() )
+				{
+					mVoiceVisualizer->setStartSpeaking();
+					
+					//printf( "gAwayTimer.reset();\n" );
+				}
 
-			mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) );
+				mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) );
 
-			if( mIsSelf )
-			{
-				gAgent.clearAFK();
+				if( mIsSelf )
+				{
+					gAgent.clearAFK();
+				}
 			}
-		}
-		else
-		{
-			if ( mVoiceVisualizer->getCurrentlySpeaking() )
+			else
 			{
-				mVoiceVisualizer->setStopSpeaking();
+				if ( mVoiceVisualizer->getCurrentlySpeaking() )
+				{
+					mVoiceVisualizer->setStopSpeaking();
+				}
 			}
-		}
 
-		//--------------------------------------------------------------------------------------------
-		// here we get the approximate head position and set as sound source for the voice symbol
-		// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
-		//--------------------------------------------------------------------------------------------
-		LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
-		mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
+			//--------------------------------------------------------------------------------------------
+			// here we get the approximate head position and set as sound source for the voice symbol
+			// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
+			//--------------------------------------------------------------------------------------------
+			LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
+			mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
 
-	}//if ( voiceEnabled )
+		}//if ( voiceEnabled )
+	}
 	//End  Ventrella
-	
 		
 	if (LLVOAvatar::sJointDebug)
 	{
@@ -2446,7 +2550,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_SHADOW, TRUE);
 	}
 
+	BOOL visible = isVisible() || mNeedsAnimUpdate;
+
 	// update attachments positions
+	if (detailed_update || !sUseImpostors)
 	{
 		LLFastTimer t(LLFastTimer::FTM_ATTACHMENT_UPDATE);
 		for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
@@ -2456,8 +2563,9 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 			LLViewerJointAttachment* attachment = curiter->second;
 			LLViewerObject *attached_object = attachment->getObject();
 
-			BOOL visibleAttachment = isVisible() || !(attached_object && attached_object->mDrawable->getSpatialBridge()
-										  && (attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
+			BOOL visibleAttachment = visible || (attached_object && 
+												!(attached_object->mDrawable->getSpatialBridge() &&
+												  attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
 
 			if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
 			{
@@ -2470,10 +2578,61 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 				{
 					gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
 				}
-				attached_object->updateText();
+
+				LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
+				if (bridge)
+				{
+					gPipeline.updateMoveNormalAsync(bridge);
+				}
+				attached_object->updateText();	
 			}
 		}
 	}
+
+	mNeedsAnimUpdate = FALSE;
+
+	if (isImpostor() && !mNeedsImpostorUpdate)
+	{
+		LLVector3 ext[2];
+		F32 distance;
+		LLVector3 angle;
+
+		getImpostorValues(ext, angle, distance);
+
+		for (U32 i = 0; i < 3 && !mNeedsImpostorUpdate; i++)
+		{
+			F32 cur_angle = angle.mV[i];
+			F32 old_angle = mImpostorAngle.mV[i];
+			F32 angle_diff = fabsf(cur_angle-old_angle);
+		
+			if (angle_diff > 3.14159f/16.f)
+			{
+				mNeedsImpostorUpdate = TRUE;
+			}
+		}
+
+		if (detailed_update && !mNeedsImpostorUpdate)
+		{	//update impostor if view angle, distance, or bounding box change
+			//significantly
+			
+			F32 dist_diff = fabsf(distance-mImpostorDistance);
+			if (dist_diff/mImpostorDistance > 0.1f)
+			{
+				mNeedsImpostorUpdate = TRUE;
+			}
+			else
+			{
+				getSpatialExtents(ext[0], ext[1]);
+				if ((ext[1]-mImpostorExtents[1]).magVec() > 0.05f ||
+					(ext[0]-mImpostorExtents[0]).magVec() > 0.05f)
+				{
+					mNeedsImpostorUpdate = TRUE;
+				}
+			}
+		}
+	}
+
+	mDrawable->movePartition();
 	
 	//force a move if sitting on an active object
 	if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
@@ -2613,7 +2772,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
 	BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
 	BOOL render_name =	visible_chat ||
-						(isVisible() &&
+						(visible &&
 						((sRenderName == RENDER_NAME_ALWAYS) ||
 						(sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
 	// If it's your own avatar, don't draw in mouselook, and don't
@@ -2996,10 +3155,9 @@ void LLVOAvatar::slamPosition()
 // updateCharacter()
 // called on both your avatar and other avatars
 //------------------------------------------------------------------------
-void LLVOAvatar::updateCharacter(LLAgent &agent)
+BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
-
 	// update screen joint size
 	if (mScreenp)
 	{
@@ -3045,7 +3203,7 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 		{
 			gAgent.setPositionAgent(getPositionAgent());
 		}
-		return;
+		return FALSE;
 	}
 
 
@@ -3053,19 +3211,51 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 
 	if (!mIsBuilt)
 	{
-		return;
+		return FALSE;
 	}
 
+	BOOL visible = isVisible();
+
 	// For fading out the names above heads, only let the timer
 	// run if we're visible.
-	if (mDrawable.notNull() && !mDrawable->isVisible())
+	if (mDrawable.notNull() && !visible)
 	{
 		mTimeVisible.reset();
 	}
 
-	if (!mIsSelf && !isVisible())
+
+	//--------------------------------------------------------------------
+	// the rest should only be done occasionally for far away avatars
+	//--------------------------------------------------------------------
+
+	if (!mIsSelf && sUseImpostors && !mNeedsAnimUpdate)
 	{
-		return;
+		F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
+		if (visible && mPixelArea <= impostor_area)
+		{
+			mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mPixelArea), 2, 8);
+
+			visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
+		}
+		else
+		{
+			mUpdatePeriod = 1;
+		}
+
+		if (!visible)
+		{
+			if (!mMotionController.isPaused())
+			{
+				mMotionController.pause();
+				mMotionController.updateMotion();
+				mMotionController.unpause();
+			}
+			else
+			{			
+				mMotionController.updateMotion();
+			}
+			return FALSE;
+		}
 	}
 
 	// change animation time quanta based on avatar render load
@@ -3336,27 +3526,6 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 		mRoot.setRotation(mDrawable->getRotation());
 	}
 	
-	//--------------------------------------------------------------------
-	// the rest should only be done when close enough to see it
-	//--------------------------------------------------------------------
-	
-
-	if (mPixelArea > 12.0f)
-		throttle = FALSE;
-	if (mPixelArea < 400.0f)
-	{
-		throttle = (LLDrawable::getCurrentFrame()+mID.mData[0])%2 != 0;
-	}
-
-	if ( !(mIsSitting && getParent()) && 
-		(throttle || 
-		(!isVisible() && (mPixelArea < MIN_PIXEL_AREA_FOR_COMPOSITE))) )
-	{
-		mRoot.setWorldRotation( getRotation() );
-		mRoot.updateWorldMatrixChildren();
-		return;
-	}
-
 	//-------------------------------------------------------------------------
 	// Update character motions
 	//-------------------------------------------------------------------------
@@ -3494,6 +3663,11 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 	{
 		setDebugText(mDebugText);
 	}
+
+	//mesh vertices need to be reskinned
+	mNeedsSkin = TRUE;
+
+	return TRUE;
 }
 
 //-----------------------------------------------------------------------------
@@ -3524,7 +3698,7 @@ void LLVOAvatar::updateHeadOffset()
 //------------------------------------------------------------------------
 // updateVisibility()
 //------------------------------------------------------------------------
-void LLVOAvatar::updateVisibility(BOOL force_invisible)
+void LLVOAvatar::updateVisibility()
 {
 	BOOL visible = FALSE;
 
@@ -3536,7 +3710,7 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible)
 	{
 		visible = FALSE;
 	}
-	else if (!force_invisible)
+	else
 	{
 		// calculate avatar distance wrt head
 		mDrawable->updateDistance(*gCamera);
@@ -3658,48 +3832,6 @@ void LLVOAvatar::updateVisibility(BOOL force_invisible)
 	mVisible = visible;
 }
 
-//------------------------------------------------------------------------
-// updateAllVisibility()
-//------------------------------------------------------------------------
-//static
-void LLVOAvatar::updateAllAvatarVisiblity()
-{
-	LLVOAvatar::sNumVisibleAvatars = 0;
-	
-	F32 render_priority = (F32)LLVOAvatar::sMaxVisible;
-	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
-		iter != LLCharacter::sInstances.end(); ++iter)
-	{
-		LLVOAvatar* avatarp = (LLVOAvatar*) *iter;
-		if (avatarp->isDead())
-		{
-			continue;
-		}
-		if (avatarp->isSelf())
-		{
-			avatarp->mRenderPriority = 1000.f;
-		}
-		else
-		{
-			avatarp->mRenderPriority = render_priority * 10.f; // 500 -> 10
-			if (render_priority > 0.f)
-			{
-				render_priority -= 1.f;
-			}
-		}
-		avatarp->updateVisibility(LLVOAvatar::sNumVisibleAvatars > LLVOAvatar::sMaxVisible);
-
-		if (avatarp->mDrawable.isNull())
-		{
-			llwarns << "Avatar with no drawable" << llendl;
-		}
-		else if (avatarp->mDrawable->isVisible())
-		{
-			LLVOAvatar::sNumVisibleAvatars++;
-		}
-	}
-}
-
 //------------------------------------------------------------------------
 // needsRenderBeam()
 //------------------------------------------------------------------------
@@ -3733,6 +3865,47 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		return num_indices;
 	}
 
+	if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
+	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
+		updateMeshData();
+        mDirtyMesh = FALSE;
+		mNeedsSkin = TRUE;
+		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
+	}
+
+	if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) <= 0)
+	{
+		if (mNeedsSkin)
+		{
+			//generate animated mesh
+			mLowerBodyLOD.updateGeometry();
+			mUpperBodyLOD.updateGeometry();
+
+			if( isWearingWearableType( WT_SKIRT ) )
+			{
+				mSkirtLOD.updateGeometry();
+			}
+
+			if (!mIsSelf || gAgent.needsRenderHead())
+			{
+				mEyeLashLOD.updateGeometry();
+				mHeadLOD.updateGeometry();
+				mHairLOD.updateGeometry();
+			}
+			mNeedsSkin = FALSE;
+			
+			LLVertexBuffer* vb = mDrawable->getFace(0)->mVertexBuffer;
+			if (vb)
+			{
+				vb->setBuffer(0);
+			}
+		}
+	}
+	else
+	{
+		mNeedsSkin = FALSE;
+	}
+
 	if (sDebugInvisible)
 	{
 		LLNameValue* firstname = getNVPair("FirstName");
@@ -3777,27 +3950,27 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		LLVector3 collide_point = slaved_pos;
 		collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE);
 
-		glBegin(GL_LINES);
+		gGL.begin(GL_LINES);
 		{
 			F32 SQUARE_SIZE = 0.2f;
-			glColor4f(1.f, 0.f, 0.f, 1.f);
+			gGL.color4f(1.f, 0.f, 0.f, 1.f);
 			
-			glVertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-			glVertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
 
-			glVertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-			glVertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
 			
-			glVertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			glVertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
 			
-			glVertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-			glVertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
 			
-			glVertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]);
-			glVertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]);
+			gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]);
 
-		}glEnd();
+		}gGL.end();
 	}
 	//--------------------------------------------------------------------
 	// render all geomety attached to the skeleton
@@ -3823,41 +3996,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 			num_indices += renderTransparent();
 		}
 	}
-	/*else if (pass == AVATAR_RENDER_PASS_CLOTHING_INNER)
-	{
-		if (!mIsSelf || gAgent.needsRenderHead())
-		{
-			num_indices += mHeadLOD.render(mAdjustedPixelArea);
-		}
-		LLViewerJointMesh::sClothingInnerColor = mTexSkinColor->getColor() * 0.5f;
-		LLViewerJointMesh::sClothingMaskImageName = mUpperMaskTexName;
-		num_indices += mUpperBodyLOD.render(mAdjustedPixelArea);
-		LLViewerJointMesh::sClothingMaskImageName = mLowerMaskTexName;
-		num_indices += mLowerBodyLOD.render(mAdjustedPixelArea);
-		LLViewerJointMesh::sClothingMaskImageName = 0;
-		if( isWearingWearableType( WT_SKIRT ) )
-		{
-			glAlphaFunc(GL_GREATER,0.25f);
-			num_indices += mSkirtLOD.render(mAdjustedPixelArea);
-			glAlphaFunc(GL_GREATER,0.01f);
-		}
-
-		if (!mIsSelf || gAgent.needsRenderHead())
-		{
-			num_indices += mEyeLashLOD.render(mAdjustedPixelArea);
-			num_indices += mHairLOD.render(mAdjustedPixelArea);
-		}
-	}
-	else if (pass == AVATAR_RENDER_PASS_CLOTHING_OUTER)
-	{
-		LLViewerJointMesh::sClothingInnerColor = mTexSkinColor->getColor() * 0.5f;
-		LLViewerJointMesh::sClothingMaskImageName = mUpperMaskTexName;
-		num_indices += mUpperBodyLOD.render(mAdjustedPixelArea);
-		LLViewerJointMesh::sClothingMaskImageName = mLowerMaskTexName;
-		num_indices += mLowerBodyLOD.render(mAdjustedPixelArea);
-		LLViewerJointMesh::sClothingMaskImageName = 0;
-	}*/
-
+	
 	LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
 	
 	//llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl;
@@ -3881,8 +4020,16 @@ U32 LLVOAvatar::renderTransparent()
 
 	if (!mIsSelf || gAgent.needsRenderHead())
 	{
+		if (LLPipeline::sImpostorRender)
+		{
+			glAlphaFunc(GL_GREATER, 0.5f);
+		}
 		num_indices += mEyeLashLOD.render(mAdjustedPixelArea, first_pass);
 		num_indices += mHairLOD.render(mAdjustedPixelArea, FALSE);
+		if (LLPipeline::sImpostorRender)
+		{
+			glAlphaFunc(GL_GREATER, 0.01f);
+		}
 	}
 
 	return num_indices;
@@ -3935,9 +4082,17 @@ U32 LLVOAvatar::renderFootShadows()
 		return 0;
 	}
 
+	// Update the shadow, tractor, and text label geometry.
+	if (mDrawable->isState(LLDrawable::REBUILD_SHADOW) && !isImpostor())
+	{
+		updateShadowFaces();
+		mDrawable->clearState(LLDrawable::REBUILD_SHADOW);
+	}
+
 	U32 foot_mask = LLVertexBuffer::MAP_VERTEX |
 					LLVertexBuffer::MAP_TEXCOORD;
 
+	LLGLDepthTest test(GL_TRUE, GL_FALSE);
 	//render foot shadows
 	LLGLEnable blend(GL_BLEND);
 	mShadowImagep->bind();
@@ -3949,6 +4104,38 @@ U32 LLVOAvatar::renderFootShadows()
 	return num_indices;
 }
 
+U32 LLVOAvatar::renderImpostor(LLColor4U color)
+{
+	if (!mImpostor.isComplete())
+	{
+		return 0;
+	}
+
+	LLVector3 pos(getRenderPosition()+mImpostorOffset);
+	LLVector3 left = gCamera->getLeftAxis()*mImpostorDim.mV[0];
+	LLVector3 up = gCamera->getUpAxis()*mImpostorDim.mV[1];
+
+	LLGLEnable test(GL_ALPHA_TEST);
+	glAlphaFunc(GL_GREATER, 0.f);
+
+	gGL.start();
+	gGL.color4ubv(color.mV);
+	mImpostor.bindTexture();
+	gGL.begin(GL_QUADS);
+	gGL.texCoord2f(0,0);
+	gGL.vertex3fv((pos+left-up).mV);
+	gGL.texCoord2f(1,0);
+	gGL.vertex3fv((pos-left-up).mV);
+	gGL.texCoord2f(1,1);
+	gGL.vertex3fv((pos-left+up).mV);
+	gGL.texCoord2f(0,1);
+	gGL.vertex3fv((pos+left+up).mV);
+	gGL.end();
+	gGL.stop();
+
+	return 6;
+}
+
 //-----------------------------------------------------------------------------
 // renderCollisionVolumes()
 //-----------------------------------------------------------------------------
@@ -3965,7 +4152,6 @@ void LLVOAvatar::renderCollisionVolumes()
 //------------------------------------------------------------------------
 void LLVOAvatar::updateTextures(LLAgent &agent)
 {
-// 	LLFastTimer ftm(LLFastTimer::FTM_TEMP5);
 	BOOL render_avatar = TRUE;
 
 	if (mIsDummy || gNoRender)
@@ -5423,38 +5609,23 @@ BOOL LLVOAvatar::isActive() const
 void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
-		
-	F32 max_scale = getMaxScale();
-	F32 mid_scale = getMidScale();
-	F32 min_scale = llmin( getScale().mV[VX], llmin( getScale().mV[VY], getScale().mV[VZ] ) );
 
-	// IW: esitmate - when close to large objects, computing range based on distance from center is no good
-	// to try to get a min distance from face, subtract min_scale/2 from the range.
-	// This means we'll load too much detail sometimes, but that's better than not enough
-	// I don't think there's a better way to do this without calculating distance per-poly
-	F32 range = (getRenderPosition()-gCamera->getOrigin()).magVec() - min_scale/2;
+	const LLVector3* ext = mDrawable->getSpatialExtents();
+	LLVector3 center = (ext[1] + ext[0]) * 0.5f;
+	LLVector3 size = (ext[1]-ext[0])*0.5f;
+
+	mPixelArea = LLPipeline::calcPixelArea(center, size, *gCamera);
+
+	F32 range = mDrawable->mDistanceWRTCamera;
 
 	if (range < 0.001f)		// range == zero
 	{
 		mAppAngle = 180.f;
-		mPixelArea =	gCamera->getViewHeightInPixels() * 
-						gCamera->getViewHeightInPixels() *  
-						gCamera->getAspect();
 	}
 	else
 	{
-		mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
-
-		F32 pixels_per_meter = gCamera->getPixelMeterRatio() / range;
-
-		mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale);
-//		if( !mIsSelf )
-//		{
-//			llinfos << "range " << range << llendl;
-//			llinfos << "pixels_per_meter " << pixels_per_meter << llendl;
-//			llinfos << "scale " << max_scale << "x" << mid_scale << llendl;
-//			llinfos << "pixel area " << mPixelArea << llendl;
-//		}
+		F32 radius = size.magVec();
+		mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG;
 	}
 
 	// We always want to look good to ourselves
@@ -5567,10 +5738,11 @@ void LLVOAvatar::updateShadowFaces()
 {
 	LLFace *face0p = mShadow0Facep;
 	LLFace *face1p = mShadow1Facep;
+
 	//
 	// render avatar shadows
 	//
-	if (mInAir)
+	if (mInAir || mUpdatePeriod >= VOAVATAR_IMPOSTOR_PERIOD)
 	{
 		face0p->setSize(0, 0);
 		face1p->setSize(0, 0);
@@ -5583,7 +5755,7 @@ void LLVOAvatar::updateShadowFaces()
 	F32 cos_elev = sqrt(1 - cos_angle * cos_angle);
 	if (cos_angle < 0) cos_elev = -cos_elev;
 	sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f);
-	LLVector3 sun_vec = gSky.mVOSkyp->getToSun();
+	LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f);
 
 	if (mShadowImagep->getHasGLTexture())
 	{
@@ -5771,7 +5943,14 @@ void LLVOAvatar::setParent(LLViewerObject* parent)
 void LLVOAvatar::addChild(LLViewerObject *childp)
 {
 	LLViewerObject::addChild(childp);
-	attachObject(childp);
+	if (childp->mDrawable)
+	{
+		attachObject(childp);
+	}
+	else
+	{
+		mPendingAttachment.push_back(childp);
+	}
 }
 
 void LLVOAvatar::removeChild(LLViewerObject *childp)
@@ -5829,20 +6008,15 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object)
 //-----------------------------------------------------------------------------
 void LLVOAvatar::lazyAttach()
 {
-	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
-		 iter != mAttachmentPoints.end(); )
+	for (U32 i = 0; i < mPendingAttachment.size(); i++)
 	{
-		attachment_map_t::iterator curiter = iter++;
-		LLViewerJointAttachment* attachment = curiter->second;
-		if (attachment->getAttachmentDirty())
+		if (mPendingAttachment[i]->mDrawable)
 		{
-			attachment->lazyAttach();
-			if (mIsSelf)
-			{
-				updateAttachmentVisibility(gAgent.getCameraMode());
-			}
+			attachObject(mPendingAttachment[i]);
 		}
 	}
+
+	mPendingAttachment.clear();
 }
 
 void LLVOAvatar::resetHUDAttachments()
@@ -9159,253 +9333,6 @@ BOOL LLVOAvatarInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
 	return TRUE;
 }
 
-void LLVOAvatar::writeCAL3D(std::string& path, std::string& file_base)
-{
-	char filename[MAX_PATH];		/* Flawfinder: ignore */
-
-	// reset animated morphs
-	setVisualParamWeight("Blink_Left", 0.f);
-	setVisualParamWeight("Blink_Right", 0.f);
-	setVisualParamWeight("Hands_Relaxed", 1.f);
-	setVisualParamWeight("Hands_Point", 0.f);
-	setVisualParamWeight("Hands_Fist", 0.f);
-	setVisualParamWeight("Hands_Relaxed_L", 0.f);
-	setVisualParamWeight("Hands_Point_L", 0.f);
-	setVisualParamWeight("Hands_Fist_L", 0.f);
-	setVisualParamWeight("Hands_Relaxed_R", 0.f);
-	setVisualParamWeight("Hands_Point_R", 0.f);
-	setVisualParamWeight("Hands_Fist_R", 0.f);
-	setVisualParamWeight("Hands_Salute_R", 0.f);
-	setVisualParamWeight("Hands_Typing", 0.f);
-	setVisualParamWeight("Hands_Peace_R", 0.f);
-	setVisualParamWeight("Hands_Spread_R", 0.f);
-	updateVisualParams();
-
-	snprintf(filename, MAX_PATH, "%s\\%s_skeleton.xsf", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-	apr_file_t* fp = ll_apr_file_open(filename, LL_APR_W);
-	if (!fp)
-	{
-		llwarns << "Unable to write avatar file " << filename << llendl;
-		return;
-	}
-	apr_file_printf(fp, "<SKELETON VERSION=\"1000\" NUMBONES=\"%d\">\n", sSkeletonInfo->getNumBones() - sSkeletonInfo->getNumCollisionVolumes());
-	mRoot.writeCAL3D(fp);
-	apr_file_printf(fp, "</SKELETON>\n");
-	apr_file_close(fp);
-
-	snprintf(filename, MAX_PATH, "%s\\%s_mesh_body.xmf", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-	//gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"avatar.cal").c_str()
-	fp = ll_apr_file_open(filename, LL_APR_W);
-	if (!fp)
-	{
-		llwarns << "Unable to write avatar file " << filename << llendl;
-		return;
-	}
-
-	BOOL has_skirt = isWearingWearableType(WT_SKIRT);
-
-	apr_file_printf(fp, "<MESH VERSION=\"1000\" NUMSUBMESH=\"%d\">\n", has_skirt ? 8 : 7);
-	mHairMesh0.writeCAL3D(fp, 5, this);
-	mHeadMesh0.writeCAL3D(fp, 0, this);
-	mEyeLashMesh0.writeCAL3D(fp, 0, this);
-	mUpperBodyMesh0.writeCAL3D(fp, 1, this);
-	mLowerBodyMesh0.writeCAL3D(fp, 2, this);
-	mEyeBallLeftMesh0.writeCAL3D(fp, 3, this);
-	mEyeBallRightMesh0.writeCAL3D(fp, 3, this);
-	if (has_skirt)
-	{
-		mSkirtMesh0.writeCAL3D(fp, 4, this);
-	}
-	apr_file_printf(fp, "</MESH>\n");
-	apr_file_close(fp);
-
-	// write out material files
-	LLPointer<LLImageTGA> tga_image = new LLImageTGA;
-
-	for (S32 i = 0; i < (has_skirt ? BAKED_TEXTURE_COUNT : BAKED_TEXTURE_COUNT - 1); i++)
-	{
-		snprintf(filename, MAX_PATH, "%s\\%s_material_tex_%d.tga", path.c_str(), file_base.c_str(), i);		/* Flawfinder: ignore */
-
-		LLViewerImage* viewer_imagep = mTEImages[sBakedTextureIndices[i]];
-		if (!viewer_imagep->getHasGLTexture())
-		{
-			llinfos << "No image data available for " << filename << llendl;
-			continue;
-		}
-		LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-		viewer_imagep->readBackRaw(-1, raw_image, false);
-		BOOL success = tga_image->encode(raw_image);
-		success = tga_image->save(filename);
-	}
-
-	// output image for hair
-	snprintf(filename, MAX_PATH, "%s\\%s_material_tex_5.tga", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-	LLViewerImage* viewer_imagep = mTEImages[TEX_HAIR];
-	if (!viewer_imagep->getHasGLTexture())
-	{
-		llinfos << "No image data available for " << filename << llendl;
-	}
-	else
-	{
-		LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-		viewer_imagep->readBackRaw(-1, raw_image, false);
-		BOOL success = tga_image->encode(raw_image);
-		success = tga_image->save(filename);
-	}
-
-	// save out attachments
-	snprintf(filename, MAX_PATH, "%s\\%s_mesh_attachments.xmf", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-	fp = ll_apr_file_open(filename, LL_APR_W);
-	if (!fp)
-	{
-		llwarns << "Unable to write attachments file " << filename << llendl;
-		return;
-	}
-
-	typedef std::multimap<LLUUID, LLMaterialExportInfo*>::iterator material_it_t;
-	std::multimap<LLUUID, LLMaterialExportInfo*> material_map;
-
-	S32 num_attachment_objects = 0;
-	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
-		 iter != mAttachmentPoints.end(); )
-	{
-		attachment_map_t::iterator curiter = iter++;
-		LLViewerJointAttachment* attachment = curiter->second;
-		LLViewerObject *attached_object = attachment->getObject();
-		if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull() &&
-			attached_object->getPCode() == LL_PCODE_VOLUME)
-		{
-			num_attachment_objects += attached_object->mDrawable->getNumFaces(); 
-			for (U32 i = 0; i < attached_object->mChildList.size(); i++)
-			{
-				LLViewerObject* child_object = attached_object->mChildList[i];
-				num_attachment_objects += child_object->mDrawable->getNumFaces();
-			}
-		}
-	}
-
-	apr_file_printf(fp, "<MESH VERSION=\"1000\" NUMSUBMESH=\"%d\">\n", num_attachment_objects);
-
-	S32 material_index = 6;
-	S32 texture_index = 6;
-	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
-		 iter != mAttachmentPoints.end(); )
-	{
-		attachment_map_t::iterator curiter = iter++;
-		LLViewerJointAttachment* attachment = curiter->second;
-		LLViewerObject *attached_object = attachment->getObject();
-		if (attached_object && !attached_object->isDead() && attached_object->getPCode() == LL_PCODE_VOLUME)
-		{
-			LLVOVolume* attached_volume = (LLVOVolume*)attached_object;
-			LLVector3 pos = attachment->getPosition();
-			LLJoint* cur_joint = attachment->getParent();
-			while (cur_joint)
-			{
-				pos += cur_joint->getSkinOffset();
-				cur_joint = (LLViewerJoint*)cur_joint->getParent();
-			}
-			pos *= 100.f;
-			S32 attached_joint_num = attachment->getParent()->mJointNum;
-			LLQuaternion rot = attachment->getRotation();
-			attached_volume->writeCAL3D(fp, path, file_base, attached_joint_num, pos, rot, material_index, texture_index, material_map);
-		}
-	}
-	apr_file_printf(fp, "</MESH>\n");
-	apr_file_close(fp);
-
-	// now dump sample animation
-	LLKeyframeMotion* walk_motion = 
-		getSex() == SEX_MALE ? (LLKeyframeMotion*)findMotion(ANIM_AGENT_WALK) : (LLKeyframeMotion*)findMotion(ANIM_AGENT_FEMALE_WALK);
-	if (FALSE)//(walk_motion)
-	{
-		snprintf(filename, MAX_PATH, "%s\\%s_anim.xaf", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-		apr_file_t* fp = ll_apr_file_open(filename, LL_APR_W);
-		if (!fp)
-		{
-			llwarns << "Unable to write avatar animation file " << filename << llendl;
-			return;
-		}
-
-		walk_motion->writeCAL3D(fp);
-
-		apr_file_close(fp);
-	}
-
-	// finally, write out .cfg file
-	snprintf(filename, MAX_PATH, "%s\\%s_avatar.cfg", path.c_str(), file_base.c_str());		/* Flawfinder: ignore */
-	fp = ll_apr_file_open(filename, LL_APR_W);
-	if (!fp)
-	{
-		llwarns << "Unable to write avatar config file " << filename << llendl;
-		return;
-	}
-
-	// this version exports animation
-	//apr_file_printf(fp, "#\n# cal3d model configuration file\n#\n# model: %s_avatar\n#\n\nscale=1.0\n\nskeleton=%s_skeleton.xsf\n\nanimation=%s_anim.xaf\n\n", file_base.c_str(), file_base.c_str(), file_base.c_str());
-	apr_file_printf(fp, "#\n# cal3d model configuration file\n#\n# model: %s_avatar\n#\n\nscale=1.0\n\nskeleton=%s_skeleton.xsf\n\n", file_base.c_str(), file_base.c_str());
-	apr_file_printf(fp, "mesh=%s_mesh_body.xmf\nmesh=%s_mesh_attachments.xmf\n", file_base.c_str(), file_base.c_str());
-
-	for (S32 i = 0; i < material_index; i++)
-	{
-		apr_file_printf(fp, "material=%s_material_%d.xrf\n", file_base.c_str(), i);
-	}
-	apr_file_close(fp);
-
-	for(S32 i = 0; i < 6; i++)
-	{
-		snprintf(filename, MAX_PATH, "%s\\%s_material_%d.xrf", path.c_str(), file_base.c_str(), i);		/* Flawfinder: ignore */
-		apr_file_t* fp = ll_apr_file_open(filename, LL_APR_W);
-		if (!fp)
-		{
-			llwarns << "Unable to write material definition file " << filename << llendl;
-			return;
-		}
-
-		// for hair material, use hair color...otherwise use white for entire body
-		LLColor4U material_color = (i == 5) ? mTexHairColor->getColor() : LLColor4U::white;
-
-		apr_file_printf(fp, "<HEADER MAGIC=\"XRF\" VERSION=\"900\" />\n<MATERIAL NUMMAPS=\"1\">\n");
-		apr_file_printf(fp, "	<AMBIENT>%d %d %d %d</AMBIENT>\n", material_color.mV[VX], material_color.mV[VY], material_color.mV[VZ], material_color.mV[VW]);
-		apr_file_printf(fp, "	<DIFFUSE>%d %d %d %d</DIFFUSE>\n", material_color.mV[VX], material_color.mV[VY], material_color.mV[VZ], material_color.mV[VW]);
-		apr_file_printf(fp, "	<SPECULAR>0 0 0 0</SPECULAR>\n");
-		apr_file_printf(fp, "	<SHININESS>1.0</SHININESS>\n");
-		apr_file_printf(fp, "	<MAP>%s_material_tex_%d.tga</MAP>\n", file_base.c_str(), i);
-		apr_file_printf(fp, "</MATERIAL>\n");
-
-		apr_file_close(fp);
-	}
-	
-	// write out material files
-	for(material_it_t material_it = material_map.begin(); material_it != material_map.end(); ++material_it)
-	{
-		LLMaterialExportInfo* export_info = material_it->second;
-
-		snprintf(filename, MAX_PATH, "%s\\%s_material_%d.xrf", path.c_str(), file_base.c_str(), export_info->mMaterialIndex);		/* Flawfinder: ignore */
-		apr_file_t* fp = ll_apr_file_open(filename, LL_APR_W);
-		if (!fp)
-		{
-			llwarns << "Unable to write material definition file " << filename << llendl;
-			return;
-		}
-
-		LLColor4U material_color = export_info->mColor;
-
-		apr_file_printf(fp, "<HEADER MAGIC=\"XRF\" VERSION=\"900\" />\n<MATERIAL NUMMAPS=\"1\">\n");
-		apr_file_printf(fp, "	<AMBIENT>%d %d %d %d</AMBIENT>\n", material_color.mV[VX], material_color.mV[VY], material_color.mV[VZ], material_color.mV[VW]);
-		apr_file_printf(fp, "	<DIFFUSE>%d %d %d %d</DIFFUSE>\n", material_color.mV[VX], material_color.mV[VY], material_color.mV[VZ], material_color.mV[VW]);
-		apr_file_printf(fp, "	<SPECULAR>0 0 0 0</SPECULAR>\n");
-		apr_file_printf(fp, "	<SHININESS>1.0</SHININESS>\n");
-		apr_file_printf(fp, "	<MAP>%s_material_tex_%d.tga</MAP>\n", file_base.c_str(), export_info->mTextureIndex);
-		apr_file_printf(fp, "</MATERIAL>\n");
-
-		apr_file_close(fp);
-	}
-
-
-	std::for_each(material_map.begin(), material_map.end(), DeletePairedPointer());
-	material_map.clear();
-}
-
 // warning: order(N) not order(1)
 S32 LLVOAvatar::getAttachmentCount()
 {
@@ -9523,40 +9450,75 @@ BOOL LLVOAvatar::updateLOD()
 	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
 		updateMeshData();
         mDirtyMesh = FALSE;
+		mNeedsSkin = TRUE;
 		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
 	}
 	
-	if (facep->getPool()->getVertexShaderLevel() <= 0)
-	{
-		//generate animated mesh
-		mLowerBodyLOD.updateGeometry();
-		mUpperBodyLOD.updateGeometry();
 
-		if( isWearingWearableType( WT_SKIRT ) )
-		{
-			mSkirtLOD.updateGeometry();
-		}
+	return res;
+}
 
-		if (!mIsSelf || gAgent.needsRenderHead())
+U32 LLVOAvatar::getPartitionType() const
+{ //avatars merely exist as drawables in the bridge partition
+	return LLViewerRegion::PARTITION_BRIDGE;
+}
+
+//static
+void LLVOAvatar::updateImpostors() 
+{
+	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+		iter != LLCharacter::sInstances.end(); ++iter)
+	{
+		LLVOAvatar* avatar = (LLVOAvatar*) *iter;
+		
+		if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor())
 		{
-			mEyeLashLOD.updateGeometry();
-			mHeadLOD.updateGeometry();
-			mHairLOD.updateGeometry();
+			gPipeline.generateImpostor(avatar);
 		}
 	}
+}
 
-	// Update the shadow, tractor, and text label geometry.
-	if (mDrawable->isState(LLDrawable::REBUILD_SHADOW))
-	{
-		updateShadowFaces();
-		mDrawable->clearState(LLDrawable::REBUILD_SHADOW);
-	}
+BOOL LLVOAvatar::isImpostor() const
+{
+	return (sUseImpostors && mUpdatePeriod >= VOAVATAR_IMPOSTOR_PERIOD) ? TRUE : FALSE;
+}
 
-	return res;
+
+BOOL LLVOAvatar::needsImpostorUpdate() const
+{
+	return mNeedsImpostorUpdate;
 }
 
-U32 LLVOAvatar::getPartitionType() const
-{ //avatars merely exist as drawables in the bridge partition
-	return LLPipeline::PARTITION_BRIDGE;
+const LLVector3& LLVOAvatar::getImpostorOffset() const
+{
+	return mImpostorOffset;
+}
+
+const LLVector2& LLVOAvatar::getImpostorDim() const
+{
+	return mImpostorDim;
+}
+
+void LLVOAvatar::setImpostorDim(const LLVector2& dim)
+{
+	mImpostorDim = dim;
+}
+
+void LLVOAvatar::cacheImpostorValues()
+{
+	getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance);
+}
+
+void LLVOAvatar::getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance)
+{
+	const LLVector3* ext = mDrawable->getSpatialExtents();
+	extents[0] = ext[0];
+	extents[1] = ext[1];
+
+	LLVector3 at = gCamera->getOrigin()-(getRenderPosition()+mImpostorOffset);
+	distance = at.normVec();
+	angle.mV[0] = acosf(at.mV[0]);
+	angle.mV[1] = acosf(at.mV[1]);
+	angle.mV[2] = acosf(at.mV[2]);
 }
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 6f262a730a5..491d991369d 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -43,7 +43,6 @@
 #include "llchat.h"
 #include "llviewerobject.h"
 #include "lljointsolverrp3.h"
-#include "llviewerjointshape.h"
 #include "llviewerjointmesh.h"
 #include "llviewerjointattachment.h"
 #include "llcharacter.h"
@@ -54,6 +53,7 @@
 #include "llframetimer.h"
 #include "llxmltree.h"
 #include "llwearable.h"
+#include "llrendertarget.h"
 
 //Ventrella
 //#include "llvoiceclient.h"
@@ -62,6 +62,7 @@
 
 const S32 VOAVATAR_SCRATCH_TEX_WIDTH = 512;
 const S32 VOAVATAR_SCRATCH_TEX_HEIGHT = 512;
+const S32 VOAVATAR_IMPOSTOR_PERIOD = 2;
 
 const LLUUID ANIM_AGENT_BODY_NOISE		=	LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise"
 const LLUUID ANIM_AGENT_BREATHE_ROT	=	LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8");  //"breathe_rot"
@@ -269,6 +270,8 @@ class LLVOAvatar :
 	LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
 	/*virtual*/ void markDead();
 
+	static void updateImpostors();
+
 	//--------------------------------------------------------------------
 	// LLViewerObject interface
 	//--------------------------------------------------------------------
@@ -288,6 +291,7 @@ class LLVOAvatar :
 	// Graphical stuff for objects - maybe broken out into render class later?
 
 	U32 renderFootShadows();
+	U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255));
 	U32 renderRigid();
 	U32 renderSkinned(EAvatarRenderPass pass);
 	U32 renderTransparent();
@@ -296,10 +300,10 @@ class LLVOAvatar :
 	/*virtual*/ void updateTextures(LLAgent &agent);
 	// If setting a baked texture, need to request it from a non-local sim.
 	/*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid);
-	
+	/*virtual*/ void onShift(const LLVector3& shift_vector);
 	virtual U32 getPartitionType() const;
 	
-	void updateVisibility(BOOL force_invisible);
+	void updateVisibility();
 	void updateAttachmentVisibility(U32 camera_mode);
 	void clampAttachmentPositions();
 	S32 getAttachmentCount();	// Warning: order(N) not order(1)
@@ -309,8 +313,6 @@ class LLVOAvatar :
 // 	void renderHUD(BOOL for_select); // old
 	void rebuildHUD();
 
-	static void updateAllAvatarVisiblity();
-
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
 	void updateShadowFaces();
@@ -318,13 +320,20 @@ class LLVOAvatar :
 	/*virtual*/ void		setPixelAreaAndAngle(LLAgent &agent);
 	BOOL					updateJointLODs();
 
-	void writeCAL3D(std::string& path, std::string& file_base);
-
 	virtual void updateRegion(LLViewerRegion *regionp);
-
 	
+	virtual const LLVector3 getRenderPosition() const;
+	virtual void updateDrawable(BOOL force_damped);
 	void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax);
-	
+	void getSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+	BOOL isImpostor() const;
+	BOOL needsImpostorUpdate() const;
+	const LLVector3& getImpostorOffset() const;
+	const LLVector2& getImpostorDim() const;
+	void getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance);
+	void cacheImpostorValues();
+	void setImpostorDim(const LLVector2& dim);
+
 	//--------------------------------------------------------------------
 	// texture entry assignment
 	//--------------------------------------------------------------------
@@ -448,7 +457,7 @@ class LLVOAvatar :
 
 	void computeBodySize();
 
-	void updateCharacter(LLAgent &agent);
+	BOOL updateCharacter(LLAgent &agent);
 	void updateHeadOffset();
 
 	LLUUID& getStepSound();
@@ -546,8 +555,7 @@ class LLVOAvatar :
 	static void		deleteCachedImages();
 	static void		destroyGL();
 	static void		restoreGL();
-	static void		initVertexPrograms();
-	static void		cleanupVertexPrograms();
+	static void		resetImpostors();
 	static enum EWearableType	getTEWearableType( S32 te );
 	static LLUUID			getDefaultTEImageID( S32 te );
 
@@ -695,6 +703,19 @@ class LLVOAvatar :
 	LLUUID			mLastEyesBakedID;
 	LLUUID			mLastSkirtBakedID;
 
+	//--------------------------------------------------------------------
+	// impostor state
+	//--------------------------------------------------------------------
+	LLRenderTarget	mImpostor;
+	LLVector3		mImpostorOffset;
+	LLVector2		mImpostorDim;
+	BOOL			mNeedsImpostorUpdate;
+	BOOL			mNeedsAnimUpdate;
+	LLVector3		mImpostorExtents[2];
+	LLVector3		mImpostorAngle;
+	F32				mImpostorDistance;
+	LLVector3		mLastAnimExtents[2];  
+
 	//--------------------------------------------------------------------
 	// Misc Render State
 	//--------------------------------------------------------------------
@@ -815,13 +836,14 @@ class LLVOAvatar :
 	// static members
 	//--------------------------------------------------------------------
 	static S32		sMaxVisible;
+	static F32		sRenderDistance; //distance at which avatars will render (affected by control "RenderAvatarMaxVisible")
 	static S32		sCurJoint;
 	static S32		sCurVolume;
 	static BOOL		sShowAnimationDebug; // show animation debug info
+	static BOOL		sUseImpostors; //use impostors for far away avatars
 	static BOOL		sShowFootPlane;	// show foot collision plane reported by server
 	static BOOL		sShowCollisionVolumes;	// show skeletal collision volumes
 	static BOOL		sVisibleInFirstPerson;
-
 	static S32		sMaxOtherAvatarsToComposite;
 
 	static S32		sNumLODChangesThisFrame;
@@ -848,14 +870,13 @@ class LLVOAvatar :
 	typedef std::map<S32, LLViewerJointAttachment*> attachment_map_t;
 	attachment_map_t mAttachmentPoints;
 
+	std::vector<LLPointer<LLViewerObject> > mPendingAttachment;
+
 	// xml parse tree of avatar config file
 	static LLXmlTree sXMLTree;
 	// xml parse tree of avatar skeleton file
 	static LLXmlTree sSkeletonXMLTree;
 
-	// number of avatar duplicates, for debugging purposes
-	static BOOL		sAvatarLoadTest;
-
 	// user-settable LOD factor
 	static F32		sLODFactor;
 
@@ -930,6 +951,9 @@ class LLVOAvatar :
 	LLTexGlobalColor*	mTexHairColor;
 	LLTexGlobalColor*	mTexEyeColor;
 
+	BOOL				mNeedsSkin;  //if TRUE, avatar has been animated and verts have not been updated
+	S32					mUpdatePeriod;
+
 	static LLVOAvatarSkeletonInfo*	sSkeletonInfo;
 	static LLVOAvatarInfo*			sAvatarInfo;
 	
diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp
index 7a2ba609e87..2e0da4727ce 100644
--- a/indra/newview/llvoclouds.cpp
+++ b/indra/newview/llvoclouds.cpp
@@ -49,6 +49,7 @@
 #include "llvosky.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 
 LLUUID gCloudTextureID = IMG_CLOUD_POOF;
 
@@ -78,14 +79,17 @@ BOOL LLVOClouds::isActive() const
 
 BOOL LLVOClouds::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
- 	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS)))
+	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS)))
+	{
 		return TRUE;
+	}
 	
 	// Set dirty flag (so renderer will rebuild primitive)
 	if (mDrawable)
 	{
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
 	}
+
 	return TRUE;
 }
 
@@ -113,9 +117,13 @@ LLDrawable* LLVOClouds::createDrawable(LLPipeline *pipeline)
 BOOL LLVOClouds::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS);
- 	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS)))
+	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS)))
+	{
 		return TRUE;
+	}
 	
+	dirtySpatialGroup();
+
 	LLFace *facep;
 	
 	S32 num_faces = mCloudGroupp->getNumPuffs();
@@ -137,19 +145,16 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable)
 			continue;
 		}
 
-		if (isParticle())
-		{
-			facep->setSize(1,1);
-		}
-		else
-		{
-			facep->setSize(4, 6);
-		}
+		facep->setSize(4, 6);
+		
 		facep->setTEOffset(face_indx);
 		facep->setTexture(getTEImage(0));
 		const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx);
 		const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal());
 		facep->mCenterLocal = puff_pos_agent;
+		/// Update cloud color based on sun color.
+		LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha());
+		facep->setFaceColor(float_color);
 	}
 	for ( ; face_indx < drawable->getNumFaces(); face_indx++)
 	{
@@ -169,11 +174,6 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable)
 	return TRUE;
 }
 
-BOOL LLVOClouds::isParticle()
-{
-	return FALSE; // gGLManager.mHasPointParameters;
-}
-
 F32 LLVOClouds::getPartSize(S32 idx)
 {
 	return (CLOUD_PUFF_HEIGHT+CLOUD_PUFF_WIDTH)*0.5f;
@@ -184,7 +184,7 @@ void LLVOClouds::getGeometry(S32 te,
 							LLStrider<LLVector3>& normalsp, 
 							LLStrider<LLVector2>& texcoordsp, 
 							LLStrider<LLColor4U>& colorsp, 
-							LLStrider<U32>& indicesp)
+							LLStrider<U16>& indicesp)
 {
 
 	if (te >= mCloudGroupp->getNumPuffs())
@@ -204,80 +204,71 @@ void LLVOClouds::getGeometry(S32 te,
 
 	const LLCloudPuff &puff = mCloudGroupp->getPuff(te);
 	S32 index_offset = facep->getGeomIndex();
-	LLColor4U color(255, 255, 255, (U8) (puff.getAlpha()*255));
-	facep->setFaceColor(LLColor4(color));
+	LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha());
+	LLColor4U color;
+	color.setVec(float_color);
+	facep->setFaceColor(float_color);
 		
 	
-	if (isParticle())
-	{
-		*verticesp++ = facep->mCenterLocal;
-		*texcoordsp++ = LLVector2(0.5f, 0.5f);
-		*colorsp++ = color;
-		*normalsp++ = normal;
-		*indicesp++ = facep->getGeomIndex();
-	}
-	else
-	{
-		LLVector3 up;
-		LLVector3 right;
-		LLVector3 at;
-
-		const LLVector3& puff_pos_agent = facep->mCenterLocal;
-		LLVector2 uvs[4];
-
-		uvs[0].setVec(0.f, 1.f);
-		uvs[1].setVec(0.f, 0.f);
-		uvs[2].setVec(1.f, 1.f);
-		uvs[3].setVec(1.f, 0.f);
-
-		LLVector3 vtx[4];
-
-		at = gCamera->getAtAxis();
-		right = at % LLVector3(0.f, 0.f, 1.f);
-		right.normVec();
-		up = right % at;
-		up.normVec();
-		right *= 0.5f*CLOUD_PUFF_WIDTH;
-		up *= 0.5f*CLOUD_PUFF_HEIGHT;;
+	LLVector3 up;
+	LLVector3 right;
+	LLVector3 at;
+
+	const LLVector3& puff_pos_agent = facep->mCenterLocal;
+	LLVector2 uvs[4];
+
+	uvs[0].setVec(0.f, 1.f);
+	uvs[1].setVec(0.f, 0.f);
+	uvs[2].setVec(1.f, 1.f);
+	uvs[3].setVec(1.f, 0.f);
+
+	LLVector3 vtx[4];
+
+	at = gCamera->getAtAxis();
+	right = at % LLVector3(0.f, 0.f, 1.f);
+	right.normVec();
+	up = right % at;
+	up.normVec();
+	right *= 0.5f*CLOUD_PUFF_WIDTH;
+	up *= 0.5f*CLOUD_PUFF_HEIGHT;;
 		
-		*colorsp++ = color;
-		*colorsp++ = color;
-		*colorsp++ = color;
-		*colorsp++ = color;
-
-		vtx[0] = puff_pos_agent - right + up;
-		vtx[1] = puff_pos_agent - right - up;
-		vtx[2] = puff_pos_agent + right + up;
-		vtx[3] = puff_pos_agent + right - up;
-
-		*verticesp++  = vtx[0];
-		*verticesp++  = vtx[1];
-		*verticesp++  = vtx[2];
-		*verticesp++  = vtx[3];
-
-		*texcoordsp++ = uvs[0];
-		*texcoordsp++ = uvs[1];
-		*texcoordsp++ = uvs[2];
-		*texcoordsp++ = uvs[3];
-
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-
-		*indicesp++ = index_offset + 0;
-		*indicesp++ = index_offset + 1;
-		*indicesp++ = index_offset + 2;
-
-		*indicesp++ = index_offset + 1;
-		*indicesp++ = index_offset + 3;
-		*indicesp++ = index_offset + 2;
-	}
+	*colorsp++ = color;
+	*colorsp++ = color;
+	*colorsp++ = color;
+	*colorsp++ = color;
+
+	vtx[0] = puff_pos_agent - right + up;
+	vtx[1] = puff_pos_agent - right - up;
+	vtx[2] = puff_pos_agent + right + up;
+	vtx[3] = puff_pos_agent + right - up;
+
+	*verticesp++  = vtx[0];
+	*verticesp++  = vtx[1];
+	*verticesp++  = vtx[2];
+	*verticesp++  = vtx[3];
+
+	*texcoordsp++ = uvs[0];
+	*texcoordsp++ = uvs[1];
+	*texcoordsp++ = uvs[2];
+	*texcoordsp++ = uvs[3];
+
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+
+	*indicesp++ = index_offset + 0;
+	*indicesp++ = index_offset + 1;
+	*indicesp++ = index_offset + 2;
+
+	*indicesp++ = index_offset + 1;
+	*indicesp++ = index_offset + 3;
+	*indicesp++ = index_offset + 2;
 }
 
 U32 LLVOClouds::getPartitionType() const
 {
-	return LLPipeline::PARTITION_CLOUD;
+	return LLViewerRegion::PARTITION_CLOUD;
 }
 
 // virtual
@@ -295,6 +286,6 @@ void LLVOClouds::updateDrawable(BOOL force_damped)
 LLCloudPartition::LLCloudPartition()
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_CLOUDS;
-	mPartitionType = LLPipeline::PARTITION_CLOUD;
+	mPartitionType = LLViewerRegion::PARTITION_CLOUD;
 }
 
diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h
index 500d9426ae2..af5bbf0e8f8 100644
--- a/indra/newview/llvoclouds.h
+++ b/indra/newview/llvoclouds.h
@@ -59,10 +59,9 @@ class LLVOClouds : public LLAlphaObject
 							LLStrider<LLVector3>& normalsp, 
 							LLStrider<LLVector2>& texcoordsp, 
 							LLStrider<LLColor4U>& colorsp, 
-							LLStrider<U32>& indicesp);
+							LLStrider<U16>& indicesp);
 
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
-	BOOL isParticle();
 	F32 getPartSize(S32 idx);
 
 	/*virtual*/ void updateTextures(LLAgent &agent);
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 84fdbfff0b7..833fe4b464d 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -48,6 +48,7 @@
 #include "llviewerimagelist.h"
 #include "llviewerregion.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llworld.h"
 #include "lldir.h"
 #include "llxmltree.h"
@@ -400,6 +401,7 @@ LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline)
 BOOL LLVOGrass::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_GRASS);
+	dirtySpatialGroup();
 	plantBlades();
 	return TRUE;
 }
@@ -439,7 +441,7 @@ void LLVOGrass::getGeometry(S32 idx,
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp)
+								LLStrider<U16>& indicesp)
 {
 	mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion());
 	if (mPatch)
@@ -552,13 +554,13 @@ void LLVOGrass::getGeometry(S32 idx,
 
 U32 LLVOGrass::getPartitionType() const
 {
-	return LLPipeline::PARTITION_GRASS;
+	return LLViewerRegion::PARTITION_GRASS;
 }
 
 LLGrassPartition::LLGrassPartition()
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_GRASS;
-	mPartitionType = LLPipeline::PARTITION_GRASS;
+	mPartitionType = LLViewerRegion::PARTITION_GRASS;
 	mLODPeriod = 16;
 	mDepthMask = TRUE;
 	mSlopRatio = 0.1f;
diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h
index f7ce9a4233b..a1dab634be6 100644
--- a/indra/newview/llvograss.h
+++ b/indra/newview/llvograss.h
@@ -68,7 +68,7 @@ class LLVOGrass : public LLAlphaObject
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp);
+								LLStrider<U16>& indicesp);
 
 	void updateFaceSize(S32 idx) { }
 	/*virtual*/ void updateTextures(LLAgent &agent);											
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index 8f6bc4a0904..fd4956113dd 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -93,7 +93,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 	S32 index_offset;
 	LLFace *face;	
 
@@ -167,6 +167,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 	*(texCoordsp++) = LLVector2(0.f, 1.f);
 	*(texCoordsp++) = LLVector2(0.5f, 0.5f);
 	
+	face->mVertexBuffer->setBuffer(0);
 	LLPipeline::sCompiles++;
 	return TRUE;
 }
diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp
index 96026c58ba9..8d813f47aa6 100644
--- a/indra/newview/llvoicevisualizer.cpp
+++ b/indra/newview/llvoicevisualizer.cpp
@@ -45,6 +45,7 @@
 #include "llviewerimage.h"
 #include "llviewerimagelist.h"
 #include "llvoiceclient.h"
+#include "llglimmediate.h"
 
 //brent's wave image
 //29de489d-0491-fb00-7dab-f9e686d31e83
@@ -197,7 +198,6 @@ void LLVoiceVisualizer::render()
 		//---------------------------------------------------------------
 		// some gl state
 		//---------------------------------------------------------------
-		LLGLEnable tex( GL_TEXTURE_2D );
 		LLGLEnable blend( GL_BLEND );
 		
 		//-------------------------------------------------------------
@@ -219,19 +219,19 @@ void LLVoiceVisualizer::render()
 		//-------------------------------------------------------------
 		// now render the dot
 		//-------------------------------------------------------------
-		glColor4fv( LLColor4( 1.0f, 1.0f, 1.0f, DOT_OPACITY ).mV );	
+		gGL.color4fv( LLColor4( 1.0f, 1.0f, 1.0f, DOT_OPACITY ).mV );	
 		
-		glBegin( GL_TRIANGLE_STRIP );
-			glTexCoord2i( 0,	0	); glVertex3fv( bottomLeft.mV );
-			glTexCoord2i( 1,	0	); glVertex3fv( bottomRight.mV );
-			glTexCoord2i( 0,	1	); glVertex3fv( topLeft.mV );
-		glEnd();
-
-		glBegin( GL_TRIANGLE_STRIP );
-			glTexCoord2i( 1,	0	); glVertex3fv( bottomRight.mV );
-			glTexCoord2i( 1,	1	); glVertex3fv( topRight.mV );
-			glTexCoord2i( 0,	1	); glVertex3fv( topLeft.mV );
-		glEnd();
+		gGL.begin( GL_TRIANGLE_STRIP );
+			gGL.texCoord2i( 0,	0	); gGL.vertex3fv( bottomLeft.mV );
+			gGL.texCoord2i( 1,	0	); gGL.vertex3fv( bottomRight.mV );
+			gGL.texCoord2i( 0,	1	); gGL.vertex3fv( topLeft.mV );
+		gGL.end();
+
+		gGL.begin( GL_TRIANGLE_STRIP );
+			gGL.texCoord2i( 1,	0	); gGL.vertex3fv( bottomRight.mV );
+			gGL.texCoord2i( 1,	1	); gGL.vertex3fv( topRight.mV );
+			gGL.texCoord2i( 0,	1	); gGL.vertex3fv( topLeft.mV );
+		gGL.end();
 		
 		
 		
@@ -338,23 +338,23 @@ void LLVoiceVisualizer::render()
 				LLVector3 topLeft		= mSoundSymbol.mPosition + l + u;
 				LLVector3 topRight		= mSoundSymbol.mPosition - l + u;
 							
-				glColor4fv( LLColor4( red, green, blue, mSoundSymbol.mWaveOpacity[i] ).mV );		
+				gGL.color4fv( LLColor4( red, green, blue, mSoundSymbol.mWaveOpacity[i] ).mV );		
 				mSoundSymbol.mTexture[i]->bind();
 				
 				//---------------------------------------------------
 				// now, render the mofo
 				//---------------------------------------------------
-				glBegin( GL_TRIANGLE_STRIP );
-					glTexCoord2i( 0, 0 ); glVertex3fv( bottomLeft.mV );
-					glTexCoord2i( 1, 0 ); glVertex3fv( bottomRight.mV );
-					glTexCoord2i( 0, 1 ); glVertex3fv( topLeft.mV );
-				glEnd();
-
-				glBegin( GL_TRIANGLE_STRIP );
-					glTexCoord2i( 1, 0 ); glVertex3fv( bottomRight.mV );
-					glTexCoord2i( 1, 1 ); glVertex3fv( topRight.mV );
-					glTexCoord2i( 0, 1 ); glVertex3fv( topLeft.mV );
-				glEnd();
+				gGL.begin( GL_TRIANGLE_STRIP );
+					gGL.texCoord2i( 0, 0 ); gGL.vertex3fv( bottomLeft.mV );
+					gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
+					gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
+				gGL.end();
+
+				gGL.begin( GL_TRIANGLE_STRIP );
+					gGL.texCoord2i( 1, 0 ); gGL.vertex3fv( bottomRight.mV );
+					gGL.texCoord2i( 1, 1 ); gGL.vertex3fv( topRight.mV );
+					gGL.texCoord2i( 0, 1 ); gGL.vertex3fv( topLeft.mV );
+				gGL.end();
 				
 			} //if ( mSoundSymbol.mWaveActive[i] ) 
 			
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 56643e321f0..14e503d2d18 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -47,6 +47,7 @@
 #include "llviewerpartsim.h"
 #include "llviewerregion.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 
 const F32 MAX_PART_LIFETIME = 120.f;
 
@@ -59,7 +60,6 @@ LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegi
 	setNumTEs(1);
 	setTETexture(0, LLUUID::null);
 	mbCanSelect = FALSE;			// users can't select particle systems
-	mDebugColor = LLColor4(ll_frand(), ll_frand(), ll_frand(), 1.f);
 }
 
 
@@ -70,7 +70,7 @@ LLVOPartGroup::~LLVOPartGroup()
 
 BOOL LLVOPartGroup::isActive() const
 {
-	return TRUE;
+	return FALSE;
 }
 
 F32 LLVOPartGroup::getBinRadius()
@@ -80,11 +80,9 @@ F32 LLVOPartGroup::getBinRadius()
 
 void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 {		
-	LLVector3 pos_agent = getPositionAgent();
-	mExtents[0] = pos_agent - mScale;
-	mExtents[1] = pos_agent + mScale;
-	newMin = mExtents[0];
-	newMax = mExtents[1];
+	const LLVector3& pos_agent = getPositionAgent();
+	newMin = pos_agent - mScale;
+	newMax = pos_agent + mScale;
 	mDrawable->setPositionGroup(pos_agent);
 }
 
@@ -139,6 +137,8 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES);
 
+	dirtySpatialGroup();
+
  	LLVector3 at;
 	LLVector3 position_agent;
 	LLVector3 camera_agent = gCamera->getOrigin();
@@ -156,7 +156,7 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 	{
 		if (group && drawable->getNumFaces())
 		{
-			group->dirtyGeom();
+			group->setState(LLSpatialGroup::GEOM_DIRTY);
 		}
 		drawable->setNumFaces(0, NULL, getTEImage(0));
 		LLPipeline::sCompiles++;
@@ -174,7 +174,6 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 	}
 
 	F32 tot_area = 0;
-	BOOL is_particle = isParticle();
 
 	F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; 
 	F32 pixel_meter_ratio = gCamera->getPixelMeterRatio();
@@ -182,7 +181,6 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 
 	S32 count=0;
 	S32 i;
-	F32 max_width = 0.f;
 	mDepth = 0.f;
 
 	for (i = 0; i < num_parts; i++)
@@ -199,9 +197,9 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 		else
 			inv_camera_dist_squared = 1.f;
 		F32 area = part.mScale.mV[0] * part.mScale.mV[1] * inv_camera_dist_squared;
-		tot_area += area;
+		tot_area = llmax(tot_area, area);
  		
-		if (!is_particle && tot_area > max_area)
+		if (tot_area > max_area)
 		{
 			break;
 		}
@@ -219,21 +217,14 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 		const F32 NEAR_PART_DIST_SQ = 5.f*5.f;  // Only discard particles > 5 m from the camera
 		const F32 MIN_PART_AREA = .005f*.005f;  // only less than 5 mm x 5 mm at 1 m from camera
 		
-		if (!is_particle)
+		if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA)
 		{
-			if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA)
-			{
-				facep->setSize(0, 0);
-				continue;
-			}
-
-			facep->setSize(4, 6);
-		}
-		else
-		{		
-			facep->setSize(1,1);
+			facep->setSize(0, 0);
+			continue;
 		}
 
+		facep->setSize(4, 6);
+		
 		facep->setViewerObject(this);
 
 		if (part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK)
@@ -248,18 +239,6 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 		facep->mCenterLocal = part.mPosAgent;
 		facep->setFaceColor(part.mColor);
 		facep->setTexture(part.mImagep);
-		
-		if (i == 0)
-		{
-			mExtents[0] = mExtents[1] = part.mPosAgent;
-		}
-		else
-		{
-			update_min_max(mExtents[0], mExtents[1], part.mPosAgent);
-		}
-
-		max_width = llmax(max_width, part.mScale.mV[0]);
-		max_width = llmax(max_width, part.mScale.mV[1]);
 
 		mPixelArea = tot_area * pixel_meter_ratio;
 		const F32 area_scale = 10.f; // scale area to increase priority a bit
@@ -274,21 +253,9 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 			continue;
 		}
 		facep->setTEOffset(i);
-		facep->setSize(0,0);
+		facep->setSize(0, 0);
 	}
-	
-	LLVector3 y = gCamera->mYAxis;
-	LLVector3 z = gCamera->mZAxis;
 
-	LLVector3 pad;
-	for (i = 0; i < 3; i++)
-	{
-		pad.mV[i] = llmax(max_width, max_width * (fabsf(y.mV[i]) + fabsf(z.mV[i])));
-	}
-	
-	mExtents[0] -= pad;
-	mExtents[1] += pad;
-	
 	mDrawable->movePartition();
 	LLPipeline::sCompiles++;
 	return TRUE;
@@ -299,7 +266,7 @@ void LLVOPartGroup::getGeometry(S32 idx,
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp)
+								LLStrider<U16>& indicesp)
 {
 	if (idx >= (S32) mViewerPartGroupp->mParticles.size())
 	{
@@ -310,92 +277,72 @@ void LLVOPartGroup::getGeometry(S32 idx,
 
 	U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex();
 
-	if (isParticle())
-	{
-		LLVector3 part_pos_agent(part.mPosAgent);
+	
+	LLVector3 part_pos_agent(part.mPosAgent);
+	LLVector3 camera_agent = gAgent.getCameraPositionAgent();
+	LLVector3 at = part_pos_agent - camera_agent;
+	LLVector3 up, right;
 
-		const LLVector3& normal = -gCamera->getXAxis();
+	right = at % LLVector3(0.f, 0.f, 1.f);
+	right.normVec();
+	up = right % at;
+	up.normVec();
 
-		*verticesp++ = part_pos_agent;
-		*normalsp++ = normal;
-		*colorsp++ = part.mColor;
-		*texcoordsp++ = LLVector2(0.5f, 0.5f);
-		*indicesp++ = vert_offset;
-	}
-	else
+	if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK)
 	{
-		LLVector3 part_pos_agent(part.mPosAgent);
-		LLVector3 camera_agent = gAgent.getCameraPositionAgent();
-		LLVector3 at = part_pos_agent - camera_agent;
-		LLVector3 up, right;
-
-		right = at % LLVector3(0.f, 0.f, 1.f);
-		right.normVec();
-		up = right % at;
+		LLVector3 normvel = part.mVelocity;
+		normvel.normVec();
+		LLVector2 up_fracs;
+		up_fracs.mV[0] = normvel*right;
+		up_fracs.mV[1] = normvel*up;
+		up_fracs.normVec();
+		LLVector3 new_up;
+		LLVector3 new_right;
+		new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up;
+		new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up;
+		up = new_up;
+		right = new_right;
 		up.normVec();
+		right.normVec();
+	}
 
-		if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK)
-		{
-			LLVector3 normvel = part.mVelocity;
-			normvel.normVec();
-			LLVector2 up_fracs;
-			up_fracs.mV[0] = normvel*right;
-			up_fracs.mV[1] = normvel*up;
-			up_fracs.normVec();
-
-			LLVector3 new_up;
-			LLVector3 new_right;
-			new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up;
-			new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up;
-			up = new_up;
-			right = new_right;
-			up.normVec();
-			right.normVec();
-		}
-
-		right *= 0.5f*part.mScale.mV[0];
-		up *= 0.5f*part.mScale.mV[1];
+	right *= 0.5f*part.mScale.mV[0];
+	up *= 0.5f*part.mScale.mV[1];
 
-		const LLVector3& normal = -gCamera->getXAxis();
+	const LLVector3& normal = -gCamera->getXAxis();
 		
-		*verticesp++ = part_pos_agent + up - right;
-		*verticesp++ = part_pos_agent - up - right;
-		*verticesp++ = part_pos_agent + up + right;
-		*verticesp++ = part_pos_agent - up + right;
-
-		*colorsp++ = part.mColor;
-		*colorsp++ = part.mColor;
-		*colorsp++ = part.mColor;
-		*colorsp++ = part.mColor;
-
-		*texcoordsp++ = LLVector2(0.f, 1.f);
-		*texcoordsp++ = LLVector2(0.f, 0.f);
-		*texcoordsp++ = LLVector2(1.f, 1.f);
-		*texcoordsp++ = LLVector2(1.f, 0.f);
-
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-		*normalsp++   = normal;
-
-		*indicesp++ = vert_offset + 0;
-		*indicesp++ = vert_offset + 1;
-		*indicesp++ = vert_offset + 2;
-
-		*indicesp++ = vert_offset + 1;
-		*indicesp++ = vert_offset + 3;
-		*indicesp++ = vert_offset + 2;
-	}
-}
-
-BOOL LLVOPartGroup::isParticle()
-{
-	return FALSE; //gGLManager.mHasPointParameters && mViewerPartGroupp->mUniformParticles;
+	*verticesp++ = part_pos_agent + up - right;
+	*verticesp++ = part_pos_agent - up - right;
+	*verticesp++ = part_pos_agent + up + right;
+	*verticesp++ = part_pos_agent - up + right;
+
+	*colorsp++ = part.mColor;
+	*colorsp++ = part.mColor;
+	*colorsp++ = part.mColor;
+	*colorsp++ = part.mColor;
+
+	*texcoordsp++ = LLVector2(0.f, 1.f);
+	*texcoordsp++ = LLVector2(0.f, 0.f);
+	*texcoordsp++ = LLVector2(1.f, 1.f);
+	*texcoordsp++ = LLVector2(1.f, 0.f);
+
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+	*normalsp++   = normal;
+
+	*indicesp++ = vert_offset + 0;
+	*indicesp++ = vert_offset + 1;
+	*indicesp++ = vert_offset + 2;
+
+	*indicesp++ = vert_offset + 1;
+	*indicesp++ = vert_offset + 3;
+	*indicesp++ = vert_offset + 2;
 }
 
 U32 LLVOPartGroup::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_PARTICLE; 
+	return LLViewerRegion::PARTITION_PARTICLE; 
 }
 
 LLParticlePartition::LLParticlePartition()
@@ -403,7 +350,7 @@ LLParticlePartition::LLParticlePartition()
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
-	mPartitionType = LLPipeline::PARTITION_PARTICLE;
+	mPartitionType = LLViewerRegion::PARTITION_PARTICLE;
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	mSlopRatio = 0.f;
 	mLODPeriod = 1;
@@ -459,6 +406,7 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	LLFastTimer ftm(LLFastTimer::FTM_REBUILD_PARTICLE_VB);
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
@@ -469,7 +417,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 
 	LLVertexBuffer* buffer = group->mVertexBuffer;
 
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texcoordsp;
@@ -503,8 +451,8 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 
 		if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
 			draw_vec[idx]->mTexture == facep->getTexture() &&
-			draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
-			draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
+			(U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange &&
+			//draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 			draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 &&
 			draw_vec[idx]->mFullbright == fullbright)
 		{
@@ -524,6 +472,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 		}
 	}
 
+	buffer->setBuffer(0);
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index 90c8ac40186..d8e1da7e5a8 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -54,7 +54,6 @@ class LLVOPartGroup : public LLAlphaObject
 
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
 	BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
-	BOOL isParticle();
 
 	virtual F32 getBinRadius();
 	virtual void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
@@ -70,7 +69,7 @@ class LLVOPartGroup : public LLAlphaObject
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp);
+								LLStrider<U16>& indicesp);
 
 	void updateFaceSize(S32 idx) { }
 	F32 getPartSize(S32 idx);
@@ -81,8 +80,6 @@ class LLVOPartGroup : public LLAlphaObject
 	~LLVOPartGroup();
 
 	LLViewerPartGroup *mViewerPartGroupp;
-	LLVector3 mExtents[2];
-	LLColor4 mDebugColor;
 };
 
 #endif // LL_LLVOPARTGROUP_H
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index b8d994d095b..ba06083fd3b 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -53,23 +53,29 @@
 #include "llviewerregion.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "lldrawpoolwlsky.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
 
-const S32 NUM_TILES_X = 8;
-const S32 NUM_TILES_Y = 4;
-const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
+#undef min
+#undef max
+
+static const S32 NUM_TILES_X = 8;
+static const S32 NUM_TILES_Y = 4;
+static const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
 
 // Heavenly body constants
-const F32 SUN_DISK_RADIUS	= 0.5f;
-const F32 MOON_DISK_RADIUS	= SUN_DISK_RADIUS * 0.9f;
-const F32 SUN_INTENSITY = 1e5;
-const F32 SUN_DISK_INTENSITY = 24.f;
+static const F32 SUN_DISK_RADIUS	= 0.5f;
+static const F32 MOON_DISK_RADIUS	= SUN_DISK_RADIUS * 0.9f;
+static const F32 SUN_INTENSITY = 1e5;
+static const F32 SUN_DISK_INTENSITY = 24.f;
 
 
 // Texture coordinates:
-const LLVector2 TEX00 = LLVector2(0.f, 0.f);
-const LLVector2 TEX01 = LLVector2(0.f, 1.f);
-const LLVector2 TEX10 = LLVector2(1.f, 0.f);
-const LLVector2 TEX11 = LLVector2(1.f, 1.f);
+static const LLVector2 TEX00 = LLVector2(0.f, 0.f);
+static const LLVector2 TEX01 = LLVector2(0.f, 1.f);
+static const LLVector2 TEX10 = LLVector2(1.f, 0.f);
+static const LLVector2 TEX11 = LLVector2(1.f, 1.f);
 
 // Exported globals
 LLUUID gSunTextureID = IMG_SUN;
@@ -134,7 +140,7 @@ class LLFastLn
 	F32 mTable[257]; // index 0 is unused
 };
 
-LLFastLn gFastLn;
+static LLFastLn gFastLn;
 
 
 // Functions used a lot.
@@ -163,42 +169,6 @@ inline LLColor3 color_norm(const LLColor3 &col)
 	else return col;
 }
 
-inline LLColor3 color_norm_fog(const LLColor3 &col)
-{
-	const F32 m = color_max(col);
-	if (m > 0.75f)
-	{
-		return 0.75f/m * col;
-	}
-	else return col;
-}
-
-
-inline LLColor4 color_norm_abs(const LLColor4 &col)
-{
-	const F32 m = color_max(col);
-	if (m > 1e-6)
-	{
-		return 1.f/m * col;
-	}
-	else
-	{
-		return col;
-	}
-}
-
-
-inline F32 color_intens ( const LLColor4 &col )
-{
-	return col.mV[0] + col.mV[1] + col.mV[2];
-}
-
-
-inline F32 color_avg ( const LLColor3 &col )
-{
-	return color_intens(col) / 3.f;
-}
-
 inline void color_gamma_correct(LLColor3 &col)
 {
 	const F32 gamma_inv = 1.f/1.2f;
@@ -216,164 +186,6 @@ inline void color_gamma_correct(LLColor3 &col)
 	}
 }
 
-inline F32 min_intens_factor( LLColor3& col, F32 min_intens, BOOL postmultiply = FALSE);
-inline F32 min_intens_factor( LLColor3& col, F32 min_intens, BOOL postmultiply)
-{ 
-	const F32 intens = color_intens(col);
-	F32 factor = 1;
-	if (0 == intens)
-	{
-		return 0;
-	}
-
-	if (intens < min_intens)
-	{
-		factor = min_intens / intens;
-		if (postmultiply)
-			col *= factor;
-	}
-	return factor;
-}
-
-inline LLVector3 move_vec(const LLVector3& v, const F32 cos_max_angle)
-{
-	LLVector3 v_norm = v;
-	v_norm.normVec();
-
-	LLVector2 v_norm_proj(v_norm.mV[0], v_norm.mV[1]);
-	const F32 projection2 = v_norm_proj.magVecSquared();
-	const F32 scale = sqrt((1 - cos_max_angle * cos_max_angle) / projection2);
-	return LLVector3(scale * v_norm_proj.mV[0], scale * v_norm_proj.mV[1], cos_max_angle);
-}
-
-
-/***************************************
-		Transparency Map
-***************************************/
-
-void LLTranspMap::init(const F32 elev, const F32 step, const F32 h, const LLHaze* const haze)
-{
-	mHaze = haze;
-	mAtmHeight = h;
-	mElevation = elev;
-	mStep = step;
-	mStepInv = 1.f / step;
-	F32 sin_angle = EARTH_RADIUS/(EARTH_RADIUS + mElevation);
-	mCosMaxAngle = -sqrt(1 - sin_angle * sin_angle);
-	mMapSize = S32(ceil((1 - mCosMaxAngle) * mStepInv + 1) + 0.5);
-	delete mT;
-	mT = new LLColor3[mMapSize];
-
-	for (S32 i = 0; i < mMapSize; ++i)
-	{
-		const F32 cos_a = 1 - i*mStep;
-		const LLVector3 dir(0, sqrt(1-cos_a*cos_a), cos_a);
-		mT[i] = calcAirTranspDir(mElevation, dir);
-	}
-}
-
-
-
-LLColor3 LLTranspMap::calcAirTranspDir(const F32 elevation, const LLVector3 &dir) const
-{
-	LLColor3 opt_depth(0, 0, 0);
-	const LLVector3 point(0, 0, EARTH_RADIUS + elevation);
-	F32 dist = -dir * point;
-	LLVector3 cur_point;
-	S32 s;
-
-	if (dist > 0)
-	{
-		cur_point = point + dist * dir;
-//		const F32 K = log(dist * INV_FIRST_STEP + 1) * INV_NO_STEPS;
-//		const F32 e_pow_k = LL_FAST_EXP(K);
-		const F32 e_pow_k = gFastLn.pow( dist * INV_FIRST_STEP + 1, INV_NO_STEPS );
-		F32 step = FIRST_STEP * (1 - 1 / e_pow_k);
-
-		for (s = 0; s < NO_STEPS; ++s)
-		{
-			const F32 h = cur_point.magVec() - EARTH_RADIUS;
-			step *= e_pow_k;
-			opt_depth += calcSigExt(h) * step;
-			cur_point -= dir * step;
-		}
-		opt_depth *= 2;
-		cur_point = point + 2 * dist * dir;
-	}
-	else
-	{
-		cur_point = point;
-	}
-
-	dist = hitsAtmEdge(cur_point, dir);
-//	const F32 K = log(dist * INV_FIRST_STEP + 1) * INV_NO_STEPS;
-//	const F32 e_pow_k = LL_FAST_EXP(K);
-	const F32 e_pow_k = gFastLn.pow( dist * INV_FIRST_STEP + 1, INV_NO_STEPS );
-	F32 step = FIRST_STEP * (1 - 1 / e_pow_k);
-
-	for (s = 0; s < NO_STEPS; ++s)
-	{
-		const F32 h = cur_point.magVec() - EARTH_RADIUS;
-		step *= e_pow_k;
-		opt_depth += calcSigExt(h) * step;
-		cur_point += dir * step;
-	}
-
-	opt_depth *= -4.0f*F_PI;
-	opt_depth.exp();
-	return opt_depth;
-}
-
-
-
-F32 LLTranspMap::hitsAtmEdge(const LLVector3& X, const LLVector3& dir) const
-{
-	const F32 tca = -dir * X;
-	const F32 R = EARTH_RADIUS + mAtmHeight;
-	const F32 thc2 = R * R - X.magVecSquared() + tca * tca;
-	return tca + sqrt ( thc2 );
-}
-
-
-
-
-
-void LLTranspMapSet::init(const S32 size, const F32 first_step, const F32 media_height, const LLHaze* const haze)
-{
-	const F32 angle_step = 0.005f;
-	mSize = size;
-	mMediaHeight = media_height;
-
-	delete[] mTransp;
-	mTransp = new LLTranspMap[mSize];
-
-	delete[] mHeights;
-	mHeights = new F32[mSize];
-
-	F32 h = 0;
-	mHeights[0] = h;
-	mTransp[0].init(h, angle_step, mMediaHeight, haze);	
-	const F32 K = log(mMediaHeight / first_step + 1) / (mSize - 1);
-	const F32 e_pow_k = exp(K);
-	F32 step = first_step * (e_pow_k - 1);
-
-	for (S32 s = 1; s < mSize; ++s)
-	{
-		h += step;
-		mHeights[s] = h;
-		mTransp[s].init(h, angle_step, mMediaHeight, haze);
-		step *= e_pow_k;
-	}
-}
-
-LLTranspMapSet::~LLTranspMapSet()
-{
-	delete[] mTransp;
-	mTransp = NULL;
-	delete[] mHeights;
-	mHeights = NULL;
-}
-
 
 
 /***************************************
@@ -392,7 +204,7 @@ LLSkyTex::LLSkyTex()
 
 void LLSkyTex::init()
 {
-	mSkyData = new LLColor3[sResolution * sResolution];
+	mSkyData = new LLColor4[sResolution * sResolution];
 	mSkyDirs = new LLVector3[sResolution * sResolution];
 
 	for (S32 i = 0; i < 2; ++i)
@@ -451,9 +263,9 @@ void LLSkyTex::initEmpty(const S32 tex)
 	createGLImage(tex);
 }
 
-
-void LLSkyTex::create(const F32 brightness_scale, const LLColor3& multiscatt)
+void LLSkyTex::create(const F32 brightness)
 {
+	/// Brightness ignored for now.
 	U8* data = mImageRaw[sCurrent]->getData();
 	for (S32 i = 0; i < sResolution; ++i)
 	{
@@ -461,23 +273,17 @@ void LLSkyTex::create(const F32 brightness_scale, const LLColor3& multiscatt)
 		{
 			const S32 basic_offset = (i * sResolution + j);
 			S32 offset = basic_offset * sComponents;
-			LLColor3 col(mSkyData[basic_offset]);
-			if (getDir(i, j).mV[VZ] >= -0.02f) {
-				col += 0.1f * multiscatt;
-				col *= brightness_scale;
-				col.clamp();
-				color_gamma_correct(col);
-			}
-			
 			U32* pix = (U32*)(data + offset);
-			LLColor4 temp = LLColor4(col, 0);
-			LLColor4U temp1 = LLColor4U(temp);
-			*pix = temp1.mAll;
+			LLColor4U temp = LLColor4U(mSkyData[basic_offset]);
+			*pix = temp.mAll;
 		}
 	}
 	createGLImage(sCurrent);
 }
 
+
+
+
 void LLSkyTex::createGLImage(S32 which)
 {	
 	mImageGL[which]->createGLTexture(0, mImageRaw[which]);
@@ -495,8 +301,6 @@ void LLSkyTex::bindTexture(BOOL curr)
 
 F32	LLHeavenBody::sInterpVal = 0;
 
-F32 LLVOSky::sNighttimeBrightness = 1.5f;
-
 S32 LLVOSky::sResolution = LLSkyTex::getResolution();
 S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X;
 S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y;
@@ -511,8 +315,32 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mCloudDensity(0.2f),
 	mWind(0.f),
 	mForceUpdate(FALSE),
-	mWorldScale(1.f)
+	mWorldScale(1.f),
+	mBumpSunDir(0.f, 0.f, 1.f)
 {
+	bool error = false;
+	
+	/// WL PARAMS
+	dome_radius = 1.f;
+	dome_offset_ratio = 0.f;
+	sunlight_color = LLColor3();
+	ambient = LLColor3();
+	gamma = 1.f;
+	lightnorm = LLVector4();
+	blue_density = LLColor3();
+	blue_horizon = LLColor3();
+	haze_density = 0.f;
+	haze_horizon = LLColor3();
+	density_multiplier = 0.f;
+	max_y = 0.f;
+	glow = LLColor3();
+	cloud_shadow = 0.f;
+	cloud_color = LLColor3();
+	cloud_scale = 0.f;
+	cloud_pos_density1 = LLColor3();
+	cloud_pos_density2 = LLColor3();
+
+
 	mInitialized = FALSE;
 	mbCanSelect = FALSE;
 	mUpdateTimer.reset();
@@ -520,6 +348,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	for (S32 i = 0; i < 6; i++)
 	{
 		mSkyTex[i].init();
+		mShinyTex[i].init();
 	}
 	for (S32 i=0; i<FACE_COUNT; i++)
 	{
@@ -529,9 +358,8 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mCameraPosAgent = gAgent.getCameraPositionAgent();
 	mAtmHeight = ATM_HEIGHT;
 	mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS);
-	updateHaze();
 
-	mSunDefaultPosition = gSavedSettings.getVector3("SkySunDefaultPosition");
+	mSunDefaultPosition = LLVector3(LLWLParamManager::instance()->mCurParams.getVector("lightnorm", error));
 	if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition"))
 	{
 		initSunDirection(mSunDefaultPosition, LLVector3(0, 0, 0));
@@ -551,6 +379,8 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mMoonTexturep->setClamp(TRUE, TRUE);
 	mBloomTexturep = gImageList.getImage(IMG_BLOOM1);
 	mBloomTexturep->setClamp(TRUE, TRUE);
+
+	mHeavenlyBodyUpdated = FALSE ;
 }
 
 
@@ -570,14 +400,11 @@ void LLVOSky::initClass()
 
 void LLVOSky::init()
 {
-    // index of refraction calculation.
-	mTransp.init(NO_STEPS+1+4, FIRST_STEP, mAtmHeight, &mHaze);
-
-	const F32 haze_int = color_intens(mHaze.calcSigSca(0));
+   	const F32 haze_int = color_intens(mHaze.calcSigSca(0));
 	mHazeConcentration = haze_int /
 		(color_intens(LLHaze::calcAirSca(0)) + haze_int);
 
-	mBrightnessScaleNew = 0;
+	calcAtmospherics();
 
 	// Initialize the cached normalized direction vectors
 	for (S32 side = 0; side < 6; ++side)
@@ -589,8 +416,16 @@ void LLVOSky::init()
 		}
 	}
 
-	calcBrightnessScaleAndColors();
+	for (S32 i = 0; i < 6; ++i)
+	{
+		mSkyTex[i].create(1.0f);
+		mShinyTex[i].create(1.0f);
+	}
+
 	initCubeMap();
+	mInitialized = true;
+
+	mHeavenlyBodyUpdated = FALSE ;
 }
 
 void LLVOSky::initCubeMap() 
@@ -598,7 +433,7 @@ void LLVOSky::initCubeMap()
 	std::vector<LLPointer<LLImageRaw> > images;
 	for (S32 side = 0; side < 6; side++)
 	{
-		images.push_back(mSkyTex[side].getImageRaw());
+		images.push_back(mShinyTex[side].getImageRaw());
 	}
 	if (mCubeMap)
 	{
@@ -639,7 +474,7 @@ void LLVOSky::restoreGL()
 	mBloomTexturep = gImageList.getImage(IMG_BLOOM1);
 	mBloomTexturep->setClamp(TRUE, TRUE);
 
-	calcBrightnessScaleAndColors();
+	calcAtmospherics();	
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap
 	    && gFeatureManagerp->isFeatureAvailable("RenderCubeMap"))
@@ -649,7 +484,7 @@ void LLVOSky::restoreGL()
 		std::vector<LLPointer<LLImageRaw> > images;
 		for (S32 side = 0; side < 6; side++)
 		{
-			images.push_back(mSkyTex[side].getImageRaw());
+			images.push_back(mShinyTex[side].getImageRaw());
 		}
 
 		if(cube_map)
@@ -666,67 +501,6 @@ void LLVOSky::restoreGL()
 
 }
 
-
-void LLVOSky::updateHaze()
-{
-	static LLRandLagFib607 weather_generator(LLUUID::getRandomSeed());
-	if (gSavedSettings.getBOOL("FixedWeather"))
-	{
-		weather_generator.seed(8008135);
-	}
-
-	const F32 fo_upper_bound = 5;
-	const F32 sca_upper_bound = 6;
-	const F32 fo = 1 + (F32)weather_generator() *(fo_upper_bound - 1);
-	const static F32 upper = 0.5f / gFastLn.ln(fo_upper_bound);
-	mHaze.setFalloff(fo);
-	mHaze.setG((F32)weather_generator() * (0.0f + upper * gFastLn.ln(fo)));
-	LLColor3 sca;
-	const F32 cd = mCloudDensity * 3;
-	F32 min_r = cd - 1;
-	if (min_r < 0)
-	{
-		min_r = 0;
-	}
-	F32 max_r = cd + 1;
-	if (max_r > sca_upper_bound)
-	{
-		max_r = sca_upper_bound;
-	}
-
-	sca.mV[0] = min_r + (F32)weather_generator() * (max_r - min_r);
-
-	min_r = sca.mV[0] - 0.1f;
-	if (min_r < 0)
-	{
-		min_r = 0;
-	}
-	max_r = sca.mV[0] + 0.5f;
-	if (max_r > sca_upper_bound)
-	{
-		max_r = sca_upper_bound;
-	}
-
-	sca.mV[1] = min_r + (F32)weather_generator() * (max_r - min_r);
-
-	min_r = sca.mV[1];
-	if (min_r < 0)
-	{
-		min_r = 0;
-	}
-	max_r = sca.mV[1] + 1;
-	if (max_r > sca_upper_bound)
-	{
-		max_r = sca_upper_bound;
-	}
-
-	sca.mV[2] = min_r + (F32)weather_generator() * (max_r - min_r);
-
-	sca = AIR_SCA_AVG * sca;
-
-	mHaze.setSigSca(sca);
-}
-
 void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 {
 	S32 tile_x = tile % NUM_TILES_X;
@@ -754,6 +528,7 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 			LLVector3 dir(coeff[0], coeff[1], coeff[2]);
 			dir.normVec();
 			mSkyTex[side].setDir(dir, x, y);
+			mShinyTex[side].setDir(dir, x, y);
 		}
 	}
 }
@@ -772,404 +547,491 @@ void LLVOSky::createSkyTexture(const S32 side, const S32 tile)
 		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
 		{
 			mSkyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y)), x, y);
+			mShinyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y), true), x, y);
 		}
 	}
 }
 
-
-LLColor3 LLVOSky::calcSkyColorInDir(const LLVector3 &dir)
+static inline LLColor3 componentDiv(LLColor3 const &left, LLColor3 const & right)
 {
-	LLColor3 col, transp;
-
-	if (dir.mV[VZ] < -0.02f)
-	{
-		col = LLColor3(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.27f));
-		float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]);
-		x *= x;
-		col.mV[0] *= x*x;
-		col.mV[1] *= powf(x, 2.5f);
-		col.mV[2] *= x*x*x;
-		return col;
-	}
+	return LLColor3(left.mV[0]/right.mV[0],
+					 left.mV[1]/right.mV[1],
+					 left.mV[2]/right.mV[2]);
+}
 
 
-	calcSkyColorInDir(col, transp, dir);
-	F32 br = color_max(col);
-	if (br > mBrightnessScaleNew)
-	{
-		mBrightnessScaleNew = br;
-		mBrightestPointNew = col;
-	}
-	return col;
+static inline LLColor3 componentMult(LLColor3 const &left, LLColor3 const & right)
+{
+	return LLColor3(left.mV[0]*right.mV[0],
+					 left.mV[1]*right.mV[1],
+					 left.mV[2]*right.mV[2]);
 }
 
 
-LLColor4 LLVOSky::calcInScatter(LLColor4& transp, const LLVector3 &point, F32 exager = 1) const
+static inline LLColor3 componentExp(LLColor3 const &v)
 {
-	LLColor3 col, tr;
-	calcInScatter(col, tr, point, exager);
-	col *= mBrightnessScaleGuess;
-	transp = LLColor4(tr);
-	return LLColor4(col);
+	return LLColor3(exp(v.mV[0]),
+					 exp(v.mV[1]),
+					 exp(v.mV[2]));
 }
 
+static inline LLColor3 componentPow(LLColor3 const &v, F32 exponent)
+{
+	return LLColor3(pow(v.mV[0], exponent),
+					pow(v.mV[1], exponent),
+					pow(v.mV[2], exponent));
+}
 
-
-void LLVOSky::calcSkyColorInDir(LLColor3& res, LLColor3& transp, const LLVector3& dir) const
+static inline LLColor3 componentSaturate(LLColor3 const &v)
 {
-	const LLVector3& tosun = getToSunLast();
-	res.setToBlack();
-	LLColor3 haze_res(0.f, 0.f, 0.f);
-	transp.setToWhite();
-	LLVector3 step_v ;
-	LLVector3 cur_pos = mCameraPosAgent;
-	F32 h;
-
-	F32 dist = calcHitsAtmEdge(mCameraPosAgent, dir);
-//	const F32 K = log(dist / FIRST_STEP + 1) / NO_STEPS;
-	const F32 K = gFastLn.ln(dist / FIRST_STEP + 1) / NO_STEPS;
-	const F32 e_pow_k = (F32)LL_FAST_EXP(K);
-	F32 step = FIRST_STEP * (1 - 1 / e_pow_k);
-
-	// Initialize outside the loop because we write into them every iteration. JC
-	LLColor3 air_sca_opt_depth;
-	LLColor3 haze_sca_opt_depth;
-	LLColor3 air_transp;
-
-	for (S32 s = 0; s < NO_STEPS; ++s)
-	{
-		h = calcHeight(cur_pos);
-		step *= e_pow_k;
-		LLHaze::calcAirSca(h, air_sca_opt_depth);
-		air_sca_opt_depth *= step;
-
-		mHaze.calcSigSca(h, haze_sca_opt_depth);
-		haze_sca_opt_depth *= step;
-
-		LLColor3 haze_ext_opt_depth = haze_sca_opt_depth;
-		haze_ext_opt_depth *= (1.f + mHaze.getAbsCoef());
-
-		if (calcHitsEarth(cur_pos, tosun) < 0) // calculates amount of in-scattered light from the sun
-		{
-			//visibility check is too expensive
-			mTransp.calcTransp(calcUpVec(cur_pos) * tosun, h, air_transp);
-			air_transp *= transp;
-			res += air_sca_opt_depth * air_transp;
-			haze_res += haze_sca_opt_depth * air_transp;
-		}
-		LLColor3 temp(-4.f * F_PI * (air_sca_opt_depth + haze_ext_opt_depth));
-		temp.exp();
-		transp *= temp;
-		step_v = dir * step;
-		cur_pos += step_v;
-	}
-	const F32 cos_dir = dir * tosun;
-	res *= calcAirPhaseFunc(cos_dir);
-	res += haze_res * mHaze.calcPhase(cos_dir);
-	res *= mSun.getIntensity();
+	return LLColor3(std::max(std::min(v.mV[0], 1.f), 0.f),
+					 std::max(std::min(v.mV[1], 1.f), 0.f),
+					 std::max(std::min(v.mV[2], 1.f), 0.f));
 }
 
 
+static inline LLColor3 componentSqrt(LLColor3 const &v)
+{
+	return LLColor3(sqrt(v.mV[0]),
+					 sqrt(v.mV[1]),
+					 sqrt(v.mV[2]));
+}
 
+static inline void componentMultBy(LLColor3 & left, LLColor3 const & right)
+{
+	left.mV[0] *= right.mV[0];
+	left.mV[1] *= right.mV[1];
+	left.mV[2] *= right.mV[2];
+}
 
-void LLVOSky::calcInScatter(LLColor3& res, LLColor3& transp, 
-					const LLVector3& P, const F32 exaggeration) const
+static inline LLColor3 colorMix(LLColor3 const & left, LLColor3 const & right, F32 amount)
 {
-	const LLVector3& tosun = getToSunLast();
-	res.setToBlack();
-	transp.setToWhite();
+	return (left + ((right - left) * amount));
+}
 
-	LLVector3 lower, upper;
-	LLVector3 dir = P - mCameraPosAgent;
+static inline F32 texture2D(LLPointer<LLImageRaw> const & tex, LLVector2 const & uv)
+{
+	U16 w = tex->getWidth();
+	U16 h = tex->getHeight();
 
-	F32 dist = exaggeration * dir.normVec();
+	U16 r = U16(uv[0] * w) % w;
+	U16 c = U16(uv[1] * h) % h;
 
-	const F32 cos_dir = dir * tosun;
+	U8 const * imageBuffer = tex->getData();
 
-	if (dir.mV[VZ] > 0)
-	{
-		lower = mCameraPosAgent;
-		upper = P;
-	}
-	else
-	{
-		lower = P;
-		upper = mCameraPosAgent;
-		dir = -dir;
-	}
+	U8 sample = imageBuffer[r * w + c];
 
-	const F32 lower_h = calcHeight(lower);
-	const F32 upper_h = calcHeight(upper);
-	const LLVector3 up_upper = calcUpVec(upper);
-	const LLVector3 up_lower = calcUpVec(lower);
+	return sample / 255.f;
+}
+
+static inline LLColor3 smear(F32 val)
+{
+	return LLColor3(val, val, val);
+}
 
-	transp = color_div(mTransp.calcTransp(up_lower * dir, lower_h),
-					mTransp.calcTransp(up_upper * dir, upper_h));
-	color_pow(transp, exaggeration);
+void LLVOSky::initAtmospherics(void)
+{	
+	bool error;
+	
+	// uniform parameters for convenience
+	dome_radius = LLWLParamManager::instance()->getDomeRadius();
+	dome_offset_ratio = LLWLParamManager::instance()->getDomeOffset();
+	sunlight_color = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("sunlight_color", error));
+	ambient = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("ambient", error));
+	//lightnorm = LLWLParamManager::instance()->mCurParams.getVector("lightnorm", error);
+	gamma = LLWLParamManager::instance()->mCurParams.getVector("gamma", error)[0];
+	blue_density = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("blue_density", error));
+	blue_horizon = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("blue_horizon", error));
+	haze_density = LLWLParamManager::instance()->mCurParams.getVector("haze_density", error)[0];
+	haze_horizon = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("haze_horizon", error));
+	density_multiplier = LLWLParamManager::instance()->mCurParams.getVector("density_multiplier", error)[0];
+	max_y = LLWLParamManager::instance()->mCurParams.getVector("max_y", error)[0];
+	glow = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("glow", error));
+	cloud_shadow = LLWLParamManager::instance()->mCurParams.getVector("cloud_shadow", error)[0];
+	cloud_color = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_color", error));
+	cloud_scale = LLWLParamManager::instance()->mCurParams.getVector("cloud_scale", error)[0];
+	cloud_pos_density1 = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_pos_density1", error));
+	cloud_pos_density2 = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_pos_density2", error));
+
+	// light norm is different.  We need the sun's direction, not the light direction
+	// which could be from the moon.  And we need to clamp it
+	// just like for the gpu
+	LLVector3 sunDir = gSky.getSunDirection();
+
+	// CFR_TO_OGL
+	lightnorm = LLVector4(sunDir.mV[1], sunDir.mV[2], sunDir.mV[0], 0);
+	unclamped_lightnorm = lightnorm;
+	if(lightnorm.mV[1] < -0.1f)
+	{
+		lightnorm.mV[1] = -0.1f;
+	}
+	
+}
 
-	if (calcHitsEarth(upper, tosun) > 0)
+LLColor4 LLVOSky::calcSkyColorInDir(const LLVector3 &dir, bool isShiny)
+{
+	F32 saturation = 0.3f;
+	if (dir.mV[VZ] < -0.02f)
 	{
-		const F32 avg = color_avg(transp);
-		//const F32 avg = llmin(1.f, 1.2f * color_avg(transp));
-		transp.setVec(avg, avg, avg);
-		return;
+		LLColor4 col = LLColor4(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.22f),0.f);
+		if (isShiny)
+		{
+			LLColor3 desat_fog = LLColor3(mFogColor);
+			F32 brightness = desat_fog.brightness();
+			// So that shiny somewhat shows up at night.
+			if (brightness < 0.15f)
+			{
+				brightness = 0.15f;
+				desat_fog = smear(0.15f);
+			}
+			LLColor3 greyscale = smear(brightness);
+			desat_fog = desat_fog * saturation + greyscale * (1.0f - saturation);
+			if (!gPipeline.canUseWindLightShaders())
+			{
+				col = LLColor4(desat_fog, 0.f);
+			}
+			else 
+			{
+				col = LLColor4(desat_fog * 0.5f, 0.f);
+			}
+		}
+		float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]);
+		x *= x;
+		col.mV[0] *= x*x;
+		col.mV[1] *= powf(x, 2.5f);
+		col.mV[2] *= x*x*x;
+		return col;
 	}
 
-	LLColor3 air_sca_opt_depth = LLHaze::calcAirSca(upper_h);
-	LLColor3 haze_sca_opt_depth = mHaze.calcSigSca(upper_h);
-	LLColor3 sun_transp;
-	mTransp.calcTransp(up_upper * tosun, upper_h, sun_transp);
+	// undo OGL_TO_CFR_ROTATION and negate vertical direction.
+	LLVector3 Pn = LLVector3(-dir[1] , -dir[2], -dir[0]);
 
-	if (calcHitsEarth(lower, tosun) < 0)
+	LLColor3 vary_HazeColor(0,0,0);
+	LLColor3 vary_CloudColorSun(0,0,0);
+	LLColor3 vary_CloudColorAmbient(0,0,0);
+	F32 vary_CloudDensity(0);
+	LLVector2 vary_HorizontalProjection[2];
+	vary_HorizontalProjection[0] = LLVector2(0,0);
+	vary_HorizontalProjection[1] = LLVector2(0,0);
+
+	calcSkyColorWLVert(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient,
+						vary_CloudDensity, vary_HorizontalProjection);
+	
+	LLColor3 sky_color =  calcSkyColorWLFrag(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient, 
+								vary_CloudDensity, vary_HorizontalProjection);
+	if (isShiny)
 	{
-		air_sca_opt_depth += LLHaze::calcAirSca(lower_h);
-		air_sca_opt_depth *= 0.5;
-		haze_sca_opt_depth += mHaze.calcSigSca(lower_h);
-		haze_sca_opt_depth *= 0.5;
-		sun_transp += mTransp.calcTransp(up_lower * tosun, lower_h);
-		sun_transp *= 0.5;
+		F32 brightness = sky_color.brightness();
+		LLColor3 greyscale = smear(brightness);
+		sky_color = sky_color * saturation + greyscale * (1.0f - saturation);
+		sky_color *= (0.5f + 0.5f * brightness);
 	}
-
-	res = calcAirPhaseFunc(cos_dir) * air_sca_opt_depth;
-	res += mHaze.calcPhase(cos_dir) * haze_sca_opt_depth;
-	res = mSun.getIntensity() * dist * sun_transp * res;
+	return LLColor4(sky_color, 0.0f);
 }
 
+// turn on floating point precision
+// in vs2003 for this function.  Otherwise
+// sky is aliased looking 7:10 - 8:50
+#if LL_MSVC && __MSVC_VER__ < 8
+#pragma optimize("p", on)
+#endif
 
+void LLVOSky::calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
+							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
+							LLVector2 vary_HorizontalProjection[2])
+{
+	// project the direction ray onto the sky dome.
+	F32 phi = acos(Pn[1]);
+	F32 sinA = sin(F_PI - phi);
+	F32 Plen = dome_radius * sin(F_PI + phi + asin(dome_offset_ratio * sinA)) / sinA;
 
+	Pn *= Plen;
 
+	vary_HorizontalProjection[0] = LLVector2(Pn[0], Pn[2]);
+	vary_HorizontalProjection[0] /= - 2.f * Plen;
 
-
-F32 LLVOSky::calcHitsEarth(const LLVector3& orig, const LLVector3& dir) const
-{
-	const LLVector3 from_earth_center = mEarthCenter - orig;
-	const F32 tca = dir * from_earth_center;
-	if ( tca < 0 )
+	// Set altitude
+	if (Pn[1] > 0.f)
 	{
-		return -1;
+		Pn *= (max_y / Pn[1]);
 	}
-
-	const F32 thc2 = EARTH_RADIUS * EARTH_RADIUS -
-			from_earth_center.magVecSquared() + tca * tca;
-	if (thc2 < 0 )
+	else
 	{
-		return -1;
+		Pn *= (-32000.f / Pn[1]);
 	}
 
-	return tca - sqrt ( thc2 );
-}
+	Plen = Pn.magVec();
+	Pn /= Plen;
 
-F32 LLVOSky::calcHitsAtmEdge(const LLVector3& orig, const LLVector3& dir) const
-{
-	const LLVector3 from_earth_center = mEarthCenter - orig;
-	const F32 tca = dir * from_earth_center;
+	// Initialize temp variables
+	LLColor3 sunlight = sunlight_color;
 
-	const F32 thc2 = (EARTH_RADIUS + mAtmHeight) * (EARTH_RADIUS + mAtmHeight) -
-			from_earth_center.magVecSquared() + tca * tca;
-	return tca + sqrt(thc2);
-}
+	// Sunlight attenuation effect (hue and brightness) due to atmosphere
+	// this is used later for sunlight modulation at various altitudes
+	LLColor3 light_atten =
+		(blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y);
 
+	// Calculate relative weights
+	LLColor3 temp2(0.f, 0.f, 0.f);
+	LLColor3 temp1 = blue_density + smear(haze_density);
+	LLColor3 blue_weight = componentDiv(blue_density, temp1);
+	LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
 
-void LLVOSky::updateBrightestDir()
-{
-	LLColor3 br_pt, transp;
-	const S32 test_no = 5;
-	const F32 step = F_PI_BY_TWO / (test_no + 1);
-	for (S32 i = 0; i < test_no; ++i)
-	{
-		F32 cos_dir = cos ((i + 1) * step);
-		calcSkyColorInDir(br_pt, transp, move_vec(getToSunLast(), cos_dir));
-		const F32 br = color_max(br_pt);
-		if (br > mBrightnessScaleGuess)
-		{
-			mBrightnessScaleGuess = br;
-			mBrightestPointGuess = br_pt;
-		}
-	}
-}
+	// Compute sunlight from P & lightnorm (for long rays like sky)
+	temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] );
 
+	temp2.mV[1] = 1.f / temp2.mV[1];
+	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
 
-void LLVOSky::calcBrightnessScaleAndColors()
-{
-	// new correct normalization.
-	if (mBrightnessScaleNew < 1e-7)
-	{
-		mBrightnessScale = 1;
-		mBrightestPoint.setToBlack();
-	}
-	else
-	{
-		mBrightnessScale = 1.f/mBrightnessScaleNew;
-		mBrightestPoint = mBrightestPointNew;
-	}
+	// Distance
+	temp2.mV[2] = Plen * density_multiplier;
 
-	mBrightnessScaleNew = 0;
-	// and addition
+	// Transparency (-> temp1)
+	temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
 
-	// Calculate Sun and Moon color
-	const F32 h = llmax(0.0f, mCameraPosAgent.mV[2]);
-	const LLColor3 sun_color = mSun.getIntensity() * mTransp.calcTransp(getToSunLast().mV[2], h);
-	const LLColor3 moon_color = mNightColorShift * 
-				mMoon.getIntensity() * mTransp.calcTransp(getToMoonLast().mV[2], h);
 
-	F32 intens = color_intens(sun_color);
-	F32 increase_sun_br = (intens > 0) ? 1.2f * color_intens(mBrightestPoint) / intens : 1;
+	// Compute haze glow
+	temp2.mV[0] = Pn * LLVector3(lightnorm);
 
-	intens = color_intens(moon_color);
-	F32 increase_moon_br = (intens > 0) ? 1.2f * llmax(1.0f, color_intens(mBrightestPoint) / intens) : 1;
+	temp2.mV[0] = 1.f - temp2.mV[0];
+		// temp2.x is 0 at the sun and increases away from sun
+	temp2.mV[0] = llmax(temp2.mV[0], .001f);	
+		// Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.mV[0] *= glow.mV[0];
+		// Higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.mV[0] = pow(temp2.mV[0], glow.mV[2]);
+		// glow.z should be negative, so we're doing a sort of (1 / "angle") function
 
-	mSun.setColor(mBrightnessScale * increase_sun_br * sun_color);
-	mMoon.setColor(mBrightnessScale * increase_moon_br * moon_color);
+	// Add "minimum anti-solar illumination"
+	temp2.mV[0] += .25f;
 
-	const LLColor3 haze_col = color_norm_abs(mHaze.getSigSca());
-	for (S32 i = 0; i < 6; ++i)
-	{
-		mSkyTex[i].create(mBrightnessScale, mHazeConcentration * mBrightestPoint * haze_col);
-	}
 
-	mBrightnessScaleGuess = mBrightnessScale;
-	mBrightestPointGuess = mBrightestPoint;
+	// Haze color above cloud
+	vary_HazeColor = (blue_horizon * blue_weight * (sunlight + ambient)
+				+ componentMult(haze_horizon.mV[0] * haze_weight, sunlight * temp2.mV[0] + ambient)
+			 );	
 
-//	calculateColors(); // MSMSM Moving this down to before generateScatterMap(), per Milo Lindens suggestion, to fix orange flashing bug.
+	// Increase ambient when there are more clouds
+	LLColor3 tmpAmbient = ambient + (LLColor3::white - ambient) * cloud_shadow * 0.5f;
 
-	mSun.renewDirection();
-	mSun.renewColor();
-	mMoon.renewDirection();
-	mMoon.renewColor();
+	// Dim sunlight by cloud shadow percentage
+	sunlight *= (1.f - cloud_shadow);
 
-	LLColor3 transp;
+	// Haze color below cloud
+	LLColor3 additiveColorBelowCloud = (blue_horizon * blue_weight * (sunlight + tmpAmbient)
+				+ componentMult(haze_horizon.mV[0] * haze_weight, sunlight * temp2.mV[0] + tmpAmbient)
+			 );	
 
-	if (calcHitsEarth(mCameraPosAgent, getToSunLast()) < 0)
-	{
-		calcSkyColorInDir(mBrightestPointGuess, transp, getToSunLast());
-		mBrightnessScaleGuess = color_max(mBrightestPointGuess);
-		updateBrightestDir();
-		mBrightnessScaleGuess = 1.f / llmax(1.0f, mBrightnessScaleGuess);
-	}
-	else if (getToSunLast().mV[2] > -0.5)
-	{
-		const LLVector3 almost_to_sun = toHorizon(getToSunLast());
-		calcSkyColorInDir(mBrightestPointGuess, transp, almost_to_sun);
-		mBrightnessScaleGuess = color_max(mBrightestPointGuess);
-		updateBrightestDir();
-		mBrightnessScaleGuess = 1.f / llmax(1.0f, mBrightnessScaleGuess);
-	}
-	else
+	// Final atmosphere additive
+	componentMultBy(vary_HazeColor, LLColor3::white - temp1);
+
+	sunlight = sunlight_color;
+	temp2.mV[1] = llmax(0.f, lightnorm[1] * 2.f);
+	temp2.mV[1] = 1.f / temp2.mV[1];
+	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
+
+	// Attenuate cloud color by atmosphere
+	temp1 = componentSqrt(temp1);	//less atmos opacity (more transparency) below clouds
+
+	// At horizon, blend high altitude sky color towards the darker color below the clouds
+	vary_HazeColor +=
+		componentMult(additiveColorBelowCloud - vary_HazeColor, LLColor3::white - componentSqrt(temp1));
+		
+	if (Pn[1] < 0.f)
 	{
-		mBrightestPointGuess.setToBlack();
-		mBrightnessScaleGuess = 1;
-	}
+		// Eric's original: 
+		// LLColor3 dark_brown(0.143f, 0.129f, 0.114f);
+		LLColor3 dark_brown(0.082f, 0.076f, 0.066f);
+		LLColor3 brown(0.430f, 0.386f, 0.322f);
+		LLColor3 sky_lighting = sunlight + ambient;
+		F32 haze_brightness = vary_HazeColor.brightness();
 
-	calculateColors(); // MSMSM Moved this down here per Milo Lindens suggestion, to fix orange flashing bug at sunset.
+		if (Pn[1] < -0.05f)
+		{
+			vary_HazeColor = colorMix(dark_brown, brown, -Pn[1] * 0.9f) * sky_lighting * haze_brightness;
+		}
+		
+		if (Pn[1] > -0.1f)
+		{
+			vary_HazeColor = colorMix(LLColor3::white * haze_brightness, vary_HazeColor, fabs((Pn[1] + 0.05f) * -20.f));
+		}
+	}
 }
 
+#if LL_MSVC && __MSVC_VER__ < 8
+#pragma optimize("p", off)
+#endif
 
-void LLVOSky::calculateColors()
+LLColor3 LLVOSky::calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
+							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
+							LLVector2 vary_HorizontalProjection[2])
 {
-	const F32 h = -0.1f;
-	const LLVector3& tosun = getToSunLast();
+	LLColor3 res;
 
-	F32 full_on, full_off, on, on_cl;
-	F32 sun_factor = 1;
+	LLColor3 color0 = vary_HazeColor;
 	
-	// Sun Diffuse
-	F32 sun_height = tosun.mV[2];
+	if (!gPipeline.canUseWindLightShaders())
+	{
+		LLColor3 color1 = color0 * 2.0f;
+		color1 = smear(1.f) - componentSaturate(color1);
+		componentPow(color1, gamma);
+		res = smear(1.f) - color1;
+	} 
+	else 
+	{
+		res = color0;
+	}
+
+#	ifndef LL_RELEASE_FOR_DOWNLOAD
+
+	LLColor3 color2 = 2.f * color0;
+
+	LLColor3 color3 = LLColor3(1.f, 1.f, 1.f) - componentSaturate(color2);
+	componentPow(color3, gamma);
+	color3 = LLColor3(1.f, 1.f, 1.f) - color3;
+
+	static enum {
+		OUT_DEFAULT		= 0,
+		OUT_SKY_BLUE	= 1,
+		OUT_RED			= 2,
+		OUT_PN			= 3,
+		OUT_HAZE		= 4,
+	} debugOut = OUT_DEFAULT;
+
+	switch(debugOut) 
+	{
+		case OUT_DEFAULT:
+			break;
+		case OUT_SKY_BLUE:
+			res = LLColor3(0.4f, 0.4f, 0.9f);
+			break;
+		case OUT_RED:
+			res = LLColor3(1.f, 0.f, 0.f);
+			break;
+		case OUT_PN:
+			res = LLColor3(Pn[0], Pn[1], Pn[2]);
+			break;
+		case OUT_HAZE:
+			res = vary_HazeColor;
+			break;
+	}
+#	endif // LL_RELEASE_FOR_DOWNLOAD
+	return res;
+}
 
-	if (sun_height <= 0.0)
-		sun_height = 0.0;
-	
-	mSunDiffuse = mBrightnessScaleGuess * mSun.getIntensity() * mTransp.calcTransp(sun_height, h);
+LLColor3 LLVOSky::createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient)
+{
+	return componentMult(diffuse, sundiffuse) * 4.0f +
+			componentMult(ambient, sundiffuse) * 2.0f + sunambient;
+}
 
-	mSunDiffuse = 1.0f * color_norm(mSunDiffuse);
+LLColor3 LLVOSky::createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient)
+{
+	return (componentMult(ambient, sundiffuse) + sunambient) * 0.8f;
+}
 
-	// Sun Ambient
-	full_off = -0.3f;
-	full_on = -0.03f;
-	if (tosun.mV[2] < full_off)
-	{
-		mSunAmbient.setToBlack();
-	}
-	else
+
+void LLVOSky::calcAtmospherics(void)
+{
+	initAtmospherics();
+
+	LLColor3 vary_HazeColor;
+	LLColor3 vary_SunlightColor;
+	LLColor3 vary_AmbientColor;
 	{
-		on = (tosun.mV[2] - full_off) / (full_on - full_off);
-		sun_factor = llmax(0.0f, llmin(on, 1.0f));
+		// Initialize temp variables
+		LLColor3 sunlight = sunlight_color;
 
-		LLColor3 sun_amb = mAmbientScale * (0.8f * mSunDiffuse + 
-					0.2f * mBrightnessScaleGuess * mBrightestPointGuess);
+		// Sunlight attenuation effect (hue and brightness) due to atmosphere
+		// this is used later for sunlight modulation at various altitudes
+		LLColor3 light_atten =
+			(blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y);
 
-		color_norm_pow(sun_amb, 0.1f, TRUE);
-		sun_factor *= min_intens_factor(sun_amb, 1.9f);
-		mSunAmbient = LLColor4(sun_factor * sun_amb);
-	}
+		// Calculate relative weights
+		LLColor3 temp2(0.f, 0.f, 0.f);
+		LLColor3 temp1 = blue_density + smear(haze_density);
+		LLColor3 blue_weight = componentDiv(blue_density, temp1);
+		LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
 
+		// Compute sunlight from P & lightnorm (for long rays like sky)
+		/// USE only lightnorm.
+		// temp2[1] = llmax(0.f, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] );
+		
+		// and vary_sunlight will work properly with moon light
+		F32 lighty = unclamped_lightnorm[1];
+		if(lighty < NIGHTTIME_ELEVATION_COS)
+		{
+			lighty = -lighty;
+		}
 
-	// Moon Diffuse
-	full_on = 0.3f;
-	full_off = 0.01f;
-	if (getToMoonLast().mV[2] < full_off)
-	{
-		mMoonDiffuse.setToBlack();
-	}
-	else
-	{
-		// Steve: Added moonlight diffuse factor scalar (was constant .3)
-		F32 diffuse_factor = .1f + sNighttimeBrightness * .2f; // [.1, .5] default = .3
-		on = (getToMoonLast().mV[2] - full_off) / (full_on - full_off);
-		on_cl = llmin(on, 1.0f);
-		mMoonDiffuse = on_cl * mNightColorShift * diffuse_factor;
-	}
+		temp2.mV[1] = llmax(0.f, lighty);
+		temp2.mV[1] = 1.f / temp2.mV[1];
+		componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
 
-	// Moon Ambient
+		// Distance
+		temp2.mV[2] = density_multiplier;
 
-	F32 moon_amb_factor = 1.f;
+		// Transparency (-> temp1)
+		temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
 
-	if (gAgent.inPrelude())
-	{
-		moon_amb_factor *= 2.0f;
-	}
+		// vary_AtmosAttenuation = temp1; 
+
+		//increase ambient when there are more clouds
+		LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5f;
+
+		//haze color
+		vary_HazeColor =
+			(blue_horizon * blue_weight * (sunlight*(1.f - cloud_shadow) + tmpAmbient)	
+			+ componentMult(haze_horizon.mV[0] * haze_weight, sunlight*(1.f - cloud_shadow) * temp2.mV[0] + tmpAmbient)
+				 );	
+
+		//brightness of surface both sunlight and ambient
+		vary_SunlightColor = componentMult(sunlight, temp1) * 1.f;
+		vary_SunlightColor.clamp();
+		vary_SunlightColor = smear(1.0f) - vary_SunlightColor;
+		vary_SunlightColor = componentPow(vary_SunlightColor, gamma);
+		vary_SunlightColor = smear(1.0f) - vary_SunlightColor;
+		vary_AmbientColor = componentMult(tmpAmbient, temp1) * 0.5;
+		vary_AmbientColor.clamp();
+		vary_AmbientColor = smear(1.0f) - vary_AmbientColor;
+		vary_AmbientColor = componentPow(vary_AmbientColor, gamma);
+		vary_AmbientColor = smear(1.0f) - vary_AmbientColor;
+
+		componentMultBy(vary_HazeColor, LLColor3(1.f, 1.f, 1.f) - temp1);
 
-	full_on = 0.30f;
-	full_off = 0.01f;
-	if (getToMoonLast().mV[2] < full_off)
-	{
-		mMoonAmbient.setToBlack();
-	}
-	else
-	{
-		on = (getToMoonLast().mV[2] - full_off) / (full_on - full_off);
-		on_cl = llmax(0.0f, llmin(on, 1.0f));
-		mMoonAmbient = on_cl * moon_amb_factor * mMoonDiffuse;
 	}
 
+	mSun.setColor(vary_SunlightColor);
+	mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f));
 
-	// Sun Diffuse
-	full_off = -0.05f;
-	full_on = -0.00f;
-	if (tosun.mV[2] < full_off)
+	mSun.renewDirection();
+	mSun.renewColor();
+	mMoon.renewDirection();
+	mMoon.renewColor();
+
+	float dp = getToSunLast() * LLVector3(0,0,1.f);
+	if (dp < 0)
 	{
-		mSunDiffuse.setToBlack();
+		dp = 0;
 	}
-	else
-	{
-		on = (getToSunLast().mV[2] - full_off) / (full_on - full_off);
-		sun_factor = llmax(0.0f, llmin(on, 1.0f));
 
-		color_norm_pow(mSunDiffuse, 0.12f, TRUE);
-		sun_factor *= min_intens_factor(mSunDiffuse, 2.1f);
-		mSunDiffuse *= sun_factor;
-	}
+	// Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio
+	// between sunlight and point lights in windlight to normalize point lights.
+	F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f);
+	LLWLParamManager::instance()->mSceneLightStrength = 2.0f * (1.0f + sun_dynamic_range * dp);
 
+	mSunDiffuse = vary_SunlightColor;
+	mSunAmbient = vary_AmbientColor;
+	mMoonDiffuse = vary_SunlightColor;
+	mMoonAmbient = vary_AmbientColor;
 
-	mTotalAmbient = mSunAmbient + mMoonAmbient;
+	mTotalAmbient = vary_AmbientColor;
 	mTotalAmbient.setAlpha(1);
-	//llinfos << "MoonDiffuse: " << mMoonDiffuse << llendl;
-	//llinfos << "TotalAmbient: " << mTotalAmbient << llendl;
-
+	
 	mFadeColor = mTotalAmbient + (mSunDiffuse + mMoonDiffuse) * 0.5f;
 	mFadeColor.setAlpha(0);
 }
 
-
 BOOL LLVOSky::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
 	return TRUE;
@@ -1177,7 +1039,7 @@ BOOL LLVOSky::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 
 BOOL LLVOSky::updateSky()
 {
- 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)))
+	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)))
 	{
 		return TRUE;
 	}
@@ -1196,7 +1058,7 @@ BOOL LLVOSky::updateSky()
 	const S32 total_no_tiles = 6 * NUM_TILES;
 	const S32 cycle_frame_no = total_no_tiles + 1;
 
-//	if (mUpdateTimer.getElapsedTimeF32() > 0.1f)
+	if (mUpdateTimer.getElapsedTimeF32() > 0.001f)
 	{
 		mUpdateTimer.reset();
 		const S32 frame = next_frame;
@@ -1205,12 +1067,13 @@ BOOL LLVOSky::updateSky()
 		next_frame = next_frame % cycle_frame_no;
 
 		sInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no;
+		// sInterpVal = (F32)next_frame / cycle_frame_no;
 		LLSkyTex::setInterpVal( sInterpVal );
 		LLHeavenBody::setInterpVal( sInterpVal );
-		calculateColors();
+		calcAtmospherics();
+
 		if (mForceUpdate || total_no_tiles == frame)
 		{
-			calcBrightnessScaleAndColors();
 			LLSkyTex::stepCurrent();
 			
 			const static F32 LIGHT_DIRECTION_THRESHOLD = (F32) cos(DEG_TO_RAD * 1.f);
@@ -1248,7 +1111,7 @@ BOOL LLVOSky::updateSky()
 							}
 						}
 
-						calcBrightnessScaleAndColors();
+						calcAtmospherics();
 
 						for (int side = 0; side < 6; side++) 
 						{
@@ -1256,21 +1119,42 @@ BOOL LLVOSky::updateSky()
 							LLImageRaw* raw2 = mSkyTex[side].getImageRaw(FALSE);
 							raw2->copy(raw1);
 							mSkyTex[side].createGLImage(mSkyTex[side].getWhich(FALSE));
+
+							raw1 = mShinyTex[side].getImageRaw(TRUE);
+							raw2 = mShinyTex[side].getImageRaw(FALSE);
+							raw2->copy(raw1);
+							mShinyTex[side].createGLImage(mShinyTex[side].getWhich(FALSE));
 						}
 						next_frame = 0;	
 					}
+				}
+			}
 
-					std::vector<LLPointer<LLImageRaw> > images;
-					for (S32 side = 0; side < 6; side++)
-					{
-						images.push_back(mSkyTex[side].getImageRaw(FALSE));
-					}
-					mCubeMap->init(images);
+			/// *TODO really, sky texture and env map should be shared on a single texture
+			/// I'll let Brad take this at some point
+
+			// update the sky texture
+			for (S32 i = 0; i < 6; ++i)
+			{
+				mSkyTex[i].create(1.0f);
+				mShinyTex[i].create(1.0f);
+			}
+			
+			// update the environment map
+			if (mCubeMap)
+			{
+				std::vector<LLPointer<LLImageRaw> > images;
+				images.reserve(6);
+				for (S32 side = 0; side < 6; side++)
+				{
+					images.push_back(mShinyTex[side].getImageRaw(TRUE));
 				}
+				mCubeMap->init(images);
 			}
 
 			gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-			gPipeline.markRebuild(gSky.mVOStarsp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+			// *TODO: decide whether we need to update the stars vertex buffer in LLVOWLSky -Brad.
+			//gPipeline.markRebuild(gSky.mVOWLSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 
 			mForceUpdate = FALSE;
 		}
@@ -1282,15 +1166,13 @@ BOOL LLVOSky::updateSky()
 		}
 	}
 
-
-	if (mDrawable)
+	if (mDrawable.notNull() && mDrawable->getFace(0) && mDrawable->getFace(0)->mVertexBuffer.isNull())
 	{
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
 	}
 	return TRUE;
 }
 
-
 void LLVOSky::updateTextures(LLAgent &agent)
 {
 	if (mSunTexturep)
@@ -1324,12 +1206,61 @@ LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
+//by bao
+//fake vertex buffer updating
+//to guaranttee at least updating one VBO buffer every frame
+//to walk around the bug caused by ATI card --> DEV-3855
+//
+void LLVOSky::createDummyVertexBuffer()
+{
+	if(!mFace[FACE_DUMMY])
+	{
+		LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY);
+		mFace[FACE_DUMMY] = mDrawable->addFace(poolp, NULL);
+	}
+
+	if(mFace[FACE_DUMMY]->mVertexBuffer.isNull())
+	{
+		mFace[FACE_DUMMY]->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
+		mFace[FACE_DUMMY]->mVertexBuffer->allocateBuffer(1, 1, TRUE);
+	}
+}
+
+void LLVOSky::updateDummyVertexBuffer()
+{	
+	if(!LLVertexBuffer::sEnableVBOs)
+		return ;
+
+	if(mHeavenlyBodyUpdated)
+	{
+		mHeavenlyBodyUpdated = FALSE ;
+		return ;
+	}
+
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE) ;
+
+	if(!mFace[FACE_DUMMY] || mFace[FACE_DUMMY]->mVertexBuffer.isNull())
+		createDummyVertexBuffer() ;
+
+	LLStrider<LLVector3> vertices ;
+	mFace[FACE_DUMMY]->mVertexBuffer->getVertexStrider(vertices,  0);
+	*vertices = mCameraPosAgent ;
+	mFace[FACE_DUMMY]->mVertexBuffer->setBuffer(0) ;
+}
+//----------------------------------
+//end of fake vertex buffer updating
+//----------------------------------
+
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 {
+	LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY);
 	if (mFace[FACE_REFLECTION] == NULL)
 	{
 		LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
-		mFace[FACE_REFLECTION] = drawable->addFace(poolp, NULL);
+		if (gPipeline.getPool(LLDrawPool::POOL_WATER)->getVertexShaderLevel() != 0)
+		{
+			mFace[FACE_REFLECTION] = drawable->addFace(poolp, NULL);
+		}
 	}
 
 	mCameraPosAgent = drawable->getPositionAgent();
@@ -1342,14 +1273,14 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 		F32 x_sgn = (i&1) ? 1.f : -1.f;
 		F32 y_sgn = (i&2) ? 1.f : -1.f;
 		F32 z_sgn = (i&4) ? 1.f : -1.f;
-		v_agent[i] = HORIZON_DIST*0.25f * LLVector3(x_sgn, y_sgn, z_sgn);
+		v_agent[i] = HORIZON_DIST * SKY_BOX_MULT * LLVector3(x_sgn, y_sgn, z_sgn);
 	}
 
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
-	S32 index_offset;
+	LLStrider<U16> indicesp;
+	U16 index_offset;
 	LLFace *face;	
 
 	for (S32 side = 0; side < 6; ++side)
@@ -1395,6 +1326,8 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 			*indicesp++ = index_offset + 0;
 			*indicesp++ = index_offset + 3;
 			*indicesp++ = index_offset + 2;
+
+			face->mVertexBuffer->setBuffer(0);
 		}
 	}
 
@@ -1430,11 +1363,8 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 	
 	if (height_above_water > 0)
 	{
-#if 1 //1.9.1
 		BOOL render_ref = gPipeline.getPool(LLDrawPool::POOL_WATER)->getVertexShaderLevel() == 0;
-#else
-		BOOL render_ref = !(gPipeline.getVertexShaderLevel(LLPipeline::SHADER_ENVIRONMENT) >= LLDrawPoolWater::SHADER_LEVEL_RIPPLE);
-#endif
+
 		if (sun_flag)
 		{
 			setDrawRefl(0);
@@ -1457,24 +1387,29 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 		setDrawRefl(-1);
 	}
 
-
 	LLPipeline::sCompiles++;
 	return TRUE;
 }
 
-
 BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, const BOOL is_sun,
 										 LLHeavenBody& hb, const F32 cos_max_angle,
 										 const LLVector3 &up, const LLVector3 &right)
 {
+	mHeavenlyBodyUpdated = TRUE ;
+
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 	S32 index_offset;
 	LLFace *facep;
 
 	LLVector3 to_dir = hb.getDirection();
+
+	if (!is_sun)
+	{
+		to_dir.mV[2] = llmax(to_dir.mV[2]+0.1f, 0.1f);
+	}
 	LLVector3 draw_pos = to_dir * HEAVENLY_BODY_DIST;
 
 
@@ -1521,14 +1456,15 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
 
 	if (facep->mVertexBuffer.isNull())
 	{
-		facep->setSize(4, 6);
-		facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+		facep->setSize(4, 6);		
+		facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
 		facep->mVertexBuffer->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE);
 		facep->setGeomIndex(0);
 		facep->setIndicesIndex(0);
 	}
 
 	index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
+
 	if (-1 == index_offset)
 	{
 		return TRUE;
@@ -1542,10 +1478,8 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
 
 	*(texCoordsp++) = TEX01;
 	*(texCoordsp++) = TEX00;
-	//*(texCoordsp++) = (t_left > 0) ? LLVector2(0, t_left) : TEX00;
 	*(texCoordsp++) = TEX11;
 	*(texCoordsp++) = TEX10;
-	//*(texCoordsp++) = (t_right > 0) ? LLVector2(1, t_right) : TEX10;
 
 	*indicesp++ = index_offset + 0;
 	*indicesp++ = index_offset + 2;
@@ -1555,6 +1489,8 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
 	*indicesp++ = index_offset + 2;
 	*indicesp++ = index_offset + 3;
 
+	facep->mVertexBuffer->setBuffer(0);
+
 	if (is_sun)
 	{
 		if ((t_left > 0) && (t_right > 0))
@@ -1651,12 +1587,13 @@ F32 clip_side_to_horizon(const LLVector3& V0, const LLVector3& V1, const F32 cos
 
 void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable )
 {
+#if 0
 	const LLVector3* v_corner = mSun.corners();
 
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 	S32 index_offset;
 	LLFace *face;
 
@@ -1708,6 +1645,7 @@ void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable )
 	*indicesp++ = index_offset + 1;
 	*indicesp++ = index_offset + 2;
 	*indicesp++ = index_offset + 3;
+#endif
 }
 
 
@@ -1932,7 +1870,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 	S32 index_offset;
 	
 	index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
@@ -2063,6 +2001,8 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 			}
 		}
 	}
+
+	face->mVertexBuffer->setBuffer(0);
 }
 
 
@@ -2072,37 +2012,11 @@ void LLVOSky::updateFog(const F32 distance)
 {
 	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
 	{
-		/*gGLSFog.addCap(GL_FOG, FALSE);
-		gGLSPipeline.addCap(GL_FOG, FALSE);
-		gGLSPipelineAlpha.addCap(GL_FOG, FALSE);
-		gGLSPipelinePixieDust.addCap(GL_FOG, FALSE);
-		gGLSPipelineSelection.addCap(GL_FOG, FALSE);
-		gGLSPipelineAvatar.addCap(GL_FOG, FALSE);
-		gGLSPipelineAvatarAlphaOnePass.addCap(GL_FOG, FALSE);
-		gGLSPipelineAvatarAlphaPass1.addCap(GL_FOG, FALSE);
-		gGLSPipelineAvatarAlphaPass2.addCap(GL_FOG, FALSE);
-		gGLSPipelineAvatarAlphaPass3.addCap(GL_FOG, FALSE);*/
 		glFogf(GL_FOG_DENSITY, 0);
 		glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV);
 		glFogf(GL_FOG_END, 1000000.f);
 		return;
 	}
-	else
-	{
-		/*gGLSFog.addCap(GL_FOG, TRUE);
-		gGLSPipeline.addCap(GL_FOG, TRUE);
-		gGLSPipelineAlpha.addCap(GL_FOG, TRUE);
-		gGLSPipelinePixieDust.addCap(GL_FOG, TRUE);
-		gGLSPipelineSelection.addCap(GL_FOG, TRUE);
-		if (!gGLManager.mIsATI)
-		{
-			gGLSPipelineAvatar.addCap(GL_FOG, TRUE);
-			gGLSPipelineAvatarAlphaOnePass.addCap(GL_FOG, TRUE);
-			gGLSPipelineAvatarAlphaPass1.addCap(GL_FOG, TRUE);
-			gGLSPipelineAvatarAlphaPass2.addCap(GL_FOG, TRUE);
-			gGLSPipelineAvatarAlphaPass3.addCap(GL_FOG, TRUE);
-		}*/
-	}
 
 	const BOOL hide_clip_plane = TRUE;
 	LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
@@ -2120,7 +2034,6 @@ void LLVOSky::updateFog(const F32 distance)
 	LLColor3 sky_fog_color = LLColor3::white;
 	LLColor3 render_fog_color = LLColor3::white;
 
-	LLColor3 transp;
 	LLVector3 tosun = getToSunLast();
 	const F32 tosun_z = tosun.mV[VZ];
 	tosun.mV[VZ] = 0.f;
@@ -2140,9 +2053,10 @@ void LLVOSky::updateFog(const F32 distance)
 	tosun_45.normVec();
 
 	// 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.
-	calcSkyColorInDir(res_color[0],transp, tosun);
-	calcSkyColorInDir(res_color[1],transp, perp_tosun);
-	calcSkyColorInDir(res_color[2],transp, tosun_45);
+	initAtmospherics();
+	res_color[0] = calcSkyColorInDir(tosun);
+	res_color[1] = calcSkyColorInDir(perp_tosun);
+	res_color[2] = calcSkyColorInDir(tosun_45);
 
 	sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]);
 
@@ -2163,54 +2077,59 @@ void LLVOSky::updateFog(const F32 distance)
 	color_gamma_correct(sky_fog_color);
 
 	render_fog_color = sky_fog_color;
+
+	F32 fog_density = 0.f;
+	fog_distance = mFogRatio * distance;
 	
 	if (camera_height > water_height)
 	{
-		fog_distance = mFogRatio * distance;
 		LLColor4 fog(render_fog_color);
 		glFogfv(GL_FOG_COLOR, fog.mV);
 		mGLFogCol = fog;
+
+		if (hide_clip_plane)
+		{
+			// For now, set the density to extend to the cull distance.
+			const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
+			fog_density = f_log/fog_distance;
+			glFogi(GL_FOG_MODE, GL_EXP2);
+		}
+		else
+		{
+			const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
+			fog_density = (f_log)/fog_distance;
+			glFogi(GL_FOG_MODE, GL_EXP);
+		}
 	}
 	else
 	{
-		// Interpolate between sky fog and water fog...
 		F32 depth = water_height - camera_height;
-		F32 depth_frac = 1.f/(1.f + 200.f*depth);
-		F32 color_frac = 1.f/(1.f + 0.5f* depth)* 0.2f;
-		fog_distance = (mFogRatio * distance) * depth_frac + 30.f * (1.f-depth_frac);
-		fog_distance = llmin(75.f, fog_distance);
-
-		F32 brightness = 1.f/(1.f + 0.05f*depth);
-		F32 sun_brightness = getSunDiffuseColor().magVec() * 0.3f;
-		brightness = llmin(1.f, brightness);
-		brightness = llmin(brightness, sun_brightness);
-		color_frac = llmin(0.7f, color_frac);
-
-		LLColor4 fogCol = brightness * (color_frac * render_fog_color + (1.f - color_frac) * LLColor4(0.f, 0.2f, 0.3f, 1.f));
+		
+		// get the water param manager variables
+		float water_fog_density = LLWaterParamManager::instance()->getFogDensity();
+		LLColor4 water_fog_color = LLDrawPoolWater::sWaterFogColor.mV;
+		
+		// adjust the color based on depth.  We're doing linear approximations
+		float depth_scale = gSavedSettings.getF32("WaterGLFogDepthScale");
+		float depth_modifier = 1.0f - llmin(llmax(depth / depth_scale, 0.01f), 
+			gSavedSettings.getF32("WaterGLFogDepthFloor"));
+
+		LLColor4 fogCol = water_fog_color * depth_modifier;
 		fogCol.setAlpha(1);
+
+		// set the gl fog color
 		glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV);
 		mGLFogCol = fogCol;
+
+		// set the density based on what the shaders use
+		fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale");
+		glFogi(GL_FOG_MODE, GL_EXP2);
 	}
 
 	mFogColor = sky_fog_color;
 	mFogColor.setAlpha(1);
 	LLGLSFog gls_fog;
 
-	F32 fog_density;
-	if (hide_clip_plane)
-	{
-		// For now, set the density to extend to the cull distance.
-		const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
-		fog_density = f_log/fog_distance;
-		glFogi(GL_FOG_MODE, GL_EXP2);
-	}
-	else
-	{
-		const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
-		fog_density = (f_log)/fog_distance;
-		glFogi(GL_FOG_MODE, GL_EXP);
-	}
-
 	glFogf(GL_FOG_END, fog_distance*2.2f);
 
 	glFogf(GL_FOG_DENSITY, fog_density);
@@ -2279,197 +2198,53 @@ F32 azimuth(const LLVector3 &v)
 	return azimuth;
 }
 
-
-#if 0
-// Not currently used
-LLColor3 LLVOSky::calcGroundFog(LLColor3& transp, const LLVector3 &view_dir, F32 obj_dist) const
-{
-	LLColor3 col;
-	calcGroundFog(col, transp, view_dir, obj_dist);
-	col *= mBrightnessScaleGuess;
-	return col;
-}
-#endif
-
-void LLVOSky::setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity)
+void LLVOSky::initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity)
 {
 	LLVector3 sun_direction = (sun_dir.magVec() == 0) ? LLVector3::x_axis : sun_dir;
 	sun_direction.normVec();
-	F32 dp = mSun.getDirection() * sun_direction;
 	mSun.setDirection(sun_direction);
+	mSun.renewDirection();
 	mSun.setAngularVelocity(sun_ang_velocity);
-	mMoon.setDirection(-sun_direction);
-	if (dp < 0.995f) { //the sun jumped a great deal, update immediately
-		updateHaze();
-		mWeatherChange = FALSE;
-		mForceUpdate = TRUE;
-	}
-	else if (mWeatherChange && (mSun.getDirection().mV[VZ] > -0.5) )
-	{
-		updateHaze();
-		init();
-		mWeatherChange = FALSE;
-	}
-	else if (mSun.getDirection().mV[VZ] < -0.5)
-	{
-		mWeatherChange = TRUE;
-	}
-}
-
-#define INV_WAVELENGTH_R_POW4 (1.f/0.2401f)			// = 1/0.7^4
-#define INV_WAVELENGTH_G_POW4 (1.f/0.0789f)			// = 1/0.53^4
-#define INV_WAVELENGTH_B_POW4 (1.f/0.03748f)		// = 1/0.44^4
-
-// Dummy class for globals used below. Replace when KILLERSKY is merged in.
-class LLKillerSky
-{
-public:
-	static F32 sRaleighGroundDensity;
-	static F32 sMieFactor;
-	static F32 sNearFalloffFactor;
-	static F32 sSkyContrib;
-
-	static void getRaleighCoefficients(float eye_sun_dp, float density, float *coefficients)
-	{
-		float dp = eye_sun_dp;
-		float angle_dep = density*(1 + dp*dp);
-		coefficients[0] = angle_dep * INV_WAVELENGTH_R_POW4;
-		coefficients[1] = angle_dep * INV_WAVELENGTH_G_POW4;
-		coefficients[2] = angle_dep * INV_WAVELENGTH_B_POW4;
-	}
-
-	static void getMieCoefficients(float eye_sun_dp, float density, float *coefficient)
-	{
-		// TOTALLY ARBITRARY FUNCTION. Seems to work though
-		// If anyone can replace this with some *actual* mie function, that'd be great
-		float dp = eye_sun_dp;
-		float dp_highpower = dp*dp;
-		float angle_dep = density * (llclamp(dp_highpower*dp, 0.f, 1.f) + 0.4f);
-		*coefficient = angle_dep;
-	}
-};
-
-F32 LLKillerSky::sRaleighGroundDensity = 0.013f;
-F32 LLKillerSky::sMieFactor = 50;
-F32 LLKillerSky::sNearFalloffFactor = 1.5f;
-F32 LLKillerSky::sSkyContrib = 0.06f;
-
-void LLVOSky::generateScatterMap()
-{
-	float raleigh[3], mie;
-
-	mScatterMap = new LLImageGL(FALSE);
-	mScatterMapRaw = new LLImageRaw(256, 256, 4);
-	U8 *data = mScatterMapRaw->getData();
+	mMoon.setDirection(-mSun.getDirection());
+	mMoon.renewDirection();
+	mLastLightingDirection = mSun.getDirection();
 
-	F32 light_brightness = gSky.getSunDirection().mV[VZ]+0.1f;
-	LLColor4 light_color;
-	LLColor4 sky_color;
-	if (light_brightness > 0)
-	{
-		F32 interp = sqrtf(light_brightness);
-		light_brightness = sqrt(sqrtf(interp));
-		light_color = lerp(gSky.getSunDiffuseColor(), LLColor4(1,1,1,1), interp) * light_brightness;
-		sky_color = lerp(LLColor4(0,0,0,0), LLColor4(0.4f, 0.6f, 1.f, 1.f), light_brightness)*LLKillerSky::sSkyContrib;
-	}
-	else
-	{
-		light_brightness = /*0.3f*/sqrt(-light_brightness);
-		light_color = gSky.getMoonDiffuseColor() * light_brightness;
-		sky_color = LLColor4(0,0,0,1);
-	}
+	calcAtmospherics();
 
-	// x = distance [0..1024m]
-	// y = dot product [-1,1]
-	for (int y=0;y<256;y++)
+	if ( !mInitialized )
 	{
-		// Accumulate outward
-		float accum_r = 0, accum_g = 0, accum_b = 0;
-
-		float dp = (((float)y)/255.f)*1.95f - 0.975f;
-		U8 *scanline = &data[y*256*4];
-		for (int x=0;x<256;x++)
-		{
-			float dist = ((float)x+1)*4; // x -> 2048
-
-			float raleigh_density = LLKillerSky::sRaleighGroundDensity * 0.05f; // Arbitrary? Perhaps...
-			float mie_density = raleigh_density*LLKillerSky::sMieFactor;
-
-			float extinction_factor = dist/LLKillerSky::sNearFalloffFactor;
-
-			LLKillerSky::getRaleighCoefficients(dp, raleigh_density, raleigh);
-			LLKillerSky::getMieCoefficients(dp, mie_density, &mie);
-
-			float falloff_r = pow(llclamp(0.985f-raleigh[0],0.f,1.f), extinction_factor);
-			float falloff_g = pow(llclamp(0.985f-raleigh[1],0.f,1.f), extinction_factor);
-			float falloff_b = pow(llclamp(0.985f-raleigh[2],0.f,1.f), extinction_factor);
-
-			float light_r = light_color.mV[0] * (raleigh[0]+mie+sky_color.mV[0]) * falloff_r;
-			float light_g = light_color.mV[1] * (raleigh[1]+mie+sky_color.mV[1]) * falloff_g;
-			float light_b = light_color.mV[2] * (raleigh[2]+mie+sky_color.mV[2]) * falloff_b;
-
-			accum_r += light_r;
-			accum_g += light_g;
-			accum_b += light_b;
-
-			scanline[x*4] = (U8)llclamp(accum_r*255.f, 0.f, 255.f);
-			scanline[x*4+1] = (U8)llclamp(accum_g*255.f, 0.f, 255.f);
-			scanline[x*4+2] = (U8)llclamp(accum_b*255.f, 0.f, 255.f);
-			float alpha = ((falloff_r+falloff_g+falloff_b)*0.33f);
-			scanline[x*4+3] = (U8)llclamp(alpha*255.f, 0.f, 255.f); // Avg falloff
-
-			// Output color Co, Input color Ci, Map channels Mrgb, Ma:
-			// Co = (Ci * Ma) + Mrgb
-		}
-	}
-
-	mScatterMap->createGLTexture(0, mScatterMapRaw);
-	mScatterMap->bind(0);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		init();
+		LLSkyTex::stepCurrent();
+	}		
 }
 
-#if 0
-// Not currently used
-void LLVOSky::calcGroundFog(LLColor3& res, LLColor3& transp, const LLVector3 view_dir, F32 obj_dist) const
+void LLVOSky::setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity)
 {
-	const LLVector3& tosun = getToSunLast();//use_old_value ? sunDir() : toSunLast();
-	res.setToBlack();
-	transp.setToWhite();
-	const F32 dist = obj_dist * mWorldScale;
-
-	//LLVector3 view_dir = gCamera->getAtAxis();
-
-	const F32 cos_dir = view_dir * tosun;
-	LLVector3 dir = view_dir;
-	LLVector3 virtual_P = mCameraPosAgent + dist * dir;
+	LLVector3 sun_direction = (sun_dir.magVec() == 0) ? LLVector3::x_axis : sun_dir;
+	sun_direction.normVec();
 
-	if (dir.mV[VZ] < 0)
-	{
-		dir = -dir;
-	}
+	// Push the sun "South" as it approaches directly overhead so that we can always see bump mapping
+	// on the upward facing faces of cubes.
+	LLVector3 newDir = sun_direction;
 
-	const F32 z_dir = dir.mV[2];
+	// Same as dot product with the up direction + clamp.
+	F32 sunDot = llmax(0.f, newDir.mV[2]);
+	sunDot *= sunDot;	
 
-	const F32 h = mCameraPosAgent.mV[2];
+	// Create normalized vector that has the sunDir pushed south about an hour and change.
+	LLVector3 adjustedDir = (newDir + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f;
 
-	transp = color_div(mTransp.calcTransp(dir * calcUpVec(virtual_P), 0),
-		mTransp.calcTransp(z_dir, h));
+	// Blend between normal sun dir and adjusted sun dir based on how close we are
+	// to having the sun overhead.
+	mBumpSunDir = adjustedDir * sunDot + newDir * (1.0f - sunDot);
+	mBumpSunDir.normVec();
 
-	if (calcHitsEarth(mCameraPosAgent, tosun) > 0)
-	{
-		const F32 avg = llmin(1.f, 1.2f * color_avg(transp));
-		transp = LLColor3(avg, avg, avg);
-		return;
+	F32 dp = mLastLightingDirection * sun_direction;
+	mSun.setDirection(sun_direction);
+	mSun.setAngularVelocity(sun_ang_velocity);
+	mMoon.setDirection(-sun_direction);
+	calcAtmospherics();
+	if (dp < 0.995f) { //the sun jumped a great deal, update immediately
+		mForceUpdate = TRUE;
 	}
-
-	LLColor3 haze_sca_opt_depth = mHaze.getSigSca();
-	LLColor3 sun_transp;
-	mTransp.calcTransp(tosun.mV[2], -0.1f, sun_transp);
-
-	res = calcAirPhaseFunc(cos_dir) * LLHaze::getAirScaSeaLevel();
-	res += mHaze.calcPhase(cos_dir) * mHaze.getSigSca();
-	res = mSun.getIntensity() * dist * sun_transp * res;
 }
-
-#endif
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index f3bceb06532..260aeeada7e 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -48,6 +48,7 @@
 //
 
 const F32 HORIZON_DIST			= 1024.0f;
+const F32 SKY_BOX_MULT			= 16.0f;
 const F32 HEAVENLY_BODY_DIST		= HORIZON_DIST - 10.f;
 const F32 HEAVENLY_BODY_FACTOR	= 0.1f;
 const F32 HEAVENLY_BODY_SCALE	= HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR;
@@ -85,7 +86,6 @@ LL_FORCE_INLINE LLColor3 color_div(const LLColor3 &col1, const LLColor3 &col2)
 }
 
 LLColor3 color_norm(const LLColor3 &col);
-LLVector3 move_vec (const LLVector3& v, F32 cos_max_angle);
 BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4],
 						  const LLVector3 v_corner[4], const F32 cos_max_angle);
 F32 clip_side_to_horizon(const LLVector3& v0, const LLVector3& v1, const F32 cos_max_angle);
@@ -111,18 +111,6 @@ inline F32 color_min(const LLColor3 &col)
 	return llmin(col.mV[0], col.mV[1], col.mV[2]);
 }
 
-inline LLColor3 color_norm_abs(const LLColor3 &col)
-{
-	const F32 m = color_max(col);
-	if (m > 1e-6)
-	{
-		return 1.f/m * col;
-	}
-	else return col;
-}
-
-
-
 class LLFace;
 class LLHaze;
 
@@ -135,7 +123,7 @@ class LLSkyTex
 	static S32		sComponents;
 	LLPointer<LLImageGL> mImageGL[2];
 	LLPointer<LLImageRaw> mImageRaw[2];
-	LLColor3		*mSkyData;
+	LLColor4		*mSkyData;
 	LLVector3		*mSkyDirs;			// Cache of sky direction vectors
 	static S32		sCurrent;
 	static F32		sInterpVal;
@@ -163,7 +151,8 @@ class LLSkyTex
 	static S32 getWhich(const BOOL curr)		{ return curr ? sCurrent : getNext(); }
 
 	void initEmpty(const S32 tex);
-	void create(F32 brightness_scale, const LLColor3& multiscatt);
+	
+	void create(F32 brightness);
 
 	void setDir(const LLVector3 &dir, const S32 i, const S32 j)
 	{
@@ -177,7 +166,7 @@ class LLSkyTex
 		return mSkyDirs[offset];
 	}
 
-	void setPixel(const LLColor3 &col, const S32 i, const S32 j)
+	void setPixel(const LLColor4 &col, const S32 i, const S32 j)
 	{
 		S32 offset = i * sResolution + j;
 		mSkyData[offset] = col;
@@ -203,7 +192,7 @@ class LLSkyTex
 	void createGLImage(BOOL curr=TRUE);
 };
 
-
+/// TODO Move into the stars draw pool (and rename them appropriately).
 class LLHeavenBody
 {
 protected:
@@ -261,27 +250,6 @@ class LLHeavenBody
 		return sInterpVal * mColor + (1 - sInterpVal) * mColorCached;
 	}
 
-//	LLColor3 getDiffuseColor() const
-//	{
-//		LLColor3 dif = mColorCached;
-//		dif.clamp();
-//		return 2 * dif;
-//	}
-	
-//	LLColor4 getAmbientColor(const LLColor3& scatt, F32 scale) const
-//	{
-//		const F32 min_val = 0.05f;
-//		LLColor4 col = LLColor4(scale * (0.8f * color_norm_abs(getDiffuseColor()) + 0.2f * scatt));
-//		//F32 left = max(0, 1 - col.mV[0]);
-//		if (col.mV[0] >= 0.9)
-//		{
-//			col.mV[1] = llmax(col.mV[1], 2.f * min_val);
-//			col.mV[2] = llmax(col.mV[2], min_val);
-//		}
-//		col.setAlpha(1.f);
-//		return col;
-//	}
-
 	const F32& getHorizonVisibility() const				{ return mHorizonVisibility; }
 	void setHorizonVisibility(const F32 c = 1)			{ mHorizonVisibility = c; }
 	const F32& getVisibility() const					{ return mVisibility; }
@@ -440,82 +408,55 @@ class LLHaze
 	F32			mAbsCoef;
 };
 
-class LLTranspMap
-{
-public:
-	LLTranspMap() : mElevation(0), mMaxAngle(0), mStep(5), mHaze(NULL), mT(NULL) {}
-	~LLTranspMap()
-	{
-		delete[] mT;
-		mT = NULL;
-	}
-
-	void init(const F32 elev, const F32 step, const F32 h, const LLHaze* const haze);
-
-	F32 calcHeight(const LLVector3& pos) const
-	{
-		return pos.magVec() - EARTH_RADIUS ;
-	}
-
-	BOOL hasHaze() const
-	{
-		return mHaze != NULL;
-	}
 
-	LLColor3 calcSigExt(const F32 h) const
-	{
-		return LLHaze::calcAirSca(h) + (hasHaze() ? mHaze->calcSigExt(h) : LLColor3(0, 0, 0));
-	}
+class LLCubeMap;
 
-	inline void calcAirTransp(const F32 cos_angle, LLColor3 &result) const;
-	LLColor3 calcAirTranspDir(const F32 elevation, const LLVector3 &dir) const;
-	LLColor3 getHorizonAirTransp () const				{ return mT[mMapSize-1]; }
-	F32 hitsAtmEdge(const LLVector3& orig, const LLVector3& dir) const;
+// turn on floating point precision
+// in vs2003 for this class.  Otherwise
+// black dots go everywhere from 7:10 - 8:50
+#if LL_MSVC && __MSVC_VER__ < 8
+#pragma optimize("p", on)		
+#endif
 
-protected:
-	F32				mAtmHeight;
-	F32				mElevation;
-	F32				mMaxAngle;
-	F32				mCosMaxAngle;
-	F32				mStep;
-	F32				mStepInv;
-	S32				mMapSize;
-	const LLHaze	*mHaze;
-	LLColor3		*mT;	// transparency values in all directions
-							//starting with mAngleBelowHorz at mElevation
-};
 
-class LLTranspMapSet
+class LLVOSky : public LLStaticViewerObject
 {
-protected:
-	F32					*mHeights;
-	LLTranspMap			*mTransp;
-	S32					mSize;
-	F32					mMediaHeight;
-	const LLHaze		*mHaze;
-	S32 lerp(F32& dt, S32& indx, const F32 h) const;
 public:
-	LLTranspMapSet() : mHeights(NULL), mTransp(NULL), mHaze(NULL) {}
-	~LLTranspMapSet();
-
-	void init (S32 size, F32 first_step, F32 media_height, const LLHaze* const haze);
-	S32 getSize() const							{ return mSize; }
-	F32 getMediaHeight() const					{ return mMediaHeight; }
-	const LLTranspMap& getLastTransp() const	{ return mTransp[mSize-1]; }
-	F32 getLastHeight() const					{ return mHeights[mSize-1]; }
-	const LLTranspMap& getMap(const S32 n) const	{ return mTransp[n]; }
-	F32 getHeight(const S32 n) const				{ return mHeights[n]; }
-	BOOL isReady() const						{ return mTransp != NULL; }
-
-	inline LLColor3 calcTransp(const F32 cos_angle, const F32 h) const;
-	inline void calcTransp(const F32 cos_angle, const F32 h, LLColor3 &result) const;
-};
+	/// WL PARAMS
+	F32 dome_radius;
+	F32 dome_offset_ratio;
+	LLColor3 sunlight_color;
+	LLColor3 ambient;
+	F32 gamma;
+	LLVector4 lightnorm;
+	LLVector4 unclamped_lightnorm;
+	LLColor3 blue_density;
+	LLColor3 blue_horizon;
+	F32 haze_density;
+	LLColor3 haze_horizon;
+	F32 density_multiplier;
+	F32 max_y;
+	LLColor3 glow;
+	F32 cloud_shadow;
+	LLColor3 cloud_color;
+	F32 cloud_scale;
+	LLColor3 cloud_pos_density1;
+	LLColor3 cloud_pos_density2;
+	
+public:
+	void initAtmospherics(void);
+	void calcAtmospherics(void);
+	LLColor3 createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient);
+	LLColor3 createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient);
 
-class LLCubeMap;
+	void calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
+							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
+							LLVector2 vary_HorizontalProjection[2]);
 
+	LLColor3 calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor,	LLColor3 & vary_CloudColorSun, 
+							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
+							LLVector2 vary_HorizontalProjection[2]);
 
-class LLVOSky : public LLStaticViewerObject
-{
 public:
 	enum
 	{
@@ -529,6 +470,7 @@ class LLVOSky : public LLStaticViewerObject
 		FACE_MOON, // was 7
 		FACE_BLOOM, // was 8
 		FACE_REFLECTION, // was 10
+		FACE_DUMMY, //for an ATI bug --bao
 		FACE_COUNT
 	};
 	
@@ -539,9 +481,7 @@ class LLVOSky : public LLStaticViewerObject
 	void init();
 	void initCubeMap();
 	void initEmpty();
-	BOOL isReady() const									{ return mTransp.isReady(); }
-	const LLTranspMapSet& getTransp() const				{ return mTransp; }
-
+	
 	void cleanupGL();
 	void restoreGL();
 
@@ -557,26 +497,12 @@ class LLVOSky : public LLStaticViewerObject
 	void initSkyTextureDirs(const S32 side, const S32 tile);
 	void createSkyTexture(const S32 side, const S32 tile);
 
-	void updateBrightestDir();
-	void calcBrightnessScaleAndColors();
-
-	LLColor3 calcSkyColorInDir(const LLVector3& dir);
-	void calcSkyColorInDir(LLColor3& res, LLColor3& transp, 
-							const LLVector3& dir) const;
-	LLColor4 calcInScatter(LLColor4& transp, const LLVector3 &point, F32 exag) const;
-	void calcInScatter( LLColor3& res, LLColor3& transp,
-					const LLVector3& P, F32 exag) const;
-
-	// Not currently used.
-	//LLColor3 calcGroundFog(LLColor3& transp, const LLVector3 &view_dir, F32 obj_dist) const;
-	//void calcGroundFog(LLColor3& res, LLColor3& transp, const LLVector3 view_dir, F32 dist) const;
-
+	LLColor4 calcSkyColorInDir(const LLVector3& dir, bool isShiny = false);
+	
 	LLColor3 calcRadianceAtPoint(const LLVector3& pos) const
 	{
-		const F32 cos_angle = calcUpVec(pos) * getToSunLast();
-		LLColor3 tr;
-		mTransp.calcTransp(cos_angle, calcHeight(pos), tr);
-		return mBrightnessScaleGuess * mSun.getIntensity() * tr;
+		F32 radiance = mBrightnessScaleGuess * mSun.getIntensity();
+		return LLColor3(radiance, radiance, radiance);
 	}
 
 	const LLHeavenBody& getSun() const						{ return mSun; }
@@ -597,58 +523,16 @@ class LLVOSky : public LLStaticViewerObject
 	LLColor4 getFogColor() const							{ return mFogColor; }
 	LLColor4 getGLFogColor() const							{ return mGLFogCol; }
 	
-	LLVector3 calcUpVec(const LLVector3 &pos) const
-	{
-		LLVector3 v = pos - mEarthCenter;
-		v.normVec();
-		return v;
-	}
-
-	F32 calcHeight(const LLVector3& pos) const
-	{
-		return dist_vec(pos, mEarthCenter) - EARTH_RADIUS;
-	}
-
-	// Phase function for atmospheric scattering.
-	// co = cos ( theta )
-	F32 calcAirPhaseFunc(const F32 co) const
-	{
-		return (0.75f * (1.f + co*co));
-	}
-
-
 	BOOL isSameFace(S32 idx, const LLFace* face) const { return mFace[idx] == face; }
 
-	void initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity)
-	{
-		LLVector3 sun_direction = (sun_dir.magVec() == 0) ? LLVector3::x_axis : sun_dir;
-		sun_direction.normVec();
-		mSun.setDirection(sun_direction);
-		mSun.renewDirection();
-		mSun.setAngularVelocity(sun_ang_velocity);
-		mMoon.setDirection(-mSun.getDirection());
-		mMoon.renewDirection();
-		mLastLightingDirection = mSun.getDirection();
-
-		if ( !isReady() )
-		{
-			init();
-			LLSkyTex::stepCurrent();
-		}
-	}
+	void initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity);
 
 	void setSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity);
 
-	void updateHaze();
-
 	BOOL updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 side, const BOOL is_sun,
 									LLHeavenBody& hb, const F32 sin_max_angle,
 									const LLVector3 &up, const LLVector3 &right);
 
-	LLVector3 toHorizon(const LLVector3& dir, F32 delta = 0) const
-	{
-		return move_vec(dir, cosHorizon(delta));
-	}
 	F32 cosHorizon(const F32 delta = 0) const
 	{
 		const F32 sin_angle = EARTH_RADIUS/(EARTH_RADIUS + mCameraPosAgent.mV[2]);
@@ -681,18 +565,14 @@ class LLVOSky : public LLStaticViewerObject
 	BOOL isReflFace(const LLFace* face) const			{ return face == mFace[FACE_REFLECTION]; }
 	LLFace* getReflFace() const							{ return mFace[FACE_REFLECTION]; }
 
-	F32 calcHitsEarth(const LLVector3& orig, const LLVector3& dir) const;
-	F32 calcHitsAtmEdge(const LLVector3& orig, const LLVector3& dir) const;
 	LLViewerImage*	getSunTex() const					{ return mSunTexturep; }
 	LLViewerImage*	getMoonTex() const					{ return mMoonTexturep; }
 	LLViewerImage*	getBloomTex() const					{ return mBloomTexturep; }
-
-	void			generateScatterMap();
-	LLImageGL*		getScatterMap()						{ return mScatterMap; }
+	void forceSkyUpdate(void)							{ mForceUpdate = TRUE; }
 
 public:
-	static F32 sNighttimeBrightness; // [0,2] default = 1.0
-	LLFace				*mFace[FACE_COUNT];
+	LLFace	*mFace[FACE_COUNT];
+	LLVector3	mBumpSunDir;
 
 protected:
 	~LLVOSky();
@@ -705,6 +585,7 @@ class LLVOSky : public LLStaticViewerObject
 	static S32			sTileResX;
 	static S32			sTileResY;
 	LLSkyTex			mSkyTex[6];
+	LLSkyTex			mShinyTex[6];
 	LLHeavenBody		mSun;
 	LLHeavenBody		mMoon;
 	LLVector3			mSunDefaultPosition;
@@ -718,7 +599,6 @@ class LLVOSky : public LLStaticViewerObject
 	LLColor3			mBrightestPointNew;
 	F32					mBrightnessScaleGuess;
 	LLColor3			mBrightestPointGuess;
-	LLTranspMapSet		mTransp;
 	LLHaze				mHaze;
 	F32					mHazeConcentration;
 	BOOL				mWeatherChange;
@@ -751,10 +631,23 @@ class LLVOSky : public LLStaticViewerObject
 
 	LLFrameTimer		mUpdateTimer;
 
-	LLPointer<LLImageGL>	mScatterMap;
-	LLPointer<LLImageRaw>	mScatterMapRaw;
+public:
+	//by bao
+	//fake vertex buffer updating
+	//to guaranttee at least updating one VBO buffer every frame
+	//to walk around the bug caused by ATI card --> DEV-3855
+	//
+	void createDummyVertexBuffer() ;
+	void updateDummyVertexBuffer() ;
+
+	BOOL mHeavenlyBodyUpdated ;
 };
 
+// turn it off
+#if LL_MSVC && __MSVC_VER__ < 8
+#pragma optimize("p", off)		
+#endif
+
 // Utility functions
 F32 azimuth(const LLVector3 &v);
 F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply = FALSE);
@@ -776,161 +669,5 @@ inline void LLHaze::calcAirSca(const F32 h, LLColor3 &result)
 	result *= calcFalloff(h);
 }
 
-// Given cos of the angle between direction of interest and zenith,
-// compute transparency by interpolation of known values.
-inline void LLTranspMap::calcAirTransp(const F32 cos_angle, LLColor3 &result) const
-{
-	if (cos_angle > 1.f)
-	{
-		result = mT[0];
-		return;
-	}
-	if (cos_angle < mCosMaxAngle - 0.1f)
-	{
-		result.setVec(0.f, 0.f, 0.f);
-		return;
-	}
-	if (cos_angle < mCosMaxAngle)
-	{
-		result = mT[mMapSize-1];
-		return;
-	}
-
-
-	const F32 relative = (1 - cos_angle)*mStepInv;
-	const S32 index = llfloor(relative);
-	const F32 dt = relative - index;
-
-	if (index >= (mMapSize-1))
-	{
-		result = mT[0];
-		return;
-	}
-//	result = mT[index];
-//	LLColor3 res2(mT[index+1]);
-//	result *= 1 - dt;
-//	res2 *= dt;
-//	result += res2;
-
-	const LLColor3& color1 = mT[index];
-	const LLColor3& color2 = mT[index + 1];
-
-	const F32 x1 = color1.mV[VX];
-	const F32 x2 = color2.mV[VX];
-	result.mV[VX] = x1 - dt * (x1 - x2);
-
-	const F32 y1 = color1.mV[VY];
-	const F32 y2 = color2.mV[VY];
-	result.mV[VY] = y1 - dt * (y1 - y2);
-
-	const F32 z1 = color1.mV[VZ];
-	const F32 z2 = color2.mV[VZ];
-	result.mV[VZ] = z1 - dt * (z1 - z2);
-}
-
-
-
-// Returns the translucency of the atmosphere along the ray in the sky.
-// dir is assumed to be normalized
-inline void LLTranspMapSet::calcTransp(const F32 cos_angle, const F32 h, LLColor3 &result) const
-{
-	S32 indx = 0;
-	F32 dt = 0.f;
-	const S32 status = lerp(dt, indx, h);
-
-	if (status < 0)
-	{
-		mTransp[0].calcAirTransp(cos_angle, result);
-		return;
-	}
-	if (status > 0)
-	{
-		mTransp[NO_STEPS].calcAirTransp(cos_angle, result);
-		return;
-	}
-
-	mTransp[indx].calcAirTransp(cos_angle, result);
-	result *= 1 - dt;
-
-	LLColor3 transp_above;
-
-	mTransp[indx + 1].calcAirTransp(cos_angle, transp_above);
-	transp_above *= dt;
-	result += transp_above;
-}
-
-
-inline LLColor3 LLTranspMapSet::calcTransp(const F32 cos_angle, const F32 h) const
-{
-	LLColor3 result;
-	S32 indx = 0;
-	F32 dt = 0;
-	const S32 status = lerp(dt, indx, h);
-
-	if (status < 0)
-	{
-		mTransp[0].calcAirTransp(cos_angle, result);
-		return result;
-	}
-	if (status > 0)
-	{
-		mTransp[NO_STEPS].calcAirTransp(cos_angle, result);
-		return result;
-	}
-
-	mTransp[indx].calcAirTransp(cos_angle, result);
-	result *= 1 - dt;
-
-	LLColor3 transp_above;
-
-	mTransp[indx + 1].calcAirTransp(cos_angle, transp_above);
-	transp_above *= dt;
-	result += transp_above;
-	return result;
-}
-
-
-// Returns -1 if height < 0; +1 if height > max height; 0 if within range
-inline S32 LLTranspMapSet::lerp(F32& dt, S32& indx, const F32 h) const
-{
-	static S32 last_indx = 0;
-
-	if (h < 0)
-	{
-		return -1;
-	}
-	if (h > getLastHeight())
-	{
-		return 1;
-	}
-
-	if (h < mHeights[last_indx])
-	{
-		indx = last_indx-1;
-		while (mHeights[indx] > h)
-		{
-			indx--;
-		}
-		last_indx = indx;
-	}
-	else if (h > mHeights[last_indx+1])
-	{
-		indx = last_indx+1;
-		while (mHeights[indx+1] < h)
-		{
-			indx++;
-		}
-		last_indx = indx;
-	}
-	else
-	{
-		indx = last_indx;
-	}
-
-	const F32 h_below = mHeights[indx];
-	const F32 h_above = mHeights[indx+1];
-	dt = (h - h_below) / (h_above - h_below);
-	return 0;
-}
 
 #endif
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 05b374e6071..d2fe5d31e69 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -46,6 +46,9 @@
 #include "llvlcomposition.h"
 #include "llvovolume.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
+
+F32 LLVOSurfacePatch::sLODFactor = 1.f;
 
 //============================================================================
 
@@ -187,6 +190,8 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TERRAIN);
 
+	dirtySpatialGroup();
+	
 	S32 min_comp, max_comp, range;
 	min_comp = lltrunc(mPatchp->getMinComposition());
 	max_comp = lltrunc(ceil(mPatchp->getMaxComposition()));
@@ -271,8 +276,6 @@ void LLVOSurfacePatch::updateFaceSize(S32 idx)
 
 BOOL LLVOSurfacePatch::updateLOD()
 {
-	//mDrawable->updateLightSet();
-	mDrawable->setState(LLDrawable::LIGHTING_BUILT);
 	return TRUE;
 }
 
@@ -281,7 +284,7 @@ void LLVOSurfacePatch::getGeometry(LLStrider<LLVector3> &verticesp,
 								LLStrider<LLColor4U> &colorsp,
 								LLStrider<LLVector2> &texCoords0p,
 								LLStrider<LLVector2> &texCoords1p,
-								LLStrider<U32> &indicesp)
+								LLStrider<U16> &indicesp)
 {
 	LLFace* facep = mDrawable->getFace(0);
 
@@ -319,7 +322,7 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
 										LLStrider<LLColor4U> &colorsp,
 										LLStrider<LLVector2> &texCoords0p,
 										LLStrider<LLVector2> &texCoords1p,
-										LLStrider<U32> &indicesp,
+										LLStrider<U16> &indicesp,
 										U32 &index_offset)
 {
 	S32 i, j, x, y;
@@ -355,10 +358,9 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
 				x = i * render_stride;
 				y = j * render_stride;
 				mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-				calcColor(verticesp.get(), normalsp.get(), colorsp.get());
+				*colorsp++ = LLColor4U::white;
 				verticesp++;
 				normalsp++;
-				colorsp++;
 				texCoords0p++;
 				texCoords1p++;
 			}
@@ -424,7 +426,7 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 										LLStrider<LLColor4U> &colorsp,
 										LLStrider<LLVector2> &texCoords0p,
 										LLStrider<LLVector2> &texCoords1p,
-										LLStrider<U32> &indicesp,
+										LLStrider<U16> &indicesp,
 										U32 &index_offset)
 {
 	S32 vertex_count = 0;
@@ -459,10 +461,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			y = 16 - render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
+			*colorsp++ = LLColor4U::white;
 			verticesp++;
 			normalsp++;
-			colorsp++;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -474,10 +475,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			x = i * render_stride;
 			y = 16;
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -514,10 +514,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			y = 16 - render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -530,10 +529,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			y = 16;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -577,10 +575,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			y = 16 - render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
+			*colorsp++ = LLColor4U::white;
 			verticesp++;
 			normalsp++;
-			colorsp++;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -593,10 +590,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
 			y = 16;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 			vertex_count++;
@@ -637,7 +633,7 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 										  LLStrider<LLColor4U> &colorsp,
 										  LLStrider<LLVector2> &texCoords0p,
 										  LLStrider<LLVector2> &texCoords1p,
-										  LLStrider<U32> &indicesp,
+										  LLStrider<U16> &indicesp,
 										  U32 &index_offset)
 {
 	S32 i, x, y;
@@ -666,10 +662,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			y = i * render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -680,10 +675,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			x = 16;
 			y = i * render_stride;
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -719,10 +713,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			y = i * render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -733,10 +726,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			y = i * render_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -778,10 +770,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			y = i * east_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -792,10 +783,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 			y = i * east_stride;
 
 			mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
-			calcColor(verticesp.get(), normalsp.get(), colorsp.get());
 			verticesp++;
 			normalsp++;
-			colorsp++;
+			*colorsp++ = LLColor4U::white;
 			texCoords0p++;
 			texCoords1p++;
 		}
@@ -829,35 +819,6 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
 	index_offset += num_vertices;
 }
 
-void LLVOSurfacePatch::calcColor(const LLVector3* vertex, const LLVector3* normal, LLColor4U* colorp)
-{
-	LLColor4 color(0,0,0,0);
-	if (gPipeline.getLightingDetail() >= 2)
-	{
-		for (LLDrawable::drawable_set_t::iterator iter = mDrawable->mLightSet.begin();
-			 iter != mDrawable->mLightSet.end(); ++iter)
-		{
-			LLDrawable* light_drawable = *iter;
-			LLVOVolume* light = light_drawable->getVOVolume();
-			if (!light)
-			{
-				continue;
-			}
-			LLColor4 light_color;
-			light->calcLightAtPoint(*vertex, *normal, light_color);
-			color += light_color;
-		}
-
-		color.mV[3] = 1.0f;
-	}
-	colorp->setVecScaleClamp(color);
-}
-
-BOOL LLVOSurfacePatch::updateShadows(BOOL use_shadow_factor)
-{
-	return FALSE; //terrain updates its shadows during standard relight
-}
-
 void LLVOSurfacePatch::setPatch(LLSurfacePatch *patchp)
 {
 	mPatchp = patchp;
@@ -966,16 +927,18 @@ void LLVOSurfacePatch::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax
 
 U32 LLVOSurfacePatch::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_TERRAIN; 
+	return LLViewerRegion::PARTITION_TERRAIN; 
 }
 
 LLTerrainPartition::LLTerrainPartition()
 : LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK)
 {
+	mOcclusionEnabled = FALSE;
 	mRenderByGroup = FALSE;
+	mInfiniteFarClip = FALSE;
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	mDrawableType = LLPipeline::RENDER_TYPE_TERRAIN;
-	mPartitionType = LLPipeline::PARTITION_TERRAIN;
+	mPartitionType = LLViewerRegion::PARTITION_TERRAIN;
 }
 
 LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
@@ -985,6 +948,8 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
 
 void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 {
+	LLFastTimer ftm(LLFastTimer::FTM_REBUILD_TERRAIN_VB);
+
 	LLVertexBuffer* buffer = group->mVertexBuffer;
 
 	//get vertex buffer striders
@@ -993,7 +958,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 	LLStrider<LLVector2> texcoords2;
 	LLStrider<LLVector2> texcoords;
 	LLStrider<LLColor4U> colors;
-	LLStrider<U32> indices;
+	LLStrider<U16> indices;
 
 	buffer->getVertexStrider(vertices);
 	buffer->getNormalStrider(normals);
@@ -1020,6 +985,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 		index_offset += facep->getGeomCount();
 	}
 
+	buffer->setBuffer(0);
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index ad2331ffed5..ede01eb1a9a 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -42,6 +42,8 @@ class LLVector2;
 class LLVOSurfacePatch : public LLStaticViewerObject
 {
 public:
+	static F32 sLODFactor;
+
 	enum
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
@@ -69,7 +71,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 								LLStrider<LLColor4U> &colorsp,
 								LLStrider<LLVector2> &texCoords0p,
 								LLStrider<LLVector2> &texCoords1p,
-								LLStrider<U32> &indicesp);
+								LLStrider<U16> &indicesp);
 
 	/*virtual*/ void updateTextures(LLAgent &agent);
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
@@ -99,8 +101,6 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 	S32				mLastStride;
 	S32				mLastLength;
 
-	void calcColor(const LLVector3* vertex, const LLVector3* normal, LLColor4U* colorp);
-	BOOL updateShadows(BOOL use_shadow_factor = FALSE);
 	void getGeomSizesMain(const S32 stride, S32 &num_vertices, S32 &num_indices);
 	void getGeomSizesNorth(const S32 stride, const S32 north_stride,
 								  S32 &num_vertices, S32 &num_indices);
@@ -113,7 +113,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 					   LLStrider<LLColor4U> &colorsp,
 					   LLStrider<LLVector2> &texCoords0p,
 					   LLStrider<LLVector2> &texCoords1p,
-					   LLStrider<U32> &indicesp,
+					   LLStrider<U16> &indicesp,
 					   U32 &index_offset);
 	void updateNorthGeometry(LLFace *facep,
 					   LLStrider<LLVector3> &verticesp,
@@ -121,7 +121,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 					   LLStrider<LLColor4U> &colorsp,
 					   LLStrider<LLVector2> &texCoords0p,
 					   LLStrider<LLVector2> &texCoords1p,
-					   LLStrider<U32> &indicesp,
+					   LLStrider<U16> &indicesp,
 					   U32 &index_offset);
 	void updateEastGeometry(LLFace *facep,
 					   LLStrider<LLVector3> &verticesp,
@@ -129,7 +129,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 					   LLStrider<LLColor4U> &colorsp,
 					   LLStrider<LLVector2> &texCoords0p,
 					   LLStrider<LLVector2> &texCoords1p,
-					   LLStrider<U32> &indicesp,
+					   LLStrider<U16> &indicesp,
 					   U32 &index_offset);
 };
 
diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp
index cd3e4d16cea..4ecf1807778 100644
--- a/indra/newview/llvotextbubble.cpp
+++ b/indra/newview/llvotextbubble.cpp
@@ -45,6 +45,7 @@
 #include "llviewerimagelist.h"
 #include "llvolume.h"
 #include "pipeline.h"
+#include "llviewerregion.h"
 
 LLVOTextBubble::LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 :	LLAlphaObject(id, pcode, regionp)
@@ -236,7 +237,7 @@ void LLVOTextBubble::getGeometry(S32 idx,
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp) 
+								LLStrider<U16>& indicesp) 
 {
 	if (idx == 0 || idx == 2)
 	{
@@ -265,5 +266,5 @@ void LLVOTextBubble::getGeometry(S32 idx,
 
 U32 LLVOTextBubble::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_PARTICLE; 
+	return LLViewerRegion::PARTITION_PARTICLE; 
 }
diff --git a/indra/newview/llvotextbubble.h b/indra/newview/llvotextbubble.h
index 35d4f97651b..790e7208bcc 100644
--- a/indra/newview/llvotextbubble.h
+++ b/indra/newview/llvotextbubble.h
@@ -54,7 +54,7 @@ class LLVOTextBubble : public LLAlphaObject
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
 								LLStrider<LLColor4U>& colorsp, 
-								LLStrider<U32>& indicesp);
+								LLStrider<U16>& indicesp);
 
 	virtual U32 getPartitionType() const;
 
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index b7c762a7c13..2f81ae84ba9 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -44,7 +44,6 @@
 #include "object_flags.h"
 
 #include "llagent.h"
-#include "llcylinder.h"
 #include "lldrawable.h"
 #include "llface.h"
 #include "llviewercamera.h"
@@ -54,11 +53,17 @@
 #include "llworld.h"
 #include "noise.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 #include "llviewerwindow.h"
 
 extern LLPipeline gPipeline;
 
-LLGLuint mLeafDList;
+const S32 MAX_SLICES = 32;
+const F32 LEAF_LEFT = 0.52f;
+const F32 LEAF_RIGHT = 0.98f;
+const F32 LEAF_TOP = 1.0f;
+const F32 LEAF_BOTTOM = 0.52f;
+const F32 LEAF_WIDTH = 1.f;
 
 S32 LLVOTree::sLODVertexOffset[4];
 S32 LLVOTree::sLODVertexCount[4];
@@ -310,7 +315,6 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys,
 	if (mTreeImagep)
 	{
 		mTreeImagep->bindTexture(0);
-		mTreeImagep->setClamp(TRUE, TRUE);
 	}
 	mBranchLength = sSpeciesTable[mSpecies]->mBranchLength;
 	mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength;
@@ -447,16 +451,9 @@ const S32 LEAF_VERTICES = 16;
 BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE);
+	const F32 SRR3 = 0.577350269f; // sqrt(1/3)
+	const F32 SRR2 = 0.707106781f; // sqrt(1/2)
 	U32 i, j;
-	const S32 MAX_SLICES = 32;
-
-	const F32 LEAF_LEFT = 0.52f;
-	const F32 LEAF_RIGHT = 0.98f;
-	const F32 LEAF_TOP = 1.0f;
-	const F32 LEAF_BOTTOM = 0.52f;
-
-	const F32 LEAF_WIDTH = 1.f;
-
 
 	U32 slices = MAX_SLICES;
 
@@ -483,7 +480,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	LLStrider<LLVector3> vertices;
 	LLStrider<LLVector3> normals;
 	LLStrider<LLVector2> tex_coords;
-	LLStrider<U32> indicesp;
+	LLStrider<U16> indicesp;
 
 	face->setSize(max_vertices, max_indices);
 
@@ -499,23 +496,22 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	S32 index_count = 0;
 	
 	// First leaf
-	for (i = 0; i < 4; i++)
-	{
-		*(normals++) =		LLVector3(0.f, 0.f, 1.f);
-	}
-
+	*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
 	vertex_count++;
 
-    *(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+	*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
+	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
 	vertex_count++;
@@ -536,26 +532,22 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	index_count++;
 
 	// Same leaf, inverse winding/normals
-	for (i = 0; i < 4; i++)
-	{
-		*(normals++) =		LLVector3(0.f, 0.f, 1.f);
-	}
-
+	*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
 	vertex_count++;
 
-	//*(tex_coords++) =	LLVector2(1.f, 1.0f);
+	*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
 	vertex_count++;
 
-	//*(tex_coords++) =	LLVector2(0.52f, 1.0f);
+	*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
 	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
 	vertex_count++;
 
-	//*(tex_coords++) =	LLVector2(1.f, 0.52f);
+	*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
 	vertex_count++;
@@ -575,23 +567,23 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	index_count++;
 
 
-	for (i = 0; i < 4; i++)
-	{
-		*(normals++) =		LLVector3(0.f, 0.f, 1.f);
-	}
-
+	// next leaf
+	*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
 	vertex_count++;
 
-    *(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+	*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
+	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
 	vertex_count++;
@@ -610,28 +602,28 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	*(indicesp++) = 9;
 	index_count++;
 
-	for (i = 0; i < 4; i++)
-	{
-		*(normals++) =		LLVector3(0.f, 0.f, 1.f);
-	}
 
+	// other side of same leaf
+	*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
 	vertex_count++;
 
-    *(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+	*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
+	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
 	vertex_count++;
 
+	*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
 	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
 	vertex_count++;
 
-
 	*(indicesp++) = 12;
 	index_count++;
 	*(indicesp++) = 14;
@@ -786,13 +778,14 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 		slices /= 2; 
 	}
 
+	face->mVertexBuffer->setBuffer(0);
 	llassert(vertex_count == max_vertices);
 	llassert(index_count == max_indices);
 
 	return TRUE;
 }
 
-U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
+U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
 {
 	U32 ret = 0;
 	//
@@ -810,7 +803,7 @@ U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U
 	
 	constant_twist = 360.f/branches;
 
-	if (stop_level >= 0)
+	if (!LLPipeline::sReflectionRender && stop_level >= 0)
 	{
 		//
 		//  Draw the tree using recursion
@@ -820,39 +813,46 @@ U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U
 			{
 				llassert(sLODIndexCount[trunk_LOD] > 0);
 				width = scale * length * aspect;
-				glPushMatrix();
-				glScalef(width,width,scale * length);
- 				glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, indicesp + sLODIndexOffset[trunk_LOD]);
-				/*glDrawRangeElements(GL_TRIANGLES,
-									sLODVertexOffset[trunk_LOD],
-									sLODVertexOffset[trunk_LOD] + sLODVertexCount[trunk_LOD]-1,
-									sLODIndexCount[trunk_LOD],
-									GL_UNSIGNED_INT,
-									indicesp + sLODIndexOffset[trunk_LOD]);*/
+				LLMatrix4 scale_mat;
+				scale_mat.mMatrix[0][0] = width;
+				scale_mat.mMatrix[1][1] = width;
+				scale_mat.mMatrix[2][2] = scale*length;
+				scale_mat *= matrix;
+
+				glLoadMatrixf((F32*) scale_mat.mMatrix);
+ 				glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]);
+				
 				stop_glerror();
 				ret += sLODIndexCount[trunk_LOD];
-				glPopMatrix();
 			}
 			
 			// Recurse to create more branches
 			for (S32 i=0; i < (S32)branches; i++) 
 			{
-				glPushMatrix();
-				glTranslatef(0.f, 0.f, scale * length);
-				glRotatef((constant_twist + ((i%2==0)?twist:-twist))*i, 0.f, 0.f, 1.f);
-				glRotatef(droop, 0.f, 1.f, 0.f);
-				glRotatef(20.f, 0.f, 0.f, 1.f);				// rotate 20deg about axis of new branch to add some random variation
-				ret += drawBranchPipeline(indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
-				glPopMatrix();
+				LLMatrix4 trans_mat;
+				trans_mat.setTranslation(0,0,scale*length);
+				trans_mat *= matrix;
+
+				LLQuaternion rot = 
+					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
+					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
+					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
+				
+				LLMatrix4 rot_mat(rot);
+				rot_mat *= trans_mat;
+
+				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
 			}
 			//  Recurse to continue trunk
 			if (trunk_depth)
 			{
-				glPushMatrix();
-				glTranslatef(0.f, 0.f, scale * length);
-				glRotatef(70.5f, 0.f, 0.f, 1.f);					// rotate a bit around Z when ascending 
-				ret += drawBranchPipeline(indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
-				glPopMatrix();
+				LLMatrix4 trans_mat;
+				trans_mat.setTranslation(0,0,scale*length);
+				trans_mat *= matrix;
+
+				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
+				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
+				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
 			}
 		}
 		else
@@ -861,21 +861,19 @@ U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U
 			//  Draw leaves as two 90 deg crossed quads with leaf textures
 			//
 			{
-				glPushMatrix();
-				//glRotatef(llFrand(50.0), llFrand(1.0), llFrand(1.0), llFrand(1.0);
-				//width = scale * (TREE_BRANCH_ASPECT + TREE_LEAF_ASPECT);
-				glScalef(scale*mLeafScale, scale*mLeafScale, scale*mLeafScale);
-				//glScalef(1.5f*width*mLeafScale,1,1.5f*scale*mLeafScale);
- 				glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, indicesp);
-				/*glDrawRangeElements(GL_TRIANGLES,
-									0,
-									LEAF_VERTICES-1,
-									LEAF_INDICES,
-									GL_UNSIGNED_INT,
-									indicesp);*/
+				LLMatrix4 scale_mat;
+				scale_mat.mMatrix[0][0] = 
+					scale_mat.mMatrix[1][1] =
+					scale_mat.mMatrix[2][2] = scale*mLeafScale;
+
+				scale_mat *= matrix;
+
+			
+				glLoadMatrixf((F32*) scale_mat.mMatrix);
+				glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
+							
 				stop_glerror();
 				ret += LEAF_INDICES;
-				glPopMatrix();
 			}
 		}
 	}
@@ -885,26 +883,25 @@ U32 LLVOTree::drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U
 		//  Draw the tree as a single billboard texture 
 		//
 
+		LLMatrix4 scale_mat;
+		scale_mat.mMatrix[0][0] = 
+			scale_mat.mMatrix[1][1] =
+			scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio;
+
+		scale_mat *= matrix;
+	
 		glMatrixMode(GL_TEXTURE);
-		glPushMatrix();
 		glTranslatef(0.0, -0.5, 0.0);
 		glMatrixMode(GL_MODELVIEW);
-		{
-			glPushMatrix();
-			glScalef(mBillboardScale*mBillboardRatio, mBillboardScale*mBillboardRatio, mBillboardScale);
- 			glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, indicesp);
-/*			glDrawRangeElements(GL_TRIANGLES,
-								0,
-								LEAF_VERTICES-1,
-								LEAF_INDICES,
-								GL_UNSIGNED_INT,
-								indicesp);*/
-			stop_glerror();
-			ret += LEAF_INDICES;
-			glPopMatrix();
-		}
+					
+		glLoadMatrixf((F32*) scale_mat.mMatrix);
+		glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
+		
+		stop_glerror();
+		ret += LEAF_INDICES;
+
 		glMatrixMode(GL_TEXTURE);
-		glPopMatrix();
+		glLoadIdentity();
 		glMatrixMode(GL_MODELVIEW);
 	}
 
@@ -923,18 +920,22 @@ void LLVOTree::updateRadius()
 
 void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 {
+	F32 radius = getScale().magVec()*0.05f;
 	LLVector3 center = getRenderPosition();
-	LLVector3 size = getScale();
-	center.mV[2] += size.mV[2];
 
+	F32 sz = mBillboardScale*mBillboardRatio*radius*0.5f; 
+	LLVector3 size(sz,sz,sz);
+
+	center += LLVector3(0, 0, size.mV[2]) * getRotation();
+	
 	newMin.setVec(center-size);
 	newMax.setVec(center+size);
-	mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+	mDrawable->setPositionGroup(center);
 }
 
 U32 LLVOTree::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_TREE; 
+	return LLViewerRegion::PARTITION_TREE; 
 }
 
 LLTreePartition::LLTreePartition()
@@ -942,7 +943,7 @@ LLTreePartition::LLTreePartition()
 {
 	mRenderByGroup = FALSE;
 	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
-	mPartitionType = LLPipeline::PARTITION_TREE;
+	mPartitionType = LLViewerRegion::PARTITION_TREE;
 	mSlopRatio = 0.f;
 	mLODPeriod = 1;
 }
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 90570f3b2ed..dee282c7522 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -78,10 +78,8 @@ class LLVOTree : public LLViewerObject
 
 	void updateRadius();
 
-	U32 drawBranchPipeline(U32* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha);
+	U32 drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha);
  
-	void drawBranch(S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha, BOOL draw_leaves);
-
 	static S32 sMaxTreeSpecies;
 
 	struct TreeSpeciesData
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 70037d3c202..5521b7f5f71 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -48,14 +48,13 @@
 #include "object_flags.h"
 #include "llagent.h"
 #include "lldrawable.h"
-#include "lldrawpoolsimple.h"
 #include "lldrawpoolbump.h"
 #include "llface.h"
+#include "llspatialpartition.h"
 
 // TEMP HACK ventrella
 #include "llhudmanager.h"
 #include "llflexibleobject.h"
-#include "llanimalcontrols.h"
 
 #include "llsky.h"
 #include "llviewercamera.h"
@@ -88,9 +87,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 	mRelativeXformInvTrans.identity();
 
 	mLOD = MIN_LOD;
-	mInited = FALSE;
 	mTextureAnimp = NULL;
-	mGlobalVolume = FALSE;
 	mVObjRadius = LLVector3(1,1,0.5f).magVec();
 	mNumFaces = 0;
 	mLODChanged = FALSE;
@@ -296,6 +293,8 @@ void LLVOVolume::animateTextures()
 		for (S32 i = start; i <= end; i++)
 		{
 			LLFace* facep = mDrawable->getFace(i);
+			if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue;
+
 			const LLTextureEntry* te = facep->getTextureEntry();
 			
 			if (!te)
@@ -321,7 +320,12 @@ void LLVOVolume::animateTextures()
 			LLQuaternion quat;
 			quat.setQuat(rot, 0, 0, -1.f);
 		
-			LLMatrix4& tex_mat = facep->mTextureMatrix;
+			if (!facep->mTextureMatrix)
+			{
+				facep->mTextureMatrix = new LLMatrix4();
+			}
+
+			LLMatrix4& tex_mat = *facep->mTextureMatrix;
 			tex_mat.identity();
 			tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
 			tex_mat.rotate(quat);				
@@ -402,7 +406,6 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 
 void LLVOVolume::updateTextures(LLAgent &agent)
 {
-// 	LLFastTimer t(LLFastTimer::FTM_TEMP6);
 	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
 	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
 	{
@@ -460,6 +463,29 @@ void LLVOVolume::updateTextures()
 		}
 
 		mPixelArea = llmax(mPixelArea, face->getPixelArea());
+
+		F32 old_size = face->getVirtualSize();
+
+		if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
+		{
+			
+			if (LLPipeline::sFastAlpha &&
+				vsize < MIN_ALPHA_SIZE && old_size > MIN_ALPHA_SIZE ||
+				vsize > MIN_ALPHA_SIZE && old_size < MIN_ALPHA_SIZE)
+			{
+				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_COLOR, FALSE);
+			}
+		}
+
+		if (face->mTextureMatrix != NULL)
+		{
+			if (vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE ||
+				vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE)
+			{
+				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE);
+			}
+		}
+		
 		face->setVirtualSize(vsize);
 		imagep->addTextureStats(vsize);
 		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
@@ -492,10 +518,12 @@ void LLVOVolume::updateTextures()
 			mSculptTexture->setBoostLevel(LLViewerImage::BOOST_SCULPTED);
 		}
 
-		S32 desired_discard = 0; // lower discard levels have MUCH less resolution - (old=MAX_LOD - mLOD)
+		S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
 		S32 current_discard = getVolume()->getSculptLevel();
-
-		if (desired_discard != current_discard)
+		
+		if (texture_discard >= 0 && //texture has some data available
+			(texture_discard < current_discard || //texture has more data than last rebuild
+			current_discard < 0)) //no previous rebuild
 		{
 			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
 			mSculptChanged = TRUE;
@@ -555,20 +583,13 @@ F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
 
 BOOL LLVOVolume::isActive() const
 {
-	return !mStatic || mTextureAnimp || isAttachment() || (mVolumeImpl && mVolumeImpl->isActive());
+	return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
 }
 
 BOOL LLVOVolume::setMaterial(const U8 material)
 {
 	BOOL res = LLViewerObject::setMaterial(material);
-	if (res)
-	{
-		// for deprecated LL_MCODE_LIGHT
-		if (mDrawable.notNull())
-		{
-			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_LIGHTING, TRUE);
-		}
-	}
+	
 	return res;
 }
 
@@ -608,14 +629,13 @@ LLFace* LLVOVolume::addFace(S32 f)
 LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 {
 	pipeline->allocDrawable(this);
+		
 	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 
 	S32 max_tes_to_set = getNumTEs();
 	for (S32 i = 0; i < max_tes_to_set; i++)
 	{
-		LLFace* face = addFace(i);
-		// JC - should there be a setViewerObject(this) call here?
-		face->setTEOffset(i);
+		addFace(i);
 	}
 	mNumFaces = max_tes_to_set;
 
@@ -666,8 +686,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 		}
 	}
 	
-	mGlobalVolume = (mVolumeImpl && mVolumeImpl->isVolumeGlobal());
-	
 	if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
 	{
 		mFaceMappingChanged = TRUE;
@@ -742,9 +760,16 @@ void LLVOVolume::sculpt()
 S32	LLVOVolume::computeLODDetail(F32 distance, F32 radius)
 {
 	S32	cur_detail;
-	// We've got LOD in the profile, and in the twist.  Use radius.
-	F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
-	cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f));
+	if (LLPipeline::sDynamicLOD)
+	{
+		// We've got LOD in the profile, and in the twist.  Use radius.
+		F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+		cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f));
+	}
+	else
+	{
+		cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);		
+	}
 	return cur_detail;
 }
 
@@ -755,6 +780,9 @@ BOOL LLVOVolume::calcLOD()
 		return FALSE;
 	}
 
+	//update face texture sizes on lod calculation
+	updateTextures();
+
 	S32 cur_detail = 0;
 	
 	F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).magVec();
@@ -860,12 +888,14 @@ void LLVOVolume::updateFaceFlags()
 
 void LLVOVolume::setParent(LLViewerObject* parent)
 {
-	LLViewerObject::setParent(parent);
-	if (mDrawable)
+	if (parent != getParent())
 	{
-		gPipeline.markMoved(mDrawable);
-		mVolumeChanged = TRUE;
-		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+		LLViewerObject::setParent(parent);
+		if (mDrawable)
+		{
+			gPipeline.markMoved(mDrawable);
+			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+		}
 	}
 }
 
@@ -909,7 +939,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 		LLFace *face = mDrawable->getFace(i);
 		res &= face->genVolumeBBoxes(*getVolume(), i,
 										mRelativeXform, mRelativeXformInvTrans,
-										mGlobalVolume | force_global);
+										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
 		
 		if (rebuild)
 		{
@@ -939,8 +969,6 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 	{
 		mDrawable->setSpatialExtents(min,max);
 		mDrawable->setPositionGroup((min+max)*0.5f);	
-		//bounding boxes changed, update texture priorities
-		updateTextures();
 	}
 
 	updateRadius();
@@ -949,6 +977,14 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 	return res;
 }
 
+void LLVOVolume::preRebuild()
+{
+	if (mVolumeImpl != NULL)
+	{
+		mVolumeImpl->preRebuild();
+	}
+}
+
 void LLVOVolume::updateRelativeXform()
 {
 	if (mVolumeImpl)
@@ -1012,8 +1048,8 @@ void LLVOVolume::updateRelativeXform()
 			rot *= mParent->getRotation();
 		}
 		
-		LLViewerRegion* region = getRegion();
-		pos += region->getOriginAgent();
+		//LLViewerRegion* region = getRegion();
+		//pos += region->getOriginAgent();
 		
 		LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot;
 		LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot;
@@ -1045,12 +1081,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	
 	if (mVolumeImpl != NULL)
 	{
-		LLFastTimer t(LLFastTimer::FTM_GEN_FLEX);
-		BOOL res = mVolumeImpl->doUpdateGeometry(drawable);
+		BOOL res;
+		{
+			LLFastTimer t(LLFastTimer::FTM_GEN_FLEX);
+			res = mVolumeImpl->doUpdateGeometry(drawable);
+		}
 		updateFaceFlags();
 		return res;
 	}
 	
+	dirtySpatialGroup();
+
 	BOOL compiled = FALSE;
 			
 	updateRelativeXform();
@@ -1063,7 +1104,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	if (mVolumeChanged || mFaceMappingChanged )
 	{
 		compiled = TRUE;
-		mInited = TRUE;
 
 		if (mVolumeChanged)
 		{
@@ -1248,6 +1288,17 @@ S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags)
 	return  res;
 }
 
+S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
+{
+	S32 res = LLViewerObject::setTEGlow(te, glow);
+	if (res)
+	{
+		gPipeline.markTextured(mDrawable);
+		mFaceMappingChanged = TRUE;
+	}
+	return  res;
+}
+
 S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
 {
 	S32 res = LLViewerObject::setTEScale(te, s, t);
@@ -1314,12 +1365,6 @@ void LLVOVolume::setIsLight(BOOL is_light)
 		{
 			// Not a light.  Remove it from the pipeline's light set.
 			gPipeline.setLight(mDrawable, FALSE);
-			
-			// Remove this object from any object which has it as a light
-			if (mDrawable)
-			{
-				mDrawable->clearLightSet();
-			}
 		}
 	}
 }
@@ -1476,92 +1521,6 @@ F32 LLVOVolume::getLightCutoff() const
 	}
 }
 
-//----------------------------------------------------------------------------
-
-// returns < 0 if inside radius
-F32 LLVOVolume::getLightDistance(const LLVector3& pos) const
-{
-	LLVector3 dpos = getRenderPosition() - pos;
-	F32 dist = dpos.magVec() - getLightRadius();
-	return dist;
-}
-
-// returns intensity, modifies color in result
-F32 LLVOVolume::calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LLColor4& result)
-{
-	if (!getIsLight())
-	{
-		return 0.0f;
-	}
-	F32 light_radius = getLightRadius();
-	LLVector3 light_pos = getRenderPosition();
-	LLVector3 light_dir = light_pos - pos;
-	F32 dist = light_dir.normVec();
-	F32 dp = norm * light_dir;
-	if ((gPipeline.getLightingDetail() > 2))
-	{
-		if (dp <= 0)
-		{
-			result *= 0;
-			return 0;
-		}
-
-		if (dist >= light_radius)
-		{
-			result *= 0;
-			return 0;
-		}
-
-		F32 mag = 1.0f-(dist/light_radius);
-		mag = powf(mag, 0.75f);
-		mag *= dp;
-		result = getLightColor() * mag;
-		return mag;
-	}
-	else
-	{
-		F32 light_radius = getLightRadius();
-		LLVector3 light_pos = getRenderPosition();
-		LLVector3 light_dir = light_pos - pos;
-		F32 dist = light_dir.normVec();
-		F32 dp = norm * light_dir;
-		F32 atten = (1.f/.2f) / (light_radius); // 20% of brightness at radius
-		F32 falloff = 1.f / (dist * atten);
-		F32 mag = falloff * dp;
-		mag = llmax(mag, 0.0f);
-		result = getLightColor() * mag;
-		return mag;
-	}
-}
-
-BOOL LLVOVolume::updateLighting(BOOL do_lighting)
-{
-	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
-#if 0
-	if (mDrawable->isStatic())
-	{
-		do_lighting = FALSE;
-	}
-
-	const LLMatrix4& mat_vert  = mDrawable->getWorldMatrix();
-	const LLMatrix3& mat_normal = LLMatrix3(mDrawable->getWorldRotation());
-	
-	LLVolume* volume = getVolume();
-
-	for (S32 i = 0; i < volume->getNumFaces(); i++)
-	{
-		LLFace *face = mDrawable->getFace(i);
-		if (face && face->getGeomCount())
-		{
-			face->genLighting(volume, mDrawable, i, i, mat_vert, mat_normal, do_lighting);
-		}
-	}		
-#endif
-	return TRUE;
-}
-
-//----------------------------------------------------------------------------
-
 U32 LLVOVolume::getVolumeInterfaceID() const
 {
 	if (mVolumeImpl)
@@ -1576,7 +1535,8 @@ BOOL LLVOVolume::isFlexible() const
 {
 	if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE))
 	{
-		if (getVolume()->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
+		LLVolume* volume = getVolume();
+		if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
 		{
 			LLVolumeParams volume_params = getVolume()->getParams();
 			U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
@@ -1684,7 +1644,13 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p
 		}
 		
 		updateRelativeXform();
-		volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, mRelativeXform, mRelativeXformInvTrans);
+		LLMatrix4 trans_mat = mRelativeXform;
+		if (mDrawable->isStatic())
+		{
+			trans_mat.translate(getRegion()->getOriginAgent());
+		}
+
+		volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans);
 
 		nodep->mSilhouetteExists = TRUE;
 	}
@@ -1744,137 +1710,6 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const
 	return mDrawable->getWorldMatrix();
 }
 
-void LLVOVolume::writeCAL3D(apr_file_t* fp, std::string& path, std::string& file_base, S32 joint_num, LLVector3& pos, LLQuaternion& rot, S32& material_index, S32& texture_index, std::multimap<LLUUID, LLMaterialExportInfo*>& material_map)
-{
-#if 0
-	LLImageTGA tga_image;
-
-	if (mDrawable.isNull())
-	{
-		return;
-	}
-
-	LLVector3 final_pos = getPosition();
-	final_pos *= 100.f;
-
-	final_pos = final_pos * rot;
-	final_pos += pos;
-	LLQuaternion final_rot;
-	final_rot = getRotation() * rot;
-	LLMatrix4 transform;
-	transform.initAll(getScale(), final_rot, final_pos);
-
-	LLMatrix4 int_transpose_transform;
-	int_transpose_transform.initAll(LLVector3(1.f / getScale().mV[VX], 1.f / getScale().mV[VY], 1.f / getScale().mV[VZ]), final_rot, LLVector3::zero);
-
-	for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
-	{
-		S32 vert_num = 0;
-		LLFace* facep = mDrawable->getFace(i);
-		LLDrawPool* poolp = facep->getPool();
-
-		const LLTextureEntry* tep = facep->getTextureEntry();
-		if (!tep)
-		{
-			continue;
-		}
-
-		S32 my_material = -1;
-		S32 my_texture = -1;
-		LLColor4 face_color = tep->getColor();
-
-		typedef std::multimap<LLUUID, LLMaterialExportInfo*>::iterator material_it_t;
-		std::pair<material_it_t, material_it_t> found_range = material_map.equal_range(tep->getID());
-		material_it_t material_it = found_range.first;
-
-		LLMaterialExportInfo* material_info = NULL;
-
-		while(material_it != material_map.end() && material_it != found_range.second)
-		{
-			// we've at least found a matching texture, so reuse it
-			my_texture = material_it->second->mTextureIndex;
-			if (material_it->second->mColor == face_color)
-			{
-				// we've found a matching material
-				material_info = material_it->second;
-			}
-			++material_it;
-		}
-
-		if (material_info)
-		{
-			// material already exported, just reuse it
-			my_material = material_info->mMaterialIndex;
-			my_texture = material_info->mTextureIndex;
-		}
-		else
-		{
-			// reserve new material number
-			my_material = material_index++;
-
-			// if we didn't already find a matching texture...
-			if (my_texture == -1)
-			{
-				//...use the next available slot...
-				my_texture = texture_index++;
-
-				//...and export texture as image file
-				char filename[MAX_PATH];		/* Flawfinder: ignore */
-				snprintf(filename, MAX_PATH, "%s\\%s_material_tex_%d.tga", path.c_str(), file_base.c_str(), my_texture);		/* Flawfinder: ignore */
-
-				LLViewerImage* imagep = facep->getTexture();
-				if (imagep->getTexName() == 0)
-				{
-					llinfos << "No image data available for " << filename << llendl;
-					continue;
-				}
-				LLImageRaw raw_image;
-				imagep->readBackRaw(-1, raw_image);
-				BOOL success = tga_image.encode(raw_image);
-				success = tga_image.save(filename);
-			}
-
-			material_info = new LLMaterialExportInfo(my_material, my_texture, face_color);
-			material_map.insert(std::make_pair<LLUUID, LLMaterialExportInfo*>(tep->getID(), material_info));
-		}
-
-		apr_file_printf(fp, "\t<SUBMESH NUMVERTICES=\"%d\" NUMFACES=\"%d\" MATERIAL=\"%d\" NUMLODSTEPS=\"0\" NUMSPRINGS=\"0\" NUMTEXCOORDS=\"1\">\n", 
-			facep->getGeomCount(), facep->getIndicesCount() / 3, my_material);
-
-		for (S32 vert_index = 0; vert_index < facep->getGeomCount(); vert_index++)
-		{
-			LLVector3 vert_pos = poolp->getVertex(facep->getGeomStart() + vert_index);
-			vert_pos *= 100.f;
-			vert_pos = vert_pos * transform;
-			LLVector3 vert_norm = poolp->getNormal(facep->getGeomStart() + vert_index);
-			vert_norm = vert_norm * int_transpose_transform;
-			LLVector2 vert_tc = poolp->getTexCoord(facep->getGeomStart() + vert_index, 0);
-			apr_file_printf(fp, "		<VERTEX ID=\"%d\" NUMINFLUENCES=\"1\">\n", vert_num++);
-			apr_file_printf(fp, "			<POS>%.4f %.4f %.4f</POS>\n", vert_pos.mV[VX], vert_pos.mV[VY], vert_pos.mV[VZ]);
-			apr_file_printf(fp, "			<NORM>%.6f %.6f %.6f</NORM>\n", vert_norm.mV[VX], vert_norm.mV[VY], vert_norm.mV[VZ]);
-			apr_file_printf(fp, "			<TEXCOORD>%.6f %.6f</TEXCOORD>\n", vert_tc.mV[VX], 1.f - vert_tc.mV[VY]);
-			apr_file_printf(fp, "			<INFLUENCE ID=\"%d\">1.0</INFLUENCE>\n", joint_num + 1);
-			apr_file_printf(fp, "		</VERTEX>\n");
-		}
-
-		for (U32 index_i = 0; index_i < facep->getIndicesCount(); index_i += 3)
-		{
-			U32 index_a = poolp->getIndex(facep->getIndicesStart() + index_i) - facep->getGeomStart();
-			U32 index_b = poolp->getIndex(facep->getIndicesStart() + index_i + 1) - facep->getGeomStart();
-			U32 index_c = poolp->getIndex(facep->getIndicesStart() + index_i + 2) - facep->getGeomStart();
-			apr_file_printf(fp, "		<FACE VERTEXID=\"%d %d %d\" />\n", index_a, index_b, index_c);
-		}
-
-		apr_file_printf(fp, "	</SUBMESH>\n");
-	}
-	
-	for (U32 i = 0; i < mChildList.size(); i++)
-	{
-		((LLVOVolume*)(LLViewerObject*)mChildList[i])->writeCAL3D(fp, path, file_base, joint_num, final_pos, final_rot, material_index, texture_index, material_map);
-	}
-#endif
-}
-
 //static
 void LLVOVolume::preUpdateGeom()
 {
@@ -1908,7 +1743,7 @@ void LLVOVolume::setSelected(BOOL sel)
 	LLViewerObject::setSelected(sel);
 	if (mDrawable.notNull())
 	{
-		mDrawable->movePartition();
+		markForUpdate(TRUE);
 	}
 }
 
@@ -1929,7 +1764,9 @@ F32 LLVOVolume::getBinRadius()
 	{
 		for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
 		{
-			if (mDrawable->getFace(i)->getPoolType() == LLDrawPool::POOL_ALPHA)
+			LLFace* face = mDrawable->getFace(i);
+			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
+				(!LLPipeline::sFastAlpha || face->getVirtualSize() > MIN_ALPHA_SIZE))
 			{
 				alpha_wrap = TRUE;
 				break;
@@ -1954,7 +1791,14 @@ F32 LLVOVolume::getBinRadius()
 	}
 	else if (mDrawable->isStatic())
 	{
-		radius = 32.f;
+		if (mDrawable->getRadius() < 2.0f)
+		{
+			radius = 16.f;
+		}
+		else
+		{
+			radius = 32.f;
+		}
 	}
 	else
 	{
@@ -2049,10 +1893,10 @@ U32 LLVOVolume::getPartitionType() const
 {
 	if (isHUDAttachment())
 	{
-		return LLPipeline::PARTITION_HUD;
+		return LLViewerRegion::PARTITION_HUD;
 	}
 
-	return LLPipeline::PARTITION_VOLUME;
+	return LLViewerRegion::PARTITION_VOLUME;
 }
 
 LLVolumePartition::LLVolumePartition()
@@ -2061,7 +1905,7 @@ LLVolumePartition::LLVolumePartition()
 	mLODPeriod = 16;
 	mDepthMask = FALSE;
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
-	mPartitionType = LLPipeline::PARTITION_VOLUME;
+	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
 	mSlopRatio = 0.25f;
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	mImageEnabled = TRUE;
@@ -2073,7 +1917,7 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
 	mDepthMask = FALSE;
 	mLODPeriod = 16;
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
-	mPartitionType = LLPipeline::PARTITION_BRIDGE;
+	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
 	
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 
@@ -2099,50 +1943,47 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 					  type == LLRenderPass::PASS_ALPHA) ? facep->isState(LLFace::FULLBRIGHT) : FALSE;
 
 	const LLMatrix4* tex_mat = NULL;
-	if (type != LLRenderPass::PASS_SHINY && facep->isState(LLFace::TEXTURE_ANIM))
+	if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
 	{
-		tex_mat = &(facep->mTextureMatrix);	
+		tex_mat = facep->mTextureMatrix;	
+	}
+
+	const LLMatrix4* model_mat = NULL;
+
+	LLDrawable* drawable = facep->getDrawable();
+	if (drawable->isActive())
+	{
+		model_mat = &(drawable->getRenderMatrix());
+	}
+	else
+	{
+		model_mat = &(drawable->getRegion()->mRenderMatrix);
 	}
 
 	U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0);
 	
-	//LLViewerImage* tex = facep->mAppAngle < FORCE_SIMPLE_RENDER_ANGLE ? NULL : facep->getTexture();
 	LLViewerImage* tex = facep->getTexture();
 
+	U8 glow = 0;
+		
 	if (type == LLRenderPass::PASS_GLOW)
 	{
-		U32 start = facep->getGeomIndex();
-		U32 end = start + facep->getGeomCount()-1;
-		U32 offset = facep->getIndicesStart();
-		U32 count = facep->getIndicesCount();
-		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset,tex, 
-			facep->mVertexBuffer, fullbright, bump); 
-		draw_info->mVSize = facep->getVirtualSize();
-		draw_vec.push_back(draw_info);
-		LLVOVolume* volume = (LLVOVolume*) facep->getViewerObject();
-		BOOL is_light = volume->mDrawable->isLight();
-
-		U8 alpha = is_light ? 196 : 160;
-		LLColor3 col = is_light ? volume->getLightColor() : LLColor3(0,0,0);
-		LLColor4 col2 = facep->getRenderColor();
-		draw_info->mGlowColor.setVec((U8) (col.mV[0]*col2.mV[0]*255),
-									(U8) (col.mV[1]*col2.mV[1]*255),
-									(U8) (col.mV[2]*col2.mV[2]*255),
-									alpha);					
-		draw_info->mTextureMatrix = tex_mat;
-		validate_draw_info(*draw_info);
+		glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
 	}
-	else if (idx >= 0 && 
+
+	if (idx >= 0 && 
 		draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
 		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
-		draw_vec[idx]->mTexture == tex &&
+		(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
 #if LL_DARWIN
 		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 #endif
+		draw_vec[idx]->mGlowColor.mV[3] == glow &&
 		draw_vec[idx]->mFullbright == fullbright &&
 		draw_vec[idx]->mBump == bump &&
-		draw_vec[idx]->mTextureMatrix == tex_mat)
+		draw_vec[idx]->mTextureMatrix == tex_mat &&
+		draw_vec[idx]->mModelMatrix == model_mat)
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
@@ -2157,10 +1998,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		U32 count = facep->getIndicesCount();
 		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset,tex, 
 			facep->mVertexBuffer, fullbright, bump); 
+		draw_info->mGroup = group;
 		draw_info->mVSize = facep->getVirtualSize();
 		draw_vec.push_back(draw_info);
 		draw_info->mReflectionMap = group->mReflectionMap;
 		draw_info->mTextureMatrix = tex_mat;
+		draw_info->mModelMatrix = model_mat;
+		draw_info->mGlowColor.setVec(0,0,0,glow);
 		validate_draw_info(*draw_info);
 	}
 }
@@ -2172,6 +2016,11 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
+	if (LLPipeline::sSkipUpdate)
+	{
+		return;
+	}
+
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -2182,6 +2031,60 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	if (!group->isState(LLSpatialGroup::GEOM_DIRTY |
 						LLSpatialGroup::ALPHA_DIRTY))
 	{
+		if (group->isState(LLSpatialGroup::MESH_DIRTY))
+		{
+			group->mBuilt = 1.f;
+			LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO);	
+
+			LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB);
+
+			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+			{
+				LLDrawable* drawablep = *drawable_iter;
+				if (drawablep->isState(LLDrawable::REBUILD_ALL))
+				{
+					LLVOVolume* vobj = drawablep->getVOVolume();
+					vobj->preRebuild();
+					LLVolume* volume = vobj->getVolume();
+					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+					{
+						LLFace* face = drawablep->getFace(i);
+						if (face && face->mVertexBuffer.notNull())
+						{
+							face->getGeometryVolume(*volume, face->getTEOffset(), 
+								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+						}
+					}
+
+					drawablep->clearState(LLDrawable::REBUILD_ALL);
+				}
+			}
+			
+			//unmap all the buffers
+			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+			{
+				LLSpatialGroup::buffer_list_t& list = i->second;
+				for (LLSpatialGroup::buffer_list_t::iterator j = list.begin(); j != list.end(); ++j)
+				{
+					LLVertexBuffer* buffer = *j;
+					if (buffer->isLocked())
+					{
+						buffer->setBuffer(0);
+					}
+				}
+			}
+			
+			// don't forget alpha
+			if(	group != NULL && 
+				!group->mVertexBuffer.isNull() && 
+				group->mVertexBuffer->isLocked())
+			{
+				group->mVertexBuffer->setBuffer(0);
+			}
+
+			group->clearState(LLSpatialGroup::MESH_DIRTY);
+		}
+
 		return;
 	}
 
@@ -2191,7 +2094,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB);
 
 	//find reflection map
-	if (group->mSpatialPartition->mImageEnabled)
+	if (group->mSpatialPartition->mImageEnabled && LLPipeline::sDynamicReflections)
 	{
 		if (group->mReflectionMap.isNull())
 		{
@@ -2213,6 +2116,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	U32 index_count = 0;
 	U32 useage = group->mSpatialPartition->mBufferUsage;
 
+	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+	max_vertices = llmin(max_vertices, (U32) 65535);
+
 	//get all the faces into a list, putting alpha faces in their own list
 	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 	{
@@ -2229,6 +2135,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		}
 
 		LLVOVolume* vobj = drawablep->getVOVolume();
+		vobj->updateTextures();
+		vobj->preRebuild();
 
 		//for each face
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
@@ -2272,9 +2180,38 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 				if (type == LLDrawPool::POOL_ALPHA)
 				{
-					vertex_count += facep->getGeomCount();
-					index_count += facep->getIndicesCount();
-					alpha_faces.push_back(facep);
+					BOOL alpha_opt = LLPipeline::sFastAlpha && gPipeline.canUseWindLightShadersOnObjects() && facep->getVirtualSize() < MIN_ALPHA_SIZE;
+
+					const LLColor4& col = facep->getTextureEntry()->getColor();
+
+					if (alpha_opt)
+					{ //if we're applying the alpha optimization, only blend faces that have alpha (0.15, 0.5]
+					  //for faces with alpha (0.5, 1.0], render with an alpha mask
+					  //for faces with alpha [0.0, 0.15], don't render
+						if (col.mV[3] > 0.5f)
+						{
+							mFaceList.push_back(facep);
+						}
+						else if (col.mV[3] > 0.15f)
+						{
+							vertex_count += facep->getGeomCount();
+							index_count += facep->getIndicesCount();
+							alpha_faces.push_back(facep);
+						}
+						else
+						{	//face has no renderable geometry
+							facep->mVertexBuffer = NULL;
+							facep->mLastVertexBuffer = NULL;
+							//don't alpha wrap drawables that have only tiny tiny alpha faces
+							facep->setPoolType(LLDrawPool::POOL_SIMPLE);
+						}
+					}
+					else
+					{
+						vertex_count += facep->getGeomCount();
+						index_count += facep->getIndicesCount();
+						alpha_faces.push_back(facep);
+					}
 				}
 				else
 				{
@@ -2291,47 +2228,60 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				facep->mLastVertexBuffer = NULL;
 				//don't alpha wrap drawables that have only tiny tiny alpha faces
 				facep->setPoolType(LLDrawPool::POOL_SIMPLE);
-			}
-
-			vobj->updateTextures();
+			}		
 		}
 	}
 
-	group->mVertexCount = vertex_count;
-	group->mIndexCount = index_count;
-	group->mBufferUsage = useage;
+	U16 alpha_vertex_count = vertex_count > 65535 ? 65535 : vertex_count;
+	U32 alpha_index_count = index_count;
 
-	LLStrider<LLVector3> vertices;
-	LLStrider<LLVector3> normals;
-	LLStrider<LLVector2> texcoords2;
-	LLStrider<LLVector2> texcoords;
-	LLStrider<LLColor4U> colors;
-	LLStrider<U32> indices;
+	group->mBufferUsage = useage;
 
 	//PROCESS NON-ALPHA FACES
 	{
-		//sort faces by texture
-		std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareTextureAndTime());
-		
+		//sort faces by things that break batches
+		std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareBatchBreaker());
+					
 		std::vector<LLFace*>::iterator face_iter = mFaceList.begin();
 		
 		LLSpatialGroup::buffer_map_t buffer_map;
 
+		LLViewerImage* last_tex = NULL;
+		U32 buffer_index = 0;
+
 		while (face_iter != mFaceList.end())
 		{
 			//pull off next face
 			LLFace* facep = *face_iter;
 			LLViewerImage* tex = facep->getTexture();
 
+			if (last_tex == tex)
+			{
+				buffer_index++;
+			}
+			else
+			{
+				last_tex = tex;
+				buffer_index = 0;
+			}
+
 			U32 index_count = facep->getIndicesCount();
 			U32 geom_count = facep->getGeomCount();
 
 			//sum up vertices needed for this texture
 			std::vector<LLFace*>::iterator i = face_iter;
 			++i;
-			while (i != mFaceList.end() && (*i)->getTexture() == tex)
+			
+			while (i != mFaceList.end() && 
+				(LLPipeline::sTextureBindTest || (*i)->getTexture() == tex))
 			{
 				facep = *i;
+				
+				if (geom_count + facep->getGeomCount() > max_vertices)
+				{ //cut vertex buffers on geom count too big
+					break;
+				}
+
 				++i;
 				index_count += facep->getIndicesCount();
 				geom_count += facep->getGeomCount();
@@ -2342,9 +2292,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			LLSpatialGroup::buffer_map_t::iterator found_iter = group->mBufferMap.find(tex);
 			if (found_iter != group->mBufferMap.end())
 			{
-				buffer = found_iter->second;
+				if (buffer_index < found_iter->second.size())
+				{
+					buffer = found_iter->second[buffer_index];
+				}
 			}
-						
+							
 			if (!buffer)
 			{ //create new buffer if needed
 				buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
@@ -2365,21 +2318,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				}
 			}
 
-			BOOL clean = TRUE;
-			buffer_map[tex] = buffer;
+			buffer_map[tex].push_back(buffer);
 
 			//add face geometry
-		
-			//get vertex buffer striders
-			buffer->getVertexStrider(vertices);
-			buffer->getNormalStrider(normals);
-			buffer->getTexCoordStrider(texcoords);
-			buffer->getTexCoord2Strider(texcoords2);
-			buffer->getColorStrider(colors);
-			buffer->getIndexStrider(indices);
 
 			U32 indices_index = 0;
-			U32 index_offset = 0;
+			U16 index_offset = 0;
 
 			while (face_iter < i)
 			{
@@ -2393,60 +2337,82 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				facep->mGeomIndex = index_offset;
 				facep->mVertexBuffer = buffer;
 				{
-					if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, 
+					if (facep->getGeometryVolume(*volume, te_idx, 
 						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
 					{
-						clean = FALSE;
 						buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
 							facep->getIndicesStart(), facep->getIndicesCount());
 					}
 				}
 
+				index_offset += facep->getGeomCount();
 				indices_index += facep->mIndicesCount;
 
 				BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
 				BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
 				const LLTextureEntry* te = facep->getTextureEntry();
 
-				if (tex->getPrimaryFormat() == GL_ALPHA)
-				{
-					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
-				}
-				else if (fullbright)
+				BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
+
+				if (!is_alpha 
+					&& gPipeline.canUseWindLightShadersOnObjects()
+					&& LLPipeline::sRenderBump 
+					&& te->getShiny())
 				{
-					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+					if (tex->getPrimaryFormat() == GL_ALPHA)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
+						registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+					}
+					else if (fullbright)
+					{						
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+					}
+					else
+					{
+						registerFace(group, facep, LLRenderPass::PASS_SHINY);
+					}
 				}
 				else
 				{
-					registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
-				}
-
-				facep->setPoolType(LLDrawPool::POOL_SIMPLE);
-
-				if (te->getShiny())
-				{
-					registerFace(group, facep, LLRenderPass::PASS_SHINY);
+					if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+					}
+					else if (fullbright)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+					}
+					else
+					{
+						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+					}
+					
+					if (!is_alpha && te->getShiny())
+					{
+						registerFace(group, facep, LLRenderPass::PASS_SHINY);
+					}
 				}
-
-				if (!force_simple && te->getBumpmap())
+				
+				if (!is_alpha)
 				{
-					registerFace(group, facep, LLRenderPass::PASS_BUMP);
+					facep->setPoolType(LLDrawPool::POOL_SIMPLE);
+					
+					if (!force_simple && te->getBumpmap())
+					{
+						registerFace(group, facep, LLRenderPass::PASS_BUMP);
+					}
 				}
 
-				if (vobj->getIsLight() ||
-					(LLPipeline::sRenderGlow && facep->isState(LLFace::FULLBRIGHT)))
+				if (LLPipeline::sRenderGlow && te->getGlow() > 0.f)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_GLOW);
 				}
-				
-
+							
 				++face_iter;
 			}
 
-			if (clean)
-			{
-				buffer->markClean();
-			}
+			buffer->setBuffer(0);
 		}
 
 		group->mBufferMap.clear();
@@ -2467,33 +2433,31 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		{
 			group->mVertexBuffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
 													  group->mBufferUsage);
-			group->mVertexBuffer->allocateBuffer(group->mVertexCount, group->mIndexCount, true);
+			group->mVertexBuffer->allocateBuffer(alpha_vertex_count, alpha_index_count, true);
 			stop_glerror();
 		}
 		else
 		{
-			group->mVertexBuffer->resizeBuffer(group->mVertexCount, group->mIndexCount);
+			group->mVertexBuffer->resizeBuffer(alpha_vertex_count, alpha_index_count);
 			stop_glerror();
 		}
 
 		//get vertex buffer striders
 		LLVertexBuffer* buffer = group->mVertexBuffer;
 
-		BOOL clean = TRUE;
-
-		buffer->getVertexStrider(vertices);
-		buffer->getNormalStrider(normals);
-		buffer->getTexCoordStrider(texcoords);
-		buffer->getTexCoord2Strider(texcoords2);
-		buffer->getColorStrider(colors);
-		buffer->getIndexStrider(indices);
-
 		U32 index_offset = 0;
 		U32 indices_index = 0;
 
 		for (std::vector<LLFace*>::iterator i = alpha_faces.begin(); i != alpha_faces.end(); ++i)
 		{
 			LLFace* facep = *i;
+
+			if (facep->mGeomCount + index_offset > 65535)
+			{ //cut off alpha nodes at 64k vertices
+				facep->mVertexBuffer = NULL ;
+				continue ;
+			}
+
 			LLDrawable* drawablep = facep->getDrawable();
 			LLVOVolume* vobj = drawablep->getVOVolume();
 			LLVolume* volume = vobj->getVolume();
@@ -2502,30 +2466,33 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			facep->mIndicesIndex = indices_index;
 			facep->mGeomIndex = index_offset;
 			facep->mVertexBuffer = group->mVertexBuffer;
-			if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, 
-				vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
+			if (facep->getGeometryVolume(*volume, te_idx, 
+										vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), 
+										index_offset))
 			{
-				clean = FALSE;
 				buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
 					facep->getIndicesStart(), facep->getIndicesCount());
 			}
 
+			index_offset += facep->getGeomCount();
 			indices_index += facep->mIndicesCount;
 
 			registerFace(group, facep, LLRenderPass::PASS_ALPHA);
-		}
 
-		if (clean)
-		{
-			buffer->markClean();
+			if (LLPipeline::sRenderGlow && facep->getTextureEntry()->getGlow() > 0.f)
+			{
+				registerFace(group, facep, LLRenderPass::PASS_GLOW);
+			}				
 		}
+
+		buffer->setBuffer(0);
 	}
 	else
 	{
 		group->mVertexBuffer = NULL;
 	}
 
-	//get all the faces into a list, putting alpha faces in their own list
+	//drawables have been rebuilt, clear rebuild status
 	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 	{
 		LLDrawable* drawablep = *drawable_iter;
@@ -2533,8 +2500,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	}
 
 	group->mLastUpdateTime = gFrameTimeSeconds;
-	group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MATRIX_DIRTY |
-						LLSpatialGroup::ALPHA_DIRTY);
+	group->mBuilt = 1.f;
+	group->clearState(LLSpatialGroup::GEOM_DIRTY |
+						LLSpatialGroup::ALPHA_DIRTY | LLSpatialGroup::MESH_DIRTY);
 
 	mFaceList.clear();
 }
@@ -2589,7 +2557,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 
 LLHUDPartition::LLHUDPartition()
 {
-	mPartitionType = LLPipeline::PARTITION_HUD;
+	mPartitionType = LLViewerRegion::PARTITION_HUD;
 	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
 	mSlopRatio = 0.f;
 	mLODPeriod = 16;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 60700e65638..5f98dd6b9ce 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -33,7 +33,6 @@
 #define LL_LLVOVOLUME_H
 
 #include "llviewerobject.h"
-#include "llspatialpartition.h"
 #include "llviewerimage.h"
 #include "llframetimer.h"
 #include "llapr.h"
@@ -67,6 +66,7 @@ class LLVolumeInterface
 	virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0;
 	virtual void updateRelativeXform() = 0;
 	virtual U32 getID() const = 0;
+	virtual void preRebuild() = 0;
 };
 
 // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME)
@@ -105,7 +105,6 @@ class LLVOVolume : public LLViewerObject
 
 				void	generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point);
 	/*virtual*/	void	setParent(LLViewerObject* parent);
-				F32		getIndividualRadius()					{ return mRadius; }
 				S32		getLOD() const							{ return mLOD; }
 	const LLVector3		getPivotPositionAgent() const;
 	const LLMatrix4&	getRelativeXform() const				{ return mRelativeXform; }
@@ -147,6 +146,7 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ S32		setTEShiny(const U8 te, const U8 shiny);
 	/*virtual*/ S32		setTEFullbright(const U8 te, const U8 fullbright);
 	/*virtual*/ S32		setTEMediaFlags(const U8 te, const U8 media_flags);
+	/*virtual*/ S32		setTEGlow(const U8 te, const F32 glow);
 	/*virtual*/ S32		setTEScale(const U8 te, const F32 s, const F32 t);
 	/*virtual*/ S32		setTEScaleS(const U8 te, const F32 s);
 	/*virtual*/ S32		setTEScaleT(const U8 te, const F32 t);
@@ -168,19 +168,10 @@ class LLVOVolume : public LLViewerObject
 				void	updateFaceFlags();
 				void	regenFaces();
 				BOOL	genBBoxes(BOOL force_global);
+				void	preRebuild();
 	virtual		void	updateSpatialExtents(LLVector3& min, LLVector3& max);
 	virtual		F32		getBinRadius();
-	virtual		void	writeCAL3D(apr_file_t* fp, 
-							std::string& path,
-							std::string& file_base,
-							S32 joint_num, 
-							LLVector3& pos, 
-							LLQuaternion& rot, 
-							S32& material_index, 
-							S32& texture_index, 
-							std::multimap<LLUUID, LLMaterialExportInfo*>& material_map);
-
-
+	
 	virtual U32 getPartitionType() const;
 
 	// For Lights
@@ -197,8 +188,7 @@ class LLVOVolume : public LLViewerObject
 	F32 getLightRadius() const;
 	F32 getLightFalloff() const;
 	F32 getLightCutoff() const;
-	F32 getLightDistance(const LLVector3& pos) const; // returns < 0 if inside radius
-
+	
 	// Flexible Objects
 	U32 getVolumeInterfaceID() const;
 	virtual BOOL isFlexible() const;
@@ -206,11 +196,7 @@ class LLVOVolume : public LLViewerObject
 	BOOL isVolumeGlobal() const;
 	BOOL canBeFlexible() const;
 	BOOL setIsFlexible(BOOL is_flexible);
-	
-	// Lighting
-	F32 calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LLColor4& result);
-	BOOL updateLighting(BOOL do_lighting);
-
+			
 protected:
 	S32	computeLODDetail(F32	distance, F32 radius);
 	BOOL calcLOD();
@@ -220,17 +206,14 @@ class LLVOVolume : public LLViewerObject
 public:
 	LLViewerTextureAnim *mTextureAnimp;
 	U8 mTexAnimMode;
-protected:
+private:
 	friend class LLDrawable;
 	
 	BOOL		mFaceMappingChanged;
-	BOOL		mGlobalVolume;
-	BOOL		mInited;
 	LLFrameTimer mTextureUpdateTimer;
 	S32			mLOD;
 	BOOL		mLODChanged;
 	BOOL		mSculptChanged;
-	F32			mRadius;
 	LLMatrix4	mRelativeXform;
 	LLMatrix3	mRelativeXformInvTrans;
 	BOOL		mVolumeChanged;
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 33095d1b8c0..901dc6de21d 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -48,6 +48,7 @@
 #include "llviewerregion.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "llspatialpartition.h"
 
 const BOOL gUseRoam = FALSE;
 
@@ -76,6 +77,7 @@ LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regi
 	setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility.
 
 	mUseTexture = TRUE;
+	mIsEdgePatch = FALSE;
 }
 
 
@@ -106,14 +108,14 @@ void LLVOWater::updateTextures(LLAgent &agent)
 // Never gets called
 BOOL LLVOWater::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
- 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER)))
+ 	/*if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER)))
 	{
 		return TRUE;
 	}
-	if (mDrawable)
+	if (mDrawable) 
 	{
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
-	}
+	}*/
 	return TRUE;
 }
 
@@ -149,23 +151,23 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	}
 	face = drawable->getFace(0);
 
-	LLVector2 uvs[4];
-	LLVector3 vtx[4];
+//	LLVector2 uvs[4];
+//	LLVector3 vtx[4];
 
 	LLStrider<LLVector3> verticesp, normalsp;
 	LLStrider<LLVector2> texCoordsp;
-	LLStrider<U32> indicesp;
-	S32 index_offset;
+	LLStrider<U16> indicesp;
+	U16 index_offset;
 
 	S32 size = 16;
 
+	S32 num_quads = size*size;	
+	face->setSize(4*num_quads, 6*num_quads);
+
 	if (face->mVertexBuffer.isNull())
 	{
-		S32 num_quads = size*size;	
-		face->setSize(4*num_quads, 6*num_quads);
-		
 		face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
-		face->mVertexBuffer->allocateBuffer(4*num_quads, 6*num_quads, TRUE);
+		face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
 		face->setIndicesIndex(0);
 		face->setGeomIndex(0);
 	}
@@ -175,11 +177,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	}
 		
 	index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
-	if (-1 == index_offset)
-	{
-		return TRUE;
-	}
-	
+		
 	LLVector3 position_agent;
 	position_agent = getPositionAgent();
 	face->mCenterAgent = position_agent;
@@ -204,34 +202,20 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 			position_agent.mV[VX] += (x + 0.5f) * step_x;
 			position_agent.mV[VY] += (y + 0.5f) * step_y;
 
-			vtx[0] = position_agent - right + up;
-			vtx[1] = position_agent - right - up;
-			vtx[2] = position_agent + right + up;
-			vtx[3] = position_agent + right - up;
-
-			*(verticesp++)  = vtx[0];
-			*(verticesp++)  = vtx[1];
-			*(verticesp++)  = vtx[2];
-			*(verticesp++)  = vtx[3];
-
-			uvs[0].setVec(x*size_inv, (y+1)*size_inv);
-			uvs[1].setVec(x*size_inv, y*size_inv);
-			uvs[2].setVec((x+1)*size_inv, (y+1)*size_inv);
-			uvs[3].setVec((x+1)*size_inv, y*size_inv);
-
-			*(texCoordsp) = uvs[0];
-			texCoordsp++;
-			*(texCoordsp) = uvs[1];
-			texCoordsp++;
-			*(texCoordsp) = uvs[2];
-			texCoordsp++;
-			*(texCoordsp) = uvs[3];
-			texCoordsp++;
-
-			*(normalsp++)   = normal;
-			*(normalsp++)   = normal;
-			*(normalsp++)   = normal;
-			*(normalsp++)   = normal;
+			*verticesp++  = position_agent - right + up;
+			*verticesp++  = position_agent - right - up;
+			*verticesp++  = position_agent + right + up;
+			*verticesp++  = position_agent + right - up;
+
+			*texCoordsp++ = LLVector2(x*size_inv, (y+1)*size_inv);
+			*texCoordsp++ = LLVector2(x*size_inv, y*size_inv);
+			*texCoordsp++ = LLVector2((x+1)*size_inv, (y+1)*size_inv);
+			*texCoordsp++ = LLVector2((x+1)*size_inv, y*size_inv);
+			
+			*normalsp++   = normal;
+			*normalsp++   = normal;
+			*normalsp++   = normal;
+			*normalsp++   = normal;
 
 			*indicesp++ = toffset + 0;
 			*indicesp++ = toffset + 1;
@@ -243,6 +227,8 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 		}
 	}
 	
+	face->mVertexBuffer->setBuffer(0);
+
 	mDrawable->movePartition();
 	LLPipeline::sCompiles++;
 	return TRUE;
@@ -268,6 +254,11 @@ void LLVOWater::setUseTexture(const BOOL use_texture)
 	mUseTexture = use_texture;
 }
 
+void LLVOWater::setIsEdgePatch(const BOOL edge_patch)
+{
+	mIsEdgePatch = edge_patch;
+}
+
 void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax)
 {
 	LLVector3 pos = getPositionAgent();
@@ -281,13 +272,14 @@ void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax)
 
 U32 LLVOWater::getPartitionType() const
 { 
-	return LLPipeline::PARTITION_WATER; 
+	return LLViewerRegion::PARTITION_WATER; 
 }
 
 LLWaterPartition::LLWaterPartition()
 : LLSpatialPartition(0)
 {
 	mRenderByGroup = FALSE;
+	mInfiniteFarClip = TRUE;
 	mDrawableType = LLPipeline::RENDER_TYPE_WATER;
-	mPartitionType = LLPipeline::PARTITION_WATER;
+	mPartitionType = LLViewerRegion::PARTITION_WATER;
 }
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index 12b5ac07fe1..346fa5bb46a 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -75,9 +75,13 @@ class LLVOWater : public LLStaticViewerObject
 	/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
 
 	void setUseTexture(const BOOL use_texture);
+	void setIsEdgePatch(const BOOL edge_patch);
+	BOOL getUseTexture() const { return mUseTexture; }
+	BOOL getIsEdgePatch() const { return mIsEdgePatch; }
 
 protected:
 	BOOL mUseTexture;
+	BOOL mIsEdgePatch;
 };
 
 #endif // LL_VOSURFACEPATCH_H
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
new file mode 100644
index 00000000000..ca9f328e482
--- /dev/null
+++ b/indra/newview/llvowlsky.cpp
@@ -0,0 +1,821 @@
+/** 
+ * @file llvowlsky.cpp
+ * @brief LLVOWLSky class implementation
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+
+#include "llvowlsky.h"
+#include "llsky.h"
+#include "lldrawpoolwlsky.h"
+#include "llface.h"
+#include "llwlparammanager.h"
+#include "llviewercontrol.h"
+
+#define DOME_SLICES 1
+const F32 LLVOWLSky::DISTANCE_TO_STARS = (HORIZON_DIST - 10.f)*0.25f;
+
+const U32 LLVOWLSky::MIN_SKY_DETAIL = 3;
+const U32 LLVOWLSky::MAX_SKY_DETAIL = 180;
+
+inline U32 LLVOWLSky::getNumStacks(void)
+{
+	return gSavedSettings.getU32("WLSkyDetail");
+}
+
+inline U32 LLVOWLSky::getNumSlices(void)
+{
+	return 2 * gSavedSettings.getU32("WLSkyDetail");
+}
+
+inline U32 LLVOWLSky::getFanNumVerts(void)
+{
+	return getNumSlices() + 1;
+}
+
+inline U32 LLVOWLSky::getFanNumIndices(void)
+{
+	return getNumSlices() * 3;
+}
+
+inline U32 LLVOWLSky::getStripsNumVerts(void)
+{
+	return (getNumStacks() - 1) * getNumSlices();
+}
+
+inline U32 LLVOWLSky::getStripsNumIndices(void)
+{
+	return 2 * ((getNumStacks() - 2) * (getNumSlices() + 1)) + 1 ; 
+}
+
+inline U32 LLVOWLSky::getStarsNumVerts(void)
+{
+	return 1000;
+}
+
+inline U32 LLVOWLSky::getStarsNumIndices(void)
+{
+	return 1000;
+}
+
+LLVOWLSky::LLVOWLSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+	: LLStaticViewerObject(id, pcode, regionp)
+{
+	initStars();
+}
+
+void LLVOWLSky::initSunDirection(LLVector3 const & sun_direction,
+		LLVector3 const & sun_angular_velocity)
+{
+}
+
+BOOL LLVOWLSky::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+	return TRUE;
+}
+
+BOOL LLVOWLSky::isActive(void) const
+{
+	return FALSE;
+}
+
+LLDrawable * LLVOWLSky::createDrawable(LLPipeline * pipeline)
+{
+	pipeline->allocDrawable(this);
+
+	//LLDrawPoolWLSky *poolp = static_cast<LLDrawPoolWLSky *>(
+		gPipeline.getPool(LLDrawPool::POOL_WL_SKY);
+
+	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_WL_SKY);
+
+	return mDrawable;
+}
+
+inline F32 LLVOWLSky::calcPhi(U32 i)
+{
+	// i should range from [0..SKY_STACKS] so t will range from [0.f .. 1.f]
+	F32 t = float(i) / float(getNumStacks());
+
+	// ^4 the parameter of the tesselation to bias things toward 0 (the dome's apex)
+	t = t*t*t*t;
+	
+	// invert and square the parameter of the tesselation to bias things toward 1 (the horizon)
+	t = 1.f - t;
+	t = t*t;
+	t = 1.f - t;
+
+	return (F_PI / 8.f) * t;
+}
+
+#if !DOME_SLICES
+static const F32 Q = (1.f + sqrtf(5.f))/2.f; //golden ratio
+
+//icosahedron verts (based on asset b0c7b76e-28c6-1f87-a1de-752d5e3cd264, contact Runitai Linden for a copy)
+static const LLVector3 icosahedron_vert[] =
+{
+	LLVector3(0,1.f,Q),
+	LLVector3(0,-1.f,Q),
+	LLVector3(0,-1.f,-Q),
+	LLVector3(0,1.f,-Q),
+
+	LLVector3(Q,0,1.f),
+	LLVector3(-Q,0,1.f),
+	LLVector3(-Q,0,-1.f),
+	LLVector3(Q,0,-1.f),
+
+	LLVector3(1,-Q,0.f),
+	LLVector3(-1,-Q,0.f),
+	LLVector3(-1,Q,0.f),
+	LLVector3(1,Q,0.f),
+};
+
+//indices
+static const U32 icosahedron_ind[] = 
+{
+	5,0,1,
+	10,0,5,
+	5,1,9,
+	10,5,6,
+	6,5,9,
+	11,0,10,
+	3,11,10,
+	3,10,6,
+	3,6,2,
+	7,3,2,
+	8,7,2,
+	4,7,8,
+	1,4,8,
+	9,8,2,
+	9,2,6,
+	11,3,7,
+	4,0,11,
+	4,11,7,
+	1,0,4,
+	1,8,9,
+};
+
+
+//split every triangle in LLVertexBuffer into even fourths (assumes index triangle lists)
+void subdivide(LLVertexBuffer& in, LLVertexBuffer* ret)
+{
+	S32 tri_in = in.getNumIndices()/3;
+
+	ret->allocateBuffer(tri_in*4*3, tri_in*4*3, TRUE);
+
+	LLStrider<LLVector3> vin, vout;
+	LLStrider<U16> indin, indout;
+
+	ret->getVertexStrider(vout);
+	in.getVertexStrider(vin);
+
+	ret->getIndexStrider(indout);
+	in.getIndexStrider(indin);
+	
+	
+	for (S32 i = 0; i < tri_in; i++)
+	{
+		LLVector3 v0 = vin[*indin++];
+		LLVector3 v1 = vin[*indin++];
+		LLVector3 v2 = vin[*indin++];
+
+		LLVector3 v3 = (v0 + v1) * 0.5f;
+		LLVector3 v4 = (v1 + v2) * 0.5f;
+		LLVector3 v5 = (v2 + v0) * 0.5f;
+
+		*vout++ = v0;
+		*vout++ = v3;
+		*vout++ = v5;
+
+		*vout++ = v3;
+		*vout++ = v4;
+		*vout++ = v5;
+
+		*vout++ = v3;
+		*vout++ = v1;
+		*vout++ = v4;
+
+		*vout++ = v5;
+		*vout++ = v4;
+		*vout++ = v2;
+	}
+	
+	for (S32 i = 0; i < ret->getNumIndices(); i++)
+	{
+		*indout++ = i;
+	}
+
+}
+
+void chop(LLVertexBuffer& in, LLVertexBuffer* out)
+{
+	//chop off all triangles below horizon 
+	F32 d = LLWLParamManager::sParamMgr->getDomeOffset() * LLWLParamManager::sParamMgr->getDomeRadius();
+	
+	std::vector<LLVector3> vert;
+	
+	LLStrider<LLVector3> vin;
+	LLStrider<U16> index;
+
+	in.getVertexStrider(vin);
+	in.getIndexStrider(index);
+
+	U32 tri_count = in.getNumIndices()/3;
+	for (U32 i = 0; i < tri_count; i++)
+	{
+		LLVector3 &v1 = vin[index[i*3+0]];
+		LLVector3 &v2 = vin[index[i*3+1]];
+		LLVector3 &v3 = vin[index[i*3+2]];
+
+		if (v1.mV[1] > d ||
+			v2.mV[1] > d ||
+			v3.mV[1] > d)
+		{
+			v1.mV[1] = llmax(v1.mV[1], d);
+			v2.mV[1] = llmax(v1.mV[1], d);
+			v3.mV[1] = llmax(v1.mV[1], d);
+
+			vert.push_back(v1);
+			vert.push_back(v2);
+			vert.push_back(v3);
+		}
+	}
+
+	out->allocateBuffer(vert.size(), vert.size(), TRUE);
+
+	LLStrider<LLVector3> vout;
+	out->getVertexStrider(vout);
+	out->getIndexStrider(index);
+
+	for (U32 i = 0; i < vert.size(); i++)
+	{
+		*vout++ = vert[i];
+		*index++ = i;
+	}	
+}
+#endif // !DOME_SLICES
+
+void LLVOWLSky::resetVertexBuffers()
+{
+	mFanVerts = NULL;
+	mStripsVerts.clear();
+	mStarsVerts = NULL;
+
+	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+}
+	
+void LLVOWLSky::cleanupGL()
+{
+	mFanVerts = NULL;
+	mStripsVerts.clear();
+	mStarsVerts = NULL;
+
+	LLDrawPoolWLSky::cleanupGL();
+}
+
+void LLVOWLSky::restoreGL()
+{
+	LLDrawPoolWLSky::restoreGL();
+	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+}
+
+BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
+{
+	LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY);
+	LLStrider<LLVector3>	vertices;
+	LLStrider<LLVector2>	texCoords;
+	LLStrider<U16>			indices;
+
+#if DOME_SLICES
+	{
+		mFanVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
+		mFanVerts->allocateBuffer(getFanNumVerts(), getFanNumIndices(), TRUE);
+
+		BOOL success = mFanVerts->getVertexStrider(vertices)
+			&& mFanVerts->getTexCoordStrider(texCoords)
+			&& mFanVerts->getIndexStrider(indices);
+
+		if(!success) 
+		{
+			llerrs << "Failed updating WindLight sky geometry." << llendl;
+		}
+
+		buildFanBuffer(vertices, texCoords, indices);
+
+		mFanVerts->setBuffer(0);
+	}
+
+	{
+		const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
+		const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
+		const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcStride(data_mask);
+
+		const U32 total_stacks = getNumStacks();
+
+		const U32 verts_per_stack = getNumSlices();
+
+		// each seg has to have one more row of verts than it has stacks
+		// then round down
+		const U32 stacks_per_seg = (max_verts - verts_per_stack) / verts_per_stack;
+
+		// round up to a whole number of segments
+		const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg;
+
+		llinfos << "WL Skydome strips in " << strips_segments << " batches." << llendl;
+
+		mStripsVerts.resize(strips_segments, NULL);
+
+		for (U32 i = 0; i < strips_segments ;++i)
+		{
+			LLVertexBuffer * segment = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
+			mStripsVerts[i] = segment;
+
+			U32 num_stacks_this_seg = stacks_per_seg;
+			if ((i == strips_segments - 1) && (total_stacks % stacks_per_seg) != 0)
+			{
+				// for the last buffer only allocate what we'll use
+				num_stacks_this_seg = total_stacks % stacks_per_seg;
+			}
+
+			// figure out what range of the sky we're filling
+			const U32 begin_stack = i * stacks_per_seg;
+			const U32 end_stack = begin_stack + num_stacks_this_seg;
+			llassert(end_stack <= total_stacks);
+
+			const U32 num_verts_this_seg = verts_per_stack * (num_stacks_this_seg+1);
+			llassert(num_verts_this_seg <= max_verts);
+
+			const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack);
+			llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes);
+
+			segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE);
+
+			// lock the buffer
+			BOOL success = segment->getVertexStrider(vertices)
+				&& segment->getTexCoordStrider(texCoords)
+				&& segment->getIndexStrider(indices);
+
+			if(!success) 
+			{
+				llerrs << "Failed updating WindLight sky geometry." << llendl;
+			}
+
+			// fill it
+			buildStripsBuffer(begin_stack, end_stack,  vertices, texCoords, indices);
+
+			// and unlock the buffer
+			segment->setBuffer(0);
+		}
+	}
+#else
+	mStripsVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
+	
+	const F32 RADIUS = LLWLParamManager::sParamMgr->getDomeRadius();
+
+	LLPointer<LLVertexBuffer> temp = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
+	temp->allocateBuffer(12, 60, TRUE);
+
+	BOOL success = temp->getVertexStrider(vertices)
+		&& temp->getIndexStrider(indices);
+
+	if (success)
+	{
+		for (U32 i = 0; i < 12; i++)
+		{
+			*vertices++ = icosahedron_vert[i];
+		}
+
+		for (U32 i = 0; i < 60; i++)
+		{
+			*indices++ = icosahedron_ind[i];
+		}
+	}
+
+
+	LLPointer<LLVertexBuffer> temp2;
+	
+	for (U32 i = 0; i < 8; i++)
+	{
+		temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
+		subdivide(*temp, temp2);
+		temp = temp2;
+	}
+	
+	temp->getVertexStrider(vertices);
+	for (S32 i = 0; i < temp->getNumVerts(); i++)
+	{
+		LLVector3 v = vertices[i];
+		v.normVec();
+		vertices[i] = v*RADIUS;
+	}
+
+	temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
+	chop(*temp, temp2);
+
+	mStripsVerts->allocateBuffer(temp2->getNumVerts(), temp2->getNumIndices(), TRUE);
+	
+	success = mStripsVerts->getVertexStrider(vertices)
+		&& mStripsVerts->getTexCoordStrider(texCoords)
+		&& mStripsVerts->getIndexStrider(indices);
+
+	LLStrider<LLVector3> v;
+	temp2->getVertexStrider(v);
+	LLStrider<U16> ind;
+	temp2->getIndexStrider(ind);
+
+	if (success)
+	{
+		for (S32 i = 0; i < temp2->getNumVerts(); ++i)
+		{
+			LLVector3 vert = *v++;
+			vert.normVec();
+			F32 z0 = vert.mV[2];
+			F32 x0 = vert.mV[0];
+			
+			vert *= RADIUS;
+			
+			*vertices++ = vert;
+			*texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f);
+		}
+
+		for (S32 i = 0; i < temp2->getNumIndices(); ++i)
+		{
+			*indices++ = *ind++;
+		}
+	}
+
+	mStripsVerts->setBuffer(0);
+#endif
+
+	updateStarColors();
+	updateStarGeometry(drawable);
+
+	LLPipeline::sCompiles++;
+
+	return TRUE;
+}
+
+void LLVOWLSky::drawStars(void)
+{
+	glEnableClientState(GL_COLOR_ARRAY);
+	
+	//  render the stars as a sphere centered at viewer camera 
+	if (mStarsVerts.notNull())
+	{
+		mStarsVerts->setBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK);
+		U16* indicesp = (U16*) mStarsVerts->getIndicesPointer();
+		glDrawElements(GL_POINTS, getStarsNumIndices(), GL_UNSIGNED_SHORT, indicesp);
+	}
+
+	glDisableClientState(GL_COLOR_ARRAY);
+}
+
+void LLVOWLSky::drawDome(void)
+{
+	if (mStripsVerts.empty())
+	{
+		updateGeometry(mDrawable);
+	}
+
+	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+
+	const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
+
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+#if DOME_SLICES
+	//mFanVerts->setBuffer(data_mask);
+	//glDrawRangeElements(
+	//	GL_TRIANGLES,
+	//	0, getFanNumVerts()-1, getFanNumIndices(),
+	//	GL_UNSIGNED_SHORT,
+	//	mFanVerts->getIndicesPointer());
+
+	//gPipeline.addTrianglesDrawn(getFanNumIndices()/3);
+
+	std::vector< LLPointer<LLVertexBuffer> >::const_iterator strips_vbo_iter, end_strips;
+	end_strips = mStripsVerts.end();
+	for(strips_vbo_iter = mStripsVerts.begin(); strips_vbo_iter != end_strips; ++strips_vbo_iter)
+	{
+		LLVertexBuffer * strips_segment = strips_vbo_iter->get();
+
+		strips_segment->setBuffer(data_mask);
+
+		glDrawRangeElements(
+			//GL_TRIANGLES,
+			GL_TRIANGLE_STRIP,
+			0, strips_segment->getRequestedVerts()-1, strips_segment->getRequestedIndices(),
+			GL_UNSIGNED_SHORT,
+			strips_segment->getIndicesPointer());
+		
+		gPipeline.addTrianglesDrawn(strips_segment->getRequestedIndices() - 2);
+	}
+
+#else
+	mStripsVerts->setBuffer(data_mask);
+	glDrawRangeElements(
+		GL_TRIANGLES,
+		0, mStripsVerts->getNumVerts()-1, mStripsVerts->getNumIndices(),
+		GL_UNSIGNED_SHORT,
+		mStripsVerts->getIndicesPointer());
+#endif
+
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	LLVertexBuffer::unbind();
+}
+
+void LLVOWLSky::initStars()
+{
+	// Initialize star map
+	mStarVertices.resize(getStarsNumVerts());
+	mStarColors.resize(getStarsNumVerts());
+	mStarIntensities.resize(getStarsNumVerts());
+
+	std::vector<LLVector3>::iterator v_p = mStarVertices.begin();
+	std::vector<LLColor4>::iterator v_c = mStarColors.begin();
+	std::vector<F32>::iterator v_i = mStarIntensities.begin();
+
+	U32 i;
+	for (i = 0; i < getStarsNumVerts(); ++i)
+	{
+		v_p->mV[VX] = ll_frand() - 0.5f;
+		v_p->mV[VY] = ll_frand() - 0.5f;
+		
+		// we only want stars on the top half of the dome!
+
+		v_p->mV[VZ] = ll_frand()/2.f;
+
+		v_p->normVec();
+		*v_p *= DISTANCE_TO_STARS;
+		*v_i = llmin((F32)pow(ll_frand(),2.f) + 0.1f, 1.f);
+		v_c->mV[VRED]   = 0.75f + ll_frand() * 0.25f ;
+		v_c->mV[VGREEN] = 1.f ;
+		v_c->mV[VBLUE]  = 0.75f + ll_frand() * 0.25f ;
+		v_c->mV[VALPHA] = 1.f;
+		v_c->clamp();
+		v_p++;
+		v_c++;
+		v_i++;
+	}
+}
+
+void LLVOWLSky::buildFanBuffer(LLStrider<LLVector3> & vertices,
+							   LLStrider<LLVector2> & texCoords,
+							   LLStrider<U16> & indices)
+{
+	const F32 RADIUS = LLWLParamManager::instance()->getDomeRadius();
+
+	U32 i, num_slices;
+	F32 phi0, theta, x0, y0, z0;
+
+	// paranoia checking for SL-55986/SL-55833
+	U32 count_verts = 0;
+	U32 count_indices = 0;
+
+	// apex
+	*vertices++		= LLVector3(0.f, RADIUS, 0.f);
+	*texCoords++	= LLVector2(0.5f, 0.5f);
+	++count_verts;
+
+	num_slices = getNumSlices();
+
+	// and fan in a circle around the apex
+	phi0 = calcPhi(1);
+	for(i = 0; i < num_slices; ++i) {
+		theta = 2.f * F_PI * float(i) / float(num_slices);
+
+		// standard transformation from  spherical to
+		// rectangular coordinates
+		x0 = sin(phi0) * cos(theta);
+		y0 = cos(phi0);
+		z0 = sin(phi0) * sin(theta);
+
+		*vertices++		= LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+		// generate planar uv coordinates
+		// note: x and z are transposed in order for things to animate
+		// correctly in the global coordinate system where +x is east and
+		// +y is north
+		*texCoords++	= LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f);
+		++count_verts;
+
+		if (i > 0)
+		{
+			*indices++ = 0;
+			*indices++ = i;
+			*indices++ = i+1;
+			count_indices += 3;
+		}
+	}
+
+	// the last vertex of the last triangle should wrap around to 
+	// the beginning
+	*indices++ = 0;
+	*indices++ = num_slices;
+	*indices++ = 1;
+	count_indices += 3;
+
+	// paranoia checking for SL-55986/SL-55833
+	llassert(getFanNumVerts() == count_verts);
+	llassert(getFanNumIndices() == count_indices);
+}
+
+void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack,
+								  LLStrider<LLVector3> & vertices,
+								  LLStrider<LLVector2> & texCoords,
+								  LLStrider<U16> & indices)
+{
+	const F32 RADIUS = LLWLParamManager::instance()->getDomeRadius();
+
+	U32 i, j, num_slices, num_stacks;
+	F32 phi0, theta, x0, y0, z0;
+
+	// paranoia checking for SL-55986/SL-55833
+	U32 count_verts = 0;
+	U32 count_indices = 0;
+
+	num_slices = getNumSlices();
+	num_stacks = getNumStacks();
+
+	llassert(end_stack <= num_stacks);
+
+	// stacks are iterated one-indexed since phi(0) was handled by the fan above
+	for(i = begin_stack + 1; i <= end_stack+1; ++i) 
+	{
+		phi0 = calcPhi(i);
+
+		for(j = 0; j < num_slices; ++j)
+		{
+			theta = F_TWO_PI * (float(j) / float(num_slices));
+
+			// standard transformation from  spherical to
+			// rectangular coordinates
+			x0 = sin(phi0) * cos(theta);
+			y0 = cos(phi0);
+			z0 = sin(phi0) * sin(theta);
+
+			if (i == num_stacks-2)
+			{
+				*vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS);
+			}
+			else if (i == num_stacks-1)
+			{
+				*vertices++ = LLVector3(0, y0*RADIUS-1024.f*2.f, 0);
+			}
+			else
+			{
+				*vertices++		= LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS);
+			}
+			++count_verts;
+
+			// generate planar uv coordinates
+			// note: x and z are transposed in order for things to animate
+			// correctly in the global coordinate system where +x is east and
+			// +y is north
+			*texCoords++	= LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f);
+		}
+	}
+
+	//build triangle strip...
+	*indices++ = 0 ;
+	count_indices++ ;
+	S32 k = 0 ;
+	for(i = 1; i <= end_stack - begin_stack; ++i) 
+	{
+		*indices++ = i * num_slices + k ;
+		count_indices++ ;
+
+		k = (k+1) % num_slices ;
+		for(j = 0; j < num_slices ; ++j) 
+		{
+			*indices++ = (i-1) * num_slices + k ;
+			*indices++ = i * num_slices + k ;
+
+			count_indices += 2 ;
+
+			k = (k+1) % num_slices ;
+		}
+
+		if((--k) < 0)
+		{
+			k = num_slices - 1 ;
+		}
+
+		*indices++ = i * num_slices + k ;
+		count_indices++ ;
+	}
+}
+
+void LLVOWLSky::updateStarColors()
+{
+	std::vector<LLColor4>::iterator v_c = mStarColors.begin();
+	std::vector<F32>::iterator v_i = mStarIntensities.begin();
+	std::vector<LLVector3>::iterator v_p = mStarVertices.begin();
+
+	const F32 var = 0.15f;
+	const F32 min = 0.5f; //0.75f;
+	const F32 sunclose_max = 0.6f;
+	const F32 sunclose_range = 1 - sunclose_max;
+
+	//F32 below_horizon = - llmin(0.0f, gSky.mVOSkyp->getToSunLast().mV[2]);
+	//F32 brightness_factor = llmin(1.0f, below_horizon * 20);
+
+	static S32 swap = 0;
+	swap++;
+
+	if ((swap % 2) == 1)
+	{
+		F32 intensity;						//  max intensity of each star
+		U32 x;
+		for (x = 0; x < getStarsNumVerts(); ++x)
+		{
+			F32 sundir_factor = 1;
+			LLVector3 tostar = *v_p;
+			tostar.normVec();
+			const F32 how_close_to_sun = tostar * gSky.mVOSkyp->getToSunLast();
+			if (how_close_to_sun > sunclose_max)
+			{
+				sundir_factor = (1 - how_close_to_sun) / sunclose_range;
+			}
+			intensity = *(v_i);
+			F32 alpha = v_c->mV[VALPHA] + (ll_frand() - 0.5f) * var * intensity;
+			if (alpha < min * intensity)
+			{
+				alpha = min * intensity;
+			}
+			if (alpha > intensity)
+			{
+				alpha = intensity;
+			}
+			//alpha *= brightness_factor * sundir_factor;
+
+			alpha = llclamp(alpha, 0.f, 1.f);
+			v_c->mV[VALPHA] = alpha;
+			v_c++;
+			v_i++;
+			v_p++;
+		}
+	}
+}
+
+BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable)
+{
+	LLStrider<LLVector3> verticesp;
+	LLStrider<LLColor4U> colorsp;
+	LLStrider<U16> indicesp;
+
+	if (mStarsVerts.isNull())
+	{
+		mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK, GL_DYNAMIC_DRAW);
+		mStarsVerts->allocateBuffer(getStarsNumVerts(), getStarsNumIndices(), TRUE);
+	}
+
+	BOOL success = mStarsVerts->getVertexStrider(verticesp)
+		&& mStarsVerts->getIndexStrider(indicesp)
+		&& mStarsVerts->getColorStrider(colorsp);
+
+	if(!success)
+	{
+		llerrs << "Failed updating star geometry." << llendl;
+	}
+
+	// *TODO: fix LLStrider with a real prefix increment operator so it can be
+	// used as a model of OutputIterator. -Brad
+	// std::copy(mStarVertices.begin(), mStarVertices.end(), verticesp);
+	for (U32 vtx = 0; vtx < getStarsNumVerts(); ++vtx)
+	{
+		*(verticesp++)  = mStarVertices[vtx];
+		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
+		*(indicesp++)   = vtx;
+	}
+
+	mStarsVerts->setBuffer(0);
+	return TRUE;
+}
diff --git a/indra/newview/llvowlsky.h b/indra/newview/llvowlsky.h
new file mode 100644
index 00000000000..dcb4b851a25
--- /dev/null
+++ b/indra/newview/llvowlsky.h
@@ -0,0 +1,110 @@
+/** 
+ * @file llvowlsky.h
+ * @brief LLVOWLSky class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_VOWLSKY_H
+#define LL_VOWLSKY_H
+
+#include "llviewerobject.h"
+
+class LLVOWLSky : public LLStaticViewerObject {
+private:
+	static const F32 DISTANCE_TO_STARS;
+
+	// anything less than 3 makes it impossible to create a closed dome.
+	static const U32 MIN_SKY_DETAIL;
+	// anything bigger than about 180 will cause getStripsNumVerts() to exceed 65535.
+	static const U32 MAX_SKY_DETAIL;
+
+	inline static U32 getNumStacks(void);
+	inline static U32 getNumSlices(void);
+	inline static U32 getFanNumVerts(void);
+	inline static U32 getFanNumIndices(void);
+	inline static U32 getStripsNumVerts(void);
+	inline static U32 getStripsNumIndices(void);
+	inline static U32 getStarsNumVerts(void);
+	inline static U32 getStarsNumIndices(void);
+
+public:
+	LLVOWLSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+
+	void initSunDirection(LLVector3 const & sun_direction,
+		LLVector3 const & sun_angular_velocity);
+
+	/*virtual*/ BOOL		 idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+	/*virtual*/ BOOL		 isActive(void) const;
+	/*virtual*/ LLDrawable * createDrawable(LLPipeline *pipeline);
+	/*virtual*/ BOOL		 updateGeometry(LLDrawable *drawable);
+
+	void drawStars(void);
+	void drawDome(void);
+	void resetVertexBuffers(void);
+	
+	void cleanupGL();
+	void restoreGL();
+
+private:
+	// a tiny helper function for controlling the sky dome tesselation.
+	static F32 calcPhi(U32 i);
+
+	// helper function for initializing the stars.
+	void initStars();
+
+	// helper function for building the fan vertex buffer.
+	static void buildFanBuffer(LLStrider<LLVector3> & vertices,
+							   LLStrider<LLVector2> & texCoords,
+							   LLStrider<U16> & indices);
+
+	// helper function for building the strips vertex buffer.
+	// note begin_stack and end_stack follow stl iterator conventions,
+	// begin_stack is the first stack to be included, end_stack is the first
+	// stack not to be included.
+	static void buildStripsBuffer(U32 begin_stack, U32 end_stack,
+								  LLStrider<LLVector3> & vertices,
+								  LLStrider<LLVector2> & texCoords,
+								  LLStrider<U16> & indices);
+
+	// helper function for updating the stars colors.
+	void updateStarColors();
+
+	// helper function for updating the stars geometry.
+	BOOL updateStarGeometry(LLDrawable *drawable);
+
+private:
+	LLPointer<LLVertexBuffer>					mFanVerts;
+	std::vector< LLPointer<LLVertexBuffer> >	mStripsVerts;
+	LLPointer<LLVertexBuffer>					mStarsVerts;
+
+	std::vector<LLVector3>	mStarVertices;				// Star verticies
+	std::vector<LLColor4>	mStarColors;				// Star colors
+	std::vector<F32>		mStarIntensities;			// Star intensities
+};
+
+#endif // LL_VOWLSKY_H
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
new file mode 100644
index 00000000000..d81cbf832fe
--- /dev/null
+++ b/indra/newview/llwaterparammanager.cpp
@@ -0,0 +1,433 @@
+/**
+ * @file llwaterparammanager.cpp
+ * @brief Implementation for the LLWaterParamManager class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwaterparammanager.h"
+
+#include "pipeline.h"
+#include "llsky.h"
+
+#include "llsliderctrl.h"
+#include "llspinctrl.h"
+#include "llcheckboxctrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewercontrol.h"
+#include "llviewercamera.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llsdserialize.h"
+
+#include "v4math.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "lldrawpoolwater.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+
+#include "llwlparammanager.h"
+#include "llwaterparamset.h"
+#include "llpostprocess.h"
+#include "llfloaterwater.h"
+
+#include "curl/curl.h"
+
+LLWaterParamManager * LLWaterParamManager::sInstance = NULL;
+
+LLWaterParamManager::LLWaterParamManager() :
+	mFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f, 0.0f, "waterFogColor", "WaterFogColor"),
+	mFogDensity(4, "waterFogDensity", 2),
+	mUnderWaterFogMod(0.25, "underWaterFogMod"),
+	mNormalScale(2.f, 2.f, 2.f, "normScale"),
+	mFresnelScale(0.5f, "fresnelScale"),
+	mFresnelOffset(0.4f, "fresnelOffset"),
+	mScaleAbove(0.025f, "scaleAbove"),
+	mScaleBelow(0.2f, "scaleBelow"),
+	mBlurMultiplier(0.1f, "blurMultiplier"),
+	mWave1Dir(.5f, .5f, "wave1Dir"),
+	mWave2Dir(.5f, .5f, "wave2Dir"),
+	mDensitySliderValue(1.0f)
+{
+}
+
+LLWaterParamManager::~LLWaterParamManager()
+{
+}
+
+void LLWaterParamManager::loadAllPresets(const LLString& file_name)
+{
+	LLString path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));
+	llinfos << "Loading water settings from " << path_name << llendl;
+
+	//mParamList.clear();
+	
+	bool found = true;			
+	while(found) 
+	{
+		std::string name;
+		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false);
+
+		llinfos << "name: " << name << llendl;
+		
+		// if we have one
+		if(found) 
+		{
+			// bugfix for SL-46920: preventing filenames that break stuff.
+			char * curl_str = curl_unescape(name.c_str(), name.size());
+			std::string unescaped_name(curl_str);
+			curl_free(curl_str);
+			curl_str = NULL;
+
+			// not much error checking here since we're getting rid of this
+			std::string water_name = unescaped_name.substr(0, unescaped_name.size() - 4);
+		
+			LLString cur_path(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", name));
+			llinfos << "Loading water from " << cur_path << llendl;
+			
+			std::ifstream water_xml(cur_path.c_str());
+			if (water_xml)
+			{
+				LLSD water_data(LLSD::emptyMap());
+				LLPointer<LLSDParser> parser = new LLSDXMLParser();
+				parser->parse(water_xml, water_data, LLSDSerialize::SIZE_UNLIMITED);
+
+				addParamSet(water_name, water_data);
+			}
+		}
+	}
+}
+
+void LLWaterParamManager::loadPreset(const LLString & name)
+{
+	// bugfix for SL-46920: preventing filenames that break stuff.
+	char * curl_str = curl_escape(name.c_str(), name.size());
+	std::string escaped_filename(curl_str);
+	curl_free(curl_str);
+	curl_str = NULL;
+
+	escaped_filename += ".xml";
+
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", escaped_filename));
+	llinfos << "Loading water settings from " << pathName << llendl;
+
+	std::ifstream presetsXML(pathName.c_str());
+
+	if (presetsXML)
+	{
+		LLSD paramsData(LLSD::emptyMap());
+
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+
+		parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED);
+
+		std::map<std::string, LLWaterParamSet>::iterator mIt = mParamList.find(name);
+		if(mIt == mParamList.end())
+		{
+			addParamSet(name, paramsData);
+		}
+		else 
+		{
+			setParamSet(name, paramsData);
+		}
+	} 
+	else 
+	{
+		llwarns << "Can't find " << name << llendl;
+		return;
+	}
+
+	getParamSet(name, mCurParams);
+
+	propagateParameters();
+}
+
+void LLWaterParamManager::savePreset(const LLString & name)
+{
+	// bugfix for SL-46920: preventing filenames that break stuff.
+	char * curl_str = curl_escape(name.c_str(), name.size());
+	std::string escaped_filename(curl_str);
+	curl_free(curl_str);
+	curl_str = NULL;
+
+	escaped_filename += ".xml";
+
+	// make an empty llsd
+	LLSD paramsData(LLSD::emptyMap());
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", escaped_filename));
+
+	// fill it with LLSD windlight params
+	paramsData = mParamList[name].getAll();
+
+	// write to file
+	std::ofstream presetsXML(pathName.c_str());
+	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+	formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY);
+	presetsXML.close();
+
+	propagateParameters();
+}
+
+
+void LLWaterParamManager::propagateParameters(void)
+{
+	// bind the variables only if we're using shaders
+	if(gPipeline.canUseVertexShaders())
+	{
+		LLShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLShaderMgr::endShaders();
+		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		{
+			if (shaders_iter->mProgramObject != 0
+				&& shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)
+			{
+				shaders_iter->mUniformsDirty = TRUE;
+			}
+		}
+	}
+
+	bool err;
+	F32 fog_density_slider = 
+		log(mCurParams.getFloat(mFogDensity.mName, err)) / 
+		log(mFogDensity.mBase);
+
+	setDensitySliderValue(fog_density_slider);
+}
+
+void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader)
+{
+	if (shader->mShaderGroup == LLGLSLShader::SG_WATER)
+	{
+		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, LLWLParamManager::instance()->getRotatedLightDir().mV);
+		shader->uniform3fv("camPosLocal", 1, gCamera->getOrigin().mV);
+		shader->uniform4fv("waterFogColor", 1, LLDrawPoolWater::sWaterFogColor.mV);
+		shader->uniform4fv("waterPlane", 1, mWaterPlane.mV);
+		shader->uniform1f("waterFogDensity", getFogDensity());
+		shader->uniform1f("waterFogKS", mWaterFogKS);
+		shader->uniform4f("distance_multiplier", 0, 0, 0, 0);
+	}
+}
+
+void LLWaterParamManager::update(LLViewerCamera * cam)
+{
+	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
+	
+	// update the shaders and the menu
+	propagateParameters();
+	
+	// sync menus if they exist
+	if(LLFloaterWater::isOpen()) 
+	{
+		LLFloaterWater::instance()->syncMenu();
+	}
+
+	stop_glerror();
+
+	// only do this if we're dealing with shaders
+	if(gPipeline.canUseVertexShaders()) 
+	{
+		//transform water plane to eye space
+		glh::vec3f norm(0, 0, 1);
+		glh::vec3f p(0, 0, gAgent.getRegion()->getWaterHeight()+0.1f);
+		
+		F32 modelView[16];
+		for (U32 i = 0; i < 16; i++)
+		{
+			modelView[i] = (F32) gGLModelView[i];
+		}
+
+		glh::matrix4f mat(modelView);
+		glh::matrix4f invtrans = mat.inverse().transpose();
+		glh::vec3f enorm;
+		glh::vec3f ep;
+		invtrans.mult_matrix_vec(norm, enorm);
+		enorm.normalize();
+		mat.mult_matrix_vec(p, ep);
+
+		mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
+
+		LLVector3 sunMoonDir;
+		if (gSky.getSunDirection().mV[2] > NIGHTTIME_ELEVATION_COS) 	 
+		{ 	 
+			sunMoonDir = gSky.getSunDirection(); 	 
+		} 	 
+		else  	 
+		{ 	 
+			sunMoonDir = gSky.getMoonDirection(); 	 
+		}
+		sunMoonDir.normVec();
+		mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP);
+
+		LLShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLShaderMgr::endShaders();
+		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		{
+			if (shaders_iter->mProgramObject != 0
+				&& shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)
+			{
+				shaders_iter->mUniformsDirty = TRUE;
+			}
+		}
+	}
+}
+
+// static
+void LLWaterParamManager::initClass(void)
+{
+	instance();
+}
+
+// static
+void LLWaterParamManager::cleanupClass(void)
+{
+	delete sInstance;
+	sInstance = NULL;
+}
+
+bool LLWaterParamManager::addParamSet(const std::string& name, LLWaterParamSet& param)
+{
+	// add a new one if not one there already
+	std::map<std::string, LLWaterParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt == mParamList.end()) 
+	{	
+		mParamList[name] = param;
+		return true;
+	}
+
+	return false;
+}
+
+BOOL LLWaterParamManager::addParamSet(const std::string& name, LLSD const & param)
+{
+	// add a new one if not one there already
+	std::map<std::string, LLWaterParamSet>::const_iterator finder = mParamList.find(name);
+	if(finder == mParamList.end())
+	{
+		mParamList[name].setAll(param);
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+bool LLWaterParamManager::getParamSet(const std::string& name, LLWaterParamSet& param)
+{
+	// find it and set it
+	std::map<std::string, LLWaterParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt != mParamList.end()) 
+	{
+		param = mParamList[name];
+		param.mName = name;
+		return true;
+	}
+
+	return false;
+}
+
+bool LLWaterParamManager::setParamSet(const std::string& name, LLWaterParamSet& param)
+{
+	mParamList[name] = param;
+
+	return true;
+}
+
+bool LLWaterParamManager::setParamSet(const std::string& name, const LLSD & param)
+{
+	// quick, non robust (we won't be working with files, but assets) check
+	if(!param.isMap()) 
+	{
+		return false;
+	}
+	
+	mParamList[name].setAll(param);
+
+	return true;
+}
+
+bool LLWaterParamManager::removeParamSet(const std::string& name, bool delete_from_disk)
+{
+	// remove from param list
+	std::map<std::string, LLWaterParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt != mParamList.end()) 
+	{
+		mParamList.erase(mIt);
+	}
+
+	if(delete_from_disk)
+	{
+		LLString path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));
+		
+		// use full curl escaped name
+		char * curl_str = curl_escape(name.c_str(), name.size());
+		std::string escaped_name(curl_str);
+		curl_free(curl_str);
+		curl_str = NULL;
+		
+		gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml");
+	}
+
+	return true;
+}
+
+F32 LLWaterParamManager::getFogDensity(void)
+{
+	bool err;
+
+	F32 fogDensity = mCurParams.getFloat("waterFogDensity", err);
+	
+	// modify if we're underwater
+	const F32 water_height = gAgent.getRegion()->getWaterHeight();
+	F32 camera_height = gAgent.getCameraPositionAgent().mV[2];
+	if(camera_height <= water_height)
+	{
+		// raise it to the underwater fog density modifier
+		fogDensity = pow(fogDensity, mCurParams.getFloat("underWaterFogMod", err));
+	}
+
+	return fogDensity;
+}
+
+// static
+LLWaterParamManager * LLWaterParamManager::instance()
+{
+	if(NULL == sInstance)
+	{
+		sInstance = new LLWaterParamManager();
+
+		sInstance->loadAllPresets("");
+
+		sInstance->getParamSet("Default", sInstance->mCurParams);
+	}
+
+	return sInstance;
+}
diff --git a/indra/newview/llwaterparammanager.h b/indra/newview/llwaterparammanager.h
new file mode 100644
index 00000000000..6892bb19240
--- /dev/null
+++ b/indra/newview/llwaterparammanager.h
@@ -0,0 +1,401 @@
+/**
+ * @file llwaterparammanager.h
+ * @brief Implementation for the LLWaterParamManager class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WATER_PARAMMANAGER_H
+#define LL_WATER_PARAMMANAGER_H
+
+#include <vector>
+#include <map>
+#include "llwaterparamset.h"
+#include "llviewercamera.h"
+#include "v4color.h"
+
+const F32 WATER_FOG_LIGHT_CLAMP = 0.3f;
+
+// color control
+struct WaterColorControl {
+	
+	F32 mR, mG, mB, mA, mI;			/// the values
+	char const * mName;				/// name to use to dereference params
+	std::string mSliderName;		/// name of the slider in menu
+	bool mHasSliderName;			/// only set slider name for true color types
+
+	inline WaterColorControl(F32 red, F32 green, F32 blue, F32 alpha,
+		F32 intensity, char const * n, char const * sliderName = "")
+		: mR(red), mG(green), mB(blue), mA(alpha), mI(intensity), mName(n), mSliderName(sliderName)
+	{
+		// if there's a slider name, say we have one
+		mHasSliderName = false;
+		if (mSliderName != "") {
+			mHasSliderName = true;
+		}
+	}
+
+	inline WaterColorControl & operator = (LLColor4 const & val) 
+	{
+		mR = val.mV[0];
+		mG = val.mV[1];
+		mB = val.mV[2];
+		mA = val.mV[3];		
+		return *this;
+	}
+
+	inline operator LLColor4 (void) const
+	{
+		return LLColor4(mR, mG, mB, mA);
+	}
+
+	inline WaterColorControl & operator = (LLVector4 const & val) 
+	{
+		mR = val.mV[0];
+		mG = val.mV[1];
+		mB = val.mV[2];
+		mA = val.mV[3];		
+		return *this;
+	}
+
+	inline operator LLVector4 (void) const 
+	{
+		return LLVector4(mR, mG, mB, mA);
+	}
+
+	inline operator LLVector3 (void) const 
+	{
+		return LLVector3(mR, mG, mB);
+	}
+
+	inline void update(LLWaterParamSet & params) const 
+	{
+		params.set(mName, mR, mG, mB, mA);
+	}
+};
+
+struct WaterVector3Control 
+{
+	F32 mX;
+	F32 mY;
+	F32 mZ;
+
+	char const * mName;
+
+	// basic constructor
+	inline WaterVector3Control(F32 valX, F32 valY, F32 valZ, char const * n)
+		: mX(valX), mY(valY), mZ(valZ), mName(n)
+	{
+	}
+
+	inline WaterVector3Control & operator = (LLVector3 const & val) 
+	{
+		mX = val.mV[0];
+		mY = val.mV[1];
+		mZ = val.mV[2];
+
+		return *this;
+	}
+
+	inline void update(LLWaterParamSet & params) const 
+	{
+		params.set(mName, mX, mY, mZ);
+	}
+
+};
+
+struct WaterVector2Control 
+{
+	F32 mX;
+	F32 mY;
+
+	char const * mName;
+
+	// basic constructor
+	inline WaterVector2Control(F32 valX, F32 valY, char const * n)
+		: mX(valX), mY(valY), mName(n)
+	{
+	}
+
+	inline WaterVector2Control & operator = (LLVector2 const & val) 
+	{
+		mX = val.mV[0];
+		mY = val.mV[1];
+
+		return *this;
+	}
+
+	inline void update(LLWaterParamSet & params) const 
+	{
+		params.set(mName, mX, mY);
+	}
+};
+
+// float slider control
+struct WaterFloatControl 
+{
+	F32 mX;
+	char const * mName;
+	F32 mMult;
+
+	inline WaterFloatControl(F32 val, char const * n, F32 m=1.0f)
+		: mX(val), mName(n), mMult(m)
+	{
+	}
+
+	inline WaterFloatControl & operator = (LLVector4 const & val) 
+	{
+		mX = val.mV[0];
+
+		return *this;
+	}
+
+	inline operator F32 (void) const 
+	{
+		return mX;
+	}
+
+	inline void update(LLWaterParamSet & params) const 
+	{
+		params.set(mName, mX);
+	}
+};
+
+// float slider control
+struct WaterExpFloatControl 
+{
+	F32 mExp;
+	char const * mName;
+	F32 mBase;
+
+	inline WaterExpFloatControl(F32 val, char const * n, F32 b)
+		: mExp(val), mName(n), mBase(b)
+	{
+	}
+
+	inline WaterExpFloatControl & operator = (F32 val) 
+	{
+		mExp = log(val) / log(mBase);
+
+		return *this;
+	}
+
+	inline operator F32 (void) const 
+	{
+		return pow(mBase, mExp);
+	}
+
+	inline void update(LLWaterParamSet & params) const 
+	{
+		params.set(mName, pow(mBase, mExp));
+	}
+};
+
+
+/// WindLight parameter manager class - what controls all the wind light shaders
+class LLWaterParamManager
+{
+public:
+
+	LLWaterParamManager();
+	~LLWaterParamManager();
+
+	/// load a preset file
+	void loadAllPresets(const LLString & fileName);
+
+	/// load an individual preset into the sky
+	void loadPreset(const LLString & name);
+
+	/// save the parameter presets to file
+	void savePreset(const LLString & name);
+
+	/// send the parameters to the shaders
+	void propagateParameters(void);
+
+	/// update information for the shader
+	void update(LLViewerCamera * cam);
+
+	/// Update shader uniforms that have changed.
+	void updateShaderUniforms(LLGLSLShader * shader);
+
+	/// Perform global initialization for this class.
+	static void initClass(void);
+
+	// Cleanup of global data that's only inited once per class.
+	static void cleanupClass();
+
+	/// add a param to the list
+	bool addParamSet(const std::string& name, LLWaterParamSet& param);
+
+	/// add a param to the list
+	BOOL addParamSet(const std::string& name, LLSD const & param);
+
+	/// get a param from the list
+	bool getParamSet(const std::string& name, LLWaterParamSet& param);
+
+	/// set the param in the list with a new param
+	bool setParamSet(const std::string& name, LLWaterParamSet& param);
+	
+	/// set the param in the list with a new param
+	bool setParamSet(const std::string& name, LLSD const & param);	
+
+	/// gets rid of a parameter and any references to it
+	/// returns true if successful
+	bool removeParamSet(const std::string& name, bool delete_from_disk);
+
+	/// set the normap map we want for water
+	bool setNormalMapID(const LLUUID& img);
+
+	void setDensitySliderValue(F32 val);
+
+	/// getters for all the different things water param manager maintains
+	LLUUID getNormalMapID(void);
+	LLVector2 getWave1Dir(void);
+	LLVector2 getWave2Dir(void);
+	F32 getScaleAbove(void);
+	F32 getScaleBelow(void);
+	LLVector3 getNormalScale(void);
+	F32 getFresnelScale(void);
+	F32 getFresnelOffset(void);
+	F32 getBlurMultiplier(void);
+	F32 getFogDensity(void);
+	LLColor4 getFogColor(void);
+
+	// singleton pattern implementation
+	static LLWaterParamManager * instance();
+
+public:
+
+	LLWaterParamSet mCurParams;
+
+	/// Atmospherics
+	WaterColorControl mFogColor;
+	WaterExpFloatControl mFogDensity;
+	WaterFloatControl mUnderWaterFogMod;
+
+	/// wavelet scales and directions
+	WaterVector3Control mNormalScale;
+	WaterVector2Control mWave1Dir;
+	WaterVector2Control mWave2Dir;
+
+	// controls how water is reflected and refracted
+	WaterFloatControl mFresnelScale;
+	WaterFloatControl mFresnelOffset;
+	WaterFloatControl mScaleAbove;
+	WaterFloatControl mScaleBelow;
+	WaterFloatControl mBlurMultiplier;
+	
+	// list of all the parameters, listed by name
+	std::map<std::string, LLWaterParamSet> mParamList;
+
+	F32 mDensitySliderValue;
+
+private:
+	// our parameter manager singleton instance
+	static LLWaterParamManager * sInstance;
+
+private:
+
+	LLVector4 mWaterPlane;
+	F32 mWaterFogKS;
+};
+
+inline void LLWaterParamManager::setDensitySliderValue(F32 val)
+{
+	val /= 10;
+	val = 1.0f - val;
+	val *= val * val;
+//	val *= val;
+	mDensitySliderValue = val;
+}
+
+inline LLUUID LLWaterParamManager::getNormalMapID()
+{	
+	return mCurParams.mParamValues["normalMap"].asUUID();
+}
+
+inline bool LLWaterParamManager::setNormalMapID(const LLUUID& id)
+{
+	mCurParams.mParamValues["normalMap"] = id;
+	return true;
+}
+
+inline LLVector2 LLWaterParamManager::getWave1Dir(void)
+{
+	bool err;
+	return mCurParams.getVector2("wave1Dir", err);
+}
+
+inline LLVector2 LLWaterParamManager::getWave2Dir(void)
+{
+	bool err;
+	return mCurParams.getVector2("wave2Dir", err);
+}
+
+inline F32 LLWaterParamManager::getScaleAbove(void)
+{
+	bool err;
+	return mCurParams.getFloat("scaleAbove", err);
+}
+
+inline F32 LLWaterParamManager::getScaleBelow(void)
+{
+	bool err;
+	return mCurParams.getFloat("scaleBelow", err);
+}
+
+inline LLVector3 LLWaterParamManager::getNormalScale(void)
+{
+	bool err;
+	return mCurParams.getVector3("normScale", err);
+}
+
+inline F32 LLWaterParamManager::getFresnelScale(void)
+{
+	bool err;
+	return mCurParams.getFloat("fresnelScale", err);
+}
+
+inline F32 LLWaterParamManager::getFresnelOffset(void)
+{
+	bool err;
+	return mCurParams.getFloat("fresnelOffset", err);
+}
+
+inline F32 LLWaterParamManager::getBlurMultiplier(void)
+{
+	bool err;
+	return mCurParams.getFloat("blurMultiplier", err);
+}
+
+inline LLColor4 LLWaterParamManager::getFogColor(void)
+{
+	bool err;
+	return LLColor4(mCurParams.getVector4("waterFogColor", err));
+}
+
+#endif
diff --git a/indra/newview/llwaterparamset.cpp b/indra/newview/llwaterparamset.cpp
new file mode 100644
index 00000000000..78baae8db62
--- /dev/null
+++ b/indra/newview/llwaterparamset.cpp
@@ -0,0 +1,233 @@
+/**
+ * @file llwaterparamset.cpp
+ * @brief Implementation for the LLWaterParamSet class.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwaterparamset.h"
+#include "llsd.h"
+
+#include "llfloaterwater.h"
+#include "llwaterparammanager.h"
+#include "lluictrlfactory.h"
+#include "llsliderctrl.h"
+#include "llviewerimagelist.h"
+#include "llviewercontrol.h"
+#include "lluuid.h"
+
+#include <llgl.h>
+
+#include <sstream>
+
+LLWaterParamSet::LLWaterParamSet(void) :
+	mName("Unnamed Preset")
+{
+	LLSD vec4;
+	LLSD vec3;
+	LLSD real(0.0f);
+
+	vec4 = LLSD::emptyArray();
+	vec4.append(22.f/255.f);
+	vec4.append(43.f/255.f);
+	vec4.append(54.f/255.f);
+	vec4.append(0.f/255.f);
+
+	vec3 = LLSD::emptyArray();
+	vec3.append(2);
+	vec3.append(2);
+	vec3.append(2);
+
+	LLSD wave1, wave2;
+	wave1 = LLSD::emptyArray();
+	wave2 = LLSD::emptyArray();
+	wave1.append(0.5f);
+	wave1.append(-.17f);
+	wave2.append(0.58f);
+	wave2.append(-.67f);
+
+	LLUUID normalMap = LLUUID(gViewerArt.getString("water_normal.tga"));
+
+	mParamValues.insert("waterFogColor", vec4);
+	mParamValues.insert("waterFogDensity", 16.0f);
+	mParamValues.insert("underWaterFogMod", 0.25f);
+	mParamValues.insert("normScale", vec3);
+	mParamValues.insert("fresnelScale", 0.5f);
+	mParamValues.insert("fresnelOffset", 0.4f);
+	mParamValues.insert("scaleAbove", 0.025f);
+	mParamValues.insert("scaleBelow", 0.2f);
+	mParamValues.insert("blurMultiplier", 0.01f);
+	mParamValues.insert("wave1Dir", wave1);
+	mParamValues.insert("wave2Dir", wave2);
+	mParamValues.insert("normalMap", normalMap);
+
+}
+
+void LLWaterParamSet::set(const char * paramName, float x) 
+{	
+	// handle case where no array
+	if(mParamValues[paramName].isReal()) 
+	{
+		mParamValues[paramName] = x;
+	} 
+	
+	// handle array
+	else if(mParamValues[paramName].isArray() &&
+			mParamValues[paramName][0].isReal())
+	{
+		mParamValues[paramName][0] = x;
+	}
+}
+
+void LLWaterParamSet::set(const char * paramName, float x, float y) {
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+}
+
+void LLWaterParamSet::set(const char * paramName, float x, float y, float z)
+{
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+	mParamValues[paramName][2] = z;
+}
+
+void LLWaterParamSet::set(const char * paramName, float x, float y, float z, float w) 
+{
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+	mParamValues[paramName][2] = z;
+	mParamValues[paramName][3] = w;
+}
+
+void LLWaterParamSet::set(const char * paramName, const float * val) 
+{
+	mParamValues[paramName][0] = val[0];
+	mParamValues[paramName][1] = val[1];
+	mParamValues[paramName][2] = val[2];
+	mParamValues[paramName][3] = val[3];
+}
+
+void LLWaterParamSet::set(const char * paramName, const LLVector4 & val) 
+{
+	mParamValues[paramName][0] = val.mV[0];
+	mParamValues[paramName][1] = val.mV[1];
+	mParamValues[paramName][2] = val.mV[2];
+	mParamValues[paramName][3] = val.mV[3];
+}
+
+void LLWaterParamSet::set(const char * paramName, const LLColor4 & val) 
+{
+	mParamValues[paramName][0] = val.mV[0];
+	mParamValues[paramName][1] = val.mV[1];
+	mParamValues[paramName][2] = val.mV[2];
+	mParamValues[paramName][3] = val.mV[3];
+}
+
+LLVector4 LLWaterParamSet::getVector4(const char * paramName, bool& error) 
+{
+	
+	// test to see if right type
+	LLSD cur_val = mParamValues.get(paramName);
+	if (!cur_val.isArray() || cur_val.size() != 4) 
+	{
+		error = true;
+		return LLVector4(0,0,0,0);
+	}
+	
+	LLVector4 val;
+	val.mV[0] = (F32) cur_val[0].asReal();
+	val.mV[1] = (F32) cur_val[1].asReal();
+	val.mV[2] = (F32) cur_val[2].asReal();
+	val.mV[3] = (F32) cur_val[3].asReal();
+	
+	error = false;
+	return val;
+}
+
+LLVector3 LLWaterParamSet::getVector3(const char * paramName, bool& error) 
+{
+	
+	// test to see if right type
+	LLSD cur_val = mParamValues.get(paramName);
+	if (!cur_val.isArray()|| cur_val.size() != 3) 
+	{
+		error = true;
+		return LLVector3(0,0,0);
+	}
+	
+	LLVector3 val;
+	val.mV[0] = (F32) cur_val[0].asReal();
+	val.mV[1] = (F32) cur_val[1].asReal();
+	val.mV[2] = (F32) cur_val[2].asReal();
+	
+	error = false;
+	return val;
+}
+
+LLVector2 LLWaterParamSet::getVector2(const char * paramName, bool& error) 
+{
+	// test to see if right type
+	int ttest;
+	ttest = mParamValues.size();
+	LLSD cur_val = mParamValues.get(paramName);
+	if (!cur_val.isArray() || cur_val.size() != 2) 
+	{
+		error = true;
+		return LLVector2(0,0);
+	}
+	
+	LLVector2 val;
+	val.mV[0] = (F32) cur_val[0].asReal();
+	val.mV[1] = (F32) cur_val[1].asReal();
+	
+	error = false;
+	return val;
+}
+
+F32 LLWaterParamSet::getFloat(const char * paramName, bool& error) 
+{
+	
+	// test to see if right type
+	LLSD cur_val = mParamValues.get(paramName);
+	if (cur_val.isArray() && cur_val.size() != 0)
+	{
+		error = false;
+		return (F32) cur_val[0].asReal();	
+	}
+	
+	if(cur_val.isReal())
+	{
+		error = false;
+		return (F32) cur_val.asReal();
+	}
+	
+	error = true;
+	return 0;
+}
+
diff --git a/indra/newview/llwaterparamset.h b/indra/newview/llwaterparamset.h
new file mode 100644
index 00000000000..f853140733e
--- /dev/null
+++ b/indra/newview/llwaterparamset.h
@@ -0,0 +1,156 @@
+/**
+ * @file llwlparamset.h
+ * @brief Interface for the LLWaterParamSet class.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WATER_PARAM_SET_H
+#define LL_WATER_PARAM_SET_H
+
+#include <string>
+#include <map>
+
+#include "v4math.h"
+#include "v4color.h"
+#include "llglslshader.h"
+
+class LLFloaterWater;
+class LLWaterParamSet;
+
+/// A class representing a set of parameter values for the Water shaders.
+class LLWaterParamSet 
+{
+	friend class LLWaterParamManager;
+
+public:
+	LLString mName;	
+	
+private:
+
+	LLSD mParamValues;
+
+public:
+
+	LLWaterParamSet();
+
+	/// Bind this set of parameter values to the uniforms of a particular shader.
+	void update(LLGLSLShader * shader) const;
+
+	/// set the total llsd
+	void setAll(const LLSD& val);
+	
+	/// get the total llsd
+	const LLSD& getAll();		
+
+	/// Set a float parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The float value to set.
+	void set(const char * paramName, float x);
+
+	/// Set a float2 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	void set(const char * paramName, float x, float y);
+
+	/// Set a float3 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	/// \param z			The z component's value to set.
+	void set(const char * paramName, float x, float y, float z);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	/// \param z			The z component's value to set.
+	/// \param w			The w component's value to set.
+	void set(const char * paramName, float x, float y, float z, float w);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			An array of the 4 float values to set the parameter to.
+	void set(const char * paramName, const float * val);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			A struct of the 4 float values to set the parameter to.
+	void set(const char * paramName, const LLVector4 & val);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			A struct of the 4 float values to set the parameter to.
+	void set(const char * paramName, const LLColor4 & val);
+
+	/// Get a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type
+	LLVector4 getVector4(const char * paramName, bool& error);
+
+	/// Get a float3 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type
+	LLVector3 getVector3(const char * paramName, bool& error);
+	
+	/// Get a float2 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type
+	LLVector2 getVector2(const char * paramName, bool& error);
+	
+	/// Get an integer parameter
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type	
+	F32 getFloat(const char * paramName, bool& error);
+		
+	/// interpolate two parameter sets
+	/// \param src			The parameter set to start with
+	/// \param dest			The parameter set to end with
+	/// \param weight		The amount to interpolate
+	void mix(LLWaterParamSet& src, LLWaterParamSet& dest, 
+		F32 weight);
+
+};
+
+inline void LLWaterParamSet::setAll(const LLSD& val)
+{
+	if(val.isMap()) {
+		LLSD::map_const_iterator mIt = val.beginMap();
+		for(; mIt != val.endMap(); mIt++)
+		{
+			mParamValues[mIt->first] = mIt->second;
+		}
+	}
+}
+
+inline const LLSD& LLWaterParamSet::getAll()
+{
+	return mParamValues;
+}
+
+#endif // LL_WaterPARAM_SET_H
diff --git a/indra/newview/llwlanimator.cpp b/indra/newview/llwlanimator.cpp
new file mode 100644
index 00000000000..1b158d06850
--- /dev/null
+++ b/indra/newview/llwlanimator.cpp
@@ -0,0 +1,168 @@
+/**
+ * @file llwlanimator.cpp
+ * @brief Implementation for the LLWLAnimator class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwlanimator.h"
+#include "llsky.h"
+#include "pipeline.h"
+#include "llwlparammanager.h"
+
+LLWLAnimator::LLWLAnimator() : mStartTime(0), mDayRate(1), mDayTime(0),
+	mIsRunning(FALSE), mUseLindenTime(false)
+{
+	mDayTime = 0;
+}
+
+void LLWLAnimator::update(LLWLParamSet& curParams)
+{
+	F64 curTime;
+	curTime = getDayTime();
+
+	// don't do anything if empty
+	if(mTimeTrack.size() == 0) {
+		return;
+	}
+
+	// start it off
+	mFirstIt = mTimeTrack.begin();
+	mSecondIt = mTimeTrack.begin();
+	mSecondIt++;
+
+	// grab the two tween iterators
+	while(mSecondIt != mTimeTrack.end() && curTime > mSecondIt->first) {
+		mFirstIt++;
+		mSecondIt++;
+	}
+
+	// scroll it around when you get to the end
+	if(mSecondIt == mTimeTrack.end() || mFirstIt->first > curTime) {
+		mSecondIt = mTimeTrack.begin();
+		mFirstIt = mTimeTrack.end();
+		mFirstIt--;
+	}
+
+	F32 weight = 0;
+
+	if(mFirstIt->first < mSecondIt->first) {
+	
+		// get the delta time and the proper weight
+		weight = F32 (curTime - mFirstIt->first) / 
+			(mSecondIt->first - mFirstIt->first);
+	
+	// handle the ends
+	} else if(mFirstIt->first > mSecondIt->first) {
+		
+		// right edge of time line
+		if(curTime >= mFirstIt->first) {
+			weight = F32 (curTime - mFirstIt->first) /
+			((1 + mSecondIt->first) - mFirstIt->first);
+		
+		// left edge of time line
+		} else {
+			weight = F32 ((1 + curTime) - mFirstIt->first) /
+			((1 + mSecondIt->first) - mFirstIt->first);
+		}
+
+	
+	// handle same as whatever the last one is
+	} else {
+		weight = 1;
+	}
+
+	// do the interpolation and set the parameters
+	curParams.mix(LLWLParamManager::instance()->mParamList[mFirstIt->second], 
+		LLWLParamManager::instance()->mParamList[mSecondIt->second], weight);
+}
+
+F64 LLWLAnimator::getDayTime()
+{
+	if(!mIsRunning) {
+		return mDayTime;
+	}
+
+	if(mUseLindenTime) {
+
+		F32 phase = gSky.getSunPhase() / F_PI;
+
+		// we're not solving the non-linear equation that determines sun phase
+		// we're just linearly interpolating between the major points
+		if (phase <= 5.0 / 4.0) {
+			mDayTime = (1.0 / 3.0) * phase + (1.0 / 3.0);
+		} else {
+			mDayTime = phase - (1.0 / 2.0);
+		}
+
+		if(mDayTime > 1) {
+			mDayTime--;
+		}
+
+		return mDayTime;
+	}
+
+	// get the time;
+	mDayTime = (LLTimer::getElapsedSeconds() - mStartTime) / mDayRate;
+
+	// clamp it
+	if(mDayTime < 0) {
+		mDayTime = 0;
+	} 
+	while(mDayTime > 1) {
+		mDayTime--;
+	}
+
+	return (F32)mDayTime;
+}
+
+void LLWLAnimator::setDayTime(F64 dayTime)
+{
+	//retroactively set start time;
+	mStartTime = LLTimer::getElapsedSeconds() - dayTime * mDayRate;
+	mDayTime = dayTime;
+
+	// clamp it
+	if(mDayTime < 0) {
+		mDayTime = 0;
+	} else if(mDayTime > 1) {
+		mDayTime = 1;
+	}
+}
+
+
+void LLWLAnimator::setTrack(std::map<F32, std::string>& curTrack,
+							F32 dayRate, F64 dayTime, bool run)
+{
+	mTimeTrack = curTrack;
+	mDayRate = dayRate;
+	setDayTime(dayTime);
+
+	mIsRunning = run;
+}
diff --git a/indra/newview/llwlanimator.h b/indra/newview/llwlanimator.h
new file mode 100644
index 00000000000..5f20df3bae5
--- /dev/null
+++ b/indra/newview/llwlanimator.h
@@ -0,0 +1,76 @@
+/**
+ * @file llwlanimator.h
+ * @brief Interface for the LLWLAnimator class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WL_ANIMATOR_H
+#define LL_WL_ANIMATOR_H
+
+#include "llwlparamset.h"
+#include <string>
+#include <map>
+
+class LLWLAnimator {
+public:
+	F64 mStartTime;
+	F32 mDayRate;
+	F64 mDayTime;
+	
+	// track to play
+	std::map<F32, std::string> mTimeTrack;
+	std::map<F32, std::string>::iterator mFirstIt, mSecondIt;
+
+	// params to use
+	//std::map<std::string, LLWLParamSet> mParamList;
+
+	bool mIsRunning;
+	bool mUseLindenTime;
+
+	// simple constructor
+	LLWLAnimator();
+
+	// update the parameters
+	void update(LLWLParamSet& curParams);
+
+	// get time in seconds
+	//F64 getTime(void);
+
+	// returns a float 0 - 1 saying what time of day is it?
+	F64 getDayTime(void);
+
+	// sets a float 0 - 1 saying what time of day it is
+	void setDayTime(F64 dayTime);
+
+	// set an animation track
+	void setTrack(std::map<F32, std::string>& track,
+		F32 dayRate, F64 dayTime = 0, bool run = true);
+
+};
+
+#endif // LL_WL_ANIMATOR_H
diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp
new file mode 100644
index 00000000000..b8b2a85ee4e
--- /dev/null
+++ b/indra/newview/llwldaycycle.cpp
@@ -0,0 +1,233 @@
+/**
+ * @file llwldaycycle.cpp
+ * @brief Implementation for the LLWLDayCycle class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwldaycycle.h"
+#include "llsdserialize.h"
+#include "llwlparammanager.h"
+
+#include "llviewerwindow.h"
+
+#include <map>
+
+LLWLDayCycle::LLWLDayCycle() : mDayRate(120)
+{
+}
+
+
+LLWLDayCycle::~LLWLDayCycle()
+{
+}
+
+void LLWLDayCycle::loadDayCycle(const LLString & fileName)
+{
+	// clear the first few things
+	mTimeMap.clear();
+
+	// now load the file
+	LLString pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, 
+		"windlight/days", fileName));
+	llinfos << "Loading DayCycle settings from " << pathName << llendl;
+	
+	llifstream day_cycle_xml(pathName.c_str());
+	if (day_cycle_xml.is_open())
+	{
+		// load and parse it
+		LLSD day_data(LLSD::emptyArray());
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+		parser->parse(day_cycle_xml, day_data, LLSDSerialize::SIZE_UNLIMITED);
+
+		// add each key
+		for(S32 i = 0; i < day_data.size(); ++i)
+		{
+			// make sure it's a two array
+			if(day_data[i].size() != 2)
+			{
+				continue;
+			}
+			
+			// check each param name exists in param manager
+			bool success;
+			LLWLParamSet pset;
+			success = LLWLParamManager::instance()->getParamSet(day_data[i][1].asString(), pset);
+			if(!success)
+			{
+				// alert the user
+				LLString::format_map_t args;
+				args["[SKY]"] = day_data[i][1].asString();
+				gViewerWindow->alertXml("WLMissingSky", args);
+				continue;
+			}
+			
+			// then add the key
+			addKey((F32)day_data[i][0].asReal(), day_data[i][1].asString());
+		}
+
+		day_cycle_xml.close();
+	}
+}
+
+void LLWLDayCycle::saveDayCycle(const LLString & fileName)
+{
+	LLSD day_data(LLSD::emptyArray());
+
+	LLString pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/days", fileName));
+	//llinfos << "Saving WindLight settings to " << pathName << llendl;
+
+	for(std::map<F32, std::string>::const_iterator mIt = mTimeMap.begin();
+		mIt != mTimeMap.end();
+		++mIt) 
+	{
+		LLSD key(LLSD::emptyArray());
+		key.append(mIt->first);
+		key.append(mIt->second);
+		day_data.append(key);
+	}
+
+	std::ofstream day_cycle_xml(pathName.c_str());
+	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+	formatter->format(day_data, day_cycle_xml, LLSDFormatter::OPTIONS_PRETTY);
+
+	//day_cycle_xml.close();
+}
+
+
+void LLWLDayCycle::clearKeys()
+{
+	mTimeMap.clear();
+}
+
+
+bool LLWLDayCycle::addKey(F32 newTime, const LLString & paramName)
+{
+	// no adding negative time
+	if(newTime < 0) 
+	{
+		newTime = 0;
+	}
+
+	// if time not being used, add it and return true
+	if(mTimeMap.find(newTime) == mTimeMap.end()) 
+	{
+		mTimeMap.insert(std::pair<F32, std::string>(newTime, paramName));
+		return true;
+	}
+
+	// otherwise, don't add, and return error
+	return false;
+}
+
+bool LLWLDayCycle::changeKeyTime(F32 oldTime, F32 newTime)
+{
+	// just remove and add back
+	std::string name = mTimeMap[oldTime];
+
+	bool stat = removeKey(oldTime);
+	if(stat == false) 
+	{
+		return stat;
+	}
+
+	return addKey(newTime, name);
+}
+
+bool LLWLDayCycle::changeKeyParam(F32 time, const LLString & name)
+{
+	// just remove and add back
+	// make sure param exists
+	LLWLParamSet tmp;
+	bool stat = LLWLParamManager::instance()->getParamSet(name, tmp);
+	if(stat == false) 
+	{
+		return stat;
+	}
+
+	mTimeMap[time] = name;
+	return true;
+}
+
+
+bool LLWLDayCycle::removeKey(F32 time)
+{
+	// look for the time.  If there, erase it
+	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
+	if(mIt != mTimeMap.end()) 
+	{
+		mTimeMap.erase(mIt);
+		return true;
+	}
+
+	return false;
+}
+
+bool LLWLDayCycle::getKey(const LLString & name, F32& key)
+{
+	// scroll through till we find the 
+	std::map<F32, std::string>::iterator mIt = mTimeMap.begin();
+	for(; mIt != mTimeMap.end(); ++mIt) 
+	{
+		if(name == mIt->second) 
+		{
+			key = mIt->first;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param)
+{
+	// just scroll on through till you find it
+	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
+	if(mIt != mTimeMap.end()) 
+	{
+		return LLWLParamManager::instance()->getParamSet(mIt->second, param);
+	}
+
+	// return error if not found
+	return false;
+}
+
+bool LLWLDayCycle::getKeyedParamName(F32 time, LLString & name)
+{
+	// just scroll on through till you find it
+	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
+	if(mIt != mTimeMap.end()) 
+	{
+		name = mTimeMap[time];
+		return true;
+	}
+
+	// return error if not found
+	return false;
+}
diff --git a/indra/newview/llwldaycycle.h b/indra/newview/llwldaycycle.h
new file mode 100644
index 00000000000..b554c915fc1
--- /dev/null
+++ b/indra/newview/llwldaycycle.h
@@ -0,0 +1,105 @@
+/**
+ * @file llwlparammanager.h
+ * @brief Implementation for the LLWLParamManager class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WL_DAY_CYCLE_H
+#define LL_WL_DAY_CYCLE_H
+
+class LLWLDayCycle;
+
+#include "llfloater.h"
+
+#include <vector>
+#include <map>
+#include <string>
+#include "llwlparamset.h"
+#include "llwlanimator.h"
+
+class LLWLDayCycle
+{
+public:
+
+	// lists what param sets are used when during the day
+	std::map<F32, std::string> mTimeMap;
+
+	// how long is my day
+	F32 mDayRate;
+
+public:
+
+	/// simple constructor
+	LLWLDayCycle();
+
+	/// simple destructor
+	~LLWLDayCycle();
+
+	/// load a day cycle
+	void loadDayCycle(const LLString & fileName);
+
+	/// load a day cycle
+	void saveDayCycle(const LLString & fileName);
+
+	/// clear keys
+	void clearKeys();
+
+	/// Getters and Setters
+	/// add a new key frame to the day cycle
+	/// returns true if successful
+	/// no negative time
+	bool addKey(F32 newTime, const LLString & paramName);
+
+	/// adjust a key's placement in the day cycle
+	/// returns true if successful
+	bool changeKeyTime(F32 oldTime, F32 newTime);
+
+	/// adjust a key's parameter used
+	/// returns true if successful
+	bool changeKeyParam(F32 time, const LLString & paramName);
+
+	/// remove a key from the day cycle
+	/// returns true if successful
+	bool removeKey(F32 time);
+
+	/// get the first key time for a parameter
+	/// returns false if not there
+	bool getKey(const LLString & name, F32& key);
+
+	/// get the param set at a given time
+	/// returns true if found one
+	bool getKeyedParam(F32 time, LLWLParamSet& param);
+
+	/// get the name
+	/// returns true if it found one
+	bool getKeyedParamName(F32 time, LLString & name);
+
+};
+
+
+#endif
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
new file mode 100644
index 00000000000..b1c1f5e2d01
--- /dev/null
+++ b/indra/newview/llwlparammanager.cpp
@@ -0,0 +1,572 @@
+/**
+ * @file llwlparammanager.cpp
+ * @brief Implementation for the LLWLParamManager class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwlparammanager.h"
+
+#include "pipeline.h"
+#include "llsky.h"
+
+#include "llsliderctrl.h"
+#include "llspinctrl.h"
+#include "llcheckboxctrl.h"
+#include "llvieweruictrlfactory.h"
+#include "llviewercamera.h"
+#include "llcombobox.h"
+#include "lllineeditor.h"
+#include "llsdserialize.h"
+
+#include "v4math.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "lldrawpoolwater.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+
+#include "llwlparamset.h"
+#include "llpostprocess.h"
+#include "llfloaterwindlight.h"
+#include "llfloaterdaycycle.h"
+#include "llfloaterenvsettings.h"
+
+#include "curl/curl.h"
+
+LLWLParamManager * LLWLParamManager::sInstance = NULL;
+
+LLWLParamManager::LLWLParamManager() :
+
+	//set the defaults for the controls
+	// index is from sWLUniforms in pipeline.cpp line 979
+
+	/// Sun Delta Terrain tweak variables.
+	mSunDeltaYaw(180.0f),
+	mSceneLightStrength(2.0f),
+	mWLGamma(1.0f, "gamma"),
+
+	mBlueHorizon(0.25f, 0.25f, 1.0f, 1.0f, "blue_horizon", "WLBlueHorizon"),
+	mHazeDensity(1.0f, 1.0f, 1.0f, 0.5f, "haze_density"),
+	mBlueDensity(0.25f, 0.25f, 0.25f, 1.0f, "blue_density", "WLBlueDensity"),
+	mDensityMult(1.0f, "density_multiplier", 1000),
+	mHazeHorizon(1.0f, 1.0f, 1.0f, 0.5f, "haze_horizon"),
+	mMaxAlt(4000.0f, "max_y"),
+
+	// Lighting
+	mLightnorm(0.f, 0.707f, -0.707f, 1.f, "lightnorm"),
+	mSunlight(0.5f, 0.5f, 0.5f, 1.0f, "sunlight_color", "WLSunlight"),
+	mAmbient(0.5f, 0.75f, 1.0f, 1.19f, "ambient", "WLAmbient"),
+	mGlow(18.0f, 0.0f, -0.01f, 1.0f, "glow"),
+
+	// Clouds
+	mCloudColor(0.5f, 0.5f, 0.5f, 1.0f, "cloud_color", "WLCloudColor"),
+	mCloudMain(0.5f, 0.5f, 0.125f, 1.0f, "cloud_pos_density1"),
+	mCloudCoverage(0.0f, "cloud_shadow"),
+	mCloudDetail(0.0f, 0.0f, 0.0f, 1.0f, "cloud_pos_density2"),
+	mDistanceMult(1.0f, "distance_multiplier"),
+	mCloudScale(0.42f, "cloud_scale"),
+
+	// sky dome
+	mDomeOffset(0.96f),
+	mDomeRadius(15000.f)
+{
+}
+
+LLWLParamManager::~LLWLParamManager()
+{
+}
+
+void LLWLParamManager::loadPresets(const LLString& file_name)
+{
+	// if fileName exists, use legacy loading form the big file, otherwise, search the sky 
+	// directory, and add the list
+	if(file_name != "") 
+	{
+		LLString path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", file_name));
+		llinfos << "Loading WindLight settings from " << path_name << llendl;
+
+		llifstream presetsXML(path_name.c_str());
+	
+		if (presetsXML)
+		{
+			LLSD paramsData(LLSD::emptyMap());
+
+			LLPointer<LLSDParser> parser = new LLSDXMLParser();
+
+			parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED);
+
+			LLSD::map_const_iterator endParams = paramsData.endMap();
+			for(LLSD::map_const_iterator curParams = paramsData.beginMap();
+				curParams != endParams;
+				++curParams)
+			{
+				addParamSet(curParams->first, curParams->second);
+			}
+		}
+	}
+	
+	// otherwise, search the sky directory and find things there
+	else
+	{
+		LLString path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
+		llinfos << "Loading WindLight settings from " << path_name << llendl;
+	
+		//mParamList.clear();
+		
+		bool found = true;			
+		while(found) 
+		{
+			std::string name;
+			found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false);
+
+			llinfos << "name: " << name << llendl;
+			
+			// if we have one
+			if(found) 
+			{
+				// bugfix for SL-46920: preventing filenames that break stuff.
+				char * curl_str = curl_unescape(name.c_str(), name.size());
+				std::string unescaped_name(curl_str);
+				curl_free(curl_str);
+				curl_str = NULL;
+
+				// not much error checking here since we're getting rid of this
+				std::string sky_name = unescaped_name.substr(0, unescaped_name.size() - 4);
+			
+				LLString cur_path(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", name));
+				llinfos << "Loading sky from " << cur_path << llendl;
+				
+				std::ifstream sky_xml(cur_path.c_str());
+				if (sky_xml)
+				{
+					LLSD sky_data(LLSD::emptyMap());
+					LLPointer<LLSDParser> parser = new LLSDXMLParser();
+					parser->parse(sky_xml, sky_data, LLSDSerialize::SIZE_UNLIMITED);
+
+					addParamSet(sky_name, sky_data);
+				}
+			}
+		}
+	}
+}
+
+void LLWLParamManager::savePresets(const LLString & fileName)
+{
+	LLSD paramsData(LLSD::emptyMap());
+	
+	LLString pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", fileName));
+
+	for(std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.begin();
+		mIt != mParamList.end();
+		++mIt) 
+	{
+		paramsData[mIt->first] = mIt->second.getAll();
+	}
+
+	std::ofstream presetsXML(pathName.c_str());
+
+	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+
+	formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY);
+
+	presetsXML.close();
+}
+
+void LLWLParamManager::loadPreset(const LLString & name)
+{
+	// bugfix for SL-46920: preventing filenames that break stuff.
+	char * curl_str = curl_escape(name.c_str(), name.size());
+	std::string escaped_filename(curl_str);
+	curl_free(curl_str);
+	curl_str = NULL;
+
+	escaped_filename += ".xml";
+
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", escaped_filename));
+	llinfos << "Loading WindLight sky setting from " << pathName << llendl;
+
+	std::ifstream presetsXML(pathName.c_str());
+
+	if (presetsXML)
+	{
+		LLSD paramsData(LLSD::emptyMap());
+
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+
+		parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED);
+
+		std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+		if(mIt == mParamList.end())
+		{
+			addParamSet(name, paramsData);
+		}
+		else 
+		{
+			setParamSet(name, paramsData);
+		}
+	} 
+	else 
+	{
+		llwarns << "Can't find " << name << llendl;
+		return;
+	}
+
+	getParamSet(name, mCurParams);
+
+	propagateParameters();
+}
+
+void LLWLParamManager::savePreset(const LLString & name)
+{
+	// bugfix for SL-46920: preventing filenames that break stuff.
+	char * curl_str = curl_escape(name.c_str(), name.size());
+	std::string escaped_filename(curl_str);
+	curl_free(curl_str);
+	curl_str = NULL;
+
+	escaped_filename += ".xml";
+
+	// make an empty llsd
+	LLSD paramsData(LLSD::emptyMap());
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", escaped_filename));
+
+	// fill it with LLSD windlight params
+	paramsData = mParamList[name].getAll();
+
+	// write to file
+	std::ofstream presetsXML(pathName.c_str());
+	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+	formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY);
+	presetsXML.close();
+
+	propagateParameters();
+}
+
+void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader)
+{
+	if (gPipeline.canUseWindLightShaders())
+	{
+		mCurParams.update(shader);
+	}
+
+	if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT)
+	{
+		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV);
+		shader->uniform3fv("camPosLocal", 1, gCamera->getOrigin().mV);
+	} 
+
+	else if (shader->mShaderGroup == LLGLSLShader::SG_SKY)
+	{
+		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV);
+	}
+
+	shader->uniform1f("scene_light_strength", mSceneLightStrength);
+	
+}
+
+void LLWLParamManager::propagateParameters(void)
+{
+	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
+	
+	LLVector4 sunDir;
+	LLVector4 moonDir;
+
+	// set the sun direction from mSunAngle and mEastAngle
+	F32 sinTheta = sin(mCurParams.getEastAngle());
+	F32 cosTheta = cos(mCurParams.getEastAngle());
+
+	F32 sinPhi = sin(mCurParams.getSunAngle());
+	F32 cosPhi = cos(mCurParams.getSunAngle());
+
+	sunDir.mV[0] = -sinTheta * cosPhi;
+	sunDir.mV[1] = sinPhi;
+	sunDir.mV[2] = cosTheta * cosPhi;
+	sunDir.mV[3] = 0;
+
+	moonDir = -sunDir;
+
+	// is the normal from the sun or the moon
+	if(sunDir.mV[1] >= 0)
+	{
+		mLightDir = sunDir;
+	}
+	else if(sunDir.mV[1] < 0 && sunDir.mV[1] > NIGHTTIME_ELEVATION_COS)
+	{
+		// clamp v1 to 0 so sun never points up and causes weirdness on some machines
+		LLVector3 vec(sunDir.mV[0], sunDir.mV[1], sunDir.mV[2]);
+		vec.mV[1] = 0;
+		vec.normVec();
+		mLightDir = LLVector4(vec, 0.f);
+	}
+	else
+	{
+		mLightDir = moonDir;
+	}
+
+	// calculate the clamp lightnorm for sky (to prevent ugly banding in sky
+	// when haze goes below the horizon
+	mClampedLightDir = sunDir;
+
+	if (mClampedLightDir.mV[1] < -0.1f)
+	{
+		mClampedLightDir.mV[1] = -0.1f;
+	}
+
+	mCurParams.set("lightnorm", mLightDir);
+
+	// bind the variables for all shaders only if we're using WindLight
+	LLShaderMgr::shader_iter shaders_iter, end_shaders;
+	end_shaders = LLShaderMgr::endShaders();
+	for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter) 
+	{
+		if (shaders_iter->mProgramObject != 0
+			&& (gPipeline.canUseWindLightShaders()
+				|| shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER))
+		{
+			shaders_iter->mUniformsDirty = TRUE;
+		}
+	}
+
+	// get the cfr version of the sun's direction
+	LLVector3 cfrSunDir(sunDir.mV[2], sunDir.mV[0], sunDir.mV[1]);
+
+	// set direction and don't allow overriding
+	gSky.setSunDirection(cfrSunDir, LLVector3(0,0,0));
+	gSky.setOverrideSun(TRUE);
+}
+
+void LLWLParamManager::update(LLViewerCamera * cam)
+{
+	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
+	
+	// update clouds, sun, and general
+	mCurParams.updateCloudScrolling();
+	
+	// update only if running
+	if(mAnimator.mIsRunning) 
+	{
+		mAnimator.update(mCurParams);
+	}
+
+	// update the shaders and the menu
+	propagateParameters();
+	
+	// sync menus if they exist
+	if(LLFloaterWindLight::isOpen()) 
+	{
+		LLFloaterWindLight::instance()->syncMenu();
+	}
+	if(LLFloaterDayCycle::isOpen()) 
+	{
+		LLFloaterDayCycle::instance()->syncMenu();
+	}
+	if(LLFloaterEnvSettings::isOpen()) 
+	{
+		LLFloaterEnvSettings::instance()->syncMenu();
+	}
+
+	F32 camYaw = cam->getYaw();
+
+	stop_glerror();
+
+	// *TODO: potential optimization - this block may only need to be
+	// executed some of the time.  For example for water shaders only.
+	{
+		F32 camYawDelta = mSunDeltaYaw * DEG_TO_RAD;
+		
+		LLVector3 lightNorm3(mLightDir);	
+		lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f));
+		mRotatedLightDir = LLVector4(lightNorm3, 0.f);
+
+		LLShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLShaderMgr::endShaders();
+		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		{
+			if (shaders_iter->mProgramObject != 0
+				&& (gPipeline.canUseWindLightShaders()
+				|| shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER))
+			{
+				shaders_iter->mUniformsDirty = TRUE;
+			}
+		}
+	}
+}
+
+// static
+void LLWLParamManager::initClass(void)
+{
+	instance();
+}
+
+// static
+void LLWLParamManager::cleanupClass()
+{
+	delete sInstance;
+	sInstance = NULL;
+}
+
+void LLWLParamManager::resetAnimator(F32 curTime, bool run)
+{
+	mAnimator.setTrack(mDay.mTimeMap, mDay.mDayRate, 
+		curTime, run);
+
+	return;
+}
+bool LLWLParamManager::addParamSet(const std::string& name, LLWLParamSet& param)
+{
+	// add a new one if not one there already
+	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt == mParamList.end()) 
+	{	
+		mParamList[name] = param;
+		return true;
+	}
+
+	return false;
+}
+
+BOOL LLWLParamManager::addParamSet(const std::string& name, LLSD const & param)
+{
+	// add a new one if not one there already
+	std::map<std::string, LLWLParamSet>::const_iterator finder = mParamList.find(name);
+	if(finder == mParamList.end())
+	{
+		mParamList[name].setAll(param);
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
+bool LLWLParamManager::getParamSet(const std::string& name, LLWLParamSet& param)
+{
+	// find it and set it
+	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt != mParamList.end()) 
+	{
+		param = mParamList[name];
+		param.mName = name;
+		return true;
+	}
+
+	return false;
+}
+
+bool LLWLParamManager::setParamSet(const std::string& name, LLWLParamSet& param)
+{
+	mParamList[name] = param;
+
+	return true;
+}
+
+bool LLWLParamManager::setParamSet(const std::string& name, const LLSD & param)
+{
+	// quick, non robust (we won't be working with files, but assets) check
+	if(!param.isMap()) 
+	{
+		return false;
+	}
+	
+	mParamList[name].setAll(param);
+
+	return true;
+}
+
+bool LLWLParamManager::removeParamSet(const std::string& name, bool delete_from_disk)
+{
+	// remove from param list
+	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	if(mIt != mParamList.end()) 
+	{
+		mParamList.erase(mIt);
+	}
+
+	F32 key;
+
+	// remove all references
+	bool stat = true;
+	do 
+	{
+		// get it
+		stat = mDay.getKey(name, key);
+		if(stat == false) 
+		{
+			break;
+		}
+
+		// and remove
+		stat = mDay.removeKey(key);
+
+	} while(stat == true);
+	
+	if(delete_from_disk)
+	{
+		LLString path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
+		
+		// use full curl escaped name
+		char * curl_str = curl_escape(name.c_str(), name.size());
+		std::string escaped_name(curl_str);
+		curl_free(curl_str);
+		curl_str = NULL;
+		
+		gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml");
+	}
+
+	return true;
+}
+
+
+// static
+LLWLParamManager * LLWLParamManager::instance()
+{
+	if(NULL == sInstance)
+	{
+		sInstance = new LLWLParamManager();
+
+		sInstance->loadPresets("");
+
+		// load the day
+		sInstance->mDay.loadDayCycle("Default.xml");
+
+		// *HACK - sets cloud scrolling to what we want... fix this better in the future
+		sInstance->getParamSet("Default", sInstance->mCurParams);
+
+		// set it to noon
+		sInstance->resetAnimator(0.5, true);
+
+		// but use linden time sets it to what the estate is
+		sInstance->mAnimator.mUseLindenTime = true;
+	}
+
+	return sInstance;
+}
diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h
new file mode 100644
index 00000000000..a78d92bf8b8
--- /dev/null
+++ b/indra/newview/llwlparammanager.h
@@ -0,0 +1,292 @@
+/**
+ * @file llwlparammanager.h
+ * @brief Implementation for the LLWLParamManager class.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WLPARAMMANAGER_H
+#define LL_WLPARAMMANAGER_H
+
+#include <vector>
+#include <map>
+#include "llwlparamset.h"
+#include "llwlanimator.h"
+#include "llwldaycycle.h"
+#include "llviewercamera.h"
+
+class LLGLSLShader;
+ 
+// color control
+struct WLColorControl {
+	
+	F32 r, g, b, i;				/// the values
+	char const * name;			/// name to use to dereference params
+	std::string mSliderName;	/// name of the slider in menu
+	bool hasSliderName;			/// only set slider name for true color types
+	bool isSunOrAmbientColor;			/// flag for if it's the sun or ambient color controller
+	bool isBlueHorizonOrDensity;		/// flag for if it's the Blue Horizon or Density color controller
+
+	inline WLColorControl(F32 red, F32 green, F32 blue, F32 intensity, char const * n,
+		char const * sliderName = "")
+		: r(red), g(green), b(blue), i(intensity), name(n), mSliderName(sliderName)
+	{
+		// if there's a slider name, say we have one
+		hasSliderName = false;
+		if (mSliderName != "") {
+			hasSliderName = true;
+		}
+
+		// if it's the sun controller
+		isSunOrAmbientColor = false;
+		if (mSliderName == "WLSunlight" || mSliderName == "WLAmbient") {
+			isSunOrAmbientColor = true;
+		}
+
+		isBlueHorizonOrDensity = false;
+		if (mSliderName == "WLBlueHorizon" || mSliderName == "WLBlueDensity") {
+			isBlueHorizonOrDensity = true;
+		}
+	}
+
+	inline WLColorControl & operator = (LLVector4 const & val) {
+		r = val.mV[0];
+		g = val.mV[1];
+		b = val.mV[2];
+		i = val.mV[3];		
+		return *this;
+	}
+
+	inline operator LLVector4 (void) const {
+		return LLVector4(r, g, b, i);
+	}
+
+	inline operator LLVector3 (void) const {
+		return LLVector3(r, g, b);
+	}
+
+	inline void update(LLWLParamSet & params) const {
+		params.set(name, r, g, b, i);
+	}
+};
+
+// float slider control
+struct WLFloatControl {
+	F32 x;
+	char const * name;
+	F32 mult;
+
+	inline WLFloatControl(F32 val, char const * n, F32 m=1.0f)
+		: x(val), name(n), mult(m)
+	{
+	}
+
+	inline WLFloatControl & operator = (LLVector4 const & val) {
+		x = val.mV[0];
+
+		return *this;
+	}
+
+	inline operator F32 (void) const {
+		return x;
+	}
+
+	inline void update(LLWLParamSet & params) const {
+		params.set(name, x);
+	}
+};
+
+/// WindLight parameter manager class - what controls all the wind light shaders
+class LLWLParamManager
+{
+public:
+
+	LLWLParamManager();
+	~LLWLParamManager();
+
+	/// load a preset file
+	void loadPresets(const LLString & fileName);
+
+	/// save the preset file
+	void savePresets(const LLString & fileName);
+
+	/// load an individual preset into the sky
+	void loadPreset(const LLString & name);
+
+	/// save the parameter presets to file
+	void savePreset(const LLString & name);
+
+	/// Set shader uniforms dirty, so they'll update automatically.
+	void propagateParameters(void);
+	
+	/// Update shader uniforms that have changed.
+	void updateShaderUniforms(LLGLSLShader * shader);
+
+	/// setup the animator to run
+	void resetAnimator(F32 curTime, bool run);
+
+	/// update information camera dependent parameters
+	void update(LLViewerCamera * cam);
+
+	// get where the light is pointing
+	inline LLVector4 getLightDir(void) const;
+
+	// get where the light is pointing
+	inline LLVector4 getClampedLightDir(void) const;
+
+	// get where the light is pointing
+	inline LLVector4 getRotatedLightDir(void) const;
+	
+	/// get the dome's offset
+	inline F32 getDomeOffset(void) const;
+
+	/// get the radius of the dome
+	inline F32 getDomeRadius(void) const;
+
+	/// Perform global initialization for this class.
+	static void initClass(void);
+
+	// Cleanup of global data that's only inited once per class.
+	static void cleanupClass();
+	
+	/// add a param to the list
+	bool addParamSet(const std::string& name, LLWLParamSet& param);
+
+	/// add a param to the list
+	BOOL addParamSet(const std::string& name, LLSD const & param);
+
+	/// get a param from the list
+	bool getParamSet(const std::string& name, LLWLParamSet& param);
+
+	/// set the param in the list with a new param
+	bool setParamSet(const std::string& name, LLWLParamSet& param);
+	
+	/// set the param in the list with a new param
+	bool setParamSet(const std::string& name, LLSD const & param);	
+
+	/// gets rid of a parameter and any references to it
+	/// returns true if successful
+	bool removeParamSet(const std::string& name, bool delete_from_disk);
+
+	// singleton pattern implementation
+	static LLWLParamManager * instance();
+
+
+public:
+
+	// helper variables
+	F32 mSunAngle;
+	F32 mEastAngle;
+	LLWLAnimator mAnimator;
+
+	/// actual direction of the sun
+	LLVector4 mLightDir;
+
+	/// light norm adjusted so haze works correctly
+	LLVector4 mRotatedLightDir;
+
+	/// clamped light norm for shaders that
+	/// are adversely affected when the sun goes below the
+	/// horizon
+	LLVector4 mClampedLightDir;
+
+	// list of params and how they're cycled for days
+	LLWLDayCycle mDay;
+
+	// length of the day in seconds
+	F32 mLengthOfDay;
+
+	LLWLParamSet mCurParams;
+
+	/// Sun Delta Terrain tweak variables.
+	F32 mSunDeltaYaw;
+	WLFloatControl mWLGamma;
+
+	F32 mSceneLightStrength;
+	
+	/// Atmospherics
+	WLColorControl mBlueHorizon;
+	WLColorControl mHazeDensity;
+	WLColorControl mBlueDensity;
+	WLFloatControl mDensityMult;
+	WLColorControl mHazeHorizon;
+	WLFloatControl mMaxAlt;
+
+	/// Lighting
+	WLColorControl mLightnorm;
+	WLColorControl mSunlight;
+	WLColorControl mAmbient;
+	WLColorControl mGlow;
+
+	/// Clouds
+	WLColorControl mCloudColor;
+	WLColorControl mCloudMain;
+	WLFloatControl mCloudCoverage;
+	WLColorControl mCloudDetail;
+	WLFloatControl mDistanceMult;
+	WLFloatControl mCloudScale;
+
+	/// sky dome
+	F32 mDomeOffset;
+	F32 mDomeRadius;
+	
+	// list of all the parameters, listed by name
+	std::map<std::string, LLWLParamSet> mParamList;
+	
+	
+private:
+	// our parameter manager singleton instance
+	static LLWLParamManager * sInstance;
+
+};
+
+inline F32 LLWLParamManager::getDomeOffset(void) const
+{
+	return mDomeOffset;
+}
+
+inline F32 LLWLParamManager::getDomeRadius(void) const
+{
+	return mDomeRadius;
+}
+
+inline LLVector4 LLWLParamManager::getLightDir(void) const
+{
+	return mLightDir;
+}
+
+inline LLVector4 LLWLParamManager::getClampedLightDir(void) const
+{
+	return mClampedLightDir;
+}
+
+inline LLVector4 LLWLParamManager::getRotatedLightDir(void) const
+{
+	return mRotatedLightDir;
+}
+
+#endif
diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp
new file mode 100644
index 00000000000..6e1a3972eab
--- /dev/null
+++ b/indra/newview/llwlparamset.cpp
@@ -0,0 +1,403 @@
+/**
+ * @file llwlparamset.cpp
+ * @brief Implementation for the LLWLParamSet class.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwlparamset.h"
+#include "llwlanimator.h"
+
+#include "llfloaterwindlight.h"
+#include "llwlparammanager.h"
+#include "lluictrlfactory.h"
+#include "llsliderctrl.h"
+
+#include <llgl.h>
+
+#include <sstream>
+
+LLWLParamSet::LLWLParamSet(void) :
+	mName("Unnamed Preset"),
+	mCloudScrollXOffset(0.f), mCloudScrollYOffset(0.f)	
+{
+/* REMOVE or init the LLSD
+	const std::map<std::string, LLVector4>::value_type hardcodedPreset[] = {
+		std::make_pair("lightnorm",				LLVector4(0.f, 0.707f, -0.707f, 0.f)),
+		std::make_pair("sunlight_color",		LLVector4(0.6f, 0.6f, 2.83f, 2.27f)),
+		std::make_pair("ambient",				LLVector4(0.27f, 0.33f, 0.44f, 1.19f)),
+		std::make_pair("blue_horizon",			LLVector4(0.3f, 0.4f, 0.9f, 1.f)),
+		std::make_pair("blue_density",			LLVector4(0.3f, 0.4f, 0.8f, 1.f)),
+		std::make_pair("haze_horizon",			LLVector4(0.6f, 0.6f, 0.6f, 1.f)),
+		std::make_pair("haze_density",			LLVector4(0.3f, 0.3f, 0.3f, 1.f)),
+		std::make_pair("cloud_shadow",			LLVector4(0.f, 0.f, 0.f, 0.f)),
+		std::make_pair("density_multiplier",	LLVector4(0.001f, 0.001f, 0.001f, 0.001f)),
+		std::make_pair("distance_multiplier",	LLVector4(1.f, 1.f, 1.f, 1.f)),
+		std::make_pair("max_y",					LLVector4(600.f, 600.f, 600.f, 0.f)),
+		std::make_pair("glow",					LLVector4(15.f, 0.001f, -0.03125f, 0.f)),
+		std::make_pair("cloud_color",			LLVector4(0.0f, 0.0f, 0.0f, 0.0f)),
+		std::make_pair("cloud_pos_density1",	LLVector4(0.f, 0.f, 0.f, 1.f)),
+		std::make_pair("cloud_pos_density2",	LLVector4(0.f, 0.f, 0.f, 1.f)),
+		std::make_pair("cloud_scale",			LLVector4(0.42f, 0.f, 0.f, 1.f)),
+		std::make_pair("gamma",					LLVector4(2.0f, 2.0f, 2.0f, 0.0f)),
+	};
+	std::map<std::string, LLVector4>::value_type const * endHardcodedPreset = 
+		hardcodedPreset + sizeof(hardcodedPreset)/sizeof(hardcodedPreset[0]);
+
+	mParamValues.insert(hardcodedPreset, endHardcodedPreset);
+*/
+}
+
+void LLWLParamSet::update(LLGLSLShader * shader) const 
+{	
+	for(LLSD::map_const_iterator i = mParamValues.beginMap();
+		i != mParamValues.endMap();
+		++i)
+	{
+		const LLString& param = i->first;
+		
+		if(	param == "star_brightness" || param == "preset_num" || param == "sun_angle" ||
+			param == "east_angle" || param == "enable_cloud_scroll" ||
+			param == "cloud_scroll_rate" || param == "lightnorm" ) 
+		{
+			continue;
+		}
+		
+		if(param == "cloud_pos_density1") 
+		{
+			LLVector4 val;
+			val.mV[0] = F32(i->second[0].asReal()) + mCloudScrollXOffset;
+			val.mV[1] = F32(i->second[1].asReal()) + mCloudScrollYOffset;
+			val.mV[2] = (F32) i->second[2].asReal();
+			val.mV[3] = (F32) i->second[3].asReal();
+			
+			shader->uniform4fv(param, 1, val.mV);	
+		} 
+		else 
+		{
+			LLVector4 val;
+			
+			// handle all the different cases
+			if(i->second.isArray() && i->second.size() == 4) 
+			{
+				val.mV[0] = (F32) i->second[0].asReal();
+				val.mV[1] = (F32) i->second[1].asReal();
+				val.mV[2] = (F32) i->second[2].asReal();
+				val.mV[3] = (F32) i->second[3].asReal();															
+			} 
+			else if(i->second.isReal()) 
+			{
+				val.mV[0] = (F32) i->second.asReal();
+			} 
+			else if(i->second.isInteger()) 
+			{
+				val.mV[0] = (F32) i->second.asReal();
+			} 
+			else if(i->second.isBoolean())
+			{
+				val.mV[0] = i->second.asBoolean();
+			}
+			
+			
+			shader->uniform4fv(param, 1, val.mV);
+		}
+	}
+}
+
+void LLWLParamSet::set(const char * paramName, float x) 
+{	
+	// handle case where no array
+	if(mParamValues[paramName].isReal()) 
+	{
+		mParamValues[paramName] = x;
+	} 
+	
+	// handle array
+	else if(mParamValues[paramName].isArray() &&
+			mParamValues[paramName][0].isReal())
+	{
+		mParamValues[paramName][0] = x;
+	}
+}
+
+void LLWLParamSet::set(const char * paramName, float x, float y) {
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+}
+
+void LLWLParamSet::set(const char * paramName, float x, float y, float z) 
+{
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+	mParamValues[paramName][2] = z;
+}
+
+void LLWLParamSet::set(const char * paramName, float x, float y, float z, float w) 
+{
+	mParamValues[paramName][0] = x;
+	mParamValues[paramName][1] = y;
+	mParamValues[paramName][2] = z;
+	mParamValues[paramName][3] = w;
+}
+
+void LLWLParamSet::set(const char * paramName, const float * val) 
+{
+	mParamValues[paramName][0] = val[0];
+	mParamValues[paramName][1] = val[1];
+	mParamValues[paramName][2] = val[2];
+	mParamValues[paramName][3] = val[3];
+}
+
+void LLWLParamSet::set(const char * paramName, const LLVector4 & val) 
+{
+	mParamValues[paramName][0] = val.mV[0];
+	mParamValues[paramName][1] = val.mV[1];
+	mParamValues[paramName][2] = val.mV[2];
+	mParamValues[paramName][3] = val.mV[3];
+}
+
+void LLWLParamSet::set(const char * paramName, const LLColor4 & val) 
+{
+	mParamValues[paramName][0] = val.mV[0];
+	mParamValues[paramName][1] = val.mV[1];
+	mParamValues[paramName][2] = val.mV[2];
+	mParamValues[paramName][3] = val.mV[3];
+}
+
+LLVector4 LLWLParamSet::getVector(const char * paramName, bool& error) 
+{
+	
+	// test to see if right type
+	LLSD cur_val = mParamValues.get(paramName);
+	if (!cur_val.isArray()) 
+	{
+		error = true;
+		return LLVector4(0,0,0,0);
+	}
+	
+	LLVector4 val;
+	val.mV[0] = (F32) cur_val[0].asReal();
+	val.mV[1] = (F32) cur_val[1].asReal();
+	val.mV[2] = (F32) cur_val[2].asReal();
+	val.mV[3] = (F32) cur_val[3].asReal();
+	
+	error = false;
+	return val;
+}
+
+F32 LLWLParamSet::getFloat(const char * paramName, bool& error) 
+{
+	
+	// test to see if right type
+	LLSD cur_val = mParamValues.get(paramName);
+	if (cur_val.isArray() && cur_val.size() != 0) 
+	{
+		error = false;
+		return (F32) cur_val[0].asReal();	
+	}
+	
+	if(cur_val.isReal())
+	{
+		error = false;
+		return (F32) cur_val.asReal();
+	}
+	
+	error = true;
+	return 0;
+}
+
+
+
+void LLWLParamSet::setSunAngle(float val) 
+{
+	// keep range 0 - 2pi
+	if(val > F_TWO_PI || val < 0)
+	{
+		F32 num = val / F_TWO_PI;
+		num -= floor(num);
+		val = F_TWO_PI * num;
+	}
+
+	mParamValues["sun_angle"] = val;
+}
+
+
+void LLWLParamSet::setEastAngle(float val) 
+{
+	// keep range 0 - 2pi
+	if(val > F_TWO_PI || val < 0)
+	{
+		F32 num = val / F_TWO_PI;
+		num -= floor(num);
+		val = F_TWO_PI * num;
+	}
+
+	mParamValues["east_angle"] = val;
+}
+
+
+void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight)
+{
+	// set up the iterators
+	LLSD::map_iterator cIt = mParamValues.beginMap();
+
+	// keep cloud positions and coverage the same
+	/// TODO masking will do this later
+	F32 cloudPos1X = (F32) mParamValues["cloud_pos_density1"][0].asReal();
+	F32 cloudPos1Y = (F32) mParamValues["cloud_pos_density1"][1].asReal();
+	F32 cloudPos2X = (F32) mParamValues["cloud_pos_density2"][0].asReal();
+	F32 cloudPos2Y = (F32) mParamValues["cloud_pos_density2"][1].asReal();
+	F32 cloudCover = (F32) mParamValues["cloud_shadow"][0].asReal();
+
+	LLSD srcVal;
+	LLSD destVal;
+
+	// do the interpolation for all the ones saved as vectors
+	// skip the weird ones
+	for(; cIt != mParamValues.endMap(); cIt++) {
+
+		// check params to make sure they're actually there
+		if(src.mParamValues.has(cIt->first))
+		{
+			srcVal = src.mParamValues[cIt->first];
+		}
+		else
+		{
+			continue;
+		}
+		
+		if(dest.mParamValues.has(cIt->first))
+		{
+			destVal = dest.mParamValues[cIt->first];
+		}
+		else
+		{
+			continue;
+		}		
+				
+		// skip if not a vector
+		if(!cIt->second.isArray()) 
+		{
+			continue;
+		}
+
+		// only Real vectors allowed
+		if(!cIt->second[0].isReal()) 
+		{
+			continue;
+		}
+		
+		// make sure all the same size
+		if(	cIt->second.size() != srcVal.size() ||
+			cIt->second.size() != destVal.size())
+		{
+			continue;
+		}
+		
+		// more error checking might be necessary;
+		
+		for(int i=0; i < cIt->second.size(); ++i) 
+		{
+			cIt->second[i] = (1.0f - weight) * (F32) srcVal[i].asReal() + 
+				weight * (F32) destVal[i].asReal();
+		}
+	}
+
+	// now mix the extra parameters
+	setStarBrightness((1 - weight) * (F32) src.getStarBrightness()
+		+ weight * (F32) dest.getStarBrightness());
+
+	llassert(src.getSunAngle() >= - F_PI && 
+					src.getSunAngle() <= 3 * F_PI);
+	llassert(dest.getSunAngle() >= - F_PI && 
+					dest.getSunAngle() <= 3 * F_PI);
+	llassert(src.getEastAngle() >= 0 && 
+					src.getEastAngle() <= 4 * F_PI);
+	llassert(dest.getEastAngle() >= 0 && 
+					dest.getEastAngle() <= 4 * F_PI);
+
+	// sun angle and east angle require some handling to make sure
+	// they go in circles.  Yes quaternions would work better.
+	F32 srcSunAngle = src.getSunAngle();
+	F32 destSunAngle = dest.getSunAngle();
+	F32 srcEastAngle = src.getEastAngle();
+	F32 destEastAngle = dest.getEastAngle();
+	
+	if(fabsf(srcSunAngle - destSunAngle) > F_PI) 
+	{
+		if(srcSunAngle > destSunAngle) 
+		{
+			destSunAngle += 2 * F_PI;
+		} 
+		else 
+		{
+			srcSunAngle += 2 * F_PI;
+		}
+	}
+
+	if(fabsf(srcEastAngle - destEastAngle) > F_PI) 
+	{
+		if(srcEastAngle > destEastAngle) 
+		{
+			destEastAngle += 2 * F_PI;
+		} 
+		else 
+		{
+			srcEastAngle += 2 * F_PI;
+		}
+	}
+
+	setSunAngle((1 - weight) * srcSunAngle + weight * destSunAngle);
+	setEastAngle((1 - weight) * srcEastAngle + weight * destEastAngle);
+	
+	// now setup the sun properly
+
+	// reset those cloud positions
+	mParamValues["cloud_pos_density1"][0] = cloudPos1X;
+	mParamValues["cloud_pos_density1"][1] = cloudPos1Y;
+	mParamValues["cloud_pos_density2"][0] = cloudPos2X;
+	mParamValues["cloud_pos_density2"][1] = cloudPos2Y;
+	mParamValues["cloud_shadow"][0] = cloudCover;
+}
+
+void LLWLParamSet::updateCloudScrolling(void) 
+{
+	static LLTimer s_cloud_timer;
+
+	F64 delta_t = s_cloud_timer.getElapsedTimeAndResetF64();
+
+	if(getEnableCloudScrollX())
+	{
+		mCloudScrollXOffset += F32(delta_t * (getCloudScrollX() - 10.f) / 100.f);
+	}
+	if(getEnableCloudScrollY())
+	{
+		mCloudScrollYOffset += F32(delta_t * (getCloudScrollY() - 10.f) / 100.f);
+	}
+}
diff --git a/indra/newview/llwlparamset.h b/indra/newview/llwlparamset.h
new file mode 100644
index 00000000000..1f72fffdfcd
--- /dev/null
+++ b/indra/newview/llwlparamset.h
@@ -0,0 +1,252 @@
+/**
+ * @file llwlparamset.h
+ * @brief Interface for the LLWLParamSet class.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_WLPARAM_SET_H
+#define LL_WLPARAM_SET_H
+
+#include <string>
+#include <map>
+
+#include "v4math.h"
+#include "v4color.h"
+#include "llglslshader.h"
+
+class LLFloaterWindLight;
+class LLWLParamSet;
+
+/// A class representing a set of parameter values for the WindLight shaders.
+class LLWLParamSet {
+
+	friend class LLWLParamManager;
+
+public:
+	LLString mName;	
+	
+private:
+
+	LLSD mParamValues;
+	
+	float mCloudScrollXOffset, mCloudScrollYOffset;
+
+public:
+
+	LLWLParamSet();
+
+	/// Update this set of shader uniforms from the parameter values.
+	void update(LLGLSLShader * shader) const;
+
+	/// set the total llsd
+	void setAll(const LLSD& val);
+	
+	/// get the total llsd
+	const LLSD& getAll();		
+	
+
+	/// Set a float parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The float value to set.
+	void set(const char * paramName, float x);
+
+	/// Set a float2 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	void set(const char * paramName, float x, float y);
+
+	/// Set a float3 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	/// \param z			The z component's value to set.
+	void set(const char * paramName, float x, float y, float z);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param x			The x component's value to set.
+	/// \param y			The y component's value to set.
+	/// \param z			The z component's value to set.
+	/// \param w			The w component's value to set.
+	void set(const char * paramName, float x, float y, float z, float w);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			An array of the 4 float values to set the parameter to.
+	void set(const char * paramName, const float * val);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			A struct of the 4 float values to set the parameter to.
+	void set(const char * paramName, const LLVector4 & val);
+
+	/// Set a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param val			A struct of the 4 float values to set the parameter to.
+	void set(const char * paramName, const LLColor4 & val);
+
+	/// Get a float4 parameter.
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type
+	LLVector4 getVector(const char * paramName, bool& error);
+
+	/// Get an integer parameter
+	/// \param paramName	The name of the parameter to set.
+	/// \param error		A flag to set if it's not the proper return type	
+	F32 getFloat(const char * paramName, bool& error);
+	
+	
+	// specific getters and setters
+	
+	
+	/// set the star's brightness
+	/// \param val brightness value
+	void setStarBrightness(F32 val);
+	
+	/// get the star brightness value;
+	F32 getStarBrightness();	
+	
+	/// set the star's brightness
+	/// \param val brightness value
+	void setSunAngle(F32 val);
+	
+	/// get the star brightness value;
+	F32 getSunAngle();	
+	
+	/// set the star's brightness
+	/// \param val brightness value
+	void setEastAngle(F32 val);
+	
+	/// get the star brightness value;
+	F32 getEastAngle();	
+	
+							
+	
+	/// set the cloud scroll x enable value
+	/// \param val scroll x value	
+	void setEnableCloudScrollX(bool val);
+
+	/// get the scroll x enable value;	
+	bool getEnableCloudScrollX();
+	
+	/// set the star's brightness
+	/// \param val scroll y bool value		
+	void setEnableCloudScrollY(bool val);	
+
+	/// get the scroll enable y value;
+	bool getEnableCloudScrollY();
+	
+	/// set the cloud scroll x enable value
+	/// \param val scroll x value	
+	void setCloudScrollX(F32 val);
+
+	/// get the scroll x enable value;	
+	F32 getCloudScrollX();
+	
+	/// set the star's brightness
+	/// \param val scroll y bool value		
+	void setCloudScrollY(F32 val);	
+
+	/// get the scroll enable y value;
+	F32 getCloudScrollY();	
+
+	/// interpolate two parameter sets
+	/// \param src			The parameter set to start with
+	/// \param dest			The parameter set to end with
+	/// \param weight		The amount to interpolate
+	void mix(LLWLParamSet& src, LLWLParamSet& dest, 
+		F32 weight);
+
+	void updateCloudScrolling(void);
+};
+
+inline void LLWLParamSet::setAll(const LLSD& val)
+{
+	if(val.isMap()) {
+		mParamValues = val;
+	}
+}
+
+inline const LLSD& LLWLParamSet::getAll()
+{
+	return mParamValues;
+}
+
+inline void LLWLParamSet::setStarBrightness(float val) {
+	mParamValues["star_brightness"] = val;
+}
+
+inline F32 LLWLParamSet::getStarBrightness() {
+	return (F32) mParamValues["star_brightness"].asReal();
+}
+
+inline F32 LLWLParamSet::getSunAngle() {
+	return (F32) mParamValues["sun_angle"].asReal();
+}
+
+inline F32 LLWLParamSet::getEastAngle() {
+	return (F32) mParamValues["east_angle"].asReal();
+}
+
+
+inline void LLWLParamSet::setEnableCloudScrollX(bool val) {
+	mParamValues["enable_cloud_scroll"][0] = val;
+}
+
+inline bool LLWLParamSet::getEnableCloudScrollX() {
+	return mParamValues["enable_cloud_scroll"][0].asBoolean();
+}
+
+inline void LLWLParamSet::setEnableCloudScrollY(bool val) {
+	mParamValues["enable_cloud_scroll"][1] = val;
+}
+
+inline bool LLWLParamSet::getEnableCloudScrollY() {
+	return mParamValues["enable_cloud_scroll"][1].asBoolean();
+}
+
+
+inline void LLWLParamSet::setCloudScrollX(F32 val) {
+	mParamValues["cloud_scroll_rate"][0] = val;
+}
+
+inline F32 LLWLParamSet::getCloudScrollX() {
+	return (F32) mParamValues["cloud_scroll_rate"][0].asReal();
+}
+
+inline void LLWLParamSet::setCloudScrollY(F32 val) {
+	mParamValues["cloud_scroll_rate"][1] = val;
+}
+
+inline F32 LLWLParamSet::getCloudScrollY() {
+	return (F32) mParamValues["cloud_scroll_rate"][1].asReal();
+}
+
+
+#endif // LL_WLPARAM_SET_H
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index ead4654c7f9..65513617397 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -636,7 +636,8 @@ void LLWorld::updateParticles()
 
 void LLWorld::updateClouds(const F32 dt)
 {
-	if (gSavedSettings.getBOOL("FreezeTime"))
+	if (gSavedSettings.getBOOL("FreezeTime") ||
+		!gSavedSettings.getBOOL("SkyUseClassicClouds"))
 	{
 		// don't move clouds in snapshot mode
 		return;
@@ -791,7 +792,6 @@ void LLWorld::setLandFarClip(const F32 far_clip)
 
 void LLWorld::updateWaterObjects()
 {
-	//llinfos << "Start water update" << llendl;
 	if (!gAgent.getRegion())
 	{
 		return;
@@ -803,35 +803,33 @@ void LLWorld::updateWaterObjects()
 	}
 
 	// First, determine the min and max "box" of water objects
-	bool first = true;
 	S32 min_x = 0;
 	S32 min_y = 0;
 	S32 max_x = 0;
 	S32 max_y = 0;
 	U32 region_x, region_y;
 
-	S32 rwidth = llfloor(getRegionWidthInMeters());
+	S32 rwidth = 256;
 
+	// We only want to fill in water for stuff that's near us, say, within 256 or 512m
+	S32 range = gCamera->getFar() > 256.f ? 512 : 256;
+
+	LLViewerRegion* regionp = gAgent.getRegion();
+	from_region_handle(regionp->getHandle(), &region_x, &region_y);
+
+	min_x = (S32)region_x - range;
+	min_y = (S32)region_y - range;
+	max_x = (S32)region_x + range;
+	max_y = (S32)region_y + range;
+
+	F32 height = 0.f;
 	
 	for (region_list_t::iterator iter = mRegionList.begin();
 		 iter != mRegionList.end(); ++iter)
 	{
 		LLViewerRegion* regionp = *iter;
-		from_region_handle(regionp->getHandle(), &region_x, &region_y);
-		if (first)
-		{
-			first = false;
-			min_x = max_x = region_x;
-			min_y = max_y = region_y;
-		}
-		else
-		{
-			min_x = llmin(min_x, (S32)region_x);
-			min_y = llmin(min_y, (S32)region_y);
-			max_x = llmax(max_x, (S32)region_x);
-			max_y = llmax(max_y, (S32)region_y);
-		}
 		LLVOWater* waterp = regionp->getLand().getWaterObj();
+		height += regionp->getWaterHeight();
 		if (waterp)
 		{
 			gObjectList.updateActive(waterp);
@@ -846,15 +844,6 @@ void LLWorld::updateWaterObjects()
 	}
 	mHoleWaterObjects.clear();
 
-	// We only want to fill in holes for stuff that's near us, say, within 512m
-	LLViewerRegion* regionp = gAgent.getRegion();
-	from_region_handle(regionp->getHandle(), &region_x, &region_y);
-
-	min_x = llmax((S32)region_x - 512, min_x);
-	min_y = llmax((S32)region_y - 512, min_y);
-	max_x = llmin((S32)region_x + 512, max_x);
-	max_y = llmin((S32)region_y + 512, max_y);
-	
 	// Now, get a list of the holes
 	S32 x, y;
 	for (x = min_x; x <= max_x; x += rwidth)
@@ -866,11 +855,11 @@ void LLWorld::updateWaterObjects()
 			{
 				LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
 				waterp->setUseTexture(FALSE);
-				gPipeline.addObject(waterp);
 				waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
 													 y + rwidth/2,
-													 DEFAULT_WATER_HEIGHT));
-				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 0.f));
+													 256.f+DEFAULT_WATER_HEIGHT));
+				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
+				gPipeline.addObject(waterp);
 				mHoleWaterObjects.push_back(waterp);
 			}
 		}
@@ -884,15 +873,12 @@ void LLWorld::updateWaterObjects()
 	center_x = min_x + (wx >> 1);
 	center_y = min_y + (wy >> 1);
 
-
-
 	S32 add_boundary[4] = {
 		512 - (max_x - region_x),
 		512 - (max_y - region_y),
 		512 - (region_x - min_x),
 		512 - (region_y - min_y) };
 		
-		
 	S32 dir;
 	for (dir = 0; dir < 8; dir++)
 	{
@@ -910,16 +896,10 @@ void LLWorld::updateWaterObjects()
 		default: dim[1] = add_boundary[1]; break;
 		}
 
-		if (dim[0] == 0 || dim[1] == 0)
-		{
-			continue;
-		}
-
 		// Resize and reshape the water objects
 		const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]);
 		const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]);
 		
-		
 		LLVOWater* waterp = mEdgeWaterObjects[dir];
 		if (!waterp || waterp->isDead())
 		{
@@ -929,23 +909,38 @@ void LLWorld::updateWaterObjects()
 																				 gAgent.getRegion());
 			waterp = mEdgeWaterObjects[dir];
 			waterp->setUseTexture(FALSE);
+			waterp->setIsEdgePatch(TRUE);
 			gPipeline.addObject(waterp);
 		}
 
 		waterp->setRegion(gAgent.getRegion());
 		LLVector3d water_pos(water_center_x, water_center_y, 
-			DEFAULT_WATER_HEIGHT);
+			DEFAULT_WATER_HEIGHT+256.f);
+		LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
+
+		//stretch out to horizon
+		water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]);
+		water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]);
+
+		water_pos.mdV[0] += 1024.f * gDirAxes[dir][0];
+		water_pos.mdV[1] += 1024.f * gDirAxes[dir][1];
+
 		waterp->setPositionGlobal(water_pos);
-		waterp->setScale(LLVector3((F32)dim[0], (F32)dim[1], 0.f));
+		waterp->setScale(water_scale);
+
 		gObjectList.updateActive(waterp);
-		/*if (!gNoRender)
-		{
-			gPipeline.markMoved(waterp->mDrawable);
-		}*/
 	}
+}
 
+void LLWorld::shiftRegions(const LLVector3& offset)
+{
+	for (region_list_t::iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
+	{
+		LLViewerRegion* region = *i;
+		region->updateRenderMatrix();
+	}
 
-	//llinfos << "End water update" << llendl;
+	mPartSim.shift(offset);
 }
 
 LLViewerImage* LLWorld::getDefaultWaterTexture()
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index e634459acdc..a3cf874cfaa 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -138,6 +138,7 @@ class LLWorld
 
 	LLViewerImage *getDefaultWaterTexture();
 	void updateWaterObjects();
+	void shiftRegions(const LLVector3& offset);
 
 	void setSpaceTimeUSec(const U64 space_time_usec);
 	U64 getSpaceTimeUSec() const;
@@ -150,6 +151,8 @@ class LLWorld
 	region_list_t	mActiveRegionList;
 	LLViewerPartSim mPartSim;
 
+	region_list_t& getRegionList() { return mActiveRegionList; }
+
 private:
 	region_list_t	mRegionList;
 	region_list_t	mVisibleRegionList;
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 1abc1b165cc..6bbe5307b0e 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -39,6 +39,7 @@
 #include "llmath.h"		// clampf()
 #include "llregionhandle.h"
 #include "lleventflags.h"
+#include "llglimmediate.h"
 
 #include "llagent.h"
 #include "llcallingcard.h"
@@ -210,9 +211,11 @@ LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect )
 	mTextBoxEast->setColor( minor_color );
 	addChild( mTextBoxEast );
 	
+	major_dir_rect.mRight += 1 ;
 	mTextBoxWest =	new LLTextBox( "W", major_dir_rect );
 	mTextBoxWest->setColor( minor_color );
 	addChild( mTextBoxWest );
+	major_dir_rect.mRight -= 1 ;
 
 	mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
 	mTextBoxSouth->setColor( minor_color );
@@ -338,16 +341,18 @@ void LLWorldMapView::draw()
 		glMatrixMode(GL_MODELVIEW);
 
 		// Clear the background alpha to 0
+		gGL.flush();
 		glColorMask(FALSE, FALSE, FALSE, TRUE);
 		glAlphaFunc(GL_GEQUAL, 0.00f);
-		glBlendFunc(GL_ONE, GL_ZERO);
-		glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
+		gGL.blendFunc(GL_ONE, GL_ZERO);
+		gGL.color4f(0.0f, 0.0f, 0.0f, 0.0f);
 		gl_rect_2d(0, height, width, 0);
 	}
 
+	gGL.flush();
 	glAlphaFunc(GL_GEQUAL, 0.01f);
 	glColorMask(TRUE, TRUE, TRUE, TRUE);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	F32 layer_alpha = 1.f;
 
@@ -410,37 +415,40 @@ void LLWorldMapView::draw()
 		LLViewerImage::bindTexture(current_image);
 
 		// Draw map image into RGB
-		//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		//gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		gGL.flush();
 		glColorMask(TRUE, TRUE, TRUE, FALSE);
-		glColor4f(1.f, 1.f, 1.f, layer_alpha);
-
-		glBegin(GL_QUADS);
-			glTexCoord2f(0.0f, 1.0f);
-			glVertex3f(left, top, -1.0f);
-			glTexCoord2f(0.0f, 0.0f);
-			glVertex3f(left, bottom, -1.0f);
-			glTexCoord2f(1.0f, 0.0f);
-			glVertex3f(right, bottom, -1.0f);
-			glTexCoord2f(1.0f, 1.0f);
-			glVertex3f(right, top, -1.0f);
-		glEnd();
+		gGL.color4f(1.f, 1.f, 1.f, layer_alpha);
+
+		gGL.begin(GL_QUADS);
+			gGL.texCoord2f(0.0f, 1.0f);
+			gGL.vertex3f(left, top, -1.0f);
+			gGL.texCoord2f(0.0f, 0.0f);
+			gGL.vertex3f(left, bottom, -1.0f);
+			gGL.texCoord2f(1.0f, 0.0f);
+			gGL.vertex3f(right, bottom, -1.0f);
+			gGL.texCoord2f(1.0f, 1.0f);
+			gGL.vertex3f(right, top, -1.0f);
+		gGL.end();
 
 		// draw an alpha of 1 where the sims are visible
+		gGL.flush();
 		glColorMask(FALSE, FALSE, FALSE, TRUE);
-		glColor4f(1.f, 1.f, 1.f, 1.f);
-
-		glBegin(GL_QUADS);
-			glTexCoord2f(0.0f, 1.0f);
-			glVertex2f(left, top);
-			glTexCoord2f(0.0f, 0.0f);
-			glVertex2f(left, bottom);
-			glTexCoord2f(1.0f, 0.0f);
-			glVertex2f(right, bottom);
-			glTexCoord2f(1.0f, 1.0f);
-			glVertex2f(right, top);
-		glEnd();
+		gGL.color4f(1.f, 1.f, 1.f, 1.f);
+
+		gGL.begin(GL_QUADS);
+			gGL.texCoord2f(0.0f, 1.0f);
+			gGL.vertex2f(left, top);
+			gGL.texCoord2f(0.0f, 0.0f);
+			gGL.vertex2f(left, bottom);
+			gGL.texCoord2f(1.0f, 0.0f);
+			gGL.vertex2f(right, bottom);
+			gGL.texCoord2f(1.0f, 1.0f);
+			gGL.vertex2f(right, top);
+		gGL.end();
 	}
 
+	gGL.flush();
 	glAlphaFunc(GL_GEQUAL, 0.01f);
 	glColorMask(TRUE, TRUE, TRUE, TRUE);
 
@@ -565,52 +573,54 @@ void LLWorldMapView::draw()
 			LLGLSUIDefault gls_ui;
 			LLViewerImage::bindTexture(simimage);
 
-			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			F32 alpha = sim_alpha * info->mAlpha;
-			glColor4f(1.f, 1.0f, 1.0f, alpha);
-
-			glBegin(GL_QUADS);
-				glTexCoord2f(0.f, 1.f);
-				glVertex3f(left, top, 0.f);
-				glTexCoord2f(0.f, 0.f);
-				glVertex3f(left, bottom, 0.f);
-				glTexCoord2f(1.f, 0.f);
-				glVertex3f(right, bottom, 0.f);
-				glTexCoord2f(1.f, 1.f);
-				glVertex3f(right, top, 0.f);
-			glEnd();
+			gGL.color4f(1.f, 1.0f, 1.0f, alpha);
+
+			gGL.begin(GL_QUADS);
+				gGL.texCoord2f(0.f, 1.f);
+				gGL.vertex3f(left, top, 0.f);
+				gGL.texCoord2f(0.f, 0.f);
+				gGL.vertex3f(left, bottom, 0.f);
+				gGL.texCoord2f(1.f, 0.f);
+				gGL.vertex3f(right, bottom, 0.f);
+				gGL.texCoord2f(1.f, 1.f);
+				gGL.vertex3f(right, top, 0.f);
+			gGL.end();
 
 			if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->getHasGLTexture())
 			{
 				LLViewerImage::bindTexture(overlayimage);
-				glColor4f(1.f, 1.f, 1.f, alpha);
-				glBegin(GL_QUADS);
-					glTexCoord2f(0.f, 1.f);
-					glVertex3f(left, top, -0.5f);
-					glTexCoord2f(0.f, 0.f);
-					glVertex3f(left, bottom, -0.5f);
-					glTexCoord2f(1.f, 0.f);
-					glVertex3f(right, bottom, -0.5f);
-					glTexCoord2f(1.f, 1.f);
-					glVertex3f(right, top, -0.5f);
-				glEnd();
+				gGL.color4f(1.f, 1.f, 1.f, alpha);
+				gGL.begin(GL_QUADS);
+					gGL.texCoord2f(0.f, 1.f);
+					gGL.vertex3f(left, top, -0.5f);
+					gGL.texCoord2f(0.f, 0.f);
+					gGL.vertex3f(left, bottom, -0.5f);
+					gGL.texCoord2f(1.f, 0.f);
+					gGL.vertex3f(right, bottom, -0.5f);
+					gGL.texCoord2f(1.f, 1.f);
+					gGL.vertex3f(right, top, -0.5f);
+				gGL.end();
 			}
 			
 			if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0)
 			{
 				// draw an alpha of 1 where the sims are visible (except NULL sims)
-				glBlendFunc(GL_ONE, GL_ZERO);
+				gGL.flush();
+				gGL.blendFunc(GL_ONE, GL_ZERO);
 				glColorMask(FALSE, FALSE, FALSE, TRUE);
-				glColor4f(1.f, 1.f, 1.f, 1.f);
+				gGL.color4f(1.f, 1.f, 1.f, 1.f);
 
 				LLGLSNoTexture gls_no_texture;
-				glBegin(GL_QUADS);
-					glVertex2f(left, top);
-					glVertex2f(left, bottom);
-					glVertex2f(right, bottom);
-					glVertex2f(right, top);
-				glEnd();
-
+				gGL.begin(GL_QUADS);
+					gGL.vertex2f(left, top);
+					gGL.vertex2f(left, bottom);
+					gGL.vertex2f(right, bottom);
+					gGL.vertex2f(right, top);
+				gGL.end();
+
+				gGL.flush();
 				glColorMask(TRUE, TRUE, TRUE, TRUE);
 			}
 		}
@@ -618,16 +628,16 @@ void LLWorldMapView::draw()
 		if (info->mAccess == SIM_ACCESS_DOWN)
 		{
 			// Draw a transparent red square over down sims
-			glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA);
-			glColor4f(0.2f, 0.0f, 0.0f, 0.4f);
+			gGL.blendFunc(GL_DST_ALPHA, GL_SRC_ALPHA);
+			gGL.color4f(0.2f, 0.0f, 0.0f, 0.4f);
 
 			LLGLSNoTexture gls_no_texture;
-			glBegin(GL_QUADS);
-				glVertex2f(left, top);
-				glVertex2f(left, bottom);
-				glVertex2f(right, bottom);
-				glVertex2f(right, top);
-			glEnd();
+			gGL.begin(GL_QUADS);
+				gGL.vertex2f(left, top);
+				gGL.vertex2f(left, bottom);
+				gGL.vertex2f(right, bottom);
+				gGL.vertex2f(right, top);
+			gGL.end();
 		}
 
 		// If this is mature, and you are not, draw a line across it
@@ -635,16 +645,16 @@ void LLWorldMapView::draw()
 			&& info->mAccess > SIM_ACCESS_PG
 			&& gAgent.isTeen())
 		{
-			glBlendFunc(GL_DST_ALPHA, GL_ZERO);
+			gGL.blendFunc(GL_DST_ALPHA, GL_ZERO);
 			
 			LLGLSNoTexture gls_no_texture;
-			glColor3f(1.f, 0.f, 0.f);
-			glBegin(GL_LINES);
-				glVertex2f(left, top);
-				glVertex2f(right, bottom);
-				glVertex2f(left, bottom);
-				glVertex2f(right, top);
-			glEnd();
+			gGL.color3f(1.f, 0.f, 0.f);
+			gGL.begin(GL_LINES);
+				gGL.vertex2f(left, top);
+				gGL.vertex2f(right, bottom);
+				gGL.vertex2f(left, bottom);
+				gGL.vertex2f(right, top);
+			gGL.end();
 		}
 
 		// Draw the region name in the lower left corner
@@ -697,13 +707,13 @@ void LLWorldMapView::draw()
 	{
 		LLGLSNoTexture gls_no_texture;
 		glAlphaFunc(GL_GEQUAL, 0.0f);
-		glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
-		glColor4fv( mBackgroundColor.mV );
+		gGL.blendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
+		gGL.color4fv( mBackgroundColor.mV );
 		gl_rect_2d(0, height, width, 0);
 	}
 	
 	glAlphaFunc(GL_GEQUAL, 0.01f);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	// Infohubs
 	if (gSavedSettings.getBOOL("MapShowInfohubs"))   //(gMapScale >= sThresholdB)
@@ -996,23 +1006,23 @@ void LLWorldMapView::drawFrustum()
 	LLGLSNoTexture gls_no_texture;
 
 	// Since we don't rotate the map, we have to rotate the frustum.
-	glPushMatrix();
-		glTranslatef( ctr_x, ctr_y, 0 );
+	gGL.pushMatrix();
+		gGL.translatef( ctr_x, ctr_y, 0 );
 		glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
 
 		// Draw triangle with more alpha in far pixels to make it 
 		// fade out in distance.
-		glBegin( GL_TRIANGLES  );
-			glColor4f(1.f, 1.f, 1.f, 0.25f);
-			glVertex2f( 0, 0 );
+		gGL.begin( GL_TRIANGLES  );
+			gGL.color4f(1.f, 1.f, 1.f, 0.25f);
+			gGL.vertex2f( 0, 0 );
 
-			glColor4f(1.f, 1.f, 1.f, 0.02f);
-			glVertex2f( -half_width_pixels, far_clip_pixels );
+			gGL.color4f(1.f, 1.f, 1.f, 0.02f);
+			gGL.vertex2f( -half_width_pixels, far_clip_pixels );
 
-			glColor4f(1.f, 1.f, 1.f, 0.02f);
-			glVertex2f(  half_width_pixels, far_clip_pixels );
-		glEnd();
-	glPopMatrix();
+			gGL.color4f(1.f, 1.f, 1.f, 0.02f);
+			gGL.vertex2f(  half_width_pixels, far_clip_pixels );
+		gGL.end();
+	gGL.popMatrix();
 }
 
 
@@ -1210,15 +1220,15 @@ static void drawDot(F32 x_pixels, F32 y_pixels,
 		F32 bottom =	y_pixels - dot_radius;
 
 		LLGLSNoTexture gls_no_texture;
-		glColor4fv( color.mV );
+		gGL.color4fv( color.mV );
 		LLUI::setLineWidth(1.5f);
 		F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom; // horizontal bar Y
-		glBegin( GL_LINES );
-			glVertex2f(left, h_bar);
-			glVertex2f(right, h_bar);
-			glVertex2f(center, top);
-			glVertex2f(center, bottom);
-		glEnd();
+		gGL.begin( GL_LINES );
+			gGL.vertex2f(center, top);
+			gGL.vertex2f(left, h_bar);
+			gGL.vertex2f(right, h_bar);
+			gGL.vertex2f(right, bottom);
+		gGL.end();
 		LLUI::setLineWidth(1.0f);
 	}
 }
@@ -1386,10 +1396,10 @@ void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const
 	}
 
 	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
-	glTranslatef((F32)x, (F32)y, 0.f);
+	gGL.pushMatrix();
+	gGL.translatef((F32)x, (F32)y, 0.f);
 	gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color);
-	glPopMatrix();
+	gGL.popMatrix();
 
 }
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 8c5ad393ab6..4f533e11899 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -50,6 +50,7 @@
 #include "v3color.h"
 #include "llui.h" 
 #include "llglheaders.h"
+#include "llglimmediate.h"
 
 // newview includes
 #include "llagent.h"
@@ -57,7 +58,6 @@
 #include "lldrawpoolalpha.h"
 #include "lldrawpoolavatar.h"
 #include "lldrawpoolground.h"
-#include "lldrawpoolsimple.h"
 #include "lldrawpoolbump.h"
 #include "lldrawpooltree.h"
 #include "lldrawpoolwater.h"
@@ -96,6 +96,10 @@
 #include "llglslshader.h"
 #include "llviewerjoystick.h"
 #include "llviewerdisplay.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llspatialpartition.h"
+
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -104,7 +108,7 @@
 //#define DEBUG_INDICES
 #endif
 
-#define AGGRESSIVE_OCCLUSION 0
+void render_ui_and_swap_if_needed();
 
 const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
 const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
@@ -112,15 +116,7 @@ const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
 const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
 const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40;
 const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
-
-// Guess on the number of visible objects in the scene, used to
-// pre-size std::vector and other arrays. JC
-const S32 ESTIMATED_VISIBLE_OBJECT_COUNT = 8192;
-
-// If the sum of the X + Y + Z scale of an object exceeds this number,
-// it will be considered a potential occluder.  For instance,
-// a box of size 6 x 6 x 1 has sum 13, which might be an occluder. JC
-const F32 OCCLUDE_SCALE_SUM_THRESHOLD = 8.f;
+const U32 REFLECTION_MAP_RES = 128;
 
 // Max number of occluders to search for. JC
 const S32 MAX_OCCLUDER_COUNT = 2;
@@ -128,31 +124,21 @@ const S32 MAX_OCCLUDER_COUNT = 2;
 extern S32 gBoxFrame;
 extern BOOL gRenderLightGlows;
 extern BOOL gHideSelectedObjects;
+extern BOOL gDisplaySwapBuffers;
 
-BOOL	gAvatarBacklight = FALSE;
+// hack counter for rendering a fixed number of frames after toggling
+// fullscreen to work around DEV-5361
+static S32 sDelayedVBOEnable = 0;
 
-S32		gTrivialAccepts = 0;
+BOOL	gAvatarBacklight = FALSE;
 
 BOOL	gRenderForSelect = FALSE;
 
 LLPipeline gPipeline;
+const LLMatrix4* gGLLastMatrix = NULL;
 
 //----------------------------------------
 
-void stamp(F32 x, F32 y, F32 xs, F32 ys)
-{
-	glBegin(GL_QUADS);
-	glTexCoord2f(0,0);
-	glVertex3f(x,   y,   0.0f);
-	glTexCoord2f(1,0);
-	glVertex3f(x+xs,y,   0.0f);
-	glTexCoord2f(1,1);
-	glVertex3f(x+xs,y+ys,0.0f);
-	glTexCoord2f(0,1);
-	glVertex3f(x,   y+ys,0.0f);
-	glEnd();
-}
-
 U32 nhpo2(U32 v) 
 {
 	U32 r = 1;
@@ -162,11 +148,60 @@ U32 nhpo2(U32 v)
 	return r;
 }
 
+glh::matrix4f glh_copy_matrix(GLdouble* src)
+{
+	glh::matrix4f ret;
+	for (U32 i = 0; i < 16; i++)
+	{
+		ret.m[i] = (F32) src[i];
+	}
+	return ret;
+}
+
+glh::matrix4f glh_get_current_modelview()
+{
+	return glh_copy_matrix(gGLModelView);
+}
+
+glh::matrix4f glh_get_current_projection()
+{
+	return glh_copy_matrix(gGLProjection);
+}
+
+void glh_copy_matrix(glh::matrix4f& src, GLdouble* dst)
+{
+	for (U32 i = 0; i < 16; i++)
+	{
+		dst[i] = src.m[i];
+	}
+}
+
+void glh_set_current_modelview(glh::matrix4f& mat)
+{
+	glh_copy_matrix(mat, gGLModelView);
+}
+
+void glh_set_current_projection(glh::matrix4f& mat)
+{
+	glh_copy_matrix(mat, gGLProjection);
+}
+
+glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
+{
+	glh::matrix4f ret(
+		2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
+		0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
+		0.f, 0.f, -2.f/(zfar-znear),  -(zfar+znear)/(zfar-znear),
+		0.f, 0.f, 0.f, 1.f);
+
+	return ret;
+}
 
 //----------------------------------------
 
 S32		LLPipeline::sCompiles = 0;
 
+BOOL	LLPipeline::sDynamicLOD = TRUE;
 BOOL	LLPipeline::sShowHUDAttachments = TRUE;
 BOOL	LLPipeline::sRenderPhysicalBeacons = TRUE;
 BOOL	LLPipeline::sRenderScriptedBeacons = FALSE;
@@ -176,32 +211,59 @@ BOOL	LLPipeline::sRenderSoundBeacons = FALSE;
 BOOL	LLPipeline::sRenderBeacons = FALSE;
 BOOL	LLPipeline::sRenderHighlight = TRUE;
 BOOL	LLPipeline::sRenderProcessBeacons = FALSE;
-BOOL	LLPipeline::sUseOcclusion = FALSE;
+S32		LLPipeline::sUseOcclusion = 0;
+BOOL	LLPipeline::sFastAlpha = TRUE;
+BOOL	LLPipeline::sDisableShaders = FALSE;
+BOOL	LLPipeline::sRenderBump = TRUE;
+BOOL	LLPipeline::sUseFarClip = TRUE;
 BOOL	LLPipeline::sSkipUpdate = FALSE;
 BOOL	LLPipeline::sDynamicReflections = FALSE;
+BOOL	LLPipeline::sWaterReflections = FALSE;
 BOOL	LLPipeline::sRenderGlow = FALSE;
+BOOL	LLPipeline::sReflectionRender = FALSE;
+BOOL	LLPipeline::sImpostorRender = FALSE;
+BOOL	LLPipeline::sUnderWaterRender = FALSE;
+BOOL	LLPipeline::sTextureBindTest = FALSE;
+BOOL	LLPipeline::sRenderFrameTest = FALSE;
+
+static LLCullResult* sCull = NULL;
+
+static const U32 gl_cube_face[] = 
+{
+	GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+	GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+	GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+	GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
+};
+
+void validate_framebuffer_object();
 
 LLPipeline::LLPipeline() :
-	mScreenTex(0),
-	mGlowMap(0),
-	mGlowBuffer(0),
+	mCubeBuffer(NULL),
+	mInitialized(FALSE),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
 	mLastRebuildPool(NULL),
 	mAlphaPool(NULL),
-	mAlphaPoolPostWater(NULL),
 	mSkyPool(NULL),
-	mStarsPool(NULL),
 	mTerrainPool(NULL),
 	mWaterPool(NULL),
 	mGroundPool(NULL),
 	mSimplePool(NULL),
+	mInvisiblePool(NULL),
 	mGlowPool(NULL),
 	mBumpPool(NULL),
+	mWLSkyPool(NULL),
 	mLightMask(0),
 	mLightMovingMask(0)
 {
-	mFramebuffer[0] = mFramebuffer[1] = 0;
+	//mFramebuffer[0] = mFramebuffer[1] = mFramebuffer[2] = mFramebuffer[3] = 0;
+	mBlurCubeBuffer[0] = mBlurCubeBuffer[1] = mBlurCubeBuffer[2] = 0;
+	mBlurCubeTexture[0] = mBlurCubeTexture[1] = mBlurCubeTexture[2] = 0;
+
+	//mDepthbuffer[0] = mDepthbuffer[1] = 0;
 	mCubeFrameBuffer = 0;
 	mCubeDepth = 0;
 }
@@ -210,27 +272,17 @@ void LLPipeline::init()
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
+	sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
+	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+
 	mInitialized = TRUE;
 	
 	stop_glerror();
 
-	//create object partitions
-	//MUST MATCH declaration of eObjectPartitions
-	mObjectPartition.push_back(new LLVolumePartition());	//PARTITION_VOLUME
-	mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE
-	mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD
-	mObjectPartition.push_back(new LLTerrainPartition());	//PARTITION_TERRAIN
-	mObjectPartition.push_back(new LLWaterPartition());		//PARTITION_WATER
-	mObjectPartition.push_back(new LLTreePartition());		//PARTITION_TREE
-	mObjectPartition.push_back(new LLParticlePartition());	//PARTITION_PARTICLE
-	mObjectPartition.push_back(new LLCloudPartition());		//PARTITION_CLOUD
-	mObjectPartition.push_back(new LLGrassPartition());		//PARTITION_GRASS
-	mObjectPartition.push_back(NULL);						//PARTITION_NONE
-	
 	//create render pass pools
 	getPool(LLDrawPool::POOL_ALPHA);
-	getPool(LLDrawPool::POOL_ALPHA_POST_WATER);
 	getPool(LLDrawPool::POOL_SIMPLE);
+	getPool(LLDrawPool::POOL_INVISIBLE);
 	getPool(LLDrawPool::POOL_BUMP);
 	getPool(LLDrawPool::POOL_GLOW);
 
@@ -239,7 +291,6 @@ void LLPipeline::init()
 
 	mRenderTypeMask = 0xffffffff;	// All render types start on
 	mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
-	mRenderFeatureMask = 0;	// All features start off
 	mRenderDebugMask = 0;	// All debug starts off
 
 	mOldRenderDebugMask = mRenderDebugMask;
@@ -249,9 +300,10 @@ void LLPipeline::init()
 	stop_glerror();
 	
 	// Enable features
-	stop_glerror();
 		
 	LLShaderMgr::setShaders();
+
+	stop_glerror();
 }
 
 LLPipeline::~LLPipeline()
@@ -261,6 +313,8 @@ LLPipeline::~LLPipeline()
 
 void LLPipeline::cleanup()
 {
+	assertInitialized();
+
 	for(pool_set_t::iterator iter = mPools.begin();
 		iter != mPools.end(); )
 	{
@@ -295,12 +349,8 @@ void LLPipeline::cleanup()
 		
 	delete mAlphaPool;
 	mAlphaPool = NULL;
-	delete mAlphaPoolPostWater;
-	mAlphaPoolPostWater = NULL;
 	delete mSkyPool;
 	mSkyPool = NULL;
-	delete mStarsPool;
-	mStarsPool = NULL;
 	delete mTerrainPool;
 	mTerrainPool = NULL;
 	delete mWaterPool;
@@ -309,10 +359,15 @@ void LLPipeline::cleanup()
 	mGroundPool = NULL;
 	delete mSimplePool;
 	mSimplePool = NULL;
+	delete mInvisiblePool;
+	mInvisiblePool = NULL;
 	delete mGlowPool;
 	mGlowPool = NULL;
 	delete mBumpPool;
 	mBumpPool = NULL;
+	// don't delete wl sky pool it was handled above in the for loop
+	//delete mWLSkyPool;
+	mWLSkyPool = NULL;
 
 	releaseGLBuffers();
 
@@ -321,21 +376,9 @@ void LLPipeline::cleanup()
 	mFaceSelectImagep = NULL;
 	mAlphaSizzleImagep = NULL;
 
-	for (S32 i = 0; i < NUM_PARTITIONS-1; i++)
-	{
-		delete mObjectPartition[i];
-	}
-	mObjectPartition.clear();
-
-	mVisibleList.clear();
-	mVisibleGroups.clear();
-	mDrawableGroups.clear();
-	mActiveGroups.clear();
-	mVisibleBridge.clear();
 	mMovedBridge.clear();
-	mOccludedBridge.clear();
-	mAlphaGroups.clear();
-	clearRenderMap();
+
+	mInitialized = FALSE;
 }
 
 //============================================================================
@@ -345,39 +388,47 @@ void LLPipeline::destroyGL()
 	stop_glerror();
 	unloadShaders();
 	mHighlightFaces.clear();
-	mVisibleList.clear();
-	mVisibleGroups.clear();
-	mDrawableGroups.clear();
-	mActiveGroups.clear();
-	mVisibleBridge.clear();
-	mOccludedBridge.clear();
-	mAlphaGroups.clear();
-	clearRenderMap();
+	
+	resetDrawOrders();
+
 	resetVertexBuffers();
 
 	releaseGLBuffers();
-}
 
-void LLPipeline::releaseGLBuffers()
-{
-	if (mGlowMap)
+	if (LLVertexBuffer::sEnableVBOs)
 	{
-		glDeleteTextures(1, &mGlowMap);
-		mGlowMap = 0;
+		// render 30 frames after switching to work around DEV-5361
+		sDelayedVBOEnable = 30;
+		LLVertexBuffer::sEnableVBOs = FALSE;
 	}
+}
 
-	if (mGlowBuffer)
+void LLPipeline::resizeScreenTexture()
+{
+	if (gPipeline.canUseVertexShaders() && assertInitialized())
 	{
-		glDeleteTextures(1, &mGlowBuffer);
-		mGlowBuffer = 0;
-	}
+		GLuint resX = gViewerWindow->getWindowDisplayWidth();
+		GLuint resY = gViewerWindow->getWindowDisplayHeight();
+	
+		U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+		if (res_mod > 1)
+		{
+			resX /= res_mod;
+			resY /= res_mod;
+		}
+	
+		mScreen.release();
+		mScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);		
 
-	if (mScreenTex)
-	{
-		glDeleteTextures(1, &mScreenTex);
-		mScreenTex = 0;
+		llinfos << "RESIZED SCREEN TEXTURE: " << resX << "x" << resY << llendl;
 	}
+}
+
 
+void LLPipeline::releaseGLBuffers()
+{
+	assertInitialized();
+	
 	if (mCubeBuffer)
 	{
 		mCubeBuffer = NULL;
@@ -390,27 +441,152 @@ void LLPipeline::releaseGLBuffers()
 		mCubeDepth = mCubeFrameBuffer = 0;
 	}
 
-	if (mFramebuffer[0])
+	/*if (mFramebuffer[0])
+	{
+		glDeleteFramebuffersEXT(4, mFramebuffer);
+		mFramebuffer[0] = mFramebuffer[1] = mFramebuffer[2] = mFramebuffer[3] = 0;
+	}*/
+
+	if (mBlurCubeBuffer[0])
+	{
+		glDeleteFramebuffersEXT(3, mBlurCubeBuffer);
+		mBlurCubeBuffer[0] = mBlurCubeBuffer[1] = mBlurCubeBuffer[2] = 0;
+	}
+
+	if (mBlurCubeTexture[0])
+	{
+		glDeleteTextures(3, mBlurCubeTexture);
+		mBlurCubeTexture[0] = mBlurCubeTexture[1] = mBlurCubeTexture[2] = 0;
+	}
+
+	mWaterRef.release();
+	mWaterDis.release();
+	mScreen.release();
+
+	for (U32 i = 0; i < 3; i++)
 	{
-		glDeleteFramebuffersEXT(2, mFramebuffer);
-		mFramebuffer[0] = mFramebuffer[1] = 0;
+		mGlow[i].release();
+	}
+
+	LLVOAvatar::resetImpostors();
+}
+
+void LLPipeline::createGLBuffers()
+{
+	assertInitialized();
+
+	if (LLPipeline::sDynamicReflections ||
+		LLPipeline::sWaterReflections)
+	{ //water reflection texture
+		U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
+			
+		mWaterRef.allocate(res,res,GL_RGBA,TRUE);
+		mWaterDis.allocate(res,res,GL_RGBA,TRUE);
+
+		if (LLPipeline::sDynamicReflections)
+		{
+			//reflection map generation buffers
+			if (mCubeFrameBuffer == 0)
+			{
+				glGenFramebuffersEXT(1, &mCubeFrameBuffer);
+				glGenRenderbuffersEXT(1, &mCubeDepth);
+
+				U32 res = REFLECTION_MAP_RES;
+
+				glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mCubeDepth);
+						
+				glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,res,res);
+							
+				glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+			}
+
+			if (mCubeBuffer.isNull())
+			{
+				res = 128;
+				mCubeBuffer = new LLCubeMap();
+				mCubeBuffer->initGL();
+				glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCubeBuffer->getGLName());
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+					
+				for (U32 i = 0; i < 6; i++)
+				{
+					glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
+				}
+			}
+
+			if (mBlurCubeBuffer[0] == 0)
+			{
+				glGenFramebuffersEXT(3, mBlurCubeBuffer);
+			}
+
+			if (mBlurCubeTexture[0] == 0)
+			{
+				glGenTextures(3, mBlurCubeTexture);
+			}
+
+			res = (U32) gSavedSettings.getS32("RenderReflectionRes");
+
+			for (U32 j = 0; j < 3; j++)
+			{
+				glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mBlurCubeTexture[j]);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+					
+				for (U32 i = 0; i < 6; i++)
+				{
+					glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
+				}
+			}
+		}
+	}
+
+	stop_glerror();
+
+	if (LLPipeline::sRenderGlow)
+	{ //screen space glow buffers
+		const U32 glow_res = llmax(1, 
+			llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
+
+		for (U32 i = 0; i < 3; i++)
+		{
+			mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE);
+		}
 	}
+
+	GLuint resX = gViewerWindow->getWindowDisplayWidth();
+	GLuint resY = gViewerWindow->getWindowDisplayHeight();
+	
+	mScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);
 }
 
 void LLPipeline::restoreGL() 
 {
-	resetVertexBuffers();
+	assertInitialized();
 
 	if (mVertexShadersEnabled)
 	{
 		LLShaderMgr::setShaders();
 	}
-	
-	for (U32 i = 0; i < mObjectPartition.size()-1; i++)
+
+	if (gWorldp)
 	{
-		if (mObjectPartition[i])
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+				iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			mObjectPartition[i]->restoreGL();
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			{
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{
+					part->restoreGL();
+				}
+			}
 		}
 	}
 }
@@ -421,7 +597,7 @@ BOOL LLPipeline::canUseVertexShaders()
 	if (!gGLManager.mHasVertexShader ||
 		!gGLManager.mHasFragmentShader ||
 		!gFeatureManagerp->isFeatureAvailable("VertexShaderEnable") ||
-		mVertexShadersLoaded == -1)
+		(assertInitialized() && mVertexShadersLoaded != 1) )
 	{
 		return FALSE;
 	}
@@ -431,12 +607,31 @@ BOOL LLPipeline::canUseVertexShaders()
 	}
 }
 
+BOOL LLPipeline::canUseWindLightShaders() const
+{
+	return (!LLPipeline::sDisableShaders &&
+			gWLSkyProgram.mProgramObject != 0 &&
+			LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_WINDLIGHT) > 1);
+}
+
+BOOL LLPipeline::canUseWindLightShadersOnObjects() const
+{
+	return (canUseWindLightShaders() 
+		&& LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0);
+}
+
 void LLPipeline::unloadShaders()
 {
 	LLShaderMgr::unloadShaders();
+
 	mVertexShadersLoaded = 0;
 }
 
+void LLPipeline::assertInitializedDoError()
+{
+	llerrs << "LLPipeline used when uninitialized." << llendl;
+}
+
 //============================================================================
 
 void LLPipeline::enableShadows(const BOOL enable_shadows)
@@ -458,6 +653,8 @@ S32 LLPipeline::getMaxLightingDetail() const
 
 S32 LLPipeline::setLightingDetail(S32 level)
 {
+	assertInitialized();
+
 	if (level < 0)
 	{
 		level = gSavedSettings.getS32("RenderLightingDetail");
@@ -466,10 +663,7 @@ S32 LLPipeline::setLightingDetail(S32 level)
 	if (level != mLightingDetail)
 	{
 		gSavedSettings.setS32("RenderLightingDetail", level);
-		if (level >= 2)
-		{
-			gObjectList.relightAllObjects();
-		}
+		
 		mLightingDetail = level;
 
 		if (mVertexShadersLoaded == 1)
@@ -487,9 +681,9 @@ class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
 
 	LLOctreeDirtyTexture(const std::set<LLViewerImage*>& textures) : mTextures(textures) { }
 
-	virtual void visit(const LLOctreeState<LLDrawable>* state)
+	virtual void visit(const LLOctreeNode<LLDrawable>* node)
 	{
-		LLSpatialGroup* group = (LLSpatialGroup*) state->getNode()->getListener(0);
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 
 		if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
 		{
@@ -517,6 +711,8 @@ class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
 // Called when a texture changes # of channels (causes faces to move to alpha pool)
 void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerImage*>& textures)
 {
+	assertInitialized();
+
 	// *TODO: This is inefficient and causes frame spikes; need a better way to do this
 	//        Most of the time is spent in dirty.traverse.
 
@@ -529,18 +725,29 @@ void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerImage*>& texture
 		}
 	}
 	
-	LLOctreeDirtyTexture dirty(textures);
-	for (U32 i = 0; i < mObjectPartition.size(); i++)
+	if (gWorldp)
 	{
-		if (mObjectPartition[i])
+		LLOctreeDirtyTexture dirty(textures);
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+				iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			dirty.traverse(mObjectPartition[i]->mOctree);
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			{
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{
+					dirty.traverse(part->mOctree);
+				}
+			}
 		}
 	}
 }
 
 LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 {
+	assertInitialized();
+
 	LLDrawPool *poolp = NULL;
 	switch( type )
 	{
@@ -548,6 +755,10 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 		poolp = mSimplePool;
 		break;
 
+	case LLDrawPool::POOL_INVISIBLE:
+		poolp = mInvisiblePool;
+		break;
+
 	case LLDrawPool::POOL_GLOW:
 		poolp = mGlowPool;
 		break;
@@ -568,10 +779,6 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 		poolp = mAlphaPool;
 		break;
 
-	case LLDrawPool::POOL_ALPHA_POST_WATER:
-		poolp = mAlphaPoolPostWater;
-		break;
-
 	case LLDrawPool::POOL_AVATAR:
 		break; // Do nothing
 
@@ -579,10 +786,6 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 		poolp = mSkyPool;
 		break;
 
-	case LLDrawPool::POOL_STARS:
-		poolp = mStarsPool;
-		break;
-
 	case LLDrawPool::POOL_WATER:
 		poolp = mWaterPool;
 		break;
@@ -591,6 +794,10 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 		poolp = mGroundPool;
 		break;
 
+	case LLDrawPool::POOL_WL_SKY:
+		poolp = mWLSkyPool;
+		break;
+
 	default:
 		llassert(0);
 		llerrs << "Invalid Pool Type in  LLPipeline::findPool() type=" << type << llendl;
@@ -659,6 +866,7 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* image
 void LLPipeline::addPool(LLDrawPool *new_poolp)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+	assertInitialized();
 	mPools.insert(new_poolp);
 	addToQuickLookup( new_poolp );
 }
@@ -686,6 +894,8 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
 	LLFastTimer t(LLFastTimer::FTM_PIPELINE);
 
+	assertInitialized();
+
 	LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
 	
 	// Based on flags, remove the drawable from the queues that it's on.
@@ -721,8 +931,13 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 		return 0;
 	}
 
-	LLDrawable *drawablep = vobj->createDrawable(this);
+	LLDrawable* drawablep = vobj->mDrawable;
 
+	if (!drawablep)
+	{
+		drawablep = vobj->createDrawable(this);
+	}
+	
 	llassert(drawablep);
 
 	if (vobj->getParent())
@@ -742,8 +957,14 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::resetFrameStats()
 {
+	assertInitialized();
+
 	mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
 
+	if (mBatchCount > 0)
+	{
+		mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
+	}
 	mTrianglesDrawn = 0;
 	sCompiles        = 0;
 	mVerticesRelit   = 0;
@@ -775,6 +996,9 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
 	{
 		return;
 	}
+
+	assertInitialized();
+
 	// update drawable now
 	drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
 	drawablep->updateMove(); // returns done
@@ -801,6 +1025,9 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
 	{
 		return;
 	}
+
+	assertInitialized();
+
 	// update drawable now
 	drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
 	drawablep->updateMove();
@@ -836,7 +1063,7 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 
 void LLPipeline::updateMove()
 {
-	//LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE);
+	LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE);
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
 	if (gSavedSettings.getBOOL("FreezeTime"))
@@ -844,6 +1071,8 @@ void LLPipeline::updateMove()
 		return;
 	}
 
+	assertInitialized();
+
 	for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
 		 iter != mRetexturedList.end(); ++iter)
 	{
@@ -881,11 +1110,18 @@ void LLPipeline::updateMove()
 	//balance octrees
 	{
  		LLFastTimer ot(LLFastTimer::FTM_OCTREE_BALANCE);
-		for (U32 i = 0; i < mObjectPartition.size()-1; i++)
+
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			if (mObjectPartition[i])
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 			{
-				mObjectPartition[i]->mOctree->balance();
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{
+					part->mOctree->balance();
+				}
 			}
 		}
 	}
@@ -915,35 +1151,80 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
 	return radius*radius * 3.14159f;
 }
 
-void LLPipeline::updateCull(LLCamera& camera)
+void LLPipeline::grabReferences(LLCullResult& result)
+{
+	sCull = &result;
+}
+
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip)
 {
 	LLFastTimer t(LLFastTimer::FTM_CULL);
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
-	mVisibleList.clear();
-	mVisibleGroups.clear();
-	mDrawableGroups.clear();
-	mActiveGroups.clear();
-	gTrivialAccepts = 0;
-	mVisibleBridge.clear();
+	grabReferences(result);
+
+	sCull->clear();
+
+	BOOL to_texture =	LLPipeline::sUseOcclusion > 1 &&
+						!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && 
+						!sReflectionRender &&
+						gPipeline.canUseVertexShaders() &&
+						sRenderGlow &&
+						gGLManager.mHasFramebufferObject;
+
+	if (to_texture)
+	{
+		mScreen.bindTarget();
+	}
+
+	glPushMatrix();
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLLastModelView);
+
+	LLVertexBuffer::unbind();
+	LLGLDisable blend(GL_BLEND);
+	LLGLDisable test(GL_ALPHA_TEST);
+	LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+
+	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
-	processOcclusion(camera);
+	for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
+	{
+		LLViewerRegion* region = *iter;
+		if (water_clip != 0)
+		{
+			LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
+			camera.setUserClipPlane(plane);
+		}
+		else
+		{
+			camera.disableUserClipPlane();
+		}
 
-	for (U32 i = 0; i < mObjectPartition.size(); i++)
-	{	
-		if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType))
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			mObjectPartition[i]->cull(camera);
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
+			{
+				if (hasRenderType(part->mDrawableType))
+				{
+					part->cull(camera);
+				}
+			}
 		}
 	}
 
+	camera.disableUserClipPlane();
+
 	if (gSky.mVOSkyp.notNull() && gSky.mVOSkyp->mDrawable.notNull())
 	{
 		// Hack for sky - always visible.
 		if (hasRenderType(LLPipeline::RENDER_TYPE_SKY)) 
 		{
 			gSky.mVOSkyp->mDrawable->setVisible(camera);
-			mVisibleList.push_back(gSky.mVOSkyp->mDrawable);
+			sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
 			gSky.updateCull();
 			stop_glerror();
 		}
@@ -953,20 +1234,35 @@ void LLPipeline::updateCull(LLCamera& camera)
 		llinfos << "No sky drawable!" << llendl;
 	}
 
-	if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && gSky.mVOGroundp.notNull() && gSky.mVOGroundp->mDrawable.notNull())
+	if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && 
+		!gPipeline.canUseWindLightShaders() &&
+		gSky.mVOGroundp.notNull() && 
+		gSky.mVOGroundp->mDrawable.notNull() &&
+		!LLPipeline::sWaterReflections)
 	{
 		gSky.mVOGroundp->mDrawable->setVisible(camera);
-		mVisibleList.push_back(gSky.mVOGroundp->mDrawable);
+		sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
+	}
+	
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+	glPopMatrix();
+
+	if (to_texture)
+	{
+		mScreen.flush();
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 	}
 }
 
-void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera, BOOL active)
+void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 {
 	if (group->getData().empty())
 	{ 
 		return;
 	}
 	
+	group->setVisible();
+
 	if (!sSkipUpdate)
 	{
 		group->updateDistance(camera);
@@ -978,29 +1274,39 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera, BOOL act
 	{
 		return;
 	}
+
+	assertInitialized();
 	
-	group->mLastRenderTime = gFrameTimeSeconds;
 	if (!group->mSpatialPartition->mRenderByGroup)
 	{ //render by drawable
-		mDrawableGroups.push_back(group);
-		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
-		{
-			markVisible(*i, camera);
-		}
+		sCull->pushDrawableGroup(group);
 	}
 	else
-	{ //render by group
-		if (active)
-		{
-			mActiveGroups.push_back(group);
-		}
-		else
-		{
-			mVisibleGroups.push_back(group);
-			for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+	{   //render by group
+		sCull->pushVisibleGroup(group);
+	}
+
+	mNumVisibleNodes++;
+}
+
+void LLPipeline::markOccluder(LLSpatialGroup* group)
+{
+	if (sUseOcclusion > 1 && group && !group->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
+	{
+		LLSpatialGroup* parent = group->getParent();
+
+		if (!parent || !parent->isState(LLSpatialGroup::OCCLUDED))
+		{ //only mark top most occluders as active occlusion
+			sCull->pushOcclusionGroup(group);
+			group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
+				
+			if (parent && 
+				!parent->isState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
+				parent->getElementCount() == 0 &&
+				parent->needsUpdate())
 			{
-				LLSpatialBridge* bridge = *i;
-				markVisible(bridge, camera);
+				sCull->pushOcclusionGroup(group);
+				parent->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
 			}
 		}
 	}
@@ -1008,38 +1314,37 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera, BOOL act
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-	if (sUseOcclusion)
+	LLVertexBuffer::unbind();
+	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 	{
-		for (U32 i = 0; i < mObjectPartition.size(); i++)
-		{
-			if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType))
-			{
-				mObjectPartition[i]->doOcclusion(&camera);
-			}
-		}
-		
-#if AGGRESSIVE_OCCLUSION
-		for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i)
+		glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
+	}
+	else
+	{
+		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	}
+	LLGLDisable blend(GL_BLEND);
+	LLGLDisable test(GL_ALPHA_TEST);
+	LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+	if (LLPipeline::sUseOcclusion > 1)
+	{
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
 		{
-			LLSpatialBridge* bridge = *i;
-			if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
-			{
-				glPushMatrix();
-				glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
-				LLCamera trans = bridge->transformCamera(camera);
-				bridge->doOcclusion(&trans);
-				glPopMatrix();
-				mOccludedBridge.push_back(bridge);
-			}
+			LLSpatialGroup* group = *iter;
+			group->doOcclusion(&camera);
+			group->clearState(LLSpatialGroup::ACTIVE_OCCLUSION);
 		}
-#endif 
 	}
+
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
 }
 	
 BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
 {
 	BOOL update_complete = drawablep->updateGeometry(priority);
-	if (update_complete)
+	if (update_complete && assertInitialized())
 	{
 		drawablep->setState(LLDrawable::BUILT);
 		mGeometryChanges++;
@@ -1055,6 +1360,17 @@ void LLPipeline::updateGeom(F32 max_dtime)
 
 	LLFastTimer t(LLFastTimer::FTM_GEO_UPDATE);
 
+	assertInitialized();
+
+	if (sDelayedVBOEnable > 0)
+	{
+		if (--sDelayedVBOEnable <= 0)
+		{
+			resetVertexBuffers();
+			LLVertexBuffer::sEnableVBOs = TRUE;
+		}
+	}
+
 	// notify various object types to reset internal cost metrics, etc.
 	// for now, only LLVOVolume does this to throttle LOD changes
 	LLVOVolume::preUpdateGeom();
@@ -1091,9 +1407,10 @@ void LLPipeline::updateGeom(F32 max_dtime)
 		
 	// Iterate through some drawables on the non-priority build queue
 	S32 min_count = 16;
-	if (mBuildQ2.size() > 1000)
+	S32 size = (S32) mBuildQ2.size();
+	if (size > 1024)
 	{
-		min_count = mBuildQ2.size();
+		min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
 	}
 		
 	S32 count = 0;
@@ -1144,44 +1461,25 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 	if(!drawablep || drawablep->isDead())
 	{
-		llwarns << "LLPipeline::markVisible called with NULL drawablep" << llendl;
 		return;
 	}
 	
-	
-#if LL_DEBUG
 	if (drawablep->isSpatialBridge())
 	{
-		if (std::find(mVisibleBridge.begin(), mVisibleBridge.end(), (LLSpatialBridge*) drawablep) !=
-			mVisibleBridge.end())
-		{
-			llerrs << "Spatial bridge marked visible redundantly." << llendl;
-		}
+		sCull->pushBridge((LLSpatialBridge*) drawablep);
 	}
 	else
 	{
-		if (std::find(mVisibleList.begin(), mVisibleList.end(), drawablep) !=
-			mVisibleList.end())
-		{
-			llerrs << "Drawable marked visible redundantly." << llendl;
-		}
+		sCull->pushDrawable(drawablep);
 	}
-#endif
 
-	if (drawablep->isSpatialBridge())
-	{
-		mVisibleBridge.push_back((LLSpatialBridge*) drawablep);
-	}
-	else
-	{
-		mVisibleList.push_back(drawablep);
-	}
 	drawablep->setVisible(camera);
 }
 
 void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
 	if (!drawablep)
 	{
 		llerrs << "Sending null drawable to moved list!" << llendl;
@@ -1200,6 +1498,7 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
 		markMoved(drawablep->getParent(), damped_motion);
 	}
 
+	assertInitialized();
 
 	if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
 	{
@@ -1226,11 +1525,14 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
 void LLPipeline::markShift(LLDrawable *drawablep)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
 	if (!drawablep || drawablep->isDead())
 	{
 		return;
 	}
 
+	assertInitialized();
+
 	if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
 	{
 		drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
@@ -1246,6 +1548,14 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+	assertInitialized();
+
+	//do a swap to indicate an invalid previous frame camera
+	render_ui_and_swap_if_needed();
+	glClear(GL_DEPTH_BUFFER_BIT);
+	gDisplaySwapBuffers = FALSE;
+
 	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
 		 iter != mShiftList.end(); iter++)
 	{
@@ -1259,11 +1569,17 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	}
 	mShiftList.resize(0);
 
-	for (U32 i = 0; i < mObjectPartition.size()-1; i++)
+	for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
 	{
-		if (mObjectPartition[i])
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			mObjectPartition[i]->shift(offset);
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
+			{
+				part->shift(offset);
+			}
 		}
 	}
 }
@@ -1271,7 +1587,8 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 void LLPipeline::markTextured(LLDrawable *drawablep)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	if (drawablep && !drawablep->isDead())
+
+	if (drawablep && !drawablep->isDead() && assertInitialized())
 	{
 		mRetexturedList.insert(drawablep);
 	}
@@ -1281,7 +1598,7 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
-	if (drawablep && !drawablep->isDead())
+	if (drawablep && !drawablep->isDead() && assertInitialized())
 	{
 		if (!drawablep->isState(LLDrawable::BUILT))
 		{
@@ -1305,60 +1622,94 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
 			drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
 		}
 		drawablep->setState(flag);
-		if ((flag & LLDrawable::REBUILD_LIGHTING) && drawablep->getLit())
-		{
-			if (drawablep->isLight())
-			{
-				drawablep->clearState(LLDrawable::LIGHTING_BUILT);
-			}
-			else
-			{
-				drawablep->clearState(LLDrawable::LIGHTING_BUILT);
-			}
-		}
 	}
 }
 
-void LLPipeline::markRelight(LLDrawable *drawablep, const BOOL priority)
+void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
-	if (getLightingDetail() >= 2)
+	const U32 face_mask = (1 << LLPipeline::RENDER_TYPE_AVATAR) |
+						  (1 << LLPipeline::RENDER_TYPE_GROUND) |
+						  (1 << LLPipeline::RENDER_TYPE_TERRAIN) |
+						  (1 << LLPipeline::RENDER_TYPE_TREE) |
+						  (1 << LLPipeline::RENDER_TYPE_SKY) |
+						  (1 << LLPipeline::RENDER_TYPE_WATER);
+
+	if (mRenderTypeMask & face_mask)
 	{
-		markRebuild(drawablep, LLDrawable::REBUILD_LIGHTING, FALSE);
+		//clear faces from face pools
+		LLFastTimer t(LLFastTimer::FTM_RESET_DRAWORDER);
+		gPipeline.resetDrawOrders();
 	}
-}
 
-void LLPipeline::stateSort(LLCamera& camera)
-{
 	LLFastTimer ftm(LLFastTimer::FTM_STATESORT);
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
-	for (LLSpatialGroup::sg_vector_t::iterator iter = mVisibleGroups.begin(); iter != mVisibleGroups.end(); ++iter)
+	grabReferences(result);
+
 	{
-		stateSort(*iter, camera);
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			group->checkOcclusion();
+			if (sUseOcclusion && group->isState(LLSpatialGroup::OCCLUDED))
+			{
+				markOccluder(group);
+			}
+			else
+			{
+				group->setVisible();
+				for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+				{
+					markVisible(*i, camera);
+				}
+			}
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			group->checkOcclusion();
+			if (sUseOcclusion && group->isState(LLSpatialGroup::OCCLUDED))
+			{
+				markOccluder(group);
+			}
+			else
+			{
+				group->setVisible();
+				stateSort(group, camera);
+			}
+		}
 	}
-		
-	for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i)
+
 	{
-		LLSpatialBridge* bridge = *i;
-		if (!bridge->isDead())
+		for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 		{
-			stateSort(bridge, camera);
+			LLCullResult::bridge_list_t::iterator cur_iter = i;
+			LLSpatialBridge* bridge = *cur_iter;
+			LLSpatialGroup* group = bridge->getSpatialGroup();
+			if (!bridge->isDead() && group && !group->isState(LLSpatialGroup::OCCLUDED))
+			{
+				stateSort(bridge, camera);
+			}
 		}
 	}
 
-	for (LLDrawable::drawable_vector_t::iterator iter = mVisibleList.begin();
-		 iter != mVisibleList.end(); iter++)
 	{
-		LLDrawable *drawablep = *iter;
-		if (!drawablep->isDead())
+		LLFastTimer ftm(LLFastTimer::FTM_STATESORT_DRAWABLE);
+		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
+			 iter != sCull->endVisibleList(); ++iter)
 		{
-			stateSort(drawablep, camera);
+			LLDrawable *drawablep = *iter;
+			if (!drawablep->isDead())
+			{
+				stateSort(drawablep, camera);
+			}
 		}
 	}
 
-	for (LLSpatialGroup::sg_vector_t::iterator iter = mActiveGroups.begin(); iter != mActiveGroups.end(); ++iter)
 	{
-		stateSort(*iter, camera);
+		LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY);
+		LLVertexBuffer::clientCopy();
 	}
 
 	postSort(camera);
@@ -1375,19 +1726,12 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 			stateSort(drawablep, camera);
 		}
 	}
-	
-#if !LL_DARWIN
-	if (gFrameTimeSeconds - group->mLastUpdateTime > 4.f)
-	{
-		group->makeStatic();
-	}
-#endif
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	if (!sSkipUpdate)
+	if (!sSkipUpdate && bridge->getSpatialGroup()->changeLOD())
 	{
 		bridge->updateDistance(camera);
 	}
@@ -1396,8 +1740,7 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
 void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	LLFastTimer ftm(LLFastTimer::FTM_STATESORT_DRAWABLE);
-	
+		
 	if (!drawablep
 		|| drawablep->isDead() 
 		|| !hasRenderType(drawablep->getRenderType()))
@@ -1414,6 +1757,17 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 		}
 	}
 
+	if (drawablep->isAvatar())
+	{ //don't draw avatars beyond render distance or if we don't have a spatial group.
+		if ((drawablep->getSpatialGroup() == NULL) || 
+			(drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
+		{
+			return;
+		}
+	}
+
+	assertInitialized();
+
 	if (hasRenderType(drawablep->mRenderType))
 	{
 		if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
@@ -1427,17 +1781,21 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 		}
 	}
 
-	if (!drawablep->isActive() && drawablep->isVisible())
+	LLSpatialGroup* group = drawablep->getSpatialGroup();
+	if (!group || group->changeLOD())
 	{
-		if (!sSkipUpdate)
+		if (!drawablep->isActive() && drawablep->isVisible())
 		{
-			drawablep->updateDistance(camera);
+			if (!sSkipUpdate)
+			{
+				drawablep->updateDistance(camera);
+			}
+		}
+		else if (drawablep->isAvatar() && drawablep->isVisible())
+		{
+			LLVOAvatar* vobj = (LLVOAvatar*) drawablep->getVObj().get();
+			vobj->updateVisibility();
 		}
-	}
-	else if (drawablep->isAvatar() && drawablep->isVisible())
-	{
-		LLVOAvatar* vobj = (LLVOAvatar*) drawablep->getVObj().get();
-		vobj->updateVisibility(FALSE);
 	}
 
 	for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
@@ -1457,15 +1815,16 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 			}
 		}
 	}
-	
-	
+
 	mNumVisibleFaces += drawablep->getNumFaces();
 }
 
 
-void LLPipeline::forAllDrawables(LLSpatialGroup::sg_vector_t& groups, void (*func)(LLDrawable*))
+void forAllDrawables(LLCullResult::sg_list_t::iterator begin, 
+					 LLCullResult::sg_list_t::iterator end,
+					 void (*func)(LLDrawable*))
 {
-	for (LLSpatialGroup::sg_vector_t::iterator i = groups.begin(); i != groups.end(); ++i)
+	for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
 	{
 		for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
 		{
@@ -1476,9 +1835,8 @@ void LLPipeline::forAllDrawables(LLSpatialGroup::sg_vector_t& groups, void (*fun
 
 void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
 {
-	forAllDrawables(mDrawableGroups, func);
-	forAllDrawables(mVisibleGroups, func);
-	forAllDrawables(mActiveGroups, func);
+	forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
+	forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
 }
 
 //function for creating scripted beacons
@@ -1498,7 +1856,8 @@ void renderScriptedBeacons(LLDrawable* drawablep)
 		if (gPipeline.sRenderHighlight)
 		{
 			S32 face_id;
-			for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++)
+			S32 count = drawablep->getNumFaces();
+			for (face_id = 0; face_id < count; face_id++)
 			{
 				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
 			}
@@ -1523,7 +1882,8 @@ void renderScriptedTouchBeacons(LLDrawable* drawablep)
 		if (gPipeline.sRenderHighlight)
 		{
 			S32 face_id;
-			for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++)
+			S32 count = drawablep->getNumFaces();
+			for (face_id = 0; face_id < count; face_id++)
 			{
 				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
 			}
@@ -1547,7 +1907,8 @@ void renderPhysicalBeacons(LLDrawable* drawablep)
 		if (gPipeline.sRenderHighlight)
 		{
 			S32 face_id;
-			for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++)
+			S32 count = drawablep->getNumFaces();
+			for (face_id = 0; face_id < count; face_id++)
 			{
 				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
 			}
@@ -1571,7 +1932,8 @@ void renderParticleBeacons(LLDrawable* drawablep)
 		if (gPipeline.sRenderHighlight)
 		{
 			S32 face_id;
-			for (face_id = 0; face_id < drawablep->getNumFaces(); face_id++)
+			S32 count = drawablep->getNumFaces();
+			for (face_id = 0; face_id < count; face_id++)
 			{
 				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
 			}
@@ -1579,73 +1941,61 @@ void renderParticleBeacons(LLDrawable* drawablep)
 	}
 }
 
-void LLPipeline::postSort(LLCamera& camera)
+void renderSoundHighlights(LLDrawable* drawablep)
 {
-	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	LLFastTimer ftm(LLFastTimer::FTM_STATESORT_POSTSORT);
-	//reset render data sets
-	clearRenderMap();
-	mAlphaGroups.clear();
-	mAlphaGroupsPostWater.clear();
-	
-	if (!gSavedSettings.getBOOL("RenderRippleWater") && hasRenderType(LLDrawPool::POOL_ALPHA))
-	{	//turn off clip plane for non-ripple water
-		toggleRenderType(LLDrawPool::POOL_ALPHA);
-	}
-
-	F32 water_height = gAgent.getRegion()->getWaterHeight();
-	BOOL above_water = gCamera->getOrigin().mV[2] > water_height ? TRUE : FALSE;
-
-	//prepare occlusion geometry
-	if (sUseOcclusion)
+	// Look for attachments, objects, etc.
+	LLViewerObject *vobj = drawablep->getVObj();
+	if (vobj && vobj->isAudioSource())
 	{
-		for (U32 i = 0; i < mObjectPartition.size(); i++)
+		if (gPipeline.sRenderHighlight)
 		{
-			if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType))
+			S32 face_id;
+			S32 count = drawablep->getNumFaces();
+			for (face_id = 0; face_id < count; face_id++)
 			{
-				mObjectPartition[i]->buildOcclusion();
-			}
-		}
-		
-#if AGGRESSIVE_OCCLUSION
-		for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i)
-		{
-			LLSpatialBridge* bridge = *i;
-			if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
-			{	
-				bridge->buildOcclusion();
+				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
 			}
 		}
-#endif
 	}
+}
 
+void LLPipeline::postSort(LLCamera& camera)
+{
+	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+	LLFastTimer ftm(LLFastTimer::FTM_STATESORT_POSTSORT);
 
-	if (!sSkipUpdate)
+	assertInitialized();
+
+	//rebuild drawable geometry
+	for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
 	{
-		//rebuild drawable geometry
-		for (LLSpatialGroup::sg_vector_t::iterator i = mDrawableGroups.begin(); i != mDrawableGroups.end(); ++i)
+		LLSpatialGroup* group = *i;
+		if (!sUseOcclusion || 
+			!group->isState(LLSpatialGroup::OCCLUDED))
 		{
-			LLSpatialGroup* group = *i;
 			group->rebuildGeom();
 		}
 	}
 
 	//build render map
-	for (LLSpatialGroup::sg_vector_t::iterator i = mVisibleGroups.begin(); i != mVisibleGroups.end(); ++i)
+	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
-		if (!sSkipUpdate)
+		if (sUseOcclusion && 
+			group->isState(LLSpatialGroup::OCCLUDED))
 		{
-			group->rebuildGeom();
+			continue;
 		}
+		
+		group->rebuildGeom();
+		
 		for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
 		{
 			LLSpatialGroup::drawmap_elem_t& src_vec = j->second;	
-			LLSpatialGroup::drawmap_elem_t& dest_vec = mRenderMap[j->first];  
-
-			for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) 
+			
+			for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
 			{
-				dest_vec.push_back(*k);
+				sCull->pushDrawInfo(j->first, *k);
 			}
 		}
 		
@@ -1653,95 +2003,47 @@ void LLPipeline::postSort(LLCamera& camera)
 		
 		if (alpha != group->mDrawMap.end())
 		{ //store alpha groups for sorting
+			LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
 			if (!sSkipUpdate)
 			{
-				group->updateDistance(camera);
-			}
-			
-			if (hasRenderType(LLDrawPool::POOL_ALPHA))
-			{
-				BOOL above = group->mObjectBounds[0].mV[2] + group->mObjectBounds[1].mV[2] > water_height ? TRUE : FALSE;
-				BOOL below = group->mObjectBounds[0].mV[2] - group->mObjectBounds[1].mV[2] < water_height ? TRUE : FALSE;
-				
-				if (below == above_water || above == below)
+				if (bridge)
 				{
-					mAlphaGroups.push_back(group);
+					LLCamera trans_camera = bridge->transformCamera(camera);
+					group->updateDistance(trans_camera);
 				}
-
-				if (above == above_water || below == above)
+				else
 				{
-					mAlphaGroupsPostWater.push_back(group);
+					group->updateDistance(camera);
 				}
 			}
-			else
+			
+			if (hasRenderType(LLDrawPool::POOL_ALPHA))
 			{
-				mAlphaGroupsPostWater.push_back(group);
+				sCull->pushAlphaGroup(group);
 			}
 		}
 	}
-	
-	//store active alpha groups
-	for (LLSpatialGroup::sg_vector_t::iterator i = mActiveGroups.begin(); i != mActiveGroups.end(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (!sSkipUpdate)
-		{
-			group->rebuildGeom();
-		}
-		LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
 		
-		if (alpha != group->mDrawMap.end())
+	{
+		//sort by texture or bump map
+		for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
 		{
-			LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
-			LLCamera trans_camera = bridge->transformCamera(camera);
-			if (!sSkipUpdate)
-			{
-				group->updateDistance(trans_camera);
-			}
-			
-			if (hasRenderType(LLDrawPool::POOL_ALPHA))
+			//if (!mRenderMap[i].empty())
 			{
-				LLSpatialGroup* bridge_group = bridge->getSpatialGroup();
-				BOOL above = bridge_group->mObjectBounds[0].mV[2] + bridge_group->mObjectBounds[1].mV[2] > water_height ? TRUE : FALSE;
-				BOOL below = bridge_group->mObjectBounds[0].mV[2] - bridge_group->mObjectBounds[1].mV[2] < water_height ? TRUE : FALSE;
-					
-				
-				if (below == above_water || above == below)
+				if (i == LLRenderPass::PASS_BUMP)
 				{
-					mAlphaGroups.push_back(group);
+					std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
 				}
-				
-				if (above == above_water || below == above)
+				else 
 				{
-					mAlphaGroupsPostWater.push_back(group);
+					std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
 				}
 			}
-			else
-			{
-				mAlphaGroupsPostWater.push_back(group);
-			}
 		}
-	}
 
-	//sort by texture or bump map
-	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
-	{
-		if (!mRenderMap[i].empty())
-		{
-			if (i == LLRenderPass::PASS_BUMP)
-			{
-				std::sort(mRenderMap[i].begin(), mRenderMap[i].end(), LLDrawInfo::CompareBump());
-			}
-			else 
-			{
-				std::sort(mRenderMap[i].begin(), mRenderMap[i].end(), LLDrawInfo::CompareTexturePtr());
-			}
-		}
+		std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
 	}
 
-	std::sort(mAlphaGroups.begin(), mAlphaGroups.end(), LLSpatialGroup::CompareDepthGreater());
-	std::sort(mAlphaGroupsPostWater.begin(), mAlphaGroupsPostWater.end(), LLSpatialGroup::CompareDepthGreater());
-
 	// only render if the flag is set. The flag is only set if the right key is pressed, we are in edit mode or the toggle is set in the menus
 	if (sRenderProcessBeacons)
 	{
@@ -1771,7 +2073,7 @@ void LLPipeline::postSort(LLCamera& camera)
 		// If god mode, also show audio cues
 		if (sRenderSoundBeacons && gAudiop)
 		{
-			// Update all of our audio sources, clean up dead ones.
+			// Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
 			LLAudioEngine::source_map::iterator iter;
 			for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
 			{
@@ -1785,6 +2087,8 @@ void LLPipeline::postSort(LLCamera& camera)
 					gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
 				}
 			}
+			// now deal with highlights for all those seeable sound sources
+			forAllVisibleDrawables(renderSoundHighlights);
 		}
 	}
 
@@ -1815,7 +2119,7 @@ void LLPipeline::postSort(LLCamera& camera)
 }
 
 
-static void render_hud_elements()
+void render_hud_elements()
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_UI);
 	gPipeline.disableLights();		
@@ -1824,8 +2128,14 @@ static void render_hud_elements()
 
 	LLGLDisable fog(GL_FOG);
 	LLGLSUIDefault gls_ui;
+
+	LLGLEnable stencil(GL_STENCIL_TEST);
+	glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
+	glStencilMask(0xFFFFFFFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
 	
-	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+	gGL.start();
+	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 	{
 		gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
 	
@@ -1857,11 +2167,15 @@ static void render_hud_elements()
 	{
 		LLHUDText::renderAllHUD();
 	}
+	gGL.stop();
 }
 
 void LLPipeline::renderHighlights()
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+	assertInitialized();
+
 	// Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
 	// Render highlighted faces.
 	LLColor4 color(1.f, 1.f, 1.f, 0.5f);
@@ -1871,7 +2185,7 @@ void LLPipeline::renderHighlights()
 	if ((LLShaderMgr::sVertexShaderLevel[LLShaderMgr::SHADER_INTERFACE] > 0))
 	{
 		gHighlightProgram.bind();
-		gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
+		gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
 	}
 	
 	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
@@ -1883,7 +2197,8 @@ void LLPipeline::renderHighlights()
 		}
 		mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
 
-		for (U32 i = 0; i < mSelectedFaces.size(); i++)
+		U32 count = mSelectedFaces.size();
+		for (U32 i = 0; i < count; i++)
 		{
 			LLFace *facep = mSelectedFaces[i];
 			if (!facep || facep->getDrawable()->isDead())
@@ -1900,7 +2215,12 @@ void LLPipeline::renderHighlights()
 	{
 		// Paint 'em red!
 		color.setVec(1.f, 0.f, 0.f, 0.5f);
-		for (U32 i = 0; i < mHighlightFaces.size(); i++)
+		if ((LLShaderMgr::sVertexShaderLevel[LLShaderMgr::SHADER_INTERFACE] > 0))
+		{
+			gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
+		}
+		int count = mHighlightFaces.size();
+		for (S32 i = 0; i < count; i++)
 		{
 			LLFace* facep = mHighlightFaces[i];
 			facep->renderSelected(LLViewerImage::sNullImagep, color);
@@ -1917,11 +2237,26 @@ void LLPipeline::renderHighlights()
 	}
 }
 
-void LLPipeline::renderGeom(LLCamera& camera)
+void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 	LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY);
-	
+
+	assertInitialized();
+
+	F64 saved_modelview[16];
+	F64 saved_projection[16];
+
+	//HACK: preserve/restore matrices around HUD render
+	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+	{
+		for (U32 i = 0; i < 16; i++)
+		{
+			saved_modelview[i] = gGLModelView[i];
+			saved_projection[i] = gGLProjection[i];
+		}
+	}
+
 	if (!mAlphaSizzleImagep)
 	{
 		mAlphaSizzleImagep = gImageList.getImage(LLUUID(gViewerArt.getString("alpha_sizzle.tga")), MIPMAP_TRUE, TRUE);
@@ -1952,11 +2287,8 @@ void LLPipeline::renderGeom(LLCamera& camera)
 		}
 	}
 
-	{
-		//LLFastTimer ftm(LLFastTimer::FTM_TEMP6);
-		LLVertexBuffer::startRender();
-	}
-
+	LLVertexBuffer::startRender();
+	
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 	{
 		LLDrawPool *poolp = *iter;
@@ -1966,6 +2298,14 @@ void LLPipeline::renderGeom(LLCamera& camera)
 		}
 	}
 
+	//by bao
+	//fake vertex buffer updating
+	//to guaranttee at least updating one VBO buffer every frame
+	//to walk around the bug caused by ATI card --> DEV-3855
+	//
+	if(forceVBOUpdate)
+		gSky.mVOSkyp->updateDummyVertexBuffer() ;
+
 	gFrameStats.start(LLFrameStats::RENDER_GEOM);
 
 	// Initialize lots of GL state to "safe" values
@@ -1976,13 +2316,18 @@ void LLPipeline::renderGeom(LLCamera& camera)
 	LLGLSPipeline gls_pipeline;
 	
 	LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
-	// LLGLState normalize(GL_NORMALIZE, TRUE);
-			
+				
 	// Toggle backface culling for debugging
 	LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
 	// Set fog
-	LLGLEnable fog_enable(hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG) ? GL_FOG : 0);
+	BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
+	LLGLEnable fog_enable(use_fog &&
+						  !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
 	gSky.updateFog(camera.getFar());
+	if (!use_fog)
+	{
+		sUnderWaterRender = FALSE;
+	}
 
 	LLViewerImage::sDefaultImagep->bind(0);
 	LLViewerImage::sDefaultImagep->setClamp(FALSE, FALSE);
@@ -1993,13 +2338,10 @@ void LLPipeline::renderGeom(LLCamera& camera)
 	//
 	//	
 	stop_glerror();
-	BOOL did_hud_elements = LLDrawPoolWater::sSkipScreenCopy;
-	BOOL occlude = sUseOcclusion;
-
+	BOOL occlude = sUseOcclusion > 1;
+	
 	U32 cur_type = 0;
 
-	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PICKING))
 	{
 		gObjectList.renderObjectsForSelect(camera);
@@ -2008,6 +2350,8 @@ void LLPipeline::renderGeom(LLCamera& camera)
 	{
 		LLFastTimer t(LLFastTimer::FTM_POOLS);
 		calcNearbyLights(camera);
+		setupHWLights(NULL);
+
 		pool_set_t::iterator iter1 = mPools.begin();
 		while ( iter1 != mPools.end() )
 		{
@@ -2018,23 +2362,18 @@ void LLPipeline::renderGeom(LLCamera& camera)
 			if (occlude && cur_type > LLDrawPool::POOL_AVATAR)
 			{
 				occlude = FALSE;
+				gGLLastMatrix = NULL;
+				glLoadMatrixd(gGLModelView);
 				doOcclusion(camera);
 			}
 
-			if (cur_type > LLDrawPool::POOL_ALPHA_POST_WATER && !did_hud_elements)
-			{
-				renderHighlights();
-				// Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
-				render_hud_elements();
-				did_hud_elements = TRUE;
-			}
-
 			pool_set_t::iterator iter2 = iter1;
 			if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
 			{
 				LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
 
-				setupHWLights(poolp);
+				gGLLastMatrix = NULL;
+				glLoadMatrixd(gGLModelView);
 			
 				for( S32 i = 0; i < poolp->getNumPasses(); i++ )
 				{
@@ -2049,11 +2388,10 @@ void LLPipeline::renderGeom(LLCamera& camera)
 						
 						p->resetTrianglesDrawn();
 						p->render(i);
-						mTrianglesDrawn += p->getTrianglesDrawn();
 					}
 					poolp->endRenderPass(i);
 #ifndef LL_RELEASE_FOR_DOWNLOAD
-#if LL_DEBUG_GL
+#	if LL_DEBUG_GL
 					GLint depth;
 					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
 					if (depth > 3)
@@ -2063,7 +2401,7 @@ void LLPipeline::renderGeom(LLCamera& camera)
 					LLGLState::checkStates();
 					LLGLState::checkTextureChannels();
 					LLGLState::checkClientArrays();
-#endif
+#	endif
 #endif
 				}
 			}
@@ -2090,94 +2428,69 @@ void LLPipeline::renderGeom(LLCamera& camera)
 	LLGLState::checkClientArrays();
 #endif
 
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+
 	if (occlude)
 	{
-		doOcclusion(camera);
 		occlude = FALSE;
-	}
-
-	if (!did_hud_elements)
-	{
-		renderHighlights();
-		render_hud_elements();
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
+		doOcclusion(camera);
 	}
 
 	stop_glerror();
-	
-	{
-		LLVertexBuffer::stopRender();
-	}
-	
+		
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
 		LLGLState::checkClientArrays();
 #endif
 	
+	if (!sReflectionRender)
+	{
+		renderHighlights();
+	}
+
 	// Contains a list of the faces of objects that are physical or
 	// have touch-handlers.
 	mHighlightFaces.clear();
 
-	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	render_hud_elements();
 
-	if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && 
-		!LLDrawPoolWater::sSkipScreenCopy &&
-		sRenderGlow &&
-		gGLManager.mHasFramebufferObject)
-	{
-		const U32 glow_res = nhpo2(gSavedSettings.getS32("RenderGlowResolution"));
-		if (mGlowMap == 0)
-		{
-			glGenTextures(1, &mGlowMap);
-			glBindTexture(GL_TEXTURE_2D, mGlowMap);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glow_res, glow_res, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-		}
+	LLVertexBuffer::stopRender();
+	LLVertexBuffer::unbind();
+	
 
-		if (mGlowBuffer == 0)
+	//HACK: preserve/restore matrices around HUD render
+	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+	{
+		for (U32 i = 0; i < 16; i++)
 		{
-			glGenTextures(1, &mGlowBuffer);
-			glBindTexture(GL_TEXTURE_2D, mGlowBuffer);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glow_res, glow_res, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+			gGLModelView[i] = saved_modelview[i];
+			gGLProjection[i] = saved_projection[i];
 		}
-
-		bindScreenToTexture();
-		renderBloom(mScreenTex, mGlowMap, mGlowBuffer, glow_res, LLVector2(0,0), mScreenScale);
 	}
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+#endif
 }
 
-void LLPipeline::processOcclusion(LLCamera& camera)
+void LLPipeline::addTrianglesDrawn(S32 count)
 {
-	//process occlusion (readback)
-	if (sUseOcclusion)
+	assertInitialized();
+	mTrianglesDrawn += count;
+	mBatchCount++;
+	mMaxBatchSize = llmax(mMaxBatchSize, count);
+	mMinBatchSize = llmin(mMinBatchSize, count);
+
+	if (LLPipeline::sRenderFrameTest)
 	{
-		for (U32 i = 0; i < mObjectPartition.size(); i++)
-		{
-			if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType))
-			{
-				mObjectPartition[i]->processOcclusion(&camera);
-			}
-		}
-		
-#if AGGRESSIVE_OCCLUSION
-		for (LLSpatialBridge::bridge_vector_t::iterator i = mOccludedBridge.begin(); i != mOccludedBridge.end(); ++i)
-		{
-			LLSpatialBridge* bridge = *i;
-			if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
-			{
-				LLCamera trans = bridge->transformCamera(camera);
-				bridge->processOcclusion(&trans);
-			}
-		}
-#endif
-		mOccludedBridge.clear();
+		gViewerWindow->getWindow()->swapBuffers();
+		ms_sleep(16);
 	}
 }
 
@@ -2185,24 +2498,41 @@ void LLPipeline::renderDebug()
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 
+	assertInitialized();
+
+	gGL.start();
+
 	// Disable all client state
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
+    //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    //glDisableClientState(GL_NORMAL_ARRAY);
+	//glDisableClientState(GL_COLOR_ARRAY);
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
 
 	// Debug stuff.
-	for (U32 i = 0; i < mObjectPartition.size(); i++)
+	for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
 	{
-		if (mObjectPartition[i] && hasRenderType(mObjectPartition[i]->mDrawableType))
+		LLViewerRegion* region = *iter;
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 		{
-			mObjectPartition[i]->renderDebug();
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
+			{
+				if (hasRenderType(part->mDrawableType))
+				{
+					part->renderDebug();
+				}
+			}
 		}
 	}
 
-	for (LLSpatialBridge::bridge_vector_t::iterator i = mVisibleBridge.begin(); i != mVisibleBridge.end(); ++i)
+	for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
-		if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+		if (!bridge->isDead() && !bridge->isState(LLSpatialGroup::OCCLUDED) && hasRenderType(bridge->mDrawableType))
 		{
 			glPushMatrix();
 			glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
@@ -2211,51 +2541,6 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_LIGHT_TRACE)
-	{
-		LLGLSNoTexture no_texture;
-
-		LLVector3 pos, pos1;
-
-		for (LLDrawable::drawable_vector_t::iterator iter = mVisibleList.begin();
-			 iter != mVisibleList.end(); iter++)
-		{
-			LLDrawable *drawablep = *iter;
-			if (drawablep->isDead())
-			{
-				continue;
-			}
-			for (LLDrawable::drawable_set_t::iterator iter = drawablep->mLightSet.begin();
-				 iter != drawablep->mLightSet.end(); iter++)
-			{
-				LLDrawable *targetp = *iter;
-				if (targetp->isDead() || !targetp->getVObj()->getNumTEs())
-				{
-					continue;
-				}
-				else
-				{
-					if (targetp->getTextureEntry(0))
-					{
-						if (drawablep->getVObj()->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
-						{
-							glColor4f(0.f, 1.f, 0.f, 1.f);
-							gObjectList.addDebugBeacon(drawablep->getPositionAgent(), "TC");
-						}
-						else
-						{
-							glColor4fv (targetp->getTextureEntry(0)->getColor().mV);
-						}
-						glBegin(GL_LINES);
-						glVertex3fv(targetp->getPositionAgent().mV);
-						glVertex3fv(drawablep->getPositionAgent().mV);
-						glEnd();
-					}
-				}
-			}
-		}
-	}
-
 	if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
 	{
 		// Debug composition layers
@@ -2263,9 +2548,9 @@ void LLPipeline::renderDebug()
 
 		LLGLSNoTexture gls_no_texture;
 
-		glBegin(GL_POINTS);
 		if (gAgent.getRegion())
 		{
+			gGL.begin(GL_POINTS);
 			// Draw the composition layer for the region that I'm in.
 			for (x = 0; x <= 260; x++)
 			{
@@ -2273,29 +2558,40 @@ void LLPipeline::renderDebug()
 				{
 					if ((x > 255) || (y > 255))
 					{
-						glColor4f(1.f, 0.f, 0.f, 1.f);
+						gGL.color4f(1.f, 0.f, 0.f, 1.f);
 					}
 					else
 					{
-						glColor4f(0.f, 0.f, 1.f, 1.f);
+						gGL.color4f(0.f, 0.f, 1.f, 1.f);
 					}
 					F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
 					z *= 5.f;
 					z += 50.f;
-					glVertex3f(x, y, z);
+					gGL.vertex3f(x, y, z);
 				}
 			}
+			gGL.end();
 		}
-		glEnd();
 	}
+	gGL.stop();
 }
 
 void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects)
 {
-	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	
-	LLVertexBuffer::startRender();
-	
+	assertInitialized();
+
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+	gPipeline.resetDrawOrders();
+
+	for (std::set<LLViewerObject*>::iterator iter = objects.begin(); iter != objects.end(); ++iter)
+	{
+		stateSort((*iter)->mDrawable, *gCamera);
+	}
+
+	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+	
+	LLVertexBuffer::startRender();
+	
 	glMatrixMode(GL_MODELVIEW);
 
 	LLGLSDefault gls_default;
@@ -2319,7 +2615,10 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects)
 		{
 			LLFacePool* face_pool = (LLFacePool*) poolp;
 			face_pool->renderForSelect();
-		
+	
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 			if (poolp->getType() != last_type)
 			{
@@ -2330,9 +2629,8 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects)
 			}
 #endif
 		}
-	}
+	}	
 
-	LLGLEnable tex(GL_TEXTURE_2D);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	LLGLEnable alpha_test(GL_ALPHA_TEST);
 	if (gPickTransparent)
@@ -2387,11 +2685,16 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects)
 	LLVOAvatar* avatarp = gAgent.getAvatarObject();
 	if (avatarp && sShowHUDAttachments)
 	{
-		glMatrixMode(GL_PROJECTION);
-		glPushMatrix();
-		glMatrixMode(GL_MODELVIEW);
-		glPushMatrix();
+		glh::matrix4f save_proj(glh_get_current_projection());
+		glh::matrix4f save_model(glh_get_current_modelview());
 
+		U32 viewport[4];
+
+		for (U32 i = 0; i < 4; i++)
+		{
+			viewport[i] = gGLViewport[i];
+		}
+		
 		setup_hud_matrices(TRUE);
 		for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); 
 			 iter != avatarp->mAttachmentPoints.end(); )
@@ -2436,15 +2739,27 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects)
 		}
 
 		glMatrixMode(GL_PROJECTION);
-		glPopMatrix();
+		glLoadMatrixf(save_proj.m);
+		glh_set_current_projection(save_proj);
+
 		glMatrixMode(GL_MODELVIEW);
-		glPopMatrix();
+		glLoadMatrixf(save_model.m);
+		glh_set_current_modelview(save_model);
+
+	
+		for (U32 i = 0; i < 4; i++)
+		{
+			gGLViewport[i] = viewport[i];
+		}
+		glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 	}
 
 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
 	
 	LLVertexBuffer::stopRender();
+
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 }
 
 void LLPipeline::renderFaceForUVSelect(LLFace* facep)
@@ -2455,6 +2770,9 @@ void LLPipeline::renderFaceForUVSelect(LLFace* facep)
 void LLPipeline::rebuildPools()
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+	assertInitialized();
+
 	S32 max_count = mPools.size();
 	pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
 	while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
@@ -2492,6 +2810,9 @@ void LLPipeline::rebuildPools()
 void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+	assertInitialized();
+
 	switch( new_poolp->getType() )
 	{
 	case LLDrawPool::POOL_SIMPLE:
@@ -2506,6 +2827,18 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		break;
 
+	case LLDrawPool::POOL_INVISIBLE:
+		if (mInvisiblePool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate simple pool." << llendl;
+		}
+		else
+		{
+			mInvisiblePool = (LLRenderPass*) new_poolp;
+		}
+		break;
+
 	case LLDrawPool::POOL_GLOW:
 		if (mGlowPool)
 		{
@@ -2550,18 +2883,6 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		break;
 
-	case LLDrawPool::POOL_ALPHA_POST_WATER:
-		if( mAlphaPoolPostWater )
-		{
-			llassert(0);
-			llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
-		}
-		else
-		{
-			mAlphaPoolPostWater = new_poolp;
-		}
-		break;
-
 	case LLDrawPool::POOL_AVATAR:
 		break; // Do nothing
 
@@ -2576,18 +2897,6 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 			mSkyPool = new_poolp;
 		}
 		break;
-
-	case LLDrawPool::POOL_STARS:
-		if( mStarsPool )
-		{
-			llassert(0);
-			llwarns << "LLPipeline::addPool(): Ignoring duplicate Stars pool" << llendl;
-		}
-		else
-		{
-			mStarsPool = new_poolp;
-		}
-		break;
 	
 	case LLDrawPool::POOL_WATER:
 		if( mWaterPool )
@@ -2613,6 +2922,18 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		break;
 
+	case LLDrawPool::POOL_WL_SKY:
+		if( mWLSkyPool )
+		{
+			llassert(0);
+			llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
+		}
+		else
+		{ 
+			mWLSkyPool = new_poolp;
+		}
+		break;
+
 	default:
 		llassert(0);
 		llwarns << "Invalid Pool Type in  LLPipeline::addPool()" << llendl;
@@ -2622,6 +2943,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 
 void LLPipeline::removePool( LLDrawPool* poolp )
 {
+	assertInitialized();
 	removeFromQuickLookup(poolp);
 	mPools.erase(poolp);
 	delete poolp;
@@ -2629,6 +2951,7 @@ void LLPipeline::removePool( LLDrawPool* poolp )
 
 void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 {
+	assertInitialized();
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
 	switch( poolp->getType() )
 	{
@@ -2637,6 +2960,16 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mSimplePool = NULL;
 		break;
 
+	case LLDrawPool::POOL_INVISIBLE:
+		llassert(mInvisiblePool == poolp);
+		mInvisiblePool = NULL;
+		break;
+
+	case LLDrawPool::POOL_WL_SKY:
+		llassert(mWLSkyPool == poolp);
+		mWLSkyPool = NULL;
+		break;
+
 	case LLDrawPool::POOL_GLOW:
 		llassert(mGlowPool == poolp);
 		mGlowPool = NULL;
@@ -2674,11 +3007,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mAlphaPool = NULL;
 		break;
 
-	case LLDrawPool::POOL_ALPHA_POST_WATER:
-		llassert( poolp == mAlphaPoolPostWater );
-		mAlphaPoolPostWater = NULL;
-		break;
-
 	case LLDrawPool::POOL_AVATAR:
 		break; // Do nothing
 
@@ -2687,11 +3015,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mSkyPool = NULL;
 		break;
 
-	case LLDrawPool::POOL_STARS:
-		llassert( poolp == mStarsPool );
-		mStarsPool = NULL;
-		break;
-
 	case LLDrawPool::POOL_WATER:
 		llassert( poolp == mWaterPool );
 		mWaterPool = NULL;
@@ -2711,6 +3034,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 
 void LLPipeline::resetDrawOrders()
 {
+	assertInitialized();
 	// Iterate through all of the draw pools and rebuild them.
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 	{
@@ -2725,7 +3049,7 @@ void LLPipeline::resetDrawOrders()
 
 void LLPipeline::setupAvatarLights(BOOL for_edit)
 {
-	const LLColor4 black(0,0,0,1);
+	assertInitialized();
 
 	if (for_edit)
 	{
@@ -2740,8 +3064,8 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 
 		mHWLightColors[1] = diffuse;
 		glLightfv(GL_LIGHT1, GL_DIFFUSE,  diffuse.mV);
-		glLightfv(GL_LIGHT1, GL_AMBIENT,  black.mV);
-		glLightfv(GL_LIGHT1, GL_SPECULAR, black.mV);
+		glLightfv(GL_LIGHT1, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
 		glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV); 
 		glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION,  1.0f);
 		glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 	 0.0f);
@@ -2756,7 +3080,7 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 		LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
 		backlight_pos.normVec();
 			
-		LLColor4 light_diffuse = mSunDiffuse * mSunShadowFactor;
+		LLColor4 light_diffuse = mSunDiffuse;
 		LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
 		F32 max_component = 0.001f;
 		for (S32 i = 0; i < 3; i++)
@@ -2780,8 +3104,8 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 		mHWLightColors[1] = backlight_diffuse;
 		glLightfv(GL_LIGHT1, GL_POSITION, backlight_pos.mV); // this is just sun/moon direction
 		glLightfv(GL_LIGHT1, GL_DIFFUSE,  backlight_diffuse.mV);
-		glLightfv(GL_LIGHT1, GL_AMBIENT,  black.mV);
-		glLightfv(GL_LIGHT1, GL_SPECULAR, black.mV);
+		glLightfv(GL_LIGHT1, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
 		glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION,  1.0f);
 		glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION,    0.0f);
 		glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
@@ -2790,10 +3114,10 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 	}
 	else
 	{
-		mHWLightColors[1] = black;
-		glLightfv(GL_LIGHT1, GL_DIFFUSE,  black.mV);
-		glLightfv(GL_LIGHT1, GL_AMBIENT,  black.mV);
-		glLightfv(GL_LIGHT1, GL_SPECULAR, black.mV);
+		mHWLightColors[1] = LLColor4::black;
+		glLightfv(GL_LIGHT1, GL_DIFFUSE,  LLColor4::black.mV);
+		glLightfv(GL_LIGHT1, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
 	}
 }
 
@@ -2829,13 +3153,15 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_
 
 void LLPipeline::calcNearbyLights(LLCamera& camera)
 {
+	assertInitialized();
+
 	if (mLightingDetail >= 1)
 	{
 		// mNearbyLight (and all light_set_t's) are sorted such that
 		// begin() == the closest light and rbegin() == the farthest light
 		const S32 MAX_LOCAL_LIGHTS = 6;
 // 		LLVector3 cam_pos = gAgent.getCameraPositionAgent();
-		LLVector3 cam_pos = LLPipeline::sSkipUpdate || LLViewerJoystick::sOverrideCamera ?
+		LLVector3 cam_pos = LLViewerJoystick::sOverrideCamera ?
 						camera.getOrigin() : 
 						gAgent.getPositionAgent();
 
@@ -2933,7 +3259,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
 
 void LLPipeline::setupHWLights(LLDrawPool* pool)
 {
-	const LLColor4 black(0,0,0,1);
+	assertInitialized();
 
 	// Ambient
 	LLColor4 ambient = gSky.getTotalAmbientColor();
@@ -2941,7 +3267,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 
 	// Light 0 = Sun or Moon (All objects)
 	{
-		mSunShadowFactor = 1.f; // no shadowing by defailt
 		if (gSky.getSunDirection().mV[2] >= NIGHTTIME_ELEVATION_COS)
 		{
 			mSunDir.setVec(gSky.getSunDirection());
@@ -2950,7 +3275,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		else
 		{
 			mSunDir.setVec(gSky.getMoonDirection());
-			mSunDiffuse.setVec(gSky.getMoonDiffuseColor() * 1.5f);
+			mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
 		}
 
 		F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
@@ -2961,12 +3286,12 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		mSunDiffuse.clamp();
 
 		LLVector4 light_pos(mSunDir, 0.0f);
-		LLColor4 light_diffuse = mSunDiffuse * mSunShadowFactor;
+		LLColor4 light_diffuse = mSunDiffuse;
 		mHWLightColors[0] = light_diffuse;
 		glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); // this is just sun/moon direction
 		glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse.mV);
-		glLightfv(GL_LIGHT0, GL_AMBIENT,  black.mV);
-		glLightfv(GL_LIGHT0, GL_SPECULAR, black.mV);
+		glLightfv(GL_LIGHT0, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV);
 		glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION,  1.0f);
 		glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION,    0.0f);
 		glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);
@@ -3002,7 +3327,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			LLColor4  light_color = light->getLightColor();
 			light_color.mV[3] = 0.0f;
 
-			F32 fade = LLPipeline::sSkipUpdate ? 1.f : iter->fade;
+			F32 fade = iter->fade;
 			if (fade < LIGHT_FADE_TIME)
 			{
 				// fade in/out light
@@ -3043,8 +3368,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			S32 gllight = GL_LIGHT0+cur_light;
 			glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
 			glLightfv(gllight, GL_DIFFUSE,  light_color.mV);
-			glLightfv(gllight, GL_AMBIENT,  black.mV);
-			glLightfv(gllight, GL_SPECULAR, black.mV);
+			glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
+			glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
 			glLightf (gllight, GL_CONSTANT_ATTENUATION,   0.0f);
 			glLightf (gllight, GL_LINEAR_ATTENUATION,     atten);
 			glLightf (gllight, GL_QUADRATIC_ATTENUATION,  quad);
@@ -3059,11 +3384,41 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 	}
 	for ( ; cur_light < 8 ; cur_light++)
 	{
-		mHWLightColors[cur_light] = black;
+		mHWLightColors[cur_light] = LLColor4::black;
 		S32 gllight = GL_LIGHT0+cur_light;
-		glLightfv(gllight, GL_DIFFUSE,  black.mV);
-		glLightfv(gllight, GL_AMBIENT,  black.mV);
-		glLightfv(gllight, GL_SPECULAR, black.mV);
+		glLightfv(gllight, GL_DIFFUSE,  LLColor4::black.mV);
+		glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
+	}
+
+	if (gAgent.getAvatarObject() &&
+		gAgent.getAvatarObject()->mSpecialRenderMode == 3)
+	{
+		LLColor4  light_color = LLColor4::white;
+		light_color.mV[3] = 0.0f;
+
+		LLVector3 light_pos(gCamera->getOrigin());
+		LLVector4 light_pos_gl(light_pos, 1.0f);
+
+		F32 light_radius = 16.f;
+		F32 atten, quad;
+
+		{
+			F32 x = 3.f;
+			atten = x / (light_radius); // % of brightness at radius
+			quad = 0.0f;
+		}
+		//mHWLightColors[cur_light] = light_color;
+		S32 gllight = GL_LIGHT2;
+		glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
+		glLightfv(gllight, GL_DIFFUSE,  light_color.mV);
+		glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
+		glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
+		glLightf (gllight, GL_CONSTANT_ATTENUATION,   0.0f);
+		glLightf (gllight, GL_LINEAR_ATTENUATION,     atten);
+		glLightf (gllight, GL_QUADRATIC_ATTENUATION,  quad);
+		glLightf (gllight, GL_SPOT_EXPONENT,          0.0f);
+		glLightf (gllight, GL_SPOT_CUTOFF,            180.0f);
 	}
 
 	// Init GL state
@@ -3075,8 +3430,9 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 	mLightMask = 0;
 }
 
-void LLPipeline::enableLights(U32 mask, F32 shadow_factor)
+void LLPipeline::enableLights(U32 mask)
 {
+	assertInitialized();
 	if (mLightingDetail == 0)
 	{
 		mask &= 0xf003; // sun and backlight only (and fullbright bit)
@@ -3113,8 +3469,9 @@ void LLPipeline::enableLights(U32 mask, F32 shadow_factor)
 	}
 }
 
-void LLPipeline::enableLightsStatic(F32 shadow_factor)
+void LLPipeline::enableLightsStatic()
 {
+	assertInitialized();
 	U32 mask = 0x01; // Sun
 	if (mLightingDetail >= 2)
 	{
@@ -3125,39 +3482,55 @@ void LLPipeline::enableLightsStatic(F32 shadow_factor)
 	{
 		mask |= 0xff & (~2); // Hardware local lights
 	}
-	enableLights(mask, shadow_factor);
+	enableLights(mask);
 }
 
-void LLPipeline::enableLightsDynamic(F32 shadow_factor)
+void LLPipeline::enableLightsDynamic()
 {
+	assertInitialized();
 	U32 mask = 0xff & (~2); // Local lights
-	enableLights(mask, shadow_factor);
+	enableLights(mask);
 	if (mLightingDetail >= 2)
 	{
 		glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
 	}
+
+	LLVOAvatar* avatarp = gAgent.getAvatarObject();
+
+	if (avatarp && getLightingDetail() <= 0)
+	{
+		if (avatarp->mSpecialRenderMode == 0) // normal
+		{
+			gPipeline.enableLightsAvatar();
+		}
+		else if (avatarp->mSpecialRenderMode >= 1)  // anim preview
+		{
+			gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
+		}
+	}
 }
 
-void LLPipeline::enableLightsAvatar(F32 shadow_factor)
+void LLPipeline::enableLightsAvatar()
 {
 	U32 mask = 0xff; // All lights
 	setupAvatarLights(FALSE);
-	enableLights(mask, shadow_factor);
+	enableLights(mask);
 }
 
 void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
 {
 	U32 mask = 0x2002; // Avatar backlight only, set ambient
 	setupAvatarLights(TRUE);
-	enableLights(mask, 1.0f);
+	enableLights(mask);
 
 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
 }
 
 void LLPipeline::enableLightsFullbright(const LLColor4& color)
 {
+	assertInitialized();
 	U32 mask = 0x1000; // Non-0 mask, set ambient
-	enableLights(mask, 1.f);
+	enableLights(mask);
 
 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
 	if (mLightingDetail >= 2)
@@ -3168,19 +3541,10 @@ void LLPipeline::enableLightsFullbright(const LLColor4& color)
 
 void LLPipeline::disableLights()
 {
-	enableLights(0, 0.f); // no lighting (full bright)
+	enableLights(0); // no lighting (full bright)
 	glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
 }
 
-// Call *after*s etting up lights
-void LLPipeline::setAmbient(const LLColor4& ambient)
-{
-	mLightMask |= 0x4000; // tweak mask so that ambient will get reset
-	LLColor4 amb = ambient + gSky.getTotalAmbientColor();
-	amb.clamp();
-	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,amb.mV);
-}
-
 //============================================================================
 
 class LLMenuItemGL;
@@ -3188,55 +3552,10 @@ class LLInvFVBridge;
 struct cat_folder_pair;
 class LLVOBranch;
 class LLVOLeaf;
-class Foo;
-
-void scale_stamp(const F32 x, const F32 y, const F32 xs, const F32 ys)
-{
-	stamp(0.25f + 0.5f*x,
-		  0.5f + 0.45f*y,
-		  0.5f*xs,
-		  0.45f*ys);
-}
-
-void drawBars(const F32 begin, const F32 end, const F32 height = 1.f)
-{
-	if (begin >= 0 && end <=1)
-	{
-		F32 lines  = 40.0f;
-		S32 ibegin = (S32)(begin * lines);
-		S32 iend   = (S32)(end   * lines);
-		F32 fbegin = begin * lines - ibegin;
-		F32 fend   = end   * lines - iend;
-
-		F32 line_height = height/lines;
-
-		if (iend == ibegin)
-		{
-			scale_stamp(fbegin, (F32)ibegin/lines,fend-fbegin, line_height);
-		}
-		else
-		{
-			// Beginning row
-			scale_stamp(fbegin, (F32)ibegin/lines,  1.0f-fbegin, line_height);
-
-			// End row
-			scale_stamp(0.0,    (F32)iend/lines,  fend, line_height);
-
-			// Middle rows
-			for (S32 l = (ibegin+1); l < iend; l++)
-			{
-				scale_stamp(0.0f, (F32)l/lines, 1.0f, line_height);
-			}
-		}
-	}
-}
 
 void LLPipeline::findReferences(LLDrawable *drawablep)
 {
-	if (std::find(mVisibleList.begin(), mVisibleList.end(), drawablep) != mVisibleList.end())
-	{
-		llinfos << "In mVisibleList" << llendl;
-	}
+	assertInitialized();
 	if (mLights.find(drawablep) != mLights.end())
 	{
 		llinfos << "In mLights" << llendl;
@@ -3278,13 +3597,16 @@ void LLPipeline::findReferences(LLDrawable *drawablep)
 
 BOOL LLPipeline::verify()
 {
-	BOOL ok = TRUE;
-	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+	BOOL ok = assertInitialized();
+	if (ok) 
 	{
-		LLDrawPool *poolp = *iter;
-		if (!poolp->verify())
+		for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 		{
-			ok = FALSE;
+			LLDrawPool *poolp = *iter;
+			if (!poolp->verify())
+			{
+				ok = FALSE;
+			}
 		}
 	}
 
@@ -3396,7 +3718,7 @@ bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3&
 
 void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
 {
-	if (drawablep)
+	if (drawablep && assertInitialized())
 	{
 		if (is_light)
 		{
@@ -3408,12 +3730,12 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
 			drawablep->clearState(LLDrawable::LIGHT);
 			mLights.erase(drawablep);
 		}
-		markRelight(drawablep);
 	}
 }
 
 void LLPipeline::setActive(LLDrawable *drawablep, BOOL active)
 {
+	assertInitialized();
 	if (active)
 	{
 		mActiveQ.insert(drawablep);
@@ -3634,7 +3956,22 @@ BOOL LLPipeline::getProcessBeacons(void* data)
 
 LLViewerObject* LLPipeline::pickObject(const LLVector3 &start, const LLVector3 &end, LLVector3 &collision)
 {
-	LLDrawable* drawable = mObjectPartition[PARTITION_VOLUME]->pickDrawable(start, end, collision);
+	LLDrawable* drawable = NULL;
+
+	for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
+	{
+		LLViewerRegion* region = *iter;
+		LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
+		if (part)
+		{
+			LLDrawable* hit = part->pickDrawable(start, end, collision);
+			if (hit)
+			{
+				drawable = hit;
+			}
+		}
+	}
 	return drawable ? drawable->getVObj().get() : NULL;
 }
 
@@ -3642,31 +3979,23 @@ LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
 {
 	if (vobj)
 	{
-		return getSpatialPartition(vobj->getPartitionType());
+		LLViewerRegion* region = vobj->getRegion();
+		if (region)
+		{
+			return region->getSpatialPartition(vobj->getPartitionType());
+		}
 	}
 	return NULL;
 }
 
-LLSpatialPartition* LLPipeline::getSpatialPartition(U32 type)
-{
-	if (type < mObjectPartition.size())
-	{
-		return mObjectPartition[type];
-	}
-	return NULL;
-}
 
-void LLPipeline::clearRenderMap()
+void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
 {
-	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+	if (!drawable || drawable->isDead())
 	{
-		mRenderMap[i].clear();
+		return;
 	}
-}
 
-
-void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
-{
 	if (!drawable)
 	{
 		return;
@@ -3682,36 +4011,63 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
 
 void LLPipeline::resetVertexBuffers()
 {
-	for (U32 i = 0; i < mObjectPartition.size(); ++i)
+	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+
+	if (gWorldp)
 	{
-		if (mObjectPartition[i])
+		for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+				iter != gWorldp->getRegionList().end(); ++iter)
 		{
-			mObjectPartition[i]->resetVertexBuffers();
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+			{
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{
+					part->resetVertexBuffers();
+				}
+			}
 		}
 	}
 
 	resetDrawOrders();
 
-	if (gSky.mVOSkyp.notNull())
+	gSky.resetVertexBuffers();
+
+	if (LLVertexBuffer::sGLCount > 0)
 	{
-		resetVertexBuffers(gSky.mVOSkyp->mDrawable);
-		resetVertexBuffers(gSky.mVOGroundp->mDrawable);
-		resetVertexBuffers(gSky.mVOStarsp->mDrawable);
-		markRebuild(gSky.mVOSkyp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-		markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-		markRebuild(gSky.mVOStarsp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+		LLVertexBuffer::cleanupClass();
 	}
 
+	//delete all name pool caches
+	LLGLNamePool::cleanupPools();
+
 	if (LLVertexBuffer::sGLCount > 0)
 	{
-		LLVertexBuffer::cleanupClass();
+		llwarns << "VBO wipe failed." << llendl;
+	}
+
+	if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() ||
+		!LLVertexBuffer::sStreamVBOPool.mNameList.empty() ||
+		!LLVertexBuffer::sDynamicIBOPool.mNameList.empty() ||
+		!LLVertexBuffer::sDynamicVBOPool.mNameList.empty())
+	{
+		llwarns << "VBO name pool cleanup failed." << llendl;
 	}
+
+	LLVertexBuffer::unbind();
+
+	LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
 }
 
 void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
 {
-	mSimplePool->renderStatic(type, mask, texture);
-	mSimplePool->renderActive(type, mask, texture);
+	assertInitialized();
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLLastModelView);
+	mSimplePool->renderGroups(type, mask, texture);
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLLastModelView);
 }
 
 void LLPipeline::setUseVBO(BOOL use_vbo)
@@ -3759,26 +4115,42 @@ void apply_cube_face_rotation(U32 face)
 		break;
 	}
 }
-void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam, GLsizei res)
+void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam)
 {
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+#endif
+
+	assertInitialized();
+
 	//render dynamic cube map
 	U32 type_mask = gPipeline.getRenderTypeMask();
-	BOOL use_occlusion = LLPipeline::sUseOcclusion;
-	LLPipeline::sUseOcclusion = FALSE;
+	S32 use_occlusion = LLPipeline::sUseOcclusion;
+	LLPipeline::sUseOcclusion = 0;
 	LLPipeline::sSkipUpdate = TRUE;
-	static GLuint blur_tex = 0;
-	if (!blur_tex)
-	{
-		glGenTextures(1, &blur_tex);
-	}
+	U32 res = REFLECTION_MAP_RES;
 
-	BOOL reattach = FALSE;
-	if (mCubeFrameBuffer == 0)
-	{
-		glGenFramebuffersEXT(1, &mCubeFrameBuffer);
-		glGenRenderbuffersEXT(1, &mCubeDepth);
-		reattach = TRUE;
+	LLPipeline::sReflectionRender = TRUE;
+
+	cube_map->bind();
+	GLint width;
+	glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_TEXTURE_WIDTH, &width);
+	if (width != res)
+	{
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		
+		for (U32 i = 0; i < 6; i++)
+		{
+			glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
+		}
 	}
+	glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);
+	cube_map->disable();
 
 	BOOL toggle_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
 	if (toggle_ui)
@@ -3788,10 +4160,9 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 	
 	U32 cube_mask = (1 << LLPipeline::RENDER_TYPE_SIMPLE) |
 					(1 << LLPipeline::RENDER_TYPE_WATER) |
-					(1 << LLPipeline::RENDER_TYPE_BUMP) |
+					//(1 << LLPipeline::RENDER_TYPE_BUMP) |
 					(1 << LLPipeline::RENDER_TYPE_ALPHA) |
 					(1 << LLPipeline::RENDER_TYPE_TREE) |
-					(1 << LLDrawPool::POOL_ALPHA_POST_WATER) |
 					//(1 << LLPipeline::RENDER_TYPE_PARTICLES) |
 					(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
 					//(1 << LLPipeline::RENDER_TYPE_STARS) |
@@ -3801,9 +4172,11 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 					(1 << LLPipeline::RENDER_TYPE_VOLUME) |
 					(1 << LLPipeline::RENDER_TYPE_TERRAIN) |
 					(1 << LLPipeline::RENDER_TYPE_SKY) |
+					(1 << LLPipeline::RENDER_TYPE_WL_SKY) |
 					(1 << LLPipeline::RENDER_TYPE_GROUND);
 	
 	LLDrawPoolWater::sSkipScreenCopy = TRUE;
+	LLPipeline::sSkipUpdate = TRUE;
 	cube_mask = cube_mask & type_mask;
 	gPipeline.setRenderTypeMask(cube_mask);
 
@@ -3816,57 +4189,23 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 	
 	glClearColor(0,0,0,0);			
 	
-	U32 cube_face[] = 
-	{
-		GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
-		GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
-		GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
-	};
-	
 	LLVector3 origin = cube_cam.getOrigin();
 
 	gPipeline.calcNearbyLights(cube_cam);
 
-	cube_map->bind();
-	for (S32 i = 0; i < 6; i++)
-	{
-		GLint res_x, res_y;
-		glGetTexLevelParameteriv(cube_face[i], 0, GL_TEXTURE_WIDTH, &res_x);
-		glGetTexLevelParameteriv(cube_face[i], 0, GL_TEXTURE_HEIGHT, &res_y);
-
-		if (res_x != res || res_y != res)
-		{
-			glTexImage2D(cube_face[i],0,GL_RGBA,res,res,0,GL_RGBA,GL_FLOAT,NULL);
-			reattach = TRUE;
-		}
-	}
-	cube_map->disable();
-
-	if (reattach)
-	{
-		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mCubeDepth);
-		GLint res_x, res_y;
-		glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_WIDTH_EXT, &res_x);
-		glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &res_y);
-
-		if (res_x != res || res_y != res)
-		{
-			glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,res,res);
-		}
-		
-		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-	}
+	stop_glerror();
+	LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubeFrameBuffer);
+	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+										GL_RENDERBUFFER_EXT, mCubeDepth);		
+	stop_glerror();
 
 	for (S32 i = 0; i < 6; i++)
 	{
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubeFrameBuffer);
 		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-									cube_face[i], cube_map->getGLName(), 0);
-		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-										GL_RENDERBUFFER_EXT, mCubeDepth);		
+									gl_cube_face[i], cube_map->getGLName(), 0);
+		validate_framebuffer_object();
 		glMatrixMode(GL_PROJECTION);
 		glLoadIdentity();
 		gluPerspective(90.f, 1.f, 0.1f, 1024.f);
@@ -3879,23 +4218,29 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 		cube_cam.setOrigin(origin);
 		LLViewerCamera::updateFrustumPlanes(cube_cam);
 		cube_cam.setOrigin(gCamera->getOrigin());
-		gPipeline.updateCull(cube_cam);
-		gPipeline.stateSort(cube_cam);
+		static LLCullResult result;
+		gPipeline.updateCull(cube_cam, result);
+		gPipeline.stateSort(cube_cam, result);
 		
+		glClearColor(0,0,0,0);
+		glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
 		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+		glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
+		stop_glerror();
 		gPipeline.renderGeom(cube_cam);
 	}
 
 	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 
 	cube_cam.setOrigin(origin);
-	gPipeline.resetDrawOrders();
 	gShinyOrigin.setVec(cube_cam.getOrigin(), cube_cam.getFar()*2.f);
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
 
+	gViewerWindow->setupViewport();
+
 	gPipeline.setRenderTypeMask(type_mask);
 	LLPipeline::sUseOcclusion = use_occlusion;
 	LLPipeline::sSkipUpdate = FALSE;
@@ -3905,12 +4250,21 @@ void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam,
 		gPipeline.toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
 	}
 	LLDrawPoolWater::sSkipScreenCopy = FALSE;
+	LLPipeline::sSkipUpdate = FALSE;
+	LLPipeline::sReflectionRender = FALSE;
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+#endif
+
 }
 
 //send cube map vertices and texture coordinates
 void render_cube_map()
 {
-	U32 idx[36];
+	U16 idx[36];
 
 	idx[0] = 1; idx[1] = 0; idx[2] = 2; //front
 	idx[3] = 3; idx[4] = 2; idx[5] = 0;
@@ -3943,18 +4297,54 @@ void render_cube_map()
 	vert[6] = r.scaledVec(LLVector3(-1,-1,-1)); //  6 - right bottom back
 	vert[7] = r.scaledVec(LLVector3(1,-1,-1)); // 7 -left bottom back
 
-	glBegin(GL_TRIANGLES);
-	for (U32 i = 0; i < 36; i++)
-	{
-		glTexCoord3fv(vert[idx[i]].mV);
-		glVertex3fv(vert[idx[i]].mV);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glTexCoordPointer(3, GL_FLOAT, 0, vert);
+	glVertexPointer(3, GL_FLOAT, 0, vert);
+
+	glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (GLushort*) idx);
+
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void validate_framebuffer_object()
+{                                                           
+	GLenum status;                                            
+	status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 
+	switch(status) 
+	{                                          
+		case GL_FRAMEBUFFER_COMPLETE_EXT:                       
+			//framebuffer OK, no error.
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+			// frame buffer not OK: probably means unsupported depth buffer format
+			llerrs << "Framebuffer Incomplete Dimensions." << llendl;
+			break;
+		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+			// frame buffer not OK: probably means unsupported depth buffer format
+			llerrs << "Framebuffer Incomplete Attachment." << llendl;
+			break; 
+		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:                    
+			/* choose different formats */                        
+			llerrs << "Framebuffer unsupported." << llendl;
+			break;                                                
+		default:                                                
+			llerrs << "Unknown framebuffer status." << llendl;
+			break;
 	}
-	glEnd();
 }
 
-void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32 res)
+void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out)
 {
-	LLGLEnable cube(GL_TEXTURE_CUBE_MAP_ARB);
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+#endif
+
+	assertInitialized();
+
+	U32 res = (U32) gSavedSettings.getS32("RenderReflectionRes");
+	enableLightsFullbright(LLColor4::white);
 	LLGLDepthTest depth(GL_FALSE);
 	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 	glMatrixMode(GL_PROJECTION);
@@ -3964,27 +4354,33 @@ void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32
 	glMatrixMode(GL_MODELVIEW);
 	glPushMatrix();
 
+	cube_out->enableTexture(0);
+	cube_out->bind();
+	GLint width;
+	glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_TEXTURE_WIDTH, &width);
+	if (width != res)
+	{
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		
+		for (U32 i = 0; i < 6; i++)
+		{
+			glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
+		}
+	}
+	glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);
+
 	glViewport(0, 0, res, res);
 	LLGLEnable blend(GL_BLEND);
 	
 	S32 kernel = 2;
 	F32 step = 90.f/res;
-	F32 alpha = 1.f/((kernel*2)+1);
-
-	glColor4f(alpha,alpha,alpha,alpha*1.25f);
-
-	S32 x = 0;
-
-	U32 cube_face[] = 
-	{
-		GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
-		GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
-		GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
-		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
-	};
+	F32 alpha = 1.f / ((kernel*2)+1);
 
+	gGL.color4f(alpha,alpha,alpha,alpha*1.25f);
+	
 	LLVector3 axis[] = 
 	{
 		LLVector3(1,0,0),
@@ -3992,117 +4388,121 @@ void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32
 		LLVector3(0,0,1)
 	};
 
-	
-	glBlendFunc(GL_ONE, GL_ONE);
+	stop_glerror();
+	glViewport(0,0,res, res);
+	gGL.blendFunc(GL_ONE, GL_ONE);
+	cube_in->enableTexture(0);
 	//3-axis blur
 	for (U32 j = 0; j < 3; j++)
 	{
-		glViewport(0,0,res, res*6);
-		glClear(GL_COLOR_BUFFER_BIT);
+		stop_glerror();
+
 		if (j == 0)
 		{
 			cube_in->bind();
 		}
+		else
+		{
+			glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mBlurCubeTexture[j-1]);
+		}
+
+		stop_glerror();
+
+		LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mBlurCubeBuffer[j]);
+		stop_glerror();
 
 		for (U32 i = 0; i < 6; i++)
 		{
-			glViewport(0,i*res, res, res);
+			stop_glerror();
+			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 
+								GL_COLOR_ATTACHMENT0_EXT,
+								gl_cube_face[i], 
+								j < 2 ? mBlurCubeTexture[j] : cube_out->getGLName(), 0);
+			validate_framebuffer_object();
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+			glClear(GL_COLOR_BUFFER_BIT);
 			glLoadIdentity();
 			apply_cube_face_rotation(i);
-			for (x = -kernel; x <= kernel; ++x)
+			for (S32 x = -kernel; x <= kernel; ++x)
 			{
 				glPushMatrix();
 				glRotatef(x*step, axis[j].mV[0], axis[j].mV[1], axis[j].mV[2]);
 				render_cube_map();
 				glPopMatrix();
 			}
+			stop_glerror();
 		}	
-
-		//readback
-		if (j == 0)
-		{
-			cube_out->bind();
-		}
-		for (U32 i = 0; i < 6; i++)
-		{
-			glCopyTexImage2D(cube_face[i], 0, GL_RGBA, 0, i*res, res, res, 0);
-		}
 	}
-	
-	glMatrixMode(GL_PROJECTION);
+
+	stop_glerror();
+
+	glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);
+	
+	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
+	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
 
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	glClear(GL_COLOR_BUFFER_BIT);
+	cube_in->disableTexture();
+	gViewerWindow->setupViewport();
+	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+#endif
 }
 
 void LLPipeline::bindScreenToTexture() 
 {
-	LLGLEnable gl_texture_2d(GL_TEXTURE_2D);
-
-	GLint* viewport = (GLint*) gGLViewport;
-	GLuint resX = nhpo2(viewport[2]);
-	GLuint resY = nhpo2(viewport[3]);
+	
+}
 
-	if (mScreenTex == 0)
+void LLPipeline::renderBloom(BOOL for_snapshot)
+{
+	if (!(gPipeline.canUseVertexShaders() &&
+		sRenderGlow &&
+		gGLManager.mHasFramebufferObject))
 	{
-		glGenTextures(1, &mScreenTex);
-		glBindTexture(GL_TEXTURE_2D, mScreenTex);
-		
-		gImageList.updateMaxResidentTexMem(-1, resX*resY*3);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resX, resY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		return;
 	}
 
-	glBindTexture(GL_TEXTURE_2D, mScreenTex);
-	GLint cResX;
-	GLint cResY;
-	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cResX);
-	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cResY);
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+#endif
+
+	assertInitialized();
 
-	if (cResX != (GLint)resX || cResY != (GLint)resY)
+	if (gUseWireframe)
 	{
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, resX, resY, 0, GL_RGB, GL_FLOAT, NULL);
-		gImageList.updateMaxResidentTexMem(-1, resX*resY*3);
+		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 	}
 
-	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, viewport[0], viewport[1], 0, 0, viewport[2], viewport[3]); 
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
 
-	
-	mScreenScale.mV[0] = (float) viewport[2]/resX;
-	mScreenScale.mV[1] = (float) viewport[3]/resY;
-	
-	LLImageGL::sBoundTextureMemory += resX * resY * 3;
-}
+	LLVector2 tc1(0,0);
+	LLVector2 tc2((F32) gViewerWindow->getWindowDisplayWidth(),
+					(F32) gViewerWindow->getWindowDisplayHeight());
 
-void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res, LLVector2 tc1, LLVector2 tc2)
-{
-	gGlowProgram.bind();
+	if (res_mod > 1)
+	{
+		tc2 /= (F32) res_mod;
+	}
 
-	LLGLEnable tex(GL_TEXTURE_2D);
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+		
+	LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM);
+	gGL.start();
 	LLGLDepthTest depth(GL_FALSE);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable cull(GL_CULL_FACE);
-
-	if (mFramebuffer[0] == 0)
-	{
-		glGenFramebuffersEXT(2, mFramebuffer);
-	}
-
-	GLint viewport[4];
-	glGetIntegerv(GL_VIEWPORT, viewport);
-	glViewport(0,0,res,res);
+	
+	enableLightsFullbright(LLColor4(1,1,1,1));
 
 	glMatrixMode(GL_PROJECTION);
 	glPushMatrix();
@@ -4111,82 +4511,774 @@ void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res,
 	glPushMatrix();
 	glLoadIdentity();
 
-	glBindTexture(GL_TEXTURE_2D, source);
-	
-	S32 kernel = gSavedSettings.getS32("RenderGlowSize")*2;
-	
 	LLGLDisable test(GL_ALPHA_TEST);
 
-	F32 delta = 1.f/(res*gSavedSettings.getF32("RenderGlowStrength"));
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	glClearColor(0,0,0,0);
+
+	if (for_snapshot)
+	{
+		mGlow[1].bindTexture();
+		{
+			//LLGLEnable stencil(GL_STENCIL_TEST);
+			//glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
+			//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+			//LLGLDisable blend(GL_BLEND);
+			LLGLEnable blend(GL_BLEND);
+			gGL.blendFunc(GL_ONE, GL_ONE);
+			tc2.setVec(1,1);				
+			gGL.begin(GL_TRIANGLE_STRIP);
+			gGL.color4f(1,1,1,1);
+			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+			gGL.vertex2f(-1,-1);
+			
+			gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+			gGL.vertex2f(-1,1);
+			
+			gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+			gGL.vertex2f(1,-1);
+			
+			gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+			gGL.vertex2f(1,1);
+			gGL.end();
 
-	for (S32 i = 0; i < kernel; i++)
+			gGL.flush();
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		}
+
+		gGL.stop();
+		glMatrixMode(GL_PROJECTION);
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+
+		return;
+	}
+	
 	{
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebuffer[i%2]);
-		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 
-								GL_COLOR_ATTACHMENT0_EXT,
-								GL_TEXTURE_2D, 
-								i%2 == 0 ? buffer : dest, 0);
+		{
+			LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO);
+			mGlow[2].bindTarget();
+			mGlow[2].clear();
+		}
+		
+		gGlowExtractProgram.bind();
+		F32 minLum = llclamp(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f, 1.0f);
+		F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");		
+		F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");	
+		LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
+		LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
+		gGlowExtractProgram.uniform1f("minLuminance", minLum);
+		gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha);
+		gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
+		gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
+		gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount);
+		LLGLEnable blend_on(GL_BLEND);
+		LLGLEnable test(GL_ALPHA_TEST);
+		glAlphaFunc(GL_GREATER, 0.f);
+		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
+		LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+		
+		glDisable(GL_TEXTURE_2D);
+		glEnable(GL_TEXTURE_RECTANGLE_ARB);
+		mScreen.bindTexture();
+
+		gGL.color4f(1,1,1,1);
+		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+		gGL.begin(GL_TRIANGLE_STRIP);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
+		
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,1);
 		
-		glBindTexture(GL_TEXTURE_2D, i == 0 ? source : 
-									i%2==0 ? dest :
-									buffer);
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(1,-1);
 		
-		glUniform1fARB(gGlowProgram.mUniform[LLShaderMgr::GLOW_DELTA],delta);					
+		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+		gGL.vertex2f(1,1);
+		gGL.end();
+		
+		glEnable(GL_TEXTURE_2D);
+		glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+		mGlow[2].flush();
+	}
+
+	tc1.setVec(0,0);
+	tc2.setVec(1,1);
+
+
+
+	// power of two between 1 and 1024
+	U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
+	const U32 glow_res = llmax(1, 
+		llmin(1024, 1 << glowResPow));
+
+	S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2;
+	F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res;
+	// Use half the glow width if we have the res set to less than 9 so that it looks
+	// almost the same in either case.
+	if (glowResPow < 9)
+	{
+		delta *= 0.5f;
+	}
+	F32 strength = gSavedSettings.getF32("RenderGlowStrength");
+
+	gGlowProgram.bind();
+	gGlowProgram.uniform1f("glowStrength", strength);
+
+	for (S32 i = 0; i < kernel; i++)
+	{
+		LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+		{
+			LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO);
+			mGlow[i%2].bindTarget();
+			mGlow[i%2].clear();
+		}
+			
+		if (i == 0)
+		{
+			mGlow[2].bindTexture();
+		}
+		else
+		{
+			mGlow[(i-1)%2].bindTexture();
+		}
+
+		if (i%2 == 0)
+		{
+			gGlowProgram.uniform2f("glowDelta", delta, 0);
+		}
+		else
+		{
+			gGlowProgram.uniform2f("glowDelta", 0, delta);
+		}
 
-		glBegin(GL_TRIANGLE_STRIP);
-		glTexCoord2f(tc1.mV[0], tc1.mV[1]);
-		glVertex2f(-1,-1);
+		gGL.begin(GL_TRIANGLE_STRIP);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
 		
-		glTexCoord2f(tc1.mV[0], tc2.mV[1]);
-		glVertex2f(-1,1);
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,1);
 		
-		glTexCoord2f(tc2.mV[0], tc1.mV[1]);
-		glVertex2f(1,-1);
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(1,-1);
 		
-		glTexCoord2f(tc2.mV[0], tc2.mV[1]);
-		glVertex2f(1,1);
-		glEnd();
-	
-		tc1.setVec(0,0);
-		tc2.setVec(1,1);
+		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+		gGL.vertex2f(1,1);
+		gGL.end();
 		
+		mGlow[i%2].flush();
 	}
 
-	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 	gGlowProgram.unbind();
 
-	glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+	if (LLRenderTarget::sUseFBO)
+	{
+		LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO);
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	}
+
+	gViewerWindow->setupViewport();
 
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_GLOW))
+	/*mGlow[1].bindTexture();
 	{
-		glClear(GL_COLOR_BUFFER_BIT);
+		LLGLEnable stencil(GL_STENCIL_TEST);
+		glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
+		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+		LLGLDisable blend(GL_BLEND);
+			
+		gGL.begin(GL_TRIANGLE_STRIP);
+		gGL.color4f(1,1,1,1);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
+		
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,1);
+		
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(1,-1);
+		
+		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+		gGL.vertex2f(1,1);
+		gGL.end();
+
+		gGL.flush();
 	}
 
-	glBindTexture(GL_TEXTURE_2D, dest);
+	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_GLOW))
 	{
+		tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(),
+				(F32) gViewerWindow->getWindowDisplayHeight());
+
+		if (res_mod > 1)
+		{
+			tc2 /= (F32) res_mod;
+		}
+
 		LLGLEnable blend(GL_BLEND);
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+		gGL.blendFunc(GL_ONE, GL_ONE);
 
-		glBegin(GL_TRIANGLE_STRIP);
-		glColor4f(1,1,1,1);
-		glTexCoord2f(tc1.mV[0], tc1.mV[1]);
-		glVertex2f(-1,-1);
+		glDisable(GL_TEXTURE_2D);
+		glEnable(GL_TEXTURE_RECTANGLE_ARB);
+		mScreen.bindTexture();
+		
+		gGL.begin(GL_TRIANGLE_STRIP);
+		gGL.color4f(1,1,1,1);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
 		
-		glTexCoord2f(tc1.mV[0], tc2.mV[1]);
-		glVertex2f(-1,1);
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,1);
 		
-		glTexCoord2f(tc2.mV[0], tc1.mV[1]);
-		glVertex2f(1,-1);
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(1,-1);
 		
-		glTexCoord2f(tc2.mV[0], tc2.mV[1]);
-		glVertex2f(1,1);
-		glEnd();
+		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+		gGL.vertex2f(1,1);
+		gGL.end();
 
-		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		gGL.flush();
+		
+		glEnable(GL_TEXTURE_2D);
+		glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	}*/
+	gGL.stop();
+	
+	{
+		LLVertexBuffer::unbind();
+
+		F32 uv0[] = 
+		{
+				tc1.mV[0], tc1.mV[1],
+				tc1.mV[0], tc2.mV[1],
+				tc2.mV[0], tc1.mV[1],
+				tc2.mV[0], tc2.mV[1]
+		};
+		
+		tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(),
+			(F32) gViewerWindow->getWindowDisplayHeight());
+
+		if (res_mod > 1)
+		{
+			tc2 /= (F32) res_mod;
+		}
+
+		F32 uv1[] = 
+		{
+				tc1.mV[0], tc1.mV[1],
+				tc1.mV[0], tc2.mV[1],
+				tc2.mV[0], tc1.mV[1],
+				tc2.mV[0], tc2.mV[1]
+		};
+
+		F32 v[] = 
+		{
+			-1,-1,
+			-1,1,
+			1,-1,
+			1,1
+		};
+		
+		LLGLDisable blend(GL_BLEND);
+
+
+		//tex unit 0
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+		
+		mGlow[1].bindTexture();
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, 0, uv0);
+		glActiveTextureARB(GL_TEXTURE1_ARB);
+		glEnable(GL_TEXTURE_RECTANGLE_ARB);
+		
+		//tex unit 1
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
+		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+		
+		glClientActiveTextureARB(GL_TEXTURE1_ARB);
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, 0, uv1);
+
+		glVertexPointer(2, GL_FLOAT, 0, v);
+		
+		mScreen.bindTexture();
+		
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		
+		glDisable(GL_TEXTURE_RECTANGLE_ARB);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+		glActiveTextureARB(GL_TEXTURE0_ARB);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	}
+	
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+#endif
+
+}
+
+void LLPipeline::processImagery(LLCamera& camera)
+{
+	for (LLWorld::region_list_t::iterator iter = gWorldp->getRegionList().begin(); 
+			iter != gWorldp->getRegionList().end(); ++iter)
+	{
+		LLViewerRegion* region = *iter;
+		LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
+		if (part)
+		{
+			part->processImagery(&camera);	
+		}
+	}
+}
+
+
+inline float sgn(float a)
+{
+    if (a > 0.0F) return (1.0F);
+    if (a < 0.0F) return (-1.0F);
+    return (0.0F);
+}
+
+void LLPipeline::generateWaterReflection(LLCamera& camera_in)
+{
+	if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+	{
+		LLCamera camera = camera_in;
+		camera.setFar(camera.getFar()*0.87654321f);
+		LLPipeline::sReflectionRender = TRUE;
+		S32 occlusion = LLPipeline::sUseOcclusion;
+		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+		U32 type_mask = gPipeline.mRenderTypeMask;
+
+		glh::matrix4f projection = glh_get_current_projection();
+		glh::matrix4f mat;
+
+		stop_glerror();
+		LLPlane plane;
+
+		F32 height = gAgent.getRegion()->getWaterHeight(); 
+		F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
+		F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
+
+		//plane params
+		LLVector3 pnorm;
+		F32 pd;
+
+		S32 water_clip = 0;
+		if (!gCamera->cameraUnderWater())
+		{ //camera is above water, clip plane points up
+			pnorm.setVec(0,0,1);
+			pd = -height;
+			plane.setVec(pnorm, pd);
+			water_clip = -1;
+		}
+		else
+		{	//camera is below water, clip plane points down
+			pnorm = LLVector3(0,0,-1);
+			pd = height;
+			plane.setVec(pnorm, pd);
+			water_clip = 1;
+		}
+
+
+
+		if (!gCamera->cameraUnderWater())
+		{	//generate planar reflection map
+			LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+			glClearColor(0,0,0,0);
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+			mWaterRef.bindTarget();
+			mWaterRef.getViewport(gGLViewport);
+			mWaterRef.clear();
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
+
+			stop_glerror();
+
+			LLVector3 origin = camera.getOrigin();
+
+			glPushMatrix();
+
+			mat.set_scale(glh::vec3f(1,1,-1));
+			mat.set_translate(glh::vec3f(0,0,height*2.f));
+			
+			glh::matrix4f current = glh_get_current_modelview();
+
+			mat = current * mat;
+
+			glh_set_current_modelview(mat);
+			glLoadMatrixf(mat.m);
+
+			LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
+
+			glCullFace(GL_FRONT);
+
+			//initial sky pass (no user clip plane)
+			{ //mask out everything but the sky
+				U32 tmp = mRenderTypeMask;
+				mRenderTypeMask &= ((1 << LLPipeline::RENDER_TYPE_SKY) |
+									(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+
+				static LLCullResult result;
+				updateCull(camera, result);
+				stateSort(camera, result);
+				renderGeom(camera, TRUE);
+
+				mRenderTypeMask = tmp;
+			}
+
+			if (LLDrawPoolWater::sNeedsReflectionUpdate)
+			{
+				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_WATER) |
+									  (1<<LLPipeline::RENDER_TYPE_GROUND) |
+									  (1<<LLPipeline::RENDER_TYPE_SKY) |
+									  (1<<LLPipeline::RENDER_TYPE_CLOUDS) |
+									  (1<<LLPipeline::RENDER_TYPE_WL_SKY));	
+
+				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				{ //mask out selected geometry based on reflection detail
+
+					S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
+					if (detail < 3)
+					{
+						mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_PARTICLES);
+						if (detail < 2)
+						{
+							mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_AVATAR);
+							if (detail < 1)
+							{
+								mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_VOLUME);
+							}
+						}
+					}
+
+					LLSpatialPartition::sFreezeState = TRUE;
+					LLPipeline::sSkipUpdate = TRUE;
+					LLGLUserClipPlane clip_plane(plane, mat, projection);
+					static LLCullResult result;
+					updateCull(camera, result, 1);
+					stateSort(camera, result);
+					renderGeom(camera);
+					LLSpatialPartition::sFreezeState = FALSE;
+					LLPipeline::sSkipUpdate = FALSE;
+				}
+			}	
+			glCullFace(GL_BACK);
+			glPopMatrix();
+			mWaterRef.flush();
+
+			glh_set_current_modelview(current);
+		}
+
+		//render distortion map
+		static BOOL last_update = TRUE;
+		if (last_update)
+		{
+			camera.setFar(camera_in.getFar());
+			mRenderTypeMask = type_mask & (~(1<<LLPipeline::RENDER_TYPE_WATER) |
+											(1<<LLPipeline::RENDER_TYPE_GROUND));	
+			stop_glerror();
+
+			LLPipeline::sUnderWaterRender = gCamera->cameraUnderWater() ? FALSE : TRUE;
+
+			if (LLPipeline::sUnderWaterRender)
+			{
+				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_GROUND) |
+									  (1<<LLPipeline::RENDER_TYPE_SKY) |
+									  (1<<LLPipeline::RENDER_TYPE_CLOUDS) |
+									  (1<<LLPipeline::RENDER_TYPE_WL_SKY));		
+			}
+			LLViewerCamera::updateFrustumPlanes(camera);
+
+			LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+			LLColor4& col = LLDrawPoolWater::sWaterFogColor;
+			glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+			mWaterDis.bindTarget();
+			mWaterDis.getViewport(gGLViewport);
+			mWaterDis.clear();
+			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
+
+			if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
+			{
+				//clip out geometry on the same side of water as the camera
+				mat = glh_get_current_modelview();
+				LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection);
+				static LLCullResult result;
+				updateCull(camera, result, water_clip);
+				stateSort(camera, result);
+				renderGeom(camera);
+			}
+
+			LLPipeline::sUnderWaterRender = FALSE;
+			mWaterDis.flush();
+		}
+		last_update = LLDrawPoolWater::sNeedsReflectionUpdate;
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		LLPipeline::sReflectionRender = FALSE;
+
+		if (!LLRenderTarget::sUseFBO)
+		{
+			glClear(GL_DEPTH_BUFFER_BIT);
+		}
+		glClearColor(0.f, 0.f, 0.f, 0.f);
+
+		gViewerWindow->setupViewport();
+		mRenderTypeMask = type_mask;
+		LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
+		gCamera->setUserClipPlane(LLPlane(-pnorm, -pd));
+		LLPipeline::sUseOcclusion = occlusion;
+	}
+}
+
+LLCubeMap* LLPipeline::findReflectionMap(const LLVector3& location)
+{
+	LLViewerRegion* region = gWorldp->getRegionFromPosAgent(location);
+	if (region)
+	{
+		LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
+		if (part)
+		{
+			LLSpatialGroup::OctreeNode* node = part->mOctree->getNodeAt(LLVector3d(location), 32.0);
+			if (node)
+			{
+				LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+				return group->mReflectionMap;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+S32 LLPipeline::getVisibleCount() const 
+{ 
+	return sCull->getVisibleListSize();
+}
+
+void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
+{
+#if !LL_RELEASE_FOR_DOWNLOAD
+	LLGLState::checkClientArrays(mask);
+#endif
+
+	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+	{
+		LLSpatialGroup* group = *i;
+		if (!group->isDead() &&
+			(!sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) &&
+			gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
+			group->mDrawMap.find(type) != group->mDrawMap.end())
+		{
+			pass->renderGroup(group,type,mask,texture);
+		}
+	}
+}
+
+void LLPipeline::generateImpostor(LLVOAvatar* avatar)
+{
+	static LLCullResult result;
+	result.clear();
+	grabReferences(result);
+	
+	if (!avatar || !avatar->mDrawable)
+	{
+		return;
+	}
+
+	assertInitialized();
+
+	if (!avatar->mImpostor.isComplete())
+	{
+		avatar->mImpostor.allocate(128,256,GL_RGBA,TRUE);
+		avatar->mImpostor.bindTexture();
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
+	}
+
+	U32 mask = (1<<LLPipeline::RENDER_TYPE_VOLUME) |
+				(1<<LLPipeline::RENDER_TYPE_AVATAR) |
+				(1<<LLPipeline::RENDER_TYPE_BUMP) |
+				(1<<LLPipeline::RENDER_TYPE_GRASS) |
+				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
+				(1<<LLPipeline::RENDER_TYPE_INVISIBLE);
+	
+	mask = mask & gPipeline.getRenderTypeMask();
+	U32 saved_mask = gPipeline.mRenderTypeMask;
+	gPipeline.mRenderTypeMask = mask;
+
+	S32 occlusion = sUseOcclusion;
+	sUseOcclusion = 0;
+	sReflectionRender = TRUE;
+	sImpostorRender = TRUE;
+
+	markVisible(avatar->mDrawable, *gCamera);
+	LLVOAvatar::sUseImpostors = FALSE;
+
+	LLVOAvatar::attachment_map_t::iterator iter;
+	for (iter = avatar->mAttachmentPoints.begin();
+		iter != avatar->mAttachmentPoints.end();
+		++iter)
+	{
+		LLViewerObject* object = iter->second->getObject();
+		if (object)
+		{
+			markVisible(object->mDrawable->getSpatialBridge(), *gCamera);
+		}
+	}
+
+	stateSort(*gCamera, result);
+	
+	glClearColor(0.0f,0.0f,0.0f,0.0f);
+	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	glStencilMask(0xFFFFFFFF);
+	glClearStencil(0);
+
+	{
+		LLGLEnable scissor(GL_SCISSOR_TEST);
+		glScissor(0, 0, 128, 256);
+		avatar->mImpostor.bindTarget();
+		avatar->mImpostor.getViewport(gGLViewport);
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+	}
+	
+	LLGLEnable stencil(GL_STENCIL_TEST);
+
+	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+	const LLVector3* ext = avatar->mDrawable->getSpatialExtents();
+	LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
+
+	LLCamera camera = *gCamera;
+
+	camera.lookAt(gCamera->getOrigin(), pos, gCamera->getUpAxis());
+	
+	LLVector2 tdim;
+
+	LLVector3 half_height = (ext[1]-ext[0])*0.5f;
+
+	LLVector3 left = camera.getLeftAxis();
+	left *= left;
+	left.normVec();
+
+	LLVector3 up = camera.getUpAxis();
+	up *= up;
+	up.normVec();
+
+	tdim.mV[0] = fabsf(half_height * left);
+	tdim.mV[1] = fabsf(half_height * up);
+
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glh::matrix4f ortho = gl_ortho(-tdim.mV[0], tdim.mV[0], -tdim.mV[1], tdim.mV[1], 1.0, 256.0);
+	glh_set_current_projection(ortho);
+	glLoadMatrixf(ortho.m);
+
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glh::matrix4f mat;
+	camera.getOpenGLTransform(mat.m);
+
+	mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
+
+	glLoadMatrixf(mat.m);
+	glh_set_current_modelview(mat);
+
+	renderGeom(camera);
+	
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+	glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
+
+	{
+		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+		LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
+		LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
+
+		LLGLEnable blend(GL_BLEND);
+		gGL.blendFunc(GL_ONE, GL_ONE);
+		LLImageGL::unbindTexture(0, GL_TEXTURE_2D);
+
+		LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+		gGL.start();
+		gGL.color4ub(0,0,0,1);
+		gGL.begin(GL_QUADS);
+		gGL.vertex3fv((pos+left-up).mV);
+		gGL.vertex3fv((pos-left-up).mV);
+		gGL.vertex3fv((pos-left+up).mV);
+		gGL.vertex3fv((pos+left+up).mV);
+		gGL.end();
+		gGL.stop();
+
+		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	}
+
+	avatar->mImpostor.flush();
+
+	avatar->setImpostorDim(tdim);
+
+	LLVOAvatar::sUseImpostors = TRUE;
+	sUseOcclusion = occlusion;
+	sReflectionRender = FALSE;
+	sImpostorRender = FALSE;
+	gPipeline.mRenderTypeMask = saved_mask;
 
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
+
+	avatar->mNeedsImpostorUpdate = FALSE;
+	avatar->cacheImpostorValues();
+}
+
+BOOL LLPipeline::hasRenderBatches(const U32 type) const
+{
+	return sCull->getRenderMapSize(type) > 0;
 }
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
+{
+	return sCull->beginRenderMap(type);
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
+{
+	return sCull->endRenderMap(type);
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
+{
+	return sCull->beginAlphaGroups();
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
+{
+	return sCull->endAlphaGroups();
+}
+
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 8b64b630161..32f5a7487ba 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -32,6 +32,7 @@
 #ifndef LL_PIPELINE_H
 #define LL_PIPELINE_H
 
+#include "llerror.h"
 #include "lldarrayptr.h"
 #include "lldqueueptr.h"
 #include "llstat.h"
@@ -43,9 +44,10 @@
 #include "llmemory.h"
 #include "lldrawpool.h"
 #include "llgl.h"
+#include "lldrawable.h"
+#include "llrendertarget.h"
 
 class LLViewerImage;
-class LLDrawable;
 class LLEdge;
 class LLFace;
 class LLViewerObject;
@@ -54,6 +56,8 @@ class LLDisplayPrimitive;
 class LLTextureEntry;
 class LLRenderFunc;
 class LLCubeMap;
+class LLCullResult;
+class LLVOAvatar;
 
 typedef enum e_avatar_skinning_method
 {
@@ -65,6 +69,11 @@ BOOL compute_min_max(LLMatrix4& box, LLVector2& min, LLVector2& max); // Shouldn
 bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon = 0);
 BOOL LLLineSegmentAABB(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
 BOOL setup_hud_matrices(BOOL for_select);
+glh::matrix4f glh_get_current_modelview();
+void glh_set_current_modelview(glh::matrix4f& mat);
+glh::matrix4f glh_get_current_projection();
+void glh_set_current_projection(glh::matrix4f& mat);
+glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
 
 class LLPipeline
 {
@@ -75,16 +84,23 @@ class LLPipeline
 	void destroyGL();
 	void restoreGL();
 	void resetVertexBuffers();
+	void resizeScreenTexture();
 	void releaseGLBuffers();
+	void createGLBuffers();
+
 	void resetVertexBuffers(LLDrawable* drawable);
 	void setUseVBO(BOOL use_vbo);
-	void generateReflectionMap(LLCubeMap* cube_map, LLCamera& camera, GLsizei res);
-	void blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out, U32 res);
+	void generateImpostor(LLVOAvatar* avatar);
+	void generateReflectionMap(LLCubeMap* cube_map, LLCamera& camera);
+	void blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out);
 	void bindScreenToTexture();
-	void renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res, LLVector2 tc1, LLVector2 tc2);
+	void renderBloom(BOOL for_snapshot);
+
+	LLCubeMap* findReflectionMap(const LLVector3& location);
 
 	void init();
 	void cleanup();
+	BOOL isInit() { return mInitialized; };
 
 	/// @brief Get a draw pool from pool type (POOL_SIMPLE, POOL_MEDIA) and texture.
 	/// @return Draw pool, or NULL if not found.
@@ -107,14 +123,14 @@ class LLPipeline
 
 	// Object related methods
 	void        markVisible(LLDrawable *drawablep, LLCamera& camera);
+	void		markOccluder(LLSpatialGroup* group);
 	void		doOcclusion(LLCamera& camera);
-	void		markNotCulled(LLSpatialGroup* group, LLCamera &camera, BOOL active = FALSE);
+	void		markNotCulled(LLSpatialGroup* group, LLCamera &camera);
 	void        markMoved(LLDrawable *drawablep, BOOL damped_motion = FALSE);
 	void        markShift(LLDrawable *drawablep);
 	void        markTextured(LLDrawable *drawablep);
 	void        markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE);
-	void        markRelight(LLDrawable *drawablep, const BOOL now = FALSE);
-	
+		
 	//get the object between start and end that's closest to start.  Return the point of collision in collision.
 	LLViewerObject* pickObject(const LLVector3 &start, const LLVector3 &end, LLVector3 &collision);
 
@@ -136,7 +152,9 @@ class LLPipeline
 	void		setUseVertexShaders(BOOL use_shaders);
 	BOOL		getUseVertexShaders() const { return mVertexShadersEnabled; }
 	BOOL		canUseVertexShaders();
-	
+	BOOL		canUseWindLightShaders() const;
+	BOOL		canUseWindLightShadersOnObjects() const;
+
 	// phases
 	void resetFrameStats();
 
@@ -144,26 +162,29 @@ class LLPipeline
 	void updateMoveNormalAsync(LLDrawable* drawablep);
 	void updateMovedList(LLDrawable::drawable_vector_t& move_list);
 	void updateMove();
-	void updateCull(LLCamera& camera);
+	void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
 	void updateGeom(F32 max_dtime);
 
 	//calculate pixel area of given box from vantage point of given camera
 	static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera);
 
-	void stateSort(LLCamera& camera);
+	void stateSort(LLCamera& camera, LLCullResult& result);
 	void stateSort(LLSpatialGroup* group, LLCamera& camera);
 	void stateSort(LLSpatialBridge* bridge, LLCamera& camera);
 	void stateSort(LLDrawable* drawablep, LLCamera& camera);
 	void postSort(LLCamera& camera);
-	void forAllDrawables(LLSpatialGroup::sg_vector_t& groups, void (*func)(LLDrawable*));
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
 	void renderObjects(U32 type, U32 mask, BOOL texture = TRUE);
+	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture);
 
-	void renderGeom(LLCamera& camera);
+	void grabReferences(LLCullResult& result);
+
+	void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
+	void processImagery(LLCamera& camera);
+	void generateWaterReflection(LLCamera& camera);
 	void renderHighlights();
 	void renderDebug();
-	void processOcclusion(LLCamera& camera);
 
 	void renderForSelect(std::set<LLViewerObject*>& objects);
 	void renderFaceForUVSelect(LLFace* facep);
@@ -172,29 +193,34 @@ class LLPipeline
 	void findReferences(LLDrawable *drawablep);	// Find the lists which have references to this object
 	BOOL verify();						// Verify that all data in the pipeline is "correct"
 
-	S32  getVisibleCount() const { return mVisibleList.size(); }
+	S32  getVisibleCount() const;
 	S32  getLightCount() const { return mLights.size(); }
 
 	void calcNearbyLights(LLCamera& camera);
 	void setupHWLights(LLDrawPool* pool);
 	void setupAvatarLights(BOOL for_edit = FALSE);
-	void enableLights(U32 mask, F32 shadow_factor);
-	void enableLightsStatic(F32 shadow_factor);
-	void enableLightsDynamic(F32 shadow_factor);
-	void enableLightsAvatar(F32 shadow_factor);
+	void enableLights(U32 mask);
+	void enableLightsStatic();
+	void enableLightsDynamic();
+	void enableLightsAvatar();
 	void enableLightsAvatarEdit(const LLColor4& color);
 	void enableLightsFullbright(const LLColor4& color);
 	void disableLights();
-	void setAmbient(const LLColor4& ambient);
 
 	void shiftObjects(const LLVector3 &offset);
 
 	void setLight(LLDrawable *drawablep, BOOL is_light);
 	void setActive(LLDrawable *drawablep, BOOL active);
 
+	BOOL hasRenderBatches(const U32 type) const;
+	LLCullResult::drawinfo_list_t::iterator beginRenderMap(U32 type);
+	LLCullResult::drawinfo_list_t::iterator endRenderMap(U32 type);
+	LLCullResult::sg_list_t::iterator beginAlphaGroups();
+	LLCullResult::sg_list_t::iterator endAlphaGroups();
+
+	void addTrianglesDrawn(S32 count);
 	BOOL hasRenderType(const U32 type) const				{ return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
 	BOOL hasRenderDebugFeatureMask(const U32 mask) const	{ return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
-	BOOL hasRenderFeatureMask(const U32 mask) const			{ return (mRenderFeatureMask & mask) ? TRUE : FALSE; }
 	BOOL hasRenderDebugMask(const U32 mask) const			{ return (mRenderDebugMask & mask) ? TRUE : FALSE; }
 	void setRenderTypeMask(const U32 mask)					{ mRenderTypeMask = mask; }
 	U32  getRenderTypeMask() const							{ return mRenderTypeMask; }
@@ -240,13 +266,12 @@ class LLPipeline
 	static BOOL getProcessBeacons(void* data);
 
 private:
-	void initShaders(BOOL force);
 	void unloadShaders();
-	BOOL loadShaders();
-	void saveVertexShaderLevel(S32 type, S32 level, S32 max);
 	void addToQuickLookup( LLDrawPool* new_poolp );
 	void removeFromQuickLookup( LLDrawPool* poolp );
 	BOOL updateDrawableGeom(LLDrawable* drawable, BOOL priority);
+	void assertInitializedDoError();
+	bool assertInitialized() { const bool is_init = isInit(); if (!is_init) assertInitializedDoError(); return is_init; };
 	
 public:
 	enum {GPU_CLASS_MAX = 3 };
@@ -255,17 +280,18 @@ class LLPipeline
 	{
 		// Following are pool types (some are also object types)
 		RENDER_TYPE_SKY			= LLDrawPool::POOL_SKY,
-		RENDER_TYPE_STARS		= LLDrawPool::POOL_STARS,
+		RENDER_TYPE_WL_SKY		= LLDrawPool::POOL_WL_SKY,
 		RENDER_TYPE_GROUND		= LLDrawPool::POOL_GROUND,	
 		RENDER_TYPE_TERRAIN		= LLDrawPool::POOL_TERRAIN,
 		RENDER_TYPE_SIMPLE		= LLDrawPool::POOL_SIMPLE,
 		RENDER_TYPE_BUMP		= LLDrawPool::POOL_BUMP,
 		RENDER_TYPE_AVATAR		= LLDrawPool::POOL_AVATAR,
 		RENDER_TYPE_TREE		= LLDrawPool::POOL_TREE,
+		RENDER_TYPE_INVISIBLE	= LLDrawPool::POOL_INVISIBLE,
 		RENDER_TYPE_WATER		= LLDrawPool::POOL_WATER,
  		RENDER_TYPE_ALPHA		= LLDrawPool::POOL_ALPHA,
 		RENDER_TYPE_GLOW		= LLDrawPool::POOL_GLOW,
-
+		
 		// Following are object types (only used in drawable mRenderType)
 		RENDER_TYPE_HUD = LLDrawPool::NUM_POOL_TYPES,
 		RENDER_TYPE_VOLUME,
@@ -288,58 +314,30 @@ class LLPipeline
 		RENDER_DEBUG_FEATURE_FOOT_SHADOWS		= 0x0100,
 	};
 
-	enum LLRenderFeatureMask
-	{
-		RENDER_FEATURE_LOCAL_LIGHTING		= 0x02,
-		RENDER_FEATURE_OBJECT_BUMP			= 0x04,
-		RENDER_FEATURE_AVATAR_BUMP			= 0x08,
-// 		RENDER_FEATURE_SHADOWS				= 0x10,
-		RENDER_FEATURE_RIPPLE_WATER			= 0X20
-	};
-
 	enum LLRenderDebugMask
 	{
-		RENDER_DEBUG_LIGHT_TRACE		= 0x00001,
-		RENDER_DEBUG_COMPOSITION		= 0x00020,
-		RENDER_DEBUG_VERIFY				= 0x00080,
-		RENDER_DEBUG_SHADOW_MAP			= 0x00100,
-		RENDER_DEBUG_BBOXES				= 0x00200,
-		RENDER_DEBUG_OCTREE				= 0x00400,
-		RENDER_DEBUG_PICKING			= 0x00800,
-		RENDER_DEBUG_OCCLUSION			= 0x01000,
-		RENDER_DEBUG_POINTS				= 0x02000,
-		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x04000,
-		RENDER_DEBUG_TEXTURE_AREA		= 0x08000,
-		RENDER_DEBUG_FACE_AREA			= 0x10000,
-		RENDER_DEBUG_PARTICLES			= 0x20000,
-		RENDER_DEBUG_GLOW				= 0x40000,
-		RENDER_DEBUG_TEXTURE_ANIM		= 0x80000,
+		RENDER_DEBUG_COMPOSITION		= 0x000020,
+		RENDER_DEBUG_VERIFY				= 0x000080,
+		RENDER_DEBUG_BBOXES				= 0x000200,
+		RENDER_DEBUG_OCTREE				= 0x000400,
+		RENDER_DEBUG_PICKING			= 0x000800,
+		RENDER_DEBUG_OCCLUSION			= 0x001000,
+		RENDER_DEBUG_POINTS				= 0x002000,
+		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x004000,
+		RENDER_DEBUG_TEXTURE_AREA		= 0x008000,
+		RENDER_DEBUG_FACE_AREA			= 0x010000,
+		RENDER_DEBUG_PARTICLES			= 0x020000,
+		RENDER_DEBUG_GLOW				= 0x040000,
+		RENDER_DEBUG_TEXTURE_ANIM		= 0x080000,
+		RENDER_DEBUG_LIGHTS				= 0x100000,
+		RENDER_DEBUG_BATCH_SIZE			= 0x200000,
 	};
 
 	LLPointer<LLViewerImage>	mAlphaSizzleImagep;
 
-	//MUST MATCH THE ORDER OF DECLARATION IN LLPipeline::init()
-	typedef enum 
-	{
-		PARTITION_VOLUME = 0,
-		PARTITION_BRIDGE,
-		PARTITION_HUD,
-		PARTITION_TERRAIN,
-		PARTITION_WATER,
-		PARTITION_TREE,
-		PARTITION_PARTICLE,
-		PARTITION_CLOUD,
-		PARTITION_GRASS,
-		PARTITION_NONE,
-		NUM_PARTITIONS
-	} eObjectPartitions;
-
-private:
-	std::vector<LLSpatialPartition*> mObjectPartition;
 public:
 	
 	LLSpatialPartition* getSpatialPartition(LLViewerObject* vobj);
-	LLSpatialPartition* getSpatialPartition(U32 index);
 
 	void updateCamera(BOOL reset = FALSE);
 	
@@ -347,7 +345,14 @@ class LLPipeline
 	LLQuaternion			mFlyCamRotation;
 
 	BOOL					 mBackfaceCull;
+	S32						 mBatchCount;
+	S32						 mMatrixOpCount;
+	S32						 mTextureMatrixOps;
+	S32						 mMaxBatchSize;
+	S32						 mMinBatchSize;
+	S32						 mMeanBatchSize;
 	S32						 mTrianglesDrawn;
+	S32						 mNumVisibleNodes;
 	LLStat                   mTrianglesDrawnStat;
 	S32						 mVerticesRelit;
 
@@ -359,25 +364,48 @@ class LLPipeline
 	static S32				sCompiles;
 
 	static BOOL				sShowHUDAttachments;
-	static BOOL				sUseOcclusion;
+	static S32				sUseOcclusion;  // 0 = no occlusion, 1 = read only, 2 = read/write
+	static BOOL				sFastAlpha;
+	static BOOL				sDisableShaders; // if TRUE, rendering will be done without shaders
+	static BOOL				sRenderBump;
+	static BOOL				sUseFBO;
+	static BOOL				sUseFarClip;
 	static BOOL				sSkipUpdate; //skip lod updates
 	static BOOL				sDynamicReflections;
+	static BOOL				sWaterReflections;
+	static BOOL				sDynamicLOD;
+	static BOOL				sReflectionRender;
+	static BOOL				sImpostorRender;
+	static BOOL				sUnderWaterRender;
 	static BOOL				sRenderGlow;
-
+	static BOOL				sTextureBindTest;
+	static BOOL				sRenderFrameTest;
+	
 	//screen texture
-	GLuint					mScreenTex;
+	LLRenderTarget			mScreen;
+	
 	LLVector2				mScreenScale;
 
-	//texture for making the glow
-	GLuint					mGlowMap;
-	GLuint					mGlowBuffer;
+	//water reflection texture
+	LLRenderTarget				mWaterRef;
+
+	//water distortion texture (refraction)
+	LLRenderTarget				mWaterDis;
 
+	//texture for making the glow
+	LLRenderTarget				mGlow[3];
+	
 	//framebuffer objects for off-screen scratch space
-	GLuint					mFramebuffer[2];
+	//GLuint					mFramebuffer[4];
+	//GLuint					mDepthbuffer[2];
 
 	//dynamic cube map scratch space
 	LLPointer<LLCubeMap>	mCubeBuffer;
 
+	//cube map anti-aliasing buffers
+	GLuint					mBlurCubeBuffer[3];
+	GLuint					mBlurCubeTexture[3];
+
 	//frambuffer object for rendering dynamic cube maps
 	GLuint					mCubeFrameBuffer;
 	
@@ -388,22 +416,12 @@ class LLPipeline
 	LLColor4				mSunDiffuse;
 	LLVector3				mSunDir;
 
-	LLSpatialGroup::sg_vector_t mActiveGroups;
-	LLSpatialGroup::drawmap_elem_t mRenderMap[LLRenderPass::NUM_RENDER_TYPES];	
-	std::vector<LLSpatialGroup* > mAlphaGroups;
-	std::vector<LLSpatialGroup* > mAlphaGroupsPostWater;
-	LLSpatialGroup::sg_vector_t mVisibleGroups;
-	LLSpatialGroup::sg_vector_t mDrawableGroups;
-
-	void clearRenderMap();
-
 	BOOL					mInitialized;
 	BOOL					mVertexShadersEnabled;
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
 
 protected:
 	U32						mRenderTypeMask;
-	U32						mRenderFeatureMask;
 	U32						mRenderDebugFeatureMask;
 	U32						mRenderDebugMask;
 
@@ -412,9 +430,6 @@ class LLPipeline
 	/////////////////////////////////////////////
 	//
 	//
-	LLDrawable::drawable_vector_t	mVisibleList;
-	LLSpatialBridge::bridge_vector_t mVisibleBridge;
-	LLSpatialBridge::bridge_vector_t mOccludedBridge;
 	LLDrawable::drawable_vector_t	mMovedList;
 	LLDrawable::drawable_vector_t mMovedBridge;
 	LLDrawable::drawable_vector_t	mShiftList;
@@ -457,7 +472,7 @@ class LLPipeline
 	//
 	LLDrawable::drawable_list_t 	mBuildQ1; // priority
 	LLDrawable::drawable_list_t 	mBuildQ2; // non-priority
-	
+		
 	LLDrawable::drawable_set_t		mActiveQ;
 	
 	LLDrawable::drawable_set_t		mRetexturedList;
@@ -496,15 +511,15 @@ class LLPipeline
 	std::map<uintptr_t, LLDrawPool*>	mTerrainPools;
 	std::map<uintptr_t, LLDrawPool*>	mTreePools;
 	LLDrawPool*					mAlphaPool;
-	LLDrawPool*					mAlphaPoolPostWater;
 	LLDrawPool*					mSkyPool;
-	LLDrawPool*					mStarsPool;
 	LLDrawPool*					mTerrainPool;
 	LLDrawPool*					mWaterPool;
 	LLDrawPool*					mGroundPool;
 	LLRenderPass*				mSimplePool;
+	LLDrawPool*					mInvisiblePool;
 	LLDrawPool*					mGlowPool;
 	LLDrawPool*					mBumpPool;
+	LLDrawPool*					mWLSkyPool;
 	// Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar
 	
 public:
@@ -519,8 +534,7 @@ class LLPipeline
 	U32						mLightMask;
 	U32						mLightMovingMask;
 	S32						mLightingDetail;
-	F32						mSunShadowFactor;
-	
+		
 	static BOOL				sRenderPhysicalBeacons;
 	static BOOL				sRenderScriptedTouchBeacons;
 	static BOOL				sRenderScriptedBeacons;
@@ -536,5 +550,6 @@ void render_bbox(const LLVector3 &min, const LLVector3 &max);
 
 extern LLPipeline gPipeline;
 extern BOOL gRenderForSelect;
+extern const LLMatrix4* gGLLastMatrix;
 
 #endif
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index a84942d7478..94688dd8bc9 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -56,6 +56,8 @@ def construct(self):
 
                         # include the entire shaders directory recursively
                         self.path("shaders")
+                        # ... and the entire windlight directory
+                        self.path("windlight")
                         self.end_prefix("app_settings")
 
                 if self.prefix(src="character"):
-- 
GitLab