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
|
||||
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->setBackdropColor(osg::Vec4(0.0f, 0.0f, 0.5f, 1.0f));
|
||||
#endif
|
||||
|
@ -72,7 +72,7 @@ class OSG_EXPORT PolygonOffset : public StateAttribute
|
||||
static void setUnitsMultiplier(float multiplier);
|
||||
static float getUnitsMultiplier();
|
||||
|
||||
static bool areUnitsAndMultipliersSet();
|
||||
static bool areFactorAndUnitsMultipliersSet();
|
||||
|
||||
/** Checks with the OpenGL driver to try and pick multiplier approrpriate for the hardware.
|
||||
note, requires a valid graphics context to be current. */
|
||||
|
@ -226,6 +226,14 @@ public:
|
||||
NONE
|
||||
};
|
||||
|
||||
enum BackdropImplementation
|
||||
{
|
||||
POLYGON_OFFSET = 0,
|
||||
NO_DEPTH_BUFFER,
|
||||
DEPTH_RANGE,
|
||||
STENCIL_BUFFER
|
||||
};
|
||||
|
||||
/**
|
||||
* BackdropType gives you a background shadow text behind your regular
|
||||
* text. This helps give text extra contrast which can be useful when
|
||||
@ -280,6 +288,85 @@ public:
|
||||
|
||||
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
|
||||
{
|
||||
@ -476,7 +563,16 @@ protected:
|
||||
void computeColorGradientsOverall() 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;
|
||||
BackdropImplementation _backdropImplementation;
|
||||
|
||||
float _backdropHorizontalOffset;
|
||||
float _backdropVerticalOffset;
|
||||
osg::Vec4 _backdropColor;
|
||||
|
@ -42,7 +42,7 @@ float PolygonOffset::getUnitsMultiplier()
|
||||
return s_UnitsMultipler;
|
||||
}
|
||||
|
||||
bool PolygonOffset::areUnitsAndMultipliersSet()
|
||||
bool PolygonOffset::areFactorAndUnitsMultipliersSet()
|
||||
{
|
||||
return s_MultiplerSet;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ Text::Text():
|
||||
_kerningType(KERNING_DEFAULT),
|
||||
_lineCount(0),
|
||||
_backdropType(NONE),
|
||||
_backdropImplementation(POLYGON_OFFSET),
|
||||
_backdropHorizontalOffset(0.07f),
|
||||
_backdropVerticalOffset(0.07f),
|
||||
_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),
|
||||
_drawMode(text._drawMode),
|
||||
_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();
|
||||
}
|
||||
@ -1446,87 +1457,34 @@ void Text::drawImplementation(osg::State& state) const
|
||||
|
||||
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 (!osg::PolygonOffset::areUnitsAndMultipliersSet())
|
||||
switch(_backdropImplementation)
|
||||
{
|
||||
osg::PolygonOffset::setFactorAndUnitsMultipliersUsingBestGuessForDriver();
|
||||
case POLYGON_OFFSET:
|
||||
renderWithPolygonOffset(state);
|
||||
break;
|
||||
case NO_DEPTH_BUFFER:
|
||||
renderWithNoDepthBuffer(state);
|
||||
break;
|
||||
case DEPTH_RANGE:
|
||||
renderWithDepthRange(state);
|
||||
break;
|
||||
case STENCIL_BUFFER:
|
||||
renderWithStencilBuffer(state);
|
||||
break;
|
||||
default:
|
||||
renderWithPolygonOffset(state);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(_backdropType != NONE)
|
||||
{
|
||||
glPopAttrib();
|
||||
renderOnlyForegroundText(state);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1626,6 +1584,15 @@ void Text::setBackdropType(BackdropType type)
|
||||
computeGlyphRepresentation();
|
||||
}
|
||||
|
||||
void Text::setBackdropImplementation(BackdropImplementation implementation)
|
||||
{
|
||||
if (_backdropImplementation==implementation) return;
|
||||
|
||||
_backdropImplementation = implementation;
|
||||
computeGlyphRepresentation();
|
||||
}
|
||||
|
||||
|
||||
void Text::setBackdropOffset(float 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