1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13
14 #include "TextNode.h"
15 #include "../../src/osgText/GlyphGeometry.h"
16
17 #include <osg/PositionAttitudeTransform>
18 #include <osg/Geode>
19 #include <osgUtil/SmoothingVisitor>
20
21 #include <osg/io_utils>
22
23 using namespace osgText;
24
25 /////////////////////////////////////////////////////////////////////////////////////////
26 //
27 // Layout
28 //
Layout()29 Layout::Layout()
30 {
31 }
32
Layout(const Layout & layout,const osg::CopyOp & copyop)33 Layout::Layout(const Layout& layout, const osg::CopyOp& copyop):
34 osg::Object(layout,copyop)
35 {
36 }
37
getDefaultLayout()38 osg::ref_ptr<Layout>& Layout::getDefaultLayout()
39 {
40 static OpenThreads::Mutex s_DefaultLayoutMutex;
41 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultLayoutMutex);
42
43 static osg::ref_ptr<Layout> s_defaultLayout = new Layout;
44 return s_defaultLayout;
45 }
46
layout(TextNode & text) const47 void Layout::layout(TextNode& text) const
48 {
49 OSG_NOTICE<<"Layout::layout"<<std::endl;
50
51 Font* font = text.getActiveFont();
52 Style* style = text.getActiveStyle();
53 TextTechnique* technique = text.getTextTechnique();
54 const String& str = text.getText();
55
56 if (!text.getTextTechnique())
57 {
58 OSG_NOTICE<<"Warning: no TextTechnique assigned to Layout"<<std::endl;
59 return;
60 }
61
62 osg::Vec3 pos(0.0f,0.0f,0.0f);
63 float characterSize = text.getCharacterSize();
64 osg::Vec3 size(characterSize, characterSize, 0.0);
65 if (style)
66 {
67 size.y() = characterSize;
68 size.z() = characterSize;
69 }
70
71
72 osgText::FontResolution resolution(32,32);
73 if (style)
74 {
75 resolution.first = static_cast<unsigned int>(static_cast<float>(resolution.first)*style->getSampleDensity());
76 resolution.second = static_cast<unsigned int>(static_cast<float>(resolution.second)*style->getSampleDensity());
77 }
78
79 float characterWidthScale = 1.0f;
80
81 bool textIs3D = (style && style->getThicknessRatio()!=0.0);
82 if (!textIs3D)
83 {
84 characterWidthScale = 1.0f/static_cast<float>(resolution.first);
85 }
86
87 osgText::KerningType kerningType = osgText::KERNING_DEFAULT;
88
89 technique->start();
90
91 unsigned int previousCharcode = 0;
92 for(unsigned int i=0; i<str.size(); ++i)
93 {
94 unsigned int charcode = str[i];
95
96 if (size.z()==0.0f)
97 {
98 osgText::Glyph* glyph = font->getGlyph(resolution, charcode);
99 if (glyph)
100 {
101 technique->addCharacter(pos, size, glyph, style);
102 pos += osg::Vec3(size.x()*(glyph->getHorizontalAdvance()*characterWidthScale), 0.0f ,0.0f);
103 }
104 }
105 else
106 {
107 osgText::Glyph3D* glyph = font->getGlyph3D(resolution, charcode);
108 OSG_NOTICE<<"pos = "<<pos<<", charcode="<<charcode<<", glyph="<<glyph<< std::endl;
109 if (glyph)
110 {
111 osg::Vec3 local_scale( size );
112 technique->addCharacter(pos, local_scale, glyph, style);
113 pos += osg::Vec3(size.x()*glyph->getWidth(), 0.0f ,0.0f);
114 }
115 }
116
117 if (previousCharcode!=0 && charcode!=0)
118 {
119 osg::Vec2 offset = font->getKerning(resolution, previousCharcode, charcode, kerningType);
120 OSG_NOTICE<<" offset = "<<offset<< std::endl;
121 pos.x() += offset.x();
122 pos.y() += offset.y();
123 }
124
125 previousCharcode = charcode;
126 }
127
128 technique->finish();
129 }
130
131
132 /////////////////////////////////////////////////////////////////////////////////////////
133 //
134 // TextTechnique
135 //
TextTechnique()136 TextTechnique::TextTechnique():
137 _textNode(0)
138 {
139 }
140
141
TextTechnique(const TextTechnique & technique,const osg::CopyOp & copyop)142 TextTechnique::TextTechnique(const TextTechnique& technique, const osg::CopyOp& copyop):
143 osg::Object(technique, copyop),
144 _textNode(0)
145 {
146 }
147
getDefaultTextTechinque()148 osg::ref_ptr<TextTechnique>& TextTechnique::getDefaultTextTechinque()
149 {
150 static OpenThreads::Mutex s_DefaultTextTechniqueMutex;
151 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultTextTechniqueMutex);
152
153 static osg::ref_ptr<TextTechnique> s_defaultTextTechnique = new TextTechnique;
154 return s_defaultTextTechnique;
155 }
156
start()157 void TextTechnique::start()
158 {
159 OSG_NOTICE<<"TextTechnique::start()"<<std::endl;
160 }
161
addCharacter(const osg::Vec3 & position,const osg::Vec3 & size,Glyph * glyph,Style * style)162 void TextTechnique::addCharacter(const osg::Vec3& position, const osg::Vec3& size, Glyph* glyph, Style* style)
163 {
164 OSG_NOTICE<<"TextTechnique::addCharacter 2D("<<position<<", "<<size<<", "<<glyph<<", "<<style<<")"<<std::endl;
165 }
166
addCharacter(const osg::Vec3 & position,const osg::Vec3 & size,Glyph3D * glyph,Style * style)167 void TextTechnique::addCharacter(const osg::Vec3& position, const osg::Vec3& size, Glyph3D* glyph, Style* style)
168 {
169 OSG_NOTICE<<"TextTechnique::addCharacter 3D("<<position<<", "<<size<<", "<<glyph<<", "<<style<<")"<<std::endl;
170
171 osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
172 transform->setPosition(position);
173 transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
174 transform->setScale(size);
175
176 osg::ref_ptr<osg::Geode> geode = new osg::Geode;
177
178 const Bevel* bevel = style ? style->getBevel() : 0;
179 bool outline = style ? style->getOutlineRatio()>0.0f : false;
180 float width = style->getThicknessRatio();
181 float creaseAngle = 30.0f;
182 bool smooth = true;
183
184 if (bevel)
185 {
186 osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph, *bevel, width);
187 osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(glyphGeometry.get(), *bevel, width);
188 osg::ref_ptr<osg::Geometry> shellGeometry = outline ? osgText::computeShellGeometry(glyphGeometry.get(), *bevel, width) : 0;
189 if (textGeometry.valid()) geode->addDrawable(textGeometry.get());
190 if (shellGeometry.valid()) geode->addDrawable(shellGeometry.get());
191
192 // create the normals
193 if (smooth && textGeometry.valid())
194 {
195 osgUtil::SmoothingVisitor::smooth(*textGeometry, osg::DegreesToRadians(creaseAngle));
196 }
197 }
198 else
199 {
200 osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(glyph, width);
201 if (textGeometry.valid()) geode->addDrawable(textGeometry.get());
202
203 // create the normals
204 if (smooth && textGeometry.valid())
205 {
206 osgUtil::SmoothingVisitor::smooth(*textGeometry, osg::DegreesToRadians(creaseAngle));
207 }
208 }
209
210 transform->addChild(geode.get());
211
212 _textNode->addChild(transform.get());
213
214 transform->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
215
216 }
217
finish()218 void TextTechnique::finish()
219 {
220 OSG_NOTICE<<"TextTechnique::finish()"<<std::endl;
221 }
222
traverse(osg::NodeVisitor & nv)223 void TextTechnique::traverse(osg::NodeVisitor& nv)
224 {
225 // OSG_NOTICE<<"TextTechnique::traverse()"<<std::endl;
226 if (_textNode) _textNode->osg::Group::traverse(nv);
227 }
228
229 /////////////////////////////////////////////////////////////////////////////////////////
230 //
231 // TextNode
232 //
TextNode()233 TextNode::TextNode():
234 _characterSize(1.0f)
235 {
236 }
237
238
TextNode(const TextNode & text,const osg::CopyOp & copyop)239 TextNode::TextNode(const TextNode& text, const osg::CopyOp& copyop):
240 osg::Group(text, copyop)
241 {
242 }
243
~TextNode()244 TextNode::~TextNode()
245 {
246 setTextTechnique(0);
247 }
248
traverse(osg::NodeVisitor & nv)249 void TextNode::traverse(osg::NodeVisitor& nv)
250 {
251 if (_technique.valid())
252 {
253 _technique->traverse(nv);
254 }
255 else
256 {
257 Group::traverse(nv);
258 }
259 }
260
setTextTechnique(TextTechnique * technique)261 void TextNode::setTextTechnique(TextTechnique* technique)
262 {
263 if (_technique==technique) return;
264
265 if (_technique.valid()) _technique->setTextNode(0);
266
267 if (TextTechnique::getDefaultTextTechinque()==technique)
268 {
269 OSG_NOTICE<<"Warning: Attempt to assign DefaultTextTechnique() prototype to TextNode::setTextTechnique(..), assigning a clone() of it instead."<<std::endl;
270 technique = new TextTechnique(*TextTechnique::getDefaultTextTechinque());
271 }
272
273 _technique = technique;
274
275 if (_technique.valid()) _technique->setTextNode(this);
276 }
277
278
update()279 void TextNode::update()
280 {
281 getActiveLayout()->layout(*this);
282 }
283
setText(const std::string & str)284 void TextNode::setText(const std::string& str)
285 {
286 _string.set(str);
287 }
288