source: git/src/glbitmapfont.cc @ 1520aee

stereo
Last change on this file since 1520aee was 410c73f, checked in by Olly Betts <olly@…>, 8 years ago

Whitespace tweaks

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