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 Also see acknowledgements in Readme.html
9
10 You may use this sample code for anything you like, it is not covered by the
11 same license as the rest of the engine.
12 -----------------------------------------------------------------------------
13 */
14
15 #include "GBufferSchemeHandler.h"
16
17 #include <OgreMaterialManager.h>
18 #include <OgreTechnique.h>
19
20 using namespace Ogre;
21
22 const String GBufferSchemeHandler::NORMAL_MAP_PATTERN = "normal";
23
handleSchemeNotFound(unsigned short schemeIndex,const String & schemeName,Material * originalMaterial,unsigned short lodIndex,const Renderable * rend)24 Technique* GBufferSchemeHandler::handleSchemeNotFound(unsigned short schemeIndex,
25 const String& schemeName, Material* originalMaterial, unsigned short lodIndex,
26 const Renderable* rend)
27 {
28 Ogre::MaterialManager& matMgr = Ogre::MaterialManager::getSingleton();
29 String curSchemeName = matMgr.getActiveScheme();
30 matMgr.setActiveScheme(MaterialManager::DEFAULT_SCHEME_NAME);
31 Technique* originalTechnique = originalMaterial->getBestTechnique(lodIndex, rend);
32 matMgr.setActiveScheme(curSchemeName);
33
34 Technique* gBufferTech = originalMaterial->createTechnique();
35 gBufferTech->removeAllPasses();
36 gBufferTech->setSchemeName(schemeName);
37
38 Technique* noGBufferTech = originalMaterial->createTechnique();
39 noGBufferTech->removeAllPasses();
40 noGBufferTech->setSchemeName("NoGBuffer");
41
42 for (unsigned short i=0; i<originalTechnique->getNumPasses(); i++)
43 {
44 Pass* originalPass = originalTechnique->getPass(i);
45 PassProperties props = inspectPass(originalPass, lodIndex, rend);
46
47 if (!props.isDeferred)
48 {
49 //Just copy the technique so it gets rendered regularly
50 Pass* clonePass = noGBufferTech->createPass();
51 *clonePass = *originalPass;
52 continue;
53 }
54
55 Pass* newPass = gBufferTech->createPass();
56 MaterialGenerator::Perm perm = getPermutation(props);
57
58 const Ogre::MaterialPtr& templateMat = mMaterialGenerator.getMaterial(perm);
59
60 //We assume that the GBuffer technique contains only one pass. But its true.
61 *newPass = *(templateMat->getTechnique(0)->getPass(0));
62 fillPass(newPass, originalPass, props);
63 }
64
65 return gBufferTech;
66 }
67
checkNormalMap(TextureUnitState * tus,GBufferSchemeHandler::PassProperties & props)68 bool GBufferSchemeHandler::checkNormalMap(
69 TextureUnitState* tus, GBufferSchemeHandler::PassProperties& props)
70 {
71 bool isNormal = false;
72 Ogre::String lowerCaseAlias = tus->getTextureNameAlias();
73 Ogre::StringUtil::toLowerCase(lowerCaseAlias);
74 if (lowerCaseAlias.find(NORMAL_MAP_PATTERN) != Ogre::String::npos)
75 {
76 isNormal = true;
77 }
78 else
79 {
80 Ogre::String lowerCaseName = tus->getTextureName();
81 Ogre::StringUtil::toLowerCase(lowerCaseName);
82 if (lowerCaseName.find(NORMAL_MAP_PATTERN) != Ogre::String::npos)
83 {
84 isNormal = true;
85 }
86 }
87
88 if (isNormal)
89 {
90 if (props.normalMap == 0)
91 {
92 props.normalMap = tus;
93 }
94 else
95 {
96 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
97 "Multiple normal map patterns matches",
98 "GBufferSchemeHandler::inspectPass");
99 }
100 }
101 return isNormal;
102 }
103
inspectPass(Pass * pass,unsigned short lodIndex,const Renderable * rend)104 GBufferSchemeHandler::PassProperties GBufferSchemeHandler::inspectPass(
105 Pass* pass, unsigned short lodIndex, const Renderable* rend)
106 {
107 PassProperties props;
108
109 //TODO : Use renderable to indicate whether this has skinning.
110 //Probably use same const cast that renderSingleObject uses.
111 if (pass->hasVertexProgram())
112 {
113 props.isSkinned = pass->getVertexProgram()->isSkeletalAnimationIncluded();
114 }
115 else
116 {
117 props.isSkinned = false;
118 }
119
120 for (unsigned short i=0; i<pass->getNumTextureUnitStates(); i++)
121 {
122 TextureUnitState* tus = pass->getTextureUnitState(i);
123 if (!checkNormalMap(tus, props))
124 {
125 props.regularTextures.push_back(tus);
126 }
127 if (tus->getEffects().size() > 0)
128 {
129 props.isDeferred = false;
130 }
131
132 }
133
134 if (pass->getDiffuse() != ColourValue::White)
135 {
136 props.hasDiffuseColour = true;
137 }
138
139 //Check transparency
140 if (pass->getDestBlendFactor() != Ogre::SBF_ZERO)
141 {
142 //TODO : Better ways to do this
143 props.isDeferred = false;
144 }
145 return props;
146 }
147
getPermutation(const PassProperties & props)148 MaterialGenerator::Perm GBufferSchemeHandler::getPermutation(const PassProperties& props)
149 {
150 MaterialGenerator::Perm perm = 0;
151 switch (props.regularTextures.size())
152 {
153 case 0:
154 perm |= GBufferMaterialGenerator::GBP_NO_TEXTURES;
155
156 if (props.normalMap != 0)
157 {
158 perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
159 }
160 else
161 {
162 perm |= GBufferMaterialGenerator::GBP_NO_TEXCOORDS;
163 }
164 break;
165 case 1:
166 perm |= GBufferMaterialGenerator::GBP_ONE_TEXTURE;
167 perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
168 break;
169 case 2:
170 perm |= GBufferMaterialGenerator::GBP_TWO_TEXTURES;
171 //TODO : When do we use two texcoords?
172 perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
173 break;
174 case 3:
175 perm |= GBufferMaterialGenerator::GBP_THREE_TEXTURES;
176 perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
177 break;
178 default:
179 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
180 "Can not generate G-Buffer materials for '>3 regular-texture' objects",
181 "GBufferSchemeHandler::inspectPass");
182 }
183
184 if (props.isSkinned)
185 {
186 perm |= GBufferMaterialGenerator::GBP_SKINNED;
187 }
188
189 if (props.normalMap != 0)
190 {
191 perm |= GBufferMaterialGenerator::GBP_NORMAL_MAP;
192 }
193
194 if (props.hasDiffuseColour)
195 {
196 perm |= GBufferMaterialGenerator::GBP_HAS_DIFFUSE_COLOUR;
197 }
198 return perm;
199 }
200
fillPass(Pass * gBufferPass,Pass * originalPass,const PassProperties & props)201 void GBufferSchemeHandler::fillPass(
202 Pass* gBufferPass, Pass* originalPass, const PassProperties& props)
203 {
204 //Reference the correct textures. Normal map first!
205 int texUnitIndex = 0;
206 if (props.normalMap != 0)
207 {
208 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.normalMap);
209 texUnitIndex++;
210 }
211 for (size_t i=0; i<props.regularTextures.size(); i++)
212 {
213 *(gBufferPass->getTextureUnitState(texUnitIndex)) = *(props.regularTextures[i]);
214 texUnitIndex++;
215 }
216 gBufferPass->setAmbient(originalPass->getAmbient());
217 gBufferPass->setDiffuse(originalPass->getDiffuse());
218 gBufferPass->setSpecular(originalPass->getSpecular());
219 gBufferPass->setShininess(originalPass->getShininess());
220 gBufferPass->setCullingMode(originalPass->getCullingMode());
221 gBufferPass->setLightingEnabled(false);
222 }
223