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-2006 Torus Knot Software Ltd |
---|
8 | Also see acknowledgements in Readme.html |
---|
9 | |
---|
10 | This program is free software; you can redistribute it and/or modify it under |
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
13 | version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
18 | |
---|
19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
23 | |
---|
24 | You may alternatively use this source under the terms of a specific version of |
---|
25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
26 | Torus Knot Software Ltd. |
---|
27 | ----------------------------------------------------------------------------- |
---|
28 | */ |
---|
29 | |
---|
30 | #include "OgreQuake3Shader.h" |
---|
31 | #include "OgreSceneManager.h" |
---|
32 | #include "OgreMaterial.h" |
---|
33 | #include "OgreTechnique.h" |
---|
34 | #include "OgrePass.h" |
---|
35 | #include "OgreTextureUnitState.h" |
---|
36 | #include "OgreMath.h" |
---|
37 | #include "OgreLogManager.h" |
---|
38 | #include "OgreTextureManager.h" |
---|
39 | #include "OgreRoot.h" |
---|
40 | #include "OgreMaterialManager.h" |
---|
41 | |
---|
42 | namespace Ogre { |
---|
43 | |
---|
44 | |
---|
45 | //----------------------------------------------------------------------- |
---|
46 | Quake3Shader::Quake3Shader(const String& name) |
---|
47 | { |
---|
48 | mName = name; |
---|
49 | numPasses = 0; |
---|
50 | deformFunc = DEFORM_FUNC_NONE; |
---|
51 | farbox = false; |
---|
52 | skyDome = false; |
---|
53 | flags = 0; |
---|
54 | fog = false; |
---|
55 | cullMode = MANUAL_CULL_BACK; |
---|
56 | |
---|
57 | } |
---|
58 | //----------------------------------------------------------------------- |
---|
59 | Quake3Shader::~Quake3Shader() |
---|
60 | { |
---|
61 | } |
---|
62 | //----------------------------------------------------------------------- |
---|
63 | MaterialPtr Quake3Shader::createAsMaterial(int lightmapNumber) |
---|
64 | { |
---|
65 | String matName; |
---|
66 | StringUtil::StrStreamType str; |
---|
67 | String resourceGroup = ResourceGroupManager::getSingleton().getWorldResourceGroupName(); |
---|
68 | |
---|
69 | str << mName << "#" << lightmapNumber; |
---|
70 | matName = str.str(); |
---|
71 | |
---|
72 | MaterialPtr mat = MaterialManager::getSingleton().create(matName, |
---|
73 | resourceGroup); |
---|
74 | Ogre::Pass* ogrePass = mat->getTechnique(0)->getPass(0); |
---|
75 | |
---|
76 | LogManager::getSingleton().logMessage("Using Q3 shader " + mName, LML_CRITICAL); |
---|
77 | for (int p = 0; p < numPasses; ++p) |
---|
78 | { |
---|
79 | TextureUnitState* t; |
---|
80 | // Create basic texture |
---|
81 | if (pass[p].textureName == "$lightmap") |
---|
82 | { |
---|
83 | StringUtil::StrStreamType str2; |
---|
84 | str2 << "@lightmap" << lightmapNumber; |
---|
85 | t = ogrePass->createTextureUnitState(str2.str()); |
---|
86 | } |
---|
87 | // Animated texture support |
---|
88 | else if (pass[p].animNumFrames > 0) |
---|
89 | { |
---|
90 | Real sequenceTime = pass[p].animNumFrames / pass[p].animFps; |
---|
91 | /* Pre-load textures |
---|
92 | We need to know if each one was loaded OK since extensions may change for each |
---|
93 | Quake3 can still include alternate extension filenames e.g. jpg instead of tga |
---|
94 | Pain in the arse - have to check for each frame as letters<n>.tga for example |
---|
95 | is different per frame! |
---|
96 | */ |
---|
97 | for (unsigned int alt = 0; alt < pass[p].animNumFrames; ++alt) |
---|
98 | { |
---|
99 | if (!ResourceGroupManager::getSingleton().resourceExists( |
---|
100 | resourceGroup, pass[p].frames[alt])) |
---|
101 | { |
---|
102 | // Try alternate extension |
---|
103 | pass[p].frames[alt] = getAlternateName(pass[p].frames[alt]); |
---|
104 | if (!ResourceGroupManager::getSingleton().resourceExists( |
---|
105 | resourceGroup, pass[p].frames[alt])) |
---|
106 | { |
---|
107 | // stuffed - no texture |
---|
108 | continue; |
---|
109 | } |
---|
110 | } |
---|
111 | |
---|
112 | } |
---|
113 | |
---|
114 | t = ogrePass->createTextureUnitState(""); |
---|
115 | t->setAnimatedTextureName(pass[p].frames, pass[p].animNumFrames, sequenceTime); |
---|
116 | |
---|
117 | } |
---|
118 | else |
---|
119 | { |
---|
120 | // Quake3 can still include alternate extension filenames e.g. jpg instead of tga |
---|
121 | // Pain in the arse - have to check for failure |
---|
122 | if (!ResourceGroupManager::getSingleton().resourceExists( |
---|
123 | resourceGroup, pass[p].textureName)) |
---|
124 | { |
---|
125 | // Try alternate extension |
---|
126 | pass[p].textureName = getAlternateName(pass[p].textureName); |
---|
127 | if (!ResourceGroupManager::getSingleton().resourceExists( |
---|
128 | resourceGroup, pass[p].textureName)) |
---|
129 | { |
---|
130 | // stuffed - no texture |
---|
131 | continue; |
---|
132 | } |
---|
133 | } |
---|
134 | t = ogrePass->createTextureUnitState(pass[p].textureName); |
---|
135 | } |
---|
136 | // Blending |
---|
137 | if (p == 0) |
---|
138 | { |
---|
139 | // scene blend |
---|
140 | mat->setSceneBlending(pass[p].blendSrc, pass[p].blendDest); |
---|
141 | if (mat->isTransparent()) |
---|
142 | mat->setDepthWriteEnabled(false); |
---|
143 | |
---|
144 | t->setColourOperation(LBO_REPLACE); |
---|
145 | // Alpha mode |
---|
146 | ogrePass->setAlphaRejectSettings( |
---|
147 | pass[p].alphaFunc, pass[p].alphaVal); |
---|
148 | } |
---|
149 | else |
---|
150 | { |
---|
151 | if (pass[p].customBlend) |
---|
152 | { |
---|
153 | // Fallback for now |
---|
154 | t->setColourOperation(LBO_MODULATE); |
---|
155 | } |
---|
156 | else |
---|
157 | { |
---|
158 | // simple layer blend |
---|
159 | t->setColourOperation(pass[p].blend); |
---|
160 | } |
---|
161 | // Alpha mode, prefer 'most alphary' |
---|
162 | CompareFunction currFunc = ogrePass->getAlphaRejectFunction(); |
---|
163 | unsigned char currVal = ogrePass->getAlphaRejectValue(); |
---|
164 | if (pass[p].alphaFunc > currFunc || |
---|
165 | (pass[p].alphaFunc == currFunc && pass[p].alphaVal < currVal)) |
---|
166 | { |
---|
167 | ogrePass->setAlphaRejectSettings( |
---|
168 | pass[p].alphaFunc, pass[p].alphaVal); |
---|
169 | } |
---|
170 | } |
---|
171 | // Tex coords |
---|
172 | if (pass[p].texGen == TEXGEN_BASE) |
---|
173 | { |
---|
174 | t->setTextureCoordSet(0); |
---|
175 | } |
---|
176 | else if (pass[p].texGen == TEXGEN_LIGHTMAP) |
---|
177 | { |
---|
178 | t->setTextureCoordSet(1); |
---|
179 | } |
---|
180 | else if (pass[p].texGen == TEXGEN_ENVIRONMENT) |
---|
181 | { |
---|
182 | t->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR); |
---|
183 | } |
---|
184 | // Tex mod |
---|
185 | // Scale |
---|
186 | t->setTextureUScale(pass[p].tcModScale[0]); |
---|
187 | t->setTextureVScale(pass[p].tcModScale[1]); |
---|
188 | // Procedural mods |
---|
189 | // Custom - don't use mod if generating environment |
---|
190 | // Because I do env a different way it look horrible |
---|
191 | if (pass[p].texGen != TEXGEN_ENVIRONMENT) |
---|
192 | { |
---|
193 | if (pass[p].tcModRotate) |
---|
194 | { |
---|
195 | t->setRotateAnimation(pass[p].tcModRotate); |
---|
196 | } |
---|
197 | if (pass[p].tcModScroll[0] || pass[p].tcModScroll[1]) |
---|
198 | { |
---|
199 | if (pass[p].tcModTurbOn) |
---|
200 | { |
---|
201 | // Turbulent scroll |
---|
202 | if (pass[p].tcModScroll[0]) |
---|
203 | { |
---|
204 | t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_U, WFT_SINE, |
---|
205 | pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); |
---|
206 | } |
---|
207 | if (pass[p].tcModScroll[1]) |
---|
208 | { |
---|
209 | t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_V, WFT_SINE, |
---|
210 | pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); |
---|
211 | } |
---|
212 | } |
---|
213 | else |
---|
214 | { |
---|
215 | // Constant scroll |
---|
216 | t->setScrollAnimation(pass[p].tcModScroll[0], pass[p].tcModScroll[1]); |
---|
217 | } |
---|
218 | } |
---|
219 | if (pass[p].tcModStretchWave != SHADER_FUNC_NONE) |
---|
220 | { |
---|
221 | WaveformType wft; |
---|
222 | switch(pass[p].tcModStretchWave) |
---|
223 | { |
---|
224 | case SHADER_FUNC_SIN: |
---|
225 | wft = WFT_SINE; |
---|
226 | break; |
---|
227 | case SHADER_FUNC_TRIANGLE: |
---|
228 | wft = WFT_TRIANGLE; |
---|
229 | break; |
---|
230 | case SHADER_FUNC_SQUARE: |
---|
231 | wft = WFT_SQUARE; |
---|
232 | break; |
---|
233 | case SHADER_FUNC_SAWTOOTH: |
---|
234 | wft = WFT_SAWTOOTH; |
---|
235 | break; |
---|
236 | case SHADER_FUNC_INVERSESAWTOOTH: |
---|
237 | wft = WFT_INVERSE_SAWTOOTH; |
---|
238 | break; |
---|
239 | default: |
---|
240 | break; |
---|
241 | } |
---|
242 | // Create wave-based stretcher |
---|
243 | t->setTransformAnimation(TextureUnitState::TT_SCALE_U, wft, pass[p].tcModStretchParams[3], |
---|
244 | pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); |
---|
245 | t->setTransformAnimation(TextureUnitState::TT_SCALE_V, wft, pass[p].tcModStretchParams[3], |
---|
246 | pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); |
---|
247 | } |
---|
248 | } |
---|
249 | // Address mode |
---|
250 | t->setTextureAddressingMode(pass[p].addressMode); |
---|
251 | |
---|
252 | //assert(!t->isBlank()); |
---|
253 | |
---|
254 | |
---|
255 | } |
---|
256 | // Do farbox (create new material) |
---|
257 | |
---|
258 | // Set culling mode and lighting to defaults |
---|
259 | mat->setCullingMode(CULL_NONE); |
---|
260 | mat->setManualCullingMode(cullMode); |
---|
261 | mat->setLightingEnabled(false); |
---|
262 | mat->load(); |
---|
263 | return mat; |
---|
264 | } |
---|
265 | String Quake3Shader::getAlternateName(const String& texName) |
---|
266 | { |
---|
267 | // Get alternative JPG to TGA and vice versa |
---|
268 | size_t pos; |
---|
269 | String ext, base; |
---|
270 | |
---|
271 | pos = texName.find_last_of("."); |
---|
272 | ext = texName.substr(pos, 4); |
---|
273 | StringUtil::toLowerCase(ext); |
---|
274 | base = texName.substr(0,pos); |
---|
275 | if (ext == ".jpg") |
---|
276 | { |
---|
277 | return base + ".tga"; |
---|
278 | } |
---|
279 | else |
---|
280 | { |
---|
281 | return base + ".jpg"; |
---|
282 | } |
---|
283 | |
---|
284 | } |
---|
285 | } |
---|