| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | #include <osg/StencilTwoSided> |
|---|
| 15 | #include <osg/State> |
|---|
| 16 | #include <osg/GLExtensions> |
|---|
| 17 | #include <osg/Notify> |
|---|
| 18 | |
|---|
| 19 | using namespace osg; |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | StencilTwoSided::StencilTwoSided() |
|---|
| 23 | { |
|---|
| 24 | |
|---|
| 25 | _func[FRONT] = _func[BACK] = ALWAYS; |
|---|
| 26 | _funcRef[FRONT] = _funcRef[BACK] = 0; |
|---|
| 27 | _funcMask[FRONT] = _funcMask[BACK] = ~0u; |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | _sfail[FRONT] = _sfail[BACK] = KEEP; |
|---|
| 31 | _zfail[FRONT] = _zfail[BACK] = KEEP; |
|---|
| 32 | _zpass[FRONT] = _zpass[BACK] = KEEP; |
|---|
| 33 | |
|---|
| 34 | _writeMask[FRONT] = _writeMask[BACK] = ~0u; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | StencilTwoSided::StencilTwoSided(const StencilTwoSided& stencil,const CopyOp& copyop): |
|---|
| 38 | StateAttribute(stencil,copyop) |
|---|
| 39 | { |
|---|
| 40 | _func[FRONT] = stencil._func[FRONT]; |
|---|
| 41 | _funcRef[FRONT] = stencil._funcRef[FRONT]; |
|---|
| 42 | _funcMask[FRONT] = stencil._funcMask[FRONT]; |
|---|
| 43 | _sfail[FRONT] = stencil._sfail[FRONT]; |
|---|
| 44 | _zfail[FRONT] = stencil._zfail[FRONT]; |
|---|
| 45 | _zpass[FRONT] = stencil._zpass[FRONT]; |
|---|
| 46 | _writeMask[FRONT] = stencil._writeMask[FRONT]; |
|---|
| 47 | |
|---|
| 48 | _func[BACK] = stencil._func[BACK]; |
|---|
| 49 | _funcRef[BACK] = stencil._funcRef[BACK]; |
|---|
| 50 | _funcMask[BACK] = stencil._funcMask[BACK]; |
|---|
| 51 | _sfail[BACK] = stencil._sfail[BACK]; |
|---|
| 52 | _zfail[BACK] = stencil._zfail[BACK]; |
|---|
| 53 | _zpass[BACK] = stencil._zpass[BACK]; |
|---|
| 54 | _writeMask[BACK] = stencil._writeMask[BACK]; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | StencilTwoSided::~StencilTwoSided() |
|---|
| 58 | { |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | int StencilTwoSided::compare(const StateAttribute& sa) const |
|---|
| 62 | { |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | COMPARE_StateAttribute_Types(StencilTwoSided,sa) |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | COMPARE_StateAttribute_Parameter(_func[FRONT]) |
|---|
| 69 | COMPARE_StateAttribute_Parameter(_funcRef[FRONT]) |
|---|
| 70 | COMPARE_StateAttribute_Parameter(_funcMask[FRONT]) |
|---|
| 71 | COMPARE_StateAttribute_Parameter(_sfail[FRONT]) |
|---|
| 72 | COMPARE_StateAttribute_Parameter(_zfail[FRONT]) |
|---|
| 73 | COMPARE_StateAttribute_Parameter(_zpass[FRONT]) |
|---|
| 74 | COMPARE_StateAttribute_Parameter(_writeMask[FRONT]) |
|---|
| 75 | |
|---|
| 76 | COMPARE_StateAttribute_Parameter(_func[BACK]) |
|---|
| 77 | COMPARE_StateAttribute_Parameter(_funcRef[BACK]) |
|---|
| 78 | COMPARE_StateAttribute_Parameter(_funcMask[BACK]) |
|---|
| 79 | COMPARE_StateAttribute_Parameter(_sfail[BACK]) |
|---|
| 80 | COMPARE_StateAttribute_Parameter(_zfail[BACK]) |
|---|
| 81 | COMPARE_StateAttribute_Parameter(_zpass[BACK]) |
|---|
| 82 | COMPARE_StateAttribute_Parameter(_writeMask[BACK]) |
|---|
| 83 | |
|---|
| 84 | return 0; |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | void StencilTwoSided::apply(State& state) const |
|---|
| 88 | { |
|---|
| 89 | |
|---|
| 90 | const unsigned int contextID = state.getContextID(); |
|---|
| 91 | const Extensions* extensions = getExtensions(contextID,true); |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | if (extensions->isOpenGL20Supported()) |
|---|
| 95 | { |
|---|
| 96 | |
|---|
| 97 | extensions->glStencilOpSeparate(GL_FRONT, (GLenum)_sfail[FRONT],(GLenum)_zfail[FRONT],(GLenum)_zpass[FRONT]); |
|---|
| 98 | extensions->glStencilMaskSeparate(GL_FRONT, _writeMask[FRONT]); |
|---|
| 99 | extensions->glStencilFuncSeparate(GL_FRONT, (GLenum)_func[FRONT],_funcRef[FRONT],_funcMask[FRONT]); |
|---|
| 100 | |
|---|
| 101 | |
|---|
| 102 | extensions->glStencilOpSeparate(GL_BACK, (GLenum)_sfail[BACK],(GLenum)_zfail[BACK],(GLenum)_zpass[BACK]); |
|---|
| 103 | extensions->glStencilMaskSeparate(GL_BACK, _writeMask[BACK]); |
|---|
| 104 | extensions->glStencilFuncSeparate(GL_BACK, (GLenum)_func[BACK],_funcRef[BACK],_funcMask[BACK]); |
|---|
| 105 | |
|---|
| 106 | return; |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | if (extensions->isStencilTwoSidedSupported()) |
|---|
| 111 | { |
|---|
| 112 | |
|---|
| 113 | glEnable(GL_STENCIL_TEST_TWO_SIDE); |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | extensions->glActiveStencilFace(GL_BACK); |
|---|
| 117 | glStencilOp((GLenum)_sfail[BACK],(GLenum)_zfail[BACK],(GLenum)_zpass[BACK]); |
|---|
| 118 | glStencilMask(_writeMask[BACK]); |
|---|
| 119 | glStencilFunc((GLenum)_func[BACK],_funcRef[BACK],_funcMask[BACK]); |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | extensions->glActiveStencilFace(GL_FRONT); |
|---|
| 123 | glStencilOp((GLenum)_sfail[FRONT],(GLenum)_zfail[FRONT],(GLenum)_zpass[FRONT]); |
|---|
| 124 | glStencilMask(_writeMask[FRONT]); |
|---|
| 125 | glStencilFunc((GLenum)_func[FRONT],_funcRef[FRONT],_funcMask[FRONT]); |
|---|
| 126 | |
|---|
| 127 | return; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | if (extensions->isSeparateStencilSupported()) |
|---|
| 132 | { |
|---|
| 133 | if( _writeMask[FRONT] != _writeMask[BACK] || |
|---|
| 134 | _funcRef[FRONT] != _funcRef[BACK] || |
|---|
| 135 | _funcMask[FRONT] != _funcMask[BACK] ) |
|---|
| 136 | { |
|---|
| 137 | OSG_WARN << "StencilTwoSided uses GL_ATI_separate_stencil and there are different\n" |
|---|
| 138 | " write mask, functionRef or functionMask values for the front and back\n" |
|---|
| 139 | " faces. This is not supported by the extension. Using front values only." << std::endl; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | glStencilMask(_writeMask[FRONT]); |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | extensions->glStencilOpSeparate(GL_FRONT, (GLenum)_sfail[FRONT], (GLenum)_zfail[FRONT], (GLenum)_zpass[FRONT]); |
|---|
| 146 | extensions->glStencilFuncSeparateATI((GLenum)_func[FRONT], (GLenum)_func[BACK], _funcRef[FRONT], _funcMask[FRONT]); |
|---|
| 147 | |
|---|
| 148 | |
|---|
| 149 | extensions->glStencilOpSeparate(GL_BACK, (GLenum)_sfail[BACK], (GLenum)_zfail[BACK], (GLenum)_zpass[BACK]); |
|---|
| 150 | extensions->glStencilFuncSeparateATI((GLenum)_func[FRONT], (GLenum)_func[BACK], _funcRef[FRONT], _funcMask[FRONT]); |
|---|
| 151 | |
|---|
| 152 | return; |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | OSG_WARN << "StencilTwoSided failed as the required graphics capabilities were\n" |
|---|
| 156 | " not found (contextID " << contextID << "). OpenGL 2.0 or one of extensions\n" |
|---|
| 157 | " GL_EXT_stencil_two_side or GL_ATI_separate_stencil is required." << std::endl; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | typedef buffered_value< ref_ptr<StencilTwoSided::Extensions> > BufferedExtensions; |
|---|
| 162 | static BufferedExtensions s_extensions; |
|---|
| 163 | |
|---|
| 164 | StencilTwoSided::Extensions* StencilTwoSided::getExtensions(unsigned int contextID,bool createIfNotInitalized) |
|---|
| 165 | { |
|---|
| 166 | if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID); |
|---|
| 167 | return s_extensions[contextID].get(); |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | void StencilTwoSided::setExtensions(unsigned int contextID,Extensions* extensions) |
|---|
| 171 | { |
|---|
| 172 | s_extensions[contextID] = extensions; |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | StencilTwoSided::Extensions::Extensions(unsigned int contextID) |
|---|
| 176 | { |
|---|
| 177 | setupGLExtensions(contextID); |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | StencilTwoSided::Extensions::Extensions(const Extensions& rhs): |
|---|
| 181 | Referenced() |
|---|
| 182 | { |
|---|
| 183 | _isStencilTwoSidedSupported = rhs._isStencilTwoSidedSupported; |
|---|
| 184 | _isOpenGL20Supported = rhs._isOpenGL20Supported; |
|---|
| 185 | _isSeparateStencilSupported = rhs._isSeparateStencilSupported; |
|---|
| 186 | _glActiveStencilFace = rhs._glActiveStencilFace; |
|---|
| 187 | _glStencilOpSeparate = rhs._glStencilOpSeparate; |
|---|
| 188 | _glStencilMaskSeparate = rhs._glStencilMaskSeparate; |
|---|
| 189 | _glStencilFuncSeparate = rhs._glStencilFuncSeparate; |
|---|
| 190 | _glStencilFuncSeparateATI = rhs._glStencilFuncSeparateATI; |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | |
|---|
| 194 | void StencilTwoSided::Extensions::lowestCommonDenominator(const Extensions& rhs) |
|---|
| 195 | { |
|---|
| 196 | if (!rhs._isStencilTwoSidedSupported) _isStencilTwoSidedSupported = false; |
|---|
| 197 | if (!rhs._isOpenGL20Supported) _isOpenGL20Supported = false; |
|---|
| 198 | if (!rhs._isSeparateStencilSupported) _isSeparateStencilSupported = false; |
|---|
| 199 | |
|---|
| 200 | if (!rhs._glActiveStencilFace) _glActiveStencilFace = NULL; |
|---|
| 201 | if (!rhs._glStencilOpSeparate) _glStencilOpSeparate = NULL; |
|---|
| 202 | if (!rhs._glStencilMaskSeparate) _glStencilMaskSeparate = NULL; |
|---|
| 203 | if (!rhs._glStencilFuncSeparate) _glStencilFuncSeparate = NULL; |
|---|
| 204 | if (!rhs._glStencilFuncSeparateATI) _glStencilFuncSeparateATI = NULL; |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | void StencilTwoSided::Extensions::setupGLExtensions(unsigned int contextID) |
|---|
| 208 | { |
|---|
| 209 | |
|---|
| 210 | _isStencilTwoSidedSupported = isGLExtensionSupported(contextID, "GL_EXT_stencil_two_side"); |
|---|
| 211 | _isOpenGL20Supported = getGLVersionNumber() >= 2.0; |
|---|
| 212 | _isSeparateStencilSupported = isGLExtensionSupported(contextID, "GL_ATI_separate_stencil"); |
|---|
| 213 | |
|---|
| 214 | |
|---|
| 215 | setGLExtensionFuncPtr(_glActiveStencilFace, "glActiveStencilFaceEXT"); |
|---|
| 216 | setGLExtensionFuncPtr(_glStencilOpSeparate, "glStencilOpSeparate", "glStencilOpSeparateATI"); |
|---|
| 217 | setGLExtensionFuncPtr(_glStencilMaskSeparate, "glStencilMaskSeparate"); |
|---|
| 218 | setGLExtensionFuncPtr(_glStencilFuncSeparate, "glStencilFuncSeparate"); |
|---|
| 219 | setGLExtensionFuncPtr(_glStencilFuncSeparateATI, "glStencilFuncSeparateATI"); |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | if (!_glActiveStencilFace) _isStencilTwoSidedSupported = false; |
|---|
| 223 | if (!_glStencilOpSeparate) { _isOpenGL20Supported = false; _isSeparateStencilSupported = false; } |
|---|
| 224 | if (!_glStencilMaskSeparate) _isOpenGL20Supported = false; |
|---|
| 225 | if (!_glStencilFuncSeparate) _isOpenGL20Supported = false; |
|---|
| 226 | if (!_glStencilFuncSeparateATI) _isSeparateStencilSupported = false; |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | if( _isOpenGL20Supported ) |
|---|
| 230 | { |
|---|
| 231 | OSG_INFO << "StencilTwoSided is going to use OpenGL 2.0 API (contextID " << contextID << ")." << std::endl; |
|---|
| 232 | } |
|---|
| 233 | else if( _isStencilTwoSidedSupported ) |
|---|
| 234 | { |
|---|
| 235 | OSG_INFO << "StencilTwoSided is going to use GL_EXT_stencil_two_side extension (contextID " << contextID << ")." << std::endl; |
|---|
| 236 | } |
|---|
| 237 | else if( _isSeparateStencilSupported ) |
|---|
| 238 | { |
|---|
| 239 | OSG_INFO << "StencilTwoSided is going to use GL_ATI_separate_stencil extension (contextID " << contextID << ")." << std::endl; |
|---|
| 240 | } |
|---|
| 241 | else |
|---|
| 242 | { |
|---|
| 243 | OSG_INFO << "StencilTwoSided did not found required graphics capabilities\n" |
|---|
| 244 | " (contextID " << contextID << "). OpenGL 2.0 or one of extensions\n" |
|---|
| 245 | " GL_EXT_stencil_two_side or GL_ATI_separate_stencil is required." << std::endl; |
|---|
| 246 | } |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | void StencilTwoSided::Extensions::glActiveStencilFace(GLenum face) const |
|---|
| 250 | { |
|---|
| 251 | if (_isStencilTwoSidedSupported) |
|---|
| 252 | { |
|---|
| 253 | _glActiveStencilFace(face); |
|---|
| 254 | } |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | void StencilTwoSided::Extensions::glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) const |
|---|
| 258 | { |
|---|
| 259 | if (_isOpenGL20Supported || _isSeparateStencilSupported) |
|---|
| 260 | { |
|---|
| 261 | _glStencilOpSeparate(face, sfail, dpfail, dppass); |
|---|
| 262 | } |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | void StencilTwoSided::Extensions::glStencilMaskSeparate(GLenum face, GLuint mask) const |
|---|
| 266 | { |
|---|
| 267 | if (_isOpenGL20Supported) |
|---|
| 268 | { |
|---|
| 269 | _glStencilMaskSeparate(face, mask); |
|---|
| 270 | } |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | void StencilTwoSided::Extensions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) const |
|---|
| 274 | { |
|---|
| 275 | if (_isOpenGL20Supported) |
|---|
| 276 | { |
|---|
| 277 | _glStencilFuncSeparate(face, func, ref, mask); |
|---|
| 278 | } |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | void StencilTwoSided::Extensions::glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) const |
|---|
| 282 | { |
|---|
| 283 | if (_isSeparateStencilSupported) |
|---|
| 284 | { |
|---|
| 285 | _glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); |
|---|
| 286 | } |
|---|
| 287 | } |
|---|