diff --git a/include/osgText/Text b/include/osgText/Text index 66c0df307..db497792f 100644 --- a/include/osgText/Text +++ b/include/osgText/Text @@ -72,74 +72,16 @@ public: enum BackdropImplementation { - /* POLYGON_OFFSET: - * This uses glPolygonOffset to draw the text multiple times to - * create the drop-shadow and outline effects. glPolygonOffset - * is used to prevent z-fighting of the overlapping text. - * This probably should have been the best option, but all the ATI - * cards we have encountered so far have serious problems with this. - * We see little white holes/artifacts in the rendered glyph textures - * which move around depending on the viewing angle. For moving text, - * the moving holes give an extremely unpleasant flickering effect. - * Pumping up the "units" parameter in glPolygonOffset can minimize - * this problem, but two other bad side-effects occur if you do this. - * First, high values will cause problems with clipping, particularly - * when there are objects behind the text. The drop-shadows or outline - * may be culled because their computed offset is behind the object or - * z-far plane. Second, there is an additional problem associated with - * the Z-slope. High values can make large chunks of the backdrop - * suddenly disappear. This can be reduced by the "factor" parameter. - * Making the "factor" value small, can help, but experimentally, we've - * found that it creates a new, different kind of z-fighting problem. - * So there is no perfect solution. With units, you trade off the 'holes' - * for the large-section clipping. - * Experimentally, we have found units values from 150-512 to be tolerable - * to acceptable with respect to the 'holes'. A factor of .1 seems to - * bring down the large clipping problem without creating a new z-fighting - * problem. - * (You can experiment with these numbers by playing with the - * osg:PolygonOffset multipliers which this backend tries to respect.) - * - * If ATI ever fixes their cards/drivers, then this might become the - * best option.*/ + /* No longer supported, naps to DELAYED_DEPTH_WRITES.*/ POLYGON_OFFSET = 0, - /* NO_DEPTH_BUFFER - * Instead of using glPolygonOffset to prevent z-fighting, this mode - * just disables the depth buffer when rendering the text. This allows - * the text to be rendered without any z-fighting. The downside to this - * mode is that render order begins to matter and the text will not - * necessarily correctly appear above or behind other objects in the - * scene based on depth values. - * This mode is best for text that only needs to be ontop and - * not obscured by any objects.*/ + /* No longer supported, naps to DELAYED_DEPTH_WRITES.*/ NO_DEPTH_BUFFER, - /* DEPTH_RANGE - * This mode is inspired by Paul Martz's OpenGL FAQ, item 13.050. - * This uses glDepthRange as a substitute for glPolygonOffset. - * Strangely, experiments on ATI cards seem to produce cleaner results - * than when using glPolygonOffset. The trade-off for this is that the - * backdrop still may be placed too far back and might be culled by objects - * directly behind the object or by the far z-plane. If ATI ever fixes - * the glPolygonOffset problem, polygon offset is probably a slightly - * better solution because you can use smaller offsets. But with the - * current ATI problem, this option may be preferable.*/ + /* No longer supported, naps to DELAYED_DEPTH_WRITES.*/ DEPTH_RANGE, - /* STENCIL_BUFFER - * (Assuming the backend is written correctly,) the Stencil Buffer is - * the most "correct" and reliable way of producing backdrop text. - * The stencil buffer is a multipass system that allows writing to the - * same z-values without needing to resort to offsets. This implementation - * should not have any of the problems associated with the 3 previous - * implementations. But the trade-off for this mode is that without - * hardware acceleration for the stencil buffer, rendering will be - * extremely slow. (There is also potentially more overhead for this - * algorithm so it could be slower than the other implementations. - * Benchmarking would be required to determine if the speed differences - * are significant on your particular hardware.) This mode is best for - * when quality is important and stencil buffer hardware acceleration - * is available.*/ + + /* No longer supported, naps to DELAYED_DEPTH_WRITES.*/ STENCIL_BUFFER, /* DELAYED_DEPTH_WRITES @@ -372,15 +314,6 @@ protected: void drawImplementationSinglePass(osg::State& state, const osg::Vec4& colorMultiplier) const; - void drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const; - void drawTextWithBackdrop(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderWithNoDepthBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderWithDepthRange(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderWithStencilBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const; - void renderWithDelayedDepthWrites(osg::State& state, const osg::Vec4& colorMultiplier) const; - bool _enableDepthWrites; BackdropType _backdropType; diff --git a/src/osgText/Text.cpp b/src/osgText/Text.cpp index cb19ebf64..2023a8951 100644 --- a/src/osgText/Text.cpp +++ b/src/osgText/Text.cpp @@ -1174,8 +1174,6 @@ void Text::drawImplementationSinglePass(osg::State& state, const osg::Vec4& colo } -#ifdef NEW_APPROACH - void Text::drawImplementation(osg::State& state, const osg::Vec4& colorMultiplier) const { bool usingVertexBufferObjects = state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects); @@ -1227,15 +1225,18 @@ void Text::drawImplementation(osg::State& state, const osg::Vec4& colorMultiplie drawImplementationSinglePass(state, colorMultiplier); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glDepthMask(GL_TRUE); + if (_enableDepthWrites) + { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glDepthMask(GL_TRUE); - drawImplementationSinglePass(state, colorMultiplier); + drawImplementationSinglePass(state, colorMultiplier); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + state.haveAppliedAttribute(osg::StateAttribute::COLORMASK); + } state.haveAppliedAttribute(osg::StateAttribute::DEPTH); - state.haveAppliedAttribute(osg::StateAttribute::COLORMASK); #endif if (usingVertexBufferObjects && !usingVertexArrayObjects) @@ -1257,174 +1258,6 @@ void Text::drawImplementation(osg::State& state, const osg::Vec4& colorMultiplie -#else -void Text::drawImplementation(osg::State& state, const osg::Vec4& colorMultiplier) const -{ - bool usingVertexBufferObjects = state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects); - - state.applyMode(GL_BLEND,true); -#if defined(OSG_GL_FIXED_FUNCTION_AVAILABLE) - state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON); - state.applyTextureAttribute(0,getActiveFont()->getTexEnv()); -#endif - - // save the previous modelview matrix - osg::Matrix previous_modelview = state.getModelViewMatrix(); - - // set up the new modelview matrix - osg::Matrix modelview; - bool needToApplyMatrix = computeMatrix(modelview, &state); - - if (needToApplyMatrix) - { - // ** mult previous by the modelview for this context - modelview.postMult(previous_modelview); - - // ** apply this new modelview matrix - state.applyModelViewMatrix(modelview); - - // workaround for GL3/GL2 - if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired(); - - // OSG_NOTICE<<"New state.applyModelViewMatrix() "<getRequiresSetArrays(); - - if (requiresSetArrays) - { - vas->lazyDisablingOfVertexAttributes(); - vas->setVertexArray(state, _coords.get()); - vas->setTexCoordArray(state, 0, _texcoords.get()); - vas->applyDisablingOfVertexAttributes(state); - } - - - if ((_drawMode&(~TEXT))!=0) - { - - if (!_decorationPrimitives.empty()) - { - osg::State::ApplyModeProxy applyMode(state, GL_LIGHTING, false); - osg::State::ApplyTextureModeProxy applyTextureMode(state, 0, GL_TEXTURE_2D, false); - - #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) - switch(_backdropImplementation) - { - case NO_DEPTH_BUFFER: - // Do nothing. The bounding box will be rendered before the text and that's all that matters. - break; - case DEPTH_RANGE: - glPushAttrib(GL_DEPTH_BUFFER_BIT); - //unsigned int backdrop_index = 0; - //unsigned int max_backdrop_index = 8; - //const double offset = double(max_backdrop_index - backdrop_index) * 0.003; - glDepthRange(0.001, 1.001); - break; - /*case STENCIL_BUFFER: - break;*/ - default: - glPushAttrib(GL_POLYGON_OFFSET_FILL); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.1f * osg::PolygonOffset::getFactorMultiplier(), 10.0f * osg::PolygonOffset::getUnitsMultiplier() ); - } - #endif - - for(Primitives::const_iterator itr = _decorationPrimitives.begin(); - itr != _decorationPrimitives.end(); - ++itr) - { - if ((*itr)->getMode()==GL_TRIANGLES) state.Color(colorMultiplier.r()*_textBBColor.r(), colorMultiplier.g()*_textBBColor.g(), colorMultiplier.b()*_textBBColor.b(), colorMultiplier.a()*_textBBColor.a()); - else state.Color(colorMultiplier.r(), colorMultiplier.g(), colorMultiplier.b(), colorMultiplier.a()); - - (*itr)->draw(state, usingVertexBufferObjects); - } - - #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) - switch(_backdropImplementation) - { - case NO_DEPTH_BUFFER: - // Do nothing. - break; - case DEPTH_RANGE: - glDepthRange(0.0, 1.0); - glPopAttrib(); - break; - /*case STENCIL_BUFFER: - break;*/ - default: - glDisable(GL_POLYGON_OFFSET_FILL); - glPopAttrib(); - } - #endif - } - } - -#if defined(OSG_GL_FIXED_FUNCTION_AVAILABLE) - state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON); - state.applyTextureAttribute(0,getActiveFont()->getTexEnv()); -#endif - - if (_drawMode & TEXT) - { - - // Okay, since ATI's cards/drivers are not working correctly, - // we need alternative solutions to glPolygonOffset. - // So this is a pick your poison approach. Each alternative - // backend has trade-offs associated with it, but with luck, - // the user may find that works for them. - if(_backdropType != NONE && _backdropImplementation != DELAYED_DEPTH_WRITES) - { - switch(_backdropImplementation) - { - case POLYGON_OFFSET: - renderWithPolygonOffset(state,colorMultiplier); - break; - case NO_DEPTH_BUFFER: - renderWithNoDepthBuffer(state,colorMultiplier); - break; - case DEPTH_RANGE: - renderWithDepthRange(state,colorMultiplier); - break; - case STENCIL_BUFFER: - renderWithStencilBuffer(state,colorMultiplier); - break; - default: - renderWithPolygonOffset(state,colorMultiplier); - } - } - else - { - renderWithDelayedDepthWrites(state,colorMultiplier); - } - - } - - if (!usingVertexArrayObjects) - { - // unbind the VBO's if any are used. - vas->unbindVertexBufferObject(); - vas->unbindElementBufferObject(); - } - - if (needToApplyMatrix) - { - // apply this new modelview matrix - - // workaround for GL3/GL2 - if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired(); - } -} -#endif - void Text::accept(osg::Drawable::ConstAttributeFunctor& af) const { if (_coords.valid() ) @@ -1538,445 +1371,6 @@ float Text::bilinearInterpolate(float x1, float x2, float y1, float y2, float x, ); } -void Text::drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const -{ - if (glyphquad._primitives.empty()) return; - - const Coords& coords = _coords; - const ColorCoords& colors = _colorCoords; - - bool usingVertexBufferObjects = state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects); - - if (coords.valid() && !coords->empty()) - { - VertexArrayState* vas = state.getCurrentVertexArrayState(); - bool usingVertexArrayObjects = usingVertexBufferObjects && state.useVertexArrayObject(_useVertexArrayObject); - - if(_colorGradientMode == SOLID) - { - vas->disableColorArray(state); - state.Color(colorMultiplier.r()*_color.r(),colorMultiplier.g()*_color.g(),colorMultiplier.b()*_color.b(),colorMultiplier.a()*_color.a()); - } - else - { - bool requiresSetArrays = (_backdropType!=NONE) || !usingVertexBufferObjects || !usingVertexArrayObjects || vas->getRequiresSetArrays(); - if (requiresSetArrays) - { - vas->setColorArray(state, colors.get()); - } - } - - glyphquad._primitives[0]->draw(state, usingVertexBufferObjects); - } -} - -void Text::renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMultiplier) const -{ - for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); - titr!=_textureGlyphQuadMap.end(); - ++titr) - { - // need to set the texture here... - state.applyTextureAttribute(0,titr->first.get()); - - const GlyphQuads& glyphquad = titr->second; - - drawForegroundText(state, glyphquad, colorMultiplier); - } -} - -void Text::renderWithDelayedDepthWrites(osg::State& state, const osg::Vec4& colorMultiplier) const -{ - // If depth testing is disabled, then just render text as normal - if( !state.getLastAppliedMode(GL_DEPTH_TEST) ) { - drawTextWithBackdrop(state,colorMultiplier); - return; - } - - //glPushAttrib( _enableDepthWrites ? (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) : GL_DEPTH_BUFFER_BIT); - // Render to color buffer without writing to depth buffer. - glDepthMask(GL_FALSE); - drawTextWithBackdrop(state,colorMultiplier); - - // Render to depth buffer if depth writes requested. - if( _enableDepthWrites ) - { - glDepthMask(GL_TRUE); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - drawTextWithBackdrop(state,colorMultiplier); - } - - state.haveAppliedAttribute(osg::StateAttribute::DEPTH); - state.haveAppliedAttribute(osg::StateAttribute::COLORMASK); - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - //glPopAttrib(); -} - -void Text::drawTextWithBackdrop(osg::State& state, const osg::Vec4& colorMultiplier) const -{ - bool usingVertexBufferObjects = state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects); - - for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); - titr!=_textureGlyphQuadMap.end(); - ++titr) - { - // need to set the texture here... - state.applyTextureAttribute(0,titr->first.get()); - - const GlyphQuads& glyphquad = titr->second; - - if(_backdropType != NONE) - { - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - state.disableColorPointer(); - state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - } - - drawForegroundText(state, glyphquad, colorMultiplier); - } -} - - -void Text::renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const -{ -#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) - - bool usingVertexBufferObjects = state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects); - VertexArrayState* vas = state.getCurrentVertexArrayState(); - - if (!osg::PolygonOffset::areFactorAndUnitsMultipliersSet()) - { - osg::PolygonOffset::setFactorAndUnitsMultipliersUsingBestGuessForDriver(); - } - - // Do I really need to do this for glPolygonOffset? - glPushAttrib(GL_POLYGON_OFFSET_FILL); - glEnable(GL_POLYGON_OFFSET_FILL); - - for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); - titr!=_textureGlyphQuadMap.end(); - ++titr) - { - // need to set the texture here... - state.applyTextureAttribute(0,titr->first.get()); - - const GlyphQuads& glyphquad = titr->second; - - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - vas->disableColorArray(state); - state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - float factor = 0.1f * osg::PolygonOffset::getFactorMultiplier(); - float units = 10.0f * float((max_backdrop_index-backdrop_index)) * osg::PolygonOffset::getUnitsMultiplier(); - glPolygonOffset(factor, units); - - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - - // Reset the polygon offset so the foreground text is on top - glPolygonOffset(0.0f,0.0f); - - drawForegroundText(state, glyphquad, colorMultiplier); - } - - glPopAttrib(); -#else - OSG_NOTICE<<"Warning: Text::renderWithPolygonOffset(..) not implemented."<first.get()); - - const GlyphQuads& glyphquad = titr->second; - - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - - state.disableColorPointer(); - state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - - drawForegroundText(state, glyphquad, colorMultiplier); - } - - glPopAttrib(); -#else - OSG_NOTICE<<"Warning: Text::renderWithNoDepthBuffer(..) not implemented."<first.get()); - - const GlyphQuads& glyphquad = titr->second; - - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - state.disableColorPointer(); - state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - double offset = double(max_backdrop_index-backdrop_index)*0.0001; - glDepthRange( offset, 1.0+offset); - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - - glDepthRange(0.0, 1.0); - - drawForegroundText(state, glyphquad, colorMultiplier); - } - - glPopAttrib(); -#else - OSG_NOTICE<<"Warning: Text::renderWithDepthRange(..) not implemented."<second; - if (glyphquad._primitives.empty()) continue; - - // need to set the texture here... - state.applyTextureAttribute(0, titr->first.get()); - - - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - - // Draw the foreground text - glyphquad._primitives[0]->draw(state, usingVertexBufferObjects); - } - - - // disable the depth buffer -// glDisable(GL_DEPTH_TEST); -// glDepthMask(GL_FALSE); -// glDepthMask(GL_TRUE); -// glDepthFunc(GL_ALWAYS); - - // Set the stencil function to pass when the stencil is 1 - // Bug: This call seems to have no effect. Try changing to NOTEQUAL - // and see the exact same results. - glStencilFunc(GL_EQUAL, 1, 1); - - // disable writing to the stencil buffer - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMask(GL_FALSE); - - // Re-enable writing to the color buffer so we can see the results - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - // Draw all the text again - - for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin(); - titr!=_textureGlyphQuadMap.end(); - ++titr) - { - // need to set the texture here... - state.applyTextureAttribute(0,titr->first.get()); - - const GlyphQuads& glyphquad = titr->second; - - unsigned int backdrop_index; - unsigned int max_backdrop_index; - if(_backdropType == OUTLINE) - { - backdrop_index = 1; - max_backdrop_index = 8; - } - else - { - backdrop_index = _backdropType+1; - max_backdrop_index = backdrop_index+1; - } - - if (max_backdrop_index>glyphquad._primitives.size()) max_backdrop_index=glyphquad._primitives.size(); - - state.disableColorPointer(); - state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a()); - - for( ; backdrop_index < max_backdrop_index; backdrop_index++) - { - glyphquad._primitives[backdrop_index]->draw(state, usingVertexBufferObjects); - } - - drawForegroundText(state, glyphquad, colorMultiplier); - } - - glPopAttrib(); -#else - OSG_NOTICE<<"Warning: Text::renderWithStencilBuffer(..) not implemented."<