Warning, /include/Geant4/toolx/sg/text_freetype is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef toolx_sg_text_freetype
0005 #define toolx_sg_text_freetype
0006
0007 //#define TOOLX_DONE_FACE
0008
0009 #include <tools/sg/base_freetype>
0010 #include <tools/sg/render_action>
0011 #include <tools/sg/pick_action>
0012 #include <tools/sg/bbox_action>
0013 #include <tools/sg/enums>
0014 #include <tools/lina/vec3d>
0015 #include <tools/fmanip>
0016 #include <tools/nostream>
0017 #include <tools/lina/box_3f>
0018
0019 // font_pixmap :
0020 #include <tools/sg/group>
0021 #include <tools/sg/blend>
0022 #include <tools/sg/tex_quadrilateral>
0023 #include <tools/platform> //for APPLE TargetConditionals.h
0024
0025 #include <tools/glutess/glutess>
0026
0027 #include <map> //for errors
0028
0029 #ifndef SWIG
0030 #include <ft2build.h>
0031 #include FT_FREETYPE_H
0032 #include FT_GLYPH_H
0033 #include FT_OUTLINE_H
0034 #endif
0035
0036 //#define TOOLX_SG_TEXT_FREETYPE_DEBUG
0037
0038 namespace toolx {
0039 namespace sg {
0040
0041 class text_freetype : public tools::sg::base_freetype {
0042 TOOLS_NODE(text_freetype,toolx::sg::text_freetype,tools::sg::base_freetype)
0043 protected:
0044 text_freetype& self() const {return const_cast<text_freetype&>(*this);}
0045 protected:
0046 TOOLS_CLASS_STRING(TOOLS_FONT_PATH)
0047 protected:
0048 enum wndg_type {
0049 wndg_ccw,
0050 wndg_cw,
0051 wndg_not_done
0052 };
0053 protected: //gstos
0054 virtual unsigned int create_gsto(std::ostream& a_out,tools::sg::render_manager& a_mgr) {
0055 std::vector<float> gsto_data;
0056
0057 {tools_vforcit(line_t,m_lines,it) {
0058 const line_t& item = *it;
0059 size_t pos = item.first;
0060 size_t num = item.second;
0061
0062 if(num<2) {
0063 a_out << "toolx::sg::text_freetype::create_gsto :"
0064 << " strange line with " << num << " points."
0065 << std::endl;
0066 continue; //do we have the case num = 1 ?
0067 }
0068
0069 const float* data = tools::vec_data<float>(m_xys)+pos;
0070
0071 // data is a line_strip(), convert it to lines.
0072
0073 size_t nsegs = num-1;
0074
0075 size_t ngsto = nsegs*2*3; //3 = have a z (Windows GL).
0076 size_t sz = gsto_data.size();
0077 gsto_data.resize(sz+ngsto);
0078 float* pxyz = tools::vec_data<float>(gsto_data)+sz;
0079
0080 tools::gl::line_strip_to_lines_2to3(num,data,pxyz);
0081 }}
0082
0083 m_gsto_lines_sz = gsto_data.size();
0084
0085 {tools_vforcit(gl_triangle_t,m_triangles,it) {
0086 const std::pair<GLUenum,triangle_t>& item = *it;
0087 size_t pos = item.second.first;
0088 size_t num = item.second.second;
0089
0090 if(num<3) {
0091 a_out << "toolx::sg::text_freetype::create_gsto :"
0092 << " strange triangle primitive with " << num << " points."
0093 << " Primitive kind is " << (*it).first << "."
0094 << std::endl;
0095 continue;
0096 }
0097
0098 const float* data = tools::vec_data<float>(m_xys)+pos;
0099
0100 if((*it).first==tools::gl::triangles()) {
0101
0102 size_t ntri = num/3;
0103
0104 size_t ngsto = ntri*3*3;
0105 size_t sz = gsto_data.size();
0106 gsto_data.resize(sz+ngsto);
0107 float* pxyz = tools::vec_data<float>(gsto_data)+sz;
0108
0109 tools::gl::cvt_2to3(num,data,pxyz);
0110
0111 } else if((*it).first==tools::gl::triangle_fan()) {
0112
0113 size_t ntri = num-2;
0114
0115 size_t ngsto = ntri*3*3;
0116 size_t sz = gsto_data.size();
0117 gsto_data.resize(sz+ngsto);
0118 float* pxyz = tools::vec_data<float>(gsto_data)+sz;
0119
0120 tools::gl::triangle_fan_to_triangles_2to3(num,data,pxyz);
0121
0122 } else if((*it).first==tools::gl::triangle_strip()) {
0123
0124 size_t ntri = num-2;
0125
0126 size_t ngsto = ntri*3*3;
0127 size_t sz = gsto_data.size();
0128 gsto_data.resize(sz+ngsto);
0129 float* pxyz = tools::vec_data<float>(gsto_data)+sz;
0130
0131 tools::gl::triangle_strip_to_triangles_2to3(num,data,pxyz);
0132
0133 } else {
0134 a_out << "toolx::sg::text_freetype::create_gsto :"
0135 << " unknown triangle primitive kind " << (*it).first << "."
0136 << std::endl;
0137 }
0138
0139 }}
0140
0141 m_gsto_sz = gsto_data.size();
0142
0143 if(gsto_data.empty()) {
0144 //a_out << "toolx::sg::text_freetype::create_gsto :"
0145 // << " empty buffer."
0146 // << std::endl;
0147 return 0;
0148 }
0149
0150 return a_mgr.create_gsto_from_data(gsto_data);
0151 }
0152
0153 public:
0154 virtual void render(tools::sg::render_action& a_action) {
0155 {bool _color_touched = color_touched(a_action.state());
0156 bool _char_height_touched = char_height_touched(a_action.state());
0157 if(touched()||_color_touched||_char_height_touched) {
0158 update_sg(a_action.out(),font.touched());
0159 reset_touched();
0160 }}
0161
0162 const tools::sg::state& state = a_action.state();
0163
0164 if(m_wndg==wndg_ccw) a_action.set_winding(tools::sg::winding_ccw);
0165 else if(m_wndg==wndg_cw) a_action.set_winding(tools::sg::winding_cw);
0166
0167 if(state.m_use_gsto) {
0168 unsigned int _id = get_gsto_id(a_action.out(),a_action.render_manager());
0169 if(_id) {
0170 a_action.begin_gsto(_id);
0171 size_t sz_tris = m_gsto_sz-m_gsto_lines_sz;
0172 if(m_gsto_lines_sz) {
0173 a_action.set_line_smooth(true);
0174 a_action.draw_gsto_v(tools::gl::lines(),m_gsto_lines_sz/3,0);
0175 a_action.set_polygon_offset(true);
0176 }
0177 if(m_gsto_lines_sz && sz_tris) {
0178 a_action.set_line_smooth(state.m_GL_LINE_SMOOTH);
0179 a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
0180 }
0181 tools::sg::bufpos pos = m_gsto_lines_sz*sizeof(float);
0182 a_action.draw_gsto_v(tools::gl::triangles(),sz_tris/3,pos);
0183 a_action.end_gsto();
0184
0185 a_action.set_line_smooth(state.m_GL_LINE_SMOOTH);
0186 a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
0187 a_action.set_winding(state.m_winding);
0188 return;
0189 } else {
0190 // use immediate rendering.
0191 }
0192 } else {
0193 clean_gstos(&a_action.render_manager());
0194 }
0195
0196 // immediate rendering :
0197
0198 ///////////////////////////////////////////////////////////
0199 /// lines /////////////////////////////////////////////////
0200 ///////////////////////////////////////////////////////////
0201
0202 a_action.set_line_smooth(true);
0203
0204 {tools_vforcit(line_t,m_lines,it) {
0205 const line_t& item = *it;
0206 size_t pos = item.first;
0207 size_t num = item.second;
0208 if(!num) continue;
0209 //a_out << "toolx::sg::text_freetype::render :"
0210 // << " num points " << num
0211 // << std::endl;
0212
0213 const float* data = tools::vec_data<float>(m_xys)+pos;
0214
0215 a_action.draw_vertex_array_xy(tools::gl::line_strip(),num*2,data);
0216 }}
0217
0218 if(m_lines.size()) a_action.set_polygon_offset(true);
0219
0220 ///////////////////////////////////////////////////////////
0221 /// triangles /////////////////////////////////////////////
0222 ///////////////////////////////////////////////////////////
0223 {tools_vforcit(gl_triangle_t,m_triangles,it) {
0224 const std::pair<GLUenum,triangle_t>& item = *it;
0225 size_t pos = item.second.first;
0226 size_t num = item.second.second;
0227 if(!num) continue;
0228 //a_out << "toolx::sg::text_freetype::render :"
0229 // << " num points " << num
0230 // << std::endl;
0231
0232 const float* data = tools::vec_data<float>(m_xys)+pos;
0233
0234 a_action.draw_vertex_array_xy((*it).first,num*2,data);
0235 }}
0236
0237 a_action.set_line_smooth(state.m_GL_LINE_SMOOTH);
0238 a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
0239 a_action.set_winding(state.m_winding);
0240
0241 ///////////////////////////////////////////////////////////
0242 /// bitmap ////////////////////////////////////////////////
0243 ///////////////////////////////////////////////////////////
0244 #if defined(ANDROID) /*|| TARGET_OS_IPHONE*/
0245 // we do not have transparent texture here (see also gl/tex_img() that does img/4-bytes => img/3-bytes) :
0246 {tools::sg::state& _state = a_action.state();
0247 tools::colorf old_color = _state.m_color;
0248 _state.m_color = tools::colorf_white();
0249 a_action.color4f(_state.m_color);
0250 m_bitmaps.render(a_action);
0251 _state.m_color = old_color;
0252 a_action.color4f(_state.m_color);}
0253 #else
0254 m_bitmaps.render(a_action);
0255 #endif
0256 }
0257
0258 virtual void pick(tools::sg::pick_action& a_action) {
0259 {bool _char_height_touched = char_height_touched(a_action.state());
0260 if(touched()||_char_height_touched) {
0261 update_sg(a_action.out(),font.touched());
0262 reset_touched();
0263 }}
0264
0265 /*
0266 //OPTIMIZATION : pick on the bounding box ?
0267 if(m_face) {
0268 tools::box3f box;
0269 get_bounds(m_face,height,strings.values(),box);
0270
0271 vec3f mn = box.mn();
0272 vec3f mx = box.mx();
0273
0274 mn = mtx*mn;
0275 mx = mtx*mx;
0276
0277 if(a_action.is_inside(b[0],b[1])) {
0278 //we have a pick.
0279 a_action.set_done(true);
0280 a_action.set_node(this);
0281 return;
0282 }
0283
0284 if(a_action.intersect(p1[0],p1[1],p2[0],p2[1],p3[0],p3[1])) {
0285 a_action.set_done(true);
0286 a_action.set_node(this);
0287 return;
0288 }
0289 }
0290 return;
0291 */
0292
0293 ///////////////////////////////////////////////////////////
0294 /// lines /////////////////////////////////////////////////
0295 ///////////////////////////////////////////////////////////
0296
0297 {tools_vforcit(line_t,m_lines,it) {
0298 const line_t& item = *it;
0299 size_t pos = item.first;
0300 size_t num = item.second;
0301 const float* data = tools::vec_data<float>(m_xys)+pos;
0302 if(a_action.add__line_strip_xy(*this,2*num,data,true)) return;
0303 }}
0304
0305
0306 ///////////////////////////////////////////////////////////
0307 /// triangles /////////////////////////////////////////////
0308 ///////////////////////////////////////////////////////////
0309 {tools_vforcit(gl_triangle_t,m_triangles,it) {
0310 const std::pair<GLUenum,triangle_t>& item = *it;
0311 size_t pos = item.second.first;
0312 size_t num = item.second.second;
0313 const float* data = tools::vec_data<float>(m_xys)+pos;
0314 if(a_action.add__primitive_xy(*this,item.first,2*num,data,true)) return;
0315 }}
0316
0317 ///////////////////////////////////////////////////////////
0318 /// bitmap ////////////////////////////////////////////////
0319 ///////////////////////////////////////////////////////////
0320 m_bitmaps.pick(a_action);
0321 }
0322
0323 virtual void bbox(tools::sg::bbox_action& a_action) {
0324 {bool _char_height_touched = char_height_touched(a_action.state());
0325 if(touched()||_char_height_touched) {
0326 update_sg(a_action.out(),font.touched());
0327 reset_touched();
0328 }}
0329
0330 {tools_vforcit(line_t,m_lines,it) {
0331 const line_t& item = *it;
0332 size_t num = item.second;
0333 const float* data = tools::vec_data<float>(m_xys)+item.first;
0334
0335 float px,py,pz;
0336 float* pos = (float*)data;
0337 for(size_t index=0;index<num;index++) {
0338 px = *pos;pos++;
0339 py = *pos;pos++;
0340 pz = 0;
0341 a_action.add_one_point(px,py,pz);
0342 }
0343
0344 }}
0345
0346 ///////////////////////////////////////////////////////////
0347 /// triangles /////////////////////////////////////////////
0348 ///////////////////////////////////////////////////////////
0349 {tools_vforcit(gl_triangle_t,m_triangles,it) {
0350 const std::pair<GLUenum,triangle_t>& item = *it;
0351 size_t num = item.second.second;
0352 const float* data = tools::vec_data<float>(m_xys)+item.second.first;
0353
0354 float px,py,pz;
0355 float* pos = (float*)data;
0356 for(size_t index=0;index<num;index++) {
0357 px = *pos;pos++;
0358 py = *pos;pos++;
0359 pz = 0;
0360 a_action.add_one_point(px,py,pz);
0361 }
0362 }}
0363
0364 ///////////////////////////////////////////////////////////
0365 /// bitmap ////////////////////////////////////////////////
0366 ///////////////////////////////////////////////////////////
0367 m_bitmaps.bbox(a_action);
0368 }
0369
0370 public:
0371 text_freetype()
0372 :parent()
0373
0374 ,m_library(0)
0375 ,m_face(0)
0376 ,m_encoding_offset(0)
0377 ,m_verbose(false)
0378 ,m_scale(1)
0379 ,m_pos(0)
0380 ,m_char_height(0)
0381 {
0382 if(!initialize()){} //throw
0383 }
0384 virtual ~text_freetype(){
0385 if(m_face) ::FT_Done_Face(m_face);
0386 if(m_library) ::FT_Done_FreeType(m_library);
0387 clear_trids();
0388 }
0389 public:
0390 text_freetype(const text_freetype& a_from)
0391 :parent(a_from)
0392
0393 ,m_library(0)
0394 ,m_face(0)
0395 ,m_encoding_offset(0)
0396 ,m_verbose(a_from.m_verbose)
0397 ,m_scale(1)
0398 ,m_pos(0)
0399 ,m_char_height(0)
0400 {
0401 if(!initialize()){} //throw
0402 }
0403
0404 text_freetype& operator=(const text_freetype& a_from){
0405 parent::operator=(a_from);
0406 if(&a_from==this) return *this;
0407
0408 if(m_face) {::FT_Done_Face(m_face);m_face = 0;}
0409 if(m_library) {::FT_Done_FreeType(m_library);m_library = 0;}
0410 clear_trids();
0411
0412 m_encoding_offset = 0;
0413 m_verbose = a_from.m_verbose;
0414 m_scale = 1;
0415 m_char_height = 0;
0416
0417 if(!initialize()){} //throw
0418
0419 return *this;
0420 }
0421 public: //tools::sg::base_text :
0422 virtual float ascent(float a_height) const {
0423 tools::nostream out;
0424 if(!m_face) self().load_face(out);
0425 if(!m_face) return 0;
0426 float value;
0427 if(!ascent(out,self().m_face,a_height,value)) return 0;
0428 #ifdef TOOLX_DONE_FACE
0429 ::FT_Done_Face(m_face);
0430 self().m_face = 0;
0431 #endif
0432 return value;
0433 }
0434
0435 virtual float descent(float a_height) const {
0436 tools::nostream out;
0437 if(!m_face) self().load_face(out);
0438 if(!m_face) return 0;
0439 float value;
0440 if(!descent(out,self().m_face,a_height,value)) return 0;
0441 #ifdef TOOLX_DONE_FACE
0442 ::FT_Done_Face(m_face);
0443 self().m_face = 0;
0444 #endif
0445 return value;
0446 }
0447
0448 virtual float y_advance(float a_height) const {
0449 tools::nostream out;
0450 if(!m_face) self().load_face(out);
0451 if(!m_face) return 0;
0452 float value;
0453 if(!y_advance(out,self().m_face,a_height,value)) return 0;
0454 #ifdef TOOLX_DONE_FACE
0455 ::FT_Done_Face(m_face);
0456 self().m_face = 0;
0457 #endif
0458 return value;
0459 }
0460
0461 virtual void get_bounds(float a_height,
0462 float& a_mn_x,float& a_mn_y,float& a_mn_z,
0463 float& a_mx_x,float& a_mx_y,float& a_mx_z) const {
0464 tools::nostream out;
0465 if(!m_face) self().load_face(out);
0466 if(!m_face) return;
0467 if(strings.values().size()) {
0468 if(!get_bounds(out,self().m_face,a_height,strings.values(),a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z)) return;
0469 } else if(unitext.values().size()) {
0470 if(!get_bounds(out,self().m_face,a_height,unitext.values(),a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z)) return;
0471 }
0472 #ifdef TOOLX_DONE_FACE
0473 ::FT_Done_Face(m_face);
0474 self().m_face = 0;
0475 #endif
0476 }
0477
0478 virtual bool truncate(const std::string& a_string,float a_height,float a_cut_width,std::string& a_out) const {
0479 a_out.clear();
0480 tools::nostream out;
0481 if(!m_face) self().load_face(out);
0482 if(!m_face) return false;
0483 if(!truncate(out,self().m_face,a_height,a_string,a_cut_width,a_out)) return false;
0484 #ifdef TOOLX_DONE_FACE
0485 ::FT_Done_Face(m_face);
0486 self().m_face = 0;
0487 #endif
0488 return true;
0489 }
0490
0491 void dump_unitext(std::ostream& a_out) {
0492 //unitext.values().size()
0493 a_out << "unitext size : " << unitext.values().size() << std::endl;
0494 tools_vforcit(uniline,unitext.values(),vit) {
0495 const uniline& line = *vit;
0496 a_out << "beg line :" << std::endl;
0497 //a_out << line << std::endl;
0498 tools_vforcit(unichar,line,it) {
0499 a_out << ((unsigned int)*it) << std::endl;
0500 }
0501 a_out << "end line." << std::endl;
0502 }
0503 }
0504
0505 protected:
0506 bool initialize() { //called from constructors.
0507 FT_Error error = ::FT_Init_FreeType(&m_library);
0508 if(error) {
0509 //m_out << "toolx::sg::text_freetype :"
0510 // << " error : " << serror(error) << "."
0511 // << std::endl;
0512 m_library = 0;
0513 return false;
0514 }
0515 // cast because of const/not const according freetype version.
0516 // (Recent version have "const FT_Vector*" in args).
0517 m_funcs.move_to = (FT_Outline_MoveToFunc)outline_move_to;
0518 m_funcs.line_to = (FT_Outline_LineToFunc)outline_line_to;
0519 m_funcs.conic_to = (FT_Outline_ConicToFunc)outline_conic_to;
0520 m_funcs.cubic_to = (FT_Outline_CubicToFunc)outline_cubic_to;
0521 m_funcs.shift = 0;
0522 m_funcs.delta = 0;
0523
0524 // Comment from OGLFT :
0525 // Default number of steps to break TrueType and Type1 arcs into.
0526 // (Note: this looks good to me, anyway)
0527 m_steps = 4;
0528 m_delta = 1.0f /(float)m_steps;
0529 m_delta2 = m_delta * m_delta;
0530 m_delta3 = m_delta2 * m_delta;
0531
0532 return true;
0533 }
0534
0535 ////////////////////////////////////////////////////////
0536 /// outline lines //////////////////////////////////////
0537 ////////////////////////////////////////////////////////
0538 enum update_what {
0539 faces = 0,
0540 lines = 1,
0541 faces_and_lines
0542 };
0543
0544 bool color_touched(const tools::sg::state& a_state) {
0545 if(modeling!=tools::sg::font_pixmap) return false;
0546 if(a_state.m_color==m_front_color) return false;
0547 m_front_color = a_state.m_color;
0548 return true;
0549 }
0550
0551 bool char_height_touched(const tools::sg::state& a_state) {
0552 if(modeling!=tools::sg::font_pixmap) return false;
0553
0554 float ymn,ymx;
0555 {float x,y,z,w;
0556 x = 0;y = -height.value()*0.5f;z = 0;
0557 if(!a_state.project_point(x,y,z,w)) return false;
0558 ymn = y;
0559 x = 0;y = height.value()*0.5f;z = 0;
0560 if(!a_state.project_point(x,y,z,w)) return false;
0561 ymx = y;}
0562 float screen_height = ymx-ymn;
0563 if(a_state.m_wh) screen_height *= a_state.m_wh; else screen_height = 100;
0564
0565 //::printf("debug : char_height_touched %g\n",screen_height);
0566
0567 if(screen_height==m_char_height) return false;
0568 m_char_height = screen_height;
0569 return true;
0570 }
0571
0572 void update_sg(std::ostream& a_out,bool a_load_font) {
0573 if(a_load_font) load_face(a_out);
0574
0575 clean_gstos(); //must reset for all render_manager.
0576
0577 if(!m_face) return;
0578
0579 //a_out << "toolx::sg::text_freetype::update_sg :"
0580 // << " font file opened."
0581 // << std::endl;
0582
0583 m_encoding_offset = 0;
0584 if(!encoding_offset(m_face,m_encoding_offset)) {
0585 a_out << "toolx::sg::text_freetype::update_sg :"
0586 << " encoding_offset failed."
0587 << std::endl;
0588 ::FT_Done_Face(m_face);
0589 m_face = 0;
0590 return;
0591 }
0592
0593 m_xys.clear();
0594 m_pos = 0;
0595 m_lines.clear();
0596 m_triangles.clear();
0597 m_bitmaps.clear();
0598 m_tqs.clear();
0599
0600 m_wndg = wndg_not_done;
0601
0602 if(modeling==tools::sg::font_pixmap) {
0603 if(m_char_height<=0) return;
0604 tools::sg::blend* blend = new tools::sg::blend;
0605 blend->on = true; //to handle background transparency.
0606 m_bitmaps.add(blend);
0607 if(!bitmap_2_gl(a_out)) {m_bitmaps.clear();m_tqs.clear();return;}
0608 } else {
0609 update_what _what = lines;
0610 //if(modeling==tools::sg::font_filled) _what = faces_and_lines;
0611 if(modeling==tools::sg::font_filled) _what = faces;
0612 if((_what==faces)||(_what==faces_and_lines)) outline_triangles_2_gl(a_out);
0613 if((_what==lines)||(_what==faces_and_lines)) outline_lines_2_gl(a_out);
0614 }
0615
0616 if(vjust==tools::sg::bottom) {
0617 } else if(vjust==tools::sg::middle) {
0618 float mn_x,mn_y,mn_z;
0619 float mx_x,mx_y,mx_z;
0620 get_bounds(height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0621 float szy = mx_y - mn_y;
0622
0623 {tools_vforit(line_t,m_lines,it) {
0624 line_t& item = *it;
0625 size_t pos = item.first;
0626 size_t npt = item.second;
0627 float* data = tools::vec_data<float>(m_xys)+pos+1;
0628 for(size_t i=0;i<npt;i++,data+=2) *data -= 0.5F * szy;
0629 }}
0630
0631 {tools_vforit(gl_triangle_t,m_triangles,it) {
0632 std::pair<GLUenum,triangle_t>& item = *it;
0633 size_t pos = item.second.first;
0634 size_t npt = item.second.second;
0635 float* data = tools::vec_data<float>(m_xys)+pos+1;
0636 for(size_t i=0;i<npt;i++,data+=2) *data -= 0.5F * szy;
0637 }}
0638
0639 {tools_vforcit(tools::sg::tex_quadrilateral*,m_tqs,itqs) {
0640 std::vector<tools::vec3f>& vcs = (*itqs)->corners.values();
0641 for(size_t i=0;i<4;i++) vcs[i][1] -= 0.5f * szy;
0642 }}
0643
0644 } else if(vjust==tools::sg::top) {
0645 float mn_x,mn_y,mn_z;
0646 float mx_x,mx_y,mx_z;
0647 get_bounds(height,mn_x,mn_y,mn_z,mx_x,mx_y,mx_z);
0648 float szy = mx_y - mn_y;
0649
0650 {tools_vforit(line_t,m_lines,it) {
0651 line_t& item = *it;
0652 size_t pos = item.first;
0653 size_t npt = item.second;
0654 float* data = tools::vec_data<float>(m_xys)+pos+1;
0655 for(size_t i=0;i<npt;i++,data+=2) *data -= szy;
0656 }}
0657
0658 {tools_vforit(gl_triangle_t,m_triangles,it) {
0659 std::pair<GLUenum,triangle_t>& item = *it;
0660 size_t pos = item.second.first;
0661 size_t npt = item.second.second;
0662 float* data = tools::vec_data<float>(m_xys)+pos+1;
0663 for(size_t i=0;i<npt;i++,data+=2) *data -= szy;
0664 }}
0665
0666 {tools_vforcit(tools::sg::tex_quadrilateral*,m_tqs,itqs) {
0667 std::vector<tools::vec3f>& vcs = (*itqs)->corners.values();
0668 for(size_t i=0;i<4;i++) vcs[i][1] -= szy;
0669 }}
0670
0671 }
0672
0673 m_tqs.clear();
0674
0675 #ifdef TOOLX_DONE_FACE
0676 ::FT_Done_Face(m_face);
0677 m_face = 0;
0678 #endif
0679 }
0680
0681 void outline_lines_2_gl(std::ostream& a_out) {
0682 if(!set_char_size(a_out,m_face,height.value(),m_scale)) return;
0683 FT_Pos face_height = m_face->size->metrics.height; //FT_Pos (long)
0684
0685 m_tobj = 0; //IMPORTANT.
0686
0687 if(strings.values().size()) {
0688 float yline = 0;
0689 tools_vforcit(std::string,strings.values(),vit) {
0690 const std::string& line = *vit;
0691 //a_out << line << std::endl;
0692 m_trans_x = 0;
0693 m_trans_y = yline;
0694 size_t ibeg = m_lines.size(); //for hjust.
0695 tools_sforcit(line,it) {
0696 if(!char_outline_2_gl(a_out,*it + m_encoding_offset)) return;
0697 }
0698 yline += -float(face_height)*m_scale; //height >0
0699
0700 {float sx = m_trans_x;
0701 if(hjust==tools::sg::center) {
0702 size_t num = m_lines.size();
0703 for(size_t index=ibeg;index<num;index++) {
0704 line_t& item = m_lines[index];
0705 size_t pos = item.first;
0706 size_t npt = item.second;
0707 float* data = tools::vec_data<float>(m_xys)+pos;
0708 for(size_t i=0;i<npt;i++,data+=2) *data -= 0.5F * sx;
0709 }
0710 } else if(hjust==tools::sg::right) {
0711 size_t num = m_lines.size();
0712 for(size_t index=ibeg;index<num;index++) {
0713 line_t& item = m_lines[index];
0714 size_t pos = item.first;
0715 size_t npt = item.second;
0716 float* data = tools::vec_data<float>(m_xys)+pos;
0717 for(size_t i=0;i<npt;i++,data+=2) *data -= sx;
0718 }
0719 }}
0720 }
0721
0722 } else if(unitext.values().size()) {
0723 float yline = 0;
0724 tools_vforcit(uniline,unitext.values(),vit) {
0725 const uniline& line = *vit;
0726 //a_out << line << std::endl;
0727 m_trans_x = 0;
0728 m_trans_y = yline;
0729 size_t ibeg = m_lines.size(); //for hjust.
0730 tools_vforcit(unichar,line,it) {
0731 if(!char_outline_2_gl(a_out,*it)) return;
0732 }
0733 yline += -float(face_height)*m_scale; //height>0
0734
0735 {float sx = m_trans_x;
0736 if(hjust==tools::sg::center) {
0737 size_t num = m_lines.size();
0738 for(size_t index=ibeg;index<num;index++) {
0739 line_t& item = m_lines[index];
0740 size_t pos = item.first;
0741 size_t npt = item.second;
0742 float* data = tools::vec_data<float>(m_xys)+pos;
0743 for(size_t i=0;i<npt;i++,data+=2) *data -= 0.5F*sx;
0744 }
0745 } else if(hjust==tools::sg::center) {
0746 size_t num = m_lines.size();
0747 for(size_t index=ibeg;index<num;index++) {
0748 line_t& item = m_lines[index];
0749 size_t pos = item.first;
0750 size_t npt = item.second;
0751 float* data = tools::vec_data<float>(m_xys)+pos;
0752 for(size_t i=0;i<npt;i++,data+=2) *data -= sx;
0753 }
0754 }}
0755 }
0756 }
0757 }
0758
0759 bool char_outline_2_gl(std::ostream& a_out,unsigned int a_unichar) {
0760 FT_ULong charcode = a_unichar; //charcode is UTF-32.
0761 FT_UInt glyph_index = ::FT_Get_Char_Index(m_face,charcode);
0762 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
0763 if((FT_Long)glyph_index>=m_face->num_glyphs) {
0764 a_out << "toolx::sg::text_freetype::char_outline_2_gl :"
0765 << " FT_Get_Char_Index : failed for char : " << a_unichar
0766 << std::endl;
0767 ::FT_Done_Face(m_face);
0768 m_face = 0;
0769 return false;
0770 }
0771
0772 {FT_Error error = ::FT_Load_Glyph(m_face,glyph_index,load_flags());
0773 if(error) {
0774 a_out << "toolx::sg::text_freetype::char_outline_2_gl :"
0775 << " for character " << a_unichar
0776 << ",FT_Load_Glyph : error : " << serror(error)
0777 << std::endl;
0778 ::FT_Done_Face(m_face);
0779 m_face = 0;
0780 return false;
0781 }}
0782
0783 //FT_GlyphSlot FT_Face.glyph;
0784 if(m_face->glyph->format!=FT_GLYPH_FORMAT_OUTLINE) {
0785 a_out << "toolx::sg::text_freetype::char_outline_2_gl :"
0786 << " for font " << tools::sout(font.value())
0787 << " and for character " << a_unichar
0788 << " glyph not at format outline."
0789 << std::endl;
0790 ::FT_Done_Face(m_face);
0791 m_face = 0;
0792 return false;
0793 }
0794
0795 FT_Outline outline = m_face->glyph->outline;
0796
0797 {FT_Error error = ::FT_Outline_Decompose(&outline,&m_funcs,this);
0798 if(error) {
0799 a_out << "toolx::sg::text_freetype::char_outline_2_gl :"
0800 << " for character " << a_unichar
0801 << ",FT_Outline_Decompose : error : " << serror(error)
0802 << std::endl;
0803 ::FT_Done_Face(m_face);
0804 m_face = 0;
0805 return false;
0806 }}
0807
0808 flush_line();
0809
0810 m_trans_x += float(m_face->glyph->advance.x)*m_scale;
0811 m_trans_y += float(m_face->glyph->advance.y)*m_scale;
0812
0813 {wndg_type wdg = ((outline.flags & FT_OUTLINE_REVERSE_FILL)?wndg_ccw:wndg_cw);
0814 if(m_wndg==wndg_not_done) {
0815 m_wndg = wdg;
0816 } else if(m_wndg!=wdg) {
0817 a_out << "toolx::sg::text_freetype::char_outline_2_gl :"
0818 << " for character " << a_unichar << ", winding anomaly."
0819 << std::endl;
0820 }}
0821
0822 return true;
0823 }
0824
0825 protected:
0826 void flush_line(){
0827 size_t num = (m_xys.size()-m_pos)/2;
0828 if(num) {
0829 m_lines.push_back(line_t(m_pos,num));
0830 }
0831 m_pos = m_xys.size();
0832 }
0833
0834 ////////////////////////////////////////////////////////
0835 /// outline triangles //////////////////////////////////
0836 ////////////////////////////////////////////////////////
0837 void outline_triangles_2_gl(std::ostream& a_out) {
0838 if(!set_char_size(a_out,m_face,height.value(),m_scale)) return;
0839 FT_Pos face_height = m_face->size->metrics.height; //FT_Pos (long)
0840
0841 m_tobj = gluNewTess();
0842
0843 // NOTE : the gluTessCallback_<enum>() functions are tools/glutess specific.
0844 // They had been introduced to avoid g++-8.1.0 warnings :
0845 // warnings : cast between incompatible function types.
0846 ::gluTessCallback_GLU_TESS_BEGIN_DATA (m_tobj,begin_cbk);
0847 ::gluTessCallback_GLU_TESS_END_DATA (m_tobj,end_cbk);
0848 ::gluTessCallback_GLU_TESS_VERTEX_DATA (m_tobj,vertex_cbk);
0849 ::gluTessCallback_GLU_TESS_COMBINE_DATA (m_tobj,combine_cbk);
0850 ::gluTessCallback_GLU_TESS_ERROR_DATA (m_tobj,error_cbk);
0851
0852 ::gluTessProperty(m_tobj,(GLUenum)GLU_TESS_WINDING_RULE,GLU_TESS_WINDING_ODD);
0853
0854 //::gluTessProperty(m_tobj, GLU_TESS_TOLERANCE, 0);
0855 //::gluTessNormal(m_tobj, 0.0f, 0.0f, -1.0f);
0856
0857 if(strings.values().size()) {
0858 float yline = 0;
0859 tools_vforcit(std::string,strings.values(),vit) {
0860 const std::string& line = *vit;
0861 //a_out << line << std::endl;
0862 m_trans_x = 0;
0863 m_trans_y = yline;
0864 size_t ibeg = m_triangles.size(); //for hjust.
0865 tools_sforcit(line,it) {
0866 if(!char_triangles_2_gl(a_out,*it + m_encoding_offset)) {
0867 ::gluDeleteTess(m_tobj);
0868 m_tobj = 0;
0869 return;
0870 }
0871 }
0872 yline += -float(face_height)*m_scale; //height>0
0873
0874 {float sx = m_trans_x;
0875 if(hjust==tools::sg::center) {
0876 size_t num = m_triangles.size();
0877 for(size_t index=ibeg;index<num;index++) {
0878 std::pair<GLUenum,triangle_t>& item = m_triangles[index];
0879 size_t pos = item.second.first;
0880 size_t npt = item.second.second;
0881 float* data = tools::vec_data<float>(m_xys)+pos;
0882 for(size_t i=0;i<npt;i++,data+=2) *data -= sx*0.5f;
0883 }
0884 } else if(hjust==tools::sg::right) {
0885 size_t num = m_triangles.size();
0886 for(size_t index=ibeg;index<num;index++) {
0887 std::pair<GLUenum,triangle_t>& item = m_triangles[index];
0888 size_t pos = item.second.first;
0889 size_t npt = item.second.second;
0890 float* data = tools::vec_data<float>(m_xys)+pos;
0891 for(size_t i=0;i<npt;i++,data+=2) *data -= sx;
0892 }
0893 }}
0894 }
0895 } else if(unitext.values().size()) {
0896 float yline = 0;
0897 tools_vforcit(uniline,unitext.values(),vit) {
0898 const uniline& line = *vit;
0899 //a_out << line << std::endl;
0900 m_trans_x = 0;
0901 m_trans_y = yline;
0902 size_t ibeg = m_triangles.size(); //for hjust.
0903 tools_vforcit(unichar,line,it) {
0904 if(!char_triangles_2_gl(a_out,*it)) {
0905 ::gluDeleteTess(m_tobj);
0906 m_tobj = 0;
0907 return;
0908 }
0909 }
0910 yline += -float(face_height)*m_scale; //height>0
0911
0912 {float sx = m_trans_x;
0913 if(hjust==tools::sg::center) {
0914 size_t num = m_triangles.size();
0915 for(size_t index=ibeg;index<num;index++) {
0916 std::pair<GLUenum,triangle_t>& item = m_triangles[index];
0917 size_t pos = item.second.first;
0918 size_t npt = item.second.second;
0919 float* data = tools::vec_data<float>(m_xys)+pos;
0920 for(size_t i=0;i<npt;i++,data+=2) *data -= sx*0.5f;
0921 }
0922 } else if(hjust==tools::sg::right) {
0923 size_t num = m_triangles.size();
0924 for(size_t index=ibeg;index<num;index++) {
0925 std::pair<GLUenum,triangle_t>& item = m_triangles[index];
0926 size_t pos = item.second.first;
0927 size_t npt = item.second.second;
0928 float* data = tools::vec_data<float>(m_xys)+pos;
0929 for(size_t i=0;i<npt;i++,data+=2) *data -= sx;
0930 }
0931 }}
0932 }
0933 }
0934
0935 ::gluDeleteTess(m_tobj);
0936 m_tobj = 0;
0937 }
0938
0939 bool char_triangles_2_gl(std::ostream& a_out,unsigned int a_unichar) {
0940 //if(m_verbose) {
0941 // a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
0942 // << " do " << a_unichar << "."
0943 // << std::endl;
0944 //}
0945
0946 FT_ULong charcode = a_unichar; //charcode is UTF-32.
0947 FT_UInt glyph_index = ::FT_Get_Char_Index(m_face,charcode);
0948 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
0949 if((FT_Long)glyph_index>=m_face->num_glyphs) {
0950 a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
0951 << " FT_Get_Char_Index : failed for char : " << a_unichar
0952 << std::endl;
0953 ::FT_Done_Face(m_face);
0954 m_face = 0;
0955 return false;
0956 }
0957
0958 {FT_Error error = ::FT_Load_Glyph(m_face,glyph_index,load_flags());
0959 if(error) {
0960 a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
0961 << " for character " << a_unichar
0962 << ",FT_Load_Glyph : error : " << serror(error)
0963 << std::endl;
0964 ::FT_Done_Face(m_face);
0965 m_face = 0;
0966 return false;
0967 }}
0968
0969 //FT_GlyphSlot FT_Face.glyph;
0970 if(m_face->glyph->format!=FT_GLYPH_FORMAT_OUTLINE) {
0971 a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
0972 << " for font " << tools::sout(font.value())
0973 << " and for character " << a_unichar
0974 << " glyph not at format outline."
0975 << std::endl;
0976 ::FT_Done_Face(m_face);
0977 m_face = 0;
0978 return false;
0979 }
0980
0981 FT_Outline outline = m_face->glyph->outline;
0982
0983 m_glutess_trids_num = 0;
0984 m_combine_trids_num = 0;
0985
0986 m_contour_open = false;
0987
0988 ::gluTessBeginPolygon(m_tobj,this);
0989
0990 {FT_Error error = ::FT_Outline_Decompose(&outline,&m_funcs,this);
0991 if(error) {
0992 a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
0993 << " for character " << a_unichar
0994 << ",FT_Outline_Decompose : error : " << serror(error)
0995 << std::endl;
0996 ::FT_Done_Face(m_face);
0997 m_face = 0;
0998 return false;
0999 }}
1000
1001 if(m_contour_open) {
1002 ::gluTessEndContour(m_tobj);
1003 m_contour_open = false;
1004 }
1005
1006 ::gluTessEndPolygon(m_tobj); //triggers callbacks and fill m_triangles.
1007
1008 m_trans_x += float(m_face->glyph->advance.x)*m_scale;
1009 m_trans_y += float(m_face->glyph->advance.y)*m_scale;
1010
1011 {wndg_type wdg = ((outline.flags & FT_OUTLINE_REVERSE_FILL)?wndg_ccw:wndg_cw);
1012 if(m_wndg==wndg_not_done) {
1013 m_wndg = wdg;
1014 } else if(m_wndg!=wdg) {
1015 a_out << "toolx::sg::text_freetype::char_triangles_2_gl :"
1016 << " for character " << a_unichar << ", winding anomaly."
1017 << std::endl;
1018 }}
1019
1020 return true;
1021 }
1022
1023 ////////////////////////////////////////////////////////
1024 /// bitmap /////////////////////////////////////////////
1025 ////////////////////////////////////////////////////////
1026 bool bitmap_2_gl(std::ostream& a_out) {
1027 //if(!set_char_size(a_out,m_face,height.value(),m_scale)) return;
1028 //::printf("debug : xxxxx %g\n",m_char_height);
1029 FT_F26Dot6 wchar = (FT_F26Dot6)(m_char_height*64);
1030 FT_F26Dot6 hchar = (FT_F26Dot6)(m_char_height*64);
1031 FT_UInt hres = 72;
1032 FT_UInt vres = 72;
1033 FT_Error error = ::FT_Set_Char_Size(m_face,wchar,hchar,hres,vres);
1034 if(error) {
1035 a_out << "toolx::sg::text_freetype::bitmap_2_gl :"
1036 << " FT_Set_Char_Size : error : " << serror(error) << "."
1037 << std::endl;
1038 ::FT_Done_Face(m_face);
1039 m_face = 0;
1040 return false;
1041 }
1042 m_scale = height.value()/float(hchar);
1043
1044 FT_Pos face_height = m_face->size->metrics.height; //FT_Pos (long)
1045 //::printf("debug : face_height %lu\n",face_height);
1046 if(strings.values().size()) {
1047 float yline = 0;
1048 tools_vforcit(std::string,strings.values(),vit) {
1049 const std::string& line = *vit;
1050 //a_out << line << std::endl;
1051 m_trans_x = 0;
1052 m_trans_y = yline;
1053 size_t ibeg = m_tqs.size(); //for hjust.
1054 tools_sforcit(line,it) {
1055 if(!char_2_bitmap(a_out,*it + m_encoding_offset)) return false;
1056 }
1057 yline += -float(face_height)*m_scale; //height>0
1058
1059 {float sx = m_trans_x;
1060 if(hjust==tools::sg::center) {
1061 size_t num = m_tqs.size();
1062 for(size_t index=ibeg;index<num;index++) {
1063 std::vector<tools::vec3f>& vcs = m_tqs[index]->corners.values();
1064 for(size_t i=0;i<4;i++) vcs[i][0] -= sx*0.5f;
1065 }
1066 } else if(hjust==tools::sg::right) {
1067 size_t num = m_tqs.size();
1068 for(size_t index=ibeg;index<num;index++) {
1069 std::vector<tools::vec3f>& vcs = m_tqs[index]->corners.values();
1070 for(size_t i=0;i<4;i++) vcs[i][0] -= sx;
1071 }
1072 }}
1073 }
1074 } else if(unitext.values().size()) {
1075 float yline = 0;
1076 tools_vforcit(uniline,unitext.values(),vit) {
1077 const uniline& line = *vit;
1078 //a_out << line << std::endl;
1079 m_trans_x = 0;
1080 m_trans_y = yline;
1081 size_t ibeg = m_tqs.size(); //for hjust.
1082 tools_vforcit(unichar,line,it) {
1083 if(!char_2_bitmap(a_out,*it)) return false;
1084 }
1085 yline += -float(face_height)*m_scale; //height>0
1086
1087 {float sx = m_trans_x;
1088 if(hjust==tools::sg::center) {
1089 size_t num = m_tqs.size();
1090 for(size_t index=ibeg;index<num;index++) {
1091 std::vector<tools::vec3f>& vcs = m_tqs[index]->corners.values();
1092 for(size_t i=0;i<4;i++) vcs[i][0] -= sx*0.5f;
1093 }
1094 } else if(hjust==tools::sg::right) {
1095 size_t num = m_tqs.size();
1096 for(size_t index=ibeg;index<num;index++) {
1097 std::vector<tools::vec3f>& vcs = m_tqs[index]->corners.values();
1098 for(size_t i=0;i<4;i++) vcs[i][0] -= sx;
1099 }
1100 }}
1101 }
1102 }
1103 return true;
1104 }
1105
1106 bool char_2_bitmap(std::ostream& a_out,unsigned int a_unichar) {
1107 //if(m_verbose) {
1108 // a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1109 // << " do " << a_unichar << "."
1110 // << std::endl;
1111 //}
1112
1113 FT_ULong charcode = a_unichar; //charcode is UTF-32.
1114 FT_UInt glyph_index = ::FT_Get_Char_Index(m_face,charcode);
1115 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
1116 if((FT_Long)glyph_index>=m_face->num_glyphs) {
1117 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1118 << " FT_Get_Char_Index : failed for char : " << a_unichar
1119 << std::endl;
1120 ::FT_Done_Face(m_face);
1121 m_face = 0;
1122 return false;
1123 }
1124
1125 {FT_Error error = ::FT_Load_Glyph(m_face,glyph_index,load_flags());
1126 if(error) {
1127 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1128 << " for character " << a_unichar
1129 << ",FT_Load_Glyph : error : " << serror(error)
1130 << std::endl;
1131 ::FT_Done_Face(m_face);
1132 m_face = 0;
1133 return false;
1134 }}
1135
1136 FT_Glyph glyph;
1137 {FT_Error error = ::FT_Get_Glyph(m_face->glyph,&glyph);
1138 if (error) {
1139 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1140 << " for font " << tools::sout(font.value())
1141 << " and for character " << a_unichar
1142 << " could not get glyph."
1143 << std::endl;
1144 ::FT_Done_Face(m_face);
1145 m_face = 0;
1146 return false;
1147 }}
1148
1149 bool smoothing = true;
1150 {FT_Error error = ::FT_Glyph_To_Bitmap(&glyph,(smoothing?ft_render_mode_normal:ft_render_mode_mono),0,1);
1151 if (error) {
1152 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1153 << " for font " << tools::sout(font.value())
1154 << " and for character " << a_unichar
1155 << " could not get glyph bitmap."
1156 << std::endl;
1157 ::FT_Done_Glyph(glyph);
1158 ::FT_Done_Face(m_face);
1159 m_face = 0;
1160 return false;
1161 }}
1162
1163 //typedef struct FT_Bitmap_ {
1164 // int rows;
1165 // int width;
1166 // int pitch;
1167 // unsigned char* buffer;
1168 // short num_grays;
1169 // char pixel_mode;
1170 // char palette_mode;
1171 // void* palette;
1172 //} FT_Bitmap;
1173
1174 FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
1175
1176 //::printf("debug : unichar %u : r %d w %d pitch %d : grays %d\n",
1177 // a_unichar,bitmap->bitmap.rows,bitmap->bitmap.width,bitmap->bitmap.pitch,bitmap->bitmap.num_grays);
1178
1179 if( (bitmap->bitmap.pixel_mode!=ft_pixel_mode_mono) &&
1180 (bitmap->bitmap.pixel_mode!=ft_pixel_mode_grays) ){
1181 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1182 << " for font " << tools::sout(font.value())
1183 << " and for character " << a_unichar
1184 << " not a mono or grays pixmap."
1185 << std::endl;
1186 ::FT_Done_Glyph(glyph);
1187 ::FT_Done_Face(m_face);
1188 m_face = 0;
1189 return false;
1190 }
1191
1192 if(bitmap->bitmap.pitch<0) {
1193 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1194 << " for font " << tools::sout(font.value())
1195 << " and for character " << a_unichar
1196 << " negative bitmap pitch."
1197 << std::endl;
1198 ::FT_Done_Glyph(glyph);
1199 ::FT_Done_Face(m_face);
1200 m_face = 0;
1201 return false;
1202 }
1203
1204 unsigned int img_w = 0;
1205 unsigned int img_h = 0;
1206 unsigned int img_bpp = 4;
1207 size_t img_sz = 0;
1208
1209 if(bitmap->bitmap.pixel_mode==ft_pixel_mode_mono) {
1210 a_out << "toolx::sg::text_freetype::char_2_bitmap : mode_mono : not yet handled." << std::endl;
1211
1212 //img_grays = 1;
1213 img_h = bitmap->bitmap.rows;
1214 //WARNING : bitmap->bitmap.pitch != int((bitmap->bitmap.width+7)/8) !!!
1215 // OpenGL wants the below for cols.
1216 img_w = (bitmap->bitmap.width+7)/8;
1217 img_sz = img_w * img_h;
1218
1219 ::FT_Done_Glyph(glyph);
1220 ::FT_Done_Face(m_face);
1221 m_face = 0;
1222 return false;
1223
1224 } else { //ft_pixel_mode_grays
1225 if(int(bitmap->bitmap.width)!=bitmap->bitmap.pitch) {
1226 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1227 << " for font " << tools::sout(font.value())
1228 << " and for character " << a_unichar
1229 << "bitmap pitch (" << bitmap->bitmap.pitch << ") != width (" << bitmap->bitmap.width << ")."
1230 << std::endl;
1231 ::FT_Done_Glyph(glyph);
1232 ::FT_Done_Face(m_face);
1233 m_face = 0;
1234 return false;
1235 }
1236 img_w = bitmap->bitmap.width;
1237 img_h = bitmap->bitmap.rows;
1238 img_sz = img_w * img_h * img_bpp;
1239 //img_grays = bitmap->bitmap.num_grays;
1240 }
1241
1242 if(img_sz<=0) {
1243 // This may happen (for example for the space character).
1244 } else {
1245 tools::byte* img_buffer = new tools::byte[img_sz];
1246 if(!img_buffer) {
1247 a_out << "toolx::sg::text_freetype::char_2_bitmap :"
1248 << " for font " << tools::sout(font.value())
1249 << " and for character " << a_unichar
1250 << ", can't alloc bitmap buffer for character."
1251 << std::endl;
1252 ::FT_Done_Glyph(glyph);
1253 ::FT_Done_Face(m_face);
1254 m_face = 0;
1255 return false;
1256 }
1257 // The bitmap is upside down for OpenGL.
1258 float a,b;
1259 tools::colorf back_color = tools::colorf_white();
1260 back_color.set_a(0); //transparent background.
1261 typedef unsigned char uchar;
1262 for(unsigned int row=0;row<img_h;++row) {
1263 unsigned char* from = (unsigned char*)bitmap->bitmap.buffer + (bitmap->bitmap.rows-row-1)*bitmap->bitmap.pitch;
1264 unsigned char* to = img_buffer + row * img_w * img_bpp;
1265 for(unsigned int col=0;col<img_w;++col,++from) {
1266 a = float(*from)/255.0f;
1267 b = float(255-*from)/255.0f;
1268 *to = uchar(m_front_color.ruchar()*a+back_color.ruchar()*b);to++;
1269 *to = uchar(m_front_color.guchar()*a+back_color.guchar()*b);to++;
1270 *to = uchar(m_front_color.buchar()*a+back_color.buchar()*b);to++;
1271 *to = uchar(m_front_color.auchar()*a+back_color.auchar()*b);to++;
1272 }
1273 }
1274
1275 FT_BBox _bbox;
1276 FT_Glyph_Get_CBox(glyph,ft_glyph_bbox_pixels,&_bbox);
1277 //float _width = float(_bbox.xMax)-float(_bbox.xMin);
1278 //float _height = float(_bbox.yMax)-float(_bbox.yMin);
1279 //aAdvance = int(face->glyph->advance.x/64);
1280
1281 std::vector<tools::vec3f> vcs;
1282 //::printf("debug : box : %d %d %d %d\n",_bbox.xMin,_bbox.xMax,_bbox.yMin,_bbox.yMax);
1283 float scale = height.value()/m_char_height;
1284 float x_min = float(_bbox.xMin)*scale+m_trans_x;
1285 float x_max = float(_bbox.xMax)*scale+m_trans_x;
1286 float y_min = float(_bbox.yMin)*scale+m_trans_y;
1287 float y_max = float(_bbox.yMax)*scale+m_trans_y;
1288 //::printf("debug : scale %g, trans %g %g\n",m_scale,m_trans_x,m_trans_y);
1289 //::printf("debug : corners %g %g %g %g\n",x_min,x_max,y_min,y_max);
1290
1291 vcs.push_back(tools::vec3f(x_min,y_min,0));
1292 vcs.push_back(tools::vec3f(x_max,y_min,0));
1293 vcs.push_back(tools::vec3f(x_max,y_max,0));
1294 vcs.push_back(tools::vec3f(x_min,y_max,0));
1295
1296 tools::sg::tex_quadrilateral* _node = new tools::sg::tex_quadrilateral;
1297 _node->img.value().set(img_w,img_h,img_bpp,img_buffer,true);
1298 _node->expand = true;
1299 _node->back_color = tools::colorf_white(); //used as back pixel when expanding.
1300 _node->back_color.value().set_a(0); //transparent background.
1301 //_node->nearest = false; //to have antialiasing on texture.
1302 _node->corners.set_values(vcs);
1303
1304 m_bitmaps.add(_node);
1305 m_tqs.push_back(_node);
1306
1307 /*
1308 if(bitmap->bitmap.pixel_mode==ft_pixel_mode_mono) {
1309 if((aChar=='T')||(aChar=='a')||(aChar=='o')||(aChar=='L')) {
1310 printf("bitmap for '%c' : w = %d h = %d cols %d : ptsize = %d\n",
1311 aChar,a_raster.width,a_raster.rows,a_raster.cols,getPointSize());
1312 for( int row = (a_raster.rows-1); row >=0; --row ) {
1313 unsigned char* bline = (unsigned char*)a_raster.buffer + row * a_raster.cols;
1314 int icol = 0;
1315 int ibit = 0;
1316 unsigned char byte = (unsigned char)bline[icol];
1317 icol++;
1318 for( int i= 0; i < a_raster.width; ++i ) {
1319 unsigned char v = (byte & (1<<(7-ibit)));
1320 printf("%c",(v?'x':' '));
1321 ibit++;
1322 if(ibit==8) {
1323 ibit = 0;
1324 byte = (unsigned char)bline[icol];
1325 icol++;
1326 }
1327 }
1328 printf("\n");
1329 }
1330 }
1331 }*/
1332
1333 }
1334
1335 m_trans_x += float(m_face->glyph->advance.x)*m_scale;
1336 m_trans_y += float(m_face->glyph->advance.y)*m_scale;
1337
1338 ::FT_Done_Glyph(glyph);
1339
1340 return true;
1341 }
1342
1343 typedef _GLUfuncptr Func;
1344
1345 static void GLUAPIENTRY begin_cbk(GLUenum a_which,void* a_this) {
1346 text_freetype& self = *((text_freetype*)a_this);
1347 self.m_mode = a_which;
1348 self.m_pos = self.m_xys.size();
1349 #ifdef TOOLX_SG_TEXT_FREETYPE_DEBUG
1350 self.m_out << "toolx::sg::text_freetype::begin_cbk :"
1351 << " which " << a_which
1352 << " GL_TRIANGLE_STRIP " << GL_TRIANGLE_STRIP
1353 << " GL_TRIANGLE_FAN " << GL_TRIANGLE_FAN
1354 << " GL_TRIANGLES " << GL_TRIANGLES
1355 << std::endl;
1356 #endif
1357 }
1358
1359 static void GLUAPIENTRY vertex_cbk(void* a_vertex,void* a_this) {
1360 text_freetype& self = *((text_freetype*)a_this);
1361 double* vertex = (double*)a_vertex;
1362 #ifdef TOOLX_SG_TEXT_FREETYPE_DEBUG
1363 std::cout << "toolx::sg::text_freetype::vertex_cbk :"
1364 << " x " << vertex[0]
1365 << " y " << vertex[1]
1366 << " z " << vertex[2]
1367 << std::endl;
1368 #endif
1369 self.add_xy(float(vertex[0]),float(vertex[1]));
1370 }
1371
1372 static void GLUAPIENTRY end_cbk(void* a_this){
1373 text_freetype& self = *((text_freetype*)a_this);
1374 size_t num = (self.m_xys.size()-self.m_pos)/2;
1375 if(num) {
1376 triangle_t t(self.m_pos,num);
1377 self.m_triangles.push_back(std::pair<GLUenum,triangle_t>(self.m_mode,t));
1378 }
1379 }
1380
1381 static void GLUAPIENTRY combine_cbk(double a_coords[3],
1382 void* /*a_vertex_data*/[4],
1383 float /*a_weight*/[4],
1384 void** a_data_out,
1385 void* a_this) {
1386 text_freetype& self = *((text_freetype*)a_this);
1387 double* v = self.add_combine_vec3d(a_coords[0],a_coords[1],a_coords[2]);
1388 //if(!v) ???
1389 *a_data_out = v;
1390 }
1391
1392 static void GLUAPIENTRY error_cbk(GLUenum,void*) {
1393 //const GLubyte* estring = gluErrorString(aErrorCode);
1394 //::fprintf(stderr, "Tessellation Error: %s\n", estring);
1395 //SbTessContour* This = (SbTessContour*)aThis;
1396 //This->setError(true);
1397 }
1398
1399 ////////////////////////////////////////////////////////
1400 /// outline triangles : end ////////////////////////////
1401 ////////////////////////////////////////////////////////
1402
1403 ////////////////////////////////////////////////////////
1404 /// FT_Outline_Decompose callbacks /////////////////////
1405 ////////////////////////////////////////////////////////
1406 static int outline_move_to(const FT_Vector* a_to,void* a_this){
1407 // NOTE : get x coords in units of wchar,
1408 // get y coords in units of hchar.
1409 // Exa : if char_width is 100*64 get some x of
1410 // the same magnitude (in [0,6400]).
1411 text_freetype& self = *((text_freetype*)a_this);
1412
1413 //self.m_out << "toolx::sg::text_freetype::outline_move_to :"
1414 // << " x " << a_to->x
1415 // << " y " << a_to->y
1416 // << std::endl;
1417
1418 float gx,gy;
1419 self.set_g(gx,gy,float(a_to->x),float(a_to->y));
1420
1421 if(self.m_tobj) {
1422 if(self.m_contour_open) {
1423 ::gluTessEndContour(self.m_tobj);
1424 self.m_contour_open = false;
1425 }
1426
1427 ::gluTessBeginContour(self.m_tobj);
1428 self.m_contour_open = true;
1429
1430 {double* v = self.add_glutess_vec3d(gx,gy,0);
1431 ::gluTessVertex(self.m_tobj,v,v);}
1432
1433 } else {
1434 self.flush_line();
1435 self.add_xy(gx,gy);
1436 }
1437
1438 self.m_last_x = float(a_to->x);
1439 self.m_last_y = float(a_to->y);
1440
1441 return 0;
1442 }
1443 static int outline_line_to(const FT_Vector* a_to,void* a_this){
1444 text_freetype& self = *((text_freetype*)a_this);
1445
1446 //self.m_out << "toolx::sg::text_freetype::outline_line_to :"
1447 // << " x " << a_to->x
1448 // << " y " << a_to->y
1449 // << std::endl;
1450
1451 float gx,gy;
1452 self.set_g(gx,gy,float(a_to->x),float(a_to->y));
1453
1454 if(self.m_tobj) {
1455 double* v = self.add_glutess_vec3d(gx,gy,0);
1456 ::gluTessVertex(self.m_tobj,v,v);
1457 } else {
1458 self.add_xy(gx,gy);
1459 }
1460
1461 self.m_last_x = float(a_to->x);
1462 self.m_last_y = float(a_to->y);
1463
1464 return 0;
1465 }
1466 static int outline_conic_to(const FT_Vector* a_ctrl,const FT_Vector* a_to,void* a_this){
1467 text_freetype& self = *((text_freetype*)a_this);
1468
1469 // it must be fast. We avoid vec3f manipulations.
1470
1471 //self.m_out << "toolx::sg::text_freetype::outline_conic_to :"
1472 // << " ctrl x " << a_ctrl->x
1473 // << " ctrl y " << a_ctrl->y
1474 // << " x " << a_to->x
1475 // << " y " << a_to->y
1476 // << std::endl;
1477
1478 float ctrlx = float(a_ctrl->x);
1479 float ctrly = float(a_ctrl->y);
1480
1481 float fromx = self.m_last_x;
1482 float fromy = self.m_last_y;
1483
1484 float tox = float(a_to->x);
1485 float toy = float(a_to->y);
1486
1487 // logic taken from OGLFT.
1488
1489 //OPTIMIZE :
1490 //b = from - 2 * ctrl + to;
1491 //c = -2 * from + 2 * ctrl;
1492 //df = c * self.m_delta + b * self.m_delta2;
1493 //df2 = 2 * b * self.m_delta2;
1494 float bx = fromx - 2 * ctrlx + tox;
1495 float by = fromy - 2 * ctrly + toy;
1496
1497 float cx = -2 * fromx + 2 * ctrlx;
1498 float cy = -2 * fromy + 2 * ctrly;
1499
1500 float dfx = cx * self.m_delta + bx * self.m_delta2;
1501 float dfy = cy * self.m_delta + by * self.m_delta2;
1502
1503 float df2x = 2 * bx * self.m_delta2;
1504 float df2y = 2 * by * self.m_delta2;
1505
1506 // if steps = 4, num = 3
1507 // from (i=0) (i=1) (i=2) (to)
1508 // then we have four steps between [from,to]
1509
1510 // from = starting point.
1511
1512 float gx,gy;
1513
1514 size_t num = self.m_steps - 1;
1515 for(size_t i=0;i<num;i++) {
1516 fromx += dfx;
1517 fromy += dfy;
1518
1519 self.set_g(gx,gy,fromx,fromy);
1520
1521 if(self.m_tobj) {
1522 double* v = self.add_glutess_vec3d(gx,gy,0);
1523 ::gluTessVertex(self.m_tobj,v,v);
1524 } else {
1525 self.add_xy(gx,gy);
1526 }
1527
1528 dfx += df2x;
1529 dfy += df2y;
1530 }
1531
1532 //g = to;
1533 self.set_g(gx,gy,tox,toy);
1534
1535 if(self.m_tobj) {
1536 double* v = self.add_glutess_vec3d(gx,gy,0);
1537 ::gluTessVertex(self.m_tobj,v,v);
1538 } else {
1539 self.add_xy(gx,gy);
1540 }
1541
1542 //self.m_last = to;
1543 self.m_last_x = tox;
1544 self.m_last_y = toy;
1545
1546 return 0;
1547 }
1548 void set_g(float& a_gx,float& a_gy,float a_x,float a_y) const {
1549 a_gx = a_x*m_scale+m_trans_x;
1550 a_gy = a_y*m_scale+m_trans_y;
1551 }
1552 static int outline_cubic_to(const FT_Vector* a_ctrl1,const FT_Vector* a_ctrl2,const FT_Vector* a_to,void* a_this){
1553 text_freetype& self = *((text_freetype*)a_this);
1554
1555 // it must be fast. We avoid vec3f manipulations.
1556
1557 //self.m_out << "toolx::sg::text_freetype::outline_cubic_to :"
1558 // << " ctrl1 x " << a_ctrl1->x
1559 // << " ctrl1 y " << a_ctrl1->y
1560 // << " ctrl2 x " << a_ctrl2->x
1561 // << " ctrl2 y " << a_ctrl2->y
1562 // << " x " << a_to->x
1563 // << " y " << a_to->y
1564 // << std::endl;
1565
1566 float ctrl1x = float(a_ctrl1->x);
1567 float ctrl1y = float(a_ctrl1->y);
1568
1569 float ctrl2x = float(a_ctrl2->x);
1570 float ctrl2y = float(a_ctrl2->y);
1571
1572 float fromx = self.m_last_x;
1573 float fromy = self.m_last_y;
1574
1575 float tox = float(a_to->x);
1576 float toy = float(a_to->y);
1577
1578 // logic taken from OGLFT.
1579
1580 //OPTIMIZE :
1581 //a = -from + 3 * ctrl1 - 3 * ctrl2 + to;
1582 //b = 3 * from - 6 * ctrl1 + 3 * ctrl2;
1583 //c = -3 * from + 3 * ctrl1;
1584 //df = c * self.m_delta + b * self.m_delta2 + a * self.m_delta3;
1585 //df2 = 2 * b * self.m_delta2 + 6 * a * self.m_delta3;
1586 //df3 = 6 * a * self.m_delta3;
1587
1588 float ax = -fromx + 3 * ctrl1x - 3 * ctrl2x + tox;
1589 float ay = -fromy + 3 * ctrl1y - 3 * ctrl2y + toy;
1590
1591 float bx = 3 * fromx - 6 * ctrl1x + 3 * ctrl2x;
1592 float by = 3 * fromy - 6 * ctrl1y + 3 * ctrl2y;
1593
1594 float cx = -3 * fromx + 3 * ctrl1x;
1595 float cy = -3 * fromy + 3 * ctrl1y;
1596
1597 float dfx = cx * self.m_delta + bx * self.m_delta2 + ax * self.m_delta3;
1598 float dfy = cy * self.m_delta + by * self.m_delta2 + ay * self.m_delta3;
1599
1600 float df2x = 2 * bx * self.m_delta2 + 6 * ax * self.m_delta3;
1601 float df2y = 2 * by * self.m_delta2 + 6 * ay * self.m_delta3;
1602
1603 float df3x = 6 * ax * self.m_delta3;
1604 float df3y = 6 * ay * self.m_delta3;
1605
1606 // if steps = 4, num = 3
1607 // from (i=0) (i=1) (i=2) (to)
1608 // then we have four steps between [from,to]
1609
1610 // from = starting point.
1611 float gx,gy;
1612
1613 size_t num = self.m_steps - 1;
1614 for(size_t i=0;i<num;i++) {
1615 fromx += dfx;
1616 fromy += dfy;
1617
1618 self.set_g(gx,gy,fromx,fromy);
1619
1620 if(self.m_tobj) {
1621 double* v = self.add_glutess_vec3d(gx,gy,0);
1622 ::gluTessVertex(self.m_tobj,v,v);
1623 } else {
1624 self.add_xy(gx,gy);
1625 }
1626
1627 dfx += df2x;
1628 dfy += df2y;
1629
1630 df2x += df3x;
1631 df2y += df3y;
1632 }
1633
1634 //g = to;
1635 self.set_g(gx,gy,tox,toy);
1636
1637 if(self.m_tobj) {
1638 double* v = self.add_glutess_vec3d(gx,gy,0);
1639 ::gluTessVertex(self.m_tobj,v,v);
1640 } else {
1641 self.add_xy(gx,gy);
1642 }
1643
1644 //self.m_last = to;
1645 self.m_last_x = tox;
1646 self.m_last_y = toy;
1647
1648 return 0;
1649 }
1650
1651
1652 public:
1653 #ifndef SWIG
1654 class serrors : public std::map<int,std::string> {
1655 typedef std::map<int,std::string> parent;
1656 public:
1657 serrors(){
1658 #undef __FTERRORS_H__
1659 #define FT_ERROR_START_LIST
1660 #define FT_ERROR_END_LIST
1661 #define FT_ERRORDEF( e, v, s ) parent::operator[](e) = s;
1662 #include FT_ERRORS_H
1663 }
1664 virtual ~serrors() {}
1665 protected:
1666 serrors(const serrors& a_from):parent(a_from) {}
1667 serrors& operator=(const serrors&){return *this;}
1668 };
1669 static std::string serror(int a_FT_Error) {
1670 static const serrors errs;
1671 std::map<int,std::string>::const_iterator it = errs.find(a_FT_Error);
1672 if(it!=errs.end()) return (*it).second;
1673 return "unknown";
1674 }
1675 #endif
1676 protected:
1677 void add_xy(float a_x,float a_y) {
1678 m_xys.push_back(a_x);
1679 m_xys.push_back(a_y);
1680 }
1681
1682 double* add_glutess_vec3d(float a_x,float a_y,float a_z) {
1683 double* v = 0;
1684 if(m_glutess_trids_num>=m_glutess_trids.size()) {
1685 v = new double[3];
1686 m_glutess_trids.push_back(v);
1687 } else {
1688 v = m_glutess_trids[m_glutess_trids_num];
1689 }
1690 m_glutess_trids_num++;
1691
1692 v[0] = a_x;
1693 v[1] = a_y;
1694 v[2] = a_z;
1695
1696 return v;
1697 }
1698
1699 double* add_combine_vec3d(double a_x,double a_y,double a_z) {
1700 double* v = 0;
1701 if(m_combine_trids_num>=m_combine_trids.size()) {
1702 v = new double[3];
1703 m_combine_trids.push_back(v);
1704 } else {
1705 v = m_combine_trids[m_combine_trids_num];
1706 }
1707 m_combine_trids_num++;
1708
1709 v[0] = a_x;
1710 v[1] = a_y;
1711 v[2] = a_z;
1712
1713 return v;
1714 }
1715
1716 void clear_trids() {
1717 {tools_vforit(double*,m_glutess_trids,it) delete [] *it;
1718 m_glutess_trids.clear();}
1719
1720 {tools_vforit(double*,m_combine_trids,it) delete [] *it;
1721 m_combine_trids.clear();}
1722 }
1723
1724 void load_face(std::ostream& a_out) {
1725 if(!m_library) {
1726 a_out << "toolx::sg::text_freetype::load_face :"
1727 << " freetype library not initialized."
1728 << std::endl;
1729 return;
1730 }
1731
1732 if(m_verbose) {
1733 a_out << "toolx::sg::text_freetype::load_face :"
1734 << " font is " << tools::sout(font.value()) << "."
1735 << std::endl;
1736 }
1737
1738 if(m_face) {
1739 ::FT_Done_Face(m_face);
1740 m_face = 0;
1741 }
1742
1743 if(font.value().empty()) {
1744 a_out << "toolx::sg::text_freetype::load_face :"
1745 << " no font given."
1746 << std::endl;
1747 return;
1748 }
1749
1750 // look for embedded fonts:
1751 {unsigned int size;
1752 const unsigned char* buffer;
1753 if(parent::find_embedded_font(font.value(),size,buffer)) {
1754 FT_Error error =
1755 ::FT_New_Memory_Face(m_library,(const FT_Byte*)buffer,(FT_Long)size,0,&m_face);
1756 if(error) {
1757 a_out << "toolx::sg::text_freetype::load_face :"
1758 << " FT_New_Memory_Face : error : " << serror(error) << "."
1759 << std::endl;
1760 m_face = 0;
1761 return;
1762 }
1763 if(m_verbose) a_out << "toolx::sg::text_freetype::load_face : load embedded font ok." << std::endl;
1764 return;
1765 }}
1766
1767 std::string file;
1768
1769 if(parent::find_font_with_finders(font.value(),file)) {
1770 } else {
1771 tools::find_with_env(a_out,s_TOOLS_FONT_PATH(),font.value(),file,false);
1772 }
1773
1774 if(file.empty()) {
1775 a_out << "toolx::sg::text_freetype::load_face :"
1776 << " font file not found for font "
1777 << tools::sout(font.value()) << "."
1778 << std::endl;
1779 return;
1780 }
1781
1782 if(m_verbose) {
1783 a_out << "toolx::sg::text_freetype::load_face :"
1784 << " load font file " << tools::sout(file) << " ..."
1785 << std::endl;
1786 }
1787
1788 FT_Error error = ::FT_New_Face(m_library,file.c_str(),0,&m_face);
1789 if(error) {
1790 a_out << "toolx::sg::text_freetype::load_face :"
1791 << " FT_New_Face : error : " << serror(error) << "."
1792 << " for font file " << tools::sout(file) << "."
1793 << std::endl;
1794 m_face = 0;
1795 return;
1796 }
1797
1798 if(m_verbose) {
1799 a_out << "toolx::sg::text_freetype::load_face :"
1800 << " load ok."
1801 << std::endl;
1802 }
1803
1804 }
1805
1806 protected:
1807 static int load_flags() {
1808 return FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
1809 //return FT_LOAD_DEFAULT;
1810 //return FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
1811 }
1812
1813 static bool set_char_size(std::ostream& a_out,FT_Face& a_face,float a_height,float& a_scale) {
1814
1815 // arrange char_width, char_height and m_scale so
1816 // that text height be 1 in world coordinates.
1817
1818 // What these fancy 26.6, 64, 72 number mean ?
1819 // In what unit do we receive points in callbacks ?
1820 // Knowing char_height and vres can we know height of points ?
1821
1822 FT_F26Dot6 wchar = 1000*64;
1823 FT_F26Dot6 hchar = 1000*64;
1824 FT_UInt hres = 72;
1825 FT_UInt vres = 72;
1826
1827 FT_Error error = ::FT_Set_Char_Size(a_face,wchar,hchar,hres,vres);
1828 if(error) {
1829 a_out << "toolx::sg::text_freetype::set_char_size :"
1830 << " FT_Set_Char_Size : error : " << serror(error) << "."
1831 << std::endl;
1832 ::FT_Done_Face(a_face);
1833 a_face = 0;
1834 a_scale = 1;
1835 return false;
1836 }
1837 a_scale = a_height/float(wchar);
1838 return true;
1839 }
1840
1841 static bool ascent(std::ostream& a_out,FT_Face& a_face,float a_height,float& a_value) {
1842 float scale;
1843 if(!set_char_size(a_out,a_face,a_height,scale)) {a_value = 0;return false;}
1844 FT_Pos ascent = a_face->size->metrics.ascender; //FT_Pos (long)
1845 a_value = float(ascent) * scale;
1846 return true;
1847 }
1848
1849 static bool descent(std::ostream& a_out,FT_Face& a_face,float a_height,float& a_value) {
1850 float scale;
1851 if(!set_char_size(a_out,a_face,a_height,scale)) {a_value = 0;return false;}
1852 FT_Pos descent = a_face->size->metrics.descender; //FT_Pos (long) //<0
1853 a_value = -(float(descent) * scale);
1854 return true;
1855 }
1856
1857 static bool y_advance(std::ostream& a_out,FT_Face& a_face,float a_height,float& a_adv) {
1858 float scale;
1859 if(!set_char_size(a_out,a_face,a_height,scale)) {a_adv = 0;return false;}
1860 FT_Pos face_height = a_face->size->metrics.height; //FT_Pos (long)
1861 a_adv = float(face_height)*scale;
1862 return true;
1863 }
1864
1865 static bool truncate(std::ostream& a_out,FT_Face& a_face,float a_height,
1866 const std::string& a_string,float a_cut_width,std::string& a_sout) {
1867 a_sout.clear();
1868
1869 float scale;
1870 if(!set_char_size(a_out,a_face,a_height,scale)) return false;
1871
1872 float width = 0;
1873
1874 unsigned short offset;
1875 if(!encoding_offset(a_face,offset)) return false;
1876
1877 tools_sforcit(a_string,it) {
1878 FT_ULong charcode = *it + offset; //charcode is UTF-32.
1879 FT_UInt glyph_index = ::FT_Get_Char_Index(a_face,charcode);
1880 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
1881 if((FT_Long)glyph_index>=a_face->num_glyphs) {
1882 #ifdef TOOLX_SG_TEXT_FREETYPE_DEBUG
1883 m_out << "toolx::sg::text_freetype::truncate :"
1884 << " FT_Get_Char_Index : failed for char : " << *it
1885 << std::endl;
1886 #endif
1887 a_sout.clear();
1888 ::FT_Done_Face(a_face);
1889 a_face = 0;
1890 return false;
1891 }
1892
1893 {FT_Error error = ::FT_Load_Glyph(a_face,glyph_index,load_flags());
1894 if(error) {
1895 #ifdef TOOLX_SG_TEXT_FREETYPE_DEBUG
1896 m_out << "toolx::sg::text_freetype::truncate :"
1897 << " for character " << *it
1898 << ",FT_Load_Glyph : error : " << serror(error)
1899 << std::endl;
1900 #endif
1901 a_sout.clear();
1902 ::FT_Done_Face(a_face);
1903 a_face = 0;
1904 return false;
1905 }}
1906
1907 float cwidth = float(a_face->glyph->metrics.width)*scale;
1908 float advance = float(a_face->glyph->advance.x)*scale;
1909 if((width+cwidth)>=a_cut_width) return true;
1910 a_sout += *it;
1911 width += advance;
1912 }
1913
1914 return true;
1915 }
1916
1917 static bool get_bounds(std::ostream& a_out,FT_Face& a_face,float a_height,
1918 const std::vector<std::string>& a_text,
1919 float& a_mn_x,float& a_mn_y,float& a_mn_z,
1920 float& a_mx_x,float& a_mx_y,float& a_mx_z){
1921 tools::box_3f_make_empty(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z);
1922
1923 if(a_text.empty()) return true;
1924
1925 float scale;
1926 if(!set_char_size(a_out,a_face,a_height,scale)) return false;
1927
1928 float xmx = 0;
1929
1930 unsigned short offset;
1931 if(!encoding_offset(a_face,offset)) return false;
1932
1933 tools_vforcit(std::string,a_text,vit) {
1934 const std::string& line = *vit;
1935
1936 float width = 0;
1937 tools_sforcit(line,it) {
1938 FT_ULong charcode = *it + offset; //charcode is UTF-32.
1939 FT_UInt glyph_index = ::FT_Get_Char_Index(a_face,charcode);
1940 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
1941 if((FT_Long)glyph_index>=a_face->num_glyphs) {
1942 ::FT_Done_Face(a_face);
1943 a_face = 0;
1944 return false;
1945 }
1946
1947 {FT_Error error = ::FT_Load_Glyph(a_face,glyph_index,load_flags());
1948 if(error) {
1949 ::FT_Done_Face(a_face);
1950 a_face = 0;
1951 return false;
1952 }}
1953
1954 //float cwidth = float(a_face->glyph->metrics.width)*scale;
1955 float advance = float(a_face->glyph->advance.x)*scale;
1956 width += advance;
1957 }
1958
1959 xmx = tools::mx<float>(xmx,width);
1960 }
1961
1962 FT_Pos ascent = a_face->size->metrics.ascender; //FT_Pos (long)
1963 FT_Pos descent = a_face->size->metrics.descender; //FT_Pos (long) //<0
1964 FT_Pos face_height = a_face->size->metrics.height; //FT_Pos (long)
1965
1966 float ymn = -float(face_height)*scale*(a_text.size()-1) //height>0
1967 +float(descent)*scale;
1968
1969 a_mn_x = 0;
1970 a_mn_y = ymn;
1971 a_mn_z = 0;
1972 a_mx_x = xmx;
1973 a_mx_y = float(ascent)*scale;
1974 a_mx_z = 0;
1975
1976 return true;
1977 }
1978
1979 static bool get_bounds(std::ostream& a_out,FT_Face& a_face,float a_height,
1980 const std::vector<uniline>& a_text,
1981 float& a_mn_x,float& a_mn_y,float& a_mn_z,
1982 float& a_mx_x,float& a_mx_y,float& a_mx_z){
1983 tools::box_3f_make_empty(a_mn_x,a_mn_y,a_mn_z,a_mx_x,a_mx_y,a_mx_z);
1984
1985 if(a_text.empty()) return true;
1986
1987 float scale;
1988 if(!set_char_size(a_out,a_face,a_height,scale)) return false;
1989
1990 float xmx = 0;
1991
1992 tools_vforcit(uniline,a_text,vit) {
1993 const uniline& line = *vit;
1994 float width = 0;
1995
1996 tools_vforcit(unichar,line,it) {
1997
1998 FT_ULong charcode = *it; //charcode is UTF-32.
1999 FT_UInt glyph_index = ::FT_Get_Char_Index(a_face,charcode);
2000 //NOTE : if not found -> glyph_index = 0 which is the "missing glyph".
2001 if((FT_Long)glyph_index>=a_face->num_glyphs) {
2002 ::FT_Done_Face(a_face);
2003 a_face = 0;
2004 return false;
2005 }
2006
2007 {FT_Error error = ::FT_Load_Glyph(a_face,glyph_index,load_flags());
2008 if(error) {
2009 ::FT_Done_Face(a_face);
2010 a_face = 0;
2011 return false;
2012 }}
2013
2014 //float cwidth = float(a_face->glyph->metrics.width)*scale;
2015 float advance = float(a_face->glyph->advance.x)*scale;
2016 width += advance;
2017 }
2018
2019 xmx = tools::mx<float>(xmx,width);
2020 }
2021
2022 FT_Pos ascent = a_face->size->metrics.ascender; //FT_Pos (long)
2023 FT_Pos descent = a_face->size->metrics.descender; //FT_Pos (long) //<0
2024 FT_Pos face_height = a_face->size->metrics.height; //FT_Pos (long)
2025
2026 float ymn = -float(face_height)*scale*(a_text.size()-1) //height>0
2027 +float(descent)*scale;
2028
2029 a_mn_x = 0;
2030 a_mn_y = ymn;
2031 a_mn_z = 0;
2032 a_mx_x = xmx;
2033 a_mx_y = float(ascent)*scale;
2034 a_mx_z = 0;
2035
2036 return true;
2037 }
2038
2039 static bool encoding_offset(FT_Face& a_face,unsigned short& a_offset) {
2040
2041 // arialbd.ttf :
2042 // num charmap 2
2043 // charmap 0, platform 1, encoding 0.
2044 // charmap 1, platform 3, encoding 1.
2045
2046 // symbol.ttf :
2047 // num charmap 2
2048 // charmap 0, platform 1, encoding 0.
2049 // charmap 1, platform 3, encoding 0.
2050
2051 // stixgeneral.otf :
2052 // num charmap 6.
2053 // charmap 0, platform 0, encoding 3.
2054 // charmap 1, platform 0, encoding 4.
2055 // charmap 2, platform 1, encoding 0.
2056 // charmap 3, platform 3, encoding 1.
2057
2058 a_offset = 0;
2059
2060 //std::cout << "toolx::sg::text_freetype::encoding_offset :"
2061 // << " num charmap " << a_face->num_charmaps << "."
2062 // << std::endl;
2063
2064 // cooking to handle symbol.ttf and wingding.ttf :
2065 FT_Int n = a_face->num_charmaps;
2066 FT_Int i;
2067 for ( i = 0; i < n; i++ ) {
2068 FT_CharMap charmap = a_face->charmaps[i];
2069 unsigned short platform = charmap->platform_id;
2070 unsigned short encoding = charmap->encoding_id;
2071
2072 //std::cout << "toolx::sg::text_freetype::encoding_offset :"
2073 // << " for charmap " << i
2074 // << ", platform " << platform
2075 // << ", encoding " << encoding << "."
2076 // << std::endl;
2077
2078 if ( (platform == 3 && encoding == 1 ) ||
2079 (platform == 3 && encoding == 0 ) ||
2080 //(platform == 1 && encoding == 0 ) ||
2081 (platform == 0 && encoding == 0 ) ) {
2082 FT_Error error = FT_Set_Charmap(a_face,charmap);
2083 if(error) {
2084 ::FT_Done_Face(a_face);
2085 a_face = 0;
2086 a_offset = 0;
2087 return false;
2088 }
2089 // For symbol.ttf and wingding.ttf
2090 if (platform == 3 && encoding == 0 ) a_offset = 0xF000;
2091 //if (platform == 1 && encoding == 0 ) a_offset = 0xF000;
2092 return true;
2093
2094 } else {
2095 //SoDebugError::post("SbTextTTF2Face::loadFont",
2096 // "for \"%s\", platform %d and encoding %d not taken into account",
2097 // filename,platform,encoding);
2098 }
2099 }
2100
2101 //a_out << "toolx::sg::text_freetype::update_sg :"
2102 // << " This font doesn't contain any Unicode mapping table."
2103 // << std::endl;
2104 ::FT_Done_Face(a_face);
2105 a_face = 0;
2106 a_offset = 0;
2107 return false;
2108 }
2109
2110 protected:
2111 FT_Library m_library;
2112 FT_Face m_face;
2113 unsigned short m_encoding_offset;
2114 bool m_verbose; //append _ to avoid clash with tools/sg/guib::m_verbose
2115 ////////////////////////////////////////////////////////
2116 /// outline ////////////////////////////////////////////
2117 ////////////////////////////////////////////////////////
2118 FT_Outline_Funcs m_funcs; //See doc in ftimage.h
2119 float m_last_x,m_last_y;
2120 float m_scale;
2121 float m_trans_x,m_trans_y;
2122 size_t m_steps;
2123 float m_delta;
2124 float m_delta2;
2125 float m_delta3;
2126
2127 std::vector<float> m_xys;
2128 ////////////////////////////////////////////////////////
2129 /// outline lines //////////////////////////////////////
2130 ////////////////////////////////////////////////////////
2131 typedef std::pair<size_t,size_t> line_t; //pos in m_xys.
2132 typedef std::vector<line_t> lines_t;
2133 lines_t m_lines;
2134 ////////////////////////////////////////////////////////
2135 /// outline triangles //////////////////////////////////
2136 ////////////////////////////////////////////////////////
2137 GLUtesselator* m_tobj;
2138 bool m_contour_open;
2139 std::vector<double*> m_glutess_trids;
2140 size_t m_glutess_trids_num;
2141 std::vector<double*> m_combine_trids;
2142 size_t m_combine_trids_num;
2143 GLUenum m_mode;
2144 typedef std::pair<size_t,size_t> triangle_t; //pos in m_xys.
2145 typedef std::pair<GLUenum,triangle_t> gl_triangle_t;
2146 typedef std::vector<gl_triangle_t> triangles_t;
2147 triangles_t m_triangles;
2148 size_t m_pos;
2149 size_t m_gsto_lines_sz;
2150 size_t m_gsto_sz;
2151 wndg_type m_wndg;
2152 tools::colorf m_front_color;
2153 tools::sg::group m_bitmaps;
2154 std::vector<tools::sg::tex_quadrilateral*> m_tqs;
2155 float m_char_height;
2156 };
2157
2158 }}
2159
2160
2161 #endif