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

Revision 11676, 9.2 kB (checked in by robert, 4 years ago)

Added raw primitive and vertex data into the osgText::Font3D and FreeTypePlugin? to aid development of new 3D text functionality.

Added new test for original 3D text support and new experimental code for exploring approaches to new 3D text support.

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    v21.normalize();
91    v32.normalize();
92    osg::Vec3 cross = v21^v32;
93
94    float t = 5.0;
95
96    osg::Vec3 bisector(v32-v21);
97
98    if (bisector.length()<0.5)
99    {
100        // angle wider than 90 degrees so use side vectors as guide for angle to project along.
101        osg::Vec3 s21 = v21 ^ osg::Vec3(0.0f,0.0f,1.0f);
102        s21.normalize();
103
104        osg::Vec3 s32 = v32 ^ osg::Vec3(0.0f,0.0f,1.0f);
105        s32.normalize();
106
107        osg::Vec3 bisector(s21+s32);
108        bisector.normalize();
109
110        float l = t / sin(angle*0.5);
111
112        osg::Vec3 new_vertex = v2 + bisector * l;
113        new_vertex.z() += 0.5f;
114
115        return new_vertex;
116    }
117    else
118    {
119        float l = t / sin(angle*0.5);
120
121        bisector.normalize();
122        if (cross.z()>0.0) bisector = -bisector;
123
124        osg::Vec3 new_vertex = v2 + bisector * l;
125        new_vertex.z() += 0.5f;
126        return new_vertex;
127    }
128}
129
130osg::PrimitiveSet* computeBevelEdge(osg::Vec3Array& orig_vertices, unsigned int start, unsigned int count, osg::Vec3Array& new_vertices)
131{
132    OSG_NOTICE<<"computeBoundaryAngles("<<orig_vertices.size()<<", "<<start<<", "<<count<<")"<<std::endl;
133    if (orig_vertices[start+count-1]==orig_vertices[start])
134    {
135        OSG_NOTICE<<"is a line loop"<<std::endl;
136    }
137    else
138    {
139        OSG_NOTICE<<"is not line loop, ("<<orig_vertices[start+count-1]<<"), ("<<orig_vertices[start]<<")"<<std::endl;
140        return new osg::DrawArrays(GL_POLYGON, start, count);
141    }
142
143    new_vertices[start] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
144    for(unsigned int i=start+1; i<start+count-1; ++i)
145    {
146        new_vertices[i] = computeNewVertexPosition(orig_vertices[i-1],orig_vertices[i],orig_vertices[i+1]);
147    }
148    new_vertices[start+count-1] = computeNewVertexPosition(orig_vertices[start+count-2],orig_vertices[start],orig_vertices[start+1]);
149
150    return new osg::DrawArrays(GL_POLYGON, start, count);
151}
152
153osg::Geometry* computeBevelEdge(osg::Geometry* orig_geometry)
154{
155    OSG_NOTICE<<"computeBoundaryAngles("<<orig_geometry<<")"<<std::endl;
156    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(orig_geometry->getVertexArray());
157    osg::Geometry::PrimitiveSetList& orig_primitives = orig_geometry->getPrimitiveSetList();
158
159    osg::Geometry* new_geometry = new osg::Geometry;
160    osg::Vec3Array* new_vertices = new osg::Vec3Array(*orig_vertices);
161    osg::Geometry::PrimitiveSetList& new_primitives = new_geometry->getPrimitiveSetList();
162    new_geometry->setVertexArray(new_vertices);
163    osg::Vec4Array* new_colours = new osg::Vec4Array;
164    new_colours->push_back(osg::Vec4(1.0,0.0,0.0,1.0));
165    new_geometry->setColorArray(new_colours);
166    new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
167
168    for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
169        itr != orig_primitives.end();
170        ++itr)
171    {
172        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
173        if (drawArray && drawArray->getMode()==GL_POLYGON)
174        {
175            new_primitives.push_back(computeBevelEdge(*orig_vertices, drawArray->getFirst(), drawArray->getCount(), *new_vertices));
176        }
177    }
178    return new_geometry;
179}
180
181int main(int argc, char** argv)
182{
183    osg::ArgumentParser arguments(&argc, argv);
184
185    if (arguments.read("--test"))
186    {
187        return main_test(argc,argv);
188    }
189    else if (arguments.read("--original") || arguments.read("--orig"))
190    {
191        return main_orig(argc,argv);
192    }
193
194    std::string fontFile("arial.ttf");
195    while(arguments.read("-f",fontFile)) {}
196
197    std::string word("This is a simple test");
198    while(arguments.read("-w",word)) {}
199
200    osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
201    if (!font) return 1;
202    OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
203
204
205    bool useTessellator = false;
206    while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
207
208    osg::ref_ptr<osg::Group> group = new osg::Group;
209    osg::Vec3 position;
210
211    for(unsigned int i=0; i<word.size(); ++i)
212    {
213        osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
214        if (!glyph) return 1;
215
216        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
217        transform->setPosition(position);
218        transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
219
220        position.x() += glyph->getHorizontalWidth();
221
222        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
223
224        osg::Vec3Array* vertices = glyph->getRawVertexArray();
225        osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList();
226
227        osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
228        geometry->setVertexArray(vertices);
229        geometry->setPrimitiveSetList(primitives);
230        osg::Vec4Array* colours = new osg::Vec4Array;
231        colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
232        geometry->setColorArray(colours);
233        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
234
235        computeBoundaryAngles(geometry);
236
237        osg::Geometry* bevel = computeBevelEdge(geometry);
238        geode->addDrawable(bevel);
239
240        if (useTessellator)
241        {
242            osgUtil::Tessellator ts;
243            ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
244            ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
245            ts.retessellatePolygons(*geometry);
246
247            ts.retessellatePolygons(*bevel);
248
249        }
250
251        geode->addDrawable(geometry.get());
252
253        transform->addChild(geode.get());
254
255        group->addChild(transform.get());
256    }
257
258    std::string filename;
259    if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
260
261    osgViewer::Viewer viewer(arguments);
262    viewer.setSceneData(group.get());
263    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
264    return viewer.run();
265}
Note: See TracBrowser for help on using the browser.