Project

General

Profile

SO3Engine
SO3GBufferSchemeHandler.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
28#include <OgreTechnique.h>
29
30namespace SO3
31{
32
33// Here we define the pattern that we will search to determine if the pass is a "normal pass".
34const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN1 = "normal";
35const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN2 = "_nrm";
36const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN3 = "_norm";
37const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN4 = "_nm";
38const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN5 = "_nrm";
39const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN6 = "_nmap";
40const Ogre::String SGBufferSchemeHandler::NORMAL_MAP_PATTERN7 = "bump";
41
42// Same thing for specular map patterns
43const Ogre::String SGBufferSchemeHandler::SPECULAR_MAP_PATTERN1 = "specular";
44const Ogre::String SGBufferSchemeHandler::SPECULAR_MAP_PATTERN2 = "_spec";
45
46// Same thing for light map patterns
47const Ogre::String SGBufferSchemeHandler::LIGHT_MAP_PATTERN1 = "lightmap";
48const Ogre::String SGBufferSchemeHandler::LIGHT_MAP_PATTERN2 = "light_map";
49const Ogre::String SGBufferSchemeHandler::LIGHT_MAP_PATTERN3 = "_light";
50
51SGBufferSchemeHandler::SGBufferSchemeHandler(SGBufferMaterialGenerator* materialGeneratorInstance)
52{
53 materialGenerator = materialGeneratorInstance;
54}
55
56SGBufferSchemeHandler::SGBufferSchemeHandler()
57{
58 // Forbiden ctor
59}
60
61Ogre::Technique* SGBufferSchemeHandler::handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend)
62{
63 //look if we didn't add the technique in a previous handleSchemeNotFound call
64 Ogre::Material::TechniqueIterator schemeTechniqueIt = originalMaterial->getTechniqueIterator();
65 while(schemeTechniqueIt.hasMoreElements())
66 {
67 Ogre::Technique* schemeTechnique = schemeTechniqueIt.getNext();
68 if(schemeTechnique->getSchemeName() == schemeName)
69 return schemeTechnique;
70 }
71
72 // Get a reference to the material manager
73 Ogre::MaterialManager& matMgr = Ogre::MaterialManager::getSingleton();
74 Ogre::String curSchemeName = matMgr.getActiveScheme();
75 matMgr.setActiveScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
76 Ogre::Technique* originalTechnique = 0;
77
78 // search for converted material technique with full textures
79 for (unsigned int i = 0; i < originalMaterial->getNumTechniques() && !originalTechnique; ++i)
80 {
81 if (originalMaterial->getTechnique(i)->getSchemeName() == "fulldef")
82 {
83 originalTechnique = originalMaterial->getTechnique(i);
84 }
85 }
86
87 if (!originalTechnique)
88 originalTechnique = originalMaterial->getBestTechnique(lodIndex, rend);
89
90 matMgr.setActiveScheme(curSchemeName);
91
92 // Create a new empty gbuffer technique on the existing material.
93 Ogre::Technique* gBufferTech = originalMaterial->createTechnique();
94 gBufferTech->removeAllPasses();
95 gBufferTech->setSchemeName(schemeName);
96
97 // Create a new empty 'no gbuffer' technique on the existing material
98 Ogre::Technique* noGBufferTech = originalMaterial->createTechnique();
99 noGBufferTech->removeAllPasses();
100 noGBufferTech->setSchemeName("NoGBuffer");
101
102 // Parse all pass of the original technique
103 unsigned short numPasses = originalTechnique->getNumPasses();
104 if(numPasses > 0)
105 {
106 Ogre::Pass* originalPass = originalTechnique->getPass(0);
107 PassProperties props = InspectPass(originalPass, lodIndex, rend);
108
109 if((numPasses > 1) || (!props.isDeferred))
110 {
111 // Not deferred!
112 for (unsigned short i=0; i<numPasses; i++)
113 {
114 // Copy the pass so it gets rendered regularly
115 Ogre::Pass* clonePass = noGBufferTech->createPass();
116 *clonePass = *(originalTechnique->getPass(i));
117 }
118 }
119 else
120 {
121 // TODO: if gBufferTech->getNumPasses() == 0 ?
122 Ogre::Pass* newPass = gBufferTech->createPass();
124
125 //We assume that the GBuffer technique contains only one pass. But its true.
126 const Ogre::MaterialPtr& templateMat = materialGenerator->GetMaterial(SDeferredShading::getSingleton().GetGBuffer(), perm);
127 *newPass = *(templateMat->getTechnique(0)->getPass(0));
128 FillPass(newPass, originalPass, props);
129 }
130 }
131 return gBufferTech;
132}
133
134
135SGBufferSchemeHandler::PassProperties SGBufferSchemeHandler::InspectPass(Ogre::Pass* pass, unsigned short lodIndex, const Ogre::Renderable* rend)
136{
137 PassProperties props;
138
139 unsigned short numberTu = pass->getNumTextureUnitStates();
140 if(numberTu > 4)
141 {
142 // TODO DEF temporary hack, cause we do not support more than 3 tu at this time (5 planned).
143 props.isDeferred = false;
144 }
145 else
146 {
147 //TODO : Use renderable to indicate wether this has skinning.
148 //Probably use same const cast that renderSingleObject uses.
149 if (pass->hasVertexProgram())
150 props.isSkinned = pass->getVertexProgram()->isSkeletalAnimationIncluded();
151 else
152 props.isSkinned = false;
153
154 for (unsigned short i=0; i<pass->getNumTextureUnitStates(); i++)
155 {
156 // Get a reference to tu
157 Ogre::TextureUnitState* tus = pass->getTextureUnitState(i);
158
159 // Get tu name
160 Ogre::String lowerCaseName = tus->getName();
161 Ogre::StringUtil::toLowerCase(lowerCaseName);
162
163 // Get tu's texture alias name
164 Ogre::String lowerCaseAlias = tus->getTextureNameAlias();
165 Ogre::StringUtil::toLowerCase(lowerCaseAlias);
166
167 // Get tu's texture filename
168 Ogre::String lowerCaseFileName = tus->getTextureName();
169 Ogre::StringUtil::toLowerCase(lowerCaseFileName);
170
171 if(!CheckNormalMap(tus, props, lowerCaseName, lowerCaseAlias, lowerCaseFileName))
172 if(!CheckSpecularMap(tus, props, lowerCaseName, lowerCaseAlias, lowerCaseFileName))
173 if(!CheckLightMap(tus, props, lowerCaseName, lowerCaseAlias, lowerCaseFileName))
174 props.regularTextures.push_back(tus);
175
176 // TODO DEF manage tu effects
177 //if (tus->getEffects().size() > 0)
178 // props.isDeferred = false;
179 }
180
181 // The pass has a diffuse colour
182 if (pass->getDiffuse() != Ogre::ColourValue::Black)
183 props.hasDiffuseColour = true;
184
185 // Override specular colour if a specular map is provided
186 if ((pass->getSpecular() != Ogre::ColourValue::Black) && (props.specularMap == 0))
187 props.hasSpecularColour = true;
188
189 // The pass has an emissive colour
190 if (pass->getEmissive() != Ogre::ColourValue::Black)
191 props.hasEmissiveColour = true;
192
193 // Test alpha rejection (texture mask using alpha channel of the texture).
194 if (pass->getAlphaRejectFunction() != Ogre::CMPF_ALWAYS_PASS)
195 props.hasAlphaRejection = true;
196
197 // Check depth write
198 if (pass->getDepthWriteEnabled() == false && !props.hasAlphaRejection)
199 props.isDeferred = false;
200 }
201 return props;
202}
203
204bool SGBufferSchemeHandler::CheckNormalMap(Ogre::TextureUnitState* tus, SGBufferSchemeHandler::PassProperties& props, const Ogre::String& lowerCaseName, const Ogre::String& lowerCaseAlias, const Ogre::String& lowerCaseFileName)
205{
206 bool isNormal = false;
207
208 // Check if the texture unit alias contains our normal pattern, first condition for efficiency
209 if ((lowerCaseName != "") &&
210 ((lowerCaseName.find(NORMAL_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseName.find(NORMAL_MAP_PATTERN2) != Ogre::String::npos) ||
211 (lowerCaseName.find(NORMAL_MAP_PATTERN3) != Ogre::String::npos) || (lowerCaseName.find(NORMAL_MAP_PATTERN4) != Ogre::String::npos) ||
212 (lowerCaseName.find(NORMAL_MAP_PATTERN5) != Ogre::String::npos) || (lowerCaseName.find(NORMAL_MAP_PATTERN6) != Ogre::String::npos) ||
213 (lowerCaseName.find(NORMAL_MAP_PATTERN7) != Ogre::String::npos)))
214 {
215 isNormal = true;
216 }
217 else
218 {
219 // Check if the texture unit alias contains our normal pattern, first condition for efficiency
220 if ((lowerCaseAlias != "") &&
221 ((lowerCaseAlias.find(NORMAL_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseAlias.find(NORMAL_MAP_PATTERN2) != Ogre::String::npos) ||
222 (lowerCaseAlias.find(NORMAL_MAP_PATTERN3) != Ogre::String::npos) || (lowerCaseAlias.find(NORMAL_MAP_PATTERN4) != Ogre::String::npos) ||
223 (lowerCaseAlias.find(NORMAL_MAP_PATTERN5) != Ogre::String::npos) || (lowerCaseAlias.find(NORMAL_MAP_PATTERN6) != Ogre::String::npos) ||
224 (lowerCaseAlias.find(NORMAL_MAP_PATTERN7) != Ogre::String::npos)))
225 {
226 isNormal = true;
227 }
228 else
229 {
230 // Check if the texture file name contains our normal pattern, first condition for efficiency
231 if ((lowerCaseFileName != "") &&
232 ((lowerCaseFileName.find(NORMAL_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseFileName.find(NORMAL_MAP_PATTERN2) != Ogre::String::npos) ||
233 (lowerCaseFileName.find(NORMAL_MAP_PATTERN3) != Ogre::String::npos) || (lowerCaseFileName.find(NORMAL_MAP_PATTERN4) != Ogre::String::npos) ||
234 (lowerCaseFileName.find(NORMAL_MAP_PATTERN5) != Ogre::String::npos) || (lowerCaseFileName.find(NORMAL_MAP_PATTERN6) != Ogre::String::npos) ||
235 (lowerCaseFileName.find(NORMAL_MAP_PATTERN7) != Ogre::String::npos)))
236 {
237 isNormal = true;
238 }
239 }
240 }
241
242 if (isNormal)
243 {
244 if (props.normalMap == 0)
245 props.normalMap = tus;
246 else
247 OGRE_EXCEPT(Ogre::Exception::ERR_DUPLICATE_ITEM, "The pass already have a normal map!", "SGBufferSchemeHandler::CheckNormalMap");
248 }
249 return isNormal;
250}
251
252bool SGBufferSchemeHandler::CheckSpecularMap(Ogre::TextureUnitState* tus, SGBufferSchemeHandler::PassProperties& props, const Ogre::String& lowerCaseName, const Ogre::String& lowerCaseAlias, const Ogre::String& lowerCaseFileName)
253{
254 bool isSpecular = false;
255
256 // Check if the texture unit alias contains our speculat pattern, first condition for efficiency
257 if ((lowerCaseName != "") &&
258 ((lowerCaseName.find(SPECULAR_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseName.find(SPECULAR_MAP_PATTERN2) != Ogre::String::npos)))
259 {
260 isSpecular = true;
261 }
262 else
263 {
264 // Check if the texture unit alias contains our speculat pattern, first condition for efficiency
265 if ((lowerCaseAlias != "") &&
266 ((lowerCaseAlias.find(SPECULAR_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseAlias.find(SPECULAR_MAP_PATTERN2) != Ogre::String::npos)))
267 {
268 isSpecular = true;
269 }
270 else
271 {
272 // Check if the texture file name contains our speculat pattern, first condition for efficiency
273 if ((lowerCaseFileName != "") &&
274 ((lowerCaseFileName.find(SPECULAR_MAP_PATTERN1) != Ogre::String::npos) || (lowerCaseFileName.find(SPECULAR_MAP_PATTERN2) != Ogre::String::npos)))
275 {
276 isSpecular = true;
277 }
278 }
279 }
280
281 if (isSpecular)
282 {
283 if (props.specularMap == 0)
284 props.specularMap = tus;
285 else
286 OGRE_EXCEPT(Ogre::Exception::ERR_DUPLICATE_ITEM, "The pass already have a specular map!", "SGBufferSchemeHandler::CheckSpecularMap");
287 }
288 return isSpecular;
289}
290
291bool SGBufferSchemeHandler::CheckLightMap(Ogre::TextureUnitState* tus, SGBufferSchemeHandler::PassProperties& props, const Ogre::String& lowerCaseName, const Ogre::String& lowerCaseAlias, const Ogre::String& lowerCaseFileName)
292{
293 bool isLightMap = false;
294
295 // Check if the texture unit alias contains our lightmap pattern, first condition for efficiency
296 if ((lowerCaseName != "") &&
297 ((lowerCaseName.find(LIGHT_MAP_PATTERN1) != Ogre::String::npos)
298 ||(lowerCaseName.find(LIGHT_MAP_PATTERN2) != Ogre::String::npos)
299 ||(lowerCaseName.find(LIGHT_MAP_PATTERN3) != Ogre::String::npos)))
300 {
301 isLightMap = true;
302 }
303 else
304 {
305 // Check if the texture unit alias contains our lightmap pattern, first condition for efficiency
306 if ((lowerCaseAlias != "") &&
307 ((lowerCaseAlias.find(LIGHT_MAP_PATTERN1) != Ogre::String::npos)
308 ||(lowerCaseAlias.find(LIGHT_MAP_PATTERN2) != Ogre::String::npos)
309 ||(lowerCaseAlias.find(LIGHT_MAP_PATTERN3) != Ogre::String::npos)))
310 {
311 isLightMap = true;
312 }
313 else
314 {
315 // Check if the texture file name contains our lightmap pattern, first condition for efficiency
316 if ((lowerCaseFileName != "") &&
317 ((lowerCaseFileName.find(LIGHT_MAP_PATTERN1) != Ogre::String::npos)
318 ||(lowerCaseName.find(LIGHT_MAP_PATTERN2) != Ogre::String::npos)
319 ||(lowerCaseFileName.find(LIGHT_MAP_PATTERN3) != Ogre::String::npos)))
320 {
321 isLightMap = true;
322 }
323 }
324 }
325
326 if (isLightMap)
327 {
328 if (props.lightMap == 0)
329 props.lightMap = tus;
330 else
331 OGRE_EXCEPT(Ogre::Exception::ERR_DUPLICATE_ITEM, "The pass already have a light map!", "SGBufferSchemeHandler::CheckLightMap");
332 }
333 return isLightMap;
334}
335
337{
339 switch (props.regularTextures.size())
340 {
341 case 0:
343 // TODO: strange...
344 if((props.normalMap != 0)
345 ||(props.specularMap != 0)
346 ||(props.lightMap != 0))
348 else
350 break;
351
352 case 1:
355 break;
356
357 case 2:
360 break;
361
362 case 3:
365 break;
366
367 default:
368 // TODO
369 SO3_EXCEPT(SExceptionUnimplemented, "Can not generate G-Buffer materials for '>3 texture' objects", "SGBufferSchemeHandler::GetPermutation", true);
370 }
371
372 if (props.isSkinned)
374
375 if (props.normalMap != 0)
377
378 if (props.specularMap != 0)
380
381 if (props.lightMap!= 0)
383
384 if (props.hasDiffuseColour)
386
387 if (props.hasSpecularColour)
389
390 if (props.hasEmissiveColour)
392
393 if (props.hasAlphaRejection != 0)
395
396 return perm;
397}
398
399void SGBufferSchemeHandler::FillPass(Ogre::Pass* gBufferPass, Ogre::Pass* originalPass, const PassProperties& props)
400{
401 //Reference the correct textures. Normal map first!
402 int texUnitIndex = 0;
403 if (props.normalMap != 0)
404 {
405 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.normalMap);
406 texUnitIndex++;
407 }
408
409 if (props.specularMap != 0)
410 {
411 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.specularMap);
412 texUnitIndex++;
413 }
414
415 if (props.lightMap != 0)
416 {
417 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.lightMap);
418 texUnitIndex++;
419 }
420
421 for (size_t i=0; i<props.regularTextures.size(); i++)
422 {
423 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.regularTextures[i]);
424 texUnitIndex++;
425 }
426
427 if (props.hasAlphaRejection != 0)
428 {
429 Ogre::GpuProgramParametersSharedPtr fragProgParams = gBufferPass->getFragmentProgramParameters();
430 if (fragProgParams->_findNamedConstantDefinition("cRejectAlpha"))
431 fragProgParams->setNamedConstant("cRejectAlpha", Ogre::Real(originalPass->getAlphaRejectValue()/255.0f));
432 }
433
434 gBufferPass->setAmbient(originalPass->getAmbient());
435 gBufferPass->setDiffuse(originalPass->getDiffuse());
436 gBufferPass->setSpecular(originalPass->getSpecular());
437 gBufferPass->setShininess(originalPass->getShininess());
438 gBufferPass->setEmissive(originalPass->getEmissive());
439 gBufferPass->setCullingMode(originalPass->getCullingMode());
440 gBufferPass->setLightingEnabled(false);
441}
442
443}
static SDeferredShading & getSingleton()
SException indicating that a call to an unimplemented functionnality was done.
static const Ogre::String NORMAL_MAP_PATTERN1
PassProperties InspectPass(Ogre::Pass *pass, unsigned short lodIndex, const Ogre::Renderable *rend)
static const Ogre::String NORMAL_MAP_PATTERN3
static const Ogre::String LIGHT_MAP_PATTERN1
static const Ogre::String NORMAL_MAP_PATTERN7
void FillPass(Ogre::Pass *gBufferPass, Ogre::Pass *originalPass, const PassProperties &props)
bool CheckSpecularMap(Ogre::TextureUnitState *tus, PassProperties &props, const Ogre::String &lowerCaseName, const Ogre::String &lowerCaseAlias, const Ogre::String &lowerCaseFileName)
static const Ogre::String LIGHT_MAP_PATTERN2
static const Ogre::String NORMAL_MAP_PATTERN5
static const Ogre::String NORMAL_MAP_PATTERN6
SGBufferMaterialPermutation GetPermutation(const PassProperties &props)
static const Ogre::String LIGHT_MAP_PATTERN3
static const Ogre::String SPECULAR_MAP_PATTERN1
virtual Ogre::Technique * handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, unsigned short lodIndex, const Ogre::Renderable *rend)
bool CheckNormalMap(Ogre::TextureUnitState *tus, PassProperties &props, const Ogre::String &lowerCaseName, const Ogre::String &lowerCaseAlias, const Ogre::String &lowerCaseFileName)
SGBufferMaterialGenerator * materialGenerator
static const Ogre::String NORMAL_MAP_PATTERN2
bool CheckLightMap(Ogre::TextureUnitState *tus, PassProperties &props, const Ogre::String &lowerCaseName, const Ogre::String &lowerCaseAlias, const Ogre::String &lowerCaseFileName)
static const Ogre::String SPECULAR_MAP_PATTERN2
static const Ogre::String NORMAL_MAP_PATTERN4
const Ogre::MaterialPtr & GetMaterial(SGBuffer *gbuffer, PERMUTATION_CLASS permutation)
Ogre::vector< Ogre::TextureUnitState * >::type regularTextures