source: git/src/glbitmapfont.cc @ 87b0ab3f

RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernlogstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 87b0ab3f was 87b0ab3f, checked in by Olly Betts <olly@…>, 10 years ago

src/glbitmapfont.cc: Fix signed/unsigned comparison warning.

  • Property mode set to 100644
File size: 5.5 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        unsigned 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 (unsigned(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    extra_data = data;
125    if (data_len && (fseek(fh, 0, SEEK_SET) < 0 ||
126               fread(data, data_len, 1, fh) != 1)) {
127        data_len = 0;
128        // FIXME: do something better.  wxGetApp().ReportError(m);
129        // We have this message available: Error in format of font file “%s”
130        // fprintf(stderr, "Couldn't load extended font.\n");
131    }
132    if (fh)
133        fclose(fh);
134
135    extra_chars = new int [0x10000 - BITMAPFONT_MAX_CHAR];
136    int data_ch = 0;
137    for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
138        if (data_ch >= data_len) {
139            extra_chars[i] = -1;
140            continue;
141        }
142        extra_chars[i] = data_ch;
143        unsigned int byte_width = data[data_ch++];
144        byte_width >>= 6;
145
146        if (byte_width) {
147            unsigned int start_and_n = data[data_ch];
148            int n = (start_and_n & 15) + 1;
149            data_ch += n * byte_width + 1;
150        }
151    }
152}
153
154int
155BitmapFont::glyph_width(wxChar ch) const
156{
157#if SIZEOF_WXCHAR > 2
158    if (ch >= 0x10000) return 0;
159#endif
160    if (!extra_data)
161        init_extra_chars();
162
163    int width = 8;
164
165    int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
166    if (char_idx >= 0) {
167        unsigned int byte_width = extra_data[char_idx];
168        width = (byte_width & 0x0f) + 2;
169    }
170
171    return width;
172}
173
174void
175BitmapFont::write_glyph(wxChar ch) const
176{
177#if SIZEOF_WXCHAR > 2
178    if (ch >= 0x10000) return;
179#endif
180    if (!extra_data)
181        init_extra_chars();
182
183    unsigned int byte_width = 0;
184    int start = 0;
185    int n = 0;
186    int width = 8;
187
188    int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
189    const unsigned char * p = extra_data;
190    if (char_idx >= 0) {
191        p += char_idx;
192        byte_width = *p++;
193        width = (byte_width & 0x0f) + 2;
194        byte_width >>= 6;
195
196        if (byte_width) {
197            unsigned int start_and_n = *p++;
198            start = start_and_n >> 4;
199            n = (start_and_n & 15) + 1;
200        }
201    }
202
203    // Even if there's nothing to display, we want to advance the
204    // raster position.
205    glBitmap(8 * byte_width, n, 0, -start, width, 0, p);
206    CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
207}
208
209void
210BitmapFont::write_string(const wxChar *s, size_t len) const
211{
212    if (!gllist_base) return;
213    glListBase(gllist_base);
214#if SIZEOF_WXCHAR == 1
215    call_lists(len, s);
216#elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
217    while (len) {
218        size_t n;
219        for (n = 0; n < len; ++n)
220            if (int(s[n]) >= BITMAPFONT_MAX_CHAR)
221                break;
222        call_lists(n, s);
223        s += n;
224        len -= n;
225        while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
226            write_glyph(*s);
227            ++s;
228            --len;
229        }
230    }
231#else
232# error "sizeof(wxChar) not 1, 2 or 4"
233#endif
234}
Note: See TracBrowser for help on using the repository browser.