/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library 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 * OpenSceneGraph Public License for more details. */ #ifndef OSG_CULLSTACK #define OSG_CULLSTACK 1 #include #include #include namespace osg { /** A CullStack class which accumulates the current project, modelview matrices and the CullingSet. */ class SG_EXPORT CullStack { public: CullStack(); ~CullStack(); typedef std::vector OccluderList; enum CullingModeValues { NO_CULLING = 0x0, VIEW_FRUSTUM_SIDES_CULLING = 0x1, NEAR_PLANE_CULLING = 0x2, FAR_PLANE_CULLING = 0x4, VIEW_FRUSTUM_CULLING = VIEW_FRUSTUM_SIDES_CULLING| NEAR_PLANE_CULLING| FAR_PLANE_CULLING, SMALL_FEATURE_CULLING = 0x8, SHADOW_OCCLUSION_CULLING = 0x10, DEFAULT_CULLING = VIEW_FRUSTUM_SIDES_CULLING| SMALL_FEATURE_CULLING| SHADOW_OCCLUSION_CULLING, ENABLE_ALL_CULLING = VIEW_FRUSTUM_CULLING| SMALL_FEATURE_CULLING| SHADOW_OCCLUSION_CULLING }; typedef unsigned int CullingMode; void reset(); void setOccluderList(const ShadowVolumeOccluderList& svol) { _occluderList = svol; } ShadowVolumeOccluderList& getOccluderList() { return _occluderList; } const ShadowVolumeOccluderList& getOccluderList() const { return _occluderList; } void pushViewport(osg::Viewport* viewport); void popViewport(); void pushProjectionMatrix(osg::RefMatrix* matrix); void popProjectionMatrix(); void pushModelViewMatrix(osg::RefMatrix* matrix); void popModelViewMatrix(); inline float getFrustumVolume() { if (_frustumVolume<0.0f) computeFrustumVolume(); return _frustumVolume; } /** Sets the current CullingMode.*/ void setCullingMode(CullingMode mode) { _cullingMode = mode; } /** Returns the current CullingMode.*/ CullingMode getCullingMode() const { return _cullingMode; } void setLODScale(float bias) { _LODScale = bias; } float getLODScale() const { return _LODScale; } void setSmallFeatureCullingPixelSize(float value) { _smallFeatureCullingPixelSize=value; } float getSmallFeatureCullingPixelSize() const { return _smallFeatureCullingPixelSize; } /** Compute the pixel of an object at position v, with specified radius.*/ float pixelSize(const Vec3& v,float radius) const { return getCurrentCullingSet().pixelSize(v,radius); } /** Compute the pixel of an bounding sphere.*/ float pixelSize(const BoundingSphere& bs) const { return pixelSize(bs.center(),bs.radius()); } inline void disableAndPushOccludersCurrentMask(NodePath& nodePath) { getCurrentCullingSet().disableAndPushOccludersCurrentMask(nodePath); } inline void popOccludersCurrentMask(NodePath& nodePath) { getCurrentCullingSet().popOccludersCurrentMask(nodePath); } inline bool isCulled(const std::vector& vertices) { return getCurrentCullingSet().isCulled(vertices); } inline bool isCulled(const BoundingBox& bb) { return bb.valid() && getCurrentCullingSet().isCulled(bb); } inline bool isCulled(const BoundingSphere& bs) { return getCurrentCullingSet().isCulled(bs); } inline bool isCulled(const osg::Node& node) { return node.isCullingActive() && getCurrentCullingSet().isCulled(node.getBound()); } inline void pushCurrentMask() { getCurrentCullingSet().pushCurrentMask(); } inline void popCurrentMask() { getCurrentCullingSet().popCurrentMask(); } typedef std::vector< CullingSet > CullingStack; inline CullingStack& getClipSpaceCullingStack() { return _clipspaceCullingStack; } inline CullingStack& getProjectionCullingStack() { return _projectionCullingStack; } inline CullingStack& getModelViewCullingStack() { return _modelviewCullingStack; } // inline CullingSet& getCurrentCullingSet() { return _modelviewCullingStack.back(); } // inline const CullingSet& getCurrentCullingSet() const { return _modelviewCullingStack.back(); } inline CullingSet& getCurrentCullingSet() { return *_back_modelviewCullingStack; } inline const CullingSet& getCurrentCullingSet() const { return *_back_modelviewCullingStack; } inline osg::Viewport* getViewport(); inline osg::RefMatrix& getModelViewMatrix(); inline osg::RefMatrix& getProjectionMatrix(); inline osg::Matrix getWindowMatrix(); inline const osg::RefMatrix& getMVPW(); inline const osg::Vec3& getEyeLocal() const { return _eyePointStack.back(); } inline const osg::Vec3 getUpLocal() const { const osg::Matrix& matrix = *_modelviewStack.back(); return osg::Vec3(matrix(0,1),matrix(1,1),matrix(2,1)); } inline const osg::Vec3 getLookVectorLocal() const { const osg::Matrix& matrix = *_modelviewStack.back(); return osg::Vec3(-matrix(0,2),-matrix(1,2),-matrix(2,2)); } protected: void pushCullingSet(); void popCullingSet(); CullingMode _cullingMode; float _LODScale; float _smallFeatureCullingPixelSize; // base set of shadow volume occluder to use in culling. ShadowVolumeOccluderList _occluderList; typedef fast_back_stack< ref_ptr > MatrixStack; MatrixStack _projectionStack; MatrixStack _modelviewStack; MatrixStack _MVPW_Stack; typedef fast_back_stack > ViewportStack; ViewportStack _viewportStack; typedef fast_back_stack EyePointStack; EyePointStack _eyePointStack; CullingStack _clipspaceCullingStack; CullingStack _projectionCullingStack; CullingStack _modelviewCullingStack; unsigned int _index_modelviewCullingStack; CullingSet* _back_modelviewCullingStack; void computeFrustumVolume(); float _frustumVolume; unsigned int _bbCornerNear; unsigned int _bbCornerFar; ref_ptr _identity; typedef std::vector< osg::ref_ptr > MatrixList; MatrixList _reuseMatrixList; unsigned int _currentReuseMatrixIndex; inline osg::RefMatrix* createOrReuseMatrix(const osg::Matrix& value); }; inline osg::Viewport* CullStack::getViewport() { if (!_viewportStack.empty()) { return _viewportStack.back().get(); } else { return 0L; } } inline osg::RefMatrix& CullStack::getModelViewMatrix() { if (!_modelviewStack.empty()) { return *_modelviewStack.back(); } else { return *_identity; } } inline osg::RefMatrix& CullStack::getProjectionMatrix() { if (!_projectionStack.empty()) { return *_projectionStack.back(); } else { return *_identity; } } inline osg::Matrix CullStack::getWindowMatrix() { if (!_viewportStack.empty()) { osg::Viewport* viewport = _viewportStack.back().get(); return viewport->computeWindowMatrix(); } else { return *_identity; } } inline const osg::RefMatrix& CullStack::getMVPW() { if (!_MVPW_Stack.empty()) { if (!_MVPW_Stack.back()) { _MVPW_Stack.back() = createOrReuseMatrix(getModelViewMatrix()); (*_MVPW_Stack.back()) *= getProjectionMatrix(); (*_MVPW_Stack.back()) *= getWindowMatrix(); } return *_MVPW_Stack.back(); } else { return *_identity; } } inline RefMatrix* CullStack::createOrReuseMatrix(const osg::Matrix& value) { // skip of any already reused matrix. while (_currentReuseMatrixIndex<_reuseMatrixList.size() && _reuseMatrixList[_currentReuseMatrixIndex]->referenceCount()>1) { ++_currentReuseMatrixIndex; } // if still within list, element must be singularly referenced // there return it to be reused. if (_currentReuseMatrixIndex<_reuseMatrixList.size()) { RefMatrix* matrix = _reuseMatrixList[_currentReuseMatrixIndex++].get(); matrix->set(value); return matrix; } // otherwise need to create new matrix. osg::RefMatrix* matrix = new RefMatrix(value); _reuseMatrixList.push_back(matrix); ++_currentReuseMatrixIndex; return matrix; } } // end of namespace #endif