mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 20:56:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_COMPONENTS_SCENEUTIL_DEPTH_H
 | |
| #define OPENMW_COMPONENTS_SCENEUTIL_DEPTH_H
 | |
| 
 | |
| #include <osg/Depth>
 | |
| 
 | |
| #include "util.hpp"
 | |
| 
 | |
| #ifndef GL_DEPTH32F_STENCIL8_NV
 | |
| #define GL_DEPTH32F_STENCIL8_NV 0x8DAC
 | |
| #endif
 | |
| 
 | |
| #ifndef GL_DEPTH32F_STENCIL8
 | |
| #define GL_DEPTH32F_STENCIL8 0x8CAD
 | |
| #endif
 | |
| 
 | |
| #ifndef GL_FLOAT_32_UNSIGNED_INT_24_8_REV
 | |
| #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
 | |
| #endif
 | |
| 
 | |
| #ifndef GL_DEPTH24_STENCIL8
 | |
| #define GL_DEPTH24_STENCIL8 0x88F0
 | |
| #endif
 | |
| 
 | |
| #ifndef GL_DEPTH_STENCIL_EXT
 | |
| #define GL_DEPTH_STENCIL_EXT 0x84F9
 | |
| #endif
 | |
| 
 | |
| #ifndef GL_UNSIGNED_INT_24_8_EXT
 | |
| #define GL_UNSIGNED_INT_24_8_EXT 0x84FA
 | |
| #endif
 | |
| 
 | |
| namespace SceneUtil
 | |
| {
 | |
|     // Sets camera clear depth to 0 if reversed depth buffer is in use, 1 otherwise.
 | |
|     void setCameraClearDepth(osg::Camera* camera);
 | |
| 
 | |
|     // Returns a perspective projection matrix for use with a reversed z-buffer
 | |
|     // and an infinite far plane. This is derived by mapping the default z-range
 | |
|     // of [0,1] to [1,0], then taking the limit as far plane approaches infinity.
 | |
|     osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near);
 | |
| 
 | |
|     // Returns a perspective projection matrix for use with a reversed z-buffer.
 | |
|     osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far);
 | |
| 
 | |
|     // Returns an orthographic projection matrix for use with a reversed z-buffer.
 | |
|     osg::Matrix getReversedZProjectionMatrixAsOrtho(
 | |
|         double left, double right, double bottom, double top, double near, double far);
 | |
| 
 | |
|     // Returns true if the GL format is a depth format
 | |
|     bool isDepthFormat(GLenum format);
 | |
| 
 | |
|     // Returns true if the GL format is a depth+stencil format
 | |
|     bool isDepthStencilFormat(GLenum format);
 | |
| 
 | |
|     // Returns the corresponding source format and type for the given internal format
 | |
|     void getDepthFormatSourceFormatAndType(GLenum internalFormat, GLenum& sourceFormat, GLenum& sourceType);
 | |
| 
 | |
|     // Converts depth-stencil formats to their corresponding depth formats.
 | |
|     GLenum getDepthFormatOfDepthStencilFormat(GLenum internalFormat);
 | |
| 
 | |
|     // Brief wrapper around an osg::Depth that applies the reversed depth function when a reversed depth buffer is in
 | |
|     // use
 | |
|     class AutoDepth : public osg::Depth
 | |
|     {
 | |
|     public:
 | |
|         AutoDepth(
 | |
|             // NB: OSG uses LESS test function by default, Morrowind uses LEQUAL
 | |
|             osg::Depth::Function func = osg::Depth::LEQUAL, double zNear = 0.0, double zFar = 1.0,
 | |
|             bool writeMask = true)
 | |
|         {
 | |
|             setFunction(func);
 | |
|             setZNear(zNear);
 | |
|             setZFar(zFar);
 | |
|             setWriteMask(writeMask);
 | |
|         }
 | |
| 
 | |
|         AutoDepth(const osg::Depth& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY)
 | |
|             : osg::Depth(copy, copyop)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         osg::Object* cloneType() const override { return new AutoDepth; }
 | |
|         osg::Object* clone(const osg::CopyOp& copyop) const override { return new AutoDepth(*this, copyop); }
 | |
| 
 | |
|         void apply(osg::State& state) const override
 | |
|         {
 | |
|             glDepthFunc(static_cast<GLenum>(AutoDepth::isReversed() ? getReversedDepthFunction() : getFunction()));
 | |
|             glDepthMask(static_cast<GLboolean>(getWriteMask()));
 | |
| #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE)
 | |
|             glDepthRangef(getZNear(), getZFar());
 | |
| #else
 | |
|             glDepthRange(getZNear(), getZFar());
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         static void setReversed(bool reverseZ)
 | |
|         {
 | |
|             static bool init = false;
 | |
| 
 | |
|             if (!init)
 | |
|             {
 | |
|                 AutoDepth::sReversed = reverseZ;
 | |
|                 init = true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static bool isReversed()
 | |
|         {
 | |
|             return AutoDepth::sReversed;
 | |
|         }
 | |
| 
 | |
|         static void setDepthFormat(GLenum format);
 | |
| 
 | |
|         static GLenum depthInternalFormat()
 | |
|         {
 | |
|             return AutoDepth::sDepthInternalFormat;
 | |
|         }
 | |
| 
 | |
|         static GLenum depthSourceFormat()
 | |
|         {
 | |
|             return AutoDepth::sDepthSourceFormat;
 | |
|         }
 | |
| 
 | |
|         static GLenum depthSourceType()
 | |
|         {
 | |
|             return AutoDepth::sDepthSourceType;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         static inline bool sReversed = false;
 | |
|         static inline GLenum sDepthSourceFormat = GL_DEPTH_COMPONENT;
 | |
|         static inline GLenum sDepthInternalFormat = GL_DEPTH_COMPONENT24;
 | |
|         static inline GLenum sDepthSourceType = GL_UNSIGNED_INT;
 | |
| 
 | |
|         osg::Depth::Function getReversedDepthFunction() const
 | |
|         {
 | |
|             const osg::Depth::Function func = getFunction();
 | |
| 
 | |
|             switch (func)
 | |
|             {
 | |
|                 case osg::Depth::LESS:
 | |
|                     return osg::Depth::GREATER;
 | |
|                 case osg::Depth::LEQUAL:
 | |
|                     return osg::Depth::GEQUAL;
 | |
|                 case osg::Depth::GREATER:
 | |
|                     return osg::Depth::LESS;
 | |
|                 case osg::Depth::GEQUAL:
 | |
|                     return osg::Depth::LEQUAL;
 | |
|                 default:
 | |
|                     return func;
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     // Replaces all nodes osg::Depth state attributes with SceneUtil::AutoDepth.
 | |
|     class ReplaceDepthVisitor : public osg::NodeVisitor
 | |
|     {
 | |
|     public:
 | |
|         ReplaceDepthVisitor()
 | |
|             : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         void apply(osg::Node& node) override
 | |
|         {
 | |
|             osg::StateSet* stateSet = node.getStateSet();
 | |
| 
 | |
|             if (stateSet)
 | |
|             {
 | |
|                 if (osg::Depth* depth = static_cast<osg::Depth*>(stateSet->getAttribute(osg::StateAttribute::DEPTH)))
 | |
|                     stateSet->setAttribute(new SceneUtil::AutoDepth(*depth));
 | |
|             };
 | |
| 
 | |
|             traverse(node);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     class SelectDepthFormatOperation : public osg::GraphicsOperation
 | |
|     {
 | |
|     public:
 | |
|         SelectDepthFormatOperation()
 | |
|             : GraphicsOperation("SelectDepthFormatOperation", false)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         void operator()(osg::GraphicsContext* graphicsContext) override;
 | |
| 
 | |
|         void setSupportedFormats(const std::vector<GLenum>& supportedFormats) { mSupportedFormats = supportedFormats; }
 | |
| 
 | |
|     private:
 | |
|         std::vector<GLenum> mSupportedFormats;
 | |
|     };
 | |
| }
 | |
| 
 | |
| #endif
 |