1 // stb_easy_font.h - v1.1 - bitmap font for 3D rendering - public domain
2 // Sean Barrett, Feb 2015
3 //
4 //    Easy-to-deploy,
5 //    reasonably compact,
6 //    extremely inefficient performance-wise,
7 //    crappy-looking,
8 //    ASCII-only,
9 //    bitmap font for use in 3D APIs.
10 //
11 // Intended for when you just want to get some text displaying
12 // in a 3D app as quickly as possible.
13 //
14 // Doesn't use any textures, instead builds characters out of quads.
15 //
16 // DOCUMENTATION:
17 //
18 //   int stb_easy_font_width(char *text)
19 //   int stb_easy_font_height(char *text)
20 //
21 //      Takes a string and returns the horizontal size and the
22 //      vertical size (which can vary if 'text' has newlines).
23 //
24 //   int stb_easy_font_print(float x, float y,
25 //                           char *text, unsigned char color[4],
26 //                           void *vertex_buffer, int vbuf_size)
27 //
28 //      Takes a string (which can contain '\n') and fills out a
29 //      vertex buffer with renderable data to draw the string.
30 //      Output data assumes increasing x is rightwards, increasing y
31 //      is downwards.
32 //
33 //      The vertex data is divided into quads, i.e. there are four
34 //      vertices in the vertex buffer for each quad.
35 //
36 //      The vertices are stored in an interleaved format:
37 //
38 //         x:float
39 //         y:float
40 //         z:float
41 //         color:uint8[4]
42 //
43 //      You can ignore z and color if you get them from elsewhere
44 //      This format was chosen in the hopes it would make it
45 //      easier for you to reuse existing vertex-buffer-drawing code.
46 //
47 //      If you pass in NULL for color, it becomes 255,255,255,255.
48 //
49 //      Returns the number of quads.
50 //
51 //      If the buffer isn't large enough, it will truncate.
52 //      Expect it to use an average of ~270 bytes per character.
53 //
54 //      If your API doesn't draw quads, build a reusable index
55 //      list that allows you to render quads as indexed triangles.
56 //
57 //   void stb_easy_font_spacing(float spacing)
58 //
59 //      Use positive values to expand the space between characters,
60 //      and small negative values (no smaller than -1.5) to contract
61 //      the space between characters.
62 //
63 //      E.g. spacing = 1 adds one "pixel" of spacing between the
64 //      characters. spacing = -1 is reasonable but feels a bit too
65 //      compact to me; -0.5 is a reasonable compromise as long as
66 //      you're scaling the font up.
67 //
68 // LICENSE
69 //
70 //   See end of file for license information.
71 //
72 // VERSION HISTORY
73 //
74 //   (2020-02-02)  1.1   make everything static so can compile it in more than one src file
75 //   (2017-01-15)  1.0   space character takes same space as numbers; fix bad spacing of 'f'
76 //   (2016-01-22)  0.7   width() supports multiline text; add height()
77 //   (2015-09-13)  0.6   #include <math.h>; updated license
78 //   (2015-02-01)  0.5   First release
79 //
80 // CONTRIBUTORS
81 //
82 //   github:vassvik    --  bug report
83 //   github:podsvirov  --  fix multiple definition errors
84 
85 #if 0
86 // SAMPLE CODE:
87 //
88 //    Here's sample code for old OpenGL; it's a lot more complicated
89 //    to make work on modern APIs, and that's your problem.
90 //
91 void print_string(float x, float y, char *text, float r, float g, float b)
92 {
93   static char buffer[99999]; // ~500 chars
94   int num_quads;
95 
96   num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
97 
98   glColor3f(r,g,b);
99   glEnableClientState(GL_VERTEX_ARRAY);
100   glVertexPointer(2, GL_FLOAT, 16, buffer);
101   glDrawArrays(GL_QUADS, 0, num_quads*4);
102   glDisableClientState(GL_VERTEX_ARRAY);
103 }
104 #endif
105 
106 #ifndef INCLUDE_STB_EASY_FONT_H
107 #define INCLUDE_STB_EASY_FONT_H
108 
109 #include <stdlib.h>
110 #include <math.h>
111 
112 static struct stb_easy_font_info_struct {
113     unsigned char advance;
114     unsigned char h_seg;
115     unsigned char v_seg;
116 } stb_easy_font_charinfo[96] = {
117     {  6,  0,  0 },  {  3,  0,  0 },  {  5,  1,  1 },  {  7,  1,  4 },
118     {  7,  3,  7 },  {  7,  6, 12 },  {  7,  8, 19 },  {  4, 16, 21 },
119     {  4, 17, 22 },  {  4, 19, 23 },  { 23, 21, 24 },  { 23, 22, 31 },
120     { 20, 23, 34 },  { 22, 23, 36 },  { 19, 24, 36 },  { 21, 25, 36 },
121     {  6, 25, 39 },  {  6, 27, 43 },  {  6, 28, 45 },  {  6, 30, 49 },
122     {  6, 33, 53 },  {  6, 34, 57 },  {  6, 40, 58 },  {  6, 46, 59 },
123     {  6, 47, 62 },  {  6, 55, 64 },  { 19, 57, 68 },  { 20, 59, 68 },
124     { 21, 61, 69 },  { 22, 66, 69 },  { 21, 68, 69 },  {  7, 73, 69 },
125     {  9, 75, 74 },  {  6, 78, 81 },  {  6, 80, 85 },  {  6, 83, 90 },
126     {  6, 85, 91 },  {  6, 87, 95 },  {  6, 90, 96 },  {  7, 92, 97 },
127     {  6, 96,102 },  {  5, 97,106 },  {  6, 99,107 },  {  6,100,110 },
128     {  6,100,115 },  {  7,101,116 },  {  6,101,121 },  {  6,101,125 },
129     {  6,102,129 },  {  7,103,133 },  {  6,104,140 },  {  6,105,145 },
130     {  7,107,149 },  {  6,108,151 },  {  7,109,155 },  {  7,109,160 },
131     {  7,109,165 },  {  7,118,167 },  {  6,118,172 },  {  4,120,176 },
132     {  6,122,177 },  {  4,122,181 },  { 23,124,182 },  { 22,129,182 },
133     {  4,130,182 },  { 22,131,183 },  {  6,133,187 },  { 22,135,191 },
134     {  6,137,192 },  { 22,139,196 },  {  6,144,197 },  { 22,147,198 },
135     {  6,150,202 },  { 19,151,206 },  { 21,152,207 },  {  6,155,209 },
136     {  3,160,210 },  { 23,160,211 },  { 22,164,216 },  { 22,165,220 },
137     { 22,167,224 },  { 22,169,228 },  { 21,171,232 },  { 21,173,233 },
138     {  5,178,233 },  { 22,179,234 },  { 23,180,238 },  { 23,180,243 },
139     { 23,180,248 },  { 22,189,248 },  { 22,191,252 },  {  5,196,252 },
140     {  3,203,252 },  {  5,203,253 },  { 22,210,253 },  {  0,214,253 },
141 };
142 
143 static unsigned char stb_easy_font_hseg[214] = {
144    97,37,69,84,28,51,2,18,10,49,98,41,65,25,81,105,33,9,97,1,97,37,37,36,
145     81,10,98,107,3,100,3,99,58,51,4,99,58,8,73,81,10,50,98,8,73,81,4,10,50,
146     98,8,25,33,65,81,10,50,17,65,97,25,33,25,49,9,65,20,68,1,65,25,49,41,
147     11,105,13,101,76,10,50,10,50,98,11,99,10,98,11,50,99,11,50,11,99,8,57,
148     58,3,99,99,107,10,10,11,10,99,11,5,100,41,65,57,41,65,9,17,81,97,3,107,
149     9,97,1,97,33,25,9,25,41,100,41,26,82,42,98,27,83,42,98,26,51,82,8,41,
150     35,8,10,26,82,114,42,1,114,8,9,73,57,81,41,97,18,8,8,25,26,26,82,26,82,
151     26,82,41,25,33,82,26,49,73,35,90,17,81,41,65,57,41,65,25,81,90,114,20,
152     84,73,57,41,49,25,33,65,81,9,97,1,97,25,33,65,81,57,33,25,41,25,
153 };
154 
155 static unsigned char stb_easy_font_vseg[253] = {
156    4,2,8,10,15,8,15,33,8,15,8,73,82,73,57,41,82,10,82,18,66,10,21,29,1,65,
157     27,8,27,9,65,8,10,50,97,74,66,42,10,21,57,41,29,25,14,81,73,57,26,8,8,
158     26,66,3,8,8,15,19,21,90,58,26,18,66,18,105,89,28,74,17,8,73,57,26,21,
159     8,42,41,42,8,28,22,8,8,30,7,8,8,26,66,21,7,8,8,29,7,7,21,8,8,8,59,7,8,
160     8,15,29,8,8,14,7,57,43,10,82,7,7,25,42,25,15,7,25,41,15,21,105,105,29,
161     7,57,57,26,21,105,73,97,89,28,97,7,57,58,26,82,18,57,57,74,8,30,6,8,8,
162     14,3,58,90,58,11,7,74,43,74,15,2,82,2,42,75,42,10,67,57,41,10,7,2,42,
163     74,106,15,2,35,8,8,29,7,8,8,59,35,51,8,8,15,35,30,35,8,8,30,7,8,8,60,
164     36,8,45,7,7,36,8,43,8,44,21,8,8,44,35,8,8,43,23,8,8,43,35,8,8,31,21,15,
165     20,8,8,28,18,58,89,58,26,21,89,73,89,29,20,8,8,30,7,
166 };
167 
168 typedef struct
169 {
170    unsigned char c[4];
171 } stb_easy_font_color;
172 
stb_easy_font_draw_segs(float x,float y,unsigned char * segs,int num_segs,int vertical,stb_easy_font_color c,char * vbuf,int vbuf_size,int offset)173 static int stb_easy_font_draw_segs(float x, float y, unsigned char *segs, int num_segs, int vertical, stb_easy_font_color c, char *vbuf, int vbuf_size, int offset)
174 {
175     int i,j;
176     for (i=0; i < num_segs; ++i) {
177         int len = segs[i] & 7;
178         x += (float) ((segs[i] >> 3) & 1);
179         if (len && offset+64 <= vbuf_size) {
180             float y0 = y + (float) (segs[i]>>4);
181             for (j=0; j < 4; ++j) {
182                 * (float *) (vbuf+offset+0) = x  + (j==1 || j==2 ? (vertical ? 1 : len) : 0);
183                 * (float *) (vbuf+offset+4) = y0 + (    j >= 2   ? (vertical ? len : 1) : 0);
184                 * (float *) (vbuf+offset+8) = 0.f;
185                 * (stb_easy_font_color *) (vbuf+offset+12) = c;
186                 offset += 16;
187             }
188         }
189     }
190     return offset;
191 }
192 
193 static float stb_easy_font_spacing_val = 0;
stb_easy_font_spacing(float spacing)194 static void stb_easy_font_spacing(float spacing)
195 {
196    stb_easy_font_spacing_val = spacing;
197 }
198 
stb_easy_font_print(float x,float y,char * text,unsigned char color[4],void * vertex_buffer,int vbuf_size)199 static int stb_easy_font_print(float x, float y, char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size)
200 {
201     char *vbuf = (char *) vertex_buffer;
202     float start_x = x;
203     int offset = 0;
204 
205     stb_easy_font_color c = { 255,255,255,255 }; // use structure copying to avoid needing depending on memcpy()
206     if (color) { c.c[0] = color[0]; c.c[1] = color[1]; c.c[2] = color[2]; c.c[3] = color[3]; }
207 
208     while (*text && offset < vbuf_size) {
209         if (*text == '\n') {
210             y += 12;
211             x = start_x;
212         } else {
213             unsigned char advance = stb_easy_font_charinfo[*text-32].advance;
214             float y_ch = advance & 16 ? y+1 : y;
215             int h_seg, v_seg, num_h, num_v;
216             h_seg = stb_easy_font_charinfo[*text-32  ].h_seg;
217             v_seg = stb_easy_font_charinfo[*text-32  ].v_seg;
218             num_h = stb_easy_font_charinfo[*text-32+1].h_seg - h_seg;
219             num_v = stb_easy_font_charinfo[*text-32+1].v_seg - v_seg;
220             offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_hseg[h_seg], num_h, 0, c, vbuf, vbuf_size, offset);
221             offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_vseg[v_seg], num_v, 1, c, vbuf, vbuf_size, offset);
222             x += advance & 15;
223             x += stb_easy_font_spacing_val;
224         }
225         ++text;
226     }
227     return (unsigned) offset/64;
228 }
229 
stb_easy_font_width(char * text)230 static int stb_easy_font_width(char *text)
231 {
232     float len = 0;
233     float max_len = 0;
234     while (*text) {
235         if (*text == '\n') {
236             if (len > max_len) max_len = len;
237             len = 0;
238         } else {
239             len += stb_easy_font_charinfo[*text-32].advance & 15;
240             len += stb_easy_font_spacing_val;
241         }
242         ++text;
243     }
244     if (len > max_len) max_len = len;
245     return (int) ceil(max_len);
246 }
247 
stb_easy_font_height(char * text)248 static int stb_easy_font_height(char *text)
249 {
250     float y = 0;
251     int nonempty_line=0;
252     while (*text) {
253         if (*text == '\n') {
254             y += 12;
255             nonempty_line = 0;
256         } else {
257             nonempty_line = 1;
258         }
259         ++text;
260     }
261     return (int) ceil(y + (nonempty_line ? 12 : 0));
262 }
263 #endif
264 
265 /*
266 ------------------------------------------------------------------------------
267 This software is available under 2 licenses -- choose whichever you prefer.
268 ------------------------------------------------------------------------------
269 ALTERNATIVE A - MIT License
270 Copyright (c) 2017 Sean Barrett
271 Permission is hereby granted, free of charge, to any person obtaining a copy of
272 this software and associated documentation files (the "Software"), to deal in
273 the Software without restriction, including without limitation the rights to
274 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
275 of the Software, and to permit persons to whom the Software is furnished to do
276 so, subject to the following conditions:
277 The above copyright notice and this permission notice shall be included in all
278 copies or substantial portions of the Software.
279 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
280 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
281 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
282 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
283 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
284 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
285 SOFTWARE.
286 ------------------------------------------------------------------------------
287 ALTERNATIVE B - Public Domain (www.unlicense.org)
288 This is free and unencumbered software released into the public domain.
289 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
290 software, either in source code form or as a compiled binary, for any purpose,
291 commercial or non-commercial, and by any means.
292 In jurisdictions that recognize copyright laws, the author or authors of this
293 software dedicate any and all copyright interest in the software to the public
294 domain. We make this dedication for the benefit of the public at large and to
295 the detriment of our heirs and successors. We intend this dedication to be an
296 overt act of relinquishment in perpetuity of all present and future rights to
297 this software under copyright law.
298 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
299 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
300 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
301 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
302 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
303 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
304 ------------------------------------------------------------------------------
305 */
306