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

Revision 7874, 9.5 kB (checked in by robert, 7 years ago)

Refactored the mutex usage in osgText and freetype plugin to prevent multi-thread crash

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    std::string foundFile = findFont3DFile(filename);
98    if (foundFile.empty()) return 0;
99   
100    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
101
102    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
103    if (!userOptions)
104    {
105        localOptions = new osgDB::ReaderWriter::Options;
106        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
107        // ** HACK to load Font3D instead of Font
108        localOptions->setPluginData("3D", (void*) 1);
109    }
110    else
111    {
112        userOptions->setPluginData("3D", (void*) 1);
113    }
114
115    osg::Object* object = osgDB::readObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
116   
117    // if the object is a font then return it.
118    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
119    if (font3D) return font3D;
120
121    // otherwise if the object has zero references then delete it by doing another unref().
122    if (object && object->referenceCount()==0) object->unref();
123    return 0;
124}
125
126osgText::Font3D* readFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
127{
128    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
129
130    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
131    if (!userOptions)
132    {
133        localOptions = new osgDB::ReaderWriter::Options;
134        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
135        localOptions->setPluginData("3D", (void*) 1);
136    }
137    else
138    {
139        userOptions->setPluginData("3D", (void*) 1);
140    }
141
142    // there should be a better way to get the FreeType ReaderWriter by name...
143    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
144    if (reader == 0) return 0;
145   
146    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
147    if (rr.error())
148    {
149        osg::notify(osg::WARN) << rr.message() << std::endl;
150        return 0;
151    }
152    if (!rr.validObject()) return 0;
153   
154    osg::Object *object = rr.takeObject();
155
156    // if the object is a font then return it.
157    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
158    if (font3D) return font3D;
159
160    // otherwise if the object has zero references then delete it by doing another unref().
161    if (object && object->referenceCount()==0) object->unref();
162    return 0;
163}
164
165osg::ref_ptr<Font3D> readRefFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
166{
167    if (filename=="") return 0;
168
169    std::string foundFile = findFont3DFile(filename);
170    if (foundFile.empty()) return 0;
171   
172    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
173
174    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
175    if (!userOptions)
176    {
177        localOptions = new osgDB::ReaderWriter::Options;
178        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
179        // ** HACK to load Font3D instead of Font
180        localOptions->setPluginData("3D", (void*) 1);
181    }
182    else
183    {
184        userOptions->setPluginData("3D", (void*) 1);
185    }
186
187    osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
188   
189    // if the object is a font then return it.
190    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object.get());
191    if (font3D) return osg::ref_ptr<Font3D>(font3D);
192
193    return 0;
194}
195
196osg::ref_ptr<Font3D> readRefFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
197{
198    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
199
200    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
201    if (!userOptions)
202    {
203        localOptions = new osgDB::ReaderWriter::Options;
204        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
205        localOptions->setPluginData("3D", (void*) 1);
206    }
207    else
208    {
209        userOptions->setPluginData("3D", (void*) 1);
210    }
211
212    // there should be a better way to get the FreeType ReaderWriter by name...
213    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
214    if (reader == 0) return 0;
215   
216    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
217    if (rr.error())
218    {
219        osg::notify(osg::WARN) << rr.message() << std::endl;
220        return 0;
221    }
222    if (!rr.validObject()) return 0;
223
224    // if the object is a font then return it.
225    osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(rr.getObject());
226    if (font3D) return osg::ref_ptr<Font3D>(font3D);
227
228    return 0;
229}
230
231Font3D::Font3D(Font3DImplementation* implementation):
232    osg::Object(true),
233    _depth(1),
234    _width(64),
235    _height(64)
236{
237    setImplementation(implementation);
238}
239
240Font3D::~Font3D()
241{
242    if (_implementation.valid()) _implementation->_facade = 0;
243}
244
245void Font3D::setImplementation(Font3DImplementation* implementation)
246{
247    if (_implementation.valid()) _implementation->_facade = 0;
248    _implementation = implementation;
249    if (_implementation.valid()) _implementation->_facade = this;
250}
251
252Font3D::Font3DImplementation* Font3D::getImplementation()
253{
254    return _implementation.get();
255}
256
257const Font3D::Font3DImplementation* Font3D::getImplementation() const
258{
259    return _implementation.get();
260}
261
262std::string Font3D::getFileName() const
263{
264    if (_implementation.valid()) return _implementation->getFileName();
265    return "";
266}
267
268Font3D::Glyph3D* Font3D::getGlyph(unsigned int charcode)
269{
270    Glyph3D * glyph3D = NULL;
271   
272    Glyph3DMap::iterator itr = _glyph3DMap.find(charcode);
273    if (itr!=_glyph3DMap.end()) glyph3D = itr->second.get();
274   
275    else if (_implementation.valid())
276    {
277        glyph3D = _implementation->getGlyph(charcode);
278        if (glyph3D) _glyph3DMap[charcode] = glyph3D;
279    }
280   
281    return glyph3D;
282}
283
284void Font3D::setThreadSafeRefUnref(bool threadSafe)
285{
286    Glyph3DMap::iterator it,end = _glyph3DMap.end();
287   
288    for (it=_glyph3DMap.begin(); it!=end; ++it)
289        it->second->setThreadSafeRefUnref(threadSafe);
290}
291
292osg::Vec2 Font3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType)
293{
294    if (_implementation.valid()) return _implementation->getKerning(leftcharcode,rightcharcode,kerningType);
295    else return osg::Vec2(0.0f,0.0f);
296}
297bool Font3D::hasVertical() const
298{
299    if (_implementation.valid()) return _implementation->hasVertical();
300    else return false;
301}
302
303void Font3D::Glyph3D::setThreadSafeRefUnref(bool threadSafe)
304{
305    if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe);
306    if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe);
307}
308}
Note: See TracBrowser for help on using the browser.