📄 freetypefont3d.cpp
字号:
_scale = 1.0/height; double charHeight = char3d._maxY-char3d._minY; double charWidth = char3d._maxX-char3d._minX; double dh = fabs(bb.yMin/64.0)/height; double dw = fabs(bb.xMin/64.0)/width; _shiftY = char3d._minY + dh*charHeight; _shiftX = char3d._minX + dw*charWidth; _charScale = 1/charHeight; }}FreeTypeFont3D::~FreeTypeFont3D(){ if(_face) { FreeTypeLibrary* freeTypeLibrary = FreeTypeLibrary::instance(); if (freeTypeLibrary) { // remove myself from the local registry to ensure that // not dangling pointers remain freeTypeLibrary->removeFont3DImplmentation(this); // free the freetype font face itself FT_Done_Face(_face); _face = 0; // release memory held for FT_Face to work if (_buffer) { delete [] _buffer; _buffer = 0; } } }}osgText::Font3D::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode){ // // GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being // returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct // values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect. // Microsoft uses a private field for its symbol fonts // unsigned int charindex = charcode; if (_face->charmap != NULL) { if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL) { charindex |= 0xF000; } } FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_DEFAULT|_flags ); if (error) { osg::notify(osg::WARN) << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl; return 0; } if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl; return 0; } // ** init FreeType to describe the glyph Char3DInfo char3d; FT_Outline outline = _face->glyph->outline; FT_Outline_Funcs funcs; funcs.conic_to = (FT_Outline_ConicToFunc)&conicTo; funcs.line_to = (FT_Outline_LineToFunc)&lineTo; funcs.cubic_to = (FT_Outline_CubicToFunc)&cubicTo; funcs.move_to = (FT_Outline_MoveToFunc)&moveTo; funcs.shift = 0; funcs.delta = 0; // ** record description FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d); if (_error) { osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : - outline decompose failed ..." << std::endl; return 0; } // ** create geometry for each part of the glyph osg::ref_ptr<osg::Geometry> frontGeo(new osg::Geometry); frontGeo->setVertexArray(char3d.get()->getVertexArray()); frontGeo->setPrimitiveSetList(char3d.get()->getPrimitiveSetList()); osg::ref_ptr<osg::Geometry> wallGeo(new osg::Geometry); wallGeo->setVertexArray(frontGeo->getVertexArray()); osg::ref_ptr<osg::Geometry> backGeo(new osg::Geometry); backGeo->setVertexArray(frontGeo->getVertexArray()); // ** for conveniance. osg::Vec3Array * vertices = char3d._verts.get(); // ** duplicate the vertex for the back face // ** with a depth equal to the font depth std::size_t len = vertices->size(); std::size_t dlen = len * 2; vertices->reserve(dlen); osg::Vec3Array::iterator begin = vertices->begin(); osg::Vec3Array::iterator it = vertices->begin(); for (std::size_t i = 0; i != len; ++i, ++it) vertices->push_back(*it);// std::copy(begin, begin + len, begin + len + 1); TOCHECK // ** and decal new vertices unsigned int depth = _facade->getFontDepth(); for (std::size_t i = len; i != dlen; ++i) { (*vertices)[i].z() -= depth; } osg::Vec3Array::iterator end; // ** create wall and back face from the front polygon // ** then accumulate them in the apropriate geometry wallGeo and backGeo for (std::size_t i=0; i < frontGeo->getNumPrimitiveSets(); ++i) { // ** get the front polygon osg::ref_ptr<osg::DrawArrays> daFront(dynamic_cast<osg::DrawArrays*>(frontGeo->getPrimitiveSet(i))); unsigned int idx = daFront->getFirst(); unsigned int cnt = daFront->getCount(); // ** reverse vertices to draw the front face in the CCW std::reverse(begin + idx, begin + idx + cnt); // ** create the back polygon osg::ref_ptr<osg::DrawArrays> daBack(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, idx + len, cnt)); backGeo->addPrimitiveSet(daBack.get()); // ** create the wall triangle strip osg::ref_ptr<osg::DrawElementsUInt> deWall(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP)); wallGeo->addPrimitiveSet(deWall.get()); // ** link triangle strip deWall->push_back(idx + len); for (unsigned int j = 1; j < cnt; ++j) { deWall->push_back(idx + cnt - j); deWall->push_back(idx + len + j); } deWall->push_back(idx); deWall->push_back(idx + len); deWall->push_back(idx + cnt - 1); } // ** tesselate front and back face { osgUtil::Tessellator ts; ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE); ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY); ts.retessellatePolygons(*frontGeo); } { osgUtil::Tessellator ts; ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE); ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY); ts.retessellatePolygons(*backGeo); } // ** generate normal { osgUtil::SmoothingVisitor sm; osg::ref_ptr<osg::Geode> geode(new osg::Geode); geode->addDrawable(wallGeo.get()); geode->accept(sm); } // ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list osgText::Font3D::Glyph3D * glyph3D = new osgText::Font3D::Glyph3D(charcode); glyph3D->setVertexArray(dynamic_cast<osg::Vec3Array*>(frontGeo->getVertexArray())); glyph3D->getFrontPrimitiveSetList() = frontGeo->getPrimitiveSetList(); glyph3D->getWallPrimitiveSetList() = wallGeo->getPrimitiveSetList(); glyph3D->getBackPrimitiveSetList() = backGeo->getPrimitiveSetList(); FT_Glyph_Metrics* metrics = &(_face->glyph->metrics); glyph3D->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX/64.0f,(float)(metrics->horiBearingY-metrics->height)/64.0f)); // bottom left. glyph3D->setHorizontalAdvance((float)metrics->horiAdvance/64.0f); glyph3D->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX/64.0f,(float)(metrics->vertBearingY-metrics->height)/64.0f)); // top middle. glyph3D->setVerticalAdvance((float)metrics->vertAdvance/64.0f); glyph3D->setWidth((float)metrics->width / 64.0f); glyph3D->setHeight((float)metrics->height / 64.0f); FT_BBox ftbb; FT_Outline_Get_BBox(&outline, &ftbb); long xmin = ft_floor( ftbb.xMin ); long xmax = ft_ceiling( ftbb.xMax ); long ymin = ft_floor( ftbb.yMin ); long ymax = ft_ceiling( ftbb.yMax ); osg::BoundingBox bb(xmin / 64.0f, ymin / 64.0f, 0.0f, xmax / 64.0f, ymax / 64.0f, 0.0f); glyph3D->setBoundingBox(bb); return glyph3D;}osg::Vec2 FreeTypeFont3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType){ if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f); FT_Kerning_Mode mode = (kerningType==osgText::KERNING_DEFAULT) ? ft_kerning_default : ft_kerning_unfitted; // convert character code to glyph index FT_UInt left = FT_Get_Char_Index( _face, leftcharcode ); FT_UInt right = FT_Get_Char_Index( _face, rightcharcode ); // get the kerning distances. FT_Vector kerning; FT_Error error = FT_Get_Kerning( _face, // handle to face object left, // left glyph index right, // right glyph index mode, // kerning mode &kerning ); // target vector if (error) { osg::notify(osg::WARN) << "FT_Get_Kerning(...) returned error code " <<std::hex<<error<<std::dec<< std::endl; return osg::Vec2(0.0f,0.0f); } return osg::Vec2((float)kerning.x/64.0f,(float)kerning.y/64.0f);}bool FreeTypeFont3D::hasVertical() const{ return FT_HAS_VERTICAL(_face)!=0;}float FreeTypeFont3D::getScale() const { return _scale; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -