/src/ogre/PlugIns/BSPSceneManager/src/OgreQuake3Shader.cpp
Line | Count | Source |
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-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | |
29 | | #include "OgreQuake3Shader.h" |
30 | | #include "OgreSceneManager.h" |
31 | | #include "OgreMaterial.h" |
32 | | #include "OgreTechnique.h" |
33 | | #include "OgrePass.h" |
34 | | #include "OgreTextureUnitState.h" |
35 | | #include "OgreMath.h" |
36 | | #include "OgreLogManager.h" |
37 | | #include "OgreTextureManager.h" |
38 | | #include "OgreRoot.h" |
39 | | #include "OgreMaterialManager.h" |
40 | | |
41 | | namespace Ogre { |
42 | | |
43 | | |
44 | | //----------------------------------------------------------------------- |
45 | | Quake3Shader::Quake3Shader(const String& name) |
46 | 0 | { |
47 | 0 | mName = name; |
48 | 0 | numPasses = 0; |
49 | 0 | deformFunc = DEFORM_FUNC_NONE; |
50 | 0 | farbox = false; |
51 | 0 | skyDome = false; |
52 | 0 | flags = 0; |
53 | 0 | fog = false; |
54 | 0 | cullMode = MANUAL_CULL_BACK; |
55 | |
|
56 | 0 | } |
57 | | //----------------------------------------------------------------------- |
58 | | Quake3Shader::~Quake3Shader() |
59 | 0 | { |
60 | 0 | } |
61 | | //----------------------------------------------------------------------- |
62 | | MaterialPtr Quake3Shader::createAsMaterial(int lightmapNumber) |
63 | 0 | { |
64 | 0 | String matName; |
65 | 0 | StringStream str; |
66 | 0 | String resourceGroup = ResourceGroupManager::getSingleton().getWorldResourceGroupName(); |
67 | |
|
68 | 0 | str << mName << "#" << lightmapNumber; |
69 | 0 | matName = str.str(); |
70 | |
|
71 | 0 | MaterialPtr mat = MaterialManager::getSingleton().create(matName, |
72 | 0 | resourceGroup); |
73 | 0 | Ogre::Pass* ogrePass = mat->getTechnique(0)->getPass(0); |
74 | |
|
75 | 0 | LogManager::getSingleton().logMessage("Using Q3 shader " + mName, LML_TRIVIAL); |
76 | 0 | for (int p = 0; p < numPasses; ++p) |
77 | 0 | { |
78 | 0 | TextureUnitState* t; |
79 | | // Create basic texture |
80 | 0 | if (pass[p].textureName == "$lightmap") |
81 | 0 | { |
82 | 0 | StringStream str2; |
83 | 0 | str2 << "@lightmap" << lightmapNumber; |
84 | 0 | t = ogrePass->createTextureUnitState(str2.str()); |
85 | 0 | } |
86 | | // Animated texture support |
87 | 0 | else if (pass[p].animNumFrames > 0) |
88 | 0 | { |
89 | 0 | Real sequenceTime = pass[p].animNumFrames / pass[p].animFps; |
90 | | /* Pre-load textures |
91 | | We need to know if each one was loaded OK since extensions may change for each |
92 | | Quake3 can still include alternate extension filenames e.g. jpg instead of tga |
93 | | Pain in the arse - have to check for each frame as letters<n>.tga for example |
94 | | is different per frame! |
95 | | */ |
96 | 0 | for (unsigned int alt = 0; alt < pass[p].animNumFrames; ++alt) |
97 | 0 | { |
98 | 0 | if (!ResourceGroupManager::getSingleton().resourceExists( |
99 | 0 | resourceGroup, pass[p].frames[alt])) |
100 | 0 | { |
101 | | // Try alternate extension |
102 | 0 | pass[p].frames[alt] = getAlternateName(pass[p].frames[alt]); |
103 | 0 | if (!ResourceGroupManager::getSingleton().resourceExists( |
104 | 0 | resourceGroup, pass[p].frames[alt])) |
105 | 0 | { |
106 | | // stuffed - no texture |
107 | 0 | continue; |
108 | 0 | } |
109 | 0 | } |
110 | |
|
111 | 0 | } |
112 | |
|
113 | 0 | t = ogrePass->createTextureUnitState(""); |
114 | 0 | t->setAnimatedTextureName(pass[p].frames, pass[p].animNumFrames, sequenceTime); |
115 | |
|
116 | 0 | } |
117 | 0 | else |
118 | 0 | { |
119 | | // Quake3 can still include alternate extension filenames e.g. jpg instead of tga |
120 | | // Pain in the arse - have to check for failure |
121 | 0 | if (!ResourceGroupManager::getSingleton().resourceExists( |
122 | 0 | resourceGroup, pass[p].textureName)) |
123 | 0 | { |
124 | | // Try alternate extension |
125 | 0 | pass[p].textureName = getAlternateName(pass[p].textureName); |
126 | 0 | if (!ResourceGroupManager::getSingleton().resourceExists( |
127 | 0 | resourceGroup, pass[p].textureName)) |
128 | 0 | { |
129 | | // stuffed - no texture |
130 | 0 | continue; |
131 | 0 | } |
132 | 0 | } |
133 | 0 | t = ogrePass->createTextureUnitState(pass[p].textureName); |
134 | 0 | } |
135 | | // Blending |
136 | 0 | if (p == 0) |
137 | 0 | { |
138 | | // scene blend |
139 | 0 | mat->setSceneBlending(pass[p].blendSrc, pass[p].blendDest); |
140 | 0 | if (mat->isTransparent()) |
141 | 0 | mat->setDepthWriteEnabled(false); |
142 | |
|
143 | 0 | t->setColourOperation(LBO_REPLACE); |
144 | | // Alpha mode |
145 | 0 | ogrePass->setAlphaRejectSettings( |
146 | 0 | pass[p].alphaFunc, pass[p].alphaVal); |
147 | 0 | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | if (pass[p].customBlend) |
151 | 0 | { |
152 | | // Fallback for now |
153 | 0 | t->setColourOperation(LBO_MODULATE); |
154 | 0 | } |
155 | 0 | else |
156 | 0 | { |
157 | | // simple layer blend |
158 | 0 | t->setColourOperation(pass[p].blend); |
159 | 0 | } |
160 | | // Alpha mode, prefer 'most alphary' |
161 | 0 | CompareFunction currFunc = ogrePass->getAlphaRejectFunction(); |
162 | 0 | unsigned char currVal = ogrePass->getAlphaRejectValue(); |
163 | 0 | if (pass[p].alphaFunc > currFunc || |
164 | 0 | (pass[p].alphaFunc == currFunc && pass[p].alphaVal < currVal)) |
165 | 0 | { |
166 | 0 | ogrePass->setAlphaRejectSettings( |
167 | 0 | pass[p].alphaFunc, pass[p].alphaVal); |
168 | 0 | } |
169 | 0 | } |
170 | | // Tex coords |
171 | 0 | if (pass[p].texGen == TEXGEN_BASE) |
172 | 0 | { |
173 | 0 | t->setTextureCoordSet(0); |
174 | 0 | } |
175 | 0 | else if (pass[p].texGen == TEXGEN_LIGHTMAP) |
176 | 0 | { |
177 | 0 | t->setTextureCoordSet(1); |
178 | 0 | } |
179 | 0 | else if (pass[p].texGen == TEXGEN_ENVIRONMENT) |
180 | 0 | { |
181 | 0 | t->setEnvironmentMap(true, TextureUnitState::ENV_CURVED); |
182 | 0 | } |
183 | | // Tex mod |
184 | | // Scale |
185 | 0 | t->setTextureUScale(pass[p].tcModScale[0]); |
186 | 0 | t->setTextureVScale(pass[p].tcModScale[1]); |
187 | | // Procedural mods |
188 | | // Custom - don't use mod if generating environment |
189 | | // Because I do env a different way it look horrible |
190 | 0 | if (pass[p].texGen != TEXGEN_ENVIRONMENT) |
191 | 0 | { |
192 | 0 | if (pass[p].tcModRotate) |
193 | 0 | { |
194 | 0 | t->setRotateAnimation(pass[p].tcModRotate); |
195 | 0 | } |
196 | 0 | if (pass[p].tcModScroll[0] || pass[p].tcModScroll[1]) |
197 | 0 | { |
198 | 0 | if (pass[p].tcModTurbOn) |
199 | 0 | { |
200 | | // Turbulent scroll |
201 | 0 | if (pass[p].tcModScroll[0]) |
202 | 0 | { |
203 | 0 | t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_U, WFT_SINE, |
204 | 0 | pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); |
205 | 0 | } |
206 | 0 | if (pass[p].tcModScroll[1]) |
207 | 0 | { |
208 | 0 | t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_V, WFT_SINE, |
209 | 0 | pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); |
210 | 0 | } |
211 | 0 | } |
212 | 0 | else |
213 | 0 | { |
214 | | // Constant scroll |
215 | 0 | t->setScrollAnimation(pass[p].tcModScroll[0], pass[p].tcModScroll[1]); |
216 | 0 | } |
217 | 0 | } |
218 | 0 | if (pass[p].tcModStretchWave != SHADER_FUNC_NONE) |
219 | 0 | { |
220 | 0 | WaveformType wft = WFT_SINE; |
221 | 0 | switch(pass[p].tcModStretchWave) |
222 | 0 | { |
223 | 0 | case SHADER_FUNC_SIN: |
224 | 0 | wft = WFT_SINE; |
225 | 0 | break; |
226 | 0 | case SHADER_FUNC_TRIANGLE: |
227 | 0 | wft = WFT_TRIANGLE; |
228 | 0 | break; |
229 | 0 | case SHADER_FUNC_SQUARE: |
230 | 0 | wft = WFT_SQUARE; |
231 | 0 | break; |
232 | 0 | case SHADER_FUNC_SAWTOOTH: |
233 | 0 | wft = WFT_SAWTOOTH; |
234 | 0 | break; |
235 | 0 | case SHADER_FUNC_INVERSESAWTOOTH: |
236 | 0 | wft = WFT_INVERSE_SAWTOOTH; |
237 | 0 | break; |
238 | 0 | default: |
239 | 0 | break; |
240 | 0 | } |
241 | | // Create wave-based stretcher |
242 | 0 | t->setTransformAnimation(TextureUnitState::TT_SCALE_U, wft, pass[p].tcModStretchParams[3], |
243 | 0 | pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); |
244 | 0 | t->setTransformAnimation(TextureUnitState::TT_SCALE_V, wft, pass[p].tcModStretchParams[3], |
245 | 0 | pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); |
246 | 0 | } |
247 | 0 | } |
248 | | // Address mode |
249 | 0 | t->setTextureAddressingMode(pass[p].addressMode); |
250 | | |
251 | | //assert(!t->isBlank()); |
252 | | |
253 | |
|
254 | 0 | } |
255 | | // Do farbox (create new material) |
256 | | |
257 | | // Set culling mode and lighting to defaults |
258 | 0 | mat->setCullingMode(CULL_NONE); |
259 | 0 | mat->setManualCullingMode(cullMode); |
260 | 0 | mat->setLightingEnabled(false); |
261 | 0 | mat->load(); |
262 | 0 | return mat; |
263 | 0 | } |
264 | | String Quake3Shader::getAlternateName(const String& texName) |
265 | 0 | { |
266 | | // Get alternative JPG to TGA and vice versa |
267 | 0 | String ext, base; |
268 | 0 | StringUtil::splitBaseFilename(texName, base, ext); |
269 | 0 | if (StringUtil::endsWith(ext, "jpg")) |
270 | 0 | { |
271 | 0 | return base + ".tga"; |
272 | 0 | } |
273 | 0 | else |
274 | 0 | { |
275 | 0 | return base + ".jpg"; |
276 | 0 | } |
277 | |
|
278 | 0 | } |
279 | | } |