1 /******************************************************************************
2 Copyright (c) W.J. van der Laan
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software  and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so, subject
9 to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all copies
12 or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 ******************************************************************************/
21 
22 #include "LightMaterialGenerator.h"
23 
24 #include "OgreStringConverter.h"
25 #include "OgreException.h"
26 #include "OgreMaterialManager.h"
27 
28 #include "OgrePass.h"
29 #include "OgreTechnique.h"
30 
31 #include "OgreGpuProgramManager.h"
32 #include "OgreHighLevelGpuProgram.h"
33 #include "OgreHighLevelGpuProgramManager.h"
34 
35 #include "DLight.h"
36 
37 using namespace Ogre;
38 
39 //CG
40 class LightMaterialGeneratorCG : public MaterialGenerator::Impl
41 {
42 public:
43 	typedef MaterialGenerator::Perm Perm;
LightMaterialGeneratorCG(const String & baseName)44 	LightMaterialGeneratorCG(const String &baseName):
45 	    mBaseName(baseName)
46 	{
47 
48 	}
~LightMaterialGeneratorCG()49 	virtual ~LightMaterialGeneratorCG()
50 	{
51 
52 	}
53 
generateVertexShader(Perm permutation)54 	virtual GpuProgramPtr generateVertexShader(Perm permutation)
55 	{
56         String programName = "DeferredShading/post/";
57 
58 		if (permutation & LightMaterialGenerator::MI_DIRECTIONAL)
59 		{
60 			programName += "vs";
61 		}
62 		else
63 		{
64 			programName += "LightMaterial_vs";
65 		}
66 
67 		GpuProgramPtr ptr = HighLevelGpuProgramManager::getSingleton().getByName(programName);
68 		assert(!ptr.isNull());
69 		return ptr;
70 	}
71 
generateFragmentShader(Perm permutation)72 	virtual GpuProgramPtr generateFragmentShader(Perm permutation)
73 	{
74 		/// Create shader
75 		if (mMasterSource.empty())
76 		{
77 			DataStreamPtr ptrMasterSource = ResourceGroupManager::getSingleton().openResource(
78 				 "DeferredShading/post/LightMaterial_ps.cg"
79 				, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
80 			assert(ptrMasterSource.isNull()==false);
81 			mMasterSource = ptrMasterSource->getAsString();
82 		}
83 
84 		assert(mMasterSource.empty()==false);
85 
86 		// Create name
87 		String name = mBaseName+StringConverter::toString(permutation)+"_ps";
88 
89 		// Create shader object
90 		HighLevelGpuProgramPtr ptrProgram = HighLevelGpuProgramManager::getSingleton().createProgram(
91 			name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
92 			"cg", GPT_FRAGMENT_PROGRAM);
93 		ptrProgram->setSource(mMasterSource);
94 		ptrProgram->setParameter("entry_point","main");
95 	    ptrProgram->setParameter("profiles","ps_2_x arbfp1");
96 		// set up the preprocessor defines
97 		// Important to do this before any call to get parameters, i.e. before the program gets loaded
98 		ptrProgram->setParameter("compile_arguments", getPPDefines(permutation));
99 
100 		setUpBaseParameters(ptrProgram->getDefaultParameters());
101 
102 		return GpuProgramPtr(ptrProgram);
103 	}
104 
generateTemplateMaterial(Perm permutation)105 	virtual MaterialPtr generateTemplateMaterial(Perm permutation)
106 	{
107 		String materialName = mBaseName;
108 
109         if(permutation & LightMaterialGenerator::MI_DIRECTIONAL)
110 		{
111 			materialName += "Quad";
112 		}
113 		else
114 		{
115 			materialName += "Geometry";
116 		}
117 
118 		if(permutation & LightMaterialGenerator::MI_SHADOW_CASTER)
119 		{
120 			materialName += "Shadow";
121 		}
122 		return MaterialManager::getSingleton().getByName(materialName);
123 	}
124 
125 	protected:
126 		String mBaseName;
127         String mMasterSource;
128 		// Utility method
getPPDefines(Perm permutation)129 		String getPPDefines(Perm permutation)
130 		{
131 			String strPPD;
132 
133 			//Get the type of light
134 			String lightType;
135 			if (permutation & LightMaterialGenerator::MI_POINT)
136 			{
137 				lightType = "POINT";
138 			}
139 			else if (permutation & LightMaterialGenerator::MI_SPOTLIGHT)
140 			{
141 				lightType = "SPOT";
142 			}
143 			else if (permutation & LightMaterialGenerator::MI_DIRECTIONAL)
144 			{
145 				lightType = "DIRECTIONAL";
146 			}
147 			else
148 			{
149 				assert(false && "Permutation must have a light type");
150 			}
151 			strPPD += "-DLIGHT_TYPE=LIGHT_" + lightType + " ";
152 
153 			//Optional parameters
154             if (permutation & LightMaterialGenerator::MI_SPECULAR)
155 			{
156 				strPPD += "-DIS_SPECULAR ";
157 			}
158 			if (permutation & LightMaterialGenerator::MI_ATTENUATED)
159 			{
160 				strPPD += "-DIS_ATTENUATED ";
161 			}
162 			if (permutation & LightMaterialGenerator::MI_SHADOW_CASTER)
163 			{
164 				strPPD += "-DIS_SHADOW_CASTER ";
165 			}
166 			return strPPD;
167 		}
168 
setUpBaseParameters(const GpuProgramParametersSharedPtr & params)169 		void setUpBaseParameters(const GpuProgramParametersSharedPtr& params)
170 		{
171 			assert(params.isNull()==false);
172 
173 			struct AutoParamPair { String name; GpuProgramParameters::AutoConstantType type; };
174 
175 			//A list of auto params that might be present in the shaders generated
176 			static const AutoParamPair AUTO_PARAMS[] = {
177 				{ "vpWidth",			GpuProgramParameters::ACT_VIEWPORT_WIDTH },
178 				{ "vpHeight",			GpuProgramParameters::ACT_VIEWPORT_HEIGHT },
179 				{ "worldView",			GpuProgramParameters::ACT_WORLDVIEW_MATRIX },
180 				{ "invProj",			GpuProgramParameters::ACT_INVERSE_PROJECTION_MATRIX },
181 				{ "invView",			GpuProgramParameters::ACT_INVERSE_VIEW_MATRIX },
182 				{ "flip",				GpuProgramParameters::ACT_RENDER_TARGET_FLIPPING },
183 				{ "lightDiffuseColor",	GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR },
184 				{ "lightSpecularColor", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR },
185 				{ "lightFalloff",		GpuProgramParameters::ACT_LIGHT_ATTENUATION },
186 				{ "lightPos",			GpuProgramParameters::ACT_LIGHT_POSITION_VIEW_SPACE },
187 				{ "lightDir",			GpuProgramParameters::ACT_LIGHT_DIRECTION_VIEW_SPACE },
188 				{ "spotParams",			GpuProgramParameters::ACT_SPOTLIGHT_PARAMS },
189 				{ "farClipDistance",	GpuProgramParameters::ACT_FAR_CLIP_DISTANCE },
190 				{ "shadowViewProjMat",	GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX }
191 			};
192 			int numParams = sizeof(AUTO_PARAMS) / sizeof(AutoParamPair);
193 
194 			for (int i=0; i<numParams; i++)
195 			{
196 				if (params->_findNamedConstantDefinition(AUTO_PARAMS[i].name))
197 				{
198 					params->setNamedAutoConstant(AUTO_PARAMS[i].name, AUTO_PARAMS[i].type);
199 				}
200 			}
201 		}
202 };
203 
204 //GLSL
205 class LightMaterialGeneratorGLSL : public MaterialGenerator::Impl
206 {
207 public:
208 	typedef MaterialGenerator::Perm Perm;
LightMaterialGeneratorGLSL(const String & baseName)209 	LightMaterialGeneratorGLSL(const String &baseName):
210     mBaseName(baseName)
211 	{
212 
213 	}
~LightMaterialGeneratorGLSL()214 	virtual ~LightMaterialGeneratorGLSL()
215 	{
216 
217 	}
218 
generateVertexShader(Perm permutation)219 	virtual GpuProgramPtr generateVertexShader(Perm permutation)
220 	{
221         String programName = "DeferredShading/post/";
222 
223 		if (permutation & LightMaterialGenerator::MI_DIRECTIONAL)
224 		{
225 			programName += "vs";
226 		}
227 		else
228 		{
229 			programName += "LightMaterial_vs";
230 		}
231 
232 		GpuProgramPtr ptr = HighLevelGpuProgramManager::getSingleton().getByName(programName);
233 		assert(!ptr.isNull());
234 		return ptr;
235 	}
236 
generateFragmentShader(Perm permutation)237 	virtual GpuProgramPtr generateFragmentShader(Perm permutation)
238 	{
239 		/// Create shader
240 		if (mMasterSource.empty())
241 		{
242 			DataStreamPtr ptrMasterSource;
243             if(GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
244                 ptrMasterSource = ResourceGroupManager::getSingleton().openResource("DeferredShading/post/LightMaterial_ps.glsles",
245                                                                                     ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
246             else
247                 ptrMasterSource = ResourceGroupManager::getSingleton().openResource("DeferredShading/post/LightMaterial_ps.glsl",
248                                                                                     ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
249 
250 			assert(ptrMasterSource.isNull()==false);
251 			mMasterSource = ptrMasterSource->getAsString();
252 		}
253 
254 		assert(mMasterSource.empty()==false);
255 
256 		// Create name
257 		String name = mBaseName+StringConverter::toString(permutation)+"_ps";
258 
259 		// Create shader object
260 		HighLevelGpuProgramPtr ptrProgram;
261         if(GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
262         {
263             ptrProgram = HighLevelGpuProgramManager::getSingleton().createProgram(name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
264                                                                                   "glsles", GPT_FRAGMENT_PROGRAM);
265             ptrProgram->setParameter("profiles", "glsles");
266         }
267         else
268         {
269             ptrProgram = HighLevelGpuProgramManager::getSingleton().createProgram(name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
270                                                                                   "glsl", GPT_FRAGMENT_PROGRAM);
271             ptrProgram->setParameter("profiles", "glsl150");
272         }
273         ptrProgram->setSource(mMasterSource);
274 		// set up the preprocessor defines
275 		// Important to do this before any call to get parameters, i.e. before the program gets loaded
276 		ptrProgram->setParameter("preprocessor_defines", getPPDefines(permutation));
277 
278 		setUpBaseParameters(ptrProgram->getDefaultParameters());
279 
280         // Bind samplers
281 		GpuProgramParametersSharedPtr params = ptrProgram->getDefaultParameters();
282         int numSamplers = 0;
283         params->setNamedConstant("Tex0", (int)numSamplers++);
284         params->setNamedConstant("Tex1", (int)numSamplers++);
285 
286         if(permutation & LightMaterialGenerator::MI_SHADOW_CASTER)
287             params->setNamedConstant("ShadowTex", (int)numSamplers++);
288 
289 		return GpuProgramPtr(ptrProgram);
290 	}
291 
generateTemplateMaterial(Perm permutation)292 	virtual MaterialPtr generateTemplateMaterial(Perm permutation)
293 	{
294 		String materialName = mBaseName;
295 
296         if(permutation & LightMaterialGenerator::MI_DIRECTIONAL)
297 		{
298 			materialName += "Quad";
299 		}
300 		else
301 		{
302 			materialName += "Geometry";
303 		}
304 
305 		if(permutation & LightMaterialGenerator::MI_SHADOW_CASTER)
306 		{
307 			materialName += "Shadow";
308 		}
309 		return MaterialManager::getSingleton().getByName(materialName);
310 	}
311 
312 protected:
313     String mBaseName;
314     String mMasterSource;
315     // Utility method
getPPDefines(Perm permutation)316     String getPPDefines(Perm permutation)
317     {
318         String strPPD;
319 
320         //Get the type of light
321         Ogre::uint lightType = 0;
322         if (permutation & LightMaterialGenerator::MI_POINT)
323         {
324             lightType = 1;
325         }
326         else if (permutation & LightMaterialGenerator::MI_SPOTLIGHT)
327         {
328             lightType = 2;
329         }
330         else if (permutation & LightMaterialGenerator::MI_DIRECTIONAL)
331         {
332             lightType = 3;
333         }
334         else
335         {
336             assert(false && "Permutation must have a light type");
337         }
338         strPPD += "LIGHT_TYPE=" + StringConverter::toString(lightType);
339 
340         //Optional parameters
341         if (permutation & LightMaterialGenerator::MI_SPECULAR)
342         {
343             strPPD += ",IS_SPECULAR=1";
344         }
345         if (permutation & LightMaterialGenerator::MI_ATTENUATED)
346         {
347             strPPD += ",IS_ATTENUATED=1";
348         }
349         if (permutation & LightMaterialGenerator::MI_SHADOW_CASTER)
350         {
351             strPPD += ",IS_SHADOW_CASTER=1";
352         }
353         return strPPD;
354     }
355 
setUpBaseParameters(const GpuProgramParametersSharedPtr & params)356     void setUpBaseParameters(const GpuProgramParametersSharedPtr& params)
357     {
358         assert(params.isNull()==false);
359 
360         struct AutoParamPair { String name; GpuProgramParameters::AutoConstantType type; };
361 
362         //A list of auto params that might be present in the shaders generated
363         static const AutoParamPair AUTO_PARAMS[] = {
364             { "vpWidth",            GpuProgramParameters::ACT_VIEWPORT_WIDTH },
365             { "vpHeight",           GpuProgramParameters::ACT_VIEWPORT_HEIGHT },
366             { "worldView",          GpuProgramParameters::ACT_WORLDVIEW_MATRIX },
367             { "invProj",            GpuProgramParameters::ACT_INVERSE_PROJECTION_MATRIX },
368             { "invView",            GpuProgramParameters::ACT_INVERSE_VIEW_MATRIX },
369             { "flip",               GpuProgramParameters::ACT_RENDER_TARGET_FLIPPING },
370             { "lightDiffuseColor",  GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR },
371             { "lightSpecularColor", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR },
372             { "lightFalloff",       GpuProgramParameters::ACT_LIGHT_ATTENUATION },
373             { "lightPos",           GpuProgramParameters::ACT_LIGHT_POSITION_VIEW_SPACE },
374             { "lightDir",           GpuProgramParameters::ACT_LIGHT_DIRECTION_VIEW_SPACE },
375             { "spotParams",         GpuProgramParameters::ACT_SPOTLIGHT_PARAMS },
376             { "farClipDistance",    GpuProgramParameters::ACT_FAR_CLIP_DISTANCE },
377             { "shadowViewProjMat",  GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX }
378         };
379         int numParams = sizeof(AUTO_PARAMS) / sizeof(AutoParamPair);
380 
381         for (int i=0; i<numParams; i++)
382         {
383             if (params->_findNamedConstantDefinition(AUTO_PARAMS[i].name))
384             {
385                 params->setNamedAutoConstant(AUTO_PARAMS[i].name, AUTO_PARAMS[i].type);
386             }
387         }
388     }
389 };
390 
LightMaterialGenerator()391 LightMaterialGenerator::LightMaterialGenerator()
392 {
393 	vsMask = 0x00000004;
394 	fsMask = 0x0000003F;
395 	matMask =	LightMaterialGenerator::MI_DIRECTIONAL |
396 				LightMaterialGenerator::MI_SHADOW_CASTER;
397 
398 	materialBaseName = "DeferredShading/LightMaterial/";
399     if ((GpuProgramManager::getSingleton().isSyntaxSupported("glsl") || GpuProgramManager::getSingleton().isSyntaxSupported("glsles")) &&
400         !(GpuProgramManager::getSingleton().isSyntaxSupported("ps_2_x") ||GpuProgramManager::getSingleton().isSyntaxSupported("arbfp1")))
401         mImpl = new LightMaterialGeneratorGLSL("DeferredShading/LightMaterial/");
402     else
403         mImpl = new LightMaterialGeneratorCG("DeferredShading/LightMaterial/");
404 }
405 
~LightMaterialGenerator()406 LightMaterialGenerator::~LightMaterialGenerator()
407 {
408 
409 }
410