root/OpenSceneGraph/trunk/src/osgText/Text.cpp @ 12597

Revision 12597, 68.8 kB (checked in by robert, 3 years ago)

Resolved warnings reported by g++ 4.6's -Wunused-but-set-variable.

Warnings were:

/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osg/ShapeDrawable.cpp: In member function ‘void PrimitiveShapeVisitor::createHalfSphere(unsigned int, unsigned int, float, int, float, const Matrix&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osg/ShapeDrawable.cpp:1409:11: warning: variable ‘nzBase’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osg/ShapeDrawable.cpp:1410:11: warning: variable ‘nRatioBase’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/DelaunayTriangulator.cpp: In function ‘osgUtil::Triangle_list osgUtil::fillHole(osg::Vec3Array*, std::vector<unsigned int, std::allocator<unsigned int> >)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/DelaunayTriangulator.cpp:569:27: warning: variable ‘ptest’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/DelaunayTriangulator.cpp: In member function ‘bool osgUtil::DelaunayTriangulator::triangulate()’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/DelaunayTriangulator.cpp:979:45: warning: variable ‘curp’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/RenderStage.cpp: In member function ‘void osgUtil::RenderStage::runCameraSetUp(osg::RenderInfo?&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgUtil/RenderStage.cpp:631:18: warning: variable ‘stencilAttached’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgText/FadeText.cpp: In member function ‘void FadeTextPolytopeData::buildPolytope()’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgText/FadeText.cpp:74:20: warning: variable ‘edge23’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgText/FadeText.cpp:75:20: warning: variable ‘edge30’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgText/Text.cpp: In member function ‘void osgText::Text::computeBackdropPositions(unsigned int) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgText/Text.cpp:747:10: warning: variable ‘is_valid_size’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/NodeTrackerManipulator.cpp: In member function ‘virtual bool osgGA::NodeTrackerManipulator::performMovementLeftMouseButton(double, double, double)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/NodeTrackerManipulator.cpp:257:21: warning: variable ‘lookVector’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/NodeTrackerManipulator.cpp:259:21: warning: variable ‘upVector’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/TerrainManipulator.cpp: In member function ‘virtual bool osgGA::TerrainManipulator::performMovementMiddleMouseButton(double, double, double)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/TerrainManipulator.cpp:217:11: warning: variable ‘lookVector’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgGA/TerrainManipulator.cpp:219:11: warning: variable ‘upVector’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgVolume/FixedFunctionTechnique.cpp: In member function ‘virtual void osgVolume::FixedFunctionTechnique::init()’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgVolume/FixedFunctionTechnique.cpp:124:30: warning: variable ‘tf’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgParticle/FluidProgram.cpp: In member function ‘virtual void osgParticle::FluidProgram::execute(double)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgParticle/FluidProgram.cpp:38:23: warning: variable ‘velBefore’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgShadow/ParallelSplitShadowMap.cpp: In member function ‘virtual void osgShadow::ParallelSplitShadowMap::cull(osgUtil::CullVisitor?&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgShadow/ParallelSplitShadowMap.cpp:593:22: warning: variable ‘bb’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgTerrain/GeometryTechnique.cpp: In member function ‘virtual void osgTerrain::GeometryTechnique::generateGeometry(osgTerrain::GeometryTechnique::BufferData?&, osgTerrain::Locator*, const osg::Vec3d&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgTerrain/GeometryTechnique.cpp:777:12: warning: variable ‘i_sampleFactor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgTerrain/GeometryTechnique.cpp:778:12: warning: variable ‘j_sampleFactor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/dds/ReaderWriterDDS.cpp: In function ‘osg::Image* ReadDDSFile(std::istream&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/dds/ReaderWriterDDS.cpp:314:10: warning: variable ‘is3dImage’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/dds/ReaderWriterDDS.cpp: In function ‘bool WriteDDSFile(const osg::Image*, std::ostream&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/dds/ReaderWriterDDS.cpp:721:10: warning: variable ‘is3dImage’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/hdr/hdrloader.cpp: In static member function ‘static bool HDRLoader::load(const char*, bool, HDRLoaderResult&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/hdr/hdrloader.cpp:101:10: warning: variable ‘cmd’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/vtf/ReaderWriterVTF.cpp: In function ‘osg::Image* ReadVTFFile(std::istream&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/vtf/ReaderWriterVTF.cpp:360:23: warning: variable ‘base’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/jp2/ReaderWriterJP2.cpp: In function ‘int putdata(jas_stream_t*, jas_image_t*, int)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/jp2/ReaderWriterJP2.cpp:41:13: warning: variable ‘linelen’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/Inventor/ConvertToInventor.cpp: In member function ‘void ConvertToInventor::processGeometry(const osg::Geometry*, ConvertToInventor::InventorState?*)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/Inventor/ConvertToInventor.cpp:1639:10: warning: variable ‘ok’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/Inventor/ConvertFromInventor.cpp: In member function ‘virtual SbBool? SoVRMLImageTextureOsg::readInstance(SoInput?*, short unsigned int)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/Inventor/ConvertFromInventor.cpp:1264:16: warning: variable ‘retval’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/GeometryRecords.cpp: In member function ‘virtual void flt::Face::readRecord(flt::RecordInputStream?&, flt::Document&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/GeometryRecords.cpp:369:19: warning: variable ‘secondaryPackedColor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/GeometryRecords.cpp: In member function ‘virtual void flt::Mesh::readRecord(flt::RecordInputStream?&, flt::Document&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/GeometryRecords.cpp:942:19: warning: variable ‘secondaryPackedColor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp: In member function ‘virtual osgDB::ReaderWriter::ReadResult? FLTReaderWriter::readNode(std::istream&, const Options*) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp:427:40: warning: variable ‘pos’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ive/ShapeAttributeList.cpp: In member function ‘void ive::ShapeAttributeList::write(ive::DataOutputStream?*)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ive/ShapeAttributeList.cpp:31:48: warning: variable ‘it’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp: In member function ‘void ac3d::Geode::ProcessGeometry?(std::ostream&, unsigned int)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp:806:35: warning: variable ‘fRep_s’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp:806:43: warning: variable ‘fRep_t’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp:807:35: warning: variable ‘fOffset_s’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp:807:46: warning: variable ‘fOffset_t’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/ac/Geode.cpp:932:38: warning: variable ‘primLength’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_geom.cpp: In member function ‘virtual bool trpgGeometry::Write(trpgWriteBuffer&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_geom.cpp:615:19: warning: variable ‘u’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_material.cpp: In member function ‘int trpgMatTable::AddMaterial?(const trpgMaterial&, bool)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_material.cpp:103:10: warning: variable ‘spaceInTable’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_rarchive.cpp: In member function ‘virtual bool trpgr_Archive::ReadHeader?(bool)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/txp/trpage_rarchive.cpp:261:14: warning: variable ‘headerHasTexTable’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/unzip.cpp: In member function ‘ZRESULT TUnzip::Get(int, ZIPENTRY*)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/unzip.cpp:4055:8: warning: variable ‘hidden’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/unzip.cpp:4055:22: warning: variable ‘system’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/unzip.cpp:4055:36: warning: variable ‘archive’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/ZipArchive.cpp: In member function ‘virtual bool ZipArchive::getFileNames(osgDB::Archive::FileNameList?&) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/zip/ZipArchive.cpp:91:37: warning: variable ‘iterEnd’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/pvr/ReaderWriterPVR.cpp: In member function ‘osgDB::ReaderWriter::ReadResult? ReaderWriterPVR::readPVRStream(std::istream&) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/pvr/ReaderWriterPVR.cpp:155:14: warning: variable ‘hasAlpha’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/View.cpp: In function ‘osg::Geometry* create3DSphericalDisplayDistortionMesh(const Vec3&, const Vec3&, const Vec3&, double, double, osg::Image*, const Matrix&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/View.cpp:737:15: warning: variable ‘cursor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/View.cpp: In function ‘osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const Vec3&, const Vec3&, const Vec3&, double, double, osg::Image*, const Matrix&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/View.cpp:1130:19: warning: variable ‘cursor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/View.cpp:1118:15: warning: variable ‘dx’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/GraphicsWindowX11.cpp: In member function ‘virtual void osgViewer::GraphicsWindowX11::checkEvents()’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgViewer/GraphicsWindowX11.cpp:1181:10: warning: variable ‘destroyWindowRequested’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/cfg/ConfigParser.cpp: In member function ‘bool osgProducer::CameraConfig::parseFile(const string&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/cfg/ConfigParser.cpp:2247:13: warning: variable ‘result’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgQt/QGraphicsViewAdapter.cpp: In member function ‘bool osgQt::QGraphicsViewAdapter::handlePointerEvent(int, int, int)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgQt/QGraphicsViewAdapter.cpp:344:17: warning: variable ‘viewportGeometry’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgdistortion/osgdistortion.cpp: In function ‘osg::Node* createDistortionSubgraph(osg::Node*, const Vec4&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgdistortion/osgdistortion.cpp:125:19: warning: variable ‘cursor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgdistortion/osgdistortion.cpp:126:19: warning: variable ‘texcoord’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgdistortion/osgdistortion.cpp: In function ‘osg::Geometry* createDomeDistortionMesh(const Vec3&, const Vec3&, const Vec3&, osg::ArgumentParser?&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgdistortion/osgdistortion.cpp:358:15: warning: variable ‘cursor’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgposter/osgposter.cpp: In function ‘int main(int, char**)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgposter/osgposter.cpp:253:31: warning: variable ‘outputTiles’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgthreadedterrain/osgthreadedterrain.cpp: In function ‘int main(int, char**)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgthreadedterrain/osgthreadedterrain.cpp:669:10: warning: variable ‘readParameter’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgtext3D/TextNode.cpp: In member function ‘virtual void osgText::Layout::layout(osgText::TextNode?&) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgtext3D/TextNode.cpp:80:11: warning: variable ‘characterHeightScale’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgvolume/osgvolume.cpp: In function ‘int main(int, char**)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgvolume/osgvolume.cpp:678:38: warning: variable ‘internalFormatMode’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgwidgetcanvas/osgwidgetcanvas.cpp: In function ‘bool windowMouseOver(osgWidget::Event&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgwidgetcanvas/osgwidgetcanvas.cpp:27:24: warning: variable ‘xy’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgwidgetcanvas/osgwidgetcanvas.cpp: In function ‘bool widgetMouseOver(osgWidget::Event&)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/examples/osgwidgetcanvas/osgwidgetcanvas.cpp:35:24: warning: variable ‘xy’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/p3d/ReaderWriterP3D.cpp: In member function ‘osg::Node* ReaderWriterP3DXML::parseXmlGraph(osgDB::XmlNode?*, bool, osgDB::Options*) const’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/src/osgPlugins/p3d/ReaderWriterP3D.cpp:2121:10: warning: variable ‘readSlide’ set but not used [-Wunused-but-set-variable]
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/applications/present3D/present3D.cpp: In function ‘int main(int, char**)’:
/home/stephan/Dev/LibSources/OpenSceneGraph-3.0.0-rc2/applications/present3D/present3D.cpp:639:10: warning: variable ‘sizesSpecified’ set but not used [-Wunused-but-set-variable]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14
15#include <osgText/Text>
16
17#include <osg/Math>
18#include <osg/GL>
19#include <osg/Notify>
20#include <osg/PolygonOffset>
21#include <osg/TexEnv>
22
23#include <osgUtil/CullVisitor>
24
25#include <osgDB/ReadFile>
26
27using namespace osg;
28using namespace osgText;
29
30//#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE
31
32Text::Text():
33    _enableDepthWrites(true),
34    _backdropType(NONE),
35    _backdropImplementation(DELAYED_DEPTH_WRITES),
36    _backdropHorizontalOffset(0.07f),
37    _backdropVerticalOffset(0.07f),
38    _backdropColor(0.0f, 0.0f, 0.0f, 1.0f),
39    _colorGradientMode(SOLID),
40    _colorGradientTopLeft(1.0f, 0.0f, 0.0f, 1.0f),
41    _colorGradientBottomLeft(0.0f, 1.0f, 0.0f, 1.0f),
42    _colorGradientBottomRight(0.0f, 0.0f, 1.0f, 1.0f),
43    _colorGradientTopRight(1.0f, 1.0f, 1.0f, 1.0f)
44{}
45
46Text::Text(const Text& text,const osg::CopyOp& copyop):
47    osgText::TextBase(text,copyop),
48    _enableDepthWrites(text._enableDepthWrites),
49    _backdropType(text._backdropType),
50    _backdropImplementation(text._backdropImplementation),
51    _backdropHorizontalOffset(text._backdropHorizontalOffset),
52    _backdropVerticalOffset(text._backdropVerticalOffset),
53    _backdropColor(text._backdropColor),
54    _colorGradientMode(text._colorGradientMode),
55    _colorGradientTopLeft(text._colorGradientTopLeft),
56    _colorGradientBottomLeft(text._colorGradientBottomLeft),
57    _colorGradientBottomRight(text._colorGradientBottomRight),
58    _colorGradientTopRight(text._colorGradientTopRight)
59{
60    computeGlyphRepresentation();
61}
62
63Text::~Text()
64{
65}
66
67void Text::setFont(osg::ref_ptr<Font> font)
68{
69    if (_font==font) return;
70
71    osg::StateSet* previousFontStateSet = _font.valid() ? _font->getStateSet() : Font::getDefaultFont()->getStateSet();
72    osg::StateSet* newFontStateSet = font.valid() ? font->getStateSet() : Font::getDefaultFont()->getStateSet();
73
74    if (getStateSet() == previousFontStateSet)
75    {
76        setStateSet( newFontStateSet );
77    }
78
79    TextBase::setFont(font);
80}
81
82
83Font* Text::getActiveFont()
84{
85    return _font.valid() ? _font.get() : Font::getDefaultFont().get();
86}
87
88const Font* Text::getActiveFont() const
89{
90    return _font.valid() ? _font.get() : Font::getDefaultFont().get();
91}
92
93String::iterator Text::computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last)
94{
95    Font* activefont = getActiveFont();
96    if (!activefont) return last;
97
98    float hr = _characterHeight;
99    float wr = hr/getCharacterAspectRatio();
100
101    bool kerning = true;
102    unsigned int previous_charcode = 0;
103
104    String::iterator lastChar = first;
105
106    for(bool outOfSpace=false;lastChar!=last;++lastChar)
107    {
108        unsigned int charcode = *lastChar;
109       
110        if (charcode=='\n')
111        {
112            return lastChar;
113        }
114
115        Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
116        if (glyph)
117        {
118
119           float width = (float)(glyph->getWidth()) * wr;
120
121            if (_layout==RIGHT_TO_LEFT)
122            {
123                cursor.x() -= glyph->getHorizontalAdvance() * wr;
124            }
125
126            // adjust cursor position w.r.t any kerning.
127            if (kerning && previous_charcode)
128            {
129                switch(_layout)
130                {
131                  case LEFT_TO_RIGHT:
132                  {
133                    osg::Vec2 delta(activefont->getKerning(previous_charcode,charcode,_kerningType));
134                    cursor.x() += delta.x() * wr;
135                    cursor.y() += delta.y() * hr;
136                    break;
137                  }
138                  case RIGHT_TO_LEFT:
139                  {
140                    osg::Vec2 delta(activefont->getKerning(charcode,previous_charcode,_kerningType));
141                    cursor.x() -= delta.x() * wr;
142                    cursor.y() -= delta.y() * hr;
143                    break;
144                  }
145                  case VERTICAL:
146                    break; // no kerning when vertical.
147                }            // check to see if we are still within line if not move to next line.
148            }
149
150            switch(_layout)
151            {
152              case LEFT_TO_RIGHT:
153              {
154                if (_maximumWidth>0.0f && cursor.x()+width>_maximumWidth) outOfSpace=true;
155                if(_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true;
156                break;
157              }
158              case RIGHT_TO_LEFT:
159              {
160                if (_maximumWidth>0.0f && cursor.x()<-_maximumWidth) outOfSpace=true;
161                if(_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true;
162                break;
163              }
164              case VERTICAL:
165                if (_maximumHeight>0.0f && cursor.y()<-_maximumHeight) outOfSpace=true;
166                break;
167            }
168           
169            // => word boundary detection & wrapping
170            if (outOfSpace) break;
171
172            // move the cursor onto the next character.
173            switch(_layout)
174            {
175              case LEFT_TO_RIGHT: cursor.x() += glyph->getHorizontalAdvance() * wr; break;
176              case VERTICAL:      cursor.y() -= glyph->getVerticalAdvance() *hr; break;
177              case RIGHT_TO_LEFT: break; // nop.
178            }
179
180            previous_charcode = charcode;
181
182        }
183
184    }
185
186    // word boundary detection & wrapping
187    if (lastChar!=last)
188    {
189        String::iterator lastValidChar = lastChar;
190          String::iterator prevChar;
191        while (lastValidChar != first){
192            prevChar = lastValidChar - 1;
193
194            // last char is after a hyphen
195                if(*lastValidChar == '-')
196                return lastValidChar + 1;
197
198            // last char is start of whitespace
199            if((*lastValidChar == ' ' || *lastValidChar == '\n') && (*prevChar != ' ' && *prevChar != '\n'))
200                return lastValidChar;
201
202            // Subtract off glyphs from the cursor position (to correctly center text)
203                if(*prevChar != '-')
204            {
205                Glyph* glyph = activefont->getGlyph(_fontSize, *prevChar);
206                if (glyph)
207                {
208                    switch(_layout)
209                    {
210                    case LEFT_TO_RIGHT: cursor.x() -= glyph->getHorizontalAdvance() * wr; break;
211                    case VERTICAL:      cursor.y() += glyph->getVerticalAdvance() * hr; break;
212                    case RIGHT_TO_LEFT: break; // nop.
213                    }
214                }
215            }
216
217            lastValidChar = prevChar;
218          }
219    }
220
221    return lastChar;
222}
223
224
225void Text::computeGlyphRepresentation()
226{
227    Font* activefont = getActiveFont();
228    if (!activefont) return;
229   
230    _textureGlyphQuadMap.clear();
231    _lineCount = 0;
232   
233    if (_text.empty())
234    {
235        _textBB.set(0,0,0,0,0,0);//no size text
236        TextBase::computePositions(); //to reset the origin
237        return;
238    }
239   
240    //OpenThreads::ScopedLock<Font::FontMutex> lock(*(activefont->getSerializeFontCallsMutex()));
241
242    // initialize bounding box, it will be expanded during glyph position calculation
243    _textBB.init();
244
245    osg::Vec2 startOfLine_coords(0.0f,0.0f);
246    osg::Vec2 cursor(startOfLine_coords);
247    osg::Vec2 local(0.0f,0.0f);
248   
249    unsigned int previous_charcode = 0;
250    unsigned int linelength = 0;
251    bool horizontal = _layout!=VERTICAL;
252    bool kerning = true;
253   
254    unsigned int lineNumber = 0;
255
256    float hr = _characterHeight;
257    float wr = hr/getCharacterAspectRatio();
258
259    for(String::iterator itr=_text.begin();
260        itr!=_text.end();
261        )
262    {
263        // record the start of the current line
264            String::iterator startOfLine_itr = itr;
265
266            // find the end of the current line.
267            osg::Vec2 endOfLine_coords(cursor);
268            String::iterator endOfLine_itr = computeLastCharacterOnLine(endOfLine_coords, itr,_text.end());
269
270            linelength = endOfLine_itr - startOfLine_itr;
271
272            // Set line position to correct alignment.
273            switch(_layout)
274            {
275            case LEFT_TO_RIGHT:
276            {
277            switch(_alignment)
278            {
279              // nothing to be done for these
280              //case LEFT_TOP:
281              //case LEFT_CENTER:
282              //case LEFT_BOTTOM:
283              //case LEFT_BASE_LINE:
284              //case LEFT_BOTTOM_BASE_LINE:
285              //  break;
286              case CENTER_TOP:
287              case CENTER_CENTER:
288              case CENTER_BOTTOM:
289              case CENTER_BASE_LINE:
290              case CENTER_BOTTOM_BASE_LINE:
291                cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f;
292                break;
293              case RIGHT_TOP:
294              case RIGHT_CENTER:
295              case RIGHT_BOTTOM:
296              case RIGHT_BASE_LINE:
297              case RIGHT_BOTTOM_BASE_LINE:
298                cursor.x() = cursor.x() - endOfLine_coords.x();
299                break;
300              default:
301                break;
302              }
303            break;
304            }
305            case RIGHT_TO_LEFT:
306            {
307            switch(_alignment)
308            {
309              case LEFT_TOP:
310              case LEFT_CENTER:
311              case LEFT_BOTTOM:
312              case LEFT_BASE_LINE:
313              case LEFT_BOTTOM_BASE_LINE:
314                cursor.x() = 2*cursor.x() - endOfLine_coords.x();
315                break;
316              case CENTER_TOP:
317              case CENTER_CENTER:
318              case CENTER_BOTTOM:
319              case CENTER_BASE_LINE:
320              case CENTER_BOTTOM_BASE_LINE:
321                cursor.x() = cursor.x() + (cursor.x() - endOfLine_coords.x()) * 0.5f;
322                break;
323              // nothing to be done for these
324              //case RIGHT_TOP:
325              //case RIGHT_CENTER:
326              //case RIGHT_BOTTOM:
327              //case RIGHT_BASE_LINE:
328              //case RIGHT_BOTTOM_BASE_LINE:
329              //  break;
330              default:
331                break;
332            }
333            break;
334            }
335            case VERTICAL:
336            {
337            switch(_alignment)
338            {
339              // TODO: current behaviour top baselines lined up in both cases - need to implement
340              //       top of characters alignment - Question is this necessary?
341              // ... otherwise, nothing to be done for these 6 cases
342              //case LEFT_TOP:
343              //case CENTER_TOP:
344              //case RIGHT_TOP:
345              //  break;
346              //case LEFT_BASE_LINE:
347              //case CENTER_BASE_LINE:
348              //case RIGHT_BASE_LINE:
349              //  break;
350              case LEFT_CENTER:
351              case CENTER_CENTER:
352              case RIGHT_CENTER:
353                cursor.y() = cursor.y() + (cursor.y() - endOfLine_coords.y()) * 0.5f;
354                break;
355              case LEFT_BOTTOM_BASE_LINE:
356              case CENTER_BOTTOM_BASE_LINE:
357              case RIGHT_BOTTOM_BASE_LINE:
358                cursor.y() = cursor.y() - (linelength * _characterHeight);
359                break;
360              case LEFT_BOTTOM:
361              case CENTER_BOTTOM:
362              case RIGHT_BOTTOM:
363                cursor.y() = 2*cursor.y() - endOfLine_coords.y();
364                break;
365              default:
366                break;
367            }
368            break;
369          }
370        }
371
372        if (itr!=endOfLine_itr)
373        {
374
375            for(;itr!=endOfLine_itr;++itr)
376            {
377                unsigned int charcode = *itr;
378
379                Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
380                if (glyph)
381                {
382                    float width = (float)(glyph->getWidth()) * wr;
383                    float height = (float)(glyph->getHeight()) * hr;
384
385                    if (_layout==RIGHT_TO_LEFT)
386                    {
387                        cursor.x() -= glyph->getHorizontalAdvance() * wr;
388                    }
389
390                    // adjust cursor position w.r.t any kerning.
391                    if (kerning && previous_charcode)
392                    {
393                        switch(_layout)
394                        {
395                          case LEFT_TO_RIGHT:
396                          {
397                            osg::Vec2 delta(activefont->getKerning(previous_charcode,charcode,_kerningType));
398                            cursor.x() += delta.x() * wr;
399                            cursor.y() += delta.y() * hr;
400                            break;
401                          }
402                          case RIGHT_TO_LEFT:
403                          {
404                            osg::Vec2 delta(activefont->getKerning(charcode,previous_charcode,_kerningType));
405                            cursor.x() -= delta.x() * wr;
406                            cursor.y() -= delta.y() * hr;
407                            break;
408                          }
409                          case VERTICAL:
410                            break; // no kerning when vertical.
411                        }
412                    }
413
414                    local = cursor;
415                    osg::Vec2 bearing(horizontal?glyph->getHorizontalBearing():glyph->getVerticalBearing());
416                    local.x() += bearing.x() * wr;
417                    local.y() += bearing.y() * hr;
418
419                    GlyphQuads& glyphquad = _textureGlyphQuadMap[glyph->getTexture()];
420
421                    glyphquad._glyphs.push_back(glyph);
422                    glyphquad._lineNumbers.push_back(lineNumber);
423
424                    // Adjust coordinates and texture coordinates to avoid
425                    // clipping the edges of antialiased characters.
426                    osg::Vec2 mintc = glyph->getMinTexCoord();
427                    osg::Vec2 maxtc = glyph->getMaxTexCoord();
428                    osg::Vec2 vDiff = maxtc - mintc;
429
430                    float fHorizTCMargin = 1.0f / glyph->getTexture()->getTextureWidth();
431                    float fVertTCMargin = 1.0f / glyph->getTexture()->getTextureHeight();
432                    float fHorizQuadMargin = vDiff.x() == 0.0f ? 0.0f : width * fHorizTCMargin / vDiff.x();
433                    float fVertQuadMargin = vDiff.y() == 0.0f ? 0.0f : height * fVertTCMargin / vDiff.y();
434
435                    mintc.x() -= fHorizTCMargin;
436                    mintc.y() -= fVertTCMargin;
437                    maxtc.x() += fHorizTCMargin;
438                    maxtc.y() += fVertTCMargin;
439
440                    // set up the coords of the quad
441                    osg::Vec2 upLeft = local+osg::Vec2(0.0f-fHorizQuadMargin,height+fVertQuadMargin);
442                    osg::Vec2 lowLeft = local+osg::Vec2(0.0f-fHorizQuadMargin,0.0f-fVertQuadMargin);
443                    osg::Vec2 lowRight = local+osg::Vec2(width+fHorizQuadMargin,0.0f-fVertQuadMargin);
444                    osg::Vec2 upRight = local+osg::Vec2(width+fHorizQuadMargin,height+fVertQuadMargin);
445                    glyphquad._coords.push_back(upLeft);
446                    glyphquad._coords.push_back(lowLeft);
447                    glyphquad._coords.push_back(lowRight);
448                    glyphquad._coords.push_back(upRight);
449
450                    // set up the tex coords of the quad
451                    glyphquad._texcoords.push_back(osg::Vec2(mintc.x(),maxtc.y()));
452                    glyphquad._texcoords.push_back(osg::Vec2(mintc.x(),mintc.y()));
453                    glyphquad._texcoords.push_back(osg::Vec2(maxtc.x(),mintc.y()));
454                    glyphquad._texcoords.push_back(osg::Vec2(maxtc.x(),maxtc.y()));
455
456                    // move the cursor onto the next character.
457                    // also expand bounding box
458                    switch(_layout)
459                    {
460                      case LEFT_TO_RIGHT:
461                          cursor.x() += glyph->getHorizontalAdvance() * wr;
462                          _textBB.expandBy(osg::Vec3(lowLeft.x(), lowLeft.y(), 0.0f)); //lower left corner
463                          _textBB.expandBy(osg::Vec3(upRight.x(), upRight.y(), 0.0f)); //upper right corner
464                          break;
465                      case VERTICAL:
466                          cursor.y() -= glyph->getVerticalAdvance() * hr;
467                          _textBB.expandBy(osg::Vec3(upLeft.x(),upLeft.y(),0.0f)); //upper left corner
468                          _textBB.expandBy(osg::Vec3(lowRight.x(),lowRight.y(),0.0f)); //lower right corner
469                          break;
470                      case RIGHT_TO_LEFT:
471                          _textBB.expandBy(osg::Vec3(lowRight.x(),lowRight.y(),0.0f)); //lower right corner
472                          _textBB.expandBy(osg::Vec3(upLeft.x(),upLeft.y(),0.0f)); //upper left corner
473                          break;
474                    }
475                    previous_charcode = charcode;
476
477                }
478            }
479
480            // skip over spaces and return.
481            while (itr != _text.end() && *itr==' ') ++itr;
482            if (itr != _text.end() && *itr=='\n') ++itr;
483        }
484        else
485        {
486            ++itr;
487        }
488                               
489               
490        // move to new line.
491        switch(_layout)
492        {
493          case LEFT_TO_RIGHT:
494          {
495            startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
496            cursor = startOfLine_coords;
497            previous_charcode = 0;
498            _lineCount++;
499            break;
500          }
501          case RIGHT_TO_LEFT:
502          {
503            startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
504            cursor = startOfLine_coords;
505            previous_charcode = 0;
506            _lineCount++;
507            break;
508          }
509          case VERTICAL:
510          {
511            startOfLine_coords.x() += _characterHeight/getCharacterAspectRatio() * (1.0 + _lineSpacing);
512            cursor = startOfLine_coords;
513            previous_charcode = 0;
514            // because _lineCount is the max vertical no. of characters....
515            _lineCount = (_lineCount >linelength)?_lineCount:linelength;
516          }
517          break;
518        }
519       
520        ++lineNumber;
521
522    }
523   
524    TextBase::computePositions();
525    computeBackdropBoundingBox();
526    computeBoundingBoxMargin();
527    computeColorGradients();
528}
529
530// Returns false if there are no glyphs and the width/height values are invalid.
531// Also sets avg_width and avg_height to 0.0f if the value is invalid.
532// This method is used several times in a loop for the same object which will produce the same values.
533// Further optimization may try saving these values instead of recomputing them.
534bool Text::computeAverageGlyphWidthAndHeight(float& avg_width, float& avg_height) const
535{
536    float width = 0.0f;
537    float height = 0.0f;
538    float running_width = 0.0f;
539    float running_height = 0.0f;
540    avg_width = 0.0f;
541    avg_height = 0.0f;
542    int counter = 0;
543    unsigned int i;
544    bool is_valid_size = true;
545    // This section is going to try to compute the average width and height
546    // for a character among the text. The reason I shift by an
547    // average amount per-character instead of shifting each character
548    // by its per-instance amount is because it may look strange to see
549    // the individual backdrop text letters not space themselves the same
550    // way the foreground text does. Using one value gives uniformity.
551    // Note: This loop is repeated for each context. I think it may produce
552    // the same values regardless of context. This code be optimized by moving
553    // this loop outside the loop.
554    for(TextureGlyphQuadMap::const_iterator const_titr=_textureGlyphQuadMap.begin();
555        const_titr!=_textureGlyphQuadMap.end();
556        ++const_titr)
557    {
558        const GlyphQuads& glyphquad = const_titr->second;
559        const GlyphQuads::Coords2& coords2 = glyphquad._coords;
560        for(i = 0; i < coords2.size(); i+=4)
561        {
562            width = coords2[i+2].x() - coords2[i].x();
563            height = coords2[i].y() - coords2[i+1].y();
564
565            running_width += width;
566            running_height += height;
567            counter++;
568        }
569    }
570    if(0 == counter)
571    {
572        is_valid_size = false;
573    }
574    else
575    {
576        avg_width = running_width/counter;
577        avg_height = running_height/counter;
578    }
579    return is_valid_size;
580}
581
582
583void Text::computePositions(unsigned int contextID) const
584{
585    switch(_alignment)
586    {
587    case LEFT_TOP:      _offset.set(_textBB.xMin(),_textBB.yMax(),_textBB.zMin()); break;
588    case LEFT_CENTER:   _offset.set(_textBB.xMin(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
589    case LEFT_BOTTOM:   _offset.set(_textBB.xMin(),_textBB.yMin(),_textBB.zMin()); break;
590
591    case CENTER_TOP:    _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMax(),_textBB.zMin()); break;
592    case CENTER_CENTER: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
593    case CENTER_BOTTOM: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMin(),_textBB.zMin()); break;
594
595    case RIGHT_TOP:     _offset.set(_textBB.xMax(),_textBB.yMax(),_textBB.zMin()); break;
596    case RIGHT_CENTER:  _offset.set(_textBB.xMax(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
597    case RIGHT_BOTTOM:  _offset.set(_textBB.xMax(),_textBB.yMin(),_textBB.zMin()); break;
598
599    case LEFT_BASE_LINE:  _offset.set(0.0f,0.0f,0.0f); break;
600    case CENTER_BASE_LINE:  _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,0.0f,0.0f); break;
601    case RIGHT_BASE_LINE:  _offset.set(_textBB.xMax(),0.0f,0.0f); break;
602   
603    case LEFT_BOTTOM_BASE_LINE:  _offset.set(0.0f,-_characterHeight*(_lineCount-1),0.0f); break;
604    case CENTER_BOTTOM_BASE_LINE:  _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,-_characterHeight*(_lineCount-1),0.0f); break;
605    case RIGHT_BOTTOM_BASE_LINE:  _offset.set(_textBB.xMax(),-_characterHeight*(_lineCount-1),0.0f); break;
606    }
607   
608    AutoTransformCache& atc = _autoTransformCache[contextID];
609    osg::Matrix& matrix = atc._matrix;
610
611    if (_characterSizeMode!=OBJECT_COORDS || _autoRotateToScreen)
612    {
613
614        matrix.makeTranslate(-_offset);
615
616        osg::Matrix rotate_matrix;
617        if (_autoRotateToScreen)
618        {
619            osg::Vec3d trans(atc._modelview.getTrans());
620            atc._modelview.setTrans(0.0f,0.0f,0.0f);
621
622            rotate_matrix.invert(atc._modelview);
623
624            atc._modelview.setTrans(trans);
625        }
626
627        matrix.postMultRotate(_rotation);
628
629        if (_characterSizeMode!=OBJECT_COORDS)
630        {
631
632            osg::Matrix M(rotate_matrix);
633            M.postMultTranslate(_position);
634            M.postMult(atc._modelview);
635            osg::Matrix& P = atc._projection;
636           
637            // compute the pixel size vector.
638                       
639            // pre adjust P00,P20,P23,P33 by multiplying them by the viewport window matrix.
640            // here we do it in short hand with the knowledge of how the window matrix is formed
641            // note P23,P33 are multiplied by an implicit 1 which would come from the window matrix.
642            // Robert Osfield, June 2002.
643
644            // scaling for horizontal pixels
645            float P00 = P(0,0)*atc._width*0.5f;
646            float P20_00 = P(2,0)*atc._width*0.5f + P(2,3)*atc._width*0.5f;
647            osg::Vec3 scale_00(M(0,0)*P00 + M(0,2)*P20_00,
648                               M(1,0)*P00 + M(1,2)*P20_00,
649                               M(2,0)*P00 + M(2,2)*P20_00);
650
651            // scaling for vertical pixels
652            float P10 = P(1,1)*atc._height*0.5f;
653            float P20_10 = P(2,1)*atc._height*0.5f + P(2,3)*atc._height*0.5f;
654            osg::Vec3 scale_10(M(0,1)*P10 + M(0,2)*P20_10,
655                               M(1,1)*P10 + M(1,2)*P20_10,
656                               M(2,1)*P10 + M(2,2)*P20_10);
657
658            float P23 = P(2,3);
659            float P33 = P(3,3);
660
661            float pixelSizeVector_w = M(3,2)*P23 + M(3,3)*P33;
662
663            float pixelSizeVert=(_characterHeight*sqrtf(scale_10.length2()))/(pixelSizeVector_w*0.701f);
664            float pixelSizeHori=(_characterHeight/getCharacterAspectRatio()*sqrtf(scale_00.length2()))/(pixelSizeVector_w*0.701f);
665
666            // avoid nasty math by preventing a divide by zero
667            if (pixelSizeVert == 0.0f)
668               pixelSizeVert= 1.0f;
669            if (pixelSizeHori == 0.0f)
670               pixelSizeHori= 1.0f;
671
672            if (_characterSizeMode==SCREEN_COORDS)
673            {
674                float scale_font_vert=_characterHeight/pixelSizeVert;
675                float scale_font_hori=_characterHeight/getCharacterAspectRatio()/pixelSizeHori;
676
677                if (P10<0)
678                   scale_font_vert=-scale_font_vert;
679                matrix.postMultScale(osg::Vec3f(scale_font_hori, scale_font_vert,1.0f));
680            }
681            else if (pixelSizeVert>getFontHeight())
682            {
683                float scale_font = getFontHeight()/pixelSizeVert;
684                matrix.postMultScale(osg::Vec3f(scale_font, scale_font,1.0f));
685            }
686
687        }
688
689        if (_autoRotateToScreen)
690        {
691            matrix.postMult(rotate_matrix);
692        }
693
694        matrix.postMultTranslate(_position);
695    }
696    else if (!_rotation.zeroRotation())
697    {
698        matrix.makeRotate(_rotation);
699        matrix.preMultTranslate(-_offset);
700        matrix.postMultTranslate(_position);
701    }
702    else
703    {
704        matrix.makeTranslate(_position-_offset);
705    }
706
707    // now apply matrix to the glyphs.
708    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
709        titr!=_textureGlyphQuadMap.end();
710        ++titr)
711    {
712        GlyphQuads& glyphquad = titr->second;
713        GlyphQuads::Coords2& coords2 = glyphquad._coords;
714        GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
715       
716        unsigned int numCoords = coords2.size();
717        if (numCoords!=transformedCoords.size())
718        {
719            transformedCoords.resize(numCoords);
720        }
721       
722        for(unsigned int i=0;i<numCoords;++i)
723        {
724            transformedCoords[i] = osg::Vec3(coords2[i].x(),coords2[i].y(),0.0f)*matrix;
725        }
726    }
727
728    computeBackdropPositions(contextID);
729
730    _normal = osg::Matrix::transform3x3(osg::Vec3(0.0f,0.0f,1.0f),matrix);
731    _normal.normalize();
732
733    const_cast<Text*>(this)->dirtyBound();   
734}
735
736// Presumes the atc matrix is already up-to-date
737void Text::computeBackdropPositions(unsigned int contextID) const
738{
739    if(_backdropType == NONE)
740    {
741        return;
742    }
743
744    float avg_width = 0.0f;
745    float avg_height = 0.0f;
746    unsigned int i;
747    bool is_valid_size;
748   
749    AutoTransformCache& atc = _autoTransformCache[contextID];
750    osg::Matrix& matrix = atc._matrix;
751
752    // FIXME: OPTIMIZE: This function produces the same value regardless of contextID.
753    // Since we tend to loop over contextID, we should cache this value some how
754    // instead of recomputing it each time.
755    is_valid_size = computeAverageGlyphWidthAndHeight(avg_width, avg_height);
756
757    if (!is_valid_size) return;
758   
759    // now apply matrix to the glyphs.
760    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
761        titr!=_textureGlyphQuadMap.end();
762        ++titr)
763    {
764        GlyphQuads& glyphquad = titr->second;
765        GlyphQuads::Coords2& coords2 = glyphquad._coords;
766
767        unsigned int backdrop_index;
768        unsigned int max_backdrop_index;
769        if(_backdropType == OUTLINE)
770        {
771            // For outline, we want to draw the in every direction
772            backdrop_index = 0;
773            max_backdrop_index = 8;
774        }
775        else
776        {
777            // Yes, this may seem a little strange,
778            // but since the code is using references,
779            // I would have to duplicate the following code twice
780            // for each part of the if/else because I can't
781            // declare a reference without setting it immediately
782            // and it wouldn't survive the scope.
783            // So it happens that the _backdropType value matches
784            // the index in the array I want to store the coordinates
785            // in. So I'll just setup the for-loop so it only does
786            // the one direction I'm interested in.
787            backdrop_index = _backdropType;
788            max_backdrop_index = _backdropType+1;
789        }
790        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
791        {
792            GlyphQuads::Coords3& transformedCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
793            unsigned int numCoords = coords2.size();
794            if (numCoords!=transformedCoords.size())
795            {
796                transformedCoords.resize(numCoords);
797            }
798
799            for(i=0;i<numCoords;++i)
800            {
801                float horizontal_shift_direction;
802                float vertical_shift_direction;
803                switch(backdrop_index)
804                {
805                    case DROP_SHADOW_BOTTOM_RIGHT:
806                        {
807                            horizontal_shift_direction = 1.0f;
808                            vertical_shift_direction = -1.0f;
809                            break;
810                        }
811                    case DROP_SHADOW_CENTER_RIGHT:
812                        {
813                            horizontal_shift_direction = 1.0f;
814                            vertical_shift_direction = 0.0f;
815                            break;
816                        }
817                    case DROP_SHADOW_TOP_RIGHT:
818                        {
819                            horizontal_shift_direction = 1.0f;
820                            vertical_shift_direction = 1.0f;
821                            break;
822                        }
823                    case DROP_SHADOW_BOTTOM_CENTER:
824                        {
825                            horizontal_shift_direction = 0.0f;
826                            vertical_shift_direction = -1.0f;
827                            break;
828                        }
829                    case DROP_SHADOW_TOP_CENTER:
830                        {
831                            horizontal_shift_direction = 0.0f;
832                            vertical_shift_direction = 1.0f;
833                            break;
834                        }                               
835                    case DROP_SHADOW_BOTTOM_LEFT:
836                        {
837                            horizontal_shift_direction = -1.0f;
838                            vertical_shift_direction = -1.0f;
839                            break;
840                        }
841                    case DROP_SHADOW_CENTER_LEFT:
842                        {
843                            horizontal_shift_direction = -1.0f;
844                            vertical_shift_direction = 0.0f;
845                            break;
846                        }
847                    case DROP_SHADOW_TOP_LEFT:
848                        {
849                            horizontal_shift_direction = -1.0f;
850                            vertical_shift_direction = 1.0f;
851                            break;
852                        }
853                    default: // error
854                        {
855                            horizontal_shift_direction = 1.0f;
856                            vertical_shift_direction = -1.0f;
857                        }
858                }
859                transformedCoords[i] = osg::Vec3(horizontal_shift_direction * _backdropHorizontalOffset * avg_width+coords2[i].x(),vertical_shift_direction * _backdropVerticalOffset * avg_height+coords2[i].y(),0.0f)*matrix;
860            }
861        }
862    }
863}
864
865// This method adjusts the bounding box to account for the expanded area caused by the backdrop.
866// This assumes that the bounding box has already been computed for the text without the backdrop.
867void Text::computeBackdropBoundingBox() const
868{
869    if(_backdropType == NONE)
870    {
871        return;
872    }
873
874    float avg_width = 0.0f;
875    float avg_height = 0.0f;
876    bool is_valid_size;
877   
878    // FIXME: OPTIMIZE: It is possible that this value has already been computed before
879    // from previous calls to this function. This might be worth optimizing.
880    is_valid_size = computeAverageGlyphWidthAndHeight(avg_width, avg_height);
881
882    // Finally, we have one more issue to deal with.
883    // Now that the text takes more space, we need
884    // to adjust the size of the bounding box.
885    if((!_textBB.valid() || !is_valid_size))
886    {
887        return;
888    }
889   
890    // Finally, we have one more issue to deal with.
891    // Now that the text takes more space, we need
892    // to adjust the size of the bounding box.
893    switch(_backdropType)
894    {
895        case DROP_SHADOW_BOTTOM_RIGHT:
896            {
897                _textBB.set(
898                    _textBB.xMin(),
899                    _textBB.yMin() - avg_height * _backdropVerticalOffset,
900                    _textBB.zMin(),
901                    _textBB.xMax() + avg_width * _backdropHorizontalOffset,
902                    _textBB.yMax(),
903                    _textBB.zMax()
904                );
905                break;
906            }
907        case DROP_SHADOW_CENTER_RIGHT:
908            {
909                _textBB.set(
910                    _textBB.xMin(),
911                    _textBB.yMin(),
912                    _textBB.zMin(),
913                    _textBB.xMax() + avg_width * _backdropHorizontalOffset,
914                    _textBB.yMax(),
915                    _textBB.zMax()
916                );
917                break;
918            }
919        case DROP_SHADOW_TOP_RIGHT:
920            {
921                _textBB.set(
922                    _textBB.xMin(),
923                    _textBB.yMin(),
924                    _textBB.zMin(),
925                    _textBB.xMax() + avg_width * _backdropHorizontalOffset,
926                    _textBB.yMax() + avg_height * _backdropVerticalOffset,
927                    _textBB.zMax()
928                );
929                break;
930            }
931        case DROP_SHADOW_BOTTOM_CENTER:
932            {
933                _textBB.set(
934                    _textBB.xMin(),
935                    _textBB.yMin() - avg_height * _backdropVerticalOffset,
936                    _textBB.zMin(),
937                    _textBB.xMax(),
938                    _textBB.yMax(),
939                    _textBB.zMax()
940                );
941                break;
942            }
943        case DROP_SHADOW_TOP_CENTER:
944            {
945                _textBB.set(
946                    _textBB.xMin(),
947                    _textBB.yMin(),
948                    _textBB.zMin(),
949                    _textBB.xMax(),
950                    _textBB.yMax() + avg_height * _backdropVerticalOffset,
951                    _textBB.zMax()
952                );
953                break;
954            }                               
955        case DROP_SHADOW_BOTTOM_LEFT:
956            {
957                _textBB.set(
958                    _textBB.xMin() - avg_width * _backdropHorizontalOffset,
959                    _textBB.yMin() - avg_height * _backdropVerticalOffset,
960                    _textBB.zMin(),
961                    _textBB.xMax(),
962                    _textBB.yMax(),
963                    _textBB.zMax()
964                );
965                break;
966            }
967        case DROP_SHADOW_CENTER_LEFT:
968            {
969                _textBB.set(
970                    _textBB.xMin() - avg_width * _backdropHorizontalOffset,
971                    _textBB.yMin(),
972                    _textBB.zMin(),
973                    _textBB.xMax(),
974                    _textBB.yMax(),
975                    _textBB.zMax()
976                );            break;
977            }
978        case DROP_SHADOW_TOP_LEFT:
979            {
980                _textBB.set(
981                    _textBB.xMin() - avg_width * _backdropHorizontalOffset,
982                    _textBB.yMin(),
983                    _textBB.zMin(),
984                    _textBB.xMax(),
985                    _textBB.yMax() + avg_height * _backdropVerticalOffset,
986                    _textBB.zMax()
987                );
988                break;
989            }
990        case OUTLINE:
991            {
992                _textBB.set(
993                    _textBB.xMin() - avg_width * _backdropHorizontalOffset,
994                    _textBB.yMin() - avg_height * _backdropVerticalOffset,
995                    _textBB.zMin(),
996                    _textBB.xMax() + avg_width * _backdropHorizontalOffset,
997                    _textBB.yMax() + avg_height * _backdropVerticalOffset,
998                    _textBB.zMax()
999                );
1000                break;
1001            }
1002        default: // error
1003            {
1004                break;
1005            }
1006    }
1007}
1008
1009// This method expands the bounding box to a settable margin when a bounding box drawing mode is active.
1010void Text::computeBoundingBoxMargin() const
1011{
1012    if(_drawMode & (BOUNDINGBOX | FILLEDBOUNDINGBOX)){
1013        _textBB.set(
1014            _textBB.xMin() - _textBBMargin,
1015            _textBB.yMin() - _textBBMargin,
1016            _textBB.zMin(),
1017            _textBB.xMax() + _textBBMargin,
1018            _textBB.yMax() + _textBBMargin,
1019            _textBB.zMax()
1020        );
1021    }
1022}
1023
1024void Text::computeColorGradients() const
1025{
1026    switch(_colorGradientMode)
1027    {
1028        case SOLID:
1029            return;
1030            break;
1031        case PER_CHARACTER:
1032            computeColorGradientsPerCharacter();
1033            break;
1034        case OVERALL:
1035            computeColorGradientsOverall();
1036            break;
1037        default:
1038            break;
1039    }
1040}
1041
1042void Text::computeColorGradientsOverall() const
1043{
1044
1045    float min_x = FLT_MAX;
1046    float min_y = FLT_MAX;
1047    float max_x = FLT_MIN;
1048    float max_y = FLT_MIN;
1049
1050    unsigned int i;
1051
1052    for(TextureGlyphQuadMap::const_iterator const_titr=_textureGlyphQuadMap.begin();
1053        const_titr!=_textureGlyphQuadMap.end();
1054        ++const_titr)
1055    {
1056        const GlyphQuads& glyphquad = const_titr->second;
1057        const GlyphQuads::Coords2& coords2 = glyphquad._coords;
1058
1059        for(i=0;i<coords2.size();++i)
1060        { 
1061            // Min and Max are needed for color gradients
1062            if(coords2[i].x() > max_x)
1063            {
1064                max_x = coords2[i].x();
1065            }
1066            if(coords2[i].x() < min_x)
1067            {
1068                min_x = coords2[i].x();
1069            }
1070            if(coords2[i].y() > max_y)
1071            {
1072                max_y = coords2[i].y();
1073            }
1074            if(coords2[i].y() < min_y)
1075            {
1076                min_y = coords2[i].y();
1077            }       
1078
1079        }
1080    }
1081
1082    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1083        titr!=_textureGlyphQuadMap.end();
1084        ++titr)
1085    {
1086        GlyphQuads& glyphquad = titr->second;
1087        GlyphQuads::Coords2& coords2 = glyphquad._coords;
1088        GlyphQuads::ColorCoords& colorCoords = glyphquad._colorCoords;
1089
1090        unsigned int numCoords = coords2.size();
1091        if (numCoords!=colorCoords.size())
1092        {
1093            colorCoords.resize(numCoords);
1094        }
1095
1096        for(i=0;i<numCoords;++i)
1097        {
1098            float red = bilinearInterpolate(
1099                min_x,
1100                max_x,
1101                min_y,
1102                max_y,
1103                coords2[i].x(),
1104                coords2[i].y(),
1105                _colorGradientBottomLeft[0],
1106                _colorGradientTopLeft[0],
1107                _colorGradientBottomRight[0],
1108                _colorGradientTopRight[0]
1109            );
1110
1111            float green = bilinearInterpolate(
1112                min_x,
1113                max_x,
1114                min_y,
1115                max_y,
1116                coords2[i].x(),
1117                coords2[i].y(),
1118                _colorGradientBottomLeft[1],
1119                _colorGradientTopLeft[1],
1120                _colorGradientBottomRight[1],
1121                _colorGradientTopRight[1]
1122            );
1123
1124            float blue = bilinearInterpolate(
1125                min_x,
1126                max_x,
1127                min_y,
1128                max_y,
1129                coords2[i].x(),
1130                coords2[i].y(),
1131                _colorGradientBottomLeft[2],
1132                _colorGradientTopLeft[2],
1133                _colorGradientBottomRight[2],
1134                _colorGradientTopRight[2]
1135            );
1136            // Alpha does not convert to HSV           
1137            float alpha = bilinearInterpolate(
1138                min_x,
1139                max_x,
1140                min_y,
1141                max_y,
1142                coords2[i].x(),
1143                coords2[i].y(),
1144                _colorGradientBottomLeft[3],
1145                _colorGradientTopLeft[3],
1146                _colorGradientBottomRight[3],
1147                _colorGradientTopRight[3]
1148            );                                   
1149
1150            colorCoords[i] = osg::Vec4(red,green,blue,alpha);
1151        }
1152    }
1153}
1154
1155void Text::computeColorGradientsPerCharacter() const
1156{
1157    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1158        titr!=_textureGlyphQuadMap.end();
1159        ++titr)
1160    {
1161        GlyphQuads& glyphquad = titr->second;
1162        GlyphQuads::Coords2& coords2 = glyphquad._coords;
1163        GlyphQuads::ColorCoords& colorCoords = glyphquad._colorCoords;
1164
1165        unsigned int numCoords = coords2.size();
1166        if (numCoords!=colorCoords.size())
1167        {
1168            colorCoords.resize(numCoords);
1169        }
1170
1171        for(unsigned int i=0;i<numCoords;++i)
1172        {
1173            switch(i%4)
1174            {
1175                case 0: // top-left
1176                    {
1177                        colorCoords[i] = _colorGradientTopLeft;
1178                        break;
1179                    }
1180                case 1: // bottom-left
1181                    {
1182                        colorCoords[i] = _colorGradientBottomLeft;
1183                        break;
1184                    }
1185                case 2: // bottom-right
1186                    {
1187                        colorCoords[i] = _colorGradientBottomRight;
1188                        break;
1189                    }
1190                case 3: // top-right
1191                    {
1192                        colorCoords[i] = _colorGradientTopRight;
1193                        break;
1194                    }
1195                default: // error
1196                    {
1197                        colorCoords[i] = osg::Vec4(0.0f,0.0f,0.0f,1.0f);
1198                    }
1199            }
1200        }
1201    }
1202}
1203
1204void Text::drawImplementation(osg::RenderInfo& renderInfo) const
1205{
1206    drawImplementation(*renderInfo.getState(), osg::Vec4(1.0f,1.0f,1.0f,1.0f));
1207}
1208
1209void Text::drawImplementation(osg::State& state, const osg::Vec4& colorMultiplier) const
1210{
1211    unsigned int contextID = state.getContextID();
1212
1213    state.applyMode(GL_BLEND,true);
1214#if 1
1215    state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON);
1216#else
1217    state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
1218#endif
1219#if defined(OSG_GL_FIXED_FUNCTION_AVAILABLE)
1220    state.applyTextureAttribute(0,getActiveFont()->getTexEnv());
1221#endif
1222    if (_characterSizeMode!=OBJECT_COORDS || _autoRotateToScreen)
1223    {
1224        unsigned int frameNumber = state.getFrameStamp()?state.getFrameStamp()->getFrameNumber():0;
1225        AutoTransformCache& atc = _autoTransformCache[contextID];
1226        const osg::Matrix& modelview = state.getModelViewMatrix();
1227        const osg::Matrix& projection = state.getProjectionMatrix();
1228
1229        osg::Vec3 newTransformedPosition = _position*modelview;
1230
1231        int width = atc._width;
1232        int height = atc._height;
1233
1234        const osg::Viewport* viewport = state.getCurrentViewport();
1235        if (viewport)
1236        {
1237            width = static_cast<int>(viewport->width());
1238            height = static_cast<int>(viewport->height());
1239        }
1240
1241        bool doUpdate = atc._traversalNumber==-1;
1242        if (atc._traversalNumber>=0)
1243        {
1244            if (atc._modelview!=modelview)
1245            {
1246                doUpdate = true;
1247            }
1248            else if (width!=atc._width || height!=atc._height)
1249            {
1250                doUpdate = true;
1251            }
1252            else if (atc._projection!=projection)
1253            {
1254                doUpdate = true;
1255            }
1256        }
1257       
1258        atc._traversalNumber = frameNumber;
1259        atc._width = width;
1260        atc._height = height;
1261       
1262        if (doUpdate)
1263        {   
1264            atc._transformedPosition = newTransformedPosition;
1265            atc._projection = projection;
1266            atc._modelview = modelview;
1267
1268            computePositions(contextID);
1269        }
1270       
1271    }
1272   
1273   
1274    // Ensure that the glyph coordinates have been transformed for
1275    // this context id.
1276
1277    if ( !_textureGlyphQuadMap.empty() )
1278    {
1279        const GlyphQuads& glyphquad = (_textureGlyphQuadMap.begin())->second;
1280        if ( glyphquad._transformedCoords[contextID].empty() )
1281        {
1282            computePositions(contextID);
1283        }
1284    }
1285
1286    osg::GLBeginEndAdapter& gl = (state.getGLBeginEndAdapter());
1287
1288    state.Normal(_normal.x(), _normal.y(), _normal.z());
1289
1290    if (_drawMode & FILLEDBOUNDINGBOX)
1291    {
1292        if (_textBB.valid())
1293        {
1294        #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1295            state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
1296
1297            const osg::Matrix& matrix = _autoTransformCache[contextID]._matrix;
1298
1299            osg::Vec3 c00(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
1300            osg::Vec3 c10(osg::Vec3(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*matrix);
1301            osg::Vec3 c11(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*matrix);
1302            osg::Vec3 c01(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*matrix);
1303
1304            switch(_backdropImplementation)
1305            {
1306                case NO_DEPTH_BUFFER:
1307                    // Do nothing.  The bounding box will be rendered before the text and that's all that matters.
1308                    break;
1309                case DEPTH_RANGE:
1310                    glPushAttrib(GL_DEPTH_BUFFER_BIT);
1311                    //unsigned int backdrop_index = 0;
1312                    //unsigned int max_backdrop_index = 8;
1313                    //const double offset = double(max_backdrop_index - backdrop_index) * 0.003;
1314                    glDepthRange(0.001, 1.001);
1315                    break;
1316                /*case STENCIL_BUFFER:
1317                    break;*/
1318                default:
1319                    glPushAttrib(GL_POLYGON_OFFSET_FILL);
1320                    glEnable(GL_POLYGON_OFFSET_FILL);
1321                    glPolygonOffset(0.1f * osg::PolygonOffset::getFactorMultiplier(), 10.0f * osg::PolygonOffset::getUnitsMultiplier() );
1322            }
1323
1324            gl.Color4f(colorMultiplier.r()*_textBBColor.r(),colorMultiplier.g()*_textBBColor.g(),colorMultiplier.b()*_textBBColor.b(),colorMultiplier.a()*_textBBColor.a());
1325            gl.Begin(GL_QUADS);
1326                gl.Vertex3fv(c00.ptr());
1327                gl.Vertex3fv(c10.ptr());
1328                gl.Vertex3fv(c11.ptr());
1329                gl.Vertex3fv(c01.ptr());
1330            gl.End();
1331
1332            switch(_backdropImplementation)
1333            {
1334                case NO_DEPTH_BUFFER:
1335                    // Do nothing.
1336                    break;
1337                case DEPTH_RANGE:
1338                    glDepthRange(0.0, 1.0);
1339                    glPopAttrib();
1340                    break;
1341                /*case STENCIL_BUFFER:
1342                    break;*/
1343                default:
1344                    glDisable(GL_POLYGON_OFFSET_FILL);
1345                    glPopAttrib();
1346            }
1347        #else
1348            OSG_NOTICE<<"Warning: Text::drawImplementation() fillMode FILLEDBOUNDINGBOX not supported"<<std::endl;
1349        #endif
1350        }
1351    }   
1352
1353#if 1
1354    state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON);
1355#else
1356    state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
1357#endif
1358#if defined(OSG_GL_FIXED_FUNCTION_AVAILABLE)
1359    state.applyTextureAttribute(0,getActiveFont()->getTexEnv());
1360#endif
1361
1362    if (_drawMode & TEXT)
1363    {
1364
1365        state.disableAllVertexArrays();
1366
1367        // Okay, since ATI's cards/drivers are not working correctly,
1368        // we need alternative solutions to glPolygonOffset.
1369        // So this is a pick your poison approach. Each alternative
1370        // backend has trade-offs associated with it, but with luck,
1371        // the user may find that works for them.
1372        if(_backdropType != NONE && _backdropImplementation != DELAYED_DEPTH_WRITES)
1373        {
1374            switch(_backdropImplementation)
1375            {
1376                case POLYGON_OFFSET:
1377                    renderWithPolygonOffset(state,colorMultiplier);
1378                    break;
1379                case NO_DEPTH_BUFFER:
1380                    renderWithNoDepthBuffer(state,colorMultiplier);
1381                    break;
1382                case DEPTH_RANGE:
1383                    renderWithDepthRange(state,colorMultiplier);
1384                    break;
1385                case STENCIL_BUFFER:
1386                    renderWithStencilBuffer(state,colorMultiplier);
1387                    break;
1388                default:
1389                    renderWithPolygonOffset(state,colorMultiplier);
1390            }
1391        }
1392        else
1393        {
1394            renderWithDelayedDepthWrites(state,colorMultiplier);
1395        }
1396    }
1397
1398    if (_drawMode & BOUNDINGBOX)
1399    {
1400
1401        if (_textBB.valid())
1402        {
1403            state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
1404
1405            const osg::Matrix& matrix = _autoTransformCache[contextID]._matrix;
1406
1407            osg::Vec3 c00(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
1408            osg::Vec3 c10(osg::Vec3(_textBB.xMax(),_textBB.yMin(),_textBB.zMin())*matrix);
1409            osg::Vec3 c11(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*matrix);
1410            osg::Vec3 c01(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*matrix);
1411
1412       
1413            gl.Color4f(colorMultiplier.r()*_textBBColor.r(),colorMultiplier.g()*_textBBColor.g(),colorMultiplier.b()*_textBBColor.b(),colorMultiplier.a()*_textBBColor.a());
1414            gl.Begin(GL_LINE_LOOP);
1415                gl.Vertex3fv(c00.ptr());
1416                gl.Vertex3fv(c10.ptr());
1417                gl.Vertex3fv(c11.ptr());
1418                gl.Vertex3fv(c01.ptr());
1419            gl.End();
1420        }
1421    }
1422
1423    if (_drawMode & ALIGNMENT)
1424    {
1425        gl.Color4fv(colorMultiplier.ptr());
1426
1427        float cursorsize = _characterHeight*0.5f;
1428
1429        const osg::Matrix& matrix = _autoTransformCache[contextID]._matrix;
1430
1431        osg::Vec3 hl(osg::Vec3(_offset.x()-cursorsize,_offset.y(),_offset.z())*matrix);
1432        osg::Vec3 hr(osg::Vec3(_offset.x()+cursorsize,_offset.y(),_offset.z())*matrix);
1433        osg::Vec3 vt(osg::Vec3(_offset.x(),_offset.y()-cursorsize,_offset.z())*matrix);
1434        osg::Vec3 vb(osg::Vec3(_offset.x(),_offset.y()+cursorsize,_offset.z())*matrix);
1435
1436        state.applyTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::OFF);
1437       
1438        gl.Begin(GL_LINES);
1439            gl.Vertex3fv(hl.ptr());
1440            gl.Vertex3fv(hr.ptr());
1441            gl.Vertex3fv(vt.ptr());
1442            gl.Vertex3fv(vb.ptr());
1443        gl.End();
1444       
1445    }   
1446}
1447
1448void Text::accept(osg::Drawable::ConstAttributeFunctor& af) const
1449{
1450    for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin();
1451        titr!=_textureGlyphQuadMap.end();
1452        ++titr)
1453    {
1454        const GlyphQuads& glyphquad = titr->second;
1455        af.apply(osg::Drawable::VERTICES,glyphquad._transformedCoords[0].size(),&(glyphquad._transformedCoords[0].front()));
1456        af.apply(osg::Drawable::TEXTURE_COORDS_0,glyphquad._texcoords.size(),&(glyphquad._texcoords.front()));
1457    }
1458}
1459
1460void Text::accept(osg::PrimitiveFunctor& pf) const
1461{
1462    for(TextureGlyphQuadMap::const_iterator titr=_textureGlyphQuadMap.begin();
1463        titr!=_textureGlyphQuadMap.end();
1464        ++titr)
1465    {
1466        const GlyphQuads& glyphquad = titr->second;
1467
1468        pf.setVertexArray(glyphquad._transformedCoords[0].size(),&(glyphquad._transformedCoords[0].front()));
1469        pf.drawArrays(GL_QUADS,0,glyphquad._transformedCoords[0].size());
1470           
1471    }
1472   
1473}
1474
1475
1476void Text::setThreadSafeRefUnref(bool threadSafe)
1477{
1478    TextBase::setThreadSafeRefUnref(threadSafe);
1479
1480    getActiveFont()->setThreadSafeRefUnref(threadSafe);
1481}
1482
1483void Text::resizeGLObjectBuffers(unsigned int maxSize)
1484{
1485    TextBase::resizeGLObjectBuffers(maxSize);
1486   
1487    getActiveFont()->resizeGLObjectBuffers(maxSize);
1488}
1489
1490
1491void Text::releaseGLObjects(osg::State* state) const
1492{
1493    TextBase::releaseGLObjects(state);
1494    getActiveFont()->releaseGLObjects(state);
1495}
1496
1497
1498void Text::setBackdropType(BackdropType type)
1499{
1500    if (_backdropType==type) return;
1501
1502    _backdropType = type;
1503    computeGlyphRepresentation();
1504}
1505
1506void Text::setBackdropImplementation(BackdropImplementation implementation)
1507{
1508    if (_backdropImplementation==implementation) return;
1509
1510    _backdropImplementation = implementation;
1511    computeGlyphRepresentation();
1512}
1513
1514
1515void Text::setBackdropOffset(float offset)
1516{
1517    _backdropHorizontalOffset = offset;
1518    _backdropVerticalOffset = offset;
1519    computeGlyphRepresentation();
1520}
1521
1522void Text::setBackdropOffset(float horizontal, float vertical)
1523{
1524    _backdropHorizontalOffset = horizontal;
1525    _backdropVerticalOffset = vertical;
1526    computeGlyphRepresentation();
1527}
1528
1529void Text::setBackdropColor(const osg::Vec4& color)
1530{
1531    _backdropColor = color;
1532}
1533
1534void Text::setColorGradientMode(ColorGradientMode mode)
1535{
1536    if (_colorGradientMode==mode) return;
1537
1538    _colorGradientMode = mode;
1539    computeGlyphRepresentation();
1540}
1541
1542void Text::setColorGradientCorners(const osg::Vec4& topLeft, const osg::Vec4& bottomLeft, const osg::Vec4& bottomRight, const osg::Vec4& topRight)
1543{
1544    _colorGradientTopLeft = topLeft;
1545    _colorGradientBottomLeft = bottomLeft;
1546    _colorGradientBottomRight = bottomRight;
1547    _colorGradientTopRight = topRight;
1548    computeGlyphRepresentation();
1549}
1550
1551// Formula for f(x,y) from Wikipedia "Bilinear interpolation", 2006-06-18
1552float Text::bilinearInterpolate(float x1, float x2, float y1, float y2, float x, float y, float q11, float q12, float q21, float q22) const
1553{
1554    return (
1555        ((q11 / ((x2-x1)*(y2-y1))) * (x2-x)*(y2-y))
1556        + ((q21 / ((x2-x1)*(y2-y1))) * (x-x1)*(y2-y))
1557        + ((q12 / ((x2-x1)*(y2-y1))) * (x2-x)*(y-y1))
1558        + ((q22 / ((x2-x1)*(y2-y1))) * (x-x1)*(y-y1))
1559    );
1560}
1561
1562void Text::drawForegroundText(osg::State& state, const GlyphQuads& glyphquad, const osg::Vec4& colorMultiplier) const
1563{
1564    unsigned int contextID = state.getContextID();
1565
1566    const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
1567    if (!transformedCoords.empty())
1568    {
1569        state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords.front()));
1570        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1571
1572        if(_colorGradientMode == SOLID)
1573        {
1574            state.disableColorPointer();
1575            state.Color(colorMultiplier.r()*_color.r(),colorMultiplier.g()*_color.g(),colorMultiplier.b()*_color.b(),colorMultiplier.a()*_color.a());
1576        }
1577        else
1578        {
1579            state.setColorPointer( 4, GL_FLOAT, 0, &(glyphquad._colorCoords.front()));
1580        }
1581
1582        state.drawQuads(0,transformedCoords.size());
1583
1584    }
1585}
1586
1587void Text::renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMultiplier) const
1588{
1589    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1590        titr!=_textureGlyphQuadMap.end();
1591        ++titr)
1592    {
1593        // need to set the texture here...
1594        state.applyTextureAttribute(0,titr->first.get());
1595
1596        const GlyphQuads& glyphquad = titr->second;
1597
1598        drawForegroundText(state, glyphquad, colorMultiplier);
1599    }
1600}
1601
1602void Text::renderWithDelayedDepthWrites(osg::State& state, const osg::Vec4& colorMultiplier) const
1603{
1604    //glPushAttrib( _enableDepthWrites ? (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) : GL_DEPTH_BUFFER_BIT);
1605    // Render to color buffer without writing to depth buffer.
1606    glDepthMask(GL_FALSE);
1607    drawTextWithBackdrop(state,colorMultiplier);
1608
1609    // Render to depth buffer if depth writes requested.
1610    if( _enableDepthWrites )
1611    {
1612        glDepthMask(GL_TRUE);
1613        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1614        drawTextWithBackdrop(state,colorMultiplier);
1615    }
1616
1617    state.haveAppliedAttribute(osg::StateAttribute::DEPTH);
1618    state.haveAppliedAttribute(osg::StateAttribute::COLORMASK);
1619
1620    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1621    //glPopAttrib();
1622}
1623
1624void Text::drawTextWithBackdrop(osg::State& state, const osg::Vec4& colorMultiplier) const
1625{
1626    unsigned int contextID = state.getContextID();
1627
1628    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1629        titr!=_textureGlyphQuadMap.end();
1630        ++titr)
1631    {
1632        // need to set the texture here...
1633        state.applyTextureAttribute(0,titr->first.get());
1634
1635        const GlyphQuads& glyphquad = titr->second;
1636
1637        if(_backdropType != NONE)
1638        {
1639            unsigned int backdrop_index;
1640            unsigned int max_backdrop_index;
1641            if(_backdropType == OUTLINE)
1642            {
1643                backdrop_index = 0;
1644                max_backdrop_index = 8;
1645            }
1646            else
1647            {
1648                backdrop_index = _backdropType;
1649                max_backdrop_index = _backdropType+1;
1650            }
1651
1652            state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1653            state.disableColorPointer();
1654            state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a());
1655
1656            for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1657            {
1658                const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1659                if (!transformedBackdropCoords.empty())
1660                {
1661                    state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1662                    state.drawQuads(0,transformedBackdropCoords.size());
1663                }
1664            }
1665        }
1666
1667        drawForegroundText(state, glyphquad, colorMultiplier);
1668    }
1669}
1670
1671
1672void Text::renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const
1673{
1674#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1675    unsigned int contextID = state.getContextID();
1676
1677    if (!osg::PolygonOffset::areFactorAndUnitsMultipliersSet())
1678    {
1679        osg::PolygonOffset::setFactorAndUnitsMultipliersUsingBestGuessForDriver();
1680    }
1681
1682    // Do I really need to do this for glPolygonOffset?
1683    glPushAttrib(GL_POLYGON_OFFSET_FILL);
1684    glEnable(GL_POLYGON_OFFSET_FILL);
1685
1686    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1687        titr!=_textureGlyphQuadMap.end();
1688        ++titr)
1689    {
1690        // need to set the texture here...
1691        state.applyTextureAttribute(0,titr->first.get());
1692
1693        const GlyphQuads& glyphquad = titr->second;
1694
1695        unsigned int backdrop_index;
1696        unsigned int max_backdrop_index;
1697        if(_backdropType == OUTLINE)
1698        {
1699            backdrop_index = 0;
1700            max_backdrop_index = 8;
1701        }
1702        else
1703        {
1704            backdrop_index = _backdropType;
1705            max_backdrop_index = _backdropType+1;
1706        }
1707
1708        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1709        state.disableColorPointer();
1710        state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a());
1711
1712        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1713        {
1714            const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1715            if (!transformedBackdropCoords.empty())
1716            {
1717                state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1718                glPolygonOffset(0.1f * osg::PolygonOffset::getFactorMultiplier(),
1719                                osg::PolygonOffset::getUnitsMultiplier() * (max_backdrop_index-backdrop_index) );
1720                state.drawQuads(0,transformedBackdropCoords.size());
1721            }
1722        }
1723
1724        // Reset the polygon offset so the foreground text is on top
1725        glPolygonOffset(0.0f,0.0f);
1726
1727        drawForegroundText(state, glyphquad, colorMultiplier);
1728    }
1729
1730    glPopAttrib();
1731#else
1732    OSG_NOTICE<<"Warning: Text::renderWithPolygonOffset(..) not implemented."<<std::endl;
1733#endif
1734}
1735   
1736
1737void Text::renderWithNoDepthBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const
1738{
1739#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1740    unsigned int contextID = state.getContextID();
1741
1742    glPushAttrib(GL_DEPTH_BUFFER_BIT);
1743    glDisable(GL_DEPTH_TEST);
1744
1745    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1746        titr!=_textureGlyphQuadMap.end();
1747        ++titr)
1748    {
1749        // need to set the texture here...
1750        state.applyTextureAttribute(0,titr->first.get());
1751
1752        const GlyphQuads& glyphquad = titr->second;
1753
1754        unsigned int backdrop_index;
1755        unsigned int max_backdrop_index;
1756        if(_backdropType == OUTLINE)
1757        {
1758            backdrop_index = 0;
1759            max_backdrop_index = 8;
1760        }
1761        else
1762        {
1763            backdrop_index = _backdropType;
1764            max_backdrop_index = _backdropType+1;
1765        }
1766
1767        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1768        state.disableColorPointer();
1769        state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a());
1770
1771        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1772        {
1773            const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1774            if (!transformedBackdropCoords.empty())
1775            {
1776                state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1777                state.drawQuads(0,transformedBackdropCoords.size());
1778            }
1779        }
1780
1781        drawForegroundText(state, glyphquad, colorMultiplier);
1782    }
1783
1784    glPopAttrib();
1785#else
1786    OSG_NOTICE<<"Warning: Text::renderWithNoDepthBuffer(..) not implemented."<<std::endl;
1787#endif
1788}
1789
1790// This idea comes from Paul Martz's OpenGL FAQ: 13.050
1791void Text::renderWithDepthRange(osg::State& state, const osg::Vec4& colorMultiplier) const
1792{
1793#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1794    unsigned int contextID = state.getContextID();
1795
1796    // Hmmm, the man page says GL_VIEWPORT_BIT for Depth range (near and far)
1797    // but experimentally, GL_DEPTH_BUFFER_BIT for glDepthRange.
1798//    glPushAttrib(GL_VIEWPORT_BIT);
1799    glPushAttrib(GL_DEPTH_BUFFER_BIT);
1800
1801    for(TextureGlyphQuadMap::iterator titr=_textureGlyphQuadMap.begin();
1802        titr!=_textureGlyphQuadMap.end();
1803        ++titr)
1804    {
1805        // need to set the texture here...
1806        state.applyTextureAttribute(0,titr->first.get());
1807
1808        const GlyphQuads& glyphquad = titr->second;
1809
1810        unsigned int backdrop_index;
1811        unsigned int max_backdrop_index;
1812        if(_backdropType == OUTLINE)
1813        {
1814            backdrop_index = 0;
1815            max_backdrop_index = 8;
1816        }
1817        else
1818        {
1819            backdrop_index = _backdropType;
1820            max_backdrop_index = _backdropType+1;
1821        }
1822
1823        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1824        state.disableColorPointer();
1825        state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a());
1826
1827        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1828        {
1829            const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1830            if (!transformedBackdropCoords.empty())
1831            {
1832                state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1833                double offset = double(max_backdrop_index-backdrop_index)*0.0001;
1834                glDepthRange( offset, 1.0+offset);
1835
1836                state.drawQuads(0,transformedBackdropCoords.size());
1837            }
1838        }
1839
1840        glDepthRange(0.0, 1.0);
1841
1842        drawForegroundText(state, glyphquad, colorMultiplier);
1843    }
1844
1845    glPopAttrib();
1846#else
1847    OSG_NOTICE<<"Warning: Text::renderWithDepthRange(..) not implemented."<<std::endl;
1848#endif
1849}
1850
1851void Text::renderWithStencilBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const
1852{
1853#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE)
1854    /* Here are the steps:
1855     * 1) Disable drawing color
1856     * 2) Enable the stencil buffer
1857     * 3) Draw all the text to the stencil buffer
1858     * 4) Disable the stencil buffer
1859     * 5) Enable color
1860     * 6) Disable the depth buffer
1861     * 7) Draw all the text again.
1862     * 7b) Make sure the foreground text is drawn last if priority levels
1863     * are the same OR
1864     * 7c) If priority levels are different, then make sure the foreground
1865     * text has the higher priority.
1866     */
1867    unsigned int contextID = state.getContextID();
1868    TextureGlyphQuadMap::iterator titr; // Moved up here for VC6
1869   
1870    glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_STENCIL_TEST);
1871
1872    // It seems I can get away without calling this here
1873    //glClear(GL_STENCIL_BUFFER_BIT);
1874
1875    // enable stencil buffer
1876    glEnable(GL_STENCIL_TEST);
1877
1878    // write a one to the stencil buffer everywhere we are about to draw
1879    glStencilFunc(GL_ALWAYS, 1, 1);
1880
1881    // write only to the stencil buffer if we pass the depth test
1882    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1883
1884    // Disable writing to the color buffer so we only write to the stencil
1885    // buffer and the depth buffer
1886    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1887
1888    // make sure the depth buffer is enabled
1889//    glEnable(GL_DEPTH_TEST);
1890//    glDepthMask(GL_TRUE);
1891//    glDepthFunc(GL_LESS);
1892
1893    // Arrrgh! Why does the code only seem to work correctly if I call this?
1894    glDepthMask(GL_FALSE);
1895   
1896
1897    // Draw all the text to the stencil buffer to mark out the region
1898    // that we can write too.
1899   
1900    for(titr=_textureGlyphQuadMap.begin();
1901        titr!=_textureGlyphQuadMap.end();
1902        ++titr)
1903    {
1904        // need to set the texture here...
1905        state.applyTextureAttribute(0,titr->first.get());
1906
1907        const GlyphQuads& glyphquad = titr->second;
1908
1909        unsigned int backdrop_index;
1910        unsigned int max_backdrop_index;
1911        if(_backdropType == OUTLINE)
1912        {
1913            backdrop_index = 0;
1914            max_backdrop_index = 8;
1915        }
1916        else
1917        {
1918            backdrop_index = _backdropType;
1919            max_backdrop_index = _backdropType+1;
1920        }
1921
1922        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1923        state.disableColorPointer();
1924
1925        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1926        {
1927            const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1928            if (!transformedBackdropCoords.empty())
1929            {
1930                state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1931                state.drawQuads(0,transformedBackdropCoords.size());
1932            }
1933        }
1934
1935        // Draw the foreground text
1936        const GlyphQuads::Coords3& transformedCoords = glyphquad._transformedCoords[contextID];
1937        if (!transformedCoords.empty())
1938        {
1939            state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedCoords.front()));
1940            state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1941            state.drawQuads(0,transformedCoords.size());
1942        }
1943    }
1944
1945
1946    // disable the depth buffer
1947//    glDisable(GL_DEPTH_TEST);
1948//    glDepthMask(GL_FALSE);
1949//    glDepthMask(GL_TRUE);
1950//    glDepthFunc(GL_ALWAYS);
1951
1952    // Set the stencil function to pass when the stencil is 1
1953    // Bug: This call seems to have no effect. Try changing to NOTEQUAL
1954    // and see the exact same results.
1955    glStencilFunc(GL_EQUAL, 1, 1);
1956
1957    // disable writing to the stencil buffer
1958    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1959    glStencilMask(GL_FALSE);
1960
1961    // Re-enable writing to the color buffer so we can see the results
1962    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1963
1964
1965    // Draw all the text again
1966
1967    for(titr=_textureGlyphQuadMap.begin();
1968        titr!=_textureGlyphQuadMap.end();
1969        ++titr)
1970    {
1971        // need to set the texture here...
1972        state.applyTextureAttribute(0,titr->first.get());
1973
1974        const GlyphQuads& glyphquad = titr->second;
1975
1976        unsigned int backdrop_index;
1977        unsigned int max_backdrop_index;
1978        if(_backdropType == OUTLINE)
1979        {
1980            backdrop_index = 0;
1981            max_backdrop_index = 8;
1982        }
1983        else
1984        {
1985            backdrop_index = _backdropType;
1986            max_backdrop_index = _backdropType+1;
1987        }
1988
1989        state.setTexCoordPointer( 0, 2, GL_FLOAT, 0, &(glyphquad._texcoords.front()));
1990        state.disableColorPointer();
1991        state.Color(_backdropColor.r(),_backdropColor.g(),_backdropColor.b(),_backdropColor.a());
1992
1993        for( ; backdrop_index < max_backdrop_index; backdrop_index++)
1994        {
1995            const GlyphQuads::Coords3& transformedBackdropCoords = glyphquad._transformedBackdropCoords[backdrop_index][contextID];
1996            if (!transformedBackdropCoords.empty())
1997            {
1998                state.setVertexPointer( 3, GL_FLOAT, 0, &(transformedBackdropCoords.front()));
1999                state.drawQuads(0,transformedBackdropCoords.size());
2000            }
2001        }
2002
2003        drawForegroundText(state, glyphquad, colorMultiplier);
2004    }
2005
2006    glPopAttrib();
2007#else
2008    OSG_NOTICE<<"Warning: Text::renderWithStencilBuffer(..) not implemented."<<std::endl;
2009#endif
2010}
Note: See TracBrowser for help on using the browser.