Adonthell  0.4
win_ttf.cc
1 /*
2  (C) Copyright 2004/2016 Kai Sterker
3  Part of the Adonthell Project <http://adonthell.nongnu.org>
4 
5  Adonthell is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  Adonthell is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with Adonthell. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <config.h>
20 #include <ctype.h>
21 #include "win_ttf.h"
22 
23 // number of references to font file
24 u_int32 win_ttf::refcount = 0;
25 // path of the font file
26 std::string win_ttf::path_;
27 // font file used
28 TTF_Font *win_ttf::ttf = NULL;
29 
30 // ctor
31 win_ttf::win_ttf (const char *color, const string & file) : win_font ()
32 {
33  switch (color[0])
34  {
35  case 'r': // red
36  Color.r = 255; Color.g = 173; Color.b = 123;
37  break;
38  case 'b': // blue
39  Color.r = 139; Color.g = 185; Color.b = 238;
40  break;
41  case 'g': // green
42  Color.r = 205; Color.g = 254; Color.b = 148;
43  break;
44  case 'y': // yellow
45  Color.r = 255; Color.g = 238; Color.b = 123;
46  break;
47  case 'v': // violet
48  Color.r = 222; Color.g = 133; Color.b = 230;
49  break;
50  default: // white and all the rest
51  Color.r = 255; Color.g = 255; Color.b = 255;
52  break;
53  }
54 
55  refcount++;
56 
57  if (load (file))
58  {
59  int real_height_ = TTF_FontHeight(ttf) + screen::scale() - 1;
60  height_ = real_height_ / screen::scale();
61  cursor = &operator[]('_');
62  length_ = cursor->length ();
63  }
64  // fallback to old win_font implementation
65  else win_font::load ((char *) color);
66 }
67 
68 win_ttf::~win_ttf ()
69 {
70  refcount--;
71  if (refcount == 0 && ttf != NULL)
72  TTF_CloseFont (ttf);
73 }
74 
75 static int glyph_height (TTF_Font *ttf, const u_int16 & chr)
76 {
77  int miny, maxy;
78  if (TTF_GlyphIsProvided(ttf, chr))
79  {
80  TTF_GlyphMetrics(ttf, chr, NULL, NULL, &miny, &maxy, NULL);
81  return maxy - miny;
82  }
83  return TTF_FontHeight(ttf)/2;
84 }
85 
86 bool win_ttf::load (const string & file)
87 {
88  string path;
89  int avg_size = 0;
90 
91  // size of font
92  u_int32 size = screen::scale () * 12;
93 
94  // load font only once
95  if (ttf != NULL) return true;
96 
97  // absolute or relative font file from config?
98  if (file.size() > 1 && (file[0] == '/' || file[1] == ':'))
99  {
100  path = file;
101  }
102  else
103  {
104  // path where is the file
105  path = WIN_DIRECTORY;
106 
107  // add win font directory path
108  path += WIN_FONT_DIRECTORY;
109 
110  // font name from config file
111  path += file == "" ? "Aclonica.ttf" : file;
112  }
113 
114  // try to load font specified in cfg file
115  ttf = TTF_OpenFont (path.c_str (), size);
116 
117  if (ttf == NULL)
118  {
119  printf ("*** error loading font '%s':\n %s\n", path.c_str (), TTF_GetError ());
120  return false;
121  }
122 
123  TTF_SetFontHinting(ttf, TTF_HINTING_LIGHT);
124 
125  // determine average pixel height of font, based on a number of glyphs
126  avg_size += glyph_height(ttf, 'c');
127  avg_size += glyph_height(ttf, 'C');
128  avg_size += glyph_height(ttf, '0');
129  avg_size += glyph_height(ttf, ':');
130 
131  // make sure our font doesn't exceed a certain height
132  // since every font is different, this really only is an
133  // approximation and results are not perfect for each and
134  // every font out there
135  while (avg_size > (22.5 * screen::scale())) {
136  avg_size = 0;
137  TTF_CloseFont (ttf);
138  ttf = TTF_OpenFont (path.c_str (), --size);
139  TTF_SetFontHinting(ttf, TTF_HINTING_LIGHT);
140 
141  avg_size += glyph_height(ttf, 'c');
142  avg_size += glyph_height(ttf, 'C');
143  avg_size += glyph_height(ttf, '0');
144  avg_size += glyph_height(ttf, ':');
145  }
146 
147  path_ = file;
148  return true;
149 }
150 
151 bool win_ttf::in_table(u_int16 tmp)
152 {
153  if (win_font::in_table (tmp) == true) return true;
154 
155  // try to create font
156  if (tmp > 0x80 || isprint (tmp)) {
157  operator[](tmp);
158  return true;
159  }
160  return false;
161 }
162 
163 image & win_ttf::operator[](u_int16 glyph)
164 {
165  u_int16 unichar[2] = { 0, 0 };
166  unichar[0] = glyph;
167 
168  static SDL_Color bg = { 0x00, 0x00, 0x00, 0 };
169  static SDL_Color white = { 0xff, 0xff, 0xff, 0 };
170 
171  if (ttf && cursor && cursor->scale() != screen::scale())
172  {
173  // if screen scale changed since creating the glyph,
174  // it needs to be recreated with the new size
175  TTF_CloseFont (ttf);
176  ttf = NULL;
177  erase();
178 
179  if (load (path_))
180  {
181  int real_height_ = TTF_FontHeight(ttf) + screen::scale() - 1;
182  height_ = real_height_ / screen::scale();
183  cursor = &operator[]('_');
184  length_ = cursor->length ();
185  }
186  }
187 
188  else if (win_font::in_table (glyph))
189  {
190  return *(glyphs[glyph]);
191  }
192 
193  if (ttf == NULL)
194  {
195  return *(glyphs[' ']);
196  }
197 
198  SDL_Surface *s = TTF_RenderUNICODE_Shaded (ttf, unichar, Color, bg);
199  if (s == NULL)
200  {
201  return *(glyphs[' ']);
202  }
203 
204  u_int16 width = s->w;
205  image tmp (s, bg);
206  overflow[glyph] = width - tmp.length() * screen::scale();
207 
208  image *glph = new image (tmp.length(), height_, screen::scale());
209  glph->fillrect (0, 0, tmp.length(), height_, screen::trans_col(), NULL);
210 
211  s = TTF_RenderUNICODE_Solid (ttf, unichar, bg);
212  if (s != NULL)
213  {
214  image shadow (s, white);
215  shadow.draw (1, 1+height_-shadow.height(), 0, 0, shadow.length(), shadow.height(), NULL, glph);
216  }
217  else
218  {
219  fprintf (stderr, "%s\n", TTF_GetError ());
220  }
221 
222  tmp.draw (0, height_-tmp.height(), 0, 0, tmp.length(), tmp.height(), NULL, glph);
223  if (cursor != NULL)
224  {
225  glyphs[glyph] = glph;
226  }
227 
228  return *glph;
229 }
230 
231 s_int8 win_ttf::kerning(const u_int16 & char1, const u_int16 & char2)
232 {
233 #ifdef HAVE_TTF_GETFONTKERNINGSIZEGLYPHS
234  if (ttf)
235  {
236  return TTF_GetFontKerningSizeGlyphs(ttf, char1, char2) + overflow[char1];
237  }
238 #endif
239  return overflow[char1];
240 }
u_int32
#define u_int32
32 bits long unsigned integer
Definition: types.h:41
surface::fillrect
void fillrect(s_int16 x, s_int16 y, u_int16 l, u_int16 h, u_int32 col, drawing_area *da_opt=NULL)
Fills an area of the surface with a given color.
Definition: surface.cc:239
drawable::length
u_int16 length() const
Returns the length of the drawable.
Definition: drawable.h:80
screen::scale
static u_int8 scale()
Scale factor of the screen.
Definition: screen.h:118
s_int8
#define s_int8
8 bits long signed integer
Definition: types.h:44
screen::trans_col
static u_int32 trans_col()
Returns the translucent color in screen's depth format.
Definition: screen.h:110
image
Image manipulation class.
Definition: image.h:45
surface::scale
u_int8 scale() const
Get the surfaces current scaling factor.
Definition: surface.h:163
win_font
Definition: win_font.h:32
u_int16
#define u_int16
16 bits long unsigned integer
Definition: types.h:38
path
A* pathfinding algorithm implementation class.
Definition: path.h:52