1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreTerrainMaterialGeneratorA.h"
29 #include "OgreTerrain.h"
30 #include "OgreMaterialManager.h"
31 #include "OgreTechnique.h"
32 #include "OgrePass.h"
33 #include "OgreTextureUnitState.h"
34 #include "OgreGpuProgramManager.h"
35 #include "OgreHighLevelGpuProgramManager.h"
36 #include "OgreHardwarePixelBuffer.h"
37 #include "OgreShadowCameraSetupPSSM.h"
38 
39 namespace Ogre
40 {
41 	//---------------------------------------------------------------------
TerrainMaterialGeneratorA()42 	TerrainMaterialGeneratorA::TerrainMaterialGeneratorA()
43 	{
44 		// define the layers
45 		// We expect terrain textures to have no alpha, so we use the alpha channel
46 		// in the albedo texture to store specular reflection
47 		// similarly we double-up the normal and height (for parallax)
48 		mLayerDecl.samplers.push_back(TerrainLayerSampler("albedo_specular", PF_BYTE_RGBA));
49 		mLayerDecl.samplers.push_back(TerrainLayerSampler("normal_height", PF_BYTE_RGBA));
50 
51 		mLayerDecl.elements.push_back(
52 			TerrainLayerSamplerElement(0, TLSS_ALBEDO, 0, 3));
53 		mLayerDecl.elements.push_back(
54 			TerrainLayerSamplerElement(0, TLSS_SPECULAR, 3, 1));
55 		mLayerDecl.elements.push_back(
56 			TerrainLayerSamplerElement(1, TLSS_NORMAL, 0, 3));
57 		mLayerDecl.elements.push_back(
58 			TerrainLayerSamplerElement(1, TLSS_HEIGHT, 3, 1));
59 
60 
61 		mProfiles.push_back(OGRE_NEW SM2Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards"));
62 		// TODO - check hardware capabilities & use fallbacks if required (more profiles needed)
63 		setActiveProfile("SM2");
64 
65 	}
66 	//---------------------------------------------------------------------
~TerrainMaterialGeneratorA()67 	TerrainMaterialGeneratorA::~TerrainMaterialGeneratorA()
68 	{
69 
70 	}
71 	//---------------------------------------------------------------------
72 	//---------------------------------------------------------------------
SM2Profile(TerrainMaterialGenerator * parent,const String & name,const String & desc)73 	TerrainMaterialGeneratorA::SM2Profile::SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc)
74 		: Profile(parent, name, desc)
75 		, mShaderGen(0)
76 		, mLayerNormalMappingEnabled(true)
77 		, mLayerParallaxMappingEnabled(true)
78 		, mLayerSpecularMappingEnabled(true)
79 		, mGlobalColourMapEnabled(true)
80 		, mLightmapEnabled(true)
81 		, mCompositeMapEnabled(true)
82 		, mReceiveDynamicShadows(true)
83 		, mPSSM(0)
84 		, mDepthShadows(false)
85 		, mLowLodShadows(false)
86         , mSM3Available(false)
87         , mSM4Available(false)
88 	{
89 		HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
90         if (hmgr.isLanguageSupported("cg"))
91         {
92             mShaderLanguage = "cg";
93         }
94         else if (hmgr.isLanguageSupported("hlsl"))
95         {
96             mShaderLanguage = "hlsl";
97         }
98         else if (hmgr.isLanguageSupported("glsl"))
99         {
100             mShaderLanguage = "glsl";
101         }
102         else if (hmgr.isLanguageSupported("glsles"))
103         {
104             mShaderLanguage = "glsles";
105         }
106         else
107         {
108             // todo
109         }
110 	}
111 	//---------------------------------------------------------------------
~SM2Profile()112 	TerrainMaterialGeneratorA::SM2Profile::~SM2Profile()
113 	{
114 		OGRE_DELETE mShaderGen;
115 	}
116 	//---------------------------------------------------------------------
requestOptions(Terrain * terrain)117 	void TerrainMaterialGeneratorA::SM2Profile::requestOptions(Terrain* terrain)
118 	{
119 		terrain->_setMorphRequired(true);
120 		terrain->_setNormalMapRequired(true);
121 		terrain->_setLightMapRequired(mLightmapEnabled, true);
122 		terrain->_setCompositeMapRequired(mCompositeMapEnabled);
123 	}
124 	//---------------------------------------------------------------------
isVertexCompressionSupported() const125 	bool TerrainMaterialGeneratorA::SM2Profile::isVertexCompressionSupported() const
126 	{
127         // FIXME: Not supporting compression on GLSL at the moment
128         if ((mShaderLanguage == "glsl") || (mShaderLanguage == "glsles"))
129             return false;
130         else
131             return true;
132 	}
133 	//---------------------------------------------------------------------
setLayerNormalMappingEnabled(bool enabled)134 	void TerrainMaterialGeneratorA::SM2Profile::setLayerNormalMappingEnabled(bool enabled)
135 	{
136 		if (enabled != mLayerNormalMappingEnabled)
137 		{
138 			mLayerNormalMappingEnabled = enabled;
139 			mParent->_markChanged();
140 		}
141 	}
142 	//---------------------------------------------------------------------
setLayerParallaxMappingEnabled(bool enabled)143 	void TerrainMaterialGeneratorA::SM2Profile::setLayerParallaxMappingEnabled(bool enabled)
144 	{
145 		if (enabled != mLayerParallaxMappingEnabled)
146 		{
147 			mLayerParallaxMappingEnabled = enabled;
148 			mParent->_markChanged();
149 		}
150 	}
151 	//---------------------------------------------------------------------
setLayerSpecularMappingEnabled(bool enabled)152 	void TerrainMaterialGeneratorA::SM2Profile::setLayerSpecularMappingEnabled(bool enabled)
153 	{
154 		if (enabled != mLayerSpecularMappingEnabled)
155 		{
156 			mLayerSpecularMappingEnabled = enabled;
157 			mParent->_markChanged();
158 		}
159 	}
160 	//---------------------------------------------------------------------
setGlobalColourMapEnabled(bool enabled)161 	void  TerrainMaterialGeneratorA::SM2Profile::setGlobalColourMapEnabled(bool enabled)
162 	{
163 		if (enabled != mGlobalColourMapEnabled)
164 		{
165 			mGlobalColourMapEnabled = enabled;
166 			mParent->_markChanged();
167 		}
168 	}
169 	//---------------------------------------------------------------------
setLightmapEnabled(bool enabled)170 	void  TerrainMaterialGeneratorA::SM2Profile::setLightmapEnabled(bool enabled)
171 	{
172 		if (enabled != mLightmapEnabled)
173 		{
174 			mLightmapEnabled = enabled;
175 			mParent->_markChanged();
176 		}
177 	}
178 	//---------------------------------------------------------------------
setCompositeMapEnabled(bool enabled)179 	void  TerrainMaterialGeneratorA::SM2Profile::setCompositeMapEnabled(bool enabled)
180 	{
181 		if (enabled != mCompositeMapEnabled)
182 		{
183 			mCompositeMapEnabled = enabled;
184 			mParent->_markChanged();
185 		}
186 	}
187 	//---------------------------------------------------------------------
setReceiveDynamicShadowsEnabled(bool enabled)188 	void  TerrainMaterialGeneratorA::SM2Profile::setReceiveDynamicShadowsEnabled(bool enabled)
189 	{
190 		if (enabled != mReceiveDynamicShadows)
191 		{
192 			mReceiveDynamicShadows = enabled;
193 			mParent->_markChanged();
194 		}
195 	}
196 	//---------------------------------------------------------------------
setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup * pssmSettings)197 	void TerrainMaterialGeneratorA::SM2Profile::setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings)
198 	{
199 		if (pssmSettings != mPSSM)
200 		{
201 			mPSSM = pssmSettings;
202 			mParent->_markChanged();
203 		}
204 	}
205 	//---------------------------------------------------------------------
setReceiveDynamicShadowsDepth(bool enabled)206 	void TerrainMaterialGeneratorA::SM2Profile::setReceiveDynamicShadowsDepth(bool enabled)
207 	{
208 		if (enabled != mDepthShadows)
209 		{
210 			mDepthShadows = enabled;
211 			mParent->_markChanged();
212 		}
213 
214 	}
215 	//---------------------------------------------------------------------
setReceiveDynamicShadowsLowLod(bool enabled)216 	void TerrainMaterialGeneratorA::SM2Profile::setReceiveDynamicShadowsLowLod(bool enabled)
217 	{
218 		if (enabled != mLowLodShadows)
219 		{
220 			mLowLodShadows = enabled;
221 			mParent->_markChanged();
222 		}
223 	}
224 	//---------------------------------------------------------------------
getMaxLayers(const Terrain * terrain) const225 	uint8 TerrainMaterialGeneratorA::SM2Profile::getMaxLayers(const Terrain* terrain) const
226 	{
227 		// count the texture units free
228 		uint8 freeTextureUnits = 16;
229 		// lightmap
230 		--freeTextureUnits;
231 		// normalmap
232 		--freeTextureUnits;
233 		// colourmap
234 		if (terrain->getGlobalColourMapEnabled())
235 			--freeTextureUnits;
236 		if (isShadowingEnabled(HIGH_LOD, terrain))
237 		{
238 			uint8 numShadowTextures = 1;
239 			if (getReceiveDynamicShadowsPSSM())
240 			{
241 				numShadowTextures = (uint8)getReceiveDynamicShadowsPSSM()->getSplitCount();
242 			}
243 			freeTextureUnits -= numShadowTextures;
244 		}
245 
246 		// each layer needs 2.25 units (1xdiffusespec, 1xnormalheight, 0.25xblend)
247 		return static_cast<uint8>(freeTextureUnits / 2.25f);
248 
249 
250 	}
251 	//---------------------------------------------------------------------
generate(const Terrain * terrain)252 	MaterialPtr TerrainMaterialGeneratorA::SM2Profile::generate(const Terrain* terrain)
253 	{
254 		// re-use old material if exists
255 		MaterialPtr mat = terrain->_getMaterial();
256 		if (mat.isNull())
257 		{
258 			MaterialManager& matMgr = MaterialManager::getSingleton();
259 
260 			// it's important that the names are deterministic for a given terrain, so
261 			// use the terrain pointer as an ID
262 			const String& matName = terrain->getMaterialName();
263 			mat = matMgr.getByName(matName);
264 			if (mat.isNull())
265 			{
266 				mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
267 			}
268 		}
269 		// clear everything
270 		mat->removeAllTechniques();
271 
272 		// Automatically disable normal & parallax mapping if card cannot handle it
273 		// We do this rather than having a specific technique for it since it's simpler
274 		GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
275 		if (!gmgr.isSyntaxSupported("ps_4_0") && !gmgr.isSyntaxSupported("ps_3_0") && !gmgr.isSyntaxSupported("ps_2_x")
276 			&& !gmgr.isSyntaxSupported("fp40") && !gmgr.isSyntaxSupported("arbfp1") && !gmgr.isSyntaxSupported("glsl")
277             && !gmgr.isSyntaxSupported("glsles"))
278 		{
279 			setLayerNormalMappingEnabled(false);
280 			setLayerParallaxMappingEnabled(false);
281 		}
282 
283 		addTechnique(mat, terrain, HIGH_LOD);
284 
285 		// LOD
286 		if(mCompositeMapEnabled)
287 		{
288 			addTechnique(mat, terrain, LOW_LOD);
289 			Material::LodValueList lodValues;
290 			lodValues.push_back(TerrainGlobalOptions::getSingleton().getCompositeMapDistance());
291 			mat->setLodLevels(lodValues);
292 			Technique* lowLodTechnique = mat->getTechnique(1);
293 			lowLodTechnique->setLodIndex(1);
294 		}
295 
296 		updateParams(mat, terrain);
297 
298 		return mat;
299 
300 	}
301 	//---------------------------------------------------------------------
generateForCompositeMap(const Terrain * terrain)302 	MaterialPtr TerrainMaterialGeneratorA::SM2Profile::generateForCompositeMap(const Terrain* terrain)
303 	{
304 		// re-use old material if exists
305 		MaterialPtr mat = terrain->_getCompositeMapMaterial();
306 		if (mat.isNull())
307 		{
308 			MaterialManager& matMgr = MaterialManager::getSingleton();
309 
310 			// it's important that the names are deterministic for a given terrain, so
311 			// use the terrain pointer as an ID
312 			const String& matName = terrain->getMaterialName() + "/comp";
313 			mat = matMgr.getByName(matName);
314 			if (mat.isNull())
315 			{
316 				mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
317 			}
318 		}
319 		// clear everything
320 		mat->removeAllTechniques();
321 
322 		addTechnique(mat, terrain, RENDER_COMPOSITE_MAP);
323 
324 		updateParamsForCompositeMap(mat, terrain);
325 
326 		return mat;
327 
328 	}
329 	//---------------------------------------------------------------------
addTechnique(const MaterialPtr & mat,const Terrain * terrain,TechniqueType tt)330 	void TerrainMaterialGeneratorA::SM2Profile::addTechnique(
331 		const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)
332 	{
333 		Technique* tech = mat->createTechnique();
334 
335 		// Only supporting one pass
336 		Pass* pass = tech->createPass();
337 
338 		GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
339 		HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
340 		if (!mShaderGen)
341 		{
342 			bool check2x = mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled;
343 			if (hmgr.isLanguageSupported("cg"))
344             {
345 				mShaderGen = OGRE_NEW ShaderHelperCg();
346             }
347 			else if (hmgr.isLanguageSupported("hlsl") &&
348 				((check2x && gmgr.isSyntaxSupported("ps_4_0")) ||
349 				(check2x && gmgr.isSyntaxSupported("ps_2_x")) ||
350 				(!check2x && gmgr.isSyntaxSupported("ps_2_0"))))
351             {
352 				mShaderGen = OGRE_NEW ShaderHelperHLSL();
353             }
354 			else if (hmgr.isLanguageSupported("glsl"))
355             {
356 				mShaderGen = OGRE_NEW ShaderHelperGLSL();
357             }
358 			else if (hmgr.isLanguageSupported("glsles"))
359             {
360 				mShaderGen = OGRE_NEW ShaderHelperGLSLES();
361             }
362 
363 			// check SM3 features
364 			mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0");
365 			mSM4Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_4_0");
366 		}
367 
368 		HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt);
369 		HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt);
370 
371 		pass->setVertexProgram(vprog->getName());
372 		pass->setFragmentProgram(fprog->getName());
373 
374 		if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP)
375 		{
376 			// global normal map
377 			TextureUnitState* tu = pass->createTextureUnitState();
378 			tu->setTextureName(terrain->getTerrainNormalMap()->getName());
379 			tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
380 
381 			// global colour map
382 			if (terrain->getGlobalColourMapEnabled() && isGlobalColourMapEnabled())
383 			{
384 				tu = pass->createTextureUnitState(terrain->getGlobalColourMap()->getName());
385 				tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
386 			}
387 
388 			// light map
389 			if (isLightmapEnabled())
390 			{
391 				tu = pass->createTextureUnitState(terrain->getLightmap()->getName());
392 				tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
393 			}
394 
395 			// blend maps
396 			uint maxLayers = getMaxLayers(terrain);
397 			uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
398 			uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
399 			for (uint i = 0; i < numBlendTextures; ++i)
400 			{
401 				tu = pass->createTextureUnitState(terrain->getBlendTextureName(i));
402 				tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
403 			}
404 
405 			// layer textures
406 			for (uint i = 0; i < numLayers; ++i)
407 			{
408 				// diffuse / specular
409 				pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
410 				// normal / height
411 				pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
412 			}
413 
414 		}
415 		else
416 		{
417 			// LOW_LOD textures
418 			// composite map
419 			TextureUnitState* tu = pass->createTextureUnitState();
420 			tu->setTextureName(terrain->getCompositeMap()->getName());
421 			tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
422 
423 			// That's it!
424 
425 		}
426 
427 		// Add shadow textures (always at the end)
428 		if (isShadowingEnabled(tt, terrain))
429 		{
430 			uint numTextures = 1;
431 			if (getReceiveDynamicShadowsPSSM())
432 			{
433 				numTextures = (uint)getReceiveDynamicShadowsPSSM()->getSplitCount();
434 			}
435 			for (uint i = 0; i < numTextures; ++i)
436 			{
437 				TextureUnitState* tu = pass->createTextureUnitState();
438 				tu->setContentType(TextureUnitState::CONTENT_SHADOW);
439 				tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
440 				tu->setTextureBorderColour(ColourValue::White);
441 			}
442 		}
443 
444 	}
445 	//---------------------------------------------------------------------
isShadowingEnabled(TechniqueType tt,const Terrain * terrain) const446 	bool TerrainMaterialGeneratorA::SM2Profile::isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const
447 	{
448 		return getReceiveDynamicShadowsEnabled() && tt != RENDER_COMPOSITE_MAP &&
449 			(tt != LOW_LOD || mLowLodShadows) &&
450 			terrain->getSceneManager()->isShadowTechniqueTextureBased();
451 
452 	}
453 	//---------------------------------------------------------------------
updateParams(const MaterialPtr & mat,const Terrain * terrain)454 	void TerrainMaterialGeneratorA::SM2Profile::updateParams(const MaterialPtr& mat, const Terrain* terrain)
455 	{
456 		mShaderGen->updateParams(this, mat, terrain, false);
457 
458 	}
459 	//---------------------------------------------------------------------
updateParamsForCompositeMap(const MaterialPtr & mat,const Terrain * terrain)460 	void TerrainMaterialGeneratorA::SM2Profile::updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain)
461 	{
462 		mShaderGen->updateParams(this, mat, terrain, true);
463 	}
464 	//---------------------------------------------------------------------
465 	//---------------------------------------------------------------------
466 	HighLevelGpuProgramPtr
generateVertexProgram(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)467 		TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::generateVertexProgram(
468 			const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
469 	{
470 		HighLevelGpuProgramPtr ret = createVertexProgram(prof, terrain, tt);
471 
472 		StringUtil::StrStreamType sourceStr;
473 		generateVertexProgramSource(prof, terrain, tt, sourceStr);
474 		ret->setSource(sourceStr.str());
475 		ret->load();
476 		defaultVpParams(prof, terrain, tt, ret);
477 #if OGRE_DEBUG_MODE
478 		LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Vertex Program: "
479 			<< ret->getName() << " ***\n" << ret->getSource() << "\n***   ***";
480 #endif
481 
482 		return ret;
483 
484 	}
485 	//---------------------------------------------------------------------
486 	HighLevelGpuProgramPtr
generateFragmentProgram(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)487 	TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::generateFragmentProgram(
488 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
489 	{
490 		HighLevelGpuProgramPtr ret = createFragmentProgram(prof, terrain, tt);
491 
492 		StringUtil::StrStreamType sourceStr;
493 		generateFragmentProgramSource(prof, terrain, tt, sourceStr);
494 		ret->setSource(sourceStr.str());
495 		ret->load();
496 		defaultFpParams(prof, terrain, tt, ret);
497 
498 #if OGRE_DEBUG_MODE
499 		LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Fragment Program: "
500 			<< ret->getName() << " ***\n" << ret->getSource() << "\n***   ***";
501 #endif
502 
503 		return ret;
504 	}
505 	//---------------------------------------------------------------------
generateVertexProgramSource(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)506 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::generateVertexProgramSource(
507 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
508 	{
509 		generateVpHeader(prof, terrain, tt, outStream);
510 
511 		if (tt != LOW_LOD)
512 		{
513 			uint maxLayers = prof->getMaxLayers(terrain);
514 			uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
515 
516 			for (uint i = 0; i < numLayers; ++i)
517 				generateVpLayer(prof, terrain, tt, i, outStream);
518 		}
519 
520 		generateVpFooter(prof, terrain, tt, outStream);
521 
522 	}
523 	//---------------------------------------------------------------------
generateFragmentProgramSource(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,StringUtil::StrStreamType & outStream)524 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::generateFragmentProgramSource(
525 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
526 	{
527 		generateFpHeader(prof, terrain, tt, outStream);
528 
529 		if (tt != LOW_LOD)
530 		{
531 			uint maxLayers = prof->getMaxLayers(terrain);
532 			uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
533 
534 			for (uint i = 0; i < numLayers; ++i)
535 				generateFpLayer(prof, terrain, tt, i, outStream);
536 		}
537 
538 		generateFpFooter(prof, terrain, tt, outStream);
539 	}
540 	//---------------------------------------------------------------------
defaultVpParams(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,const HighLevelGpuProgramPtr & prog)541 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::defaultVpParams(
542 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
543 	{
544 		GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
545 		params->setIgnoreMissingParams(true);
546 		params->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
547 		params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
548 		params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM,
549 			Terrain::LOD_MORPH_CUSTOM_PARAM);
550 		params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
551 
552 		if (prof->isShadowingEnabled(tt, terrain))
553 		{
554 			uint numTextures = 1;
555 			if (prof->getReceiveDynamicShadowsPSSM())
556 			{
557 				numTextures = (uint)prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
558 			}
559 			for (uint i = 0; i < numTextures; ++i)
560 			{
561 				params->setNamedAutoConstant("texViewProjMatrix" + StringConverter::toString(i),
562 					GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
563 				if (prof->getReceiveDynamicShadowsDepth())
564 				{
565 					params->setNamedAutoConstant("depthRange" + StringConverter::toString(i),
566 						GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i);
567 				}
568 			}
569 		}
570 
571 		if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
572 		{
573 			Matrix4 posIndexToObjectSpace;
574 			terrain->getPointTransform(&posIndexToObjectSpace);
575 			params->setNamedConstant("posIndexToObjectSpace", posIndexToObjectSpace);
576 		}
577 
578 
579 
580 	}
581 	//---------------------------------------------------------------------
defaultFpParams(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,const HighLevelGpuProgramPtr & prog)582 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::defaultFpParams(
583 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
584 	{
585 		GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
586 		params->setIgnoreMissingParams(true);
587 
588 		params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
589 		params->setNamedAutoConstant("lightPosObjSpace", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, 0);
590 		params->setNamedAutoConstant("lightDiffuseColour", GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 0);
591 		params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 0);
592 		params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
593 		params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
594 
595 		if (prof->isShadowingEnabled(tt, terrain))
596 		{
597 			uint numTextures = 1;
598 			if (prof->getReceiveDynamicShadowsPSSM())
599 			{
600 				PSSMShadowCameraSetup* pssm = prof->getReceiveDynamicShadowsPSSM();
601 				numTextures = (uint)pssm->getSplitCount();
602 				Vector4 splitPoints;
603 				const PSSMShadowCameraSetup::SplitPointList& splitPointList = pssm->getSplitPoints();
604 				// Populate from split point 1, not 0, since split 0 isn't useful (usually 0)
605 				for (uint i = 1; i < numTextures; ++i)
606 				{
607 					splitPoints[i-1] = splitPointList[i];
608 				}
609 				params->setNamedConstant("pssmSplitPoints", splitPoints);
610 			}
611 
612 			if (prof->getReceiveDynamicShadowsDepth())
613 			{
614 				size_t samplerOffset = (tt == HIGH_LOD) ? mShadowSamplerStartHi : mShadowSamplerStartLo;
615 				for (uint i = 0; i < numTextures; ++i)
616 				{
617 					params->setNamedAutoConstant("inverseShadowmapSize" + StringConverter::toString(i),
618 						GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i + samplerOffset);
619 				}
620 			}
621 		}
622 
623         // Explicitly bind samplers for GLSL
624         if ((prof->_getShaderLanguage() == "glsl") || (prof->_getShaderLanguage() == "glsles"))
625         {
626             int numSamplers = 0;
627             if (tt == LOW_LOD)
628             {
629                 params->setNamedConstant("compositeMap", (int)numSamplers++);
630             }
631             else
632             {
633                 params->setNamedConstant("globalNormal", (int)numSamplers++);
634 
635                 if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
636                 {
637                     params->setNamedConstant("globalColourMap", (int)numSamplers++);
638                 }
639                 if (prof->isLightmapEnabled())
640                 {
641                     params->setNamedConstant("lightMap", (int)numSamplers++);
642                 }
643 
644                 uint maxLayers = prof->getMaxLayers(terrain);
645                 uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
646                 uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
647                 // Blend textures - sampler definitions
648                 for (uint i = 0; i < numBlendTextures; ++i)
649                 {
650                     params->setNamedConstant("blendTex" + StringConverter::toString(i), (int)numSamplers++);
651                 }
652 
653                 // Layer textures - sampler definitions & UV multipliers
654                 for (uint i = 0; i < numLayers; ++i)
655                 {
656                     params->setNamedConstant("difftex" + StringConverter::toString(i), (int)numSamplers++);
657                     params->setNamedConstant("normtex" + StringConverter::toString(i), (int)numSamplers++);
658                 }
659 
660                 uint numShadowTextures = 1;
661                 if (prof->getReceiveDynamicShadowsPSSM())
662                     numShadowTextures = (uint)prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
663 
664                 for (uint i = 0; i < numShadowTextures; ++i)
665                 {
666                     if (prof->isShadowingEnabled(tt, terrain))
667                         params->setNamedConstant("shadowMap" + StringConverter::toString(i), (int)numSamplers++);
668                 }
669             }
670         }
671 	}
672 	//---------------------------------------------------------------------
updateParams(const SM2Profile * prof,const MaterialPtr & mat,const Terrain * terrain,bool compositeMap)673 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::updateParams(
674 		const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap)
675 	{
676 		Pass* p = mat->getTechnique(0)->getPass(0);
677 		if (compositeMap)
678 		{
679 			updateVpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getVertexProgramParameters());
680 			updateFpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getFragmentProgramParameters());
681 		}
682 		else
683 		{
684 			// high lod
685 			updateVpParams(prof, terrain, HIGH_LOD, p->getVertexProgramParameters());
686 			updateFpParams(prof, terrain, HIGH_LOD, p->getFragmentProgramParameters());
687 
688 			if(prof->isCompositeMapEnabled())
689 			{
690 				// low lod
691 				p = mat->getTechnique(1)->getPass(0);
692 				updateVpParams(prof, terrain, LOW_LOD, p->getVertexProgramParameters());
693 				updateFpParams(prof, terrain, LOW_LOD, p->getFragmentProgramParameters());
694 			}
695 		}
696 	}
697 	//---------------------------------------------------------------------
updateVpParams(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,const GpuProgramParametersSharedPtr & params)698 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::updateVpParams(
699 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
700 	{
701 		params->setIgnoreMissingParams(true);
702 		uint maxLayers = prof->getMaxLayers(terrain);
703 		uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
704 		uint numUVMul = numLayers / 4;
705 		if (numLayers % 4)
706 			++numUVMul;
707 		for (uint i = 0; i < numUVMul; ++i)
708 		{
709 			Vector4 uvMul(
710 				terrain->getLayerUVMultiplier(i * 4),
711 				terrain->getLayerUVMultiplier(i * 4 + 1),
712 				terrain->getLayerUVMultiplier(i * 4 + 2),
713 				terrain->getLayerUVMultiplier(i * 4 + 3)
714 				);
715 			params->setNamedConstant("uvMul_" + StringConverter::toString(i), uvMul);
716 		}
717 
718 		if (terrain->_getUseVertexCompression() && tt != RENDER_COMPOSITE_MAP)
719 		{
720 			Real baseUVScale = 1.0f / (terrain->getSize() - 1);
721 			params->setNamedConstant("baseUVScale", baseUVScale);
722 		}
723 
724 	}
725 	//---------------------------------------------------------------------
updateFpParams(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt,const GpuProgramParametersSharedPtr & params)726 	void TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::updateFpParams(
727 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
728 	{
729 		params->setIgnoreMissingParams(true);
730 		// TODO - parameterise this?
731 		Vector4 scaleBiasSpecular(0.03, -0.04, 32, 1);
732 		params->setNamedConstant("scaleBiasSpecular", scaleBiasSpecular);
733 
734 	}
735 	//---------------------------------------------------------------------
getChannel(uint idx)736 	String TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::getChannel(uint idx)
737 	{
738 		uint rem = idx % 4;
739 		switch(rem)
740 		{
741 		case 0:
742 		default:
743 			return "r";
744 		case 1:
745 			return "g";
746 		case 2:
747 			return "b";
748 		case 3:
749 			return "a";
750 		};
751 	}
752 	//---------------------------------------------------------------------
getVertexProgramName(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)753 	String TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::getVertexProgramName(
754 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
755 	{
756 		String progName = terrain->getMaterialName() + "/sm2/vp";
757 
758 		switch(tt)
759 		{
760 		case HIGH_LOD:
761 			progName += "/hlod";
762 			break;
763 		case LOW_LOD:
764 			progName += "/llod";
765 			break;
766 		case RENDER_COMPOSITE_MAP:
767 			progName += "/comp";
768 			break;
769 		}
770 
771 		return progName;
772 
773 	}
774 	//---------------------------------------------------------------------
getFragmentProgramName(const SM2Profile * prof,const Terrain * terrain,TechniqueType tt)775 	String TerrainMaterialGeneratorA::SM2Profile::ShaderHelper::getFragmentProgramName(
776 		const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
777 	{
778 
779 		String progName = terrain->getMaterialName() + "/sm2/fp";
780 
781 		switch(tt)
782 		{
783 		case HIGH_LOD:
784 			progName += "/hlod";
785 			break;
786 		case LOW_LOD:
787 			progName += "/llod";
788 			break;
789 		case RENDER_COMPOSITE_MAP:
790 			progName += "/comp";
791 			break;
792 		}
793 
794 		return progName;
795 	}
796 }
797