Update for 1.2.31
[survex.git] / src / glbitmapfont.cc
blob5ed1023858c63d39be1e70ffea22e9e189c7c509
1 //
2 // glbitmapfont.cc
3 //
4 // Draw text using glBitmap.
5 //
6 // Copyright (C) 2011,2012,2013,2014,2015 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.
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.
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
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include "glbitmapfont.h"
29 #include "aventypes.h"
30 #include "useful.h"
31 #include "wx.h"
33 #include <cerrno>
34 #ifdef HAVE_MMAP
35 #include <sys/mman.h>
36 #else
37 #include <unistd.h>
38 #endif
40 using namespace std;
42 #include "../lib/preload_font.h"
44 #define CHECK_GL_ERROR(M, F) do { \
45 GLenum error_code_ = glGetError(); \
46 if (error_code_ != GL_NO_ERROR) { \
47 wxLogError(wxT(__FILE__ ":" STRING(__LINE__) ": OpenGL error: %s " \
48 "(call " F " in method " M ")"), \
49 wxString((const char *)gluErrorString(error_code_), \
50 wxConvUTF8).c_str()); \
51 } \
52 } while (0)
54 bool
55 BitmapFont::load(const wxString & font_file_)
57 font_file = font_file_;
59 if (!gllist_base) {
60 gllist_base = glGenLists(BITMAPFONT_MAX_CHAR);
63 const unsigned char * p = fontdata_preloaded;
64 const unsigned char * end = p + sizeof(fontdata_preloaded);
65 for (int ch = 0; ch < BITMAPFONT_MAX_CHAR; ++ch) {
66 glNewList(gllist_base + ch, GL_COMPILE);
67 CHECK_GL_ERROR("BitmapFont::load", "glNewList");
68 if (p == end) {
69 return false;
71 unsigned int byte_width = *p++;
73 char_width[ch] = (byte_width & 0x0f) + 2;
74 byte_width >>= 6;
76 int start = 0;
77 unsigned int n = 0;
78 if (byte_width) {
79 if (p == end) {
80 return false;
82 unsigned int start_and_n = *p++;
83 start = start_and_n >> 4;
84 n = (start_and_n & 15) + 1;
86 if (unsigned(end - p) < n * byte_width) {
87 return false;
91 // Even if there's nothing to display, we want to advance the
92 // raster position.
93 glBitmap(8 * byte_width, n, 0, -start, char_width[ch], 0, p);
94 CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
95 glEndList();
96 CHECK_GL_ERROR("BitmapFont::load", "glEndList");
98 p += n * byte_width;
101 return true;
104 inline void call_lists(GLsizei n, const GLvoid * lists)
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
117 void
118 BitmapFont::init_extra_chars() const
120 int fd = wxOpen(font_file,
121 #ifdef __WXMSW__
122 _O_RDONLY|_O_SEQUENTIAL|_O_BINARY,
123 #else
124 O_RDONLY,
125 #endif
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;
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) {
141 data_len = 0;
142 } else {
143 extra_data = data = static_cast<unsigned char*>(p);
146 #else
147 data = new unsigned char[data_len];
148 extra_data = data;
149 if (data_len) {
150 size_t c = data_len;
151 unsigned char * p = data;
152 while (c) {
153 ssize_t n = read(fd, p, c);
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;
162 p += n;
163 c -= n;
166 #endif
168 if (fd >= 0)
169 close(fd);
171 extra_chars = new int[0x10000 - BITMAPFONT_MAX_CHAR];
172 int data_ch = 0;
173 for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
174 if (data_ch >= data_len) {
175 extra_chars[i] = -1;
176 continue;
178 extra_chars[i] = data_ch;
179 unsigned int byte_width = data[data_ch++];
180 byte_width >>= 6;
182 if (byte_width) {
183 unsigned int start_and_n = data[data_ch];
184 int n = (start_and_n & 15) + 1;
185 data_ch += n * byte_width + 1;
191 BitmapFont::glyph_width(wxChar ch) const
193 #if SIZEOF_WXCHAR > 2
194 if (ch >= 0x10000) return 0;
195 #endif
196 if (!extra_chars)
197 init_extra_chars();
199 int width = 8;
201 int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
202 if (char_idx >= 0) {
203 unsigned int byte_width = extra_data[char_idx];
204 width = (byte_width & 0x0f) + 2;
207 return width;
210 void
211 BitmapFont::write_glyph(wxChar ch) const
213 #if SIZEOF_WXCHAR > 2
214 if (ch >= 0x10000) return;
215 #endif
216 if (!extra_chars)
217 init_extra_chars();
219 unsigned int byte_width = 0;
220 int start = 0;
221 int n = 0;
222 int width = 8;
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;
228 byte_width = *p++;
229 width = (byte_width & 0x0f) + 2;
230 byte_width >>= 6;
232 if (byte_width) {
233 unsigned int start_and_n = *p++;
234 start = start_and_n >> 4;
235 n = (start_and_n & 15) + 1;
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);
242 CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
245 void
246 BitmapFont::write_string(const wxChar *s, size_t len) const
248 if (!gllist_base) return;
249 glListBase(gllist_base);
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;
261 while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
262 write_glyph(*s);
263 ++s;
264 --len;
267 #else
268 # error "sizeof(wxChar) not 1, 2 or 4"
269 #endif