From Eric Wing, add alternate backdrop implementations.
From Robert Osfield, updated naming and copy constructor methods.
This commit is contained in:
parent
f2d50d943b
commit
419e185895
@ -167,6 +167,13 @@ osg:: Node* createTextLeft(const osg::BoundingBox& bb)
|
|||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
text->setBackdropType(osgText::Text::OUTLINE);
|
text->setBackdropType(osgText::Text::OUTLINE);
|
||||||
|
// text->setBackdropType(osgText::Text::DROP_SHADOW_BOTTOM_RIGHT);
|
||||||
|
|
||||||
|
text->setBackdropImplementation(osgText::Text::POLYGON_OFFSET);
|
||||||
|
// text->setBackdropImplementation(osgText::Text::NO_DEPTH_BUFFER);
|
||||||
|
// text->setBackdropImplementation(osgText::Text::DEPTH_RANGE);
|
||||||
|
// text->setBackdropImplementation(osgText::Text::STENCIL_BUFFER);
|
||||||
|
|
||||||
text->setBackdropOffset(0.05f);
|
text->setBackdropOffset(0.05f);
|
||||||
text->setBackdropColor(osg::Vec4(0.0f, 0.0f, 0.5f, 1.0f));
|
text->setBackdropColor(osg::Vec4(0.0f, 0.0f, 0.5f, 1.0f));
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,7 +72,7 @@ class OSG_EXPORT PolygonOffset : public StateAttribute
|
|||||||
static void setUnitsMultiplier(float multiplier);
|
static void setUnitsMultiplier(float multiplier);
|
||||||
static float getUnitsMultiplier();
|
static float getUnitsMultiplier();
|
||||||
|
|
||||||
static bool areUnitsAndMultipliersSet();
|
static bool areFactorAndUnitsMultipliersSet();
|
||||||
|
|
||||||
/** Checks with the OpenGL driver to try and pick multiplier approrpriate for the hardware.
|
/** Checks with the OpenGL driver to try and pick multiplier approrpriate for the hardware.
|
||||||
note, requires a valid graphics context to be current. */
|
note, requires a valid graphics context to be current. */
|
||||||
|
@ -226,6 +226,14 @@ public:
|
|||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BackdropImplementation
|
||||||
|
{
|
||||||
|
POLYGON_OFFSET = 0,
|
||||||
|
NO_DEPTH_BUFFER,
|
||||||
|
DEPTH_RANGE,
|
||||||
|
STENCIL_BUFFER
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackdropType gives you a background shadow text behind your regular
|
* BackdropType gives you a background shadow text behind your regular
|
||||||
* text. This helps give text extra contrast which can be useful when
|
* text. This helps give text extra contrast which can be useful when
|
||||||
@ -280,6 +288,85 @@ public:
|
|||||||
|
|
||||||
const osg::Vec4& getBackdropColor() const { return _backdropColor; }
|
const osg::Vec4& getBackdropColor() const { return _backdropColor; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This specifies the underlying backdrop rendering implementation.
|
||||||
|
* Unfortunately, at this time, there is no "perfect" rendering solution
|
||||||
|
* so this function is provided to let you 'pick your poison'. Each
|
||||||
|
* implementation has trade-offs.
|
||||||
|
*
|
||||||
|
* 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_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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void setBackdropImplementation(BackdropImplementation implementation);
|
||||||
|
|
||||||
|
BackdropImplementation getBackdropImplementation() const { return _backdropImplementation; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ColorGradientMode
|
enum ColorGradientMode
|
||||||
{
|
{
|
||||||
@ -470,13 +557,22 @@ protected:
|
|||||||
|
|
||||||
void computePositions();
|
void computePositions();
|
||||||
void computePositions(unsigned int contextID) const;
|
void computePositions(unsigned int contextID) const;
|
||||||
|
|
||||||
void computeBackdropPositions(unsigned int contextID) const;
|
void computeBackdropPositions(unsigned int contextID) const;
|
||||||
void computeColorGradients() const;
|
void computeColorGradients() const;
|
||||||
void computeColorGradientsOverall() const;
|
void computeColorGradientsOverall() const;
|
||||||
void computeColorGradientsPerCharacter() const;
|
void computeColorGradientsPerCharacter() const;
|
||||||
|
|
||||||
|
void drawForegroundText(osg::State& state, const GlyphQuads& glyphquad) const;
|
||||||
|
void renderOnlyForegroundText(osg::State& state) const;
|
||||||
|
void renderWithPolygonOffset(osg::State& state) const;
|
||||||
|
void renderWithNoDepthBuffer(osg::State& state) const;
|
||||||
|
void renderWithDepthRange(osg::State& state) const;
|
||||||
|
void renderWithStencilBuffer(osg::State& state) const;
|
||||||
|
|
||||||
BackdropType _backdropType;
|
BackdropType _backdropType;
|
||||||
|
BackdropImplementation _backdropImplementation;
|
||||||
|
|
||||||
float _backdropHorizontalOffset;
|
float _backdropHorizontalOffset;
|
||||||
float _backdropVerticalOffset;
|
float _backdropVerticalOffset;
|
||||||
osg::Vec4 _backdropColor;
|
osg::Vec4 _backdropColor;
|
||||||
|
@ -42,7 +42,7 @@ float PolygonOffset::getUnitsMultiplier()
|
|||||||
return s_UnitsMultipler;
|
return s_UnitsMultipler;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PolygonOffset::areUnitsAndMultipliersSet()
|
bool PolygonOffset::areFactorAndUnitsMultipliersSet()
|
||||||
{
|
{
|
||||||
return s_MultiplerSet;
|
return s_MultiplerSet;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ Text::Text():
|
|||||||
_kerningType(KERNING_DEFAULT),
|
_kerningType(KERNING_DEFAULT),
|
||||||
_lineCount(0),
|
_lineCount(0),
|
||||||
_backdropType(NONE),
|
_backdropType(NONE),
|
||||||
|
_backdropImplementation(POLYGON_OFFSET),
|
||||||
_backdropHorizontalOffset(0.07f),
|
_backdropHorizontalOffset(0.07f),
|
||||||
_backdropVerticalOffset(0.07f),
|
_backdropVerticalOffset(0.07f),
|
||||||
_backdropColor(0.0f, 0.0f, 0.0f, 1.0f),
|
_backdropColor(0.0f, 0.0f, 0.0f, 1.0f),
|
||||||
@ -79,7 +80,17 @@ Text::Text(const Text& text,const osg::CopyOp& copyop):
|
|||||||
_color(text._color),
|
_color(text._color),
|
||||||
_drawMode(text._drawMode),
|
_drawMode(text._drawMode),
|
||||||
_kerningType(text._kerningType),
|
_kerningType(text._kerningType),
|
||||||
_lineCount(text._lineCount)
|
_lineCount(text._lineCount),
|
||||||
|
_backdropType(text._backdropType),
|
||||||
|
_backdropImplementation(text._backdropImplementation),
|
||||||
|
_backdropHorizontalOffset(text._backdropHorizontalOffset),
|
||||||
|
_backdropVerticalOffset(text._backdropVerticalOffset),
|
||||||
|
_backdropColor(text._backdropColor),
|
||||||
|
_colorGradientMode(text._colorGradientMode),
|
||||||
|
_colorGradientTopLeft(text._colorGradientTopLeft),
|
||||||
|
_colorGradientBottomLeft(text._colorGradientBottomLeft),
|
||||||
|
_colorGradientBottomRight(text._colorGradientBottomRight),
|
||||||
|
_colorGradientTopRight(text._colorGradientTopRight)
|
||||||
{
|
{
|
||||||
computeGlyphRepresentation();
|
computeGlyphRepresentation();
|
||||||
}
|
}
|
||||||
@ -1446,88 +1457,35 @@ void Text::drawImplementation(osg::State& state) const
|
|||||||
|
|
||||||
state.disableAllVertexArrays();
|
state.disableAllVertexArrays();
|
||||||
|
|
||||||
|
// 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)
|
if(_backdropType != NONE)
|
||||||
{
|
{
|
||||||
if (!osg::PolygonOffset::areUnitsAndMultipliersSet())
|
switch(_backdropImplementation)
|
||||||
{
|
{
|
||||||
osg::PolygonOffset::setFactorAndUnitsMultipliersUsingBestGuessForDriver();
|
case POLYGON_OFFSET:
|
||||||
}
|
renderWithPolygonOffset(state);
|
||||||
|
break;
|
||||||
// Do I really need to do this for glPolygonOffset?
|
case NO_DEPTH_BUFFER:
|
||||||
glPushAttrib(GL_POLYGON_OFFSET_FILL);
|
renderWithNoDepthBuffer(state);
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
break;
|
||||||
}
|
case DEPTH_RANGE:
|
||||||
|
renderWithDepthRange(state);
|
||||||
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
break;
|
||||||
titr!=_textureGlyphQuadMap.end();
|
case STENCIL_BUFFER:
|
||||||
++titr)
|
renderWithStencilBuffer(state);
|
||||||
{
|
break;
|
||||||
// need to set the texture here...
|
default:
|
||||||
state.apply(titr->first.get());
|
renderWithPolygonOffset(state);
|
||||||
|
|
||||||
const GlyphQuads& glyphquad = titr->second;
|
|
||||||
|
|
||||||
// For backdrop text
|
|
||||||
if(_backdropType != NONE)
|
|
||||||
{
|
|
||||||
unsigned int backdrop_index;
|
|
||||||
unsigned int max_backdrop_index;
|
|
||||||
if(_backdropType == OUTLINE)
|
|
||||||
{
|
|
||||||
backdrop_index = 0;
|
|
||||||
max_backdrop_index = 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
backdrop_index = _backdropType;
|
|
||||||
max_backdrop_index = _backdropType+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
|
||||||
state.disableColorPointer();
|
|
||||||
glColor4fv(_backdropColor.ptr());
|
|
||||||
|
|
||||||
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
|
||||||
{
|
|
||||||
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
|
||||||
if (!transformedBackdropCoords.empty())
|
|
||||||
{
|
|
||||||
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
|
||||||
glPolygonOffset(2.0f * osg::PolygonOffset::getFactorMultiplier(),
|
|
||||||
3.0f * osg::PolygonOffset::getUnitsMultiplier() * (max_backdrop_index-backdrop_index) );
|
|
||||||
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glPolygonOffset(0.0f,0.0f);
|
|
||||||
|
|
||||||
} // end of backdrop text
|
|
||||||
|
|
||||||
const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
|
|
||||||
if (!transformedCoords.empty())
|
|
||||||
{
|
|
||||||
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords.front()));
|
|
||||||
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
|
||||||
|
|
||||||
if(_colorGradientMode == SOLID)
|
|
||||||
{
|
|
||||||
state.disableColorPointer();
|
|
||||||
glColor4fv(_color.ptr());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.setColorPointer( 4, GL_FLOAT, 0, &(glyphquad._colorCoords.front()));
|
|
||||||
}
|
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS,0,transformedCoords.size());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if(_backdropType != NONE)
|
|
||||||
{
|
{
|
||||||
glPopAttrib();
|
renderOnlyForegroundText(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_drawMode & BOUNDINGBOX)
|
if (_drawMode & BOUNDINGBOX)
|
||||||
@ -1626,6 +1584,15 @@ void Text::setBackdropType(BackdropType type)
|
|||||||
computeGlyphRepresentation();
|
computeGlyphRepresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Text::setBackdropImplementation(BackdropImplementation implementation)
|
||||||
|
{
|
||||||
|
if (_backdropImplementation==implementation) return;
|
||||||
|
|
||||||
|
_backdropImplementation = implementation;
|
||||||
|
computeGlyphRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Text::setBackdropOffset(float offset)
|
void Text::setBackdropOffset(float offset)
|
||||||
{
|
{
|
||||||
_backdropHorizontalOffset = offset;
|
_backdropHorizontalOffset = offset;
|
||||||
@ -1859,7 +1826,373 @@ void Text::convertRgbToHsv( float rgb[], float hsv[] ) const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Text::drawForegroundText(osg::State& state, const GlyphQuads& glyphquad) const
|
||||||
|
{
|
||||||
|
unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
|
||||||
|
if (!transformedCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords.front()));
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
|
||||||
|
if(_colorGradientMode == SOLID)
|
||||||
|
{
|
||||||
|
state.disableColorPointer();
|
||||||
|
glColor4fv(_color.ptr());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.setColorPointer( 4, GL_FLOAT, 0, &(glyphquad._colorCoords.front()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedCoords.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::renderOnlyForegroundText(osg::State& state) const
|
||||||
|
{
|
||||||
|
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
drawForegroundText(state, glyphquad);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Text::renderWithPolygonOffset(osg::State& state) const
|
||||||
|
{
|
||||||
|
// glNormal3fv(_normal.ptr());
|
||||||
|
|
||||||
|
// state.disableAllVertexArrays();
|
||||||
|
unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
|
||||||
|
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::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
unsigned int backdrop_index;
|
||||||
|
unsigned int max_backdrop_index;
|
||||||
|
if(_backdropType == OUTLINE)
|
||||||
|
{
|
||||||
|
backdrop_index = 0;
|
||||||
|
max_backdrop_index = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop_index = _backdropType;
|
||||||
|
max_backdrop_index = _backdropType+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
state.disableColorPointer();
|
||||||
|
glColor4fv(_backdropColor.ptr());
|
||||||
|
|
||||||
|
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
||||||
|
{
|
||||||
|
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
||||||
|
if (!transformedBackdropCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
||||||
|
glPolygonOffset(0.1f * osg::PolygonOffset::getFactorMultiplier(),
|
||||||
|
2.0f * osg::PolygonOffset::getUnitsMultiplier() * (max_backdrop_index-backdrop_index) );
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the polygon offset so the foreground text is on top
|
||||||
|
glPolygonOffset(0.0f,0.0f);
|
||||||
|
|
||||||
|
drawForegroundText(state, glyphquad);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopAttrib();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Text::renderWithNoDepthBuffer(osg::State& state) const
|
||||||
|
{
|
||||||
|
unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
glPushAttrib(GL_DEPTH_BUFFER_BIT);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
unsigned int backdrop_index;
|
||||||
|
unsigned int max_backdrop_index;
|
||||||
|
if(_backdropType == OUTLINE)
|
||||||
|
{
|
||||||
|
backdrop_index = 0;
|
||||||
|
max_backdrop_index = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop_index = _backdropType;
|
||||||
|
max_backdrop_index = _backdropType+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
state.disableColorPointer();
|
||||||
|
glColor4fv(_backdropColor.ptr());
|
||||||
|
|
||||||
|
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
||||||
|
{
|
||||||
|
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
||||||
|
if (!transformedBackdropCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawForegroundText(state, glyphquad);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopAttrib();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This idea comes from Paul Martz's OpenGL FAQ: 13.050
|
||||||
|
void Text::renderWithDepthRange(osg::State& state) const
|
||||||
|
{
|
||||||
|
unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
// Hmmm, the man page says GL_VIEWPORT_BIT for Depth range (near and far)
|
||||||
|
// but experimentally, GL_DEPTH_BUFFER_BIT for glDepthRange.
|
||||||
|
// glPushAttrib(GL_VIEWPORT_BIT);
|
||||||
|
glPushAttrib(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
unsigned int backdrop_index;
|
||||||
|
unsigned int max_backdrop_index;
|
||||||
|
if(_backdropType == OUTLINE)
|
||||||
|
{
|
||||||
|
backdrop_index = 0;
|
||||||
|
max_backdrop_index = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop_index = _backdropType;
|
||||||
|
max_backdrop_index = _backdropType+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
state.disableColorPointer();
|
||||||
|
glColor4fv(_backdropColor.ptr());
|
||||||
|
|
||||||
|
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
||||||
|
{
|
||||||
|
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
||||||
|
if (!transformedBackdropCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
||||||
|
glDepthRange(0.01f + ((max_backdrop_index-backdrop_index)/1000.0f), 1.0);
|
||||||
|
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glDepthRange(0.0, 0.982);
|
||||||
|
|
||||||
|
drawForegroundText(state, glyphquad);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopAttrib();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::renderWithStencilBuffer(osg::State& state) const
|
||||||
|
{
|
||||||
|
/* Here are the steps:
|
||||||
|
* 1) Disable drawing color
|
||||||
|
* 2) Enable the stencil buffer
|
||||||
|
* 3) Draw all the text to the stencil buffer
|
||||||
|
* 4) Disable the stencil buffer
|
||||||
|
* 5) Enable color
|
||||||
|
* 6) Disable the depth buffer
|
||||||
|
* 7) Draw all the text again.
|
||||||
|
* 7b) Make sure the foreground text is drawn last if priority levels
|
||||||
|
* are the same OR
|
||||||
|
* 7c) If priority levels are different, then make sure the foreground
|
||||||
|
* text has the higher priority.
|
||||||
|
*/
|
||||||
|
unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
// It seems I can get away without calling this here
|
||||||
|
//glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
// enable stencil buffer
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
// write a one to the stencil buffer everywhere we are about to draw
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, 1);
|
||||||
|
|
||||||
|
// write only to the stencil buffer if we pass the depth test
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
|
||||||
|
// Disable writing to the color buffer so we only write to the stencil
|
||||||
|
// buffer and the depth buffer
|
||||||
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
|
|
||||||
|
// make sure the depth buffer is enabled
|
||||||
|
// glEnable(GL_DEPTH_TEST);
|
||||||
|
// glDepthMask(GL_TRUE);
|
||||||
|
// glDepthFunc(GL_LESS);
|
||||||
|
|
||||||
|
// Arrrgh! Why does the code only seem to work correctly if I call this?
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
// Draw all the text to the stencil buffer to mark out the region
|
||||||
|
// that we can write too.
|
||||||
|
|
||||||
|
for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
unsigned int backdrop_index;
|
||||||
|
unsigned int max_backdrop_index;
|
||||||
|
if(_backdropType == OUTLINE)
|
||||||
|
{
|
||||||
|
backdrop_index = 0;
|
||||||
|
max_backdrop_index = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop_index = _backdropType;
|
||||||
|
max_backdrop_index = _backdropType+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
state.disableColorPointer();
|
||||||
|
|
||||||
|
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
||||||
|
{
|
||||||
|
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
||||||
|
if (!transformedBackdropCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the foreground text
|
||||||
|
const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
|
||||||
|
if (!transformedCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords.front()));
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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::iterator titr=_textureGlyphQuadMap.begin();
|
||||||
|
titr!=_textureGlyphQuadMap.end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
// need to set the texture here...
|
||||||
|
state.apply(titr->first.get());
|
||||||
|
|
||||||
|
const GlyphQuads& glyphquad = titr->second;
|
||||||
|
|
||||||
|
unsigned int backdrop_index;
|
||||||
|
unsigned int max_backdrop_index;
|
||||||
|
if(_backdropType == OUTLINE)
|
||||||
|
{
|
||||||
|
backdrop_index = 0;
|
||||||
|
max_backdrop_index = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop_index = _backdropType;
|
||||||
|
max_backdrop_index = _backdropType+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
|
||||||
|
state.disableColorPointer();
|
||||||
|
glColor4fv(_backdropColor.ptr());
|
||||||
|
|
||||||
|
for( ; backdrop_index < max_backdrop_index; backdrop_index++)
|
||||||
|
{
|
||||||
|
const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
|
||||||
|
if (!transformedBackdropCoords.empty())
|
||||||
|
{
|
||||||
|
state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
|
||||||
|
glDrawArrays(GL_QUADS,0,transformedBackdropCoords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawForegroundText(state, glyphquad);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopAttrib();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user