2 This file is part of fxwt, the window system toolkit of 3dengfx.
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* True type text rendering and management.
23 * Author: John Tsiombikas 2005
26 #include "3dengfx_config.h"
28 #ifndef FXWT_NO_FREETYPE
33 #include FT_FREETYPE_H
35 #include "3dengfx/textures.hpp"
36 #include "3dengfx/texman.hpp"
37 #include "common/hashtable.hpp"
38 #include "dsys/demosys.hpp"
39 #include "common/err_msg.h"
40 #include "common/string_hash.hpp"
41 #include "gfx/img_manip.hpp"
51 static const char *find_font_file(const char *font);
52 static string gen_key_str(const char *text);
53 static void draw_free_type_bitmap(FT_Bitmap *ftbm, PixelBuffer *pbuf, int x, int y);
54 static PixelBuffer *create_text_image(const char *str, FT_Face face, int font_size);
55 static int next_pow_two(int num);
56 static Texture *pixel_buf_to_texture(const PixelBuffer &pbuf);
58 static FT_LibraryRec_ *ft;
59 static vector<FT_FaceRec_*> face_list;
60 static HashTable<string, Text> text_table;
61 static FT_FaceRec_ *font;
62 static int font_size = 64;
63 static scalar_t latest_fetched_aspect = 1;
64 static TextRenderMode render_mode = TEXT_TRANSPARENT;
66 /* This list MUST correspond to the enum Font at text.hpp
67 * so take care to keep them in sync.
69 static const char *font_names[] = {
73 "Bitstream Vera Sans",
74 "Bitstream Vera Serif",
75 "Bitstream Vera Sans Mono",
81 // update these lists when adding a new font
82 static Font font_style_list[3][4] = {
84 {FONT_FREE_SANS, FONT_MS_SANS, FONT_VERA_SANS, FONT_NULL},
86 {FONT_FREE_SERIF, FONT_MS_SERIF, FONT_VERA_SERIF, FONT_NULL},
88 {FONT_FREE_MONO, FONT_MS_MONO, FONT_VERA_MONO, FONT_NULL}
93 #define VERDANA_FILE "Verdana.ttf"
94 #define TIMES_NEW_ROMAN_FILE "Times_New_Roman.ttf"
95 #define COURIER_NEW_FILE "Courier_New.ttf"
96 #elif defined(WIN32) || defined(__WIN32__)
97 #define VERDANA_FILE "verdana.ttf"
98 #define TIMES_NEW_ROMAN_FILE "times.ttf"
99 #define COURIER_NEW_FILE "cour.ttf"
102 bool fxwt::text_init() {
106 text_table.set_hash_function(string_hash);
108 if(FT_Init_FreeType(&ft) != 0) return false;
110 static const char *fonts[] = {
111 "FreeSans.ttf", "FreeSerif.ttf", "FreeMono.ttf", // freefonts
112 "Vera.ttf", "VeraSe.ttf", "VeraMono.ttf", // bitstream vera fonts
113 VERDANA_FILE, TIMES_NEW_ROMAN_FILE, COURIER_NEW_FILE, // MS fonts
117 const char **fptr = fonts;
119 const char *font_path = find_font_file(*fptr++);
122 if(FT_New_Face(ft, font_path, 0, &face) == 0) {
123 info("Loaded font \"%s\" (%s)", font_path, face->family_name);
124 if(!font) font = face;
126 face_list.push_back(face);
130 atexit(fxwt::text_close);
137 void fxwt::text_close() {
138 // TODO: free the textures
140 for(size_t i=0; i<face_list.size(); i++) {
141 FT_Done_Face(face_list[i]);
143 FT_Done_FreeType(ft);
146 void fxwt::set_text_render_mode(TextRenderMode mode) {
150 void fxwt::set_font_size(int sz) {
154 int fxwt::get_font_size() {
158 bool fxwt::set_font(Font fnt) {
159 for(size_t i=0; i<face_list.size(); i++) {
160 if(!strcmp(face_list[i]->family_name, font_names[fnt])) {
168 bool fxwt::set_font(FontStyle fstyle) {
170 while(font_style_list[fstyle][i] != FONT_NULL) {
171 if(set_font(font_style_list[fstyle][i++])) return true;
176 const char *fxwt::get_font_name(Font fnt) {
177 return font_names[fnt];
180 Texture *fxwt::get_text(const char *text_str) {
181 Pair<string, Text> *res;
182 if((res = text_table.find(gen_key_str(text_str)))) {
183 latest_fetched_aspect = res->val.aspect;
184 return res->val.texture;
187 PixelBuffer *text_img = create_text_image(text_str, font, font_size);
188 scalar_t aspect = (scalar_t)text_img->width / (scalar_t)text_img->height;
189 Texture *tex = pixel_buf_to_texture(*text_img);
192 Text text = {tex, aspect};
193 text_table.insert(gen_key_str(text_str), text);
195 latest_fetched_aspect = aspect;
200 void fxwt::print_text(const char *text_str, const Vector2 &pos, scalar_t size, const Color &col) {
201 Texture *tex = get_text(text_str);
202 Vector2 sz_vec(size * latest_fetched_aspect, size);
204 dsys::overlay(tex, pos, pos + sz_vec, col);
207 static const char *find_font_file(const char *font) {
208 static char path[512];
211 // TODO: add data path search through the locator
212 if((fp = fopen(font, "r"))) {
218 // try /usr/share/fonts/truetype
219 sprintf(path, "/usr/share/fonts/truetype/%s", font);
220 if((fp = fopen(path, "r"))) {
225 // try /usr/share/fonts/truetype/freefont
226 sprintf(path, "/usr/share/fonts/truetype/freefont/%s", font);
227 if((fp = fopen(path, "r"))) {
232 // try /usr/share/fonts/truetype/ttf-bitstream-vera
233 sprintf(path, "/usr/share/fonts/truetype/ttf-bitstream-vera/%s", font);
234 if((fp = fopen(path, "r"))) {
238 #endif /* __unix__ */
241 // try %windir%\fonts
242 sprintf(path, "%s\\fonts\\%s", getenv("WINDIR"), font);
243 if((fp = fopen(path, "r"))) {
252 static string gen_key_str(const char *text) {
253 if(font->family_name) {
254 return string(font->family_name) + string("##") + string(text);
260 static void draw_free_type_bitmap(FT_Bitmap *ftbm, PixelBuffer *pbuf, int x, int y) {
262 Pixel *dptr = pbuf->buffer + y * pbuf->width + x;
263 unsigned char *sptr = (unsigned char*)ftbm->buffer;
268 for(i=0; i<ftbm->rows; i++) {
269 if(i + y >= (int)pbuf->height) break;
271 for(j=0; j<ftbm->width; j++) {
272 if(j + x >= (int)pbuf->width) break;
274 Pixel pixel = *sptr++;
276 if(render_mode == TEXT_TRANSPARENT) {
277 *dptr++ = 0x00ffffff | (pixel << 24);
279 *dptr++ = 0xff000000 | (pixel << 8) | (pixel << 16) | pixel;
283 sptr += ftbm->pitch - j;
284 dptr += pbuf->width - j;
288 static PixelBuffer *create_text_image(const char *str, FT_Face face, int font_size) {
289 FT_GlyphSlot slot = face->glyph;
290 FT_Set_Pixel_Sizes(face, 0, font_size); // set size
292 size_t len = strlen(str);
293 PixelBuffer tmp_buf(len * font_size * 2, font_size * 2);
294 memset(tmp_buf.buffer, 0, tmp_buf.width * tmp_buf.height * sizeof(Pixel));
297 int pen_y = font_size;
299 for(size_t i=0; i<len; i++) {
300 if(FT_Load_Char(face, *str++, FT_LOAD_RENDER) != 0) {
301 cerr << "aaaaaaaa!\n";
305 draw_free_type_bitmap(&slot->bitmap, &tmp_buf, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top);
307 pen_x += slot->advance.x >> 6;
310 assert(pen_x <= (int)tmp_buf.width);
312 PixelBuffer *pbuf = new PixelBuffer(pen_x, (int)(font_size * 1.5));
314 Pixel *dptr = pbuf->buffer;
315 Pixel *sptr = tmp_buf.buffer;
317 for(size_t i=0; i<pbuf->height; i++) {
318 memcpy(dptr, sptr, pbuf->width * sizeof(Pixel));
320 sptr += tmp_buf.width;
326 static int next_pow_two(int num) {
328 while(val < num) val <<= 1;
332 static Texture *pixel_buf_to_texture(const PixelBuffer &pbuf) {
337 if (engfx_state::sys_caps.non_power_of_two_textures)
341 tex = new Texture(w, h);
342 tex->set_pixel_data(pbuf);
346 w = next_pow_two(pbuf.width);
347 h = next_pow_two(pbuf.height);
348 PixelBuffer tmp = pbuf;
349 resample_pixel_buffer(&tmp, w, h);
350 tex = new Texture(w, h);
351 tex->set_pixel_data(tmp);
356 float dx = (float)pbuf.width / (float)w;
357 float dy = (float)pbuf.height / (float)h;
359 for(int j=0; j<h; j++) {
360 for(int i=0; i<w; i++) {
361 int x = (int)(((float)i * dx) + 0.5);
362 int y = (int)(((float)j * dy) + 0.5);
363 tex->buffer[j * w + i] = pbuf.buffer[y * pbuf.width + x];
371 #else // if we excluded freetype dependencies from compilation
374 #include "common/err_msg.h"
376 using namespace fxwt;
378 #define FT_NOT_COMPILED "some text-rendering function is called, but freetype support is not compiled in"
380 bool fxwt::text_init() {
384 void fxwt::text_close() {}
386 void fxwt::set_text_render_mode(TextRenderMode mode) {
387 error(FT_NOT_COMPILED);
390 void fxwt::set_font_size(int sz) {
391 error(FT_NOT_COMPILED);
394 int fxwt::get_font_size() {
395 error(FT_NOT_COMPILED);
399 bool fxwt::set_font(Font fnt) {
400 error(FT_NOT_COMPILED);
404 bool fxwt::set_font(FontStyle fstyle) {
405 error(FT_NOT_COMPILED);
409 const char *fxwt::get_font_name(Font fnt) {
410 error(FT_NOT_COMPILED);
414 Texture *fxwt::get_text(const char *text_str) {
415 error(FT_NOT_COMPILED);
419 void fxwt::print_text(const char *text_str, const Vector2 &pos, scalar_t size, const Color &col) {
420 static bool first = true;
422 error(FT_NOT_COMPILED);
427 #endif // FXWT_NO_FREETYPE