From a3e84e25dd6974688810fa66dc8152ef7add3b87 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 1 Feb 2015 01:49:17 -0800 Subject: [PATCH] added stb_easy_font.h --- README.md | 6 +- data/easy_font_raw.png | Bin 0 -> 645 bytes stb_easy_font.h | 220 ++++++++++++++++++++++++++++++++++++++++ tools/README.list | 32 +++--- tools/easy_font_maker.c | 211 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 452 insertions(+), 17 deletions(-) create mode 100644 data/easy_font_raw.png create mode 100644 stb_easy_font.h create mode 100644 tools/easy_font_maker.c diff --git a/README.md b/README.md index 8918d86..5f8e1f7 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,13 @@ library | lastest version | category | description **stb_textedit.h** | 1.5 | UI | guts of a text editor for games etc implementing them from scratch **stb_dxt.h** | 1.04 | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor **stb_perlin.h** | 0.2 | 3D graphics | revised Perlin noise (3D input, 1D output) -**stb_tilemap_editor.h** | 0.30 | games | embeddable tilemap editor -**stb_herringbone_wang_tile.h** | 0.6 | games | herringbone Wang tile map generator +**stb_easy_font.h** | 0.5 | 3D graphics | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc +**stb_tilemap_editor.h** | 0.30 | game development | embeddable tilemap editor +**stb_herringbone_wang_tile.h** | 0.6 | game development | herringbone Wang tile map generator **stb_c_lexer.h** | 0.06 | parsing | simplify writing parsers for C-like languages **stb_divide.h** | 0.91 | math | more useful 32-bit modulus e.g. "euclidean divide" **stb.h** | 2.24 | misc | helper functions for C, mostly redundant in C++; basically author's personal stuff +**stb_leakcheck.h** | 0.1 | misc | quick-and-dirty malloc/free leak-checking FAQ --- diff --git a/data/easy_font_raw.png b/data/easy_font_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..2f08148b4614413c1c975ab264ca563fdf667c65 GIT binary patch literal 645 zcmV;00($+4P)dL_t(|UhS5FYQr!LMDHp4|8E|o2WL&hWbGJiRCUf$ zY{`)?s-q7{A4XlE+q@aq`w+kGn&`JeMBR@DHueUS=)8LYGtsDfr|vv4(Bu9ac}tzY z2j~Pid+-f}c9Mx;I0Ir^(F{}YpnIgUhRPP+y~S(gUW5JS8hGbs@i?eVmxG< zJ&U8a3qQ>wGB?wcgM&3m^G!?mg2nQbyDTC%*XSClo@CL6^-_J4ML!?v%VtfoaY#^W znS)E8gA7`nI0*SZ(J1c-;$Xg7DEkJiEFwCKsm1k0O2VcY07-K1DonO=GB}YFGT?j@ zK58ut#5*G(gM{aV#rn#kAtP2*m88~rsW<17E1PM#de0a^AIOrMG=c2FU{NHj4V5(% zNiEtp4=!zMG3(}PB}4w0ttA4okW~Qg)M9OFQJN9_^K?xXt19&t@?u$bEW!ngXv<=X zrqZ&j9_V*aMQ f1)BOYi~B&Iu%ieWP969(00000NkvXXu0mjfRf{XR literal 0 HcmV?d00001 diff --git a/stb_easy_font.h b/stb_easy_font.h new file mode 100644 index 0000000..7b1cb26 --- /dev/null +++ b/stb_easy_font.h @@ -0,0 +1,220 @@ +// stb_easy_font.h - v0.5 - bitmap font for 3D rendering - public domain +// Sean Barrett, Feb 2015 +// +// Easy-to-deploy, +// reasonably compact, +// extremely inefficient performance-wise, +// crappy-looking, +// ASCII-only, +// bitmap font for use in 3D APIs. +// +// Intended for when you just want to get some text displaying +// in a 3D app as quickly as possible. +// +// Doesn't use any textures, instead builds characters out of quads. +// +// DOCUMENTATION: +// +// int stb_easy_font_width(char *text) +// +// Takes a string without newlines and returns the horizontal size. +// +// int stb_easy_font_print(float x, float y, +// char *text, unsigned char color[4], +// void *vertex_buffer, int vbuf_size) +// +// Takes a string (which can contain '\n') and fills out a +// vertex buffer with renderable data to draw the string. +// Output data assumes increasing x is rightwards, increasing y +// is downwards. +// +// The vertex data is divided into quads, i.e. there are four +// vertices in the vertex buffer for each quad. +// +// The vertices are stored in an interleaved format: +// +// x:float +// y:float +// z:float +// color:uint8[4] +// +// You can ignore z and color if you get them from elsewhere +// This format was chosen in the hopes it would make it +// easier for you to reuse existing buffer-drawing code. +// +// If you pass in NULL for color, it becomes 255,255,255,255. +// +// Returns the number of quads. +// +// If the buffer isn't large enough, it will truncate. +// Expect it to use an average of ~270 bytes per character. +// +// If your API doesn't draw quads, build a reusable index +// list that allows you to render quads as indexed triangles. +// +// void stb_easy_font_spacing(float spacing) +// +// Use positive values to expand the space between characters, +// and small negative values (no smaller than -1.5) to contract +// the space between characters. +// +// E.g. spacing = 1 adds one "pixel" of spacing between the +// characters. spacing = -1 is reasonable but feels a bit too +// compact to me; -0.5 is a reasonable compromise as long as +// you're scaling the font up. +// +// SAMPLE CODE: +// +// Here's sample code for old OpenGL; it's a lot more complicated +// to make work on modern APIs, and that's your problem. +// +#if 0 +void print_string(float x, float y, char *text, float r, float g, float b) +{ + static char buffer[99999]; // ~500 chars + int num_quads; + + num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer)); + + glColor3f(r,g,b); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 16, buffer); + glDrawArrays(GL_QUADS, 0, num_quads*4); + glDisableClientState(GL_VERTEX_ARRAY); +} +#endif + +#ifndef INCLUDE_STB_EASY_FONT_H +#define INCLUDE_STB_EASY_FONT_H + +#include + +struct { + unsigned char advance; + unsigned char h_seg; + unsigned char v_seg; +} stb_easy_font_charinfo[96] = { + { 5, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 }, + { 7, 3, 7 }, { 7, 6, 12 }, { 7, 8, 19 }, { 4, 16, 21 }, + { 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 }, + { 20, 23, 34 }, { 22, 23, 36 }, { 19, 24, 36 }, { 21, 25, 36 }, + { 6, 25, 39 }, { 6, 27, 43 }, { 6, 28, 45 }, { 6, 30, 49 }, + { 6, 33, 53 }, { 6, 34, 57 }, { 6, 40, 58 }, { 6, 46, 59 }, + { 6, 47, 62 }, { 6, 55, 64 }, { 19, 57, 68 }, { 20, 59, 68 }, + { 21, 61, 69 }, { 22, 66, 69 }, { 21, 68, 69 }, { 7, 73, 69 }, + { 9, 75, 74 }, { 6, 78, 81 }, { 6, 80, 85 }, { 6, 83, 90 }, + { 6, 85, 91 }, { 6, 87, 95 }, { 6, 90, 96 }, { 7, 92, 97 }, + { 6, 96,102 }, { 5, 97,106 }, { 6, 99,107 }, { 6,100,110 }, + { 6,100,115 }, { 7,101,116 }, { 6,101,121 }, { 6,101,125 }, + { 6,102,129 }, { 7,103,133 }, { 6,104,140 }, { 6,105,145 }, + { 7,107,149 }, { 6,108,151 }, { 7,109,155 }, { 7,109,160 }, + { 7,109,165 }, { 7,118,167 }, { 6,118,172 }, { 4,120,176 }, + { 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 }, + { 4,130,182 }, { 22,131,183 }, { 6,133,187 }, { 22,135,191 }, + { 6,137,192 }, { 22,139,196 }, { 5,144,197 }, { 22,147,198 }, + { 6,150,202 }, { 19,151,206 }, { 21,152,207 }, { 6,155,209 }, + { 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 }, + { 22,167,224 }, { 22,169,228 }, { 21,171,232 }, { 21,173,233 }, + { 5,178,233 }, { 22,179,234 }, { 23,180,238 }, { 23,180,243 }, + { 23,180,248 }, { 22,189,248 }, { 22,191,252 }, { 5,196,252 }, + { 3,203,252 }, { 5,203,253 }, { 22,210,253 }, { 0,214,253 }, +}; + +unsigned char stb_easy_font_hseg[214] = { + 97,37,69,84,28,51,2,18,10,49,98,41,65,25,81,105,33,9,97,1,97,37,37,36, + 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, + 98,8,25,33,65,81,10,50,17,65,97,25,33,25,49,9,65,20,68,1,65,25,49,41, + 11,105,13,101,76,10,50,10,50,98,11,99,10,98,11,50,99,11,50,11,99,8,57, + 58,3,99,99,107,10,10,11,10,99,11,5,100,41,65,57,41,65,9,17,81,97,3,107, + 9,97,1,97,33,25,9,25,41,100,41,26,82,42,98,27,83,42,98,26,51,82,8,41, + 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, + 26,82,41,25,33,82,26,49,73,35,90,17,81,41,65,57,41,65,25,81,90,114,20, + 84,73,57,41,49,25,33,65,81,9,97,1,97,25,33,65,81,57,33,25,41,25, +}; + +unsigned char stb_easy_font_vseg[253] = { + 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, + 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, + 26,66,3,8,8,15,19,21,90,58,26,18,66,18,105,89,28,74,17,8,73,57,26,21, + 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, + 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, + 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, + 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, + 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, + 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, + 20,8,8,28,18,58,89,58,26,21,89,73,89,29,20,8,8,30,7, +}; + +typedef struct +{ + unsigned char c[4]; +} stb_easy_font_color; + +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) +{ + int i,j; + for (i=0; i < num_segs; ++i) { + int len = segs[i] & 7; + x += (float) ((segs[i] >> 3) & 1); + if (len && offset+64 <= vbuf_size) { + float y0 = y + (float) (segs[i]>>4); + for (j=0; j < 4; ++j) { + * (float *) (vbuf+offset+0) = x + (j==1 || j==2 ? (vertical ? 1 : len) : 0); + * (float *) (vbuf+offset+4) = y0 + ( j >= 2 ? (vertical ? len : 1) : 0); + * (float *) (vbuf+offset+8) = 0.f; + * (stb_easy_font_color *) (vbuf+offset+12) = c; + offset += 16; + } + } + } + return offset; +} + +float stb_easy_font_spacing_val = 0; +static void stb_easy_font_spacing(float spacing) +{ + stb_easy_font_spacing_val = spacing; +} + +static int stb_easy_font_print(float x, float y, char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size) +{ + char *vbuf = (char *) vertex_buffer; + float start_x = x; + int offset = 0; + + stb_easy_font_color c = { 255,255,255,255 }; // use structure copying to avoid needing depending on memcpy() + if (color) { c.c[0] = color[0]; c.c[1] = color[1]; c.c[2] = color[2]; c.c[3] = color[3]; } + + while (*text && offset < vbuf_size) { + if (*text == '\n') { + y += 12; + x = start_x; + } else { + unsigned char advance = stb_easy_font_charinfo[*text-32].advance; + float y_ch = advance & 16 ? y+1 : y; + int h_seg, v_seg, num_h, num_v; + h_seg = stb_easy_font_charinfo[*text-32 ].h_seg; + v_seg = stb_easy_font_charinfo[*text-32 ].v_seg; + num_h = stb_easy_font_charinfo[*text-32+1].h_seg - h_seg; + num_v = stb_easy_font_charinfo[*text-32+1].v_seg - v_seg; + offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_hseg[h_seg], num_h, 0, c, vbuf, vbuf_size, offset); + offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_vseg[v_seg], num_v, 1, c, vbuf, vbuf_size, offset); + x += advance & 15; + x += stb_easy_font_spacing_val; + } + ++text; + } + return (unsigned) offset/64; +} + +static int stb_easy_font_width(char *text) +{ + int len = 0; + while (*text) { + len += stb_easy_font_charinfo[*text-32].advance & 15; + len += stb_easy_font_spacing_val; + ++text; + } + return len; +} +#endif diff --git a/tools/README.list b/tools/README.list index c53b0db..0f3639d 100644 --- a/tools/README.list +++ b/tools/README.list @@ -1,15 +1,17 @@ -stb_vorbis.c | audio | decode ogg vorbis files from file/memory to float/16-bit signed output -stb_image.h | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -stb_truetype.h | graphics | parse, decode, and rasterize characters from truetype fonts -stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP -stb_image_resize.h | graphics | resize images larger/smaller with good quality -stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality -stretchy_buffer.h | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ -stb_textedit.h | UI | guts of a text editor for games etc implementing them from scratch -stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor -stb_perlin.h | 3D graphics | revised Perlin noise (3D input, 1D output) -stb_tilemap_editor.h | games | embeddable tilemap editor -stb_herringbone_wang_tile.h | games | herringbone Wang tile map generator -stb_c_lexer.h | parsing | simplify writing parsers for C-like languages -stb_divide.h | math | more useful 32-bit modulus e.g. "euclidean divide" -stb.h | misc | helper functions for C, mostly redundant in C++; basically author's personal stuff +stb_vorbis.c | audio | decode ogg vorbis files from file/memory to float/16-bit signed output +stb_image.h | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC +stb_truetype.h | graphics | parse, decode, and rasterize characters from truetype fonts +stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP +stb_image_resize.h | graphics | resize images larger/smaller with good quality +stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality +stretchy_buffer.h | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ +stb_textedit.h | UI | guts of a text editor for games etc implementing them from scratch +stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor +stb_perlin.h | 3D graphics | revised Perlin noise (3D input, 1D output) +stb_easy_font.h | 3D graphics | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc +stb_tilemap_editor.h | game development | embeddable tilemap editor +stb_herringbone_wang_tile.h | game development | herringbone Wang tile map generator +stb_c_lexer.h | parsing | simplify writing parsers for C-like languages +stb_divide.h | math | more useful 32-bit modulus e.g. "euclidean divide" +stb.h | misc | helper functions for C, mostly redundant in C++; basically author's personal stuff +stb_leakcheck.h | misc | quick-and-dirty malloc/free leak-checking diff --git a/tools/easy_font_maker.c b/tools/easy_font_maker.c new file mode 100644 index 0000000..f1b4836 --- /dev/null +++ b/tools/easy_font_maker.c @@ -0,0 +1,211 @@ +// This program was used to encode the data for stb_simple_font.h + +#define STB_DEFINE +#include "stb.h" +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +int w,h; +uint8 *data; + +int last_x[2], last_y[2]; +int num_seg[2], non_empty; +#if 0 +typedef struct +{ + unsigned short first_segment; + unsigned char advance; +} chardata; + +typedef struct +{ + unsigned char x:4; + unsigned char y:4; + unsigned char len:3; + unsigned char dir:1; +} segment; + +segment *segments; + +void add_seg(int x, int y, int len, int horizontal) +{ + segment s; + s.x = x; + s.y = y; + s.len = len; + s.dir = horizontal; + assert(s.x == x); + assert(s.y == y); + assert(s.len == len); + stb_arr_push(segments, s); +} +#else +typedef struct +{ + unsigned char first_segment:8; + unsigned char first_v_segment:8; + unsigned char advance:5; + unsigned char voff:1; +} chardata; + +#define X_LIMIT 1 +#define LEN_LIMIT 7 + +typedef struct +{ + unsigned char dx:1; + unsigned char y:4; + unsigned char len:3; +} segment; + +segment *segments; +segment *vsegments; + +void add_seg(int x, int y, int len, int horizontal) +{ + segment s; + + while (x - last_x[horizontal] > X_LIMIT) { + add_seg(last_x[horizontal] + X_LIMIT, 0, 0, horizontal); + } + while (len > LEN_LIMIT) { + add_seg(x, y, LEN_LIMIT, horizontal); + len -= LEN_LIMIT; + x += LEN_LIMIT*horizontal; + y += LEN_LIMIT*!horizontal; + } + + s.dx = x - last_x[horizontal]; + s.y = y; + s.len = len; + non_empty += len != 0; + //assert(s.x == x); + assert(s.y == y); + assert(s.len == len); + ++num_seg[horizontal]; + if (horizontal) + stb_arr_push(segments, s); + else + stb_arr_push(vsegments, s); + last_x[horizontal] = x; +} + +void print_segments(segment *s) +{ + int i, hpos; + printf(" "); + hpos = 4; + for (i=0; i < stb_arr_len(s); ++i) { + // repack for portability + unsigned char seg = s[i].len + s[i].dx*8 + s[i].y*16; + hpos += printf("%d,", seg); + if (hpos > 72 && i+1 < stb_arr_len(s)) { + hpos = 4; + printf("\n "); + } + } + printf("\n"); +} + +#endif + +chardata charinfo[128]; + +int parse_char(int x, chardata *c, int offset) +{ + int start_x = x, end_x, top_y = 0, y; + + c->first_segment = stb_arr_len(segments); + c->first_v_segment = stb_arr_len(vsegments) - offset; + assert(c->first_segment == stb_arr_len(segments)); + assert(c->first_v_segment + offset == stb_arr_len(vsegments)); + + // find advance distance + end_x = x+1; + while (data[end_x*3] == 255) + ++end_x; + c->advance = end_x - start_x + 1; + + last_x[0] = last_x[1] = 0; + last_y[0] = last_y[1] = 0; + + for (y=2; y < h; ++y) { + for (x=start_x; x < end_x; ++x) { + if (data[y*3*w+x*3+1] < 255) { + top_y = y; + break; + } + } + if (top_y) + break; + } + c->voff = top_y > 2; + if (top_y > 2) + top_y = 3; + + for (x=start_x; x < end_x; ++x) { + int y; + for (y=2; y < h; ++y) { + if (data[y*3*w+x*3+1] < 255) { + if (data[y*3*w+x*3+0] == 255) { // red + int len=0; + while (y+len < h && data[(y+len)*3*w+x*3+0] == 255 && data[(y+len)*3*w+x*3+1] == 0) { + data[(y+len)*3*w+x*3+0] = 0; + ++len; + } + add_seg(x-start_x,y-top_y,len,0); + } + if (data[y*3*w+x*3+2] == 255) { // blue + int len=0; + while (x+len < end_x && data[y*3*w+(x+len)*3+2] == 255 && data[y*3*w+(x+len)*3+1] == 0) { + data[y*3*w+(x+len)*3+2] = 0; + ++len; + } + add_seg(x-start_x,y-top_y,len,1); + } + } + } + } + return end_x; +} + + +int main(int argc, char **argv) +{ + int c, x=0; + data = stbi_load("easy_font_raw.png", &w, &h, 0, 3); + for (c=32; c < 127; ++c) { + x = parse_char(x, &charinfo[c], 0); + printf("%3d -- %3d %3d\n", c, charinfo[c].first_segment, charinfo[c].first_v_segment); + } + printf("===\n"); + printf("%d %d %d\n", num_seg[0], num_seg[1], non_empty); + printf("%d\n", sizeof(segments[0]) * stb_arr_len(segments)); + printf("%d\n", sizeof(segments[0]) * stb_arr_len(segments) + sizeof(segments[0]) * stb_arr_len(vsegments) + sizeof(charinfo[32])*95); + + printf("struct {\n" + " unsigned char advance;\n" + " unsigned char h_seg;\n" + " unsigned char v_seg;\n" + "} stb_easy_font_charinfo[96] = {\n"); + charinfo[c].first_segment = stb_arr_len(segments); + charinfo[c].first_v_segment = stb_arr_len(vsegments); + for (c=32; c < 128; ++c) { + if ((c & 3) == 0) printf(" "); + printf("{ %2d,%3d,%3d },", + charinfo[c].advance + 16*charinfo[c].voff, + charinfo[c].first_segment, + charinfo[c].first_v_segment); + if ((c & 3) == 3) printf("\n"); else printf(" "); + } + printf("};\n\n"); + + printf("unsigned char stb_easy_font_hseg[%d] = {\n", stb_arr_len(segments)); + print_segments(segments); + printf("};\n\n"); + + printf("unsigned char stb_easy_font_vseg[%d] = {\n", stb_arr_len(vsegments)); + print_segments(vsegments); + printf("};\n"); + return 0; +}