You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/sceneutil/depth.hpp

196 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