| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | #include <osgText/Font3D> |
|---|
| 17 | #include <osgText/Text> |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | #include <osg/Notify> |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | #include <osgDB/ReadFile> |
|---|
| 24 | #include <osgDB/FileUtils> |
|---|
| 25 | #include <osgDB/FileNameUtils> |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | #include <OpenThreads/ReentrantMutex> |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | using namespace std; |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | static OpenThreads::ReentrantMutex s_Font3DFileMutex; |
|---|
| 36 | |
|---|
| 37 | namespace osgText |
|---|
| 38 | { |
|---|
| 39 | |
|---|
| 40 | std::string findFont3DFile(const std::string& str) |
|---|
| 41 | { |
|---|
| 42 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 89 | osg::notify(osg::WARN)<<"Warning: font file \""<<str<<"\" not found."<<std::endl; |
|---|
| 90 | return std::string(); |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | osgText::Font3D* readFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions) |
|---|
| 94 | { |
|---|
| 95 | if (filename=="") return 0; |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 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 | |
|---|
| 107 | std::string foundFile = findFont3DFile(tmpFilename); |
|---|
| 108 | if (foundFile.empty()) return 0; |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 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 | |
|---|
| 125 | osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object); |
|---|
| 126 | if (font3D) return font3D; |
|---|
| 127 | |
|---|
| 128 | |
|---|
| 129 | if (object && object->referenceCount()==0) object->unref(); |
|---|
| 130 | return 0; |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | osgText::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 | |
|---|
| 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 | |
|---|
| 164 | osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object); |
|---|
| 165 | if (font3D) return font3D; |
|---|
| 166 | |
|---|
| 167 | |
|---|
| 168 | if (object && object->referenceCount()==0) object->unref(); |
|---|
| 169 | return 0; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | osg::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 | |
|---|
| 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 | |
|---|
| 207 | osg::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 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 242 | Font3D::Font3D(Font3DImplementation* implementation): |
|---|
| 243 | osg::Object(true), |
|---|
| 244 | _depth(1), |
|---|
| 245 | _width(64), |
|---|
| 246 | _height(64) |
|---|
| 247 | { |
|---|
| 248 | setImplementation(implementation); |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | Font3D::~Font3D() |
|---|
| 252 | { |
|---|
| 253 | if (_implementation.valid()) _implementation->_facade = 0; |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | void Font3D::setImplementation(Font3DImplementation* implementation) |
|---|
| 257 | { |
|---|
| 258 | if (_implementation.valid()) _implementation->_facade = 0; |
|---|
| 259 | _implementation = implementation; |
|---|
| 260 | if (_implementation.valid()) _implementation->_facade = this; |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | Font3D::Font3DImplementation* Font3D::getImplementation() |
|---|
| 264 | { |
|---|
| 265 | return _implementation.get(); |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | const Font3D::Font3DImplementation* Font3D::getImplementation() const |
|---|
| 269 | { |
|---|
| 270 | return _implementation.get(); |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | std::string Font3D::getFileName() const |
|---|
| 274 | { |
|---|
| 275 | if (_implementation.valid()) return _implementation->getFileName(); |
|---|
| 276 | return ""; |
|---|
| 277 | } |
|---|
| 278 | |
|---|
| 279 | Font3D::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 | |
|---|
| 295 | void 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 | |
|---|
| 303 | osg::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 | } |
|---|
| 308 | bool Font3D::hasVertical() const |
|---|
| 309 | { |
|---|
| 310 | if (_implementation.valid()) return _implementation->hasVertical(); |
|---|
| 311 | else return false; |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | void Font3D::Glyph3D::setThreadSafeRefUnref(bool threadSafe) |
|---|
| 315 | { |
|---|
| 316 | if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe); |
|---|
| 317 | if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe); |
|---|
| 318 | } |
|---|
| 319 | } |
|---|