/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2005 The OGRE Team Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. ----------------------------------------------------------------------------- */ #include "OgreStableHeaders.h" // RenderSystem implementation // Note that most of this class is abstract since // we cannot know how to implement the behaviour without // being aware of the 3D API. However there are a few // simple functions which can have a base implementation #include "OgreRenderSystem.h" #include "OgreRoot.h" #include "OgreViewport.h" #include "OgreException.h" #include "OgreRenderTarget.h" #include "OgreRenderWindow.h" #include "OgreMeshManager.h" #include "OgreMaterial.h" #include "OgreTimer.h" #include "OgreHardwareOcclusionQuery.h" namespace Ogre { const PlaneList Renderable::msDummyPlaneList; // FIX ME: temporary //----------------------------------------------------------------------- RenderSystem::RenderSystem() { mActiveViewport = 0; mActiveRenderTarget = NULL; mTextureManager = 0; mCapabilities = 0; mVSync = true; mWBuffer = false; // This means CULL clockwise vertices, i.e. front of poly is counter-clockwise // This makes it the same as OpenGL and other right-handed systems mCullingMode = CULL_CLOCKWISE; mInvertVertexWinding = false; // instanciate RenderSystemCapabilities mCapabilities = new RenderSystemCapabilities(); } //----------------------------------------------------------------------- RenderSystem::~RenderSystem() { shutdown(); delete mCapabilities; mCapabilities = 0; } //----------------------------------------------------------------------- void RenderSystem::_initRenderTargets(void) { // Init stats for( RenderTargetMap::iterator it = mRenderTargets.begin(); it != mRenderTargets.end(); ++it ) { it->second->resetStatistics(); } } //----------------------------------------------------------------------- void RenderSystem::_updateAllRenderTargets(void) { // Update all in order of priority // This ensures render-to-texture targets get updated before render windows RenderTargetPriorityMap::iterator itarg, itargend; itargend = mPrioritisedRenderTargets.end(); for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg ) { if( itarg->second->isActive() && itarg->second->isAutoUpdated()) itarg->second->update(); } } //----------------------------------------------------------------------- RenderWindow* RenderSystem::initialise(bool autoCreateWindow, const String& windowTitle) { // Have I been registered by call to Root::setRenderSystem? /** Don't do this anymore, just allow via Root RenderSystem* regPtr = Root::getSingleton().getRenderSystem(); if (!regPtr || regPtr != this) // Register self - library user has come to me direct Root::getSingleton().setRenderSystem(this); */ // Subclasses should take it from here // They should ALL call this superclass method from // their own initialise() implementations. return 0; } //--------------------------------------------------------------------------------------------- void RenderSystem::destroyRenderWindow(const String& name) { destroyRenderTarget(name); } //--------------------------------------------------------------------------------------------- void RenderSystem::destroyRenderTexture(const String& name) { destroyRenderTarget(name); } //--------------------------------------------------------------------------------------------- void RenderSystem::destroyRenderTarget(const String& name) { RenderTarget* rt = detachRenderTarget(name); delete rt; } //--------------------------------------------------------------------------------------------- void RenderSystem::attachRenderTarget( RenderTarget &target ) { assert( target.getPriority() < OGRE_NUM_RENDERTARGET_GROUPS ); mRenderTargets.insert( RenderTargetMap::value_type( target.getName(), &target ) ); mPrioritisedRenderTargets.insert( RenderTargetPriorityMap::value_type(target.getPriority(), &target )); } //--------------------------------------------------------------------------------------------- RenderTarget * RenderSystem::getRenderTarget( const String &name ) { RenderTargetMap::iterator it = mRenderTargets.find( name ); RenderTarget *ret = NULL; if( it != mRenderTargets.end() ) { ret = it->second; } return ret; } //--------------------------------------------------------------------------------------------- RenderTarget * RenderSystem::detachRenderTarget( const String &name ) { RenderTargetMap::iterator it = mRenderTargets.find( name ); RenderTarget *ret = NULL; if( it != mRenderTargets.end() ) { ret = it->second; /* Remove the render target from the priority groups. */ RenderTargetPriorityMap::iterator itarg, itargend; itargend = mPrioritisedRenderTargets.end(); for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg ) { if( itarg->second == ret ) { mPrioritisedRenderTargets.erase( itarg ); break; } } mRenderTargets.erase( it ); } return ret; } //----------------------------------------------------------------------- Viewport* RenderSystem::_getViewport(void) { return mActiveViewport; } //----------------------------------------------------------------------- void RenderSystem::_setTextureUnitSettings(size_t texUnit, TextureUnitState& tl) { // This method is only ever called to set a texture unit to valid details // The method _disableTextureUnit is called to turn a unit off // Texture name if (tl.isBlank()) { _setTexture(texUnit, true, StringUtil::BLANK); } else { _setTexture(texUnit, true, tl.getTextureName()); } // Set texture coordinate set _setTextureCoordSet(texUnit, tl.getTextureCoordSet()); // Set texture layer filtering _setTextureUnitFiltering(texUnit, tl.getTextureFiltering(FT_MIN), tl.getTextureFiltering(FT_MAG), tl.getTextureFiltering(FT_MIP)); // Set texture layer filtering _setTextureLayerAnisotropy(texUnit, tl.getTextureAnisotropy()); // Set blend modes // Note, colour before alpha is important _setTextureBlendMode(texUnit, tl.getColourBlendMode()); _setTextureBlendMode(texUnit, tl.getAlphaBlendMode()); // Texture addressing mode _setTextureAddressingMode(texUnit, tl.getTextureAddressingMode() ); // Set texture effects TextureUnitState::EffectMap::iterator effi; // Iterate over new effects bool anyCalcs = false; for (effi = tl.mEffects.begin(); effi != tl.mEffects.end(); ++effi) { switch (effi->second.type) { case TextureUnitState::ET_ENVIRONMENT_MAP: if (effi->second.subtype == TextureUnitState::ENV_CURVED) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_PLANAR) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_PLANAR); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_REFLECTION) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_REFLECTION); anyCalcs = true; } else if (effi->second.subtype == TextureUnitState::ENV_NORMAL) { _setTextureCoordCalculation(texUnit, TEXCALC_ENVIRONMENT_MAP_NORMAL); anyCalcs = true; } break; case TextureUnitState::ET_SCROLL: case TextureUnitState::ET_ROTATE: case TextureUnitState::ET_TRANSFORM: break; case TextureUnitState::ET_PROJECTIVE_TEXTURE: _setTextureCoordCalculation(texUnit, TEXCALC_PROJECTIVE_TEXTURE, effi->second.frustum); anyCalcs = true; break; } } // Ensure any previous texcoord calc settings are reset if there are now none if (!anyCalcs) { _setTextureCoordCalculation(texUnit, TEXCALC_NONE); _setTextureCoordSet(texUnit, tl.getTextureCoordSet()); } // Change tetxure matrix _setTextureMatrix(texUnit, tl.getTextureTransform()); } //----------------------------------------------------------------------- void RenderSystem::_disableTextureUnit(size_t texUnit) { _setTexture(texUnit, false, ""); _setTextureMatrix(texUnit, Matrix4::IDENTITY); } //--------------------------------------------------------------------- void RenderSystem::_disableTextureUnitsFrom(size_t texUnit) { for (size_t i = texUnit; i < mCapabilities->getNumTextureUnits(); ++i) { _disableTextureUnit(i); } } //----------------------------------------------------------------------- void RenderSystem::_setTextureUnitFiltering(size_t unit, FilterOptions minFilter, FilterOptions magFilter, FilterOptions mipFilter) { _setTextureUnitFiltering(unit, FT_MIN, minFilter); _setTextureUnitFiltering(unit, FT_MAG, magFilter); _setTextureUnitFiltering(unit, FT_MIP, mipFilter); } //----------------------------------------------------------------------- CullingMode RenderSystem::_getCullingMode(void) const { return mCullingMode; } //----------------------------------------------------------------------- bool RenderSystem::getWaitForVerticalBlank(void) const { return mVSync; } //----------------------------------------------------------------------- void RenderSystem::setWaitForVerticalBlank(bool enabled) { mVSync = enabled; } bool RenderSystem::getWBufferEnabled(void) const { return mWBuffer; } //----------------------------------------------------------------------- void RenderSystem::setWBufferEnabled(bool enabled) { mWBuffer = enabled; } //----------------------------------------------------------------------- void RenderSystem::shutdown(void) { // Remove occlusion queries for (HardwareOcclusionQueryList::iterator i = mHwOcclusionQueries.begin(); i != mHwOcclusionQueries.end(); ++i) { delete *i; } mHwOcclusionQueries.clear(); // Remove all the render targets. // (destroy primary target last since others may depend on it) RenderTarget* primary = 0; for (RenderTargetMap::iterator it = mRenderTargets.begin(); it != mRenderTargets.end(); ++it) { if (!primary && it->second->isPrimary()) primary = it->second; else delete it->second; } delete primary; mRenderTargets.clear(); mPrioritisedRenderTargets.clear(); } //----------------------------------------------------------------------- void RenderSystem::_beginGeometryCount(void) { mFaceCount = mVertexCount = 0; } //----------------------------------------------------------------------- unsigned int RenderSystem::_getFaceCount(void) const { return static_cast< unsigned int >( mFaceCount ); } //----------------------------------------------------------------------- unsigned int RenderSystem::_getVertexCount(void) const { return static_cast< unsigned int >( mVertexCount ); } //----------------------------------------------------------------------- void RenderSystem::_setWorldMatrices(const Matrix4* m, unsigned short count) { // Save these matrices for software blending later for (unsigned short i = 0; i < count; ++i) { mWorldMatrices[i] = m[i]; } // Set hardware matrix to nothing _setWorldMatrix(Matrix4::IDENTITY); } //----------------------------------------------------------------------- void RenderSystem::_render(const RenderOperation& op) { // Update stats size_t val; if (op.useIndexes) val = op.indexData->indexCount; else val = op.vertexData->vertexCount; switch(op.operationType) { case RenderOperation::OT_TRIANGLE_LIST: mFaceCount += val / 3; break; case RenderOperation::OT_TRIANGLE_STRIP: case RenderOperation::OT_TRIANGLE_FAN: mFaceCount += val - 2; break; case RenderOperation::OT_POINT_LIST: case RenderOperation::OT_LINE_LIST: case RenderOperation::OT_LINE_STRIP: break; } mVertexCount += op.vertexData->vertexCount; } //----------------------------------------------------------------------- void RenderSystem::setInvertVertexWinding(bool invert) { mInvertVertexWinding = invert; } //----------------------------------------------------------------------- void RenderSystem::setClipPlane (ushort index, const Plane &p) { setClipPlane (index, p.normal.x, p.normal.y, p.normal.z, p.d); } //----------------------------------------------------------------------- void RenderSystem::_notifyCameraRemoved(const Camera* cam) { RenderTargetMap::iterator i, iend; iend = mRenderTargets.end(); for (i = mRenderTargets.begin(); i != iend; ++i) { RenderTarget* target = i->second; target->_notifyCameraRemoved(cam); } } //----------------------------------------------------------------------- void RenderSystem::addListener(Listener* l) { mEventListeners.push_back(l); } //----------------------------------------------------------------------- void RenderSystem::removeListener(Listener* l) { mEventListeners.remove(l); } //----------------------------------------------------------------------- void RenderSystem::fireEvent(const String& name, const NameValuePairList* params) { for(ListenerList::iterator i = mEventListeners.begin(); i != mEventListeners.end(); ++i) { (*i)->eventOccurred(name, params); } } //----------------------------------------------------------------------- void RenderSystem::destroyHardwareOcclusionQuery( HardwareOcclusionQuery *hq) { for (HardwareOcclusionQueryList::iterator i = mHwOcclusionQueries.begin(); i != mHwOcclusionQueries.end(); ++i) { if (*i == hq) { delete *i; mHwOcclusionQueries.erase(i); break; } } } }