Refactored 3d text geometry creation code so that the text is all placed in one osg::Geometry.
This commit is contained in:
parent
7eb172277f
commit
f3617062a0
@ -1,6 +1,11 @@
|
||||
#this file is automatically generated
|
||||
|
||||
SET(TARGET_H
|
||||
GlyphGeometry.h
|
||||
)
|
||||
|
||||
SET(TARGET_SRC
|
||||
GlyphGeometry.cpp
|
||||
osgtext3D_orig.cpp
|
||||
osgtext3D_test.cpp
|
||||
osgtext3D.cpp
|
||||
|
788
examples/osgtext3D/GlyphGeometry.cpp
Normal file
788
examples/osgtext3D/GlyphGeometry.cpp
Normal file
@ -0,0 +1,788 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
#include <osg/io_utils>
|
||||
#include <osg/TriangleIndexFunctor>
|
||||
#include <osg/LineWidth>
|
||||
#include <osgUtil/Tessellator>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
namespace osgText
|
||||
{
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Boundary
|
||||
//
|
||||
class Boundary
|
||||
{
|
||||
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;
|
||||
Segments _segments;
|
||||
|
||||
Boundary(osg::Vec3Array* vertices, unsigned int start, unsigned int count)
|
||||
{
|
||||
_vertices = vertices;
|
||||
_start = start;
|
||||
_count = count;
|
||||
|
||||
if ((*_vertices)[start]==(*_vertices)[start+count-1])
|
||||
{
|
||||
// OSG_NOTICE<<"Boundary is a line loop"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<"Boundary is not a line loop"<<std::endl;
|
||||
}
|
||||
|
||||
_segments.reserve(count-1);
|
||||
for(unsigned int i=start; i<start+count-2; ++i)
|
||||
{
|
||||
_segments.push_back(Segment(i,i+1));
|
||||
}
|
||||
_segments.push_back(Segment(start+count-2,start));
|
||||
|
||||
}
|
||||
|
||||
osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn)
|
||||
{
|
||||
float denominator = ( cn.x() * an.y() - cn.y() * an.x());
|
||||
if (denominator==0.0f)
|
||||
{
|
||||
//OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl;
|
||||
// line segments must be parallel.
|
||||
return (a+c)*0.5f;
|
||||
}
|
||||
|
||||
float t = ((a.x()-c.x())*an.y() - (a.y()-c.y())*an.x()) / denominator;
|
||||
return c + cn*t;
|
||||
}
|
||||
|
||||
osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
|
||||
{
|
||||
return computeRayIntersectionPoint(a, b-a, c, d-c);
|
||||
}
|
||||
|
||||
osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
|
||||
{
|
||||
osg::Vec2 ab(a.x()-b.x(), a.y()-b.y());
|
||||
osg::Vec2 dc(d.x()-c.x(), d.y()-c.y());
|
||||
/*float length_ab =*/ ab.normalize();
|
||||
/*float length_dc =*/ dc.normalize();
|
||||
|
||||
float e = dc.y() - ab.y();
|
||||
float f = ab.x() - dc.x();
|
||||
float denominator = sqrtf(e*e + f*f);
|
||||
float nx = e / denominator;
|
||||
float ny = f / denominator;
|
||||
if (( ab.x()*ny - ab.y()*nx) > 0.0f)
|
||||
{
|
||||
// OSG_NOTICE<<" computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" no need to swap"<<std::endl;
|
||||
return osg::Vec3(nx,ny,0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<" computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" need to swap!!!"<<std::endl;
|
||||
return osg::Vec3(-nx,-ny,0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
float computeBisectorIntersectorThickness(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d, const osg::Vec3& e, const osg::Vec3& f)
|
||||
{
|
||||
osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
|
||||
osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
|
||||
osg::Vec3 intersection_cdef = computeIntersectionPoint(c,d,e,f);
|
||||
osg::Vec3 bisector_cdef = computeBisectorNormal(c,d,e,f);
|
||||
if (bisector_abcd==bisector_cdef)
|
||||
{
|
||||
//OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
|
||||
//OSG_NOTICE<<" bisectors parallel, thickness = "<<FLT_MAX<<std::endl;
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
osg::Vec3 bisector_intersection = computeRayIntersectionPoint(intersection_abcd,bisector_abcd, intersection_cdef, bisector_cdef);
|
||||
osg::Vec3 normal(d.y()-c.y(), c.x()-d.x(), 0.0);
|
||||
float cd_length = normal.normalize();
|
||||
if (cd_length==0)
|
||||
{
|
||||
//OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
|
||||
//OSG_NOTICE<<" segment length==0, thickness = "<<FLT_MAX<<std::endl;
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
float thickness = (bisector_intersection - c) * normal;
|
||||
#if 0
|
||||
OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
|
||||
OSG_NOTICE<<" bisector_abcd = "<<bisector_abcd<<", bisector_cdef="<<bisector_cdef<<std::endl;
|
||||
OSG_NOTICE<<" bisector_intersection = "<<bisector_intersection<<", thickness = "<<thickness<<std::endl;
|
||||
#endif
|
||||
return thickness;
|
||||
}
|
||||
|
||||
|
||||
float computeThickness(unsigned int i)
|
||||
{
|
||||
Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
|
||||
Segment& seg_target = _segments[ (i) % _segments.size() ];
|
||||
Segment& seg_after = _segments[ (i+1) % _segments.size() ];
|
||||
return computeBisectorIntersectorThickness(
|
||||
(*_vertices)[seg_before.first], (*_vertices)[seg_before.second],
|
||||
(*_vertices)[seg_target.first], (*_vertices)[seg_target.second],
|
||||
(*_vertices)[seg_after.first], (*_vertices)[seg_after.second]);
|
||||
}
|
||||
|
||||
void computeAllThickness()
|
||||
{
|
||||
for(unsigned int i=0; i<_segments.size(); ++i)
|
||||
{
|
||||
computeThickness(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool findMinThickness(unsigned int& minThickness_i, float& minThickness)
|
||||
{
|
||||
minThickness_i = _segments.size();
|
||||
for(unsigned int i=0; i<_segments.size(); ++i)
|
||||
{
|
||||
float thickness = computeThickness(i);
|
||||
if (thickness>0.0 && thickness < minThickness)
|
||||
{
|
||||
minThickness = thickness;
|
||||
minThickness_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
return minThickness_i != _segments.size();
|
||||
}
|
||||
|
||||
void removeAllSegmentsBelowThickness(float targetThickness)
|
||||
{
|
||||
// OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
|
||||
for(;;)
|
||||
{
|
||||
unsigned int minThickness_i = _segments.size();
|
||||
float minThickness = targetThickness;
|
||||
if (!findMinThickness(minThickness_i,minThickness)) break;
|
||||
|
||||
// OSG_NOTICE<<" removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
|
||||
_segments.erase(_segments.begin()+minThickness_i);
|
||||
}
|
||||
}
|
||||
|
||||
bool findMaxThickness(unsigned int& maxThickness_i, float& maxThickness)
|
||||
{
|
||||
maxThickness_i = _segments.size();
|
||||
for(unsigned int i=0; i<_segments.size(); ++i)
|
||||
{
|
||||
float thickness = computeThickness(i);
|
||||
if (thickness<0.0 && thickness > maxThickness)
|
||||
{
|
||||
maxThickness = thickness;
|
||||
maxThickness_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxThickness_i != _segments.size();
|
||||
}
|
||||
|
||||
|
||||
void removeAllSegmentsAboveThickness(float targetThickness)
|
||||
{
|
||||
// OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
|
||||
for(;;)
|
||||
{
|
||||
unsigned int maxThickness_i = _segments.size();
|
||||
float maxThickness = targetThickness;
|
||||
if (!findMaxThickness(maxThickness_i,maxThickness)) break;
|
||||
|
||||
// OSG_NOTICE<<" removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
|
||||
_segments.erase(_segments.begin()+maxThickness_i);
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec3 computeBisectorPoint(unsigned int i, float targetThickness)
|
||||
{
|
||||
Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
|
||||
Segment& seg_target = _segments[ (i) % _segments.size() ];
|
||||
osg::Vec3& a = (*_vertices)[seg_before.first];
|
||||
osg::Vec3& b = (*_vertices)[seg_before.second];
|
||||
osg::Vec3& c = (*_vertices)[seg_target.first];
|
||||
osg::Vec3& d = (*_vertices)[seg_target.second];
|
||||
osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
|
||||
osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
|
||||
osg::Vec3 ab_sidevector(b.y()-a.y(), a.x()-b.x(), 0.0);
|
||||
ab_sidevector.normalize();
|
||||
float scale_factor = 1.0/ (bisector_abcd*ab_sidevector);
|
||||
osg::Vec3 new_vertex = intersection_abcd + bisector_abcd*(scale_factor*targetThickness);
|
||||
|
||||
// OSG_NOTICE<<"bisector_abcd = "<<bisector_abcd<<", ab_sidevector="<<ab_sidevector<<", b-a="<<b-a<<", scale_factor="<<scale_factor<<std::endl;
|
||||
return new_vertex;
|
||||
}
|
||||
|
||||
void addBoundaryToGeometry(osg::Geometry* geometry, float targetThickness, bool requireFace)
|
||||
{
|
||||
if (_segments.empty()) return;
|
||||
|
||||
if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array);
|
||||
osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
||||
|
||||
// allocate the primitive set to store the face geometry
|
||||
osg::ref_ptr<osg::DrawElementsUShort> face = new osg::DrawElementsUShort(GL_POLYGON);
|
||||
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);
|
||||
|
||||
// create vertices
|
||||
unsigned int previous_second = _segments[0].second;
|
||||
osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness);
|
||||
unsigned int first = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
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)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
|
||||
|
||||
for(unsigned int i=1; i<_segments.size(); ++i)
|
||||
{
|
||||
newPoint = computeBisectorPoint(i, targetThickness);
|
||||
unsigned int vi = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
if (previous_second != _segments[i].first)
|
||||
{
|
||||
//OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
|
||||
for(unsigned int j=previous_second; j<=_segments[i].first;++j)
|
||||
{
|
||||
face->push_back(vi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
face->push_back(vi);
|
||||
}
|
||||
|
||||
previous_second = _segments[i].second;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
|
||||
|
||||
if (requireFace)
|
||||
{
|
||||
// add face primitive set for polygon
|
||||
geometry->addPrimitiveSet(face.get());
|
||||
}
|
||||
|
||||
|
||||
osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
|
||||
bevel->setName("bevel");
|
||||
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]);
|
||||
bevel->push_back(vi);
|
||||
bevel->push_back((*face)[i]);
|
||||
}
|
||||
geometry->addPrimitiveSet(bevel);
|
||||
}
|
||||
|
||||
void newAddBoundaryToGeometry(osg::Geometry* geometry, float targetThickness, const std::string& faceName, const std::string& bevelName)
|
||||
{
|
||||
if (_segments.empty()) return;
|
||||
|
||||
if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array(*_vertices));
|
||||
osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
||||
|
||||
// allocate the primitive set to store the face geometry
|
||||
osg::ref_ptr<osg::DrawElementsUShort> face = new osg::DrawElementsUShort(GL_POLYGON);
|
||||
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);
|
||||
|
||||
// create vertices
|
||||
unsigned int previous_second = _segments[0].second;
|
||||
osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness);
|
||||
unsigned int first = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
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)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
|
||||
|
||||
for(unsigned int i=1; i<_segments.size(); ++i)
|
||||
{
|
||||
newPoint = computeBisectorPoint(i, targetThickness);
|
||||
unsigned int vi = new_vertices->size();
|
||||
new_vertices->push_back(newPoint);
|
||||
|
||||
if (previous_second != _segments[i].first)
|
||||
{
|
||||
//OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
|
||||
for(unsigned int j=previous_second; j<=_segments[i].first;++j)
|
||||
{
|
||||
face->push_back(vi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
face->push_back(vi);
|
||||
}
|
||||
|
||||
previous_second = _segments[i].second;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
face->push_back(first);
|
||||
}
|
||||
|
||||
if (!faceName.empty())
|
||||
{
|
||||
// add face primitive set for polygon
|
||||
geometry->addPrimitiveSet(face.get());
|
||||
}
|
||||
|
||||
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->push_back(_start+i);
|
||||
bevel->push_back((*face)[i]);
|
||||
}
|
||||
geometry->addPrimitiveSet(bevel);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BevelProfile
|
||||
//
|
||||
BevelProfile::BevelProfile()
|
||||
{
|
||||
flatBevel();
|
||||
}
|
||||
|
||||
void BevelProfile::flatBevel(float width)
|
||||
{
|
||||
_vertices.clear();
|
||||
|
||||
if (width>0.5f) width = 0.5f;
|
||||
|
||||
_vertices.push_back(osg::Vec2(0.0f,0.0f));
|
||||
|
||||
_vertices.push_back(osg::Vec2(width,1.0f));
|
||||
|
||||
if (width<0.5f) _vertices.push_back(osg::Vec2(1-width,1.0f));
|
||||
|
||||
_vertices.push_back(osg::Vec2(1.0f,0.0f));
|
||||
}
|
||||
|
||||
void BevelProfile::roundedBevel(float width, unsigned int numSteps)
|
||||
{
|
||||
_vertices.clear();
|
||||
|
||||
if (width>0.5f) width = 0.5f;
|
||||
|
||||
unsigned int i = 0;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, sinf(angle)) );
|
||||
}
|
||||
|
||||
// start the second half one into the curve if the width is half way across
|
||||
i = width<0.5f ? 0 : 1;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, sin(angle)) );
|
||||
}
|
||||
}
|
||||
|
||||
void BevelProfile::roundedBevel2(float width, unsigned int numSteps)
|
||||
{
|
||||
_vertices.clear();
|
||||
|
||||
if (width>0.5f) width = 0.5f;
|
||||
|
||||
float h = 0.1f;
|
||||
float r = 1.0f-h;
|
||||
|
||||
_vertices.push_back(osg::Vec2(0.0,0.0));
|
||||
|
||||
unsigned int i = 0;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, h + sinf(angle)*r) );
|
||||
}
|
||||
|
||||
// start the second half one into the curve if the width is half way across
|
||||
i = width<0.5f ? 0 : 1;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, h + sin(angle)*r) );
|
||||
}
|
||||
|
||||
_vertices.push_back(osg::Vec2(1.0,0.0));
|
||||
|
||||
}
|
||||
|
||||
void BevelProfile::print(std::ostream& fout)
|
||||
{
|
||||
OSG_NOTICE<<"print bevel"<<std::endl;
|
||||
for(Vertices::iterator itr = _vertices.begin();
|
||||
itr != _vertices.end();
|
||||
++itr)
|
||||
{
|
||||
OSG_NOTICE<<" "<<*itr<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// computeGlyphGeometry
|
||||
//
|
||||
struct CollectTriangleIndicesFunctor
|
||||
{
|
||||
CollectTriangleIndicesFunctor() {}
|
||||
|
||||
typedef std::vector<unsigned int> Indices;
|
||||
Indices _indices;
|
||||
|
||||
void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
|
||||
{
|
||||
if (p1==p2 || p2==p3 || p1==p3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_indices.push_back(p1);
|
||||
_indices.push_back(p3);
|
||||
_indices.push_back(p2);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
osg::Geometry* computeGlyphGeometry(osgText::Font3D::Glyph3D* glyph, float bevelThickness, float shellThickness)
|
||||
{
|
||||
osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
|
||||
osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();
|
||||
|
||||
osg::ref_ptr<osg::Geometry> new_geometry = new osg::Geometry;
|
||||
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
|
||||
itr != orig_primitives.end();
|
||||
++itr)
|
||||
{
|
||||
osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
|
||||
if (drawArray && drawArray->getMode()==GL_POLYGON)
|
||||
{
|
||||
Boundary boundaryInner(orig_vertices, drawArray->getFirst(), drawArray->getCount());
|
||||
boundaryInner.removeAllSegmentsBelowThickness(bevelThickness);
|
||||
boundaryInner.newAddBoundaryToGeometry(new_geometry, bevelThickness, "face", "bevel");
|
||||
|
||||
Boundary boundaryOuter(orig_vertices, drawArray->getFirst(), drawArray->getCount());
|
||||
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;
|
||||
face_geometry->setVertexArray(vertices);
|
||||
|
||||
osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
|
||||
|
||||
osg::Geometry::PrimitiveSetList primitiveSets;
|
||||
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = new_geometry->getPrimitiveSetList().begin();
|
||||
itr != new_geometry->getPrimitiveSetList().end();
|
||||
++itr)
|
||||
{
|
||||
osg::PrimitiveSet* prim = itr->get();
|
||||
if (prim->getName()=="face") face_geometry->addPrimitiveSet(copyop(*itr));
|
||||
else primitiveSets.push_back(prim);
|
||||
}
|
||||
|
||||
osgUtil::Tessellator ts;
|
||||
ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
|
||||
ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
|
||||
ts.retessellatePolygons(*face_geometry);
|
||||
|
||||
osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
|
||||
face_geometry->accept(ctif);
|
||||
CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
|
||||
|
||||
// remove the previous primitive sets
|
||||
new_geometry->getPrimitiveSetList().clear();
|
||||
|
||||
// create a front face using triangle indices
|
||||
osg::DrawElementsUShort* front_face = new osg::DrawElementsUShort(GL_TRIANGLES);
|
||||
front_face->setName("face");
|
||||
new_geometry->addPrimitiveSet(front_face);
|
||||
for(unsigned int i=0; i<indices.size();++i)
|
||||
{
|
||||
front_face->push_back(indices[i]);
|
||||
}
|
||||
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = primitiveSets.begin();
|
||||
itr != primitiveSets.end();
|
||||
++itr)
|
||||
{
|
||||
osg::PrimitiveSet* prim = itr->get();
|
||||
if (prim->getName()!="face") new_geometry->addPrimitiveSet(prim);
|
||||
}
|
||||
}
|
||||
|
||||
return new_geometry.release();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// computeTextGeometry
|
||||
//
|
||||
osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, BevelProfile& profile, float width)
|
||||
{
|
||||
osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(glyphGeometry->getVertexArray());
|
||||
if (!orig_vertices)
|
||||
{
|
||||
OSG_NOTICE<<"computeTextGeometry(..): No vertices on glyphGeometry."<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
|
||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
||||
text_geometry->setVertexArray(vertices.get());
|
||||
|
||||
typedef std::vector<unsigned int> Indices;
|
||||
const unsigned int NULL_VALUE = UINT_MAX;
|
||||
Indices front_indices, back_indices;
|
||||
front_indices.resize(orig_vertices->size(), NULL_VALUE);
|
||||
back_indices.resize(orig_vertices->size(), NULL_VALUE);
|
||||
|
||||
osg::DrawElementsUShort* face = 0;
|
||||
osg::Geometry::PrimitiveSetList bevelPrimitiveSets;
|
||||
osg::Vec3 forward(0,0,-width);
|
||||
|
||||
// collect bevels and face primitive sets
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = glyphGeometry->getPrimitiveSetList().begin();
|
||||
itr != glyphGeometry->getPrimitiveSetList().end();
|
||||
++itr)
|
||||
{
|
||||
osg::PrimitiveSet* prim = itr->get();
|
||||
if (prim->getName()=="face") face = dynamic_cast<osg::DrawElementsUShort*>(prim);
|
||||
else if (prim->getName()=="bevel") bevelPrimitiveSets.push_back(prim);
|
||||
}
|
||||
|
||||
// if we don't have a face we can't create any 3d text
|
||||
if (!face) return 0;
|
||||
|
||||
// build up the vertices primitives for the front face, and record the indices
|
||||
// for later use, and to ensure sharing of vertices in the face primitive set
|
||||
osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
|
||||
text_geometry->addPrimitiveSet(frontFace);
|
||||
for(unsigned int i=0; i<face->size();)
|
||||
{
|
||||
unsigned int pi = (*face)[i++];
|
||||
if (front_indices[pi]==NULL_VALUE)
|
||||
{
|
||||
front_indices[pi] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[pi]);
|
||||
}
|
||||
frontFace->push_back(front_indices[pi]);
|
||||
}
|
||||
|
||||
|
||||
// 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<face->size()-2;)
|
||||
{
|
||||
unsigned int p1 = (*face)[i++];
|
||||
unsigned int p2 = (*face)[i++];
|
||||
unsigned int p3 = (*face)[i++];
|
||||
if (back_indices[p1]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p1] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[p1]+forward);
|
||||
}
|
||||
|
||||
if (back_indices[p2]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p2] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[p2]+forward);
|
||||
}
|
||||
|
||||
if (back_indices[p3]==NULL_VALUE)
|
||||
{
|
||||
back_indices[p3] = vertices->size();
|
||||
vertices->push_back((*orig_vertices)[p3]+forward);
|
||||
}
|
||||
|
||||
backFace->push_back(back_indices[p1]);
|
||||
backFace->push_back(back_indices[p3]);
|
||||
backFace->push_back(back_indices[p2]);
|
||||
}
|
||||
|
||||
bool shareVerticesWithFaces = true;
|
||||
|
||||
// now build up the bevel
|
||||
for(osg::Geometry::PrimitiveSetList::iterator itr = bevelPrimitiveSets.begin();
|
||||
itr != bevelPrimitiveSets.end();
|
||||
++itr)
|
||||
{
|
||||
osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
|
||||
if (!bevel) continue;
|
||||
|
||||
unsigned int no_vertices_on_boundary = bevel->size()/2;
|
||||
|
||||
osgText::BevelProfile::Vertices& profileVertices = profile.getVertices();
|
||||
unsigned int no_vertices_on_bevel = profileVertices.size();
|
||||
|
||||
Indices bevelIndices;
|
||||
bevelIndices.resize(no_vertices_on_boundary*no_vertices_on_bevel, NULL_VALUE);
|
||||
|
||||
// populate vertices
|
||||
for(unsigned int i=0; i<no_vertices_on_boundary; ++i)
|
||||
{
|
||||
unsigned int topi = (*bevel)[i*2];
|
||||
unsigned int basei = (*bevel)[i*2+1];
|
||||
|
||||
osg::Vec3& top_vertex = (*orig_vertices)[ topi ];
|
||||
osg::Vec3& base_vertex = (*orig_vertices)[ basei ];
|
||||
osg::Vec3 up = top_vertex-base_vertex;
|
||||
|
||||
if (shareVerticesWithFaces)
|
||||
{
|
||||
if (front_indices[basei]==NULL_VALUE)
|
||||
{
|
||||
front_indices[basei] = vertices->size();
|
||||
vertices->push_back(base_vertex);
|
||||
}
|
||||
|
||||
bevelIndices[i*no_vertices_on_bevel + 0] = front_indices[basei];
|
||||
|
||||
for(unsigned int j=1; j<no_vertices_on_bevel-1; ++j)
|
||||
{
|
||||
const osg::Vec2& pv = profileVertices[j];
|
||||
osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
|
||||
bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
|
||||
vertices->push_back(pos);
|
||||
}
|
||||
|
||||
if (back_indices[basei]==NULL_VALUE)
|
||||
{
|
||||
back_indices[basei] = vertices->size();
|
||||
vertices->push_back(base_vertex + forward);
|
||||
}
|
||||
|
||||
bevelIndices[i*no_vertices_on_bevel + no_vertices_on_bevel-1] = back_indices[basei];
|
||||
}
|
||||
else
|
||||
{
|
||||
for(unsigned int j=0; j<no_vertices_on_bevel; ++j)
|
||||
{
|
||||
const osg::Vec2& pv = profileVertices[j];
|
||||
osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
|
||||
bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
|
||||
vertices->push_back(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
|
||||
unsigned int base, next;
|
||||
for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
|
||||
{
|
||||
for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
|
||||
{
|
||||
base = i*no_vertices_on_bevel + j;
|
||||
next = base + no_vertices_on_bevel;
|
||||
|
||||
elements->push_back(bevelIndices[base]);
|
||||
elements->push_back(bevelIndices[next]);
|
||||
elements->push_back(bevelIndices[base+1]);
|
||||
|
||||
elements->push_back(bevelIndices[base+1]);
|
||||
elements->push_back(bevelIndices[next]);
|
||||
elements->push_back(bevelIndices[next+1]);
|
||||
}
|
||||
}
|
||||
|
||||
text_geometry->addPrimitiveSet(elements);
|
||||
}
|
||||
|
||||
return text_geometry.release();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// computeShellGeometry
|
||||
//
|
||||
osg::Geometry* computeShellGeometry(osg::Geometry* glyphGeometry, BevelProfile& profile, float width)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
53
examples/osgtext3D/GlyphGeometry.h
Normal file
53
examples/osgtext3D/GlyphGeometry.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef OSGTEXT_GLYPHGEOMETRY
|
||||
#define OSGTEXT_GLYPHGEOMETRY 1
|
||||
|
||||
#include <osgText/Font3D>
|
||||
|
||||
namespace osgText
|
||||
{
|
||||
|
||||
class BevelProfile
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<osg::Vec2> Vertices;
|
||||
|
||||
BevelProfile();
|
||||
|
||||
void flatBevel(float width=0.25f);
|
||||
|
||||
void roundedBevel(float width=0.5f, unsigned int numSteps=10);
|
||||
|
||||
void roundedBevel2(float width=0.5f, unsigned int numSteps=10);
|
||||
|
||||
void print(std::ostream& fout);
|
||||
|
||||
Vertices& getVertices() { return _vertices; }
|
||||
|
||||
protected:
|
||||
|
||||
Vertices _vertices;
|
||||
};
|
||||
|
||||
extern osg::Geometry* computeGlyphGeometry(osgText::Font3D::Glyph3D* glyph, float bevelThickness, float shellThickness);
|
||||
|
||||
extern osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, BevelProfile& profile, float width);
|
||||
|
||||
extern osg::Geometry* computeShellGeometry(osg::Geometry* glyphGeometry, BevelProfile& profile, float width);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@
|
||||
#include <osg/ArgumentParser>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/TriangleIndexFunctor>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osgUtil/SmoothingVisitor>
|
||||
@ -30,75 +31,12 @@
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
#include <osg/io_utils>
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
extern int main_orig(int, char**);
|
||||
extern int main_test(int, char**);
|
||||
|
||||
|
||||
class BevelProfile
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<osg::Vec2> Vertices;
|
||||
|
||||
BevelProfile()
|
||||
{
|
||||
flatBevel();
|
||||
}
|
||||
|
||||
void flatBevel(float width=0.25f)
|
||||
{
|
||||
_vertices.clear();
|
||||
|
||||
if (width>0.5f) width = 0.5f;
|
||||
|
||||
_vertices.push_back(osg::Vec2(0.0f,0.0f));
|
||||
|
||||
_vertices.push_back(osg::Vec2(width,1.0f));
|
||||
|
||||
if (width<0.5f) _vertices.push_back(osg::Vec2(1-width,1.0f));
|
||||
|
||||
_vertices.push_back(osg::Vec2(1.0f,0.0f));
|
||||
}
|
||||
|
||||
void roundedBevel(float width=0.5f, unsigned int numSteps=10)
|
||||
{
|
||||
_vertices.clear();
|
||||
|
||||
if (width>0.5f) width = 0.5f;
|
||||
|
||||
unsigned int i = 0;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, sinf(angle)) );
|
||||
}
|
||||
|
||||
// start the second half one into the curve if the width is half way across
|
||||
i = width<0.5f ? 0 : 1;
|
||||
for(; i<=numSteps; ++i)
|
||||
{
|
||||
float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
|
||||
_vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, sin(angle)) );
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::ostream& fout)
|
||||
{
|
||||
OSG_NOTICE<<"print bevel"<<std::endl;
|
||||
for(Vertices::iterator itr = _vertices.begin();
|
||||
itr != _vertices.end();
|
||||
++itr)
|
||||
{
|
||||
OSG_NOTICE<<" "<<*itr<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Vertices& getVertices() { return _vertices; }
|
||||
|
||||
protected:
|
||||
|
||||
Vertices _vertices;
|
||||
};
|
||||
|
||||
class Boundary
|
||||
{
|
||||
@ -261,6 +199,37 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool findMaxThickness(unsigned int& maxThickness_i, float& maxThickness)
|
||||
{
|
||||
maxThickness_i = _segments.size();
|
||||
for(unsigned int i=0; i<_segments.size(); ++i)
|
||||
{
|
||||
float thickness = computeThickness(i);
|
||||
if (thickness<0.0 && thickness > maxThickness)
|
||||
{
|
||||
maxThickness = thickness;
|
||||
maxThickness_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxThickness_i != _segments.size();
|
||||
}
|
||||
|
||||
|
||||
void removeAllSegmentsAboveThickness(float targetThickness)
|
||||
{
|
||||
// OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
|
||||
for(;;)
|
||||
{
|
||||
unsigned int maxThickness_i = _segments.size();
|
||||
float maxThickness = targetThickness;
|
||||
if (!findMaxThickness(maxThickness_i,maxThickness)) break;
|
||||
|
||||
// OSG_NOTICE<<" removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
|
||||
_segments.erase(_segments.begin()+maxThickness_i);
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec3 computeBisectorPoint(unsigned int i, float targetThickness)
|
||||
{
|
||||
Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
|
||||
@ -400,7 +369,7 @@ osg::Geometry* getGeometryComponent(osg::Geometry* geometry, bool bevel)
|
||||
return new_geometry;
|
||||
}
|
||||
|
||||
osg::Geometry* computeBevelGeometry(osg::Geometry* geometry, BevelProfile& profile, float width)
|
||||
osg::Geometry* computeBevelGeometry(osg::Geometry* geometry, osgText::BevelProfile& profile, float width)
|
||||
{
|
||||
if (!geometry) return 0;
|
||||
|
||||
@ -423,7 +392,7 @@ osg::Geometry* computeBevelGeometry(osg::Geometry* geometry, BevelProfile& profi
|
||||
|
||||
unsigned int no_vertices_on_boundary = bevel->size()/2;
|
||||
|
||||
BevelProfile::Vertices& profileVertices = profile.getVertices();
|
||||
osgText::BevelProfile::Vertices& profileVertices = profile.getVertices();
|
||||
unsigned int no_vertices_on_bevel = profileVertices.size();
|
||||
|
||||
unsigned int start = new_vertices->size();
|
||||
@ -530,6 +499,54 @@ osg::Geometry* computeFrontAndBackGeometry(osg::Geometry* geometry, float width)
|
||||
return new_geometry;
|
||||
}
|
||||
|
||||
|
||||
osg::Geometry* createShell(osg::Geometry* geometry, float distance)
|
||||
{
|
||||
if (!geometry) return 0;
|
||||
|
||||
osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
||||
if (!orig_vertices) return 0;
|
||||
|
||||
osg::Vec3Array* orig_normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
|
||||
if (!orig_normals) return 0;
|
||||
|
||||
if (orig_vertices->size() != orig_normals->size()) return 0;
|
||||
|
||||
osg::Geometry* new_geometry = new osg::Geometry;
|
||||
osg::Vec3Array* new_vertices = new osg::Vec3Array(orig_vertices->size());
|
||||
for(unsigned int i=0; i<orig_vertices->size(); ++i)
|
||||
{
|
||||
(*new_vertices)[i] = (*orig_vertices)[i] + (*orig_normals)[i]*distance;
|
||||
}
|
||||
|
||||
new_geometry->setVertexArray(new_vertices);
|
||||
|
||||
osg::Vec4Array* new_colours = new osg::Vec4Array;
|
||||
new_colours->push_back(osg::Vec4(1.0,1.0,1.0,0.2));
|
||||
new_geometry->setColorArray(new_colours);
|
||||
new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
|
||||
osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
|
||||
geometry->accept(ctif);
|
||||
|
||||
// front face
|
||||
osg::DrawElementsUInt* shell = new osg::DrawElementsUInt(GL_TRIANGLES);
|
||||
new_geometry->addPrimitiveSet(shell);
|
||||
CollectTriangleIndicesFunctor::Indices& face = ctif._indices;
|
||||
for(unsigned int i=0; i<face.size();++i)
|
||||
{
|
||||
shell->push_back(face[i]);
|
||||
}
|
||||
|
||||
osg::StateSet* stateset = new_geometry->getOrCreateStateSet();
|
||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateset->setAttributeAndModes(new osg::CullFace, osg::StateAttribute::ON);
|
||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
return new_geometry;
|
||||
}
|
||||
|
||||
|
||||
osg::Geometry* computeThickness(osg::Geometry* orig_geometry, float thickness)
|
||||
{
|
||||
// OSG_NOTICE<<"computeThickness("<<orig_geometry<<")"<<std::endl;
|
||||
@ -546,7 +563,8 @@ osg::Geometry* computeThickness(osg::Geometry* orig_geometry, float thickness)
|
||||
if (drawArray && drawArray->getMode()==GL_POLYGON)
|
||||
{
|
||||
Boundary boundary(orig_vertices, drawArray->getFirst(), drawArray->getCount());
|
||||
boundary.removeAllSegmentsBelowThickness(thickness);
|
||||
if (thickness>0.0f) boundary.removeAllSegmentsBelowThickness(thickness);
|
||||
else if (thickness<0.0f) boundary.removeAllSegmentsAboveThickness(thickness);
|
||||
boundary.addBoundaryToGeometry(new_geometry, thickness);
|
||||
}
|
||||
}
|
||||
@ -601,9 +619,10 @@ int main(int argc, char** argv)
|
||||
|
||||
OSG_NOTICE<<"creaseAngle="<<creaseAngle<<std::endl;
|
||||
|
||||
BevelProfile profile;
|
||||
osgText::BevelProfile 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); }
|
||||
|
||||
profile.print(std::cout);
|
||||
@ -627,6 +646,24 @@ int main(int argc, char** argv)
|
||||
|
||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
|
||||
|
||||
#if 1
|
||||
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 = osgText::computeShellGeometry(glyphGeometry.get(), profile, width);
|
||||
if (textGeometry.valid())
|
||||
{
|
||||
geode->addDrawable(textGeometry.get());
|
||||
// create the normals
|
||||
if (true)
|
||||
{
|
||||
osgUtil::SmoothingVisitor smoother;
|
||||
smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
|
||||
geode->accept(smoother);
|
||||
}
|
||||
}
|
||||
|
||||
if (shellGeometry.valid()) geode->addDrawable(shellGeometry.get());
|
||||
#else
|
||||
osg::Vec3Array* vertices = glyph->getRawVertexArray();
|
||||
osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList();
|
||||
|
||||
@ -661,9 +698,25 @@ int main(int argc, char** argv)
|
||||
geode->addDrawable(bevel.get());
|
||||
}
|
||||
|
||||
osgUtil::SmoothingVisitor smoother;
|
||||
smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
|
||||
geode->accept(smoother);
|
||||
// create the normals
|
||||
{
|
||||
osgUtil::SmoothingVisitor smoother;
|
||||
geode->accept(smoother);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> shell = createShell(bevel.get(), width);
|
||||
|
||||
{
|
||||
osgUtil::SmoothingVisitor smoother;
|
||||
smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
|
||||
geode->accept(smoother);
|
||||
}
|
||||
|
||||
if (shell.valid())
|
||||
{
|
||||
geode->addDrawable(shell.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
transform->addChild(geode.get());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user