PageRenderTime 204ms CodeModel.GetById 20ms app.highlight 167ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/lldrawpoolbump.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1611 lines | 1257 code | 235 blank | 119 comment | 170 complexity | 0f2cc2489411c961dc5f360581b4222f MD5 | raw file
   1/** 
   2 * @file lldrawpoolbump.cpp
   3 * @brief LLDrawPoolBump class implementation
   4 *
   5 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "lldrawpoolbump.h"
  30
  31#include "llstl.h"
  32#include "llviewercontrol.h"
  33#include "lldir.h"
  34#include "m3math.h"
  35#include "m4math.h"
  36#include "v4math.h"
  37#include "llglheaders.h"
  38#include "llrender.h"
  39
  40#include "llcubemap.h"
  41#include "lldrawable.h"
  42#include "llface.h"
  43#include "llsky.h"
  44#include "lltextureentry.h"
  45#include "llviewercamera.h"
  46#include "llviewertexturelist.h"
  47#include "pipeline.h"
  48#include "llspatialpartition.h"
  49#include "llviewershadermgr.h"
  50
  51//#include "llimagebmp.h"
  52//#include "../tools/imdebug/imdebug.h"
  53
  54// static
  55LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; 
  56
  57// static
  58U32 LLStandardBumpmap::sStandardBumpmapCount = 0;
  59
  60// static
  61LLBumpImageList gBumpImageList;
  62
  63const S32 STD_BUMP_LATEST_FILE_VERSION = 1;
  64
  65const U32 VERTEX_MASK_SHINY = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
  66const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
  67
  68U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY;
  69
  70
  71static LLGLSLShader* shader = NULL;
  72static S32 cube_channel = -1;
  73static S32 diffuse_channel = -1;
  74static S32 bump_channel = -1;
  75
  76// static 
  77void LLStandardBumpmap::init()
  78{
  79	LLStandardBumpmap::restoreGL();
  80}
  81
  82// static 
  83void LLStandardBumpmap::shutdown()
  84{
  85	LLStandardBumpmap::destroyGL();
  86}
  87
  88// static 
  89void LLStandardBumpmap::restoreGL()
  90{
  91	addstandard();
  92}
  93
  94// static
  95void LLStandardBumpmap::addstandard()
  96{
  97	if(!gTextureList.isInitialized())
  98	{
  99		//Note: loading pre-configuration sometimes triggers this call.
 100		//But it is safe to return here because bump images will be reloaded during initialization later.
 101		return ;
 102	}
 103
 104	// can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup.  Sigh.  So clear the list every time before we (re-)add the standard bumpmaps.
 105	//llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 );
 106	clear();
 107	llinfos << "Adding standard bumpmaps." << llendl;
 108	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("None");		// BE_NO_BUMP
 109	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Brightness");	// BE_BRIGHTNESS
 110	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness");	// BE_DARKNESS
 111
 112	std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" );
 113	LLFILE* file = LLFile::fopen( file_name, "rt" );	 /*Flawfinder: ignore*/
 114	if( !file )
 115	{
 116		llwarns << "Could not open std_bump <" << file_name << ">" << llendl;
 117		return;
 118	}
 119
 120	S32 file_version = 0;
 121
 122	S32 fields_read = fscanf( file, "LLStandardBumpmap version %d", &file_version );
 123	if( fields_read != 1 )
 124	{
 125		llwarns << "Bad LLStandardBumpmap header" << llendl;
 126		return;
 127	}
 128
 129	if( file_version > STD_BUMP_LATEST_FILE_VERSION )
 130	{
 131		llwarns << "LLStandardBumpmap has newer version (" << file_version << ") than viewer (" << STD_BUMP_LATEST_FILE_VERSION << ")" << llendl;
 132		return;
 133	}
 134
 135	while( !feof(file) && (LLStandardBumpmap::sStandardBumpmapCount < (U32)TEM_BUMPMAP_COUNT) )
 136	{
 137		// *NOTE: This buffer size is hard coded into scanf() below.
 138		char label[2048] = "";	/* Flawfinder: ignore */
 139		char bump_image_id[2048] = "";	/* Flawfinder: ignore */
 140		fields_read = fscanf(	/* Flawfinder: ignore */
 141			file, "\n%2047s %2047s", label, bump_image_id);
 142		if( EOF == fields_read )
 143		{
 144			break;
 145		}
 146		if( fields_read != 2 )
 147		{
 148			llwarns << "Bad LLStandardBumpmap entry" << llendl;
 149			return;
 150		}
 151
 152// 		llinfos << "Loading bumpmap: " << bump_image_id << " from viewerart" << llendl;
 153		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label;
 154		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = 
 155			LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id));	
 156		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
 157		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL );
 158		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0) ;
 159		LLStandardBumpmap::sStandardBumpmapCount++;
 160	}
 161
 162	fclose( file );
 163}
 164
 165// static
 166void LLStandardBumpmap::clear()
 167{
 168	llinfos << "Clearing standard bumpmaps." << llendl;
 169	for( U32 i = 0; i < LLStandardBumpmap::sStandardBumpmapCount; i++ )
 170	{
 171		gStandardBumpmapList[i].mLabel.assign("");
 172		gStandardBumpmapList[i].mImage = NULL;
 173	}
 174	sStandardBumpmapCount = 0;
 175}
 176
 177// static
 178void LLStandardBumpmap::destroyGL()
 179{
 180	clear();
 181}
 182
 183
 184
 185////////////////////////////////////////////////////////////////
 186
 187LLDrawPoolBump::LLDrawPoolBump() 
 188:  LLRenderPass(LLDrawPool::POOL_BUMP)
 189{
 190	mShiny = FALSE;
 191}
 192
 193
 194void LLDrawPoolBump::prerender()
 195{
 196	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 197}
 198
 199// static
 200S32 LLDrawPoolBump::numBumpPasses()
 201{
 202	if (gSavedSettings.getBOOL("RenderObjectBump"))
 203	{
 204		if (mVertexShaderLevel > 1)
 205		{
 206			if (LLPipeline::sImpostorRender)
 207			{
 208				return 2;
 209			}
 210			else
 211			{
 212				return 3;
 213			}
 214		}
 215		else if (LLPipeline::sImpostorRender)
 216		{
 217			return 1;
 218		}
 219		else
 220		{
 221			return 2;
 222		}
 223	}
 224    else
 225	{
 226		return 0;
 227	}
 228}
 229
 230S32 LLDrawPoolBump::getNumPasses()
 231{
 232	return numBumpPasses();
 233}
 234
 235void LLDrawPoolBump::beginRenderPass(S32 pass)
 236{
 237	LLFastTimer t(FTM_RENDER_BUMP);
 238	switch( pass )
 239	{
 240		case 0:
 241			beginShiny();
 242			break;
 243		case 1:
 244			if (mVertexShaderLevel > 1)
 245			{
 246				beginFullbrightShiny();
 247			}
 248			else 
 249			{
 250				beginBump();
 251			}
 252			break;
 253		case 2:
 254			beginBump();
 255			break;
 256		default:
 257			llassert(0);
 258			break;
 259	}
 260}
 261
 262void LLDrawPoolBump::render(S32 pass)
 263{
 264	LLFastTimer t(FTM_RENDER_BUMP);
 265	
 266	if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
 267	{
 268		return;
 269	}
 270	
 271	switch( pass )
 272	{
 273		case 0:
 274			renderShiny();
 275			break;
 276		case 1:
 277			if (mVertexShaderLevel > 1)
 278			{
 279				renderFullbrightShiny();
 280			}
 281			else 
 282			{
 283				renderBump(); 
 284			}
 285			break;
 286		case 2:
 287			renderBump();
 288			break;
 289		default:
 290			llassert(0);
 291			break;
 292	}
 293}
 294
 295void LLDrawPoolBump::endRenderPass(S32 pass)
 296{
 297	LLFastTimer t(FTM_RENDER_BUMP);
 298	switch( pass )
 299	{
 300		case 0:
 301			endShiny();
 302			break;
 303		case 1:
 304			if (mVertexShaderLevel > 1)
 305			{
 306				endFullbrightShiny();
 307			}
 308			else 
 309			{
 310				endBump();
 311			}
 312			break;
 313		case 2:
 314			endBump();
 315			break;
 316		default:
 317			llassert(0);
 318			break;
 319	}
 320
 321	//to cleanup texture channels
 322	LLRenderPass::endRenderPass(pass);
 323}
 324
 325//static
 326void LLDrawPoolBump::beginShiny(bool invisible)
 327{
 328	LLFastTimer t(FTM_RENDER_SHINY);
 329	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
 330		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
 331	{
 332		return;
 333	}
 334
 335	mShiny = TRUE;
 336	sVertexMask = VERTEX_MASK_SHINY;
 337	// Second pass: environment map
 338	if (!invisible && mVertexShaderLevel > 1)
 339	{
 340		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 341	}
 342	
 343	if (getVertexShaderLevel() > 0)
 344	{
 345		if (LLPipeline::sUnderWaterRender)
 346		{
 347			shader = &gObjectShinyWaterProgram;
 348		}
 349		else
 350		{
 351			shader = &gObjectShinyProgram;
 352		}
 353		shader->bind();
 354	}
 355	else
 356	{
 357		shader = NULL;
 358	}
 359
 360	bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
 361
 362	if (mVertexShaderLevel > 1)
 363	{ //indexed texture rendering, channel 0 is always diffuse
 364		diffuse_channel = 0;
 365	}
 366}
 367
 368//static
 369void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
 370{
 371	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 372	if( cube_map )
 373	{
 374		if (!invisible && shader )
 375		{
 376			LLMatrix4 mat;
 377			mat.initRows(LLVector4(gGLModelView+0),
 378						 LLVector4(gGLModelView+4),
 379						 LLVector4(gGLModelView+8),
 380						 LLVector4(gGLModelView+12));
 381			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 382			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
 383			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 384			if (shader_level > 1)
 385			{
 386				cube_map->setMatrix(1);
 387				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 388				// the cube map in the one pass shiny shaders
 389				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 390				cube_map->enableTexture(cube_channel);
 391				cube_map->enableTextureCoords(1);
 392				diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 393			}
 394			else
 395			{
 396				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 397				diffuse_channel = -1;
 398				cube_map->setMatrix(0);
 399				cube_map->enable(cube_channel);
 400			}			
 401			gGL.getTexUnit(cube_channel)->bind(cube_map);
 402			gGL.getTexUnit(0)->activate();
 403		}
 404		else
 405		{
 406			cube_channel = 0;
 407			diffuse_channel = -1;
 408			gGL.getTexUnit(0)->disable();
 409			cube_map->enable(0);
 410			cube_map->setMatrix(0);
 411			gGL.getTexUnit(0)->bind(cube_map);
 412
 413			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
 414			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA);
 415		}
 416	}
 417}
 418
 419void LLDrawPoolBump::renderShiny(bool invisible)
 420{
 421	LLFastTimer t(FTM_RENDER_SHINY);
 422	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
 423		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
 424	{
 425		return;
 426	}
 427
 428	if( gSky.mVOSkyp->getCubeMap() )
 429	{
 430		LLGLEnable blend_enable(GL_BLEND);
 431		if (!invisible && mVertexShaderLevel > 1)
 432		{
 433			LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 434		}
 435		else if (!invisible)
 436		{
 437			renderGroups(LLRenderPass::PASS_SHINY, sVertexMask);
 438		}
 439		//else // invisible (deprecated)
 440		//{
 441			//renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
 442		//}
 443	}
 444}
 445
 446//static
 447void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
 448{
 449	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 450	if( cube_map )
 451	{
 452		cube_map->disable();
 453		cube_map->restoreMatrix();
 454
 455		if (!invisible && shader_level > 1)
 456		{
 457			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 458					
 459			if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0)
 460			{
 461				if (diffuse_channel != 0)
 462				{
 463					shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 464				}
 465			}
 466		}
 467	}
 468
 469	if (!LLGLSLShader::sNoFixedFunction)
 470	{
 471		gGL.getTexUnit(diffuse_channel)->disable();
 472		gGL.getTexUnit(cube_channel)->disable();
 473
 474		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 475		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 476	}
 477}
 478
 479void LLDrawPoolBump::endShiny(bool invisible)
 480{
 481	LLFastTimer t(FTM_RENDER_SHINY);
 482	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
 483		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
 484	{
 485		return;
 486	}
 487
 488	unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
 489	if (shader)
 490	{
 491		shader->unbind();
 492	}
 493
 494	diffuse_channel = -1;
 495	cube_channel = 0;
 496	mShiny = FALSE;
 497}
 498
 499void LLDrawPoolBump::beginFullbrightShiny()
 500{
 501	LLFastTimer t(FTM_RENDER_SHINY);
 502	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
 503	{
 504		return;
 505	}
 506
 507	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 508
 509	// Second pass: environment map
 510	
 511	if (LLPipeline::sUnderWaterRender)
 512	{
 513		shader = &gObjectFullbrightShinyWaterProgram;
 514	}
 515	else
 516	{
 517		shader = &gObjectFullbrightShinyProgram;
 518	}
 519
 520	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 521	if( cube_map )
 522	{
 523		LLMatrix4 mat;
 524		mat.initRows(LLVector4(gGLModelView+0),
 525					 LLVector4(gGLModelView+4),
 526					 LLVector4(gGLModelView+8),
 527					 LLVector4(gGLModelView+12));
 528		shader->bind();
 529		LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 530		LLVector4 vec4(vec, gShinyOrigin.mV[3]);
 531		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 532
 533		cube_map->setMatrix(1);
 534		// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 535		// the cube map in the one pass shiny shaders
 536		gGL.getTexUnit(1)->disable();
 537		cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 538		cube_map->enableTexture(cube_channel);
 539		cube_map->enableTextureCoords(1);
 540		diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 541
 542		gGL.getTexUnit(cube_channel)->bind(cube_map);
 543		gGL.getTexUnit(0)->activate();
 544	}
 545
 546	if (mVertexShaderLevel > 1)
 547	{ //indexed texture rendering, channel 0 is always diffuse
 548		diffuse_channel = 0;
 549	}
 550
 551	mShiny = TRUE;
 552}
 553
 554void LLDrawPoolBump::renderFullbrightShiny()
 555{
 556	LLFastTimer t(FTM_RENDER_SHINY);
 557	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
 558	{
 559		return;
 560	}
 561
 562	if( gSky.mVOSkyp->getCubeMap() )
 563	{
 564		LLGLEnable blend_enable(GL_BLEND);
 565
 566		if (mVertexShaderLevel > 1)
 567		{
 568			LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 569		}
 570		else
 571		{
 572			LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
 573		}
 574	}
 575}
 576
 577void LLDrawPoolBump::endFullbrightShiny()
 578{
 579	LLFastTimer t(FTM_RENDER_SHINY);
 580	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY))
 581	{
 582		return;
 583	}
 584
 585	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 586	if( cube_map )
 587	{
 588		cube_map->disable();
 589		cube_map->restoreMatrix();
 590
 591		/*if (diffuse_channel != 0)
 592		{
 593			shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 594		}
 595		gGL.getTexUnit(0)->activate();
 596		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);*/
 597
 598		shader->unbind();
 599		//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 600	}
 601	
 602	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 603	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 604
 605	diffuse_channel = -1;
 606	cube_channel = 0;
 607	mShiny = FALSE;
 608}
 609
 610void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE)
 611{					
 612	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];	
 613	
 614	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) 
 615	{
 616		LLDrawInfo& params = **k;
 617		
 618		applyModelMatrix(params);
 619
 620		if (params.mGroup)
 621		{
 622			params.mGroup->rebuildMesh();
 623		}
 624		params.mVertexBuffer->setBuffer(mask);
 625		params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 626		gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
 627	}
 628}
 629
 630
 631// static
 632BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 633{
 634	U8 bump_code = params.mBump;
 635
 636	return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel);
 637}
 638
 639//static
 640BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel)
 641{
 642	const LLTextureEntry* te = face->getTextureEntry();
 643	if (te)
 644	{
 645		U8 bump_code = te->getBumpmap();
 646		return bindBumpMap(bump_code, face->getTexture(), face->getVirtualSize(), channel);
 647	}
 648
 649	return FALSE;
 650}
 651
 652//static
 653BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
 654{
 655	//Note: texture atlas does not support bump texture now.
 656	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 657	if(!tex)
 658	{
 659		//if the texture is not a fetched texture
 660		return FALSE;
 661	}
 662
 663	LLViewerTexture* bump = NULL;
 664
 665	switch( bump_code )
 666	{
 667	case BE_NO_BUMP:		
 668		break;
 669	case BE_BRIGHTNESS: 
 670	case BE_DARKNESS:
 671		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );		
 672		break;
 673
 674	default:
 675		if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
 676		{
 677			bump = gStandardBumpmapList[bump_code].mImage;
 678			gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize);
 679		}
 680		break;
 681	}
 682
 683	if (bump)
 684	{
 685		if (channel == -2)
 686		{
 687			gGL.getTexUnit(1)->bind(bump);
 688			gGL.getTexUnit(0)->bind(bump);
 689		}
 690		else
 691		{
 692			gGL.getTexUnit(channel)->bind(bump);
 693		}
 694
 695		return TRUE;
 696	}
 697
 698	return FALSE;
 699}
 700
 701//static
 702void LLDrawPoolBump::beginBump(U32 pass)
 703{	
 704	if (!gPipeline.hasRenderBatches(pass))
 705	{
 706		return;
 707	}
 708
 709	sVertexMask = VERTEX_MASK_BUMP;
 710	LLFastTimer t(FTM_RENDER_BUMP);
 711	// Optional second pass: emboss bump map
 712	stop_glerror();
 713
 714	if (LLGLSLShader::sNoFixedFunction)
 715	{
 716		gObjectBumpProgram.bind();
 717	}
 718	else
 719	{
 720		// TEXTURE UNIT 0
 721		// Output.rgb = texture at texture coord 0
 722		gGL.getTexUnit(0)->activate();
 723
 724		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 725		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 726
 727		// TEXTURE UNIT 1
 728		gGL.getTexUnit(1)->activate();
 729 
 730		gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 731
 732		gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD_SIGNED, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_ONE_MINUS_TEX_ALPHA);
 733		gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 734
 735		// src	= tex0 + (1 - tex1) - 0.5
 736		//		= (bump0/2 + 0.5) + (1 - (bump1/2 + 0.5)) - 0.5
 737		//		= (1 + bump0 - bump1) / 2
 738
 739
 740		// Blend: src * dst + dst * src
 741		//		= 2 * src * dst
 742		//		= 2 * ((1 + bump0 - bump1) / 2) * dst   [0 - 2 * dst]
 743		//		= (1 + bump0 - bump1) * dst.rgb
 744		//		= dst.rgb + dst.rgb * (bump0 - bump1)
 745
 746		gGL.getTexUnit(0)->activate();
 747		gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
 748	}
 749
 750	gGL.setSceneBlendType(LLRender::BT_MULT_X2);
 751	stop_glerror();
 752}
 753
 754//static
 755void LLDrawPoolBump::renderBump(U32 pass)
 756{
 757	if (!gPipeline.hasRenderBatches(pass))
 758	{
 759		return;
 760	}
 761
 762	LLFastTimer ftm(FTM_RENDER_BUMP);
 763	LLGLDisable fog(GL_FOG);
 764	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
 765	LLGLEnable blend(GL_BLEND);
 766	gGL.diffuseColor4f(1,1,1,1);
 767	/// Get rid of z-fighting with non-bump pass.
 768	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
 769	glPolygonOffset(-1.0f, -1.0f);
 770	renderBump(pass, sVertexMask);
 771}
 772
 773//static
 774void LLDrawPoolBump::endBump(U32 pass)
 775{
 776	if (!gPipeline.hasRenderBatches(pass))
 777	{
 778		return;
 779	}
 780
 781	if (LLGLSLShader::sNoFixedFunction)
 782	{
 783		gObjectBumpProgram.unbind();
 784	}
 785	else
 786	{
 787		// Disable texture blending on unit 1
 788		gGL.getTexUnit(1)->activate();
 789		gGL.getTexUnit(1)->disable();
 790		gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
 791
 792		// Disable texture blending on unit 0
 793		gGL.getTexUnit(0)->activate();
 794		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 795	}
 796	
 797	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 798}
 799
 800S32 LLDrawPoolBump::getNumDeferredPasses()
 801{ 
 802	if (gSavedSettings.getBOOL("RenderObjectBump"))
 803	{
 804		return 1;
 805	}
 806	else
 807	{
 808		return 0;
 809	}
 810}
 811
 812void LLDrawPoolBump::beginDeferredPass(S32 pass)
 813{
 814	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
 815	{
 816		return;
 817	}
 818	LLFastTimer ftm(FTM_RENDER_BUMP);
 819	mShiny = TRUE;
 820	gDeferredBumpProgram.bind();
 821	diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 822	bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP);
 823	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
 824	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
 825}
 826
 827void LLDrawPoolBump::endDeferredPass(S32 pass)
 828{
 829	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
 830	{
 831		return;
 832	}
 833	LLFastTimer ftm(FTM_RENDER_BUMP);
 834	mShiny = FALSE;
 835	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 836	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP);
 837	gDeferredBumpProgram.unbind();
 838	gGL.getTexUnit(0)->activate();
 839}
 840
 841void LLDrawPoolBump::renderDeferred(S32 pass)
 842{
 843	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
 844	{
 845		return;
 846	}
 847	LLFastTimer ftm(FTM_RENDER_BUMP);
 848
 849	U32 type = LLRenderPass::PASS_BUMP;
 850	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
 851	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
 852
 853	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 854	
 855	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
 856	{
 857		LLDrawInfo& params = **i;
 858
 859		LLDrawPoolBump::bindBumpMap(params, bump_channel);
 860		pushBatch(params, mask, TRUE);
 861	}
 862}
 863
 864void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
 865{
 866	switch (pass)
 867	{
 868	case 0:
 869		beginFullbrightShiny();
 870		break;
 871	case 1:
 872		beginBump(LLRenderPass::PASS_POST_BUMP);
 873		break;
 874	}
 875}
 876
 877void LLDrawPoolBump::endPostDeferredPass(S32 pass)
 878{
 879	switch (pass)
 880	{
 881	case 0:
 882		endFullbrightShiny();
 883		break;
 884	case 1:
 885		endBump(LLRenderPass::PASS_POST_BUMP);
 886		break;
 887	}
 888
 889	//to disable texture channels
 890	LLRenderPass::endRenderPass(pass);
 891}
 892
 893void LLDrawPoolBump::renderPostDeferred(S32 pass)
 894{
 895	switch (pass)
 896	{
 897	case 0:
 898		renderFullbrightShiny();
 899		break;
 900	case 1:
 901		renderBump(LLRenderPass::PASS_POST_BUMP);
 902		break;
 903	}
 904}
 905
 906////////////////////////////////////////////////////////////////
 907// List of bump-maps created from other textures.
 908
 909
 910//const LLUUID TEST_BUMP_ID("3d33eaf2-459c-6f97-fd76-5fce3fc29447");
 911
 912void LLBumpImageList::init()
 913{
 914	llassert( mBrightnessEntries.size() == 0 );
 915	llassert( mDarknessEntries.size() == 0 );
 916
 917	LLStandardBumpmap::init();
 918}
 919
 920void LLBumpImageList::clear()
 921{
 922	llinfos << "Clearing dynamic bumpmaps." << llendl;
 923	// these will be re-populated on-demand
 924	mBrightnessEntries.clear();
 925	mDarknessEntries.clear();
 926
 927	LLStandardBumpmap::clear();
 928}
 929
 930void LLBumpImageList::shutdown()
 931{
 932	clear();
 933	LLStandardBumpmap::shutdown();
 934}
 935
 936void LLBumpImageList::destroyGL()
 937{
 938	clear();
 939	LLStandardBumpmap::destroyGL();
 940}
 941
 942void LLBumpImageList::restoreGL()
 943{
 944	if(!gTextureList.isInitialized())
 945	{
 946		//safe to return here because bump images will be reloaded during initialization later.
 947		return ;
 948	}
 949
 950	LLStandardBumpmap::restoreGL();
 951	// Images will be recreated as they are needed.
 952}
 953
 954
 955LLBumpImageList::~LLBumpImageList()
 956{
 957	// Shutdown should have already been called.
 958	llassert( mBrightnessEntries.size() == 0 );
 959	llassert( mDarknessEntries.size() == 0 );
 960}
 961
 962
 963// Note: Does nothing for entries in gStandardBumpmapList that are not actually standard bump images (e.g. none, brightness, and darkness)
 964void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size)
 965{
 966	bump &= TEM_BUMP_MASK;
 967	LLViewerFetchedTexture* bump_image = gStandardBumpmapList[bump].mImage;
 968	if( bump_image )
 969	{		
 970		bump_image->addTextureStats(virtual_size);
 971	}
 972}
 973
 974
 975void LLBumpImageList::updateImages()
 976{	
 977	for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); )
 978	{
 979		bump_image_map_t::iterator curiter = iter++;
 980		LLViewerTexture* image = curiter->second;
 981		if( image )
 982		{
 983			BOOL destroy = TRUE;
 984			if( image->hasGLTexture())
 985			{
 986				if( image->getBoundRecently() )
 987				{
 988					destroy = FALSE;
 989				}
 990				else
 991				{
 992					image->destroyGLTexture();
 993				}
 994			}
 995
 996			if( destroy )
 997			{
 998				//llinfos << "*** Destroying bright " << (void*)image << llendl;
 999				mBrightnessEntries.erase(curiter);   // deletes the image thanks to reference counting
1000			}
1001		}
1002	}
1003	
1004	for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); )
1005	{
1006		bump_image_map_t::iterator curiter = iter++;
1007		LLViewerTexture* image = curiter->second;
1008		if( image )
1009		{
1010			BOOL destroy = TRUE;
1011			if( image->hasGLTexture())
1012			{
1013				if( image->getBoundRecently() )
1014				{
1015					destroy = FALSE;
1016				}
1017				else
1018				{
1019					image->destroyGLTexture();
1020				}
1021			}
1022
1023			if( destroy )
1024			{
1025				//llinfos << "*** Destroying dark " << (void*)image << llendl;;
1026				mDarknessEntries.erase(curiter);  // deletes the image thanks to reference counting
1027			}
1028		}
1029	}
1030}
1031
1032
1033// Note: the caller SHOULD NOT keep the pointer that this function returns.  It may be updated as more data arrives.
1034LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code )
1035{
1036	llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
1037
1038	LLViewerTexture* bump = NULL;
1039	
1040	bump_image_map_t* entries_list = NULL;
1041	void (*callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL;
1042
1043	switch( bump_code )
1044	{
1045	case BE_BRIGHTNESS:
1046		entries_list = &mBrightnessEntries;
1047		callback_func = LLBumpImageList::onSourceBrightnessLoaded;
1048		break;
1049	case BE_DARKNESS:
1050		entries_list = &mDarknessEntries;
1051		callback_func = LLBumpImageList::onSourceDarknessLoaded;
1052		break;
1053	default:
1054		llassert(0);
1055		return NULL;
1056	}
1057
1058	bump_image_map_t::iterator iter = entries_list->find(src_image->getID());
1059	if (iter != entries_list->end() && iter->second.notNull())
1060	{
1061		bump = iter->second;
1062	}
1063	else
1064	{
1065		LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
1066		raw->clear(0x77, 0x77, 0xFF, 0xFF);
1067
1068		(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
1069		bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
1070	}
1071
1072	if (!src_image->hasCallbacks())
1073	{ //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again
1074		if (src_image->getWidth() != bump->getWidth() ||
1075			src_image->getHeight() != bump->getHeight())// ||
1076			//(LLPipeline::sRenderDeferred && bump->getComponents() != 4))
1077		{
1078			src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
1079			src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL );
1080			src_image->forceToSaveRawImage(0) ;
1081		}
1082	}
1083
1084	return bump;
1085}
1086
1087
1088static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback");
1089
1090// static
1091void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
1092{
1093	LLUUID* source_asset_id = (LLUUID*)userdata;
1094	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS );
1095	if( final )
1096	{
1097		delete source_asset_id;
1098	}
1099}
1100
1101// static
1102void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
1103{
1104	LLUUID* source_asset_id = (LLUUID*)userdata;
1105	LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS );
1106	if( final )
1107	{
1108		delete source_asset_id;
1109	}
1110}
1111
1112static LLFastTimer::DeclareTimer FTM_BUMP_GEN_NORMAL("Generate Normal Map");
1113static LLFastTimer::DeclareTimer FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map");
1114
1115void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
1116{
1117	if (success && LLPipeline::sRenderDeferred)
1118	{
1119		LLFastTimer t(FTM_BUMP_SOURCE_STANDARD_LOADED);
1120		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
1121		{
1122			LLFastTimer t(FTM_BUMP_GEN_NORMAL);
1123			generateNormalMapFromAlpha(src, nrm_image);
1124		}
1125		src_vi->setExplicitFormat(GL_RGBA, GL_RGBA);
1126		{
1127			LLFastTimer t(FTM_BUMP_CREATE_TEXTURE);
1128			src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image);
1129		}
1130	}
1131}
1132
1133void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image)
1134{
1135	U8* nrm_data = nrm_image->getData();
1136	S32 resX = src->getWidth();
1137	S32 resY = src->getHeight();
1138
1139	U8* src_data = src->getData();
1140
1141	S32 src_cmp = src->getComponents();
1142
1143	F32 norm_scale = gSavedSettings.getF32("RenderNormalMapScale");
1144
1145	U32 idx = 0;
1146	//generate normal map from pseudo-heightfield
1147	for (S32 j = 0; j < resY; ++j)
1148	{
1149		for (S32 i = 0; i < resX; ++i)
1150		{
1151			S32 rX = (i+1)%resX;
1152			S32 rY = (j+1)%resY;
1153			S32 lX = (i-1)%resX;
1154			S32 lY = (j-1)%resY;
1155
1156			if (lX < 0)
1157			{
1158				lX += resX;
1159			}
1160			if (lY < 0)
1161			{
1162				lY += resY;
1163			}
1164
1165			F32 cH = (F32) src_data[(j*resX+i)*src_cmp+src_cmp-1];
1166
1167			LLVector3 right = LLVector3(norm_scale, 0, (F32) src_data[(j*resX+rX)*src_cmp+src_cmp-1]-cH);
1168			LLVector3 left = LLVector3(-norm_scale, 0, (F32) src_data[(j*resX+lX)*src_cmp+src_cmp-1]-cH);
1169			LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH);
1170			LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH);
1171
1172			LLVector3 norm = right%down + down%left + left%up + up%right;
1173		
1174			norm.normVec();
1175			
1176			norm *= 0.5f;
1177			norm += LLVector3(0.5f,0.5f,0.5f);
1178
1179			idx = (j*resX+i)*4;
1180			nrm_data[idx+0]= (U8) (norm.mV[0]*255);
1181			nrm_data[idx+1]= (U8) (norm.mV[1]*255);
1182			nrm_data[idx+2]= (U8) (norm.mV[2]*255);
1183			nrm_data[idx+3]= src_data[(j*resX+i)*src_cmp+src_cmp-1];
1184		}
1185	}
1186}
1187
1188
1189static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_LOADED("Bump Source Loaded");
1190static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update");
1191static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_MIN_MAX("Min/Max");
1192static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance");
1193static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RESCALE("Rescale");
1194static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal");
1195static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_CREATE("Create");
1196
1197// static
1198void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
1199{
1200	if( success )
1201	{
1202		LLFastTimer t(FTM_BUMP_SOURCE_LOADED);
1203
1204
1205		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
1206		bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
1207
1208		{
1209			LLFastTimer t(FTM_BUMP_SOURCE_ENTRIES_UPDATE);
1210			if (iter == entries_list.end() ||
1211				iter->second.isNull() ||
1212							iter->second->getWidth() != src->getWidth() ||
1213							iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
1214			{ //make sure an entry exists for this image
1215				LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
1216				raw->clear(0x77, 0x77, 0xFF, 0xFF);
1217
1218				entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
1219				iter = entries_list.find(src_vi->getID());
1220			}
1221		}
1222
1223		//if (iter->second->getWidth() != src->getWidth() ||
1224		//	iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
1225		{
1226			LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
1227			U8* dst_data = dst_image->getData();
1228			S32 dst_data_size = dst_image->getDataSize();
1229
1230			U8* src_data = src->getData();
1231			S32 src_data_size = src->getDataSize();
1232
1233			S32 src_components = src->getComponents();
1234
1235			// Convert to luminance and then scale and bias that to get ready for
1236			// embossed bump mapping.  (0-255 maps to 127-255)
1237
1238			// Convert to fixed point so we don't have to worry about precision/clamping.
1239			const S32 FIXED_PT = 8;
1240			const S32 R_WEIGHT = S32(0.2995f * (1<<FIXED_PT));
1241			const S32 G_WEIGHT = S32(0.5875f * (1<<FIXED_PT));
1242			const S32 B_WEIGHT = S32(0.1145f * (1<<FIXED_PT));
1243
1244			S32 minimum = 255;
1245			S32 maximum = 0;
1246
1247			switch( src_components )
1248			{
1249			case 1:
1250			case 2:
1251				{
1252					LLFastTimer t(FTM_BUMP_SOURCE_MIN_MAX);
1253					if( src_data_size == dst_data_size * src_components )
1254					{
1255						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
1256						{
1257							dst_data[i] = src_data[j];
1258							if( dst_data[i] < minimum )
1259							{
1260								minimum = dst_data[i];
1261							}
1262							if( dst_data[i] > maximum )
1263							{
1264								maximum = dst_data[i];
1265							}
1266						}
1267					}
1268					else
1269					{
1270						llassert(0);
1271						dst_image->clear();
1272					}
1273				}
1274				break;
1275			case 3:
1276			case 4:
1277				{
1278					LLFastTimer t(FTM_BUMP_SOURCE_RGB2LUM);
1279					if( src_data_size == dst_data_size * src_components )
1280					{
1281						for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components )
1282						{
1283							// RGB to luminance
1284							dst_data[i] = (R_WEIGHT * src_data[j] + G_WEIGHT * src_data[j+1] + B_WEIGHT * src_data[j+2]) >> FIXED_PT;
1285							//llassert( dst_data[i] <= 255 );true because it's 8bit
1286							if( dst_data[i] < minimum )
1287							{
1288								minimum = dst_data[i];
1289							}
1290							if( dst_data[i] > maximum )
1291							{
1292								maximum = dst_data[i];
1293							}
1294						}
1295					}
1296					else
1297					{
1298						llassert(0);
1299						dst_image->clear();
1300					}
1301				}
1302				break;
1303			default:
1304				llassert(0);
1305				dst_image->clear();
1306				break;
1307			}
1308
1309			if( maximum > minimum )
1310			{
1311				LLFastTimer t(FTM_BUMP_SOURCE_RESCALE);
1312				U8 bias_and_scale_lut[256];
1313				F32 twice_one_over_range = 2.f / (maximum - minimum);
1314				S32 i;
1315
1316				const F32 ARTIFICIAL_SCALE = 2.f;  // Advantage: exaggerates the effect in midrange.  Disadvantage: clamps at the extremes.
1317				if (BE_DARKNESS == bump_code)
1318				{
1319					for( i = minimum; i <= maximum; i++ )
1320					{
1321						F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f;
1322						bias_and_scale_lut[i] = llclampb(llround(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128));
1323					}
1324				}
1325				else
1326				{
1327					for( i = minimum; i <= maximum; i++ )
1328					{
1329						F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f;
1330						bias_and_scale_lut[i] = llclampb(llround(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128));
1331					}
1332				}
1333
1334				for( i = 0; i < dst_data_size; i++ )
1335				{
1336					dst_data[i] = bias_and_scale_lut[dst_data[i]];
1337				}
1338			}
1339
1340			//---------------------------------------------------
1341			// immediately assign bump to a global smart pointer in case some local smart pointer
1342			// accidentally releases it.
1343			LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE );
1344			
1345			
1346			if (!LLPipeline::sRenderDeferred)
1347			{
1348				LLFastTimer t(FTM_BUMP_SOURCE_CREATE);
1349				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
1350				bump->createGLTexture(0, dst_image);
1351			}
1352			else 
1353			{ //convert to normal map
1354				{
1355					LLFastTimer t(FTM_BUMP_SOURCE_CREATE);
1356					bump->setExplicitFormat(GL_RGBA8, GL_ALPHA);
1357					bump->createGLTexture(0, dst_image);
1358				}
1359
1360				{
1361					LLFastTimer t(FTM_BUMP_SOURCE_GEN_NORMAL);
1362					gPipeline.mScreen.bindTarget();
1363					
1364					LLGLDepthTest depth(GL_FALSE);
1365					LLGLDisable cull(GL_CULL_FACE);
1366					LLGLDisable blend(GL_BLEND);
1367					gGL.setColorMask(TRUE, TRUE);
1368					gNormalMapGenProgram.bind();
1369					gNormalMapGenProgram.uniform1f("norm_scale", gSavedSettings.getF32("RenderNormalMapScale"));
1370					gNormalMapGenProgram.uniform1f("stepX", 1.f/bump->getWidth());
1371					gNormalMapGenProgram.uniform1f("stepY", 1.f/bump->getHeight());
1372
1373					LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(),
1374								(F32) bump->getHeight()/gPipeline.mScreen.getHeight());
1375
1376					gGL.getTexUnit(0)->bind(bump);
1377					
1378					S32 width = bump->getWidth();
1379					S32 height = bump->getHeight();
1380
1381					S32 screen_width = gPipeline.mScreen.getWidth();
1382					S32 screen_height = gPipeline.mScreen.getHeight();
1383
1384					glViewport(0, 0, screen_width, screen_height);
1385
1386					for (S32 left = 0; left < width; left += screen_width)
1387					{
1388						S32 right = left + screen_width;
1389						right = llmin(right, width);
1390						
1391						F32 left_tc = (F32) left/ width;
1392						F32 right_tc = (F32) right/width;
1393
1394						for (S32 bottom = 0; bottom < height; bottom += screen_height)
1395						{
1396							S32 top = bottom+screen_height;
1397							top = llmin(top, height);
1398
1399							F32 bottom_tc = (F32) bottom/height;
1400							F32 top_tc = (F32)(bottom+screen_height)/height;
1401							top_tc = llmin(top_tc, 1.f);
1402
1403							F32 screen_right = (F32) (right-left)/screen_width;
1404							F32 screen_top = (F32) (top-bottom)/screen_height;
1405
1406							gGL.begin(LLRender::TRIANGLE_STRIP);
1407							gGL.texCoord2f(left_tc, bottom_tc);
1408							gGL.vertex2f(0, 0);
1409
1410							gGL.texCoord2f(left_tc, top_tc);
1411							gGL.vertex2f(0, screen_top);
1412
1413							gGL.texCoord2f(right_tc, bottom_tc);
1414							gGL.vertex2f(screen_right, 0);
1415
1416							gGL.texCoord2f(right_tc, top_tc);
1417							gGL.vertex2f(screen_right, screen_top);
1418
1419							gGL.end();
1420
1421							gGL.flush();
1422
1423							S32 w = right-left;
1424							S32 h = top-bottom;
1425
1426							glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
1427						}
1428					}
1429
1430					glGenerateMipmap(GL_TEXTURE_2D);
1431
1432					gPipeline.mScreen.flush();
1433
1434					gNormalMapGenProgram.unbind();
1435										
1436					//generateNormalMapFromAlpha(dst_image, nrm_image);
1437				}
1438			}
1439		
1440			iter->second = bump; // derefs (and deletes) old image
1441			//---------------------------------------------------
1442		}
1443	}
1444}
1445
1446void LLDrawPoolBump::renderBump(U32 type, U32 mask)
1447{	
1448	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
1449	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
1450
1451	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
1452	{
1453		LLDrawInfo& params = **i;
1454
1455		if (LLDrawPoolBump::bindBumpMap(params))
1456		{
1457			pushBatch(params, mask, FALSE);
1458		}
1459	}
1460}
1461
1462void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
1463{
1464	applyModelMatrix(params);
1465
1466	bool tex_setup = false;
1467
1468	if (batch_textures && params.mTextureList.size() > 1)
1469	{
1470		for (U32 i = 0; i < params.mTextureList.size(); ++i)
1471		{
1472			if (params.mTextureList[i].notNull())
1473			{
1474				gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
1475			}
1476		}
1477	}
1478	else
1479	{ //not batching textures or batch has only 1 texture -- might need a texture matrix
1480		if (params.mTextureMatrix)
1481		{
1482			if (mShiny)
1483			{
1484				gGL.getTexUnit(0)->activate();
1485				gGL.matrixMode(LLRender::MM_TEXTURE);
1486			}
1487			else
1488			{
1489				if (!LLGLSLShader::sNoFixedFunction)
1490				{
1491					gGL.getTexUnit(1)->activate();
1492					gGL.matrixMode(LLRender::MM_TEXTURE);
1493					gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
1494				}
1495
1496				gGL.getTexUnit(0)->activate();
1497				gGL.matrixMode(LLRender::MM_TEXTURE);
1498				gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
1499				gPipeline.mTextureMatrixOps++;
1500			}
1501
1502			gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
1503			gPipeline.mTextureMatrixOps++;
1504
1505			tex_setup = true;
1506		}
1507
1508		if (mShiny && mVertexShaderLevel > 1 && texture)
1509		{
1510			if (params.mTexture.notNull())
1511			{
1512				gGL.getTexUnit(diffuse_channel)->bind(params.mTexture);
1513				params.mTexture->addTextureStats(params.mVSize);		
1514			}
1515			else
1516			{
1517				gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
1518			}
1519		}
1520	}
1521
1522	if (params.mGroup)
1523	{
1524		params.mGroup->rebuildMesh();
1525	}
1526	params.mVertexBuffer->setBuffer(mask);
1527	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
1528	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
1529	if (tex_setup)
1530	{
1531		if (mShiny)
1532		{
1533			gGL.getTexUnit(0)->activate();
1534		}
1535		else
1536		{
1537			if (!LLGLSLShader::sNoFixedFunction)
1538			{
1539				gGL.getTexUnit(1)->activate();
1540				gGL.matrixMode(LLRender::MM_TEXTURE);
1541				gGL.loadIdentity();
1542			}
1543			gGL.getTexUnit(0)->activate();
1544			gGL.matrixMode(LLRender::MM_TEXTURE);
1545		}
1546		gGL.loadIdentity();
1547		gGL.matrixMode(LLRender::MM_MODELVIEW);
1548	}
1549}
1550
1551void LLDrawPoolInvisible::render(S32 pass)
1552{ //render invisiprims
1553	LLFastTimer t(FTM_RENDER_INVISIBLE);
1554  
1555	if (gPipeline.canUseVertexShaders())
1556	{
1557		gOcclusionProgram.bind();
1558	}
1559
1560	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
1561	glStencilMask(0);
1562	gGL.setColorMask(false, false);
1563	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
1564	gGL.setColorMask(true, false);
1565	glStencilMask(0xFFFFFFFF);
1566
1567	if (gPipeline.canUseVertexShaders())
1568	{
1569		gOcclusionProgram.unbind();
1570	}
1571
1572	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
1573	{
1574		beginShiny(true);
1575		renderShiny(true);
1576		endShiny(true);
1577	}
1578}
1579
1580void LLDrawPoolInvisible::beginDeferredPass(S32 pass)
1581{
1582	beginRenderPass(pass);
1583}
1584
1585void LLDrawPoolInvisible::endDeferredPass( S32 pass )
1586{
1587	endRenderPass(pass);
1588}
1589
1590void LLDrawPoolInvisible::renderDeferred( S32 pass )
1591{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff
1592#if 0 
1593	LLFastTimer t(FTM_RENDER_INVISIBLE);
1594  
1595	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
1596	glStencilMask(0);
1597	glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE);
1598	gGL.setColorMask(false, false);
1599	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
1600	gGL.setColorMask(true, true);
1601	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1602	glStencilMask(0xFFFFFFFF);
1603	
1604	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
1605	{
1606		beginShiny(true);
1607		renderShiny(true);
1608		endShiny(true);
1609	}
1610#endif
1611}