root/OpenSceneGraph/trunk/src/osgText/Font3D.cpp @ 9881

Revision 9881, 9.9 kB (checked in by robert, 5 years ago)

From David Callu, "Problem:

osgText::Text and osgText::Text3D use the same font file.
The first really load the file and obtain an osgText::Font object,
the second use the cache created during the first load of the
font file, and so obtain an osgText::Font object instead of
osgText::Font3D object. To obtain an osgText::Font3D object,
osgText::Text3D call osgDB::readObjectFile(...) with an option
to specify the plugin we want an osgText::Font3D instead of
osgText::Font.

Generalised Problem:

In osgDB::Registry, loaded file cache is referenced by the name
of this file, so if I load a file with some options, and the cache
already contain object for this filename, I obtain an object
potentially not loaded with my options.

Behaviours:

Cache management is delegate to osgDB::Registry, but cache
coherence (load a file with option then reuse it, deactivate the
cache when load a specific file or don't cached the loaded file)
is user's responsibility.

Text3D solution:

Postfix the font file name by .text3d or something similar and then have the freetype plugin return
osgText::Font3D when it detects this.
This operation is done by osgText::readFont3DFile() which unsure the filename have .text3d as extension.
This is totaly transparent for user, and backward compatible.

BTW, I fix the bug about the Normal of 3D text. Currently, the front and wall face have
the same normal (0,0,1) in the Text3D object coordinate. Now the wall face have its own
normal array computed by the plugin.

BTW 2, I implement
- void Text3D::accept(osg::Drawable::ConstAttributeFunctor?& af) const
- void Text3D::accept(osg::PrimitiveFunctor?& pf) const
so now statistics are well reported.
"

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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
15
16#include <osgText/Font3D>
17#include <osgText/Text>
18
19//#include <osg/State>
20#include <osg/Notify>
21//#include <osg/ApplicationUsage>
22
23#include <osgDB/ReadFile>
24#include <osgDB/FileUtils>
25#include <osgDB/FileNameUtils>
26//#include <osg/GLU>
27
28#include <OpenThreads/ReentrantMutex>
29
30
31using namespace std;
32
33//static osg::ApplicationUsageProxy Font3D_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_TEXT3D_INCREMENTAL_SUBLOADING <type>","ON | OFF");
34
35static OpenThreads::ReentrantMutex s_Font3DFileMutex;
36
37namespace osgText
38{
39
40std::string findFont3DFile(const std::string& str)
41{
42    // try looking in OSGFILEPATH etc first for fonts.
43    std::string filename = osgDB::findDataFile(str);
44    if (!filename.empty()) return filename;
45
46    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(s_Font3DFileMutex);
47
48    static osgDB::FilePathList s_FontFilePath;
49    static bool initialized = false;
50    if (!initialized)
51    {
52        initialized = true;
53    #if defined(WIN32)
54        osgDB::convertStringPathIntoFilePathList(
55            ".;C:/winnt/fonts;C:/windows/fonts",
56            s_FontFilePath);
57
58        char *ptr;
59        if ((ptr = getenv( "windir" )))
60        {
61            std::string winFontPath = ptr;
62            winFontPath += "\\fonts";
63            s_FontFilePath.push_back(winFontPath);
64        }
65    #else
66        osgDB::convertStringPathIntoFilePathList(
67            ".:/usr/share/fonts/ttf:/usr/share/fonts/ttf/western:/usr/share/fonts/ttf/decoratives",
68            s_FontFilePath);
69    #endif
70    }
71
72    filename = osgDB::findFileInPath(str,s_FontFilePath);
73    if (!filename.empty()) return filename;
74
75    // Try filename without pathname, if it has a path
76    filename = osgDB::getSimpleFileName(str);
77    if(filename!=str)
78    {
79        filename = osgDB::findFileInPath(filename,s_FontFilePath);
80        if (!filename.empty()) return filename;
81    }
82    else
83    {
84        filename = osgText::findFont3DFile(std::string("fonts/")+filename);
85        if (!filename.empty()) return filename;
86    }
87
88    // Not found, return empty string
89    osg::notify(osg::WARN)<<"Warning: font file \""<<str<<"\" not found."<<std::endl;
90    return std::string();
91}
92
93osgText::Font3D* readFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
94{
95    if (filename=="") return 0;
96
97    // unsure filename have not .text3d at the end
98    std::string tmpFilename;
99    std::string text3dExt = ".text3d";
100    std::string ext = osgDB::getFileExtensionIncludingDot(filename);
101    if (ext == text3dExt)
102        tmpFilename = filename.substr(filename.size() - ext.size(), ext.size());
103    else
104        tmpFilename = filename;
105
106    //search font file
107    std::string foundFile = findFont3DFile(tmpFilename);
108    if (foundFile.empty()) return 0;
109
110    //unsure filename have .text3d at the end
111    foundFile += text3dExt;
112
113    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
114
115    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
116    if (!userOptions)
117    {
118        localOptions = new osgDB::ReaderWriter::Options;
119        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
120    }
121
122    osg::Object* object = osgDB::readObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
123
124    // if the object is a font then return it.
125    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
126    if (font3D) return font3D;
127
128    // otherwise if the object has zero references then delete it by doing another unref().
129    if (object && object->referenceCount()==0) object->unref();
130    return 0;
131}
132
133osgText::Font3D* readFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
134{
135    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
136
137    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
138    if (!userOptions)
139    {
140        localOptions = new osgDB::ReaderWriter::Options;
141        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
142        localOptions->setPluginData("3D", (void*) 1);
143    }
144    else
145    {
146        userOptions->setPluginData("3D", (void*) 1);
147    }
148
149    // there should be a better way to get the FreeType ReaderWriter by name...
150    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
151    if (reader == 0) return 0;
152
153    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
154    if (rr.error())
155    {
156        osg::notify(osg::WARN) << rr.message() << std::endl;
157        return 0;
158    }
159    if (!rr.validObject()) return 0;
160
161    osg::Object *object = rr.takeObject();
162
163    // if the object is a font then return it.
164    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
165    if (font3D) return font3D;
166
167    // otherwise if the object has zero references then delete it by doing another unref().
168    if (object && object->referenceCount()==0) object->unref();
169    return 0;
170}
171
172osg::ref_ptr<Font3D> readRefFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
173{
174    if (filename=="") return 0;
175
176    std::string tmpFilename;
177    std::string text3dExt = ".text3d";
178    std::string ext = osgDB::getFileExtensionIncludingDot(filename);
179    if (ext == text3dExt)
180        tmpFilename = filename.substr(0, filename.size() - ext.size());
181    else
182        tmpFilename = filename;
183
184    std::string foundFile = findFont3DFile(tmpFilename);
185    if (foundFile.empty()) return 0;
186
187    foundFile += text3dExt;
188
189    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
190
191    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
192    if (!userOptions)
193    {
194        localOptions = new osgDB::ReaderWriter::Options;
195        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
196    }
197
198    osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
199
200    // if the object is a font then return it.
201    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object.get());
202    if (font3D) return osg::ref_ptr<Font3D>(font3D);
203
204    return 0;
205}
206
207osg::ref_ptr<Font3D> readRefFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
208{
209    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
210
211    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
212    if (!userOptions)
213    {
214        localOptions = new osgDB::ReaderWriter::Options;
215        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
216        localOptions->setPluginData("3D", (void*) 1);
217    }
218    else
219    {
220        userOptions->setPluginData("3D", (void*) 1);
221    }
222
223    // there should be a better way to get the FreeType ReaderWriter by name...
224    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
225    if (reader == 0) return 0;
226
227    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
228    if (rr.error())
229    {
230        osg::notify(osg::WARN) << rr.message() << std::endl;
231        return 0;
232    }
233    if (!rr.validObject()) return 0;
234
235    // if the object is a font then return it.
236    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(rr.getObject());
237    if (font3D) return osg::ref_ptr<Font3D>(font3D);
238
239    return 0;
240}
241
242Font3D::Font3D(Font3DImplementation* implementation):
243    osg::Object(true),
244    _depth(1),
245    _width(64),
246    _height(64)
247{
248    setImplementation(implementation);
249}
250
251Font3D::~Font3D()
252{
253    if (_implementation.valid()) _implementation->_facade = 0;
254}
255
256void Font3D::setImplementation(Font3DImplementation* implementation)
257{
258    if (_implementation.valid()) _implementation->_facade = 0;
259    _implementation = implementation;
260    if (_implementation.valid()) _implementation->_facade = this;
261}
262
263Font3D::Font3DImplementation* Font3D::getImplementation()
264{
265    return _implementation.get();
266}
267
268const Font3D::Font3DImplementation* Font3D::getImplementation() const
269{
270    return _implementation.get();
271}
272
273std::string Font3D::getFileName() const
274{
275    if (_implementation.valid()) return _implementation->getFileName();
276    return "";
277}
278
279Font3D::Glyph3D* Font3D::getGlyph(unsigned int charcode)
280{
281    Glyph3D * glyph3D = NULL;
282
283    Glyph3DMap::iterator itr = _glyph3DMap.find(charcode);
284    if (itr!=_glyph3DMap.end()) glyph3D = itr->second.get();
285
286    else if (_implementation.valid())
287    {
288        glyph3D = _implementation->getGlyph(charcode);
289        if (glyph3D) _glyph3DMap[charcode] = glyph3D;
290    }
291
292    return glyph3D;
293}
294
295void Font3D::setThreadSafeRefUnref(bool threadSafe)
296{
297    Glyph3DMap::iterator it,end = _glyph3DMap.end();
298
299    for (it=_glyph3DMap.begin(); it!=end; ++it)
300        it->second->setThreadSafeRefUnref(threadSafe);
301}
302
303osg::Vec2 Font3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType)
304{
305    if (_implementation.valid()) return _implementation->getKerning(leftcharcode,rightcharcode,kerningType);
306    else return osg::Vec2(0.0f,0.0f);
307}
308bool Font3D::hasVertical() const
309{
310    if (_implementation.valid()) return _implementation->hasVertical();
311    else return false;
312}
313
314void Font3D::Glyph3D::setThreadSafeRefUnref(bool threadSafe)
315{
316    if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe);
317    if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe);
318}
319}
Note: See TracBrowser for help on using the browser.