source: git/src/glbitmapfont.cc @ 8c87227

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 8c87227 was 7ada45b, checked in by Olly Betts <olly@…>, 10 years ago

configure.ac,src/glbitmapfont.cc,src/glbitmapfont.h: For platforms
which support mmap(), just mmap the extra font data, which on Linux
seems to typically be about twice as quick as loading it via fread()
or read(). For other platforms, use read() instead of fread(), since
that seems fractionally faster, and means more code in common with
the mmap case.

  • Property mode set to 100644
File size: 6.0 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 <cerrno>
34#include <sys/mman.h>
35
36using namespace std;
37
38#include "../lib/preload_font.h"
39
40#define CHECK_GL_ERROR(M, F) do { \
41    GLenum error_code_ = glGetError(); \
42    if (error_code_ != GL_NO_ERROR) { \
43        wxLogError(wxT(__FILE__":"STRING(__LINE__)": OpenGL error: %s " \
44                   "(call "F" in method "M")"), \
45                   wxString((const char *)gluErrorString(error_code_), \
46                            wxConvUTF8).c_str()); \
47    } \
48} while (0)
49
50bool
51BitmapFont::load(const wxString & font_file_)
52{
53    font_file = font_file_;
54
55    if (!gllist_base) {
56        gllist_base = glGenLists(BITMAPFONT_MAX_CHAR);
57    }
58
59    const unsigned char * p = fontdata_preloaded;
60    const unsigned char * end = p + sizeof(fontdata_preloaded);
61    for (int ch = 0; ch < BITMAPFONT_MAX_CHAR; ++ch) {
62        glNewList(gllist_base + ch, GL_COMPILE);
63        CHECK_GL_ERROR("BitmapFont::load", "glNewList");
64        if (p == end) {
65            return false;
66        }
67        unsigned int byte_width = *p++;
68
69        char_width[ch] = (byte_width & 0x0f) + 2;
70        byte_width >>= 6;
71
72        int start = 0;
73        unsigned int n = 0;
74        if (byte_width) {
75            if (p == end) {
76                return false;
77            }
78            unsigned int start_and_n = *p++;
79            start = start_and_n >> 4;
80            n = (start_and_n & 15) + 1;
81
82            if (unsigned(end - p) < n * byte_width) {
83                return false;
84            }
85        }
86
87        // Even if there's nothing to display, we want to advance the
88        // raster position.
89        glBitmap(8 * byte_width, n, 0, -start, char_width[ch], 0, p);
90        CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
91        glEndList();
92        CHECK_GL_ERROR("BitmapFont::load", "glEndList");
93
94        p += n * byte_width;
95    }
96
97    return true;
98}
99
100inline void call_lists(GLsizei n, const GLvoid * lists)
101{
102#if SIZEOF_WXCHAR == 1
103    glCallLists(n, GL_UNSIGNED_BYTE, lists);
104#elif SIZEOF_WXCHAR == 2
105    glCallLists(n, GL_UNSIGNED_SHORT, lists);
106#elif SIZEOF_WXCHAR == 4
107    glCallLists(n, GL_UNSIGNED_INT, lists);
108#else
109# error "sizeof(wxChar) not 1, 2 or 4"
110#endif
111}
112
113void
114BitmapFont::init_extra_chars() const
115{
116#ifdef __WXMSW__
117    int fd = _wopen(font_file.fn_str(), _O_RDONLY|_O_SEQUENTIAL);
118#else
119    int fd = open(font_file.mb_str(), O_RDONLY);
120#endif
121
122    int data_len = 0;
123    unsigned char * data = NULL;
124    if (fd >= 0) {
125        struct stat sb;
126        if (fstat(fd, &sb) >= 0) {
127            data_len = sb.st_size;
128        }
129    }
130
131#if HAVE_MMAP
132    if (data_len) {
133        void * p = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, 0);
134        if (p == MAP_FAILED) {
135            data_len = 0;
136        } else {
137            extra_data = data = static_cast<unsigned char*>(p);
138        }
139    }
140#else
141    data = new unsigned char [data_len];
142    extra_data = data;
143    if (data_len) {
144        size_t c = data_len;
145        while (c) {
146            ssize_t n = read(fd, data, c);
147            if (n <= 0) {
148                if (errno == EINTR) continue;
149                data_len = 0;
150                // FIXME: do something better.  wxGetApp().ReportError(m);
151                // We have this message available: Error in format of font file “%s”
152                // fprintf(stderr, "Couldn't load extended font.\n");
153                break;
154            }
155            data += n;
156            c -= n;
157        }
158        data = extra_data;
159    }
160#endif
161
162    if (fd >= 0)
163        close(fd);
164
165    extra_chars = new int [0x10000 - BITMAPFONT_MAX_CHAR];
166    int data_ch = 0;
167    for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
168        if (data_ch >= data_len) {
169            extra_chars[i] = -1;
170            continue;
171        }
172        extra_chars[i] = data_ch;
173        unsigned int byte_width = data[data_ch++];
174        byte_width >>= 6;
175
176        if (byte_width) {
177            unsigned int start_and_n = data[data_ch];
178            int n = (start_and_n & 15) + 1;
179            data_ch += n * byte_width + 1;
180        }
181    }
182}
183
184int
185BitmapFont::glyph_width(wxChar ch) const
186{
187#if SIZEOF_WXCHAR > 2
188    if (ch >= 0x10000) return 0;
189#endif
190    if (!extra_chars)
191        init_extra_chars();
192
193    int width = 8;
194
195    int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
196    if (char_idx >= 0) {
197        unsigned int byte_width = extra_data[char_idx];
198        width = (byte_width & 0x0f) + 2;
199    }
200
201    return width;
202}
203
204void
205BitmapFont::write_glyph(wxChar ch) const
206{
207#if SIZEOF_WXCHAR > 2
208    if (ch >= 0x10000) return;
209#endif
210    if (!extra_chars)
211        init_extra_chars();
212
213    unsigned int byte_width = 0;
214    int start = 0;
215    int n = 0;
216    int width = 8;
217
218    int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
219    const unsigned char * p = extra_data;
220    if (char_idx >= 0) {
221        p += char_idx;
222        byte_width = *p++;
223        width = (byte_width & 0x0f) + 2;
224        byte_width >>= 6;
225
226        if (byte_width) {
227            unsigned int start_and_n = *p++;
228            start = start_and_n >> 4;
229            n = (start_and_n & 15) + 1;
230        }
231    }
232
233    // Even if there's nothing to display, we want to advance the
234    // raster position.
235    glBitmap(8 * byte_width, n, 0, -start, width, 0, p);
236    CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
237}
238
239void
240BitmapFont::write_string(const wxChar *s, size_t len) const
241{
242    if (!gllist_base) return;
243    glListBase(gllist_base);
244#if SIZEOF_WXCHAR == 1
245    call_lists(len, s);
246#elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
247    while (len) {
248        size_t n;
249        for (n = 0; n < len; ++n)
250            if (int(s[n]) >= BITMAPFONT_MAX_CHAR)
251                break;
252        call_lists(n, s);
253        s += n;
254        len -= n;
255        while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
256            write_glyph(*s);
257            ++s;
258            --len;
259        }
260    }
261#else
262# error "sizeof(wxChar) not 1, 2 or 4"
263#endif
264}
Note: See TracBrowser for help on using the repository browser.