source: git/src/glbitmapfont.cc @ 614d60b

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since 614d60b was 614d60b, checked in by Olly Betts <olly@…>, 10 years ago

lib/Makefile.am,lib/make-pixel-font,src/glbitmapfont.cc,
src/glbitmapfont.h: Embed the font data for the first 256 Unicode
codepoints into the compiled aven binary to reduce start up
overhead. Any additional codepoints are loaded from a data file
only if/when a character >= U+100 is actually needed (as before).

  • Property mode set to 100644
File size: 5.4 KB
Line 
1//
2//  glbitmapfont.cc
3//
4//  Draw text using glBitmap.
5//
6//  Copyright (C) 2011,2012,2013,2014 Olly Betts
7//
8//  This program is free software; you can redistribute it and/or modify
9//  it under the terms of the GNU General Public License as published by
10//  the Free Software Foundation; either version 2 of the License, or
11//  (at your option) any later version.
12//
13//  This program is distributed in the hope that it will be useful,
14//  but WITHOUT ANY WARRANTY; without even the implied warranty of
15//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//  GNU General Public License for more details.
17//
18//  You should have received a copy of the GNU General Public License
19//  along with this program; if not, write to the Free Software
20//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21//
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include "glbitmapfont.h"
28
29#include "aventypes.h"
30#include "useful.h"
31#include "wx.h"
32
33#include "../lib/preload_font.h"
34
35#define CHECK_GL_ERROR(M, F) do { \
36    GLenum error_code_ = glGetError(); \
37    if (error_code_ != GL_NO_ERROR) { \
38        wxLogError(wxT(__FILE__":"STRING(__LINE__)": OpenGL error: %s " \
39                   "(call "F" in method "M")"), \
40                   wxString((const char *)gluErrorString(error_code_), \
41                            wxConvUTF8).c_str()); \
42    } \
43} while (0)
44
45bool
46BitmapFont::load(const wxString & font_file_)
47{
48    font_file = font_file_;
49
50    if (!gllist_base) {
51        gllist_base = glGenLists(BITMAPFONT_MAX_CHAR);
52    }
53
54    const unsigned char * p = fontdata_preloaded;
55    const unsigned char * end = p + sizeof(fontdata_preloaded);
56    for (int ch = 0; ch < BITMAPFONT_MAX_CHAR; ++ch) {
57        glNewList(gllist_base + ch, GL_COMPILE);
58        CHECK_GL_ERROR("BitmapFont::load", "glNewList");
59        if (p == end) {
60            return false;
61        }
62        unsigned int byte_width = *p++;
63
64        char_width[ch] = (byte_width & 0x0f) + 2;
65        byte_width >>= 6;
66
67        int start = 0;
68        int n = 0;
69        if (byte_width) {
70            if (p == end) {
71                return false;
72            }
73            unsigned int start_and_n = *p++;
74            start = start_and_n >> 4;
75            n = (start_and_n & 15) + 1;
76
77            if (end - p < n * byte_width) {
78                return false;
79            }
80        }
81
82        // Even if there's nothing to display, we want to advance the
83        // raster position.
84        glBitmap(8 * byte_width, n, 0, -start, char_width[ch], 0, p);
85        CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
86        glEndList();
87        CHECK_GL_ERROR("BitmapFont::load", "glEndList");
88
89        p += n * byte_width;
90    }
91
92    return true;
93}
94
95inline void call_lists(GLsizei n, const GLvoid * lists)
96{
97#if SIZEOF_WXCHAR == 1
98    glCallLists(n, GL_UNSIGNED_BYTE, lists);
99#elif SIZEOF_WXCHAR == 2
100    glCallLists(n, GL_UNSIGNED_SHORT, lists);
101#elif SIZEOF_WXCHAR == 4
102    glCallLists(n, GL_UNSIGNED_INT, lists);
103#else
104# error "sizeof(wxChar) not 1, 2 or 4"
105#endif
106}
107
108void
109BitmapFont::init_extra_chars() const
110{
111#ifdef __WXMSW__
112    FILE * fh = _wfopen(font_file.fn_str(), L"rb");
113#else
114    FILE * fh = fopen(font_file.mb_str(), "rb");
115#endif
116
117    long data_len = 0;
118    if (fh && fseek(fh, 0, SEEK_END) >= 0) {
119        data_len = ftell(fh);
120        if (data_len == -1)
121            data_len = 0;
122    }
123    unsigned char * data = new unsigned char [data_len];
124    if (data_len && (fseek(fh, 0, SEEK_SET) < 0 ||
125               fread(data, data_len, 1, fh) != 1)) {
126        data_len = 0;
127        // FIXME: do something better.  wxGetApp().ReportError(m);
128        // We have this message available: Error in format of font file “%s”
129        // fprintf(stderr, "Couldn't load extended font.\n");
130    }
131    if (fh)
132        fclose(fh);
133
134    extra_chars = new unsigned char * [0x10000 - BITMAPFONT_MAX_CHAR];
135    for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
136        if (data_len <= 0) {
137            extra_chars[i] = NULL;
138            continue;
139        }
140        extra_chars[i] = data;
141        unsigned int byte_width = *data++;
142        byte_width >>= 6;
143
144        if (byte_width) {
145            unsigned int start_and_n = *data;
146            int n = (start_and_n & 15) + 1;
147            data += n * byte_width + 1;
148            data_len -= n * byte_width + 1;
149        }
150    }
151}
152
153int
154BitmapFont::glyph_width(wxChar ch) const
155{
156#if SIZEOF_WXCHAR > 2
157    if (ch >= 0x10000) return 0;
158#endif
159    if (!extra_chars)
160        init_extra_chars();
161
162    int width = 8;
163
164    const unsigned char * p = extra_chars[ch - BITMAPFONT_MAX_CHAR];
165    if (p) {
166        unsigned int byte_width = *p;
167        width = (byte_width & 0x0f) + 2;
168    }
169
170    return width;
171}
172
173void
174BitmapFont::write_glyph(wxChar ch) const
175{
176#if SIZEOF_WXCHAR > 2
177    if (ch >= 0x10000) return;
178#endif
179    if (!extra_chars)
180        init_extra_chars();
181
182    unsigned int byte_width = 0;
183    int start = 0;
184    int n = 0;
185    int width = 8;
186
187    const unsigned char * p = extra_chars[ch - BITMAPFONT_MAX_CHAR];
188    if (p) {
189        byte_width = *p++;
190        width = (byte_width & 0x0f) + 2;
191        byte_width >>= 6;
192
193        if (byte_width) {
194            unsigned int start_and_n = *p++;
195            start = start_and_n >> 4;
196            n = (start_and_n & 15) + 1;
197        }
198    }
199
200    // Even if there's nothing to display, we want to advance the
201    // raster position.
202    glBitmap(8 * byte_width, n, 0, -start, width, 0, p);
203    CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
204}
205
206void
207BitmapFont::write_string(const wxChar *s, size_t len) const
208{
209    if (!gllist_base) return;
210    glListBase(gllist_base);
211#if SIZEOF_WXCHAR == 1
212    call_lists(len, s);
213#elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
214    while (len) {
215        size_t n;
216        for (n = 0; n < len; ++n)
217            if (int(s[n]) >= BITMAPFONT_MAX_CHAR)
218                break;
219        call_lists(n, s);
220        s += n;
221        len -= n;
222        while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
223            write_glyph(*s);
224            ++s;
225            --len;
226        }
227    }
228#else
229# error "sizeof(wxChar) not 1, 2 or 4"
230#endif
231}
Note: See TracBrowser for help on using the repository browser.