Moved TextNode into osgText.
Cleaned up freetype plugin so it no longer does tesselation - instead Glyph and TextNode do this.
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
#this file is automatically generated
|
||||
|
||||
SET(TARGET_H
|
||||
GlyphGeometry.h
|
||||
TextNode.h
|
||||
)
|
||||
|
||||
SET(TARGET_SRC
|
||||
GlyphGeometry.cpp
|
||||
TextNode.cpp
|
||||
osgtext3D_orig.cpp
|
||||
osgtext3D_test.cpp
|
||||
osgtext3D.cpp
|
||||
|
||||
@@ -35,32 +35,48 @@ public:
|
||||
typedef std::pair<unsigned int, unsigned int> Segment;
|
||||
typedef std::vector<Segment> Segments;
|
||||
osg::ref_ptr<osg::Vec3Array> _vertices;
|
||||
unsigned int _start;
|
||||
unsigned int _count;
|
||||
osg::ref_ptr<osg::DrawElementsUShort> _elements;
|
||||
Segments _segments;
|
||||
|
||||
Boundary(osg::Vec3Array* vertices, unsigned int start, unsigned int count)
|
||||
Boundary(osg::Vec3Array* vertices, osg::PrimitiveSet* primitiveSet)
|
||||
{
|
||||
_vertices = vertices;
|
||||
_start = start;
|
||||
_count = count;
|
||||
|
||||
if ((*_vertices)[start]==(*_vertices)[start+count-1])
|
||||
osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(primitiveSet);
|
||||
if (drawArrays)
|
||||
{
|
||||
// OSG_NOTICE<<"Boundary is a line loop"<<std::endl;
|
||||
set(vertices, drawArrays->getFirst(), drawArrays->getCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<"Boundary is not a line loop"<<std::endl;
|
||||
osg::DrawElementsUShort* elements = dynamic_cast<osg::DrawElementsUShort*>(primitiveSet);
|
||||
if (elements) set(vertices, elements);
|
||||
}
|
||||
}
|
||||
|
||||
_segments.reserve(count-1);
|
||||
for(unsigned int i=start; i<start+count-2; ++i)
|
||||
void set(osg::Vec3Array* vertices, unsigned int start, unsigned int count)
|
||||
{
|
||||
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::POLYGON);
|
||||
for(unsigned int i=start; i<start+count; ++i)
|
||||
{
|
||||
_segments.push_back(Segment(i,i+1));
|
||||
elements->push_back(i);
|
||||
}
|
||||
_segments.push_back(Segment(start+count-2,start));
|
||||
|
||||
set(vertices, elements);
|
||||
}
|
||||
|
||||
void set(osg::Vec3Array* vertices, osg::DrawElementsUShort* elements)
|
||||
{
|
||||
_vertices = vertices;
|
||||
_elements = elements;
|
||||
|
||||
_segments.clear();
|
||||
|
||||
if (elements->empty()) return;
|
||||
|
||||
_segments.reserve(elements->size()-1);
|
||||
for(unsigned int i=0; i<elements->size()-1; ++i)
|
||||
{
|
||||
_segments.push_back(Segment((*elements)[i],(*elements)[i+1]));
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn)
|
||||
@@ -251,7 +267,7 @@ public:
|
||||
face->setName("face");
|
||||
|
||||
// reserve enough space in the vertex array to accomodate the vertices associated with the segments
|
||||
new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _count);
|
||||
new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _elements->size());
|
||||
|
||||
// create vertices
|
||||
unsigned int previous_second = _segments[0].second;
|
||||
@@ -259,10 +275,13 @@ public:
|
||||
unsigned int first = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
if (_segments[0].first != _start)
|
||||
unsigned int start = (*_elements)[0];
|
||||
unsigned int count = _elements->size();
|
||||
|
||||
if (_segments[0].first != start)
|
||||
{
|
||||
//OSG_NOTICE<<"We have pruned from the start"<<std::endl;
|
||||
for(unsigned int j=_start; j<=_segments[0].first;++j)
|
||||
for(unsigned int j=start; j<=_segments[0].first;++j)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
@@ -298,7 +317,7 @@ public:
|
||||
// fill the end of the polygon with repititions of the first index in the polygon to ensure
|
||||
// that the orignal and new boundary polygons have the same number and pairing of indices.
|
||||
// This ensures that the bevel can be created coherently.
|
||||
while(face->size() < _count)
|
||||
while(face->size() < count)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
@@ -313,11 +332,11 @@ public:
|
||||
|
||||
osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
|
||||
bevel->setName("bevel");
|
||||
bevel->reserve(_count*2);
|
||||
for(unsigned int i=0; i<_count; ++i)
|
||||
bevel->reserve(count*2);
|
||||
for(unsigned int i=0; i<count; ++i)
|
||||
{
|
||||
unsigned int vi = new_vertices->size();
|
||||
new_vertices->push_back((*_vertices)[_start+i]);
|
||||
new_vertices->push_back((*_vertices)[(*_elements)[i]]);
|
||||
bevel->push_back(vi);
|
||||
bevel->push_back((*face)[i]);
|
||||
}
|
||||
@@ -328,6 +347,9 @@ public:
|
||||
{
|
||||
if (_segments.empty()) return;
|
||||
|
||||
unsigned int start = (*_elements)[0];
|
||||
unsigned int count = _elements->size();
|
||||
|
||||
if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array(*_vertices));
|
||||
osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
||||
|
||||
@@ -336,7 +358,7 @@ public:
|
||||
face->setName(faceName);
|
||||
|
||||
// reserve enough space in the vertex array to accomodate the vertices associated with the segments
|
||||
new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _count);
|
||||
new_vertices->reserve(new_vertices->size() + _segments.size()+1 + count);
|
||||
|
||||
// create vertices
|
||||
unsigned int previous_second = _segments[0].second;
|
||||
@@ -344,10 +366,10 @@ public:
|
||||
unsigned int first = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
if (_segments[0].first != _start)
|
||||
if (_segments[0].first != start)
|
||||
{
|
||||
//OSG_NOTICE<<"We have pruned from the start"<<std::endl;
|
||||
for(unsigned int j=_start; j<=_segments[0].first;++j)
|
||||
for(unsigned int j=start; j<=_segments[0].first;++j)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
@@ -383,7 +405,7 @@ public:
|
||||
// fill the end of the polygon with repititions of the first index in the polygon to ensure
|
||||
// that the orignal and new boundary polygons have the same number and pairing of indices.
|
||||
// This ensures that the bevel can be created coherently.
|
||||
while(face->size() < _count)
|
||||
while(face->size() < count)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
@@ -396,10 +418,10 @@ public:
|
||||
|
||||
osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
|
||||
bevel->setName(bevelName);
|
||||
bevel->reserve(_count*2);
|
||||
for(unsigned int i=0; i<_count; ++i)
|
||||
bevel->reserve(count*2);
|
||||
for(unsigned int i=0; i<count; ++i)
|
||||
{
|
||||
bevel->push_back(_start+i);
|
||||
bevel->push_back((*_elements)[i]);
|
||||
bevel->push_back((*face)[i]);
|
||||
}
|
||||
geometry->addPrimitiveSet(bevel);
|
||||
@@ -444,24 +466,24 @@ osg::Geometry* computeGlyphGeometry(osgText::Glyph3D* glyph, float bevelThicknes
|
||||
itr != orig_primitives.end();
|
||||
++itr)
|
||||
{
|
||||
osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
|
||||
if (drawArray && drawArray->getMode()==GL_POLYGON)
|
||||
if ((*itr)->getMode()==GL_POLYGON)
|
||||
{
|
||||
Boundary boundaryInner(orig_vertices, drawArray->getFirst(), drawArray->getCount());
|
||||
Boundary boundaryInner(orig_vertices, itr->get());
|
||||
boundaryInner.removeAllSegmentsBelowThickness(bevelThickness);
|
||||
boundaryInner.newAddBoundaryToGeometry(new_geometry, bevelThickness, "face", "bevel");
|
||||
|
||||
Boundary boundaryOuter(orig_vertices, drawArray->getFirst(), drawArray->getCount());
|
||||
Boundary boundaryOuter(orig_vertices, itr->get());
|
||||
boundaryOuter.removeAllSegmentsAboveThickness(-shellThickness);
|
||||
boundaryOuter.newAddBoundaryToGeometry(new_geometry, -shellThickness, "", "shell");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(new_geometry->getVertexArray());
|
||||
|
||||
// need to tessellate the inner boundary
|
||||
{
|
||||
osg::Geometry* face_geometry = new osg::Geometry;
|
||||
osg::ref_ptr<osg::Geometry> face_geometry = new osg::Geometry;
|
||||
face_geometry->setVertexArray(vertices);
|
||||
|
||||
osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
|
||||
@@ -510,6 +532,123 @@ osg::Geometry* computeGlyphGeometry(osgText::Glyph3D* glyph, float bevelThicknes
|
||||
return new_geometry.release();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// computeTextGeometry
|
||||
//
|
||||
osg::Geometry* computeTextGeometry(osgText::Glyph3D* glyph, float width)
|
||||
{
|
||||
osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
|
||||
osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();
|
||||
|
||||
osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
|
||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array((*orig_vertices));
|
||||
|
||||
text_geometry->setVertexArray(vertices.get());
|
||||
text_geometry->setPrimitiveSetList(orig_primitives);
|
||||
|
||||
osgUtil::Tessellator ts;
|
||||
ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
|
||||
ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
|
||||
ts.retessellatePolygons(*text_geometry);
|
||||
|
||||
osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
|
||||
text_geometry->accept(ctif);
|
||||
CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
|
||||
|
||||
// remove the previous primitive sets
|
||||
text_geometry->getPrimitiveSetList().clear();
|
||||
|
||||
if (indices.empty()) return 0;
|
||||
|
||||
|
||||
// create a front face using triangle indices
|
||||
osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
|
||||
frontFace->setName("face");
|
||||
text_geometry->addPrimitiveSet(frontFace);
|
||||
for(unsigned int i=0; i<indices.size();++i)
|
||||
{
|
||||
frontFace->push_back(indices[i]);
|
||||
}
|
||||
|
||||
typedef std::vector<unsigned int> Indices;
|
||||
const unsigned int NULL_VALUE = UINT_MAX;
|
||||
Indices back_indices;
|
||||
back_indices.resize(vertices->size(), NULL_VALUE);
|
||||
osg::Vec3 forward(0,0,-width);
|
||||
|
||||
// build up the vertices primitives for the back face, and record the indices
|
||||
// for later use, and to ensure sharing of vertices in the face primitive set
|
||||
// the order of the triangle indices are flipped to make sure that the triangles are back face
|
||||
osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
|
||||
text_geometry->addPrimitiveSet(backFace);
|
||||
for(unsigned int i=0; i<indices.size()-2;)
|
||||
{
|
||||
unsigned int p1 = indices[i++];
|
||||
unsigned int p2 = indices[i++];
|
||||
unsigned int p3 = indices[i++];
|
||||
if (back_indices[p1]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p1] = vertices->size();
|
||||
vertices->push_back((*vertices)[p1]+forward);
|
||||
}
|
||||
|
||||
if (back_indices[p2]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p2] = vertices->size();
|
||||
vertices->push_back((*vertices)[p2]+forward);
|
||||
}
|
||||
|
||||
if (back_indices[p3]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p3] = vertices->size();
|
||||
vertices->push_back((*vertices)[p3]+forward);
|
||||
}
|
||||
|
||||
backFace->push_back(back_indices[p1]);
|
||||
backFace->push_back(back_indices[p3]);
|
||||
backFace->push_back(back_indices[p2]);
|
||||
}
|
||||
|
||||
unsigned int orig_size = orig_vertices->size();
|
||||
Indices frontedge_indices, backedge_indices;
|
||||
frontedge_indices.resize(orig_size, NULL_VALUE);
|
||||
backedge_indices.resize(orig_size, NULL_VALUE);
|
||||
|
||||
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
|
||||
itr != orig_primitives.end();
|
||||
++itr)
|
||||
{
|
||||
osg::DrawElementsUShort* edging = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
|
||||
text_geometry->addPrimitiveSet(edging);
|
||||
|
||||
osg::DrawElementsUShort* elements = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
|
||||
if (elements)
|
||||
{
|
||||
for(unsigned int i=0; i<elements->size(); ++i)
|
||||
{
|
||||
unsigned int ei = (*elements)[i];
|
||||
if (frontedge_indices[ei]==NULL_VALUE)
|
||||
{
|
||||
frontedge_indices[ei] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[ei]);
|
||||
}
|
||||
if (backedge_indices[ei]==NULL_VALUE)
|
||||
{
|
||||
backedge_indices[ei] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[ei]+forward);
|
||||
}
|
||||
|
||||
edging->push_back(backedge_indices[ei]);
|
||||
edging->push_back(frontedge_indices[ei]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text_geometry.release();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// computeTextGeometry
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace osgText
|
||||
|
||||
extern osg::Geometry* computeGlyphGeometry(osgText::Glyph3D* glyph, float bevelThickness, float shellThickness);
|
||||
|
||||
extern osg::Geometry* computeTextGeometry(osgText::Glyph3D* glyph, float width);
|
||||
|
||||
extern osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, const Bevel& profile, float width);
|
||||
|
||||
extern osg::Geometry* computeShellGeometry(osg::Geometry* glyphGeometry, const Bevel& profile, float width);
|
||||
|
||||
@@ -335,6 +335,14 @@ void TextTechnique::addCharacter(const osg::Vec3& position, const osg::Vec3& siz
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(glyph, width);
|
||||
if (textGeometry.valid()) geode->addDrawable(textGeometry.get());
|
||||
|
||||
// create the normals
|
||||
if (smooth && textGeometry.valid())
|
||||
{
|
||||
osgUtil::SmoothingVisitor::smooth(*textGeometry, osg::DegreesToRadians(creaseAngle));
|
||||
}
|
||||
}
|
||||
|
||||
transform->addChild(geode.get());
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <osg/TriangleIndexFunctor>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osgUtil/SmoothingVisitor>
|
||||
#include <osgText/Font3D>
|
||||
#include <osgDB/WriteFile>
|
||||
#include <osgGA/StateSetManipulator>
|
||||
#include <osgUtil/Tessellator>
|
||||
@@ -31,113 +30,11 @@
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
#include <osg/io_utils>
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
#include "TextNode.h"
|
||||
#include <osgText/TextNode>
|
||||
|
||||
extern int main_orig(int, char**);
|
||||
extern int main_test(int, char**);
|
||||
|
||||
int main_experimental(osg::ArgumentParser& arguments)
|
||||
{
|
||||
std::string fontFile("arial.ttf");
|
||||
while(arguments.read("-f",fontFile)) {}
|
||||
|
||||
std::string word("This is a simple test");
|
||||
|
||||
while(arguments.read("--ascii"))
|
||||
{
|
||||
word.clear();
|
||||
for(unsigned int c=' '; c<=127;++c)
|
||||
{
|
||||
word.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
while(arguments.read("-w",word)) {}
|
||||
|
||||
osg::ref_ptr<osgText::Font> font = osgText::readFontFile(fontFile);
|
||||
if (!font) return 1;
|
||||
OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
|
||||
|
||||
bool useTessellator = true;
|
||||
while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
|
||||
while(arguments.read("--no-tessellate")) { useTessellator = false; }
|
||||
|
||||
float thickness = 5.0;
|
||||
while(arguments.read("--thickness",thickness)) {}
|
||||
|
||||
float width = 20.0;
|
||||
while(arguments.read("--width",width)) {}
|
||||
|
||||
float creaseAngle = 30.0f;
|
||||
while(arguments.read("--crease-angle",creaseAngle)) {}
|
||||
|
||||
OSG_NOTICE<<"creaseAngle="<<creaseAngle<<std::endl;
|
||||
|
||||
osgText::Bevel profile;
|
||||
float ratio = 0.5;
|
||||
while(arguments.read("--rounded",ratio)) { profile.roundedBevel(ratio); }
|
||||
while(arguments.read("--rounded2",ratio)) { profile.roundedBevel2(ratio); }
|
||||
while(arguments.read("--flat",ratio)) { profile.flatBevel(ratio); }
|
||||
|
||||
bool outline = false;
|
||||
while(arguments.read("--outline")) { outline = true; }
|
||||
while(arguments.read("--no-outline")) { outline = false; }
|
||||
|
||||
bool smooth = true;
|
||||
while(arguments.read("--flat-shaded")) { smooth = false; }
|
||||
while(arguments.read("--smooth")) { smooth = false; }
|
||||
|
||||
unsigned int numSamples = 10;
|
||||
while(arguments.read("--samples", numSamples)) {}
|
||||
font->setNumberCurveSamples(numSamples);
|
||||
|
||||
profile.print(std::cout);
|
||||
|
||||
|
||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||
osg::Vec3 position;
|
||||
|
||||
for(unsigned int i=0; i<word.size(); ++i)
|
||||
{
|
||||
osg::ref_ptr<osgText::Glyph3D> glyph = font->getGlyph3D(word[i]);
|
||||
if (!glyph) return 1;
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
|
||||
transform->setPosition(position);
|
||||
transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
|
||||
|
||||
position.x() += glyph->getHorizontalWidth();
|
||||
|
||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
|
||||
|
||||
osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph.get(), thickness, width);
|
||||
osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(glyphGeometry.get(), profile, width);
|
||||
osg::ref_ptr<osg::Geometry> shellGeometry = outline ? osgText::computeShellGeometry(glyphGeometry.get(), profile, width) : 0;
|
||||
if (textGeometry.valid()) geode->addDrawable(textGeometry.get());
|
||||
if (shellGeometry.valid()) geode->addDrawable(shellGeometry.get());
|
||||
|
||||
// create the normals
|
||||
if (smooth && textGeometry.valid())
|
||||
{
|
||||
osgUtil::SmoothingVisitor::smooth(*textGeometry, osg::DegreesToRadians(creaseAngle));
|
||||
}
|
||||
|
||||
transform->addChild(geode.get());
|
||||
|
||||
group->addChild(transform.get());
|
||||
}
|
||||
|
||||
std::string filename;
|
||||
if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
|
||||
|
||||
osgViewer::Viewer viewer(arguments);
|
||||
viewer.setSceneData(group.get());
|
||||
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
|
||||
viewer.addEventHandler(new osgViewer::StatsHandler);
|
||||
return viewer.run();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
osg::ArgumentParser arguments(&argc, argv);
|
||||
@@ -150,10 +47,6 @@ int main(int argc, char** argv)
|
||||
{
|
||||
return main_orig(argc,argv);
|
||||
}
|
||||
else if (arguments.read("--exp"))
|
||||
{
|
||||
return main_experimental(arguments);
|
||||
}
|
||||
|
||||
osgViewer::Viewer viewer(arguments);
|
||||
|
||||
@@ -184,6 +77,10 @@ int main(int argc, char** argv)
|
||||
|
||||
style->setBevel(bevel);
|
||||
|
||||
// set up outline.
|
||||
while(arguments.read("--outline",r)) { style->setOutlineRatio(r); }
|
||||
|
||||
|
||||
osgText::TextNode* text = new osgText::TextNode;
|
||||
text->setText(word);
|
||||
text->setFont(font.get());
|
||||
|
||||
Reference in New Issue
Block a user