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 #include "OgreStableHeaders.h" 00026 // RenderSystem implementation 00027 // Note that most of this class is abstract since 00028 // we cannot know how to implement the behaviour without 00029 // being aware of the 3D API. However there are a few 00030 // simple functions which can have a base implementation 00031 00032 #include "OgreRenderSystem.h" 00033 00034 #include "OgreRoot.h" 00035 #include "OgreViewport.h" 00036 #include "OgreException.h" 00037 #include "OgreRenderTarget.h" 00038 #include "OgreRenderWindow.h" 00039 #include "OgreMeshManager.h" 00040 #include "OgreMaterial.h" 00041 #include "OgreTimer.h" 00042 00043 namespace Ogre { 00044 //----------------------------------------------------------------------- 00045 RenderSystem::RenderSystem() 00046 { 00047 mActiveViewport = 0; 00048 mActiveRenderTarget = NULL; 00049 mTextureManager = 0; 00050 mCapabilities = 0; 00051 mVSync = true; 00052 00053 00054 // This means CULL clockwise vertices, i.e. front of poly is counter-clockwise 00055 // This makes it the same as OpenGL and other right-handed systems 00056 mCullingMode = CULL_CLOCKWISE; 00057 mInvertVertexWinding = false; 00058 00059 // instanciate RenderSystemCapabilities 00060 mCapabilities = new RenderSystemCapabilities(); 00061 } 00062 00063 //----------------------------------------------------------------------- 00064 RenderSystem::~RenderSystem() 00065 { 00066 shutdown(); 00067 } 00068 //----------------------------------------------------------------------- 00069 void RenderSystem::_initRenderTargets(void) 00070 { 00071 00072 // Init stats 00073 for( 00074 RenderTargetMap::iterator it = mRenderTargets.begin(); 00075 it != mRenderTargets.end(); 00076 ++it ) 00077 { 00078 it->second->resetStatistics(); 00079 } 00080 00081 } 00082 //----------------------------------------------------------------------- 00083 void RenderSystem::_updateAllRenderTargets(void) 00084 { 00085 // Update all in order of priority 00086 // This ensures render-to-texture targets get updated before render windows 00087 RenderTargetPriorityMap::iterator itarg, itargend; 00088 itargend = mPrioritisedRenderTargets.end(); 00089 for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg ) 00090 { 00091 if( itarg->second->isActive() ) 00092 itarg->second->update(); 00093 } 00094 } 00095 //----------------------------------------------------------------------- 00096 RenderWindow* RenderSystem::initialise(bool autoCreateWindow) 00097 { 00098 // Have I been registered by call to Root::setRenderSystem? 00107 // Subclasses should take it from here 00108 // They should ALL call this superclass method from 00109 // their own initialise() implementations. 00110 00111 return 0; 00112 } 00113 //--------------------------------------------------------------------------------------------- 00114 void RenderSystem::attachRenderTarget( RenderTarget &target ) 00115 { 00116 assert( target.getPriority() < OGRE_NUM_RENDERTARGET_GROUPS ); 00117 00118 mRenderTargets.insert( RenderTargetMap::value_type( target.getName(), &target ) ); 00119 mPrioritisedRenderTargets.insert( 00120 RenderTargetPriorityMap::value_type(target.getPriority(), &target )); 00121 } 00122 00123 //--------------------------------------------------------------------------------------------- 00124 RenderTarget * RenderSystem::getRenderTarget( const String &name ) 00125 { 00126 RenderTargetMap::iterator it = mRenderTargets.find( name ); 00127 RenderTarget *ret = NULL; 00128 00129 if( it != mRenderTargets.end() ) 00130 { 00131 ret = it->second; 00132 } 00133 00134 return ret; 00135 } 00136 00137 //--------------------------------------------------------------------------------------------- 00138 RenderTarget * RenderSystem::detachRenderTarget( const String &name ) 00139 { 00140 RenderTargetMap::iterator it = mRenderTargets.find( name ); 00141 RenderTarget *ret = NULL; 00142 00143 if( it != mRenderTargets.end() ) 00144 { 00145 ret = it->second; 00146 00147 /* Remove the render target from the priority groups. */ 00148 RenderTargetPriorityMap::iterator itarg, itargend; 00149 itargend = mPrioritisedRenderTargets.end(); 00150 for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg ) 00151 { 00152 if( itarg->second == ret ) { 00153 mPrioritisedRenderTargets.erase( itarg ); 00154 break; 00155 } 00156 } 00157 00158 mRenderTargets.erase( it ); 00159 } 00160 00161 return ret; 00162 } 00163 //----------------------------------------------------------------------- 00164 Viewport* RenderSystem::_getViewport(void) 00165 { 00166 return mActiveViewport; 00167 } 00168 //----------------------------------------------------------------------- 00169 void RenderSystem::_setTextureUnitSettings(size_t texUnit, TextureUnitState& tl) 00170 { 00171 // This method is only ever called to set a texture unit to valid details 00172 // The method _disableTextureUnit is called to turn a unit off 00173 00174 // Texture name 00175 _setTexture(texUnit, true, tl.getTextureName()); 00176 00177 // Set texture coordinate set 00178 _setTextureCoordSet(texUnit, tl.getTextureCoordSet()); 00179 00180 // Set texture layer filtering 00181 _setTextureUnitFiltering(texUnit, 00182 tl.getTextureFiltering(FT_MIN), 00183 tl.getTextureFiltering(FT_MAG), 00184 tl.getTextureFiltering(FT_MIP)); 00185 00186 // Set texture layer filtering 00187 _setTextureLayerAnisotropy(texUnit, tl.getTextureAnisotropy()); 00188 00189 // Set blend modes 00190 _setTextureBlendMode(texUnit, tl.getColourBlendMode()); 00191 _setTextureBlendMode(texUnit, tl.getAlphaBlendMode()); 00192 00193 // Texture addressing mode 00194 _setTextureAddressingMode(texUnit, tl.getTextureAddressingMode() ); 00195 00196 // Set texture effects 00197 TextureUnitState::EffectMap::iterator effi; 00198 // Iterate over new effects 00199 bool anyCalcs = false; 00200 for (effi = tl.mEffects.begin(); effi != tl.mEffects.end(); ++effi) 00201 { 00202 switch (effi->second.type) 00203 { 00204 case TextureUnitState::ET_ENVIRONMENT_MAP: 00205 if (effi->second.subtype == TextureUnitState::ENV_CURVED) 00206 { 00207 _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP); 00208 anyCalcs = true; 00209 } 00210 else if (effi->second.subtype == TextureUnitState::ENV_PLANAR) 00211 { 00212 _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_PLANAR); 00213 anyCalcs = true; 00214 } 00215 else if (effi->second.subtype == TextureUnitState::ENV_REFLECTION) 00216 { 00217 _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_REFLECTION); 00218 anyCalcs = true; 00219 } 00220 else if (effi->second.subtype == TextureUnitState::ENV_NORMAL) 00221 { 00222 _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_NORMAL); 00223 anyCalcs = true; 00224 } 00225 break; 00226 case TextureUnitState::ET_SCROLL: 00227 case TextureUnitState::ET_ROTATE: 00228 case TextureUnitState::ET_TRANSFORM: 00229 break; 00230 } 00231 } 00232 // Ensure any previous texcoord calc settings are reset if there are now none 00233 if (!anyCalcs) 00234 { 00235 _setTextureCoordCalculation(texUnit, TEXCALC_NONE); 00236 _setTextureCoordSet(texUnit, tl.getTextureCoordSet()); 00237 } 00238 00239 // Change tetxure matrix 00240 _setTextureMatrix(texUnit, tl.getTextureTransform()); 00241 00242 // Set alpha rejection 00243 _setAlphaRejectSettings(tl.getAlphaRejectFunction(), 00244 tl.getAlphaRejectValue()); 00245 00246 } 00247 //----------------------------------------------------------------------- 00248 void RenderSystem::_disableTextureUnit(size_t texUnit) 00249 { 00250 _setTexture(texUnit, false, ""); 00251 } 00252 //--------------------------------------------------------------------- 00253 void RenderSystem::_disableTextureUnitsFrom(size_t texUnit) 00254 { 00255 for (size_t i = texUnit; i < mCapabilities->getNumTextureUnits(); ++i) 00256 { 00257 _disableTextureUnit(i); 00258 } 00259 } 00260 //----------------------------------------------------------------------- 00261 void RenderSystem::_setTextureUnitFiltering(size_t unit, FilterOptions minFilter, 00262 FilterOptions magFilter, FilterOptions mipFilter) 00263 { 00264 _setTextureUnitFiltering(unit, FT_MIN, minFilter); 00265 _setTextureUnitFiltering(unit, FT_MAG, magFilter); 00266 _setTextureUnitFiltering(unit, FT_MIP, mipFilter); 00267 } 00268 //----------------------------------------------------------------------- 00269 CullingMode RenderSystem::_getCullingMode(void) const 00270 { 00271 return mCullingMode; 00272 } 00273 //----------------------------------------------------------------------- 00274 bool RenderSystem::getWaitForVerticalBlank(void) const 00275 { 00276 return mVSync; 00277 } 00278 //----------------------------------------------------------------------- 00279 void RenderSystem::setWaitForVerticalBlank(bool enabled) 00280 { 00281 mVSync = enabled; 00282 } 00283 //----------------------------------------------------------------------- 00284 void RenderSystem::shutdown(void) 00285 { 00286 // Remove all the render targets. 00287 for( RenderTargetMap::iterator it = mRenderTargets.begin(); it != mRenderTargets.end(); ++it ) 00288 { 00289 delete it->second; 00290 } 00291 mRenderTargets.clear(); 00292 00293 mPrioritisedRenderTargets.clear(); 00294 } 00295 //----------------------------------------------------------------------- 00296 void RenderSystem::_beginGeometryCount(void) 00297 { 00298 mFaceCount = mVertexCount = 0; 00299 00300 } 00301 //----------------------------------------------------------------------- 00302 unsigned int RenderSystem::_getFaceCount(void) const 00303 { 00304 return static_cast< unsigned int >( mFaceCount ); 00305 } 00306 //----------------------------------------------------------------------- 00307 unsigned int RenderSystem::_getVertexCount(void) const 00308 { 00309 return static_cast< unsigned int >( mVertexCount ); 00310 } 00311 //----------------------------------------------------------------------- 00312 /* 00313 bool RenderSystem::_isVertexBlendSupported(void) 00314 { 00315 // TODO: implement vertex blending support in DX8 & possibly GL_ARB_VERTEX_BLEND (in subclasses) 00316 // DX7 support not good enough - only 4 matrices supported 00317 return false; 00318 } 00319 */ 00320 //----------------------------------------------------------------------- 00321 void RenderSystem::softwareVertexBlend(VertexData* vertexData, Matrix4* pMatrices) 00322 { 00323 // Source vectors 00324 Vector3 sourceVec, sourceNorm; 00325 // Accumulation vectors 00326 Vector3 accumVecPos, accumVecNorm; 00327 Matrix3 rot3x3; 00328 00329 Real *pSrcPos, *pSrcNorm, *pDestPos, *pDestNorm, *pBlendWeight; 00330 unsigned char* pBlendIdx; 00331 bool posNormShareBuffer = false; 00332 00333 const VertexElement* elemPos = 00334 vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 00335 const VertexElement* elemNorm = 00336 vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 00337 00338 HardwareVertexBufferSharedPtr posBuf, normBuf; 00339 posBuf = vertexData->vertexBufferBinding->getBuffer(elemPos->getSource()); 00340 if (elemNorm) 00341 { 00342 normBuf = vertexData->vertexBufferBinding->getBuffer(elemNorm->getSource()); 00343 posNormShareBuffer = (posBuf.get() == normBuf.get()); 00344 } 00345 // Lock buffers for writing 00346 assert (elemPos->getOffset() == 0 && 00347 "Positions must be first element in dedicated buffer!"); 00348 pDestPos = static_cast<Real*>( 00349 posBuf->lock(HardwareBuffer::HBL_DISCARD)); 00350 if (elemNorm) 00351 { 00352 if (posNormShareBuffer) 00353 { 00354 // Same buffer, must be packed directly after position 00355 assert (elemNorm->getOffset() == sizeof(Real) * 3 && 00356 "Normals must be packed directly after positions in buffer!"); 00357 // pDestNorm will not be used 00358 } 00359 else 00360 { 00361 // Different buffer 00362 assert (elemNorm->getOffset() == 0 && 00363 "Normals must be first element in dedicated buffer!"); 00364 pDestNorm = static_cast<Real*>( 00365 normBuf->lock(HardwareBuffer::HBL_DISCARD)); 00366 } 00367 } 00368 00369 // Loop per vertex 00370 pSrcPos = vertexData->softwareBlendInfo->pSrcPositions; 00371 pSrcNorm = vertexData->softwareBlendInfo->pSrcNormals; 00372 pBlendIdx = vertexData->softwareBlendInfo->pBlendIndexes; 00373 pBlendWeight = vertexData->softwareBlendInfo->pBlendWeights; 00374 // Make sure we have the source pointers we need 00375 assert(pSrcPos && pBlendIdx && pBlendWeight && (pSrcNorm || !elemNorm)); 00376 Vector3 tempVec; 00377 for (size_t vertIdx = 0; vertIdx < vertexData->vertexCount; ++vertIdx) 00378 { 00379 // Load source vertex elements 00380 sourceVec.x = *pSrcPos++; 00381 sourceVec.y = *pSrcPos++; 00382 sourceVec.z = *pSrcPos++; 00383 00384 if (elemNorm) 00385 { 00386 sourceNorm.x = *pSrcNorm++; 00387 sourceNorm.y = *pSrcNorm++; 00388 sourceNorm.z = *pSrcNorm++; 00389 } 00390 // Load accumulators 00391 accumVecPos = Vector3::ZERO; 00392 accumVecNorm = Vector3::ZERO; 00393 00394 // Loop per blend weight 00395 for (unsigned short blendIdx = 0; 00396 blendIdx < vertexData->softwareBlendInfo->numWeightsPerVertex; ++blendIdx) 00397 { 00398 // Blend by multiplying source by blend matrix and scaling by weight 00399 // Add to accumulator 00400 // NB weights must be normalised!! 00401 if (*pBlendWeight != 0.0) 00402 { 00403 // Blend position 00404 tempVec = pMatrices[*pBlendIdx] * sourceVec; 00405 tempVec *= *pBlendWeight; 00406 accumVecPos += tempVec; 00407 if (elemNorm) 00408 { 00409 // Blend normal 00410 // We should blend by inverse transpose here, but because we're assuming the 3x3 00411 // aspect of the matrix is orthogonal (no non-uniform scaling), the inverse transpose 00412 // is equal to the main 3x3 matrix 00413 // Note because it's a normal we just extract the rotational part, saves us renormalising here 00414 pMatrices[*pBlendIdx].extract3x3Matrix(rot3x3); 00415 tempVec = rot3x3 * sourceNorm; 00416 tempVec *= *pBlendWeight; 00417 accumVecNorm += tempVec; 00418 } 00419 00420 } 00421 ++pBlendWeight; 00422 ++pBlendIdx; 00423 } 00424 00425 // Stored blended vertex in hardware buffer 00426 *pDestPos++ = accumVecPos.x; 00427 *pDestPos++ = accumVecPos.y; 00428 *pDestPos++ = accumVecPos.z; 00429 00430 // Stored blended vertex in temp buffer 00431 if (elemNorm) 00432 { 00433 // Normalise 00434 accumVecNorm.normalise(); 00435 if (posNormShareBuffer) 00436 { 00437 // Pack into same buffer 00438 *pDestPos++ = accumVecNorm.x; 00439 *pDestPos++ = accumVecNorm.y; 00440 *pDestPos++ = accumVecNorm.z; 00441 } 00442 else 00443 { 00444 *pDestNorm++ = accumVecNorm.x; 00445 *pDestNorm++ = accumVecNorm.y; 00446 *pDestNorm++ = accumVecNorm.z; 00447 } 00448 } 00449 } 00450 posBuf->unlock(); 00451 if (elemNorm && !posNormShareBuffer) 00452 { 00453 normBuf->unlock(); 00454 } 00455 00456 } 00457 //----------------------------------------------------------------------- 00458 void RenderSystem::_setWorldMatrices(const Matrix4* m, unsigned short count) 00459 { 00460 if (!mCapabilities->hasCapability(RSC_VERTEXBLENDING)) 00461 { 00462 // Save these matrices for software blending later 00463 for (unsigned short i = 0; i < count; ++i) 00464 { 00465 mWorldMatrices[i] = m[i]; 00466 } 00467 // Set hardware matrix to nothing 00468 _setWorldMatrix(Matrix4::IDENTITY); 00469 } 00470 // TODO: implement vertex blending support in DX8 & possibly GL_ARB_VERTEX_BLEND (in subclasses) 00471 } 00472 //--------------------------------------------------------------------- 00473 void RenderSystem::setStencilBufferParams(CompareFunction func, ulong refValue, 00474 ulong mask, StencilOperation stencilFailOp, 00475 StencilOperation depthFailOp, StencilOperation passOp) 00476 { 00477 setStencilBufferFunction(func); 00478 setStencilBufferReferenceValue(refValue); 00479 setStencilBufferMask(mask); 00480 setStencilBufferFailOperation(stencilFailOp); 00481 setStencilBufferDepthFailOperation(depthFailOp); 00482 setStencilBufferPassOperation(passOp); 00483 } 00484 //----------------------------------------------------------------------- 00485 void RenderSystem::_render(const RenderOperation& op) 00486 { 00487 // Update stats 00488 size_t val; 00489 00490 if (op.useIndexes) 00491 val = op.indexData->indexCount; 00492 else 00493 val = op.vertexData->vertexCount; 00494 00495 switch(op.operationType) 00496 { 00497 case RenderOperation::OT_TRIANGLE_LIST: 00498 mFaceCount += val / 3; 00499 break; 00500 case RenderOperation::OT_TRIANGLE_STRIP: 00501 case RenderOperation::OT_TRIANGLE_FAN: 00502 mFaceCount += val - 2; 00503 break; 00504 case RenderOperation::OT_POINT_LIST: 00505 case RenderOperation::OT_LINE_LIST: 00506 case RenderOperation::OT_LINE_STRIP: 00507 break; 00508 } 00509 00510 mVertexCount += op.vertexData->vertexCount; 00511 00512 if (op.vertexData->softwareBlendInfo && op.vertexData->softwareBlendInfo->automaticBlend) 00513 { 00514 // Software Blend 00515 softwareVertexBlend(const_cast<VertexData*>(op.vertexData), mWorldMatrices); 00516 } 00517 } 00518 //----------------------------------------------------------------------- 00519 void RenderSystem::setInvertVertexWinding(bool invert) 00520 { 00521 mInvertVertexWinding = invert; 00522 } 00523 00524 } 00525
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:24 2004