浏览代码

added stb_easy_font.h

Sean Barrett 10 年之前
父节点
当前提交
a3e84e25dd
共有 5 个文件被更改,包括 452 次插入17 次删除
  1. 4 2
      README.md
  2. 二进制
      data/easy_font_raw.png
  3. 220 0
      stb_easy_font.h
  4. 17 15
      tools/README.list
  5. 211 0
      tools/easy_font_maker.c

+ 4 - 2
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
 ---

二进制
data/easy_font_raw.png


+ 220 - 0
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 <stdlib.h>
+
+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

+ 17 - 15
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

+ 211 - 0
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;
+}