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