summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/tilefont.cc
diff options
context:
space:
mode:
authorIxtli <cg@325i.org>2010-03-14 20:40:54 +0900
committerEnne Walker <ennewalker@users.sourceforge.net>2010-04-24 10:19:45 -0400
commit149c76283904371235ea6d564037900edb8b07af (patch)
tree6bcde02f7acf2485f7e557bb4c64f74d3abefa9d /crawl-ref/source/tilefont.cc
parentbab61331e9e1287ae14afe2644b68f4c49ff09d8 (diff)
downloadcrawl-ref-149c76283904371235ea6d564037900edb8b07af.tar.gz
crawl-ref-149c76283904371235ea6d564037900edb8b07af.zip
Created FontWrapper, and made FT flag in makefile.
Diffstat (limited to 'crawl-ref/source/tilefont.cc')
-rw-r--r--crawl-ref/source/tilefont.cc787
1 files changed, 8 insertions, 779 deletions
diff --git a/crawl-ref/source/tilefont.cc b/crawl-ref/source/tilefont.cc
index 30f7d561bf..8d2b9d4793 100644
--- a/crawl-ref/source/tilefont.cc
+++ b/crawl-ref/source/tilefont.cc
@@ -1,788 +1,17 @@
-/*
- * File: tilefont.cc
- * Created by: ennewalker on Sat Apr 26 01:33:53 2008 UTC
- */
-
#include "AppHdr.h"
#ifdef USE_TILE
-
-#include "tilebuf.h"
#include "tilefont.h"
-#include "defines.h"
-#include "files.h"
-#include "glwrapper.h"
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-const VColour term_colours[MAX_TERM_COLOUR] =
-{
- VColour( 0, 0, 0), // BLACK
- VColour( 0, 82, 255), // BLUE
- VColour(100, 185, 70), // GREEN
- VColour( 0, 180, 180), // CYAN
- VColour(255, 48, 0), // RED
- VColour(238, 92, 238), // MAGENTA
- VColour(165, 91, 0), // BROWN
- VColour(162, 162, 162), // LIGHTGREY
- VColour( 82, 82, 82), // DARKGREY
- VColour( 82, 102, 255), // LIGHTBLUE
- VColour( 82, 255, 82), // LIGHTGREEN
- VColour( 82, 255, 255), // LIGHTCYAN
- VColour(255, 82, 82), // LIGHTRED
- VColour(255, 82, 255), // LIGHTMAGENTA
- VColour(255, 255, 82), // YELLOW
- VColour(255, 255, 255) // WHITE
-};
-
-FTFont::FTFont() :
- m_glyphs(NULL),
- m_max_advance(0, 0),
- m_min_offset(0)
-{
-}
-
-FTFont::~FTFont()
-{
- delete[] m_glyphs;
-}
-
-bool FTFont::load_font(const char *font_name, unsigned int font_size, bool outl)
-{
- FT_Library library;
- FT_Face face;
- FT_Error error;
-
- error = FT_Init_FreeType(&library);
- if (error)
- {
- fprintf(stderr, "Failed to initialise freetype library.\n");
- return false;
- }
-
- // TODO enne - need to find a cross-platform way to also
- // attempt to locate system fonts by name...
- std::string font_path = datafile_path(font_name, false, true);
- if (font_path.c_str()[0] == 0)
- {
- fprintf(stderr, "Could not find font '%s'\n", font_name);
- return false;
- }
-
- error = FT_New_Face(library, font_path.c_str(), 0, &face);
- if (error == FT_Err_Unknown_File_Format)
- {
- fprintf(stderr, "Unknown font format for file '%s'\n",
- font_path.c_str());
- return false;
- }
- else if (error)
- {
- fprintf(stderr, "Invalid font from file '%s'\n", font_path.c_str());
- }
-
- error = FT_Set_Pixel_Sizes(face, font_size, font_size);
- ASSERT(!error);
-
- // Get maximum advance
- m_max_advance = coord_def(0,0);
- int ascender = face->ascender >> 6;
- int min_y = 100000;
- int max_y = 0;
- int max_width = 0;
- m_min_offset = 0;
- m_glyphs = new GlyphInfo[256];
- for (unsigned int c = 0; c < 256; c++)
- {
- m_glyphs[c].offset = 0;
- m_glyphs[c].advance = 0;
- m_glyphs[c].renderable = false;
-
- FT_Int glyph_index = FT_Get_Char_Index(face, c);
- if (!glyph_index)
- continue;
-
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
- ASSERT(!error);
-
- FT_Bitmap *bmp = &face->glyph->bitmap;
-
- int advance = face->glyph->advance.x >> 6;
-
- m_max_advance.x = std::max(m_max_advance.x, advance);
-
- int bmp_width = bmp->width;
- int bmp_top = ascender - face->glyph->bitmap_top;
- int bmp_bottom = ascender + bmp->rows - face->glyph->bitmap_top;
- if (outl)
- {
- bmp_width += 2;
- bmp_top -= 1;
- bmp_bottom += 1;
- }
-
- max_width = std::max(max_width, bmp_width);
- min_y = std::min(min_y, bmp_top);
- max_y = std::max(max_y, bmp_bottom);
-
- m_glyphs[c].offset = face->glyph->bitmap_left;
- m_glyphs[c].advance = advance;
- m_glyphs[c].width = bmp_width;
-
- m_min_offset = std::min((char)m_min_offset, m_glyphs[c].offset);
- }
-
- // The ascender and text height given by FreeType2 is ridiculously large
- // (e.g. 37 pixels high for 14 pixel font). Use min and max bounding
- // heights on the characters we care about to get better values for the
- // text height and the ascender.
- m_max_advance.y = max_y - min_y;
- ascender -= min_y;
-
- int max_height = m_max_advance.y;
-
- // Grow character size to power of 2
- coord_def charsz(1,1);
- while (charsz.x < max_width)
- charsz.x *= 2;
- while (charsz.y < max_height)
- charsz.y *= 2;
-
- // Fill out texture to be (16*charsz.x) X (16*charsz.y) X (32-bit)
- // Having to blow out 8-bit alpha values into full 32-bit textures is
- // kind of frustrating, but not all OpenGL implementations support the
- // "esoteric" ALPHA8 format and it's not like this texture is very large.
- unsigned int width = 16 * charsz.x;
- unsigned int height = 16 * charsz.y;
- unsigned char *pixels = new unsigned char[4 * width * height];
- memset(pixels, 0, sizeof(unsigned char) * 4 * width * height);
-
- // Special case c = 0 for full block.
- {
- m_glyphs[0].renderable = false;
- for (int x = 0; x < max_width; x++)
- for (int y = 0; y < max_height; y++)
- {
- unsigned int idx = x + y * width;
- idx *= 4;
- pixels[idx] = 255;
- pixels[idx + 1] = 255;
- pixels[idx + 2] = 255;
- pixels[idx + 3] = 255;
- }
- }
-
- for (unsigned int c = 1; c < 256; c++)
- {
- FT_Int glyph_index = FT_Get_Char_Index(face, c);
- if (!glyph_index)
- {
- // If no mapping for this character, leave blank.
- continue;
- }
-
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
- ASSERT(!error);
-
- FT_Bitmap *bmp = &face->glyph->bitmap;
- ASSERT(bmp);
- // Some glyphs (e.g. ' ') don't get a buffer.
- if (!bmp->buffer)
- continue;
-
- m_glyphs[c].renderable = true;
-
- int vert_offset = ascender - face->glyph->bitmap_top;
-
- ASSERT(bmp->pixel_mode == FT_PIXEL_MODE_GRAY);
- ASSERT(bmp->num_grays == 256);
-
- // Horizontal offset stored in m_glyphs and handled when drawing
- unsigned int offset_x = (c % 16) * charsz.x;
- unsigned int offset_y = (c / 16) * charsz.y + vert_offset;
-
- if (outl)
- {
- const int charw = bmp->width;
- for (int x = -1; x <= bmp->width; x++)
- for (int y = -1; y <= bmp->rows; y++)
- {
- bool x_valid = x >= 0 && x < bmp->width;
- bool y_valid = y >= 0 && y < bmp->rows;
- bool valid = x_valid && y_valid;
- unsigned char orig = valid ? bmp->buffer[x + charw * y] : 0;
-
- unsigned char edge = 0;
- if (y_valid && x > 0)
- edge = std::max(bmp->buffer[(x-1) + charw * y], edge);
- if (x_valid && y > 0)
- edge = std::max(bmp->buffer[x + charw * (y-1)], edge);
- if (y_valid && x < bmp->width - 1)
- edge = std::max(bmp->buffer[(x+1) + charw * y], edge);
- if (x_valid && y < bmp->rows - 1)
- edge = std::max(bmp->buffer[x + charw * (y+1)], edge);
-
- unsigned int idx = offset_x+x+1 + (offset_y+y+1) * width;
- idx *= 4;
-
- pixels[idx] = orig;
- pixels[idx + 1] = orig;
- pixels[idx + 2] = orig;
- pixels[idx + 3] = std::min(orig + edge, 255);
- }
- }
- else
- {
- for (int x = 0; x < bmp->width; x++)
- for (int y = 0; y < bmp->rows; y++)
- {
- unsigned int idx = offset_x + x + (offset_y + y) * width;
- idx *= 4;
- unsigned char alpha = bmp->buffer[x + bmp->width * y];
- pixels[idx] = 255;
- pixels[idx + 1] = 255;
- pixels[idx + 2] = 255;
- pixels[idx + 3] = alpha;
- }
- }
- }
-
- bool success = m_tex.load_texture(pixels, width, height,
- MIPMAP_NONE);
-
- delete[] pixels;
-
- return success;
-}
-
-struct FontVertLayout
-{
- float pos_x;
- float pos_y;
- float tex_x;
- float tex_y;
- unsigned char r;
- unsigned char g;
- unsigned char b;
- unsigned char a;
-};
-
-void FTFont::render_textblock(unsigned int x_pos, unsigned int y_pos,
- unsigned char *chars, unsigned char *colours,
- unsigned int width, unsigned int height,
- bool drop_shadow)
-{
- if (!chars || !colours || !width || !height || !m_glyphs)
- return;
-
- coord_def adv(std::max(-m_min_offset, 0), 0);
- unsigned int i = 0;
-
- std::vector<FontVertLayout> verts;
- // TODO enne - make this better
- // This is bad for the CRT. Maybe we should just reserve some fixed limit?
- // Maybe we should just cache this in FTFont?
- verts.reserve(4 * width * height);
-
- float texcoord_dy = (float)m_max_advance.y / (float)m_tex.height();
-
- for (unsigned int y = 0; y < height; y++)
- {
- for (unsigned int x = 0; x < width; x++)
- {
- unsigned char c = chars[i];
- unsigned char col_bg = colours[i] >> 4;
- unsigned char col_fg = colours[i] & 0xF;
-
- if (col_bg != 0)
- {
- FontVertLayout v;
- v.tex_x = v.tex_y = 0;
- v.r = term_colours[col_bg].r;
- v.g = term_colours[col_bg].g;
- v.b = term_colours[col_bg].b;
- v.a = 255;
-
- v.pos_x = adv.x;
- v.pos_y = adv.y;
- verts.push_back(v);
-
- v.pos_x = adv.x;
- v.pos_y = adv.y + m_max_advance.y;
- verts.push_back(v);
-
- v.pos_x = adv.x + m_max_advance.x;
- v.pos_y = adv.y + m_max_advance.y;
- verts.push_back(v);
-
- v.pos_x = adv.x + m_max_advance.x;
- v.pos_y = adv.y;
- verts.push_back(v);
- }
-
- adv.x += m_glyphs[c].offset;
-
- if (m_glyphs[c].renderable)
- {
- int this_width = m_glyphs[c].width;
-
- float tex_x = (float)(c % 16) / 16.0f;
- float tex_y = (float)(c / 16) / 16.0f;
- float tex_x2 = tex_x + (float)this_width / (float)m_tex.width();
- float tex_y2 = tex_y + texcoord_dy;
- FontVertLayout v;
- v.r = term_colours[col_fg].r;
- v.g = term_colours[col_fg].g;
- v.b = term_colours[col_fg].b;
- v.a = 255;
-
- v.pos_x = adv.x;
- v.pos_y = adv.y;
- v.tex_x = tex_x;
- v.tex_y = tex_y;
- verts.push_back(v);
-
- v.pos_x = adv.x;
- v.pos_y = adv.y + m_max_advance.y;
- v.tex_x = tex_x;
- v.tex_y = tex_y2;
- verts.push_back(v);
-
- v.pos_x = adv.x + this_width;
- v.pos_y = adv.y + m_max_advance.y;
- v.tex_x = tex_x2;
- v.tex_y = tex_y2;
- verts.push_back(v);
-
- v.pos_x = adv.x + this_width;
- v.pos_y = adv.y;
- v.tex_x = tex_x2;
- v.tex_y = tex_y;
- verts.push_back(v);
- }
-
- i++;
- adv.x += m_glyphs[c].advance - m_glyphs[c].offset;
- }
-
- adv.x = 0;
- adv.y += m_max_advance.y;
- }
-
- if (!verts.size())
- return;
-
- GLState state;
- state.array_vertex = true;
- state.array_texcoord = true;
- state.blend = true;
- state.texture = true;
- glmanager->set(state);
- m_tex.bind();
-
- GLPrimitive prim( sizeof(FontVertLayout), verts.size(), 2,
- &verts[0].pos_x,
- NULL,
- &verts[0].tex_x);
-
- // Defaults to GLW_QUADS
- GLW_3VF trans(x_pos, y_pos, 0.0f);
-
- if (drop_shadow)
- {
- GLW_3VF color(0.0f, 0.0f, 0.0f);
- glmanager->set_current_color(color);
-
- trans.x++;
- trans.y++;
- glmanager->set_transform(&trans);
- glmanager->draw_primitive(prim);
- trans.x--;
- trans.y--;
-
- color.set(1.0f, 1.0f, 1.0f);
- glmanager->set_current_color(color);
- }
-
- // TODO: Review this to see if turning array color on and off
- // here is really necessary ...
- state.array_colour = true;
- glmanager->set(state);
- prim.colour_pointer = &verts[0].r;
- glmanager->set_transform(&trans);
- glmanager->draw_primitive(prim);
- state.array_colour = false;
- glmanager->set(state);
-}
-struct box_vert
-{
- float x;
- float y;
- unsigned char r;
- unsigned char g;
- unsigned char b;
- unsigned char a;
-};
-
-static void _draw_box(int x_pos, int y_pos, float width, float height,
- float box_width, unsigned char box_colour,
- unsigned char box_alpha)
-{
- box_vert verts[4];
- for (unsigned int i = 0; i < 4; i++)
- {
- verts[i].r = term_colours[box_colour].r;
- verts[i].g = term_colours[box_colour].g;
- verts[i].b = term_colours[box_colour].b;
- verts[i].a = box_alpha;
- }
- verts[0].x = x_pos - box_width;
- verts[0].y = y_pos - box_width;
- verts[1].x = verts[0].x;
- verts[1].y = y_pos + height + box_width;
- verts[2].x = x_pos + width + box_width;
- verts[2].y = verts[1].y;
- verts[3].x = verts[2].x;
- verts[3].y = verts[0].y;
-
- // Load identity matrix
- glmanager->set_transform();
-
- GLState state;
- state.array_vertex = true;
- state.array_colour = true;
- state.blend = true;
- glmanager->set(state);
-
- GLPrimitive prim( sizeof(box_vert), sizeof(verts) / sizeof(box_vert), 2,
- &verts[0].x,
- &verts[0].r,
- NULL);
-
- glmanager->draw_primitive(prim);
-}
-
-unsigned int FTFont::string_height(const formatted_string &str)
-{
- std::string temp = str.tostring();
- return string_height(temp.c_str());
-}
-
-unsigned int FTFont::string_height(const char *text)
-{
- int height = 1;
- for (const char *itr = text; (*itr); itr++)
- if (*itr == '\n')
- height++;
-
- return char_height() * height;
-}
-
-unsigned int FTFont::string_width(const formatted_string &str)
-{
- std::string temp = str.tostring();
- return string_width(temp.c_str());
-}
-
-unsigned int FTFont::string_width(const char *text)
-{
- unsigned int base_width = std::max(-m_min_offset, 0);
- unsigned int max_width = 0;
-
- unsigned int width = base_width;
- unsigned int adjust = 0;
- for (const unsigned char *itr = (unsigned const char *)text; *itr; itr++)
- {
- if (*itr == '\n')
- {
- max_width = std::max(width + adjust, max_width);
- width = base_width;
- adjust = 0;
- }
- else
- {
- width += m_glyphs[*itr].advance;
- adjust = std::max(0, m_glyphs[*itr].width - m_glyphs[*itr].advance);
- }
- }
-
- max_width = std::max(width + adjust, max_width);
- return max_width;
-}
-
-int FTFont::find_index_before_width(const char *text, int max_width)
-{
- int width = std::max(-m_min_offset, 0);
-
- for (int i = 0; text[i]; i++)
- {
- unsigned char c = text[i];
- width += m_glyphs[c].advance;
- int adjust = std::max(0, m_glyphs[c].width - m_glyphs[c].advance);
- if (width + adjust > max_width)
- return i;
- }
-
- return -1;
-}
-
-formatted_string FTFont::split(const formatted_string &str,
- unsigned int max_width, unsigned int max_height)
-{
- int max_lines = max_height / char_height();
-
- if (max_lines < 1)
- return formatted_string();
-
- formatted_string ret;
- ret += str;
-
- std::string base = str.tostring();
- int num_lines = 0;
-
- char *line = &base[0];
- while (true)
- {
- int line_end = find_index_before_width(line, max_width);
- if (line_end == -1)
- break;
-
- int space_idx = 0;
- for (char *search = &line[line_end]; search > line; search--)
- {
- if (*search == ' ')
- {
- space_idx = search - line;
- break;
- }
- }
-
- if (++num_lines >= max_lines || !space_idx)
- {
- int ellipses;
- if (space_idx && (space_idx - line_end > 2))
- ellipses = space_idx;
- else
- ellipses = line_end - 2;
-
- size_t idx = &line[ellipses] - &base[0];
- ret[idx] = '.';
- ret[idx+1] = '.';
-
- return ret.substr(0, idx + 2);
- }
- else
- {
- line[space_idx] = '\n';
- ret[&line[space_idx] - &base[0]] = '\n';
- }
-
- line = &line[space_idx+1];
- }
-
- return ret;
-}
-
-void FTFont::render_string(unsigned int px, unsigned int py,
- const char *text,
- const coord_def &min_pos, const coord_def &max_pos,
- unsigned char font_colour, bool drop_shadow,
- unsigned char box_alpha,
- unsigned char box_colour,
- unsigned int outline,
- bool tooltip)
-{
- ASSERT(text);
-
- // Determine extent of this text
- unsigned int max_rows = 1;
- unsigned int cols = 0;
- unsigned int max_cols = 0;
- for (const char *itr = text; *itr; itr++)
- {
- cols++;
- max_cols = std::max(cols, max_cols);
-
- // NOTE: only newlines should be used for tool tips. Don't use EOL.
- ASSERT(*itr != '\r');
-
- if (*itr == '\n')
- {
- cols = 0;
- max_rows++;
- }
- }
-
- // Create the text block
- unsigned char *chars = (unsigned char *)alloca(max_rows * max_cols);
- unsigned char *colours = (unsigned char *)alloca(max_rows * max_cols);
- memset(chars, ' ', max_rows * max_cols);
- memset(colours, font_colour, max_rows * max_cols);
-
- // Fill the text block
- cols = 0;
- unsigned int rows = 0;
- for (const char *itr = text; *itr; itr++)
- {
- chars[cols + rows * max_cols] = *itr;
- cols++;
-
- if (*itr == '\n')
- {
- cols = 0;
- rows++;
- }
- }
-
- // Find a suitable location on screen
- const int buffer = 5; // additional buffer size from edges
-
- int wx = string_width(text);
- int wy = max_rows * char_height();
-
- int sx, sy; // box starting location, uses extra buffer
- int tx, ty; // text starting location
-
- tx = px - wx / 2;
- sx = tx - buffer;
- if (tooltip)
- {
- sy = py + outline;
- ty = sy + buffer;
- }
- else
- {
- ty = py - wy - outline;
- sy = ty - buffer;
- }
- // box ending position
- int ex = tx + wx + buffer;
- int ey = ty + wy + buffer;
-
- if (ex > max_pos.x)
- tx += max_pos.x - ex;
- else if (sx < min_pos.x)
- tx -= sx - min_pos.x;
-
- if (ey > max_pos.y)
- ty += max_pos.y - ey;
- else if (sy < min_pos.y)
- ty -= sy - min_pos.y;
-
- if (box_alpha != 0)
- _draw_box(tx, ty, wx, wy, outline, box_colour, box_alpha);
-
- render_textblock(tx, ty, chars, colours, max_cols, max_rows, drop_shadow);
-}
-
-void FTFont::store(FontBuffer &buf, float &x, float &y,
- const std::string &str, const VColour &col)
-{
- store(buf, x, y, str, col, x);
-}
-
-void FTFont::store(FontBuffer &buf, float &x, float &y,
- const std::string &str, const VColour &col, float orig_x)
-{
- for (unsigned int i = 0; i < str.size(); i++)
- {
- char c = str[i];
- if (c == '\n')
- {
- x = orig_x;
- y += m_max_advance.y;
- }
- else
- {
- store(buf, x, y, c, col);
- }
- }
-}
-
-void FTFont::store(FontBuffer &buf, float &x, float &y,
- const formatted_string &fs)
-{
- store(buf, x, y, fs, x);
-}
-
-void FTFont::store(FontBuffer &buf, float &x, float &y,
- const formatted_string &fs, float orig_x)
-{
- int colour = LIGHTGREY;
- for (unsigned int i = 0; i < fs.ops.size(); i++)
- {
- switch (fs.ops[i].type)
- {
- case FSOP_COLOUR:
- // Only foreground colors for now...
- colour = fs.ops[i].x & 0xF;
- break;
- case FSOP_TEXT:
- store(buf, x, y, fs.ops[i].text, term_colours[colour], orig_x);
- break;
- default:
- break;
- }
- }
-}
+#ifdef USE_FT
+#include "fontwrapper-ft.h"
+#endif
-void FTFont::store(FontBuffer &buf, float &x, float &y,
- unsigned char c, const VColour &col)
+FontWrapper* FontWrapper::create()
{
- if (!m_glyphs[c].renderable)
- {
- x += m_glyphs[c].advance;
- return;
- }
-
- int this_width = m_glyphs[c].width;
-
- float pos_sx = x + m_glyphs[c].offset;
- float pos_sy = y;
- float pos_ex = pos_sx + this_width;
- float pos_ey = y + m_max_advance.y;
-
- float tex_sx = (float)(c % 16) / 16.0f;
- float tex_sy = (float)(c / 16) / 16.0f;
- float tex_ex = tex_sx + (float)this_width / (float)m_tex.width();
- float tex_ey = tex_sy + (float)m_max_advance.y / (float)m_tex.height();
-
- {
- PTCVert &v = buf.get_next();
- v.col = col;
- v.pos_x = pos_sx;
- v.pos_y = pos_sy;
- v.tex_x = tex_sx;
- v.tex_y = tex_sy;
- }
- {
- PTCVert &v = buf.get_next();
- v.col = col;
- v.pos_x = pos_sx;
- v.pos_y = pos_ey;
- v.tex_x = tex_sx;
- v.tex_y = tex_ey;
- }
- {
- PTCVert &v = buf.get_next();
- v.col = col;
- v.pos_x = pos_ex;
- v.pos_y = pos_ey;
- v.tex_x = tex_ex;
- v.tex_y = tex_ey;
- }
- {
- PTCVert &v = buf.get_next();
- v.col = col;
- v.pos_x = pos_ex;
- v.pos_y = pos_sy;
- v.tex_x = tex_ex;
- v.tex_y = tex_sy;
- }
-
- x += m_glyphs[c].advance;
+#ifdef USE_FT
+ return (FontWrapper *) new FTFontWrapper();
+#endif
}
-#endif
+#endif // USE_TILE