4 // Draw text using glBitmap.
6 // Copyright (C) 2011-2022 Olly Betts
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
25 #include "glbitmapfont.h"
27 #include "aventypes.h"
28 #include "gllogerror.h"
42 #include "../lib/preload_font.h"
44 BitmapFont::~BitmapFont() {
45 if (!gllist_base
) return;
46 glDeleteLists(gllist_base
, BITMAPFONT_MAX_CHAR
);
47 CHECK_GL_ERROR("BitmapFont::~BitmapFont", "glDeleteLists");
50 static uint16_t* tab_2x
= NULL
;
51 static uint16_t* fontdata_2x
= NULL
;
52 static uint16_t* fontdata_2x_extra
= NULL
;
55 BitmapFont::load(const wxString
& font_file_
, bool double_size
)
57 font_file
= font_file_
;
59 font_size
= double_size
? 32 : 16;
62 gllist_base
= glGenLists(BITMAPFONT_MAX_CHAR
);
63 CHECK_GL_ERROR("BitmapFont::load", "glGenLists");
66 if (double_size
&& !tab_2x
) {
67 tab_2x
= new uint16_t[256];
68 for (unsigned i
= 0; i
< 256; ++i
) {
69 unsigned v
= (i
& 1) << 8 |
79 fontdata_2x
= new uint16_t[sizeof(fontdata_preloaded
) * 2];
81 const unsigned char * p
= fontdata_preloaded
;
82 const unsigned char * end
= p
+ sizeof(fontdata_preloaded
);
83 uint16_t* out
= fontdata_2x
;
84 for (int ch
= 0; ch
< BITMAPFONT_MAX_CHAR
; ++ch
) {
85 glNewList(gllist_base
+ ch
, GL_COMPILE
);
86 CHECK_GL_ERROR("BitmapFont::load", "glNewList");
90 unsigned int byte_width
= *p
++;
92 char_width
[ch
] = (byte_width
& 0x0f) + 2;
101 unsigned int start_and_n
= *p
++;
102 start
= start_and_n
>> 4;
103 n
= (start_and_n
& 15) + 1;
105 if (unsigned(end
- p
) < n
* byte_width
) {
110 // Note that even if there's nothing to display, we still call
111 // glBitmap() to advance the raster position.
113 const GLubyte
* q
= reinterpret_cast<const GLubyte
*>(out
);
114 for (unsigned i
= 0; i
!= n
; ++i
) {
115 for (unsigned j
= 0; j
!= byte_width
; ++j
) {
116 *out
++ = tab_2x
[*p
++];
118 memcpy(out
, out
- byte_width
, byte_width
* sizeof(uint16_t));
123 glBitmap(2 * 8 * byte_width
, 2 * n
, 0, -2 * start
, char_width
[ch
], 0, q
);
125 glBitmap(8 * byte_width
, n
, 0, -start
, char_width
[ch
], 0, p
);
128 CHECK_GL_ERROR("BitmapFont::load", "glBitmap");
130 CHECK_GL_ERROR("BitmapFont::load", "glEndList");
136 inline void call_lists(GLsizei n
, const GLvoid
* lists
)
138 #if SIZEOF_WXCHAR == 1
139 glCallLists(n
, GL_UNSIGNED_BYTE
, lists
);
140 #elif SIZEOF_WXCHAR == 2
141 glCallLists(n
, GL_UNSIGNED_SHORT
, lists
);
142 #elif SIZEOF_WXCHAR == 4
143 glCallLists(n
, GL_UNSIGNED_INT
, lists
);
145 # error "sizeof(wxChar) not 1, 2 or 4"
150 BitmapFont::init_extra_chars() const
152 bool double_size
= (tab_2x
!= NULL
);
153 int fd
= wxOpen(font_file
,
155 _O_RDONLY
|_O_SEQUENTIAL
|_O_BINARY
,
162 unsigned char * data
= NULL
;
165 if (fstat(fd
, &sb
) >= 0) {
166 data_len
= sb
.st_size
;
172 void * p
= mmap(NULL
, data_len
, PROT_READ
, MAP_SHARED
, fd
, 0);
173 if (p
== MAP_FAILED
) {
176 extra_data
= data
= static_cast<unsigned char*>(p
);
180 data
= new unsigned char[data_len
];
184 unsigned char * p
= data
;
186 ssize_t n
= read(fd
, p
, c
);
188 if (errno
== EINTR
) continue;
190 // FIXME: do something better. wxGetApp().ReportError(m);
191 // We have this message available: Error in format of font file ā%sā
192 // fprintf(stderr, "Couldn't load extended font.\n");
204 extra_chars
= new int[0x10000 - BITMAPFONT_MAX_CHAR
];
208 // The bitmap data will increase 4*, while the metadata will increase
209 // 2*, so we can use 4* the total size as an overestimate.
210 fontdata_2x_extra
= new uint16_t[data_len
* 2];
211 uint16_t* out
= fontdata_2x_extra
;
213 while (data_ch
< data_len
) {
214 extra_chars
[ch
++] = out
- fontdata_2x_extra
;
215 unsigned int b
= data
[data_ch
++];
217 unsigned int byte_width
= b
>> 6;
219 unsigned int start_and_n
= data
[data_ch
++];
220 *out
++ = start_and_n
;
221 unsigned int n
= (start_and_n
& 15) + 1;
222 for (unsigned i
= 0; i
!= n
; ++i
) {
223 for (unsigned j
= 0; j
!= byte_width
; ++j
) {
224 *out
++ = tab_2x
[data
[data_ch
++]];
225 if (out
- fontdata_2x_extra
>= data_len
* 2) abort();
227 memcpy(out
, out
- byte_width
, byte_width
* sizeof(uint16_t));
229 if (out
- fontdata_2x_extra
>= data_len
* 2) abort();
235 while (data_ch
< data_len
) {
236 extra_chars
[ch
++] = data_ch
;
237 unsigned int byte_width
= data
[data_ch
++];
241 unsigned int start_and_n
= data
[data_ch
];
242 int n
= (start_and_n
& 15) + 1;
243 data_ch
+= n
* byte_width
+ 1;
248 while (ch
< 0x10000 - BITMAPFONT_MAX_CHAR
) {
249 extra_chars
[ch
++] = -1;
254 BitmapFont::glyph_width(wxChar ch
) const
256 #if SIZEOF_WXCHAR > 2
257 if (ch
>= 0x10000) return 0;
262 int char_idx
= extra_chars
[ch
- BITMAPFONT_MAX_CHAR
];
264 return tab_2x
? 16 : 8;
267 unsigned int byte_width
= fontdata_2x_extra
[char_idx
];
268 return ((byte_width
& 0x0f) + 2) << 1;
270 unsigned int byte_width
= extra_data
[char_idx
];
271 return (byte_width
& 0x0f) + 2;
276 BitmapFont::write_glyph(wxChar ch
) const
278 #if SIZEOF_WXCHAR > 2
279 if (ch
>= 0x10000) return;
284 unsigned int byte_width
= 0;
289 int char_idx
= extra_chars
[ch
- BITMAPFONT_MAX_CHAR
];
290 const unsigned char* data
= NULL
;
293 const uint16_t* p
= fontdata_2x_extra
+ char_idx
;
295 width
= (byte_width
& 0x0f) + 2;
300 unsigned int start_and_n
= *p
++;
301 start
= (start_and_n
>> 4) << 1;
302 n
= ((start_and_n
& 15) + 1) << 1;
306 data
= reinterpret_cast<const unsigned char*>(p
);
308 const unsigned char * p
= extra_data
+ char_idx
;
310 width
= (byte_width
& 0x0f) + 2;
314 unsigned int start_and_n
= *p
++;
315 start
= start_and_n
>> 4;
316 n
= (start_and_n
& 15) + 1;
322 // Even if there's nothing to display, we want to advance the
324 glBitmap(8 * byte_width
, n
, 0, -start
, width
, 0, data
);
325 CHECK_GL_ERROR("BitmapFont::write_glyph", "glBitmap");
329 BitmapFont::write_string(const wxChar
*s
, size_t len
) const
331 if (!gllist_base
) return;
332 glListBase(gllist_base
);
333 #if SIZEOF_WXCHAR == 1
335 #elif SIZEOF_WXCHAR == 2 || SIZEOF_WXCHAR == 4
338 for (n
= 0; n
< len
; ++n
)
339 if (int(s
[n
]) >= BITMAPFONT_MAX_CHAR
)
344 while (len
&& int(*s
) >= BITMAPFONT_MAX_CHAR
) {
351 # error "sizeof(wxChar) not 1, 2 or 4"