Fix coding style
[survex.git] / src / glbitmapfont.cc
blob9a0b871223deffdcaff9c9e29ed43353baad7e6e
1 //
2 // glbitmapfont.cc
3 //
4 // Draw text using glBitmap.
5 //
6 // Copyright (C) 2011,2012,2013,2014,2015,2018 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 "gllogerror.h"
31 #include "useful.h"
32 #include "wx.h"
34 #include <cerrno>
35 #ifdef HAVE_MMAP
36 #include <sys/mman.h>
37 #else
38 #include <unistd.h>
39 #endif
41 using namespace std;
43 #include "../lib/preload_font.h"
45 BitmapFont::~BitmapFont() {
46 if (!gllist_base) return;
47 glDeleteLists(gllist_base, BITMAPFONT_MAX_CHAR);
48 CHECK_GL_ERROR("BitmapFont::~BitmapFont", "glDeleteLists");
51 bool
52 BitmapFont::load(const wxString & font_file_)
54 font_file = font_file_;
56 if (!gllist_base) {
57 gllist_base = glGenLists(BITMAPFONT_MAX_CHAR);
58 CHECK_GL_ERROR("BitmapFont::load", "glGenLists");
61 const unsigned char * p = fontdata_preloaded;
62 const unsigned char * end = p + sizeof(fontdata_preloaded);
63 for (int ch = 0; ch < BITMAPFONT_MAX_CHAR; ++ch) {
64 glNewList(gllist_base + ch, GL_COMPILE);
65 CHECK_GL_ERROR("BitmapFont::load", "glNewList");
66 if (p == end) {
67 return false;
69 unsigned int byte_width = *p++;
71 char_width[ch] = (byte_width & 0x0f) + 2;
72 byte_width >>= 6;
74 int start = 0;
75 unsigned int n = 0;
76 if (byte_width) {
77 if (p == end) {
78 return false;
80 unsigned int start_and_n = *p++;
81 start = start_and_n >> 4;
82 n = (start_and_n & 15) + 1;
84 if (unsigned(end - p) < n * byte_width) {
85 return false;
89 // Even if there's nothing to display, we want to advance the
90 // raster position.
91 glBitmap(8 * byte_width, n, 0, -start, char_width[ch], 0, p);
92 CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
93 glEndList();
94 CHECK_GL_ERROR("BitmapFont::load", "glEndList");
96 p += n * byte_width;
99 return true;
102 inline void call_lists(GLsizei n, const GLvoid * lists)
104 #if SIZEOF_WXCHAR == 1
105 glCallLists(n, GL_UNSIGNED_BYTE, lists);
106 #elif SIZEOF_WXCHAR == 2
107 glCallLists(n, GL_UNSIGNED_SHORT, lists);
108 #elif SIZEOF_WXCHAR == 4
109 glCallLists(n, GL_UNSIGNED_INT, lists);
110 #else
111 # error "sizeof(wxChar) not 1, 2 or 4"
112 #endif
115 void
116 BitmapFont::init_extra_chars() const
118 int fd = wxOpen(font_file,
119 #ifdef __WXMSW__
120 _O_RDONLY|_O_SEQUENTIAL|_O_BINARY,
121 #else
122 O_RDONLY,
123 #endif
126 int data_len = 0;
127 unsigned char * data = NULL;
128 if (fd >= 0) {
129 struct stat sb;
130 if (fstat(fd, &sb) >= 0) {
131 data_len = sb.st_size;
135 #if HAVE_MMAP
136 if (data_len) {
137 void * p = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, 0);
138 if (p == MAP_FAILED) {
139 data_len = 0;
140 } else {
141 extra_data = data = static_cast<unsigned char*>(p);
144 #else
145 data = new unsigned char[data_len];
146 extra_data = data;
147 if (data_len) {
148 size_t c = data_len;
149 unsigned char * p = data;
150 while (c) {
151 ssize_t n = read(fd, p, c);
152 if (n <= 0) {
153 if (errno == EINTR) continue;
154 data_len = 0;
155 // FIXME: do something better. wxGetApp().ReportError(m);
156 // We have this message available: Error in format of font file ā€œ%sā€
157 // fprintf(stderr, "Couldn't load extended font.\n");
158 break;
160 p += n;
161 c -= n;
164 #endif
166 if (fd >= 0)
167 close(fd);
169 extra_chars = new int[0x10000 - BITMAPFONT_MAX_CHAR];
170 int data_ch = 0;
171 for (int i = 0; i < 0x10000 - BITMAPFONT_MAX_CHAR; ++i) {
172 if (data_ch >= data_len) {
173 extra_chars[i] = -1;
174 continue;
176 extra_chars[i] = data_ch;
177 unsigned int byte_width = data[data_ch++];
178 byte_width >>= 6;
180 if (byte_width) {
181 unsigned int start_and_n = data[data_ch];
182 int n = (start_and_n & 15) + 1;
183 data_ch += n * byte_width + 1;
189 BitmapFont::glyph_width(wxChar ch) const
191 #if SIZEOF_WXCHAR > 2
192 if (ch >= 0x10000) return 0;
193 #endif
194 if (!extra_chars)
195 init_extra_chars();
197 int width = 8;
199 int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
200 if (char_idx >= 0) {
201 unsigned int byte_width = extra_data[char_idx];
202 width = (byte_width & 0x0f) + 2;
205 return width;
208 void
209 BitmapFont::write_glyph(wxChar ch) const
211 #if SIZEOF_WXCHAR > 2
212 if (ch >= 0x10000) return;
213 #endif
214 if (!extra_chars)
215 init_extra_chars();
217 unsigned int byte_width = 0;
218 int start = 0;
219 int n = 0;
220 int width = 8;
222 int char_idx = extra_chars[ch - BITMAPFONT_MAX_CHAR];
223 const unsigned char * p = extra_data;
224 if (char_idx >= 0) {
225 p += char_idx;
226 byte_width = *p++;
227 width = (byte_width & 0x0f) + 2;
228 byte_width >>= 6;
230 if (byte_width) {
231 unsigned int start_and_n = *p++;
232 start = start_and_n >> 4;
233 n = (start_and_n & 15) + 1;
237 // Even if there's nothing to display, we want to advance the
238 // raster position.
239 glBitmap(8 * byte_width, n, 0, -start, width, 0, p);
240 CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
243 void
244 BitmapFont::write_string(const wxChar *s, size_t len) const
246 if (!gllist_base) return;
247 glListBase(gllist_base);
248 #if SIZEOF_WXCHAR == 1
249 call_lists(len, s);
250 #elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
251 while (len) {
252 size_t n;
253 for (n = 0; n < len; ++n)
254 if (int(s[n]) >= BITMAPFONT_MAX_CHAR)
255 break;
256 call_lists(n, s);
257 s += n;
258 len -= n;
259 while (len && int(*s) >= BITMAPFONT_MAX_CHAR) {
260 write_glyph(*s);
261 ++s;
262 --len;
265 #else
266 # error "sizeof(wxChar) not 1, 2 or 4"
267 #endif