1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
#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
|