📄 freetypefont3d.cpp
字号:
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details.*/#include "FreeTypeFont3D.h"#include "FreeTypeLibrary.h"#include <limits.h>#include <fstream>#include <osg/Geometry>#include <osg/Notify> #include <osgDB/WriteFile>#include <osgUtil/SmoothingVisitor>#include <osgUtil/Tessellator>#include <ft2build.h> #include FT_FREETYPE_H#include <freetype/ftoutln.h>#include <freetype/ftbbox.h>namespace{struct Char3DInfo{ Char3DInfo(int numSteps=50): _verts( new osg::Vec3Array ), _geometry( new osg::Geometry ), _idx(0), _numSteps(numSteps), _maxY(-FLT_MAX), _maxX(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX) { } ~Char3DInfo() { } osg::Geometry* get() { int len = _verts->size()-_idx; if (len) { _geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) ); _idx = _verts->size(); } _geometry->setVertexArray(_verts.get()); return _geometry.get(); } void moveTo(osg::Vec2 pos) { if (_verts->size()) { int len = _verts->size()-_idx; _geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) ); } _idx = _verts->size(); _verts->push_back( osg::Vec3(pos.x(),pos.y(),0) ); setMinMax(pos); } void lineTo(osg::Vec2 pos) { _verts->push_back( osg::Vec3(pos.x(),pos.y(),0) ); setMinMax(pos); } void conicTo(osg::Vec2 control, osg::Vec2 pos) { osg::Vec3 p0 = _verts->back(); osg::Vec3 p1 = osg::Vec3(control.x(),control.y(),0); osg::Vec3 p2 = osg::Vec3(pos.x(),pos.y(),0); double dt = 1.0/_numSteps; double u=0; for (int i=0; i<=_numSteps; ++i) { double w = 1; double bs = 1.0/( (1-u)*(1-u)+2*(1-u)*u*w +u*u ); osg::Vec3 p = (p0*((1-u)*(1-u)) + p1*(2*(1-u)*u*w) + p2*(u*u))*bs; _verts->push_back( p ); u += dt; } setMinMax(pos); } void cubicTo(osg::Vec2 control1, osg::Vec2 control2, osg::Vec2 pos) { osg::Vec3 p0 = _verts->back(); osg::Vec3 p1 = osg::Vec3(control1.x(),control1.y(),0); osg::Vec3 p2 = osg::Vec3(control2.x(),control2.y(),0); osg::Vec3 p3 = osg::Vec3(pos.x(),pos.y(),0); double cx = 3*(p1.x() - p0.x()); double bx = 3*(p2.x() - p1.x()) - cx; double ax = p3.x() - p0.x() - cx - bx; double cy = 3*(p1.y() - p0.y()); double by = 3*(p2.y() - p1.y()) - cy; double ay = p3.y() - p0.y() - cy - by; double dt = 1.0/_numSteps; double u=0; for (int i=0; i<=_numSteps; ++i) { osg::Vec3 p = osg::Vec3( ax*u*u*u + bx*u*u + cx*u + p0.x(),ay*u*u*u + by*u*u + cy*u + p0.y(),0 ); _verts->push_back( p ); u += dt; } setMinMax(pos); } void setMinMax(osg::Vec2 pos) { _maxY = std::max(_maxY, (double) pos.y()); _minY = std::min(_minY, (double) pos.y()); _maxX = std::max(_maxX, (double) pos.x()); _minX = std::min(_minX, (double) pos.x()); } osg::ref_ptr<osg::Vec3Array> _verts; osg::ref_ptr<osg::Geometry> _geometry; int _idx; int _numSteps; double _maxY; double _maxX; double _minX; double _minY;};#define FT_NUM(x) (x/64.0)int moveTo( const FT_Vector* to, void* user ){ Char3DInfo* char3d = (Char3DInfo*)user; char3d->moveTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) ); return 0;}int lineTo( const FT_Vector* to, void* user ){ Char3DInfo* char3d = (Char3DInfo*)user; char3d->lineTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) ); return 0;}int conicTo( const FT_Vector* control,const FT_Vector* to, void* user ){ Char3DInfo* char3d = (Char3DInfo*)user; char3d->conicTo( osg::Vec2(FT_NUM(control->x),FT_NUM(control->y)), osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) ); return 0;}int cubicTo( const FT_Vector* control1,const FT_Vector* control2,const FT_Vector* to, void* user ){ Char3DInfo* char3d = (Char3DInfo*)user; char3d->cubicTo( osg::Vec2(FT_NUM(control1->x),FT_NUM(control1->y)), osg::Vec2(FT_NUM(control2->x),FT_NUM(control2->y)), osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) ); return 0;}#undef FT_NUM}FreeTypeFont3D::FreeTypeFont3D(const std::string& filename, FT_Face face, unsigned int flags): _filename(filename), _buffer(0), _face(face), _flags(flags), _scale(1.0), _shiftY(0.0), _shiftX(0.0), _charScale(1.0){ init();}FreeTypeFont3D::FreeTypeFont3D(FT_Byte* buffer, FT_Face face, unsigned int flags): _filename(""), _buffer(buffer), _face(face), _flags(flags), _scale(1.0), _shiftY(0.0), _shiftX(0.0), _charScale(1.0){ init();}void FreeTypeFont3D::init(){ FT_Error _error = FT_Set_Pixel_Sizes(_face, 32, 32); if (_error) { osg::notify(osg::NOTICE) << "FreeTypeFont3D: set pixel sizes failed ..." << std::endl; return; } FT_Set_Char_Size( _face, 64*64, 64*64, 600, 600); int glyphIndex = FT_Get_Char_Index( _face, 'M' ); _error = FT_Load_Glyph( _face, glyphIndex, FT_LOAD_DEFAULT ); if (_error) { osg::notify(osg::NOTICE) << "FreeTypeFont3D: initial glyph load failed ..." << std::endl; return; } if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { osg::notify(osg::NOTICE) << "FreeTypeFont3D: not a vector font" << std::endl; return; } { 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; _error = FT_Outline_Decompose(&outline,&funcs,&char3d); if (_error) { osg::notify(osg::NOTICE) << "FreeTypeFont3D: - outline decompose failed ..." << std::endl; return; } FT_BBox bb; FT_Outline_Get_BBox(&outline,&bb); long xmin = ft_floor( bb.xMin ); long xmax = ft_ceiling( bb.xMax ); long ymin = ft_floor( bb.yMin ); long ymax = ft_ceiling( bb.yMax ); double width = (xmax - xmin)/64.0; double height = (ymax - ymin)/64.0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -