root/OpenSceneGraph/trunk/examples/osgtext3D/osgtext3D.cpp @ 11678

Revision 11678, 9.8 kB (checked in by robert, 4 years ago)

Added handling of duplicate vertices

Line 
1/* OpenSceneGraph example, osgtext.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/ArgumentParser>
20#include <osg/Geode>
21#include <osg/Geometry>
22#include <osg/PositionAttitudeTransform>
23#include <osgText/Font3D>
24#include <osgDB/WriteFile>
25#include <osgGA/StateSetManipulator>
26#include <osgUtil/Tessellator>
27#include <osgViewer/Viewer>
28#include <osgViewer/ViewerEventHandlers>
29#include <osg/io_utils>
30
31extern int main_orig(int, char**);
32extern int main_test(int, char**);
33
34
35float computeAngle(osg::Vec3& v1, osg::Vec3& v2, osg::Vec3& v3)
36{
37    osg::Vec3 v12(v1-v2);
38    osg::Vec3 v32(v3-v2);
39    v12.normalize();
40    v32.normalize();
41    float dot = v12*v32;
42    float angle = acosf(dot);
43    OSG_NOTICE<<"    v1="<<v1<<", v2="<<v2<<", v3="<<v3<<", dot_angle="<<osg::RadiansToDegrees(angle)<<std::endl;
44    return angle;
45}
46
47void computeBoundaryAngles(osg::Vec3Array& vertices, unsigned int start, unsigned int count)
48{
49    OSG_NOTICE<<"computeBoundaryAngles("<<vertices.size()<<", "<<start<<", "<<count<<")"<<std::endl;
50    if (vertices[start+count-1]==vertices[start])
51    {
52        OSG_NOTICE<<"is a line loop"<<std::endl;
53    }
54    else
55    {
56        OSG_NOTICE<<"is not line loop, ("<<vertices[start+count-1]<<"), ("<<vertices[start]<<")"<<std::endl;
57        return;
58    }
59
60    computeAngle(vertices[start+count-2],vertices[start],vertices[start+1]);
61    for(unsigned int i=start+1; i<start+count-1; ++i)
62    {
63        computeAngle(vertices[i-1],vertices[i],vertices[i+1]);
64    }
65    computeAngle(vertices[start+count-2],vertices[start],vertices[start+1]);
66}
67
68void computeBoundaryAngles(osg::Geometry* geometry)
69{
70    OSG_NOTICE<<"computeBoundaryAngles("<<geometry<<")"<<std::endl;
71    osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
72    osg::Geometry::PrimitiveSetList& primitives = geometry->getPrimitiveSetList();
73    for(osg::Geometry::PrimitiveSetList::iterator itr = primitives.begin();
74        itr != primitives.end();
75        ++itr)
76    {
77        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
78        if (drawArray && drawArray->getMode()==GL_POLYGON)
79        {
80            computeBoundaryAngles(*vertices, drawArray->getFirst(), drawArray->getCount());
81        }
82    }
83}
84
85osg::Vec3 computeNewVertexPosition(osg::Vec3& v1, osg::Vec3& v2, osg::Vec3& v3)
86{
87    double angle = computeAngle(v1,v2,v3);
88    osg::Vec3 v21(v2-v1);
89    osg::Vec3 v32(v3-v2);
90    float length_21 = v21.normalize();
91    float length_32 = v32.normalize();
92
93    float t = 5.0;
94    if (length_21==0.0)
95    {
96        OSG_NOTICE<<"length_21=="<<length_21<<", length_32="<<length_32<<std::endl;
97        osg::Vec3 bisector = v32 ^ osg::Vec3(0.0f,0.0f,1.0f);
98        bisector.normalize();
99        osg::Vec3 new_vertex = v2 + bisector * t;
100        return new_vertex;
101    }
102    else if (length_32==0.0)
103    {
104        OSG_NOTICE<<"length_21=="<<length_21<<", length_32="<<length_32<<std::endl;
105        osg::Vec3 bisector = v21 ^ osg::Vec3(0.0f,0.0f,1.0f);
106        bisector.normalize();
107        osg::Vec3 new_vertex = v2 + bisector * t;
108        return new_vertex;
109    }
110
111    osg::Vec3 cross = v21^v32;
112    osg::Vec3 bisector(v32-v21);
113
114    if (bisector.length()<0.5)
115    {
116        // angle wider than 90 degrees so use side vectors as guide for angle to project along.
117        osg::Vec3 s21 = v21 ^ osg::Vec3(0.0f,0.0f,1.0f);
118        s21.normalize();
119
120        osg::Vec3 s32 = v32 ^ osg::Vec3(0.0f,0.0f,1.0f);
121        s32.normalize();
122
123        osg::Vec3 bisector(s21+s32);
124        bisector.normalize();
125
126        float l = t / sin(angle*0.5);
127
128        osg::Vec3 new_vertex = v2 + bisector * l;
129        new_vertex.z() += 0.5f;
130
131        return new_vertex;
132    }
133    else
134    {
135        float l = t / sin(angle*0.5);
136
137        bisector.normalize();
138        if (cross.z()>0.0) bisector = -bisector;
139
140        osg::Vec3 new_vertex = v2 + bisector * l;
141        new_vertex.z() += 0.5f;
142        return new_vertex;
143    }
144}
145
146osg::PrimitiveSet* computeBevelEdge(osg::Vec3Array& orig_vertices, unsigned int start, unsigned int count, osg::Vec3Array& new_vertices)
147{
148    OSG_NOTICE<<"computeBoundaryAngles("<<orig_vertices.size()<<", "<<start<<", "<<count<<")"<<std::endl;
149    if (orig_vertices[start+count-1]==orig_vertices[start])
150    {
151        OSG_NOTICE<<"is a line loop"<<std::endl;
152    }
153    else
154    {
155        OSG_NOTICE<<"is not line loop, ("<<orig_vertices[start+count-1]<<"), ("<<orig_vertices[start]<<")"<<std::endl;
156        return new osg::DrawArrays(GL_POLYGON, start, count);
157    }
158
159    new_vertices[start] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
160    for(unsigned int i=start+1; i<start+count-1; ++i)
161    {
162        new_vertices[i] = computeNewVertexPosition(orig_vertices[i-1],orig_vertices[i],orig_vertices[i+1]);
163    }
164    new_vertices[start+count-1] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
165
166    return new osg::DrawArrays(GL_POLYGON, start, count);
167}
168
169osg::Geometry* computeBevelEdge(osg::Geometry* orig_geometry)
170{
171    OSG_NOTICE<<"computeBoundaryAngles("<<orig_geometry<<")"<<std::endl;
172    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(orig_geometry->getVertexArray());
173    osg::Geometry::PrimitiveSetList& orig_primitives = orig_geometry->getPrimitiveSetList();
174
175    osg::Geometry* new_geometry = new osg::Geometry;
176    osg::Vec3Array* new_vertices = new osg::Vec3Array(*orig_vertices);
177    osg::Geometry::PrimitiveSetList& new_primitives = new_geometry->getPrimitiveSetList();
178    new_geometry->setVertexArray(new_vertices);
179    osg::Vec4Array* new_colours = new osg::Vec4Array;
180    new_colours->push_back(osg::Vec4(1.0,0.0,0.0,1.0));
181    new_geometry->setColorArray(new_colours);
182    new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
183
184    for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
185        itr != orig_primitives.end();
186        ++itr)
187    {
188        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
189        if (drawArray && drawArray->getMode()==GL_POLYGON)
190        {
191            new_primitives.push_back(computeBevelEdge(*orig_vertices, drawArray->getFirst(), drawArray->getCount(), *new_vertices));
192        }
193    }
194    return new_geometry;
195}
196
197int main(int argc, char** argv)
198{
199    osg::ArgumentParser arguments(&argc, argv);
200
201    if (arguments.read("--test"))
202    {
203        return main_test(argc,argv);
204    }
205    else if (arguments.read("--original") || arguments.read("--orig"))
206    {
207        return main_orig(argc,argv);
208    }
209
210    std::string fontFile("arial.ttf");
211    while(arguments.read("-f",fontFile)) {}
212
213    std::string word("This is a simple test");
214    while(arguments.read("-w",word)) {}
215
216    osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
217    if (!font) return 1;
218    OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
219
220
221    bool useTessellator = false;
222    while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
223
224    osg::ref_ptr<osg::Group> group = new osg::Group;
225    osg::Vec3 position;
226
227    for(unsigned int i=0; i<word.size(); ++i)
228    {
229        osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
230        if (!glyph) return 1;
231
232        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
233        transform->setPosition(position);
234        transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
235
236        position.x() += glyph->getHorizontalWidth();
237
238        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
239
240        osg::Vec3Array* vertices = glyph->getRawVertexArray();
241        osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList();
242
243        osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
244        geometry->setVertexArray(vertices);
245        geometry->setPrimitiveSetList(primitives);
246        osg::Vec4Array* colours = new osg::Vec4Array;
247        colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
248        geometry->setColorArray(colours);
249        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
250
251        computeBoundaryAngles(geometry);
252
253        osg::Geometry* bevel = computeBevelEdge(geometry);
254        geode->addDrawable(bevel);
255
256        if (useTessellator)
257        {
258            osgUtil::Tessellator ts;
259            ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
260            ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
261            ts.retessellatePolygons(*geometry);
262
263            ts.retessellatePolygons(*bevel);
264
265        }
266
267        geode->addDrawable(geometry.get());
268
269        transform->addChild(geode.get());
270
271        group->addChild(transform.get());
272    }
273
274    std::string filename;
275    if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
276
277    osgViewer::Viewer viewer(arguments);
278    viewer.setSceneData(group.get());
279    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
280    return viewer.run();
281}
Note: See TracBrowser for help on using the browser.