2007-12-10 23:15:56 +08:00
/* OpenSceneGraph example, osgtext.
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
2010-07-15 02:50:41 +08:00
# include <osg/ArgumentParser>
# include <osg/Geode>
# include <osg/Geometry>
# include <osg/PositionAttitudeTransform>
# include <osgText/Font3D>
# include <osgDB/WriteFile>
# include <osgGA/StateSetManipulator>
# include <osgUtil/Tessellator>
2007-12-10 23:15:56 +08:00
# include <osgViewer/Viewer>
# include <osgViewer/ViewerEventHandlers>
2010-07-15 02:50:41 +08:00
# include <osg/io_utils>
2007-12-10 23:15:56 +08:00
2010-07-15 02:50:41 +08:00
extern int main_orig ( int , char * * ) ;
extern int main_test ( int , char * * ) ;
2007-12-10 23:15:56 +08:00
2010-07-20 04:34:15 +08:00
2010-07-17 20:03:17 +08:00
class Boundary
{
2010-07-20 04:34:15 +08:00
public :
typedef std : : pair < unsigned int , unsigned int > Segment ;
typedef std : : vector < Segment > Segments ;
osg : : ref_ptr < osg : : Vec3Array > _vertices ;
Segments _segments ;
2010-07-17 20:03:17 +08:00
2010-07-20 04:34:15 +08:00
Boundary ( osg : : Vec3Array * vertices , unsigned int start , unsigned int count )
2010-07-17 20:03:17 +08:00
{
2010-07-20 04:34:15 +08:00
_vertices = vertices ;
2010-07-17 20:03:17 +08:00
2010-07-20 04:34:15 +08:00
if ( ( * _vertices ) [ start ] = = ( * _vertices ) [ start + count - 1 ] )
{
2010-07-20 18:46:27 +08:00
// OSG_NOTICE<<"Boundary is a line loop"<<std::endl;
2010-07-20 04:34:15 +08:00
}
else
{
OSG_NOTICE < < " Boundary is not a line loop " < < std : : endl ;
}
_segments . reserve ( count - 1 ) ;
for ( unsigned int i = start ; i < start + count - 1 ; + + i )
{
_segments . push_back ( Segment ( i , i + 1 ) ) ;
}
}
2010-07-26 19:06:45 +08:00
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.0 )
{
//OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl;
// line segments must be parallel.
return ( a + c ) * 0.5 ;
}
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 ;
}
2010-07-20 04:34:15 +08:00
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 )
{
2010-07-20 18:46:27 +08:00
// OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
2010-07-20 04:34:15 +08:00
for ( ; ; )
{
unsigned int minThickness_i = _segments . size ( ) ;
float minThickness = targetThickness ;
if ( ! findMinThickness ( minThickness_i , minThickness ) ) break ;
2010-07-20 18:46:27 +08:00
// OSG_NOTICE<<" removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
2010-07-20 04:34:15 +08:00
_segments . erase ( _segments . begin ( ) + minThickness_i ) ;
}
}
2010-07-17 20:03:17 +08:00
2010-07-20 18:46:27 +08:00
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;
new_vertex . z ( ) + = 0.5f ;
return new_vertex ;
}
void addBoundaryToGeometry ( osg : : Geometry * geometry , float targetThickness )
{
if ( _segments . empty ( ) ) return ;
if ( geometry - > getVertexArray ( ) = = 0 ) geometry - > setVertexArray ( new osg : : Vec3Array ) ;
osg : : Vec3Array * new_vertices = dynamic_cast < osg : : Vec3Array * > ( geometry - > getVertexArray ( ) ) ;
unsigned int first = new_vertices - > size ( ) ;
unsigned int count = 0 ;
// reserve enough space in the vertex array to accomodate the vertices associated with the segments
// new_vertices->reserve(new_vertices->size()+_segments.size()+1);
// create vertices
unsigned int previous_second = _segments [ 0 ] . second ;
osg : : Vec3 newPoint = computeBisectorPoint ( 0 , targetThickness ) ;
new_vertices - > push_back ( newPoint ) ;
+ + count ;
for ( unsigned int i = 1 ; i < _segments . size ( ) ; + + i )
{
previous_second = _segments [ i ] . second ;
newPoint = computeBisectorPoint ( i , targetThickness ) ;
new_vertices - > push_back ( newPoint ) ;
+ + count ;
}
// repeat the first point to make it a full closed loop
new_vertices - > push_back ( ( * new_vertices ) [ first ] ) ;
+ + count ;
// add DrawArrays primitive set for polygon
if ( count ! = 0 ) geometry - > addPrimitiveSet ( new osg : : DrawArrays ( GL_POLYGON , first , count ) ) ;
}
2010-07-17 20:03:17 +08:00
} ;
2007-12-10 23:15:56 +08:00
2010-07-20 04:34:15 +08:00
osg : : Geometry * computeThickness ( osg : : Geometry * orig_geometry , float thickness )
{
2010-07-20 18:46:27 +08:00
// OSG_NOTICE<<"computeThickness("<<orig_geometry<<")"<<std::endl;
2010-07-20 04:34:15 +08:00
osg : : Vec3Array * orig_vertices = dynamic_cast < osg : : Vec3Array * > ( orig_geometry - > getVertexArray ( ) ) ;
osg : : Geometry : : PrimitiveSetList & orig_primitives = orig_geometry - > getPrimitiveSetList ( ) ;
2010-07-20 18:46:27 +08:00
osg : : Geometry * new_geometry = new osg : : Geometry ;
osg : : Vec4Array * new_colours = new osg : : Vec4Array ;
new_colours - > push_back ( osg : : Vec4 ( 1.0 , 1.0 , 0.0 , 1.0 ) ) ;
new_geometry - > setColorArray ( new_colours ) ;
new_geometry - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
2010-07-20 04:34:15 +08:00
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 boundary ( orig_vertices , drawArray - > getFirst ( ) , drawArray - > getCount ( ) ) ;
boundary . computeAllThickness ( ) ;
boundary . removeAllSegmentsBelowThickness ( thickness ) ;
2010-07-20 18:46:27 +08:00
boundary . addBoundaryToGeometry ( new_geometry , thickness ) ;
2010-07-20 04:34:15 +08:00
}
}
2010-07-20 18:46:27 +08:00
return new_geometry ;
2010-07-20 04:34:15 +08:00
}
2010-07-15 02:50:41 +08:00
int main ( int argc , char * * argv )
{
osg : : ArgumentParser arguments ( & argc , argv ) ;
if ( arguments . read ( " --test " ) )
{
return main_test ( argc , argv ) ;
}
else if ( arguments . read ( " --original " ) | | arguments . read ( " --orig " ) )
{
return main_orig ( argc , argv ) ;
}
std : : string fontFile ( " arial.ttf " ) ;
while ( arguments . read ( " -f " , fontFile ) ) { }
std : : string word ( " This is a simple test " ) ;
2010-07-20 18:46:27 +08:00
while ( arguments . read ( " --ascii " ) )
{
word . clear ( ) ;
for ( unsigned int c = ' ' ; c < = 127 ; + + c )
{
word . push_back ( c ) ;
}
}
2010-07-15 02:50:41 +08:00
while ( arguments . read ( " -w " , word ) ) { }
osg : : ref_ptr < osgText : : Font3D > font = osgText : : readFont3DFile ( fontFile ) ;
if ( ! font ) return 1 ;
OSG_NOTICE < < " Read font " < < fontFile < < " font= " < < font . get ( ) < < std : : endl ;
bool useTessellator = false ;
while ( arguments . read ( " -t " ) | | arguments . read ( " --tessellate " ) ) { useTessellator = true ; }
2010-07-20 04:34:15 +08:00
float thickness = 5.0 ;
while ( arguments . read ( " --thickness " , thickness ) ) { }
2010-07-15 02:50:41 +08:00
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 : : Font3D : : Glyph3D > glyph = font - > getGlyph ( 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 : : Vec3Array * vertices = glyph - > getRawVertexArray ( ) ;
osg : : Geometry : : PrimitiveSetList & primitives = glyph - > getRawFacePrimitiveSetList ( ) ;
osg : : ref_ptr < osg : : Geometry > geometry = new osg : : Geometry ;
geometry - > setVertexArray ( vertices ) ;
geometry - > setPrimitiveSetList ( primitives ) ;
osg : : Vec4Array * colours = new osg : : Vec4Array ;
colours - > push_back ( osg : : Vec4 ( 1.0 , 1.0 , 1.0 , 1.0 ) ) ;
geometry - > setColorArray ( colours ) ;
geometry - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
2010-07-26 19:06:45 +08:00
osg : : Geometry * bevel = computeThickness ( geometry , thickness ) ;
2010-07-15 02:50:41 +08:00
2010-07-20 18:46:27 +08:00
if ( bevel ) geode - > addDrawable ( bevel ) ;
2010-07-20 04:34:15 +08:00
2010-07-15 02:50:41 +08:00
if ( useTessellator )
{
2010-07-20 18:46:27 +08:00
if ( geometry )
{
osgUtil : : Tessellator ts ;
ts . setWindingType ( osgUtil : : Tessellator : : TESS_WINDING_POSITIVE ) ;
ts . setTessellationType ( osgUtil : : Tessellator : : TESS_TYPE_GEOMETRY ) ;
ts . retessellatePolygons ( * geometry ) ;
}
2010-07-15 02:50:41 +08:00
2010-07-20 18:46:27 +08:00
if ( bevel )
{
osgUtil : : Tessellator ts ;
ts . setWindingType ( osgUtil : : Tessellator : : TESS_WINDING_POSITIVE ) ;
ts . setTessellationType ( osgUtil : : Tessellator : : TESS_TYPE_GEOMETRY ) ;
ts . retessellatePolygons ( * bevel ) ;
}
2010-07-15 02:50:41 +08:00
}
geode - > addDrawable ( geometry . get ( ) ) ;
transform - > addChild ( geode . get ( ) ) ;
group - > addChild ( transform . get ( ) ) ;
}
std : : string filename ;
if ( arguments . read ( " -o " , filename ) ) osgDB : : writeNodeFile ( * group , filename ) ;
2007-12-10 23:15:56 +08:00
2010-07-15 02:50:41 +08:00
osgViewer : : Viewer viewer ( arguments ) ;
viewer . setSceneData ( group . get ( ) ) ;
viewer . addEventHandler ( new osgGA : : StateSetManipulator ( viewer . getCamera ( ) - > getOrCreateStateSet ( ) ) ) ;
return viewer . run ( ) ;
}