source: git/src/glbitmapfont.cc @ cba8bf34

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

src/glbitmapfont.cc,src/glbitmapfont.h:
BitmapFont::get_text_extent() now uses the width of all glyphs,
rather than assuming all those > BITMAPFONT_MAX_CHAR have width 16.

  • Property mode set to 100644
File size: 5.2 KB
RevLine 
[a1614eb]1//
2//  glbitmapfont.cc
3//
4//  Draw text using glBitmap.
5//
[c7627d4]6//  Copyright (C) 2011,2012,2013,2014 Olly Betts
[a1614eb]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#define CHECK_GL_ERROR(M, F) do { \
34    GLenum error_code_ = glGetError(); \
[1c8ab60]35    if (error_code_ != GL_NO_ERROR) { \
[a1614eb]36        wxLogError(wxT(__FILE__":"STRING(__LINE__)": OpenGL error: %s " \
37                   "(call "F" in method "M")"), \
38                   wxString((const char *)gluErrorString(error_code_), \
39                            wxConvUTF8).c_str()); \
[1c8ab60]40    } \
[a1614eb]41} while (0)
42
43bool
44BitmapFont::load(const wxString & font_file)
45{
[36b4cd7]46    if (fh) fclose(fh);
[a1614eb]47#ifdef __WXMSW__
[36b4cd7]48    fh = _wfopen(font_file.fn_str(), L"rb");
[a1614eb]49#else
[36b4cd7]50    fh = fopen(font_file.mb_str(), "rb");
[a1614eb]51#endif
52
53    if (!fh) {
54        return false;
55    }
56
57    if (!gllist_base) {
58        gllist_base = glGenLists(BITMAPFONT_MAX_CHAR);
59    }
60
61    unsigned char buf[32];
62
63    for (int ch = 0; ch < BITMAPFONT_MAX_CHAR; ++ch) {
64        glNewList(gllist_base + ch, GL_COMPILE);
65        CHECK_GL_ERROR("BitmapFont::load", "glNewList");
[17c483d]66        int b = GETC(fh);
67        if (b == EOF) {
68            fclose(fh);
69            return false;
70        }
71        unsigned int byte_width = b;
[a1614eb]72
[d4d6909]73        char_width[ch] = (byte_width & 0x0f) + 2;
74        byte_width >>= 6;
[a1614eb]75
76        int start = 0;
77        int n = 0;
78        if (byte_width) {
[17c483d]79            b = GETC(fh);
80            if (b == EOF) {
81                fclose(fh);
82                return false;
83            }
84            unsigned int start_and_n = b;
[a1614eb]85            start = start_and_n >> 4;
86            n = (start_and_n & 15) + 1;
[17c483d]87            if (fread(buf, n * byte_width, 1, fh) != 1) {
88                fclose(fh);
89                return false;
90            }
[a1614eb]91        }
92
93        // Even if there's nothing to display, we want to advance the
94        // raster position.
95        glBitmap(8 * byte_width, n, 0, -start, char_width[ch], 0, buf);
96        CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
97        glEndList();
98        CHECK_GL_ERROR("BitmapFont::load", "glEndList");
99    }
100
101    return true;
102}
103
104inline void call_lists(GLsizei n, const GLvoid * lists)
105{
[30b66b5]106#if SIZEOF_WXCHAR == 1
107    glCallLists(n, GL_UNSIGNED_BYTE, lists);
108#elif SIZEOF_WXCHAR == 2
109    glCallLists(n, GL_UNSIGNED_SHORT, lists);
110#elif SIZEOF_WXCHAR == 4
111    glCallLists(n, GL_UNSIGNED_INT, lists);
112#else
113# error "sizeof(wxChar) not 1, 2 or 4"
114#endif
[a1614eb]115}
116
[36b4cd7]117void
[cba8bf34]118BitmapFont::init_extra_chars() const
[36b4cd7]119{
[cba8bf34]120    long here = ftell(fh);
121    if (here == -1 || fseek(fh, 0, SEEK_END) < 0)
122        return;
123    long data_len = ftell(fh);
124    if (data_len == -1)
125        return;
126    data_len -= here;
127    unsigned char * data = new unsigned char [data_len];
128    if (fseek(fh, here, SEEK_SET) < 0 ||
129        fread(data, data_len, 1, fh) != 1) {
130        delete data;
131        return;
132    }
133    extra_chars = new unsigned char * [0x10000 - BITMAPFONT_MAX_CHAR];
134
135    for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
136        if (data_len <= 0) {
137            extra_chars[i] = NULL;
138            continue;
[36b4cd7]139        }
[cba8bf34]140        extra_chars[i] = data;
141        unsigned int byte_width = *data++;
142        byte_width >>= 6;
[36b4cd7]143
[cba8bf34]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;
[36b4cd7]149        }
150    }
[cba8bf34]151    fclose(fh);
152    fh = NULL;
153}
154
155int
156BitmapFont::glyph_width(wxChar ch) const
157{
158#if SIZEOF_WXCHAR > 2
159    if (ch >= 0x10000) return 0;
160#endif
161    if (!extra_chars)
162        init_extra_chars();
163
164    unsigned int byte_width = 0;
165    int width = 8;
166
167    const unsigned char * p = extra_chars[ch - BITMAPFONT_MAX_CHAR];
168    if (p) {
169        byte_width = *p++;
170        width = (byte_width & 0x0f) + 2;
171    }
172
173    return width;
174}
175
176void
177BitmapFont::write_glyph(wxChar ch) const
178{
179#if SIZEOF_WXCHAR > 2
180    if (ch >= 0x10000) return;
181#endif
182    if (!extra_chars)
183        init_extra_chars();
[36b4cd7]184
[d4d6909]185    unsigned int byte_width = 0;
[36b4cd7]186    int start = 0;
187    int n = 0;
188    int width = 8;
[d4d6909]189
190    const unsigned char * p = extra_chars[ch - BITMAPFONT_MAX_CHAR];
191    if (p) {
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        }
[36b4cd7]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}
207
[a1614eb]208void
209BitmapFont::write_string(const wxChar *s, size_t len) const
210{
[36b4cd7]211    if (!gllist_base) return;
[a1614eb]212    glListBase(gllist_base);
[30b66b5]213#if SIZEOF_WXCHAR == 1
214    call_lists(len, s);
215#elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
216    while (len) {
217        size_t n;
218        for (n = 0; n < len; ++n)
219            if (int(s[n]) >= BITMAPFONT_MAX_CHAR)
220                break;
221        call_lists(n, s);
222        s += n;
223        len -= n;
[c7627d4]224        while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
225            write_glyph(*s);
[30b66b5]226            ++s;
227            --len;
[a1614eb]228        }
229    }
[30b66b5]230#else
231# error "sizeof(wxChar) not 1, 2 or 4"
232#endif
[a1614eb]233}
Note: See TracBrowser for help on using the repository browser.