00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 00006 00007 Copyright © 2000-2002 The OGRE Team 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 00026 #include "OgreQuake3Shader.h" 00027 #include "OgreSceneManager.h" 00028 #include "OgreMaterial.h" 00029 #include "OgreTechnique.h" 00030 #include "OgrePass.h" 00031 #include "OgreTextureUnitState.h" 00032 #include "OgreMath.h" 00033 #include "OgreLogManager.h" 00034 #include "OgreTextureManager.h" 00035 00036 namespace Ogre { 00037 00038 00039 //----------------------------------------------------------------------- 00040 Quake3Shader::Quake3Shader(const String& name) 00041 { 00042 mName = name; 00043 numPasses = 0; 00044 deformFunc = DEFORM_FUNC_NONE; 00045 farbox = false; 00046 skyDome = false; 00047 flags = 0; 00048 fog = false; 00049 cullMode = MANUAL_CULL_BACK; 00050 00051 } 00052 //----------------------------------------------------------------------- 00053 Quake3Shader::~Quake3Shader() 00054 { 00055 } 00056 //----------------------------------------------------------------------- 00057 void Quake3Shader::load(void) 00058 { 00059 // Do nothing 00060 } 00061 //----------------------------------------------------------------------- 00062 void Quake3Shader::unload(void) 00063 { 00064 // Do nothing 00065 } 00066 //----------------------------------------------------------------------- 00067 Material* Quake3Shader::createAsMaterial(SceneManager* sm, int lightmapNumber) 00068 { 00069 char matName[72]; 00070 sprintf(matName, "%s#%d", mName.c_str(), lightmapNumber); 00071 Material* mat = sm->createMaterial(matName); 00072 00073 char msg[256]; 00074 sprintf(msg, "Using Q3 shader %s", mName.c_str()); 00075 LogManager::getSingleton().logMessage(msg, LML_CRITICAL); 00076 for (int p = 0; p < numPasses; ++p) 00077 { 00078 TextureUnitState* t; 00079 // Create basic texture 00080 if (pass[p].textureName == "$lightmap") 00081 { 00082 char lightmapName[16]; 00083 sprintf(lightmapName, "@lightmap%d", lightmapNumber); 00084 t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(lightmapName); 00085 } 00086 // Animated texture support 00087 else if (pass[p].animNumFrames > 0) 00088 { 00089 Real sequenceTime = pass[p].animNumFrames / pass[p].animFps; 00090 /* Pre-load textures 00091 We need to know if each one was loaded OK since extensions may change for each 00092 Quake3 can still include alternate extension filenames e.g. jpg instead of tga 00093 Pain in the arse - have to check for each frame as letters<n>.tga for example 00094 is different per frame! 00095 */ 00096 for (unsigned int alt = 0; alt < pass[p].animNumFrames; ++alt) 00097 { 00098 try { 00099 TextureManager::getSingleton().load(pass[p].frames[alt]); 00100 } 00101 catch (...) 00102 { 00103 // Try alternate extension 00104 pass[p].frames[alt] = getAlternateName(pass[p].frames[alt]); 00105 try { 00106 TextureManager::getSingleton().load(pass[p].frames[alt]); 00107 } 00108 catch (...) 00109 { // stuffed - no texture 00110 } 00111 } 00112 00113 } 00114 00115 t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(""); 00116 t->setAnimatedTextureName(pass[p].frames, pass[p].animNumFrames, sequenceTime); 00117 00118 } 00119 else 00120 { 00121 // Quake3 can still include alternate extension filenames e.g. jpg instead of tga 00122 // Pain in the arse - have to check for failure 00123 try { 00124 TextureManager::getSingleton().load(pass[p].textureName); 00125 } 00126 catch (...) 00127 { 00128 // Try alternate extension 00129 pass[p].textureName = getAlternateName(pass[p].textureName); 00130 try { 00131 TextureManager::getSingleton().load(pass[p].textureName); 00132 } 00133 catch (...) 00134 { // stuffed - no texture 00135 } 00136 } 00137 t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(pass[p].textureName); 00138 } 00139 // Blending 00140 if (p == 0) 00141 { 00142 // scene blend 00143 mat->setSceneBlending(pass[p].blendSrc, pass[p].blendDest); 00144 if (mat->isTransparent() && 00145 pass[p].blendSrc != SBF_SOURCE_ALPHA) 00146 mat->setDepthWriteEnabled(false); 00147 00148 t->setColourOperation(LBO_REPLACE); 00149 } 00150 else 00151 { 00152 if (pass[p].customBlend) 00153 { 00154 // Fallback for now 00155 t->setColourOperation(LBO_MODULATE); 00156 } 00157 else 00158 { 00159 // simple layer blend 00160 t->setColourOperation(pass[p].blend); 00161 } 00162 } 00163 // Tex coords 00164 if (pass[p].texGen == TEXGEN_BASE) 00165 { 00166 t->setTextureCoordSet(0); 00167 } 00168 else if (pass[p].texGen == TEXGEN_LIGHTMAP) 00169 { 00170 t->setTextureCoordSet(1); 00171 } 00172 else if (pass[p].texGen == TEXGEN_ENVIRONMENT) 00173 { 00174 t->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR); 00175 } 00176 // Tex mod 00177 // Scale 00178 t->setTextureUScale(pass[p].tcModScale[0]); 00179 t->setTextureVScale(pass[p].tcModScale[1]); 00180 // Procedural mods 00181 // Custom - don't use mod if generating environment 00182 // Because I do env a different way it look horrible 00183 if (pass[p].texGen != TEXGEN_ENVIRONMENT) 00184 { 00185 if (pass[p].tcModRotate) 00186 { 00187 t->setRotateAnimation(pass[p].tcModRotate); 00188 } 00189 if (pass[p].tcModScroll[0] || pass[p].tcModScroll[1]) 00190 { 00191 if (pass[p].tcModTurbOn) 00192 { 00193 // Turbulent scroll 00194 if (pass[p].tcModScroll[0]) 00195 { 00196 t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_U, WFT_SINE, 00197 pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); 00198 } 00199 if (pass[p].tcModScroll[1]) 00200 { 00201 t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_V, WFT_SINE, 00202 pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]); 00203 } 00204 } 00205 else 00206 { 00207 // Constant scroll 00208 t->setScrollAnimation(pass[p].tcModScroll[0], pass[p].tcModScroll[1]); 00209 } 00210 } 00211 if (pass[p].tcModStretchWave != SHADER_FUNC_NONE) 00212 { 00213 WaveformType wft; 00214 switch(pass[p].tcModStretchWave) 00215 { 00216 case SHADER_FUNC_SIN: 00217 wft = WFT_SINE; 00218 break; 00219 case SHADER_FUNC_TRIANGLE: 00220 wft = WFT_TRIANGLE; 00221 break; 00222 case SHADER_FUNC_SQUARE: 00223 wft = WFT_SQUARE; 00224 break; 00225 case SHADER_FUNC_SAWTOOTH: 00226 wft = WFT_SAWTOOTH; 00227 break; 00228 case SHADER_FUNC_INVERSESAWTOOTH: 00229 wft = WFT_INVERSE_SAWTOOTH; 00230 break; 00231 00232 } 00233 // Create wave-based stretcher 00234 t->setTransformAnimation(TextureUnitState::TT_SCALE_U, wft, pass[p].tcModStretchParams[3], 00235 pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); 00236 t->setTransformAnimation(TextureUnitState::TT_SCALE_V, wft, pass[p].tcModStretchParams[3], 00237 pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]); 00238 } 00239 } 00240 // Address mode 00241 t->setTextureAddressingMode(pass[p].addressMode); 00242 // Alpha mode 00243 t->setAlphaRejectSettings(pass[p].alphaFunc, pass[p].alphaVal); 00244 00245 //assert(!t->isBlank()); 00246 00247 00248 } 00249 // Do farbox (create new material) 00250 00251 // Do skydome (use this material) 00252 if (skyDome) 00253 { 00254 // Quake3 is always aligned with Z upwards 00255 Quaternion q; 00256 q.FromAngleAxis(Math::HALF_PI, Vector3::UNIT_X); 00257 // Also draw last, and make close to camera (far clip plane is shorter) 00258 sm->setSkyDome(true, matName, 20 - (cloudHeight / 256 * 18), 12, 2000, false, q); 00259 } 00260 00261 00262 // Set culling mode and lighting to defaults 00263 mat->setCullingMode(CULL_NONE); 00264 mat->setManualCullingMode(cullMode); 00265 mat->setLightingEnabled(false); 00266 mat->load(); 00267 return mat; 00268 } 00269 String Quake3Shader::getAlternateName(const String& texName) 00270 { 00271 // Get alternative JPG to TGA and vice versa 00272 size_t pos; 00273 String ext, base; 00274 00275 pos = texName.find_last_of("."); 00276 ext = static_cast<String>(texName.substr(pos, 4)).toLowerCase(); 00277 base = texName.substr(0,pos); 00278 if (ext == ".jpg") 00279 { 00280 return base + ".tga"; 00281 } 00282 else 00283 { 00284 return base + ".jpg"; 00285 } 00286 00287 } 00288 }
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:23 2004