NCBI C++ ToolKit
glbitmapfont.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: glbitmapfont.cpp 47292 2022-12-21 00:32:34Z evgeniev $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Mike DiCuccio, Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
34 #include "glutbitmap.h"
35 
37 #include <gui/opengl/gldlist.hpp>
38 #include <gui/opengl/glutils.hpp>
39 
40 #include <util/static_map.hpp>
41 
42 #include <math.h>
43 #include <stdio.h>
44 
45 
46 ///
47 /// Standard non-rotated fonts; the explicit sc_foo_ptr business works
48 /// around a bug in ICC 9, which otherwise fails to populate sc_Fonts
49 /// correctly. :-/
50 ///
51 
52 #define NCBI_FONT(x) \
53  static const BitmapFontRec* const sc_##x##_ptr = &x
54 
55 // clean fonts
64 
65 // courier fonts
74 
75 // fixed size fonts
82 
83 // helvetica fonts
92 
93 // lucida fonts
102 
103 // times fonts
112 
113 
115 
117 static const TFontPair sc_Fonts[] = {
123 
132 
141 
150 
159 
166 
175 
176 };
180 
181 
182 ///
183 /// rotated versions of the above
184 /// we store a cache of these that is generated on the fly
185 /// these fonts are only created as needed, and the data structures will
186 /// only be created once per session
187 ///
188 
190 {
191  /// non-rotated font
193 
194  /// rotation type
196 };
197 
199 {
200  bool operator() (const SRotateKey& rk1, const SRotateKey& rk2) const
201  {
202  if (rk1.font < rk2.font) {
203  return true;
204  }
205  if (rk2.font < rk1.font) {
206  return false;
207  }
208  return rk1.rot < rk2.rot;
209  }
210 };
211 
212 
216 
218 {
220  {
222  //BitmapFontPtr font = iter->second;
223  free((void*)iter->second->name);
224  for (int i = 0; i < iter->second->num_chars; ++i) {
225  if (iter->second->ch[i]) {
226  delete [] iter->second->ch[i]->bitmap;
227  delete [] iter->second->ch[i];
228  }
229  }
230  delete [] iter->second->ch;
231  delete iter->second;
232  }
233  }
234 };
236 
237 
238 
239 static inline
241 {
242  TFontMap::const_iterator iter = sc_FontMap.lower_bound(font);
243  if (iter->first == font) {
244  // exact match
245  return iter->second;
246  } else if (iter->first != font) {
247  // probably off by size
249  static_cast<CGlBitmapFont::EFontFace>
250  (font & 0xff);
251  CGlBitmapFont::EFontFace this_face =
252  static_cast<CGlBitmapFont::EFontFace>
253  (iter->first & 0xff);
254  if (this_face == face) {
255  // faces match, return font
256  return iter->second;
257  } else {
258  // faces don't match
259  // we need to jump forward or back to get the right face
260  TFontMap::const_iterator back = iter;
261  TFontMap::const_iterator forward = iter;
262  for ( ;
263  back != sc_FontMap.begin() &&
264  forward != sc_FontMap.end(); ) {
265  if (back != sc_FontMap.begin()) {
266  this_face = static_cast<CGlBitmapFont::EFontFace>
267  (back->first & 0xff);
268  if (this_face == face) {
269  return back->second;
270  }
271  --back;
272  }
273  if (forward != sc_FontMap.end()) {
274  this_face =
275  static_cast<CGlBitmapFont::EFontFace>
276  (forward->first & 0xff);
277  if (this_face == face) {
278  return forward->second;
279  }
280  ++forward;
281  }
282  }
283  }
284  }
285 
287  "OpenGL bitmap font font not found");
288 }
289 
290 
291 static const BitmapCharRec *s_GetCharPtr(const BitmapFontRec *font_ptr, int c)
292 {
293  if (c < font_ptr->first ||
294  c >= font_ptr->first + font_ptr->num_chars) {
295  return NULL;
296  }
297  return font_ptr->ch[c - font_ptr->first];
298 }
299 
300 
301 static TModelUnit s_GetCapHeight(const BitmapFontRec *font_ptr)
302 {
303  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, 'H');
304  return ch? ch->height : 0.0;
305 }
306 
307 
308 ///
309 /// create a rotated font
310 ///
311 /// this is limited to creating fonts roted 90, 180, or 270 degrees
312 ///
314  (const BitmapFontRec * source_font, CGlBitmapFont::EFontRotate rot)
315 {
316  _ASSERT(source_font);
317  if (rot == CGlBitmapFont::eFontRotate_0) {
318  return source_font;
319  }
320 
321  /// first, determine the baseline
322  /// the baseline may shift depending on our rotation
323  /// this ias based on the height of a capital 'M'
324  TModelUnit cap_ht = s_GetCapHeight(source_font);
325 
326 
327  ///
328  /// an OpenGL bitmap is stored as a set of GLubytes, with each bit
329  /// corresponding to a pixel. These are packed to end on even byte boundaries
330  /// at the end of a scanline.
331  ///
332  //CNcbiOfstream ostr("c:/temp/bitmap.txt");
333  BitmapCharRec** chars = new BitmapCharRec*[source_font->num_chars];
334  for (int charidx = 0; charidx < source_font->num_chars; ++charidx) {
335  const BitmapCharRec* orig_ch = source_font->ch[charidx];
336  BitmapCharRec* new_char = 0;
337  if (orig_ch) {
338  int i;
339  int j;
340 
341  /**
342  {{
343  int row_len = orig_ch->width / 8 + (orig_ch->width % 8 ? 1 : 0);
344  ostr << "0x" << hex << charidx << ": '"
345  << (char)charidx << "': "
346  << orig_ch->width << 'x' << orig_ch->height << ": "
347  << orig_ch->xorig << ',' << orig_ch->yorig << ": "
348  << orig_ch->advance
349  << endl;
350  for (j = 0; j < orig_ch->height; ++j) {
351  for (i = 0; i < orig_ch->width; ++i) {
352  int idx = j * row_len + i/8;
353  int bit = i % 8;
354  if (orig_ch->bitmap[idx] & (0x80 >> bit)) {
355  ostr << '*';
356  } else {
357  ostr << ' ';
358  }
359  }
360  ostr << endl;
361  }
362  ostr << endl;
363  }}
364  **/
365 
366  switch (rot) {
369  {{
370  /// 90 degree rotation tilts the image
371  int row_len = (orig_ch->width + 7) / 8;
372  int new_row_len = (orig_ch->height + 7) / 8;
373  GLubyte* data = new GLubyte[new_row_len * orig_ch->width];
374  memset(data, 0, new_row_len * orig_ch->width * sizeof (GLubyte));
375 
376  new_char = new BitmapCharRec;
377  new_char->width = orig_ch->height;
378  new_char->height = orig_ch->width;
379  new_char->advance = orig_ch->advance;
380  new_char->bitmap = data;
381 
382  for(i = 0; i < new_char->height; i++) { // by rows
383  for(j = 0; j < new_row_len; j++) { // by columns
384  GLubyte *b = data + i * new_row_len + j;
385  // dest bit (j*8 + k, i) <-- (i, H - (j*8 + k) - 1), where H = orig_ch->height
386  // source byte = (i/8, H - j*8 - k - 1), bit offset = i % 8
387  int k; // dest bit offset
388  int max_k = min(8, new_char->width - j*8);
389  for(k = 0; k < max_k; k++){
390  int src_row = orig_ch->height - j * 8 - k - 1;
391  int src_bit = i;
392  int src_byte = src_bit / 8 + row_len * src_row;
393  int src_bit_off = src_bit % 8;
394  if(orig_ch->bitmap[src_byte] & (0x80 >> src_bit_off)){
395  *b |= (0x80 >> k);
396  }
397  }
398  }
399  }
400 
401  // new bitmap origin corner is original's top-left
402  new_char->yorig = orig_ch->xorig;
404  new_char->xorig = -orig_ch->yorig - (GLfloat)cap_ht + orig_ch->height;
405  } else {
406  new_char->xorig = -orig_ch->yorig + orig_ch->height;
407  }
408 
409  }}
410  break;
411 
414  {{
415  int row_len = (orig_ch->width + 7) / 8;
416  GLubyte* data = new GLubyte[row_len * orig_ch->height];
417  memset(data, 0, row_len * orig_ch->height * sizeof (GLubyte));
418 
419  new_char = new BitmapCharRec;
420  new_char->width = orig_ch->width;
421  new_char->height = orig_ch->height;
422  new_char->bitmap = data;
423 
424  for(i = 0; i < new_char->height; i++) { // by rows
425  for(j = 0; j < row_len; j++) { // by columns
426  GLubyte *b = data + i * row_len + j;
427  // dest bit (j*8 + k, i) <-- (W - (j*8 + k) - 1, H - i - 1),
428  // where H = orig_ch->height, W = orig_ch->width
429  int k;
430  int max_k = min(8, new_char->width - j*8);
431  for(k = 0; k < max_k; k++){
432  int src_row = orig_ch->height - i - 1;
433  int src_bit = orig_ch->width - j * 8 - k - 1;
434  int src_byte = src_bit / 8 + row_len * src_row;
435  int src_bit_off = src_bit % 8;
436  if(orig_ch->bitmap[src_byte] & (0x80 >> src_bit_off)){
437  *b |= (0x80 >> k);
438  }
439  }
440  }
441  }
442 
443  // new baseline is the same as old one
444  // new bitmap origin corner is original's top-right
446  new_char->xorig = -orig_ch->xorig + orig_ch->width;
447  new_char->yorig = -orig_ch->yorig + orig_ch->height;
448  } else {
449  new_char->xorig = -orig_ch->xorig + orig_ch->width;
450  new_char->yorig = -orig_ch->yorig + orig_ch->height - (GLfloat)cap_ht;
451  }
452  new_char->advance = -orig_ch->advance;
453 
454  }}
455  break;
456 
459  {{
460  /// 270 degree rotation is NOT just a transpose of the
461  /// original bitmap image
462  int row_len = (orig_ch->width + 7) / 8;
463  int new_row_len = (orig_ch->height + 7) / 8;
464  GLubyte* data = new GLubyte[new_row_len * orig_ch->width];
465  new_char = new BitmapCharRec;
466  new_char->width = orig_ch->height;
467  new_char->height = orig_ch->width;
468  new_char->bitmap = data;
469 
470  memset(data, 0, new_row_len * new_char->height * sizeof (GLubyte));
471 
472  for(i = 0; i < new_char->height; i++) { // by rows
473  for(j = 0; j < new_row_len; j++) { // by columns
474  GLubyte *b = data + i * new_row_len + j;
475  // dest bit (j*8 + k, i) <-- (W - i - 1, (j*8 + k)), where W = orig_ch->width
476  // source byte = ((W - i - 1)/8, j*8 + k), bit offset = (W - i - 1) % 8
477  int k; // dest bit offset
478  int max_k = min(8, new_char->width - j*8);
479  for(k = 0; k < max_k; k++){
480  int src_row = j * 8 + k;
481  int src_bit = orig_ch->width - i - 1;
482  int src_byte = src_bit / 8 + row_len * src_row;
483  int src_bit_off = src_bit % 8;
484  if(orig_ch->bitmap[src_byte] & (0x80 >> src_bit_off)){
485  *b |= (0x80 >> k);
486  }
487  }
488  }
489  }
490 
492  new_char->xorig = orig_ch->yorig;
493  new_char->yorig = -orig_ch->xorig + orig_ch->width;
494  } else {
495  new_char->xorig = orig_ch->yorig + (GLfloat)cap_ht;
496  new_char->yorig = -orig_ch->xorig + orig_ch->width;
497  }
498  new_char->advance = -orig_ch->advance;
499  }}
500  break;
501 
502  default:
503  break;
504  }
505 
506  /**
507  {{
508  int row_len = new_char->width / 8 + (new_char->width % 8 ? 1 : 0);
509  ostr << "0x" << hex << charidx << ": '"
510  << (char)charidx << "': "
511  << new_char->width << 'x' << new_char->height << ": "
512  << new_char->xorig << ',' << new_char->yorig << ": "
513  << new_char->advance
514  << endl;
515  for (j = 0; j < new_char->height; ++j) {
516  for (i = 0; i < new_char->width; ++i) {
517  int idx = j * row_len + i/8;
518  int bit = i % 8;
519  if (new_char->bitmap[idx] & (0x80 >> bit)) {
520  ostr << '*';
521  } else {
522  ostr << ' ';
523  }
524  }
525  ostr << endl;
526  }
527  ostr << endl;
528  }}
529  **/
530 
531  }
532  chars[charidx] = new_char;
533  }
534 
535  /// initialize our new bitmap structure
536  const char* name = NULL;
537  switch (rot) {
539  name = strdup((string(source_font->name) + "-rot90c").c_str());
540  break;
541 
543  name = strdup((string(source_font->name) + "-rot90b").c_str());
544  break;
545 
547  name = strdup((string(source_font->name) + "-rot180c").c_str());
548  break;
549 
551  name = strdup((string(source_font->name) + "-rot180b").c_str());
552  break;
553 
555  name = strdup((string(source_font->name) + "-rot270c").c_str());
556  break;
557 
559  name = strdup((string(source_font->name) + "-rot270b").c_str());
560  break;
561 
562  default:
563  /// can't happen
564  _ASSERT(false);
565  }
566 
567  BitmapFontPtr new_font = new BitmapFontRec;
568  new_font->name = name;
569  new_font->num_chars = source_font->num_chars;
570  new_font->first = source_font->first;
571  new_font->ch = chars;
572  return new_font;
573 }
574 
575 
576 static inline
579 {
580  const BitmapFontRec * font_ptr = s_FindFontPtr(font);
582 
583  switch (rot) {
585  return font_ptr;
586 
587  default:
594  {{
595  SRotateKey rk;
596  rk.font = font_ptr;
597  rk.rot = rot;
598  iter = s_RotatedCache.find(rk);
599  if (iter == s_RotatedCache.end()) {
600  const BitmapFontRec * ptr = s_CreateRotatedFont(font_ptr, rot);
601  s_RotatedCache[rk] = ptr;
602  iter = s_RotatedCache.find(rk);
603  }
604  }}
605  break;
606  }
607 
608  return iter->second;
609 }
610 
611 // return the width of a single character
612 // this is really the *advance* of a character
613 static TModelUnit s_GetCharAdvance(char c, const BitmapFontRec* font_ptr)
614 {
615  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, c);
616  return ch ? ch->advance : 0.0;
617 }
618 
619 static TModelUnit s_GetCharWidth(char c, const BitmapFontRec* font_ptr)
620 {
621  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, c);
622  if (ch) {
623  return ch->width - ch->xorig;
624  }
625  return 0.0;
626 }
627 
628 static TModelUnit s_GetCharBitmapWidth(char c, const BitmapFontRec* font_ptr)
629 {
630  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, c);
631  if (ch) {
632  return ch->width;
633  }
634  return 0.0;
635 }
636 
637 static TModelUnit s_GetCharDescender(char c, const BitmapFontRec* font_ptr)
638 {
639  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, c);
640  return ch ? ch->yorig : 0.0;
641 }
642 
644 {
645  float desc = 0.0;
646  for (int charidx = 0; charidx < font_ptr->num_chars; ++charidx) {
647  const BitmapCharRec* ch = font_ptr->ch[charidx];
648  desc = max(desc, ch->yorig);
649  }
650  return TModelUnit(desc);
651 }
652 
653 
654 
656  : m_Font(eBitmap8x13)
657  , m_FontRotate(eFontRotate_0)
658  , m_Condensed(false)
659 {
661 }
662 
663 
665  : m_Font(font)
666  , m_FontRotate(eFontRotate_0)
667  , m_Condensed(false)
668 {
669  SetFont(font);
670 }
671 
672 
674 {
675 }
676 
677 
679 {
680  m_Font = proto.m_Font;
681  m_FontRotate = proto.m_FontRotate;
682  m_Condensed = proto.m_Condensed;
683  return *this;
684 }
685 
686 
688 {
689  EFont font = static_cast<EFont>((m_Font & 0xff) | face);
690  SetFont(font);
691 }
692 
693 
695 {
696  return (EFontFace)(m_Font & 0xFFFFFF00);
697 }
698 
699 
701 {
702  EFont font = static_cast<EFont>((m_Font & ~0xff) | size);
703  SetFont(font);
704 }
705 
706 
708 {
709  return (EFontSize)(m_Font & 0xFF);
710 }
711 
712 
714 {
715  return m_FontRotate;
716 }
717 
718 
720 {
721  m_FontRotate = rot;
722 }
723 
724 
725 void CGlBitmapFont::SetCondensed(bool condensed)
726 {
727  m_Condensed = condensed;
728 }
729 
730 
732 {
733  return m_Condensed;
734 }
735 
736 
738 {
739  if (font != m_Font) {
740  m_Font = font;
741  }
742 }
743 
744 
746 {
747  return m_Font;
748 }
749 
750 
752 static const TFaceElem sc_FaceTagArray[] = {
753  { CGlBitmapFont::eFontFace_Bitmap, "Bitmap" },
754  { CGlBitmapFont::eFontFace_Helvetica, "Helvetica" },
755  { CGlBitmapFont::eFontFace_Lucida, "Lucida" },
756  { CGlBitmapFont::eFontFace_Courier, "Courier" },
757  { CGlBitmapFont::eFontFace_Clean, "Clean" },
758  { CGlBitmapFont::eFontFace_Fixed, "Fixed" },
759  { CGlBitmapFont::eFontFace_TimesRoman, "Times Roman" }
760 };
763 
764 
766 static const TSizeElem sc_SizeTagArray[] = {
769  { CGlBitmapFont::eFontSize_10, "10" },
770  { CGlBitmapFont::eFontSize_12, "12" },
771  { CGlBitmapFont::eFontSize_14, "14" },
772  { CGlBitmapFont::eFontSize_18, "18" },
773  { CGlBitmapFont::eFontSize_20, "20" },
774  { CGlBitmapFont::eFontSize_24, "24" },
775 };
778 
779 
780 void CGlBitmapFont::GetAllFaces(vector<string>& faces)
781 {
782  faces.clear();
783  ITERATE (TFaceMap, iter, sc_FaceMap) {
784  if (iter->first != eFontFace_Bitmap) {
785  faces.push_back(iter->second);
786  }
787  }
788 }
789 
790 
791 void CGlBitmapFont::GetAllSizes(vector<string>& sizes)
792 {
793  sizes.clear();
794  ITERATE (TSizeMap, iter, sc_SizeMap) {
795  sizes.push_back(iter->second);
796  }
797 }
798 
799 
801 {
802  TFaceMap::const_iterator iter = sc_FaceMap.find(face);
803  if (iter != sc_FaceMap.end()) {
804  return iter->second;
805  }
806  return string();
807 }
808 
809 
811 {
812  ITERATE (TFaceMap, iter, sc_FaceMap) {
813  if (str == iter->second) {
814  return iter->first;
815  }
816  }
817 
818  return (EFontFace) 0;
819 }
820 
821 
823 {
824  TSizeMap::const_iterator iter = sc_SizeMap.find(size);
825  if (iter != sc_SizeMap.end()) {
826  return iter->second;
827  }
828  return string();
829 }
830 
831 
833 {
834  ITERATE (TSizeMap, iter, sc_SizeMap) {
835  if (str == iter->second) {
836  return iter->first;
837  }
838  }
839 
840  return (EFontSize) 0;
841 }
842 
843 
845 {
846  string s ( NStr::IntToString(i) );
847  return SizeFromString(s);
848 }
849 
850 
852 {
853  string str = FaceToString(GetFontFace());
854  str += ",";
856  return str;
857 }
858 
859 
860 void CGlBitmapFont::FromString(const string& value)
861 {
862  string s_face, s_size;
863 
864  bool ok = false;
865  if(NStr::SplitInTwo(value, ",", s_face, s_size)) {
866  NStr::TruncateSpaces(s_face);
867  NStr::TruncateSpaces(s_size);
868 
869  EFontFace face = FaceFromString(s_face);
870  EFontSize size = SizeFromString(s_size);
871 
872  if(face != 0 && size != 0) {
873  SetFontFace(face);
874  SetFontSize(size);
875  ok = true;
876  }
877  }
878  if(! ok) {
879  NCBI_THROW2(CStringException, eConvert, "String cannot be converted to a CGlBitmapFont", 0);
880  }
881 }
882 
883 
885 {
886  return s_GetFont(m_Font, rot);
887 }
888 
889 const void* CGlBitmapFont::GetFontPtr() const
890 {
891  return s_FindFontPtr(m_Font);
892 }
893 
895 {
896  const BitmapFontRec *font_ptr = s_FindFontPtr(m_Font);
897  return s_GetFontDescender(font_ptr);
898 }
899 
900 
901 template<class TOutputMethod>
902 void DoTextOut(TOutputMethod& method)
903 {
904  // save a bunch of states
905  GLint swapbytes;
906  GLint lsbfirst;
907  GLint rowlength;
908  GLint skiprows;
909  GLint skippixels;
910  GLint alignment;
911  glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
912  glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
913  glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
914  glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
915  glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
916  glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
917 
918  glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
919  glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
920  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
921  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
922  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
923  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
924 
925  // render our text
926  method();
927 
928  // restore states
929  glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
930  glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
931  glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
932  glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
933  glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
934  glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
935 }
936 
937 
939 {
940 public:
941  CTextPrinter(const char* text, const BitmapFontRec* font_ptr,
942  CGlBitmapFont::EFontRotate rot, bool condensed = false)
943  : m_Text(text),
944  m_FontPtr(font_ptr),
945  m_FontRotate(rot),
946  m_Condensed(condensed)
947  {
948  }
949 
950 
951  void operator()()
952  {
953  GLfloat pos[4];
954  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
955  TModelUnit x_adv = 0.0, y_adv = 0.0;
956  for (const char* p = m_Text; p && *p; ++p) {
957  const BitmapCharRec *ch = s_GetCharPtr(m_FontPtr, *p);
958  if (ch) {
959  TModelUnit x_orig = ch->xorig, y_orig = ch->yorig;
960  switch (m_FontRotate) {
961  default:
963  if(m_Condensed){
964  x_adv = ch->width + 1.0;
965  x_orig = 0.0;
966  } else
967  x_adv = ch->advance;
968  break;
969 
972  if(m_Condensed){
973  x_adv = -ch->width - 1.0;
974  x_orig = ch->width;
975  } else
976  x_adv = ch->advance;
977  break;
978 
981  if(m_Condensed){
982  y_adv = ch->height + 1.0;
983  y_orig = 0.0;
984  } else
985  y_adv = ch->advance;
986  break;
987 
990  if(m_Condensed){
991  y_adv = -ch->height - 1.0;
992  y_orig = ch->height;
993  } else
994  y_adv = ch->advance;
995  break;
996 
997  }
998  glBitmap(ch->width, ch->height,
999  (GLfloat)x_orig, (GLfloat)y_orig,
1000  (GLfloat)x_adv, (GLfloat)y_adv, ch->bitmap);
1001  }
1002  }
1003  };
1004 protected:
1005  const char* const m_Text;
1006  const BitmapFontRec* const m_FontPtr;
1008  const bool m_Condensed;
1009 };
1010 
1011 
1012 
1013 // TextOut()
1014 // This version performs most of the low-level work. It simply
1015 // outputs text at a previously determined raster position
1016 void CGlBitmapFont::TextOut(const char* text) const
1017 {
1018  GLint mode;
1019  glGetIntegerv(GL_RENDER_MODE, &mode);
1020  switch (mode) {
1021  case GL_FEEDBACK:
1022  {{
1023  GLfloat pos[4];
1024  GLfloat col[4];
1025 
1026  // Not sure we should do this (this is the color
1027  // set after first call to glRasterPos if lighting
1028  // is enabled, which it may not be.)
1029  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
1030  glGetFloatv(GL_CURRENT_RASTER_COLOR, col);
1031 
1032  const CRgbaColor c(col, 4);
1033 
1034  typedef vector<float> TFList;
1035  TFList vectext =
1036  CGlFeedbackFont::EncodeText(pos, c, text, strlen(text));
1037  ITERATE (TFList, it, vectext) {
1038  glPassThrough(*it);
1039  }
1040  }}
1041  break;
1042 
1043  default:
1044  {{
1045  // first, retrieve our OpenGL font
1046  CTextPrinter printer(text,
1049  DoTextOut(printer);
1050  }}
1051  break;
1052  }
1053 }
1054 
1056 {
1057 public:
1059  const vector<CRgbaColor*>* colors,
1061  TModelUnit scale_x, TModelUnit scale_y,
1062  CGlBitmapFont* font)
1063  : m_Text(text),
1064  m_Colors(colors),
1065  m_X(x),
1066  m_Y(y),
1067  m_dX(dx),
1068  m_dY(dy),
1069  m_ScaleX(scale_x),
1070  m_ScaleY(scale_y),
1071  m_CapHeight(0),
1072  m_Font(font)
1073  {
1075  }
1076 
1077  void operator()()
1078  {
1079  const BitmapFontRec * font_ptr
1081  TModelUnit k_x = m_ScaleX / 2;
1082  TModelUnit k_y = m_ScaleY / 2;
1083 
1084  for (const char* p = m_Text; p && *p; ++p) {
1085  const BitmapCharRec *ch = s_GetCharPtr(font_ptr, *p);
1086  if(ch) {
1087  int ind = (int)(p - m_Text);
1088  TModelUnit pos_x = m_X + ind * m_dX;
1089  TModelUnit pos_y = m_Y + ind * m_dY;
1090  TModelUnit off_x;
1091  TModelUnit off_y;
1092 
1093  off_x = ch->width * k_x; // to current coord system
1094  off_y = ch->height * k_y; // to current coord system
1095 
1096  if(m_Colors) {
1097  CRgbaColor& c = *(*m_Colors)[ind];
1098  glColorC(c);
1099  }
1100 
1101 
1102  switch (m_Font->GetFontRotate()) {
1103  default:
1105  CTextUtils::SetRasterPosSafe(pos_x - off_x, pos_y);
1106  glBitmap(ch->width, ch->height, 0, ch->yorig,
1107  ch->advance, 0, ch->bitmap);
1108  break;
1109 
1111  CTextUtils::SetRasterPosSafe(pos_x - m_CapHeight, pos_y - off_y);
1112  glBitmap(ch->width, ch->height, ch->xorig, 0,
1113  0, ch->advance, ch->bitmap);
1114  break;
1115 
1117  CTextUtils::SetRasterPosSafe(pos_x, pos_y - off_y);
1118  glBitmap(ch->width, ch->height, ch->xorig, 0,
1119  0, ch->advance, ch->bitmap);
1120  break;
1121 
1123  CTextUtils::SetRasterPosSafe(pos_x - off_x, pos_y + m_CapHeight);
1124  glBitmap(ch->width, ch->height, 0, ch->yorig,
1125  ch->advance, 0, ch->bitmap);
1126  break;
1127 
1129  CTextUtils::SetRasterPosSafe(pos_x - off_x, pos_y);
1130  glBitmap(ch->width, ch->height, 0, ch->yorig,
1131  ch->advance, 0, ch->bitmap);
1132  break;
1133 
1135  CTextUtils::SetRasterPosSafe(pos_x, pos_y + off_y - ch->height);
1136  glBitmap(ch->width, ch->height, ch->xorig, 0,
1137  0, 0, ch->bitmap);
1138  break;
1139 
1141  CTextUtils::SetRasterPosSafe(pos_x + m_CapHeight, pos_y + off_y - ch->height);
1142  glBitmap(ch->width, ch->height, ch->xorig, 0,
1143  0, 0, ch->bitmap);
1144  break;
1145  }
1146  }
1147  }
1148  };
1149 
1150 protected:
1151  const char* m_Text;
1152  const vector<CRgbaColor*>* m_Colors;
1161 };
1162 
1163 
1165 {
1166 public:
1169  TModelUnit scale_x, TModelUnit scale_y,
1170  const BitmapFontRec * const & font_ptr)
1171  : m_Text(text),
1172  m_X(x),
1173  m_Y(y),
1174  m_dX(dx),
1175  m_dY(dy),
1176  m_ScaleX(scale_x),
1177  m_ScaleY(scale_y),
1178  m_FontPtr(font_ptr)
1179  {
1180  }
1181 
1182  void operator()()
1183  {
1184  TModelUnit k_x = m_ScaleX / 2;
1185  TModelUnit k_y = m_ScaleY / 2;
1186 
1187  for (const char* p = m_Text; p && *p; ++p) {
1188  if (*p < m_FontPtr->first ||
1189  *p >= m_FontPtr->first + m_FontPtr->num_chars) {
1190  continue;
1191  }
1192  const BitmapCharRec *ch = m_FontPtr->ch[*p - m_FontPtr->first];
1193  if (ch ) {
1194  int ind = (int)(p - m_Text);
1195  TModelUnit pos_x = m_X + ind * m_dX;
1196  TModelUnit pos_y = m_Y + ind * m_dY;
1197  TModelUnit off_x = ch->width * k_x; // to current coord system
1198  TModelUnit off_y = ch->height * k_y; // to current coord system
1199 
1200  CTextUtils::SetRasterPosSafe(pos_x - off_x, pos_y - off_y);
1201 
1202  GLfloat pos[4];
1203  GLfloat col[4];
1204 
1205  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
1206  glGetFloatv(GL_CURRENT_RASTER_COLOR, col);
1207 
1208  const CRgbaColor c(col, 4);
1209 
1210  typedef vector<float> TFList;
1211  TFList vectext =
1212  CGlFeedbackFont::EncodeText(pos, c, p, 1);
1213  ITERATE (TFList, it, vectext) {
1214  glPassThrough(*it);
1215  }
1216  }
1217  }
1218  };
1219 protected:
1220  const char* m_Text;
1227  const BitmapFontRec * const& m_FontPtr;
1228 };
1229 
1230 
1232  const char* text,
1233  const vector<CRgbaColor*>* colors,
1234  TModelUnit scale_x, TModelUnit scale_y) const
1235 {
1236  GLint mode;
1237  glGetIntegerv(GL_RENDER_MODE, &mode);
1238  switch (mode) {
1239  case GL_FEEDBACK:
1240  {
1241  // first, retrieve our OpenGL font
1242  const BitmapFontRec * font_ptr = s_GetFont(m_Font, m_FontRotate);
1243  CFeedbackTextArrayPrinter printer(text, x, y, dx, dy,
1244  scale_x, scale_y, font_ptr);
1245  DoTextOut(printer);
1246  }
1247  break;
1248  default:
1249  {
1250  CTextArrayPrinter printer(text, colors,
1251  x, y, dx, dy,
1252  scale_x, scale_y,
1253  const_cast<CGlBitmapFont*>(this));
1254  DoTextOut(printer);
1255  }
1256  break;
1257  }
1258 }
1259 
1260 
1261 // This version of TextOut() performs some label alignment in the specified box
1263  const char* text, TAlign align, ETruncate trunc,
1264  TModelUnit scale_x, TModelUnit scale_y) const
1265 {
1266  if(x2 < x1) {
1267  swap(x1, x2);
1268  }
1269  if(y2 < y1) {
1270  swap(y1, y2);
1271  }
1272  TModelUnit x = x1;
1273  TModelUnit y = y1;
1274  TModelUnit w = x2 - x1;
1275  TModelUnit h = y2 - y1;
1276 
1277  /// truncate as appropriate
1278  string str;
1279  switch (trunc) {
1280  case eTruncate_None:
1281  str = text;
1282  break;
1283 
1284  case eTruncate_Empty:
1285  case eTruncate_Ellipsis:
1286  {{
1287  TModelUnit text_width = w;
1288  switch (GetFontRotate()) {
1289  case eFontRotate_0:
1290  case eFontRotate_180_Base:
1291  case eFontRotate_180_Cap:
1292  text_width = w;
1293  break;
1294 
1295  case eFontRotate_90_Base:
1296  case eFontRotate_90_Cap:
1297  case eFontRotate_270_Base:
1298  case eFontRotate_270_Cap:
1299  text_width = h;
1300  break;
1301  }
1302 
1303  x_Truncate(text, text_width, trunc, &str);
1304  }}
1305  break;
1306  }
1307 
1308  ///
1309  /// determine where our text starts
1310  ///
1311  TModelUnit ras_x = 0;
1312  TModelUnit ras_y = 0;
1313 
1314  EFontRotate rot = GetFontRotate();
1315  switch (rot) {
1316  case eFontRotate_0:
1317  // eAlign_Right or eAlign_Center are applied to horz position only if
1318  // eAlign_Left is not specifed
1319  if ((align & eAlign_HorizMask) == eAlign_Left) {
1320  ras_x = x;
1321  } else if ((align & eAlign_HorizMask) == eAlign_Right) {
1322  // right justify
1323  TModelUnit text_wid = TextWidth(str.c_str()) * scale_x;
1324  ras_x = x + (w - text_wid);
1325  } else { // center
1326  TModelUnit text_wid = TextWidth(str.c_str()) * scale_x;
1327  ras_x = x + (w - text_wid) * 0.5;
1328  }
1329 
1330  if ((align & eAlign_VertMask) == eAlign_Bottom) {
1331  ras_y = y;
1332  } else if ((align & eAlign_VertMask) == eAlign_Top) {
1333  // skip down enough to keep our text inside
1334  TModelUnit text_ht = TextHeight() * scale_y;
1335  ras_y = y + (h - text_ht);
1336  } else {
1337  // if nothing given or eAlign_Center is specified - center
1338  // vertically
1339  TModelUnit text_ht = TextHeight() * scale_y;
1340  ras_y = y + (h - text_ht) * 0.5;
1341  }
1342  break;
1343 
1344  case eFontRotate_90_Base:
1345  case eFontRotate_90_Cap:
1346  // eAlign_Right or eAlign_Center are applied to horz position only if
1347  // eAlign_Left is not specifed
1348  if ((align & eAlign_HorizMask) == eAlign_Left) {
1349  ras_y = y;
1350  } else if ((align & eAlign_HorizMask) == eAlign_Right) {
1351  // right justify
1352  TModelUnit text_wid = TextWidth(str.c_str()) * scale_y;
1353  ras_y = y + (h - text_wid);
1354  } else { // center
1355  TModelUnit text_wid = TextWidth(str.c_str()) * scale_y;
1356  ras_y = y + (h - text_wid) * 0.5;
1357  }
1358 
1359  // descender is not taken into account
1360  if ((align & eAlign_VertMask) == eAlign_Bottom) {
1361  // skip down enough to keep our text inside
1362  TModelUnit text_ht = TextHeight() * scale_x;
1363  if (rot == eFontRotate_90_Base)
1364  ras_x = x + w;
1365  else
1366  ras_x = x + w - text_ht;
1367  } else if ((align & eAlign_VertMask) == eAlign_Top) {
1368  if (rot == eFontRotate_90_Base) {
1369  TModelUnit text_ht = TextHeight() * scale_x;
1370  ras_x = x - text_ht;
1371  } else
1372  ras_x = x;
1373  } else {
1374  // if nothing given or eAlign_Center is specified - center
1375  // vertically
1376  TModelUnit text_ht = TextHeight() * scale_x;
1377  if (rot == eFontRotate_90_Base)
1378  ras_x = x + (w + text_ht) * 0.5;
1379  else
1380  ras_x = x + (w - text_ht) * 0.5;
1381  }
1382  break;
1383 
1384  case eFontRotate_180_Base:
1385  case eFontRotate_180_Cap:
1386  // eAlign_Right or eAlign_Center are applied to horz position only if
1387  // eAlign_Left is not specifed
1388  if ((align & eAlign_HorizMask) == eAlign_Left) {
1389  ras_x = x + w;
1390  } else if ((align & eAlign_HorizMask) == eAlign_Right) {
1391  // right justify
1392  TModelUnit text_wid = TextWidth(str.c_str()) * scale_x;
1393  ras_x = x + text_wid;
1394  } else { // center
1395  TModelUnit text_wid = TextWidth(str.c_str()) * scale_x;
1396  ras_x = x + w - (w - text_wid) * 0.5;
1397  }
1398 
1399  if ((align & eAlign_VertMask) == eAlign_Bottom) {
1400  if (rot == eFontRotate_180_Base) {
1401  TModelUnit text_ht = TextHeight() * scale_y;
1402  ras_y = y - text_ht;
1403  } else
1404  ras_y = y;
1405  } else if ((align & eAlign_VertMask) == eAlign_Top) {
1406  // skip down enough to keep our text inside
1407  TModelUnit text_ht = TextHeight() * scale_y;
1408  if (rot == eFontRotate_180_Base)
1409  ras_y = y + h;
1410  else
1411  ras_y = y + (h - text_ht);
1412  } else {
1413  // if nothing given or eAlign_Center is specified - center
1414  // vertically
1415  TModelUnit text_ht = TextHeight() * scale_y;
1416  if (rot == eFontRotate_180_Base)
1417  ras_y = y + (h + text_ht) * 0.5;
1418  else
1419  ras_y = y + (h - text_ht) * 0.5;
1420  }
1421  break;
1422 
1423  case eFontRotate_270_Cap:
1424  case eFontRotate_270_Base:
1425  // eAlign_Right or eAlign_Center are applied to horz position only if
1426  // eAlign_Left is not specifed
1427  if ((align & eAlign_HorizMask) == eAlign_Left) {
1428  ras_y = y + h;
1429  } else if ((align & eAlign_HorizMask) == eAlign_Right) {
1430  // right justify
1431  TModelUnit text_wid = TextWidth(str.c_str()) * scale_y;
1432  ras_y = y + text_wid;
1433  } else { // center
1434  TModelUnit text_wid = TextWidth(str.c_str()) * scale_y;
1435  ras_y = y + (h + text_wid) * 0.5f;
1436  }
1437 
1438  if ((align & eAlign_VertMask) == eAlign_Bottom) {
1439  if (rot == eFontRotate_270_Base)
1440  ras_x = x;
1441  else {
1442  TModelUnit text_ht = TextHeight() * scale_y;
1443  ras_x = x + text_ht;
1444  }
1445  } else if ((align & eAlign_VertMask) == eAlign_Top) {
1446  // skip down enough to keep our text inside
1447  if (rot == eFontRotate_270_Base) {
1448  TModelUnit text_ht = TextHeight() * scale_x;
1449  ras_x = x + (w - text_ht);
1450  } else
1451  ras_x = x + w;
1452  } else {
1453  // if nothing given or eAlign_Center is specified - center
1454  // vertically
1455  TModelUnit text_ht = TextHeight() * scale_x;
1456  if (rot == eFontRotate_270_Base) {
1457  ras_x = x + (w - text_ht) * 0.5f;
1458  } else {
1459  ras_x = x + (w + text_ht) * 0.5f;
1460  }
1461  }
1462  break;
1463  }
1464 
1465  TextOut(ras_x, ras_y, str.c_str());
1466 }
1467 
1468 void CGlBitmapFont::TextOut(TModelUnit x, TModelUnit y, const char* text) const
1469 {
1471 
1472  TextOut(text);
1473 }
1474 
1475 //
1476 // compute the width of a string of characters
1477 // this will count out at most n characters, stopping on a null
1478 // note that the comparison function used for 'n' is 0 or non-zero -
1479 // so passing '-1' for 'n' means 'compute until a null character is found'
1480 // This allows us to avoid calling strlen()
1481 //
1483 {
1484  return GetMetric(eMetric_TextWidth, text, n);
1485 }
1486 
1487 
1488 /// compute the length of a null-terminated string
1490 {
1491  return GetMetric(eMetric_TextWidth, text);
1492 }
1493 
1494 
1495 /// compute the height of a string
1497 {
1498  return GetMetric(eMetric_CharHeight);
1499 }
1500 
1501 
1503 {
1504  const BitmapFontRec * const& font_ptr = s_FindFontPtr(m_Font);
1505  return m_Condensed? s_GetCharBitmapWidth(c, font_ptr) + 1 : s_GetCharAdvance(c, font_ptr);
1506 }
1507 
1508 
1509 // generic text metric retrieval
1511  const char* text, int text_len) const
1512 {
1513  // first, retrieve our OpenGL font
1514  const BitmapFontRec* font_ptr = s_FindFontPtr(m_Font);
1515 
1516  switch (metric) {
1517  case eMetric_CharHeight:
1518  // return the height of a capital letter
1519  {{
1520  // we first scan the capital letters, this gives us the height
1521  // of the text without descents but with ascents
1522  static const char* sc_caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1523  GLsizei max_ht = 0;
1524 
1525  for (const char* p = sc_caps; p && *p; ++p) {
1526  const BitmapCharRec *ch = font_ptr->ch[*p - font_ptr->first];
1527  if (ch) {
1528  GLsizei ht = GLsizei(ch->height - ch->yorig);
1529  max_ht = max(max_ht, ht);
1530  }
1531  }
1532  return max_ht;
1533  }}
1534 
1536  // return the maximal height of all available characters
1537  {{
1538  // we first scan the capital letters
1539  // this gives us the height of the text without descents but with
1540  // ascents
1541  GLsizei max_ht = 0;
1542  for (int i = font_ptr->first; i < font_ptr->num_chars; ++i) {
1543  const BitmapCharRec *ch = font_ptr->ch[i];
1544  if (ch) {
1545  GLsizei ht = GLsizei(ch->height - ch->yorig);
1546  max_ht = max(max_ht, ht);
1547  }
1548  }
1549  return max_ht;
1550  }}
1551 
1552  case eMetric_AvgCharWidth:
1553  // return the maximal height of all available characters
1554  {{
1555  // we first scan the capital letters
1556  // this gives us the height of the text without descents but with
1557  // ascents
1558  GLfloat wid = 0;
1559  GLsizei count = 0;
1560  for (int i = font_ptr->first; i < font_ptr->num_chars; ++i) {
1561  const BitmapCharRec *ch = font_ptr->ch[i];
1562  if (ch) {
1563  wid += ch->advance;
1564  ++count;
1565  }
1566  }
1567  return wid / float(count);
1568  }}
1569 
1570  case eMetric_MaxCharWidth:
1571  // return the maximal height of all available characters
1572  {{
1573  // we first scan the capital letters this gives us the height
1574  // of the text without descents but with ascents
1575  GLfloat wid = 0;
1576  GLsizei count = 0;
1577  for (int i = font_ptr->first; i < font_ptr->num_chars; ++i) {
1578  const BitmapCharRec *ch = font_ptr->ch[i];
1579  if (ch) {
1580  wid = max(ch->advance, wid);
1581  ++count;
1582  }
1583  }
1584  return wid;
1585  }}
1586 
1587  case eMetric_TextWidth:
1588  case eMetric_FullTextWidth:
1589  // return the width of the text with or without the final advance
1590  if (text) {
1591  // iterate over our text
1592  TModelUnit sum = 0.0;
1593  const char* p = text;
1594  for ( ; text_len && p && *p; ++p, --text_len) {
1595  sum += m_Condensed? s_GetCharBitmapWidth(*p, font_ptr) + 1.0 : s_GetCharAdvance(*p, font_ptr);
1596  }
1597 
1598  // adjust for the trailing character
1599  if (p && metric == eMetric_TextWidth) {
1600  --p;
1601  if(m_Condensed)
1602  sum -= 1.0;
1603  else
1604  sum += s_GetCharWidth(*p, font_ptr) - s_GetCharAdvance(*p, font_ptr);
1605  }
1606  return sum;
1607  }
1608  break;
1609 
1610  case eMetric_Descender:
1611  // return character descender for a given string
1612  // use to define the string base line
1613  if(text) {
1614  TModelUnit desc = 0.0;
1615  const char *p = text;
1616  for( ; text_len && p && *p; ++p, --text_len) {
1617  desc = max(desc, s_GetCharDescender(*p, font_ptr));
1618  }
1619  return desc;
1620  }
1621  break;
1622 
1623  default:
1624  break;
1625  }
1626 
1627  return 0.0;
1628 }
1629 
1630 
1632 {
1633  string res;
1634  x_Truncate(text, w, trunc, &res);
1635  return res;
1636 }
1637 
1638 
1639 string CGlBitmapFont::Truncate(const string& str, TModelUnit w, ETruncate trunc) const
1640 {
1641  string res;
1642  x_Truncate(str.c_str(), w, trunc, &res);
1643  return res;
1644 }
1645 
1646 
1647 // Truncate a string for display. This version will return the maximum
1648 // number of characters that can fit into the given width
1650  string* str) const
1651 {
1652  // first, retrieve our OpenGL font
1653  const BitmapFontRec* font_ptr = s_GetFont(m_Font, m_FontRotate);
1654  static const char* sc_ellipsis = "...";
1655  const char* ellip = NULL;
1656 
1657  const char* end_pos = text;
1658  switch (trunc) {
1659  case eTruncate_None:
1660  end_pos = text + strlen(text);
1661  break;
1662 
1663  case eTruncate_Ellipsis: {
1664  // first, do a blunt cut
1665  int pos = x_Truncate(text, w, eTruncate_Empty);
1666  end_pos = text + pos;
1667  if ( !*end_pos ) {
1668  // we can fit the whole thing
1669  break;
1670  }
1671 
1672  // adjust for the ellipsis
1673  TModelUnit e_wid = TextWidth(sc_ellipsis);
1674  while (e_wid > 0) {
1675  ellip = sc_ellipsis;
1676  e_wid -= s_GetCharWidth(*end_pos, font_ptr);
1677  if (end_pos > text) {
1678  --end_pos;
1679  } else {
1680  break;
1681  }
1682  }
1683  }
1684  break;
1685 
1686  case eTruncate_Empty:
1687  for ( ; end_pos && *end_pos && w >= 0; ++end_pos) {
1688  TModelUnit wid = s_GetCharAdvance(*end_pos, font_ptr);
1689  if (w - wid < 0) {
1690  wid = s_GetCharWidth(*end_pos, font_ptr);
1691  }
1692 
1693  w -= wid;
1694  }
1695 
1696  if (w < 0) {
1697  --end_pos;
1698  }
1699  break;
1700  }
1701 
1702  if (end_pos < text) {
1703  end_pos = text;
1704  }
1705 
1706  if (str) {
1707  str->assign(text, end_pos);
1708  if (ellip) {
1709  *str += ellip;
1710  }
1711  }
1712  return (int)(end_pos - text);
1713 }
1714 
1715 
1716 static const char* kPostfixes[] = { "", " K", " M", " G" };
1717 
1718 
1719 string CTextUtils::FormatSeparatedNumber(int Number, bool b_postfix)
1720 {
1721  bool bNegative = Number < 0;
1722  Number = abs(Number);
1723 
1724  string s_number, s_postfix;
1725  char cSep = ',';
1726 
1727  int i_postfix = 0;
1728  if(Number != 0 && b_postfix) {
1729  int Rest = Number % 1000;
1730  for( i_postfix = 0; Rest == 0; i_postfix++) {
1731  Number = Number / 1000;
1732  Rest = Number % 1000;
1733  }
1734  _ASSERT(i_postfix < 4);
1735  s_postfix = kPostfixes[i_postfix];
1736  }
1737 
1738  char sTemplGroup[] = " %.3d";
1739  sTemplGroup[0] = cSep;
1740  char sTemplLast[] = "%d";
1741 
1742  char S[20];
1743  do {
1744  int Rest = Number % 1000;
1745  Number = Number / 1000;
1746  sprintf(S, Number ? sTemplGroup : sTemplLast, Rest);
1747  s_number = string(S) + s_number;
1748  } while(Number);
1749  s_number += s_postfix;
1750 
1751  if(bNegative) {
1752  s_number = "-" + s_number;
1753  }
1754  return s_number;
1755 }
1756 
1757 
1759 {
1760  int MaxDigits = (int) ceil( log10((double) Number)); // decimal digist in number
1761  int nSep = (MaxDigits - 1) / 3; // number of separators between groups
1762  return MaxDigits + nSep;
1763 }
1764 
1765 
1767 {
1768  double max_dig_w = 0;
1769 
1770  for( char c = '0'; c <= '9'; c++) {
1771  double char_w = font.GetAdvance(c);
1772  max_dig_w = max(max_dig_w, char_w);
1773  }
1774  double comma_w = font.GetAdvance(',');
1775 
1776  double mod = abs(max_num);
1777  int digits_count = (int) ceil(log10(mod));
1778  int commas_count = (digits_count - 1) / 3;
1779 
1780  // length of the longest possible label in pixels (add 2 for separation)
1781  double w = digits_count * max_dig_w + commas_count * comma_w;
1782  if(max_num < 0) {
1783  w += font.GetAdvance('-');
1784  }
1785  return w;
1786 }
1787 
1789 {
1790  // Set the current raster position
1791  glRasterPos2d(x, y);
1792 
1793  // check if the position was valid (if (x,y) projects ont a pixel inside
1794  // the viewport boundary):
1795  GLboolean valid;
1796  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
1797 
1798 
1799  // If the raster position is outside of the viewport, nothing will
1800  // display on screen, even if the text extends from outside the
1801  // viewport to inside. So instead we do a 'trick' where we
1802  // set the raster position to a point inside the viewport,
1803  // then call glBitmap(...) to move the raster position to the
1804  // correct position outside of the viewport.
1805 
1806  // Note that this does slow things down if you draw lots of off-screen
1807  // text, so avoid drawing text that is fully outside the viewing area.
1808  // (probably because drawing to invalid raster positions has no cost)
1809  if (!valid) {
1810  GLdouble modelview_matrix[16];
1811  GLdouble projection_matrix[16];
1812  GLint viewport[4];
1813 
1814  glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
1815  glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
1816  glGetIntegerv(GL_VIEWPORT, viewport);
1817 
1818  // Get the window coordinates of the current raster position. Since
1819  // our raster position is invaid, this will be outside of the viewport
1820  // bounds.
1821  GLdouble wx, wy, wz;
1822  gluProjectX(x, y, 0.0,
1823  modelview_matrix, projection_matrix, viewport,
1824  &wx, &wy, &wz);
1825 
1826  // Now get the world coordinates of the window position at the center
1827  // of the viewport. (This will give us a point in world coordinates that
1828  // we know projects to a valid raster position).
1829  GLdouble unprojected_center_x = 0;
1830  GLdouble unprojected_center_y = 0;
1831  GLdouble unprojected_center_z = 0;
1832  GLdouble centerx = viewport[0] + (viewport[2]-viewport[0])/2.0;
1833  GLdouble centery = viewport[1] + (viewport[3]-viewport[1])/2.0;
1834  gluUnProjectX( centerx, centery, 0.0,
1835  modelview_matrix, projection_matrix, viewport,
1836  &unprojected_center_x, &unprojected_center_y, &unprojected_center_z);
1837 
1838  // Set the current raster position to the center of the viewport
1839  glRasterPos2d(unprojected_center_x, unprojected_center_y);
1840 
1841  // Get the delta (in raster coordinates) between text position which is
1842  // outside of the window area and the center of the viewport, then
1843  // move that distance to give us the correct raster position.
1844  GLfloat deltax = (GLfloat)(wx-centerx);
1845  GLfloat deltay = (GLfloat)(wy-centery);
1846  glBitmap(0, 0,
1847  0.0f, 0.0f,
1848  deltax, deltay, NULL);
1849  }
1850 }
1851 
1852 
const BitmapFontRec *const & m_FontPtr
CFeedbackTextArrayPrinter(const char *text, TModelUnit x, TModelUnit y, TModelUnit dx, TModelUnit dy, TModelUnit scale_x, TModelUnit scale_y, const BitmapFontRec *const &font_ptr)
class CRgbaColor provides a simple abstraction for managing colors.
Definition: rgba_color.hpp:58
class CStaticArrayMap<> is an array adaptor that provides an STLish interface to statically-defined a...
Definition: static_map.hpp:105
TBase::const_iterator const_iterator
Definition: static_map.hpp:109
CStringException –.
Definition: ncbistr.hpp:4506
CGlBitmapFont * m_Font
const vector< CRgbaColor * > * m_Colors
CTextArrayPrinter(const char *text, const vector< CRgbaColor * > *colors, TModelUnit x, TModelUnit y, TModelUnit dx, TModelUnit dy, TModelUnit scale_x, TModelUnit scale_y, CGlBitmapFont *font)
const char * m_Text
TModelUnit m_CapHeight
const char *const m_Text
const bool m_Condensed
const BitmapFontRec *const m_FontPtr
const CGlBitmapFont::EFontRotate m_FontRotate
CTextPrinter(const char *text, const BitmapFontRec *font_ptr, CGlBitmapFont::EFontRotate rot, bool condensed=false)
container_type::iterator iterator
Definition: map.hpp:54
const_iterator end() const
Definition: map.hpp:152
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
static const Colors colors
Definition: cn3d_colors.cpp:50
#define S(s)
#define false
Definition: bool.h:36
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static int trunc
Definition: array_out.c:8
static const char * str(char *buf, int n)
Definition: stats.c:84
char data[12]
Definition: iconv.c:80
static const BitmapFontRec *const sc_ncbi_fixed_18_ptr
static const BitmapFontRec *const sc_ncbi_lucida_18_ptr
static const BitmapFontRec *const sc_ncbi_lucida_8_ptr
static const BitmapFontRec *const sc_ncbi_helvetica_10_ptr
static const BitmapFontRec *const sc_ncbi_lucida_12_ptr
static TModelUnit s_GetCharBitmapWidth(char c, const BitmapFontRec *font_ptr)
static TModelUnit s_GetCharAdvance(char c, const BitmapFontRec *font_ptr)
static const BitmapFontRec *const sc_ncbi_helvetica_12_ptr
map< SRotateKey, const BitmapFontRec *, SRotateKeyLess > TRotatedFontCache
static const BitmapFontRec *const sc_ncbi_times_12_ptr
static const BitmapFontRec *const sc_ncbi_fixed_8_ptr
static const BitmapFontRec *const sc_ncbi_courier_8_ptr
static const BitmapFontRec *const s_FindFontPtr(CGlBitmapFont::EFont font)
static const BitmapFontRec *const sc_ncbi_clean_6_ptr
static const BitmapFontRec *const sc_ncbi_clean_16_ptr
SStaticPair< CGlBitmapFont::EFont, const BitmapFontRec * > TFontPair
static const BitmapFontRec *const sc_ncbi_helvetica_14_ptr
static const BitmapFontRec *const sc_ncbi_clean_12_ptr
static const char * kPostfixes[]
static SRotatedFontCachePurger s_FontCachePurger
static const BitmapFontRec *const sc_ncbi_helvetica_6_ptr
static const BitmapFontRec *const sc_ncbi_helvetica_18_ptr
static const BitmapFontRec *const sc_ncbi_clean_10_ptr
static TModelUnit s_GetCharDescender(char c, const BitmapFontRec *font_ptr)
static const BitmapFontRec *const sc_ncbi_times_8_ptr
static const BitmapFontRec *const sc_ncbi_helvetica_24_ptr
static const BitmapFontRec *const sc_ncbi_times_10_ptr
static const BitmapFontRec *const sc_ncbi_courier_20_ptr
static const BitmapFontRec *const sc_ncbi_lucida_6_ptr
CStaticPairArrayMap< CGlBitmapFont::EFont, const BitmapFontRec * > TFontMap
static const BitmapFontRec *const sc_ncbi_times_14_ptr
static const BitmapFontRec *const sc_ncbi_helvetica_8_ptr
static const BitmapFontRec *const sc_ncbi_times_24_ptr
CStaticPairArrayMap< CGlBitmapFont::EFontFace, const char * > TFaceMap
static const BitmapFontRec *const s_GetFont(CGlBitmapFont::EFont font, CGlBitmapFont::EFontRotate rot)
static TModelUnit s_GetCharWidth(char c, const BitmapFontRec *font_ptr)
static const BitmapFontRec *const sc_ncbi_lucida_24_ptr
DEFINE_STATIC_ARRAY_MAP(TFontMap, sc_FontMap, sc_Fonts)
SStaticPair< CGlBitmapFont::EFontFace, const char * > TFaceElem
static const BitmapFontRec *const sc_ncbi_courier_14_ptr
static const BitmapFontRec *const sc_ncbi_times_18_ptr
void DoTextOut(TOutputMethod &method)
static const BitmapCharRec * s_GetCharPtr(const BitmapFontRec *font_ptr, int c)
static const BitmapFontRec *const sc_ncbi_courier_18_ptr
static const BitmapFontRec *const sc_ncbi_helvetica_20_ptr
CStaticPairArrayMap< CGlBitmapFont::EFontSize, const char * > TSizeMap
static const BitmapFontRec *const sc_ncbi_fixed_10_ptr
static const BitmapFontRec *const sc_ncbi_lucida_20_ptr
static const BitmapFontRec *const sc_ncbi_clean_15_ptr
static const BitmapFontRec *const sc_ncbi_fixed_12_ptr
static const BitmapFontRec *const sc_ncbi_courier_10_ptr
static const BitmapFontRec *const sc_ncbi_clean_8_ptr
static const BitmapFontRec *const sc_ncbi_lucida_14_ptr
static const TSizeElem sc_SizeTagArray[]
static const BitmapFontRec *const sc_ncbi_courier_24_ptr
static const BitmapFontRec *const sc_ncbi_clean_13_ptr
SStaticPair< CGlBitmapFont::EFontSize, const char * > TSizeElem
static const BitmapFontRec *const sc_ncbi_courier_6_ptr
static const BitmapFontRec *const sc_ncbi_times_6_ptr
static const TFaceElem sc_FaceTagArray[]
#define NCBI_FONT(x)
Standard non-rotated fonts; the explicit sc_foo_ptr business works around a bug in ICC 9,...
static TModelUnit s_GetFontDescender(const BitmapFontRec *font_ptr)
static const BitmapFontRec *const sc_ncbi_courier_12_ptr
static TRotatedFontCache s_RotatedCache
static TModelUnit s_GetCapHeight(const BitmapFontRec *font_ptr)
static const BitmapFontRec *const sc_ncbi_fixed_14_ptr
static const BitmapFontRec *const sc_ncbi_times_20_ptr
static const TFontPair sc_Fonts[]
static const BitmapFontRec *const sc_ncbi_lucida_10_ptr
static const BitmapFontRec * s_CreateRotatedFont(const BitmapFontRec *source_font, CGlBitmapFont::EFontRotate rot)
create a rotated font
static const BitmapFontRec *const sc_ncbi_fixed_20_ptr
static const BitmapFontRec *const sc_ncbi_clean_14_ptr
const BitmapFontRec ncbi_lucida_6
const BitmapFontRec ncbi_courier_20
const BitmapFontRec ncbi_clean_13
const BitmapFontRec ncbi_lucida_24
const BitmapFontRec ncbi_courier_12
const BitmapFontRec ncbi_fixed_8
Definition: ncbi_fixed8.c:2053
const BitmapFontRec ncbi_courier_14
const BitmapFontRec ncbi_helvetica_8
const BitmapFontRec ncbi_clean_16
const BitmapFontRec ncbi_clean_6
Definition: ncbi_clean6.c:1225
const BitmapFontRec ncbi_fixed_10
const BitmapFontRec ncbi_clean_12
const BitmapFontRec ncbi_clean_14
const BitmapFontRec ncbi_helvetica_20
const BitmapFontRec ncbi_clean_15
const BitmapFontRec ncbi_fixed_18
const BitmapFontRec ncbi_fixed_20
const BitmapFontRec ncbi_helvetica_10
const BitmapFontRec ncbi_times_14
const BitmapFontRec ncbi_times_18
const BitmapFontRec ncbi_lucida_18
const BitmapFontRec ncbi_courier_6
const BitmapFontRec ncbi_fixed_14
const BitmapFontRec ncbi_helvetica_6
const BitmapFontRec ncbi_times_24
const BitmapFontRec ncbi_lucida_20
const BitmapFontRec ncbi_helvetica_12
const BitmapFontRec ncbi_helvetica_14
const BitmapFontRec ncbi_lucida_12
const BitmapFontRec ncbi_courier_8
const BitmapFontRec ncbi_courier_24
const BitmapFontRec ncbi_courier_18
const BitmapFontRec ncbi_clean_10
const BitmapFontRec ncbi_lucida_8
const BitmapFontRec ncbi_times_6
Definition: ncbi_times6.c:1861
const BitmapFontRec ncbi_lucida_10
const BitmapFontRec ncbi_times_20
const BitmapFontRec ncbi_times_10
const BitmapFontRec ncbi_lucida_14
const BitmapFontRec ncbi_times_12
const BitmapFontRec ncbi_helvetica_18
const BitmapFontRec ncbi_courier_10
const BitmapFontRec ncbi_helvetica_24
const BitmapFontRec ncbi_times_8
Definition: ncbi_times8.c:1809
const BitmapFontRec ncbi_clean_8
Definition: ncbi_clean8.c:1175
const BitmapFontRec ncbi_fixed_12
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
#define NCBI_THROW2(exception_class, err_code, message, extra)
Throw exception with extra parameter.
Definition: ncbiexpt.hpp:1754
GLdouble TModelUnit
Definition: gltypes.hpp:48
int gluProjectX(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *winx, GLdouble *winy, GLdouble *winz)
Definition: glutils.hpp:223
static TModelUnit GetMaxWidth(int max_num, const CGlBitmapFont &font)
returns minimal space sufficient to render any number in the range [0, max_num].
bool IsCondensed(void) const
static void SetRasterPosSafe(TModelUnit x, TModelUnit y)
static string SizeToString(EFontSize size)
static EFontSize SizeFromInt(int i)
virtual void TextOut(const char *text) const
string Truncate(const char *, TModelUnit w, ETruncate trunc=eTruncate_Ellipsis) const
static void GetAllSizes(vector< string > &sizes)
void SetFontSize(EFontSize size)
int x_Truncate(const char *text, TModelUnit w, ETruncate trunc, string *str=NULL) const
EFontRotate m_FontRotate
The font - combination of face and size.
static string FaceToString(EFontFace face)
TModelUnit GetAdvance(char c) const
void SetFontRotate(EFontRotate rot)
static int GetCharsCount(int number)
returns number of characters in symbolic representation of the given number including non-digit separ...
static vector< float > EncodeText(GLfloat pos[4], const CRgbaColor &color, const char *text, size_t length)
Definition: glfont.cpp:57
static string FormatSeparatedNumber(int number, bool b_postfix=false)
virtual TModelUnit GetMetric(EMetric metric, const char *text_start=NULL, int len=-1) const
virtual TModelUnit TextHeight(void) const
compute the height of a string
static EFontFace FaceFromString(const string &str)
EFontRotate GetFontRotate(void) const
EFontFace GetFontFace() const
const void * GetFontPtr() const
virtual TModelUnit TextWidth(const char *text) const
compute the length of a null-terminated string
EFont GetFont() const
void FromString(const string &value)
bool m_Condensed
rotation state of the font
void SetFont(EFont font)
void glColorC(const CRgbaColor &color)
Definition: glutils.hpp:177
CGlBitmapFont & operator=(const CGlBitmapFont &)
void ArrayTextOut(TModelUnit x, TModelUnit y, TModelUnit dx, TModelUnit dy, const char *text, const vector< CRgbaColor * > *colors=NULL, TModelUnit scale_x=1.0f, TModelUnit scale_y=1.0f) const
prints array of characters in positions (x + i*dx, y + i*dy) where "i" is index of a character in the...
static EFontSize SizeFromString(const string &str)
void SetFontFace(EFontFace face)
void SetCondensed(bool condensed)
EFontSize GetFontSize() const
virtual TModelUnit GetFontDescender() const
string ToString() const
int gluUnProjectX(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz)
Definition: glutils.hpp:237
ETruncate
Definition: glfont.hpp:62
int TAlign
Definition: glfont.hpp:113
static void GetAllFaces(vector< string > &faces)
@ eAlign_Right
Definition: glfont.hpp:104
@ eAlign_Top
Definition: glfont.hpp:107
@ eAlign_Bottom
Definition: glfont.hpp:109
@ eAlign_Left
Definition: glfont.hpp:102
@ eAlign_HorizMask
Definition: glfont.hpp:101
@ eAlign_VertMask
Definition: glfont.hpp:106
@ eMetric_FullCharHeight
Definition: glfont.hpp:80
@ eMetric_AvgCharWidth
Definition: glfont.hpp:83
@ eMetric_FullTextWidth
Definition: glfont.hpp:93
@ eMetric_Descender
Definition: glfont.hpp:96
@ eMetric_TextWidth
Definition: glfont.hpp:90
@ eMetric_CharHeight
Definition: glfont.hpp:76
@ eMetric_MaxCharWidth
Definition: glfont.hpp:86
@ eTruncate_Empty
Definition: glfont.hpp:67
@ eTruncate_None
Definition: glfont.hpp:64
@ eTruncate_Ellipsis
Definition: glfont.hpp:70
@ eUnknown
Definition: app_popup.hpp:72
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3554
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int i
yy_size_t n
static void text(MDB_val *v)
Definition: mdb_dump.c:62
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::SIZE size
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
static const BitmapCharRec *const chars[]
Definition: ncbi_10x20.c:1829
#define strdup
Definition: ncbi_ansi_ext.h:70
#define abs(a)
Definition: ncbi_heapmgr.c:130
T max(T x_, T y_)
T log10(T x_)
T min(T x_, T y_)
Int mod(Int i, Int j)
Definition: njn_integer.hpp:67
GLfloat xorig
Definition: glutbitmap.h:21
GLsizei width
Definition: glutbitmap.h:19
GLfloat yorig
Definition: glutbitmap.h:22
GLsizei height
Definition: glutbitmap.h:20
GLfloat advance
Definition: glutbitmap.h:23
const GLubyte * bitmap
Definition: glutbitmap.h:24
const BitmapCharRec *const * ch
Definition: glutbitmap.h:31
const char * name
Definition: glutbitmap.h:28
bool operator()(const SRotateKey &rk1, const SRotateKey &rk2) const
rotated versions of the above we store a cache of these that is generated on the fly these fonts are ...
const BitmapFontRec * font
non-rotated font
CGlBitmapFont::EFontRotate rot
rotation type
Template structure SStaticPair is simlified replacement of STL pair<> Main reason of introducing this...
Definition: static_set.hpp:60
#define _ASSERT
void free(voidpf ptr)
Modified on Sat Jun 22 10:40:24 2024 by modify_doxy.py rev. 669887