Ver código fonte

Merge branch 'master' into working

Conflicts:
	stb_voxel_render.h
Sean Barrett 10 anos atrás
pai
commit
d821fd83f3

+ 49 - 26
README.md

@@ -1,28 +1,34 @@
+<!---   THIS FILE IS AUTOMATICALLY GENERATED, DO NOT CHANGE IT BY HAND   --->
+
 stb
 ===
 
 single-file public domain libraries for C/C++
 
-library    | lastest version | category | description
---------------------- | ---- | -------- | --------------------------------
-**stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output
-**stb_image.h** | 2.03 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
-**stb_truetype.h** | 1.03 | graphics | parse, decode, and rasterize characters from truetype fonts
-**stb_image_write.h** | 0.98 | graphics | image writing to disk: PNG, TGA, BMP
-**stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality
-**stb_rect_pack.h** | 0.05 | graphics | simple 2D rectangle packer with decent quality
-**stretchy_buffer.h** | 1.01 | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
-**stb_textedit.h** | 1.5 | UI | guts of a text editor for games etc implementing them from scratch
-**stb_voxel_render.h** | 0.80 | 3D&nbsp;graphics | Minecraft-esque voxel rendering "engine" with many more features
-**stb_dxt.h** | 1.04 | 3D&nbsp;graphics | Fabian "ryg" Giesen's real-time DXT compressor
-**stb_perlin.h** | 0.2 | 3D&nbsp;graphics | revised Perlin noise (3D input, 1D output)
-**stb_easy_font.h** | 0.5 | 3D&nbsp;graphics | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
-**stb_tilemap_editor.h** | 0.30 | game&nbsp;development | embeddable tilemap editor
-**stb_herringbone_wang_tile.h** | 0.6 | game&nbsp;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
+library    | lastest version | category | LoC | description
+--------------------- | ---- | -------- | --- | --------------------------------
+**stb_vorbis.c** | 1.05 | audio | 5445 | decode ogg vorbis files from file/memory to float/16-bit signed output
+**stb_image.h** | 2.06 | graphics | 6437 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
+**stb_truetype.h** | 1.06 | graphics | 2632 | parse, decode, and rasterize characters from truetype fonts
+**stb_image_write.h** | 0.98 | graphics | 730 | image writing to disk: PNG, TGA, BMP
+**stb_image_resize.h** | 0.90 | graphics | 2585 | resize images larger/smaller with good quality
+**stb_rect_pack.h** | 0.06 | graphics | 560 | simple 2D rectangle packer with decent quality
+**stretchy_buffer.h** | 1.02 | utility | 210 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
+**stb_textedit.h** | 1.6 | UI | 1290 | guts of a text editor for games etc implementing them from scratch
+**stb_voxel_render.h** | 0.81 | 3D&nbsp;graphics | 3644 | Minecraft-esque voxel rendering "engine" with many more features
+**stb_dxt.h** | 1.04 | 3D&nbsp;graphics | 624 | Fabian "ryg" Giesen's real-time DXT compressor
+**stb_perlin.h** | 0.2 | 3D&nbsp;graphics | 175 | revised Perlin noise (3D input, 1D output)
+**stb_easy_font.h** | 0.5 | 3D&nbsp;graphics | 220 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
+**stb_tilemap_editor.h** | 0.35 | game&nbsp;dev | 4120 | embeddable tilemap editor
+**stb_herringbone_wa...** | 0.6 | game&nbsp;dev | 1217 | herringbone Wang tile map generator
+**stb_c_lexer.h** | 0.06 | parsing | 809 | simplify writing parsers for C-like languages
+**stb_divide.h** | 0.91 | math | 373 | more useful 32-bit modulus e.g. "euclidean divide"
+**stb.h** | 2.24 | misc | 14086 | helper functions for C, mostly redundant in C++; basically author's personal stuff
+**stb_leakcheck.h** | 0.2 | misc | 117 | quick-and-dirty malloc/free leak-checking
+
+Total libraries: 18  
+Total lines of C code: 45274
+
 
 FAQ
 ---
@@ -45,6 +51,17 @@ attribution requirement). They may be less featureful, slower,
 and/or use more memory. If you're already using an equivalent
 library, there's probably no good reason to switch.
 
+#### Why do you list "lines of code"? It's a terrible metric.
+
+Just to give you some idea of the internal complexity of the library,
+to help you manage your expectations, or to let you know what you're
+getting into. While not all the libraries are written in the same
+style, they're certainly similar styles, and so comparisons between
+the libraries are probably still meaningful.
+
+Note though that the lines do include both the implementation, the
+part that corresponds to a header file, and the documentation.
+
 #### Why single-file headers?
 
 Windows doesn't have standard directories where libraries
@@ -52,12 +69,21 @@ live. That makes deploying libraries in Windows a lot more
 painful than open source developers on Unix-derivates generally
 realize. (It also makes library dependencies a lot worse in Windows.)
 
+There's also a common problem in Windows where a library was built
+against a different version of the runtime library, which causes
+link conflicts and confusion. Shipping the libs as headers means
+you normally just compile them straight into your project without
+making libraries, thus sidestepping that problem.
+
 Making them a single file makes it very easy to just
 drop them into a project that needs them. (Of course you can
 still put them in a proper shared library tree if you want.)
 
+Why not two files, one a header and one an implementation?
 The difference between 10 files and 9 files is not a big deal,
 but the difference between 2 files and 1 file is a big deal.
+You don't need to zip or tar the files up, you don't have to
+remember to attach *two* files, etc.
 
 #### Why "stb"? Is this something to do with Set-Top Boxes?
 
@@ -83,12 +109,9 @@ Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
 
 #### Why public domain?
 
-Because more people will use it. Because it's not viral, people
-are not obligated to give back, so you could argue that it hurts
-the *development* of it, and then because it doesn't develop as
-well it's not as good, and then because it's not as good, in the
-long run maybe fewer people will use it. I have total respect for
-that opinion, but I just don't believe it myself for most software.
+I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons.
+Some of them are listed here:
+https://github.com/nothings/stb/blob/master/docs/why_public_domain.md
 
 #### Why C?
 

+ 116 - 0
docs/why_public_domain.md

@@ -0,0 +1,116 @@
+My collected rationales for placing these libraries
+in the public domain:
+
+1. Public domain vs. viral licenses
+
+  Why is this library public domain?
+  Because more people will use it. Because it's not viral, people are
+  not obligated to give back, so you could argue that it hurts the
+  development of it, and then because it doesn't develop as well it's
+  not as good, and then because it's not as good, in the long run
+  maybe fewer people will use it. I have total respect for that
+  opinion, but I just don't believe it myself for most software.
+
+2. Public domain vs. attribution-required licenses
+
+  The primary difference between public domain and, say, a Creative Commons
+  commercial / non-share-alike / attribution license is solely the
+  requirement for attribution. (Similarly the BSD license and such.)
+  While I would *appreciate* acknowledgement and attribution, I believe
+  that it is foolish to place a legal encumberment (i.e. a license) on
+  the software *solely* to get attribution.
+
+  In other words, I'm arguing that PD is superior to the BSD license and
+  the Creative Commons 'Attribution' license. If the license offers
+  anything besides attribution -- as does, e.g., CC NonCommercial-ShareAlike,
+  or the GPL -- that's a separate discussion.
+
+3. Other aspects of BSD-style licenses besides attribution
+
+  Permissive licenses like zlib and BSD license are perfectly reasonable
+  in their requirements, but they are very wordy and
+  have only two benefits over public domain: legally-mandated
+  attribution and liability-control. I do not believe these
+  are worth the excessive verbosity and user-unfriendliness
+  these licenses induce, especially in the single-file
+  case where those licenses tend to be at the top of
+  the file, the first thing you see.
+
+  To the specific points, I have had no trouble receiving
+  attribution for my libraries; liability in the face of
+  no explicit disclaimer of liability is an open question,
+  but one I have a lot of difficulty imagining there being
+  any actual doubt about in court. Sometimes I explicitly
+  note in my libraries that I make no guarantees about them
+  being fit for purpose, but it's pretty absurd to do this;
+  as a whole, it comes across as "here is a library to decode
+  vorbis audio files, but it may not actually work and if
+  you have problems it's not my fault, but also please
+  report bugs so I can fix them"--so dumb!
+
+4. full discussion from stb_howto.txt on what YOU should do for YOUR libs
+
+```
+EASY-TO-COMPLY LICENSE
+
+I make my libraries public domain. You don't have to.
+But my goal in releasing stb-style libraries is to
+reduce friction for potential users as much as
+possible. That means:
+
+  a. easy to build (what this file is mostly about)
+  b. easy to invoke (which requires good API design)
+  c. easy to deploy (which is about licensing)
+
+I choose to place all my libraries in the public
+domain, abjuring copyright, rather than license
+the libraries. This has some benefits and some
+drawbacks.
+
+Any license which is "viral" to modifications
+causes worries for lawyers, even if their programmers
+aren't modifying it.
+
+Any license which requires crediting in documentation
+adds friction which can add up. Valve used to have
+a page with a list of all of these on their web site,
+and it was insane, and obviously nobody ever looked
+at it so why would you care whether your credit appeared
+there?
+
+Permissive licenses like zlib and BSD license are
+perfectly reasonable, but they are very wordy and
+have only two benefits over public domain: legally-mandated
+attribution and liability-control. I do not believe these
+are worth the excessive verbosity and user-unfriendliness
+these licenses induce, especially in the single-file
+case where those licenses tend to be at the top of
+the file, the first thing you see. (To the specific
+points, I have had no trouble receiving attribution
+for my libraries; liability in the face of no explicit
+disclaimer of liability is an open question.)
+
+However, public domain has frictions of its own, because
+public domain declarations aren't necessary recognized
+in the USA and some other locations. For that reason,
+I recommend a declaration along these lines:
+
+// This software is in the public domain. Where that dedication is not
+// recognized, you are granted a perpetual, irrevocable license to copy
+// and modify this file as you see fit.
+
+I typically place this declaration at the end of the initial
+comment block of the file and just say 'public domain'
+at the top.
+
+I have had people say they couldn't use one of my
+libraries because it was only "public domain" and didn't
+have the additional fallback clause, who asked if
+I could dual-license it under a traditional license.
+
+My answer: they can create a derivative work by
+modifying one character, and then license that however
+they like. (Indeed, *adding* the zlib or BSD license
+would be such a modification!) Unfortunately, their
+lawyers reportedly didn't like that answer. :(
+```

+ 1 - 1
stb.h

@@ -5255,7 +5255,7 @@ int stb_fullpath(char *abs, int abs_size, char *rel)
    #ifdef _MSC_VER
    return _fullpath(abs, rel, abs_size) != NULL;
    #else
-   if (abs[0] == '/' || abs[0] == '~') {
+   if (rel[0] == '/' || rel[0] == '~') {
       if ((int) strlen(rel) >= abs_size)
          return 0;
       strcpy(abs,rel);

+ 29 - 18
stb_image.h

@@ -1,4 +1,4 @@
-/* stb_image - v2.03 - public domain image loader - http://nothings.org/stb_image.h
+/* stb_image - v2.06 - public domain image loader - http://nothings.org/stb_image.h
                                      no warranty implied; use at your own risk
 
    Do this:
@@ -143,6 +143,9 @@
 
 
    Latest revision history:
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
       2.03  (2015-04-12) additional corruption checking
                          stbi_set_flip_vertically_on_load
                          fix NEON support; fix mingw support
@@ -159,8 +162,6 @@
       1.47  (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
                          optimize PNG
                          fix bug in interlaced PNG with user-specified channel count
-      1.46  (2014-08-26) fix broken tRNS chunk in non-paletted PNG
-      1.45  (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc
 
    See end of file for full revision history.
 
@@ -633,11 +634,14 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
 #endif
 
 // x86/x64 detection
-#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
 #define STBI__X86_TARGET
 #endif
 
-#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// NOTE: not clear do we actually need this for the 64-bit path?
 // gcc doesn't support sse2 intrinsics unless you compile with -msse2,
 // (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
 // this is just broken and gcc are jerks for not fixing it properly
@@ -646,6 +650,8 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
 #endif
 
 #if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
 // 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
 // Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
 // As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
@@ -1640,7 +1646,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
 
    sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
    k = stbi_lrot(j->code_buffer, n);
-   STBI_ASSERT(n >= 0 && n < sizeof(stbi__bmask)/sizeof(*stbi__bmask));
+   STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
    j->code_buffer = k & ~stbi__bmask[n];
    k &= stbi__bmask[n];
    j->code_bits -= n;
@@ -1846,8 +1852,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
                   if (r)
                      j->eob_run += stbi__jpeg_get_bits(j, r);
                   r = 64; // force end of block
-               } else
-                  r = 16; // r=15 is the code for 16 0s
+               } else {
+                  // r=15 s=0 should write 16 0s, so we just do
+                  // a run of 15 0s and then write s (which is 0),
+                  // so we don't have to do anything special here
+               }
             } else {
                if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
                // sign bit
@@ -1859,7 +1868,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
 
             // advance by r
             while (k <= j->spec_end) {
-               short *p = &data[stbi__jpeg_dezigzag[k]];
+               short *p = &data[stbi__jpeg_dezigzag[k++]];
                if (*p != 0) {
                   if (stbi__jpeg_get_bit(j))
                      if ((*p & bit)==0) {
@@ -1868,15 +1877,12 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
                         else
                            *p -= bit;
                      }
-                  ++k;
                } else {
                   if (r == 0) {
-                     if (s)
-                        data[stbi__jpeg_dezigzag[k++]] = (short) s;
+                     *p = (short) s;
                      break;
                   }
                   --r;
-                  ++k;
                }
             }
          } while (k <= j->spec_end);
@@ -5134,7 +5140,8 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
          p = out+channel;
          if (channel >= channelCount) {
             // Fill this channel with default data.
-            for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4;
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = (channel == 3 ? 255 : 0);
          } else {
             // Read the RLE data.
             count = 0;
@@ -5180,11 +5187,12 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
          p = out + channel;
          if (channel > channelCount) {
             // Fill this channel with default data.
-            for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4;
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = channel == 3 ? 255 : 0;
          } else {
             // Read the data.
-            for (i = 0; i < pixelCount; i++)
-               *p = stbi__get8(s), p += 4;
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = stbi__get8(s);
          }
       }
    }
@@ -5194,7 +5202,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
       if (out == NULL) return out; // stbi__convert_format frees input on failure
    }
 
-   if (comp) *comp = channelCount;
+   if (comp) *comp = 4;
    *y = h;
    *x = w;
 
@@ -6287,6 +6295,9 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
 
 /*
    revision history:
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
       2.03  (2015-04-12) extra corruption checking (mmozeiko)
                          stbi_set_flip_vertically_on_load (nguillemot)
                          fix NEON support; fix mingw support

+ 2 - 2
stb_leakcheck.h

@@ -1,4 +1,4 @@
-// stb_leakcheck.h - v0.1 - quick & dirty malloc leak-checking - public domain
+// stb_leakcheck.h - v0.2 - quick & dirty malloc leak-checking - public domain
 
 #ifdef STB_LEAKCHECK_IMPLEMENTATION
 #undef STB_LEAKCHECK_IMPLEMENTATION // don't implenment more than once
@@ -27,7 +27,7 @@ static stb_leakcheck_malloc_info *mi_head;
 
 void *stb_leakcheck_malloc(size_t sz, char *file, int line)
 {
-   stb_leakcheck_malloc_info *mi = malloc(sz + sizeof(*mi));
+   stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
    if (mi == NULL) return mi;
    mi->file = file;
    mi->line = line;

+ 17 - 3
stb_rect_pack.h

@@ -1,4 +1,4 @@
-// stb_rect_pack.h - v0.05 - public domain - rectangle packing
+// stb_rect_pack.h - v0.06 - public domain - rectangle packing
 // Sean Barrett 2014
 //
 // Useful for e.g. packing rectangular textures into an atlas.
@@ -13,6 +13,7 @@
 // More docs to come.
 //
 // No memory allocations; uses qsort() and assert() from stdlib.
+// Can override those by defining STBRP_SORT and STBRP_ASSERT.
 //
 // This library currently uses the Skyline Bottom-Left algorithm.
 //
@@ -20,8 +21,18 @@
 // implement them to the same API, but with a different init
 // function.
 //
+// Credits
+//
+//  Library
+//    Sean Barrett
+//  Minor features
+//    Martins Mozeiko
+//  Bugfixes / warning fixes
+//    [your name could be here]
+//
 // Version history:
 //
+//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort
 //     0.05:  added STBRP_ASSERT to allow replacing assert
 //     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
 //     0.01:  initial release
@@ -169,7 +180,10 @@ struct stbrp_context
 //
 
 #ifdef STB_RECT_PACK_IMPLEMENTATION
+#ifndef STBRP_SORT
 #include <stdlib.h>
+#define STBRP_SORT qsort
+#endif
 
 #ifndef STBRP_ASSERT
 #include <assert.h>
@@ -524,7 +538,7 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
    }
 
    // sort according to heuristic
-   qsort(rects, num_rects, sizeof(rects[0]), rect_height_compare);
+   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
 
    for (i=0; i < num_rects; ++i) {
       stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
@@ -537,7 +551,7 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
    }
 
    // unsort
-   qsort(rects, num_rects, sizeof(rects[0]), rect_original_order);
+   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
 
    // set was_packed flags
    for (i=0; i < num_rects; ++i)

+ 14 - 8
stb_textedit.h

@@ -1,4 +1,4 @@
-// stb_textedit.h - v1.5  - public domain - Sean Barrett
+// stb_textedit.h - v1.6  - public domain - Sean Barrett
 // Development of this library was sponsored by RAD Game Tools
 //
 // This C header file implements the guts of a multi-line text-editing
@@ -24,12 +24,14 @@
 //
 // DEPENDENCIES
 //
-// Uses the C runtime function 'memmove'. Uses no other functions.
-// Performs no runtime allocations.
+// Uses the C runtime function 'memmove', which you can override
+// by defining STB_TEXTEDIT_memmove before the implementation.
+// Uses no other functions. Performs no runtime allocations.
 //
 //
 // VERSION HISTORY
 //
+//   1.6  (2015-04-15) allow STB_TEXTEDIT_memmove
 //   1.5  (2014-09-10) add support for secondary keys for OS X
 //   1.4  (2014-08-17) fix signed/unsigned warnings
 //   1.3  (2014-06-19) fix mouse clicking to round to nearest char boundary
@@ -45,6 +47,7 @@
 //   Ulf Winklemann: move-by-word in 1.1
 //   Scott Graham: mouse selection bugfix in 1.3
 //   Fabian Giesen: secondary key inputs in 1.5
+//   Martins Mozeiko: STB_TEXTEDIT_memmove
 //
 // USAGE
 //
@@ -358,7 +361,10 @@ typedef struct
 // included just the "header" portion
 #ifdef STB_TEXTEDIT_IMPLEMENTATION
 
-#include <string.h> // memmove
+#ifndef STB_TEXTEDIT_memmove
+#include <string.h>
+#define STB_TEXTEDIT_memmove memmove
+#endif
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1038,13 +1044,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
          int n = state->undo_rec[0].insert_length, i;
          // delete n characters from all other records
          state->undo_char_point = state->undo_char_point - (short) n;  // vsnet05
-         memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
+         STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
          for (i=0; i < state->undo_point; ++i)
             if (state->undo_rec[i].char_storage >= 0)
                state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it
       }
       --state->undo_point;
-      memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
+      STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
    }
 }
 
@@ -1062,13 +1068,13 @@ static void stb_textedit_discard_redo(StbUndoState *state)
          int n = state->undo_rec[k].insert_length, i;
          // delete n characters from all other records
          state->redo_char_point = state->redo_char_point + (short) n; // vsnet05
-         memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
+         STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
          for (i=state->redo_point; i < k; ++i)
             if (state->undo_rec[i].char_storage >= 0)
                state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05
       }
       ++state->redo_point;
-      memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
+      STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
    }
 }
 

+ 33 - 10
stb_tilemap_editor.h

@@ -1,4 +1,4 @@
-// stb_tilemap_editor.h - v0.30 - Sean Barrett - http://nothings.org/stb
+// stb_tilemap_editor.h - v0.35 - Sean Barrett - http://nothings.org/stb
 // placed in the public domain - not copyrighted - first released 2014-09
 //
 // Embeddable tilemap editor for C/C++
@@ -275,6 +275,10 @@
 //   either approach allows cut&pasting between levels.)
 //
 // REVISION HISTORY
+//   0.35  layername button changes
+//          - layername buttons grow with the layer panel
+//          - fix stbte_create_map being declared as stbte_create
+//          - fix declaration of stbte_create_map
 //   0.30  properties release
 //          - properties panel for editing user-defined "object" properties
 //          - can link each tile to one other tile
@@ -296,11 +300,16 @@
 //   Support STBTE_HITTEST_TILE above
 //  ?Cancel drags by clicking other button? - may be fixed
 //   Finish support for toolbar at side
-//   Layer name buttons grow to fill box
 //
 // CREDITS
 //
-//   Written by Sean Barrett, September & October 2014.
+//
+//   Main editor & features
+//      Sean Barrett
+//   Additional features:
+//      Josh Huelsman
+//   Bugfixes:
+//      [this could be you!]
 //
 // LICENSE
 //
@@ -339,7 +348,7 @@ enum
 // creation
 //
 
-extern stbte_tilemap *stbte_create(int map_x, int map_y, int map_layers, int spacing_x, int spacing_y, int max_tiles);
+extern stbte_tilemap *stbte_create_map(int map_x, int map_y, int map_layers, int spacing_x, int spacing_y, int max_tiles);
 // create an editable tilemap
 //   map_x      : dimensions of map horizontally (user can change this in editor), <= STBTE_MAX_TILEMAP_X
 //   map_y      : dimensions of map vertically (user can change this in editor)    <= STBTE_MAX_TILEMAP_Y
@@ -352,7 +361,7 @@ extern stbte_tilemap *stbte_create(int map_x, int map_y, int map_layers, int spa
 
 extern void stbte_define_tile(stbte_tilemap *tm, unsigned short id, unsigned int layermask, const char * category);
 // call this repeatedly for each tile to install the tile definitions into the editable tilemap
-//   tm        : tilemap created by stbte_create
+//   tm        : tilemap created by stbte_create_map
 //   id        : unique identifier for each tile, 0 <= id < 32768
 //   layermask : bitmask of which layers tile is allowed on: 1 = layer 0, 255 = layers 0..7
 //               (note that onscreen, the editor numbers the layers from 1 not 0)
@@ -938,6 +947,7 @@ struct stbte_tilemap
     int tileinfo_dirty;
     stbte__layer layerinfo[STBTE_MAX_LAYERS];
     int has_layer_names;
+    int layername_width;
     int layer_scroll;
     int propmode;
     int solo_layer;
@@ -1016,6 +1026,7 @@ stbte_tilemap *stbte_create_map(int map_x, int map_y, int map_layers, int spacin
    tm->layer_scroll = 0;
    tm->propmode = 0;
    tm->has_layer_names = 0;
+   tm->layername_width = 0;
    tm->undo_available_valid = 0;
 
    for (i=0; i < tm->num_layers; ++i) {
@@ -1088,12 +1099,17 @@ void stbte_define_tile(stbte_tilemap *tm, unsigned short id, unsigned int layerm
    tm->tileinfo_dirty = 1;
 }
 
+static int stbte__text_width(const char *str);
+
 void stbte_set_layername(stbte_tilemap *tm, int layer, const char *layername)
 {
    STBTE_ASSERT(layer >= 0 && layer < tm->num_layers);
    if (layer >= 0 && layer < tm->num_layers) {
+      int width;
       tm->layerinfo[layer].name = layername;
       tm->has_layer_names = 1;
+      width = stbte__text_width(layername);
+      tm->layername_width = (width > tm->layername_width ? width : tm->layername_width);
    }
 }
 
@@ -3382,14 +3398,21 @@ static void stbte__info(stbte_tilemap *tm, int x0, int y0, int w, int h)
 
 static void stbte__layers(stbte_tilemap *tm, int x0, int y0, int w, int h)
 {
-   int i, y, n;
-   int x1 = x0+w;
-   int y1 = y0+h;
-   int xoff = tm->has_layer_names ? 50 : 20;
    static char *propmodes[3] = {
       "default", "always", "never"
    };
    int num_rows;
+   int i, y, n;
+   int x1 = x0+w;
+   int y1 = y0+h;
+   int xoff = 20;
+   
+   if (tm->has_layer_names) {
+      int side = stbte__ui.panel[STBTE__panel_layers].side;
+      xoff = stbte__region[side].width - 42;
+      xoff = (xoff < tm->layername_width + 10 ? xoff : tm->layername_width + 10);
+   }
+
    x0 += 2;
    y0 += 5;
    if (!tm->has_layer_names) {
@@ -3427,7 +3450,7 @@ static void stbte__layers(stbte_tilemap *tm, int x0, int y0, int w, int h)
    n = stbte__text_width("prop:")+2;
    stbte__draw_text(x0,y+2, "prop:", w, STBTE__TEXTCOLOR(STBTE__cpanel));
    i = w - n - 4;
-   if (i > 45) i = 45;
+   if (i > 50) i = 50;
    if (stbte__button(STBTE__clayer_button, propmodes[tm->propmode], x0+n,y,0,i, STBTE__ID(STBTE__layer,256), 0,0))
       tm->propmode = (tm->propmode+1)%3;
 #endif

+ 521 - 52
stb_truetype.h

@@ -1,4 +1,4 @@
-// stb_truetype.h - v1.03 - public domain
+// stb_truetype.h - v1.06 - public domain
 // authored from 2009-2014 by Sean Barrett / RAD Game Tools
 //
 //   This library processes TrueType files:
@@ -38,12 +38,18 @@
 //       Cap Petschulat
 //       Omar Cornut
 //       github:aloucks
+//       Peter LaValle
 //
 //   Misc other:
 //       Ryan Gordon
 //
 // VERSION HISTORY
 //
+//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
+//                     also more precise AA rasterizer, except if shapes overlap
+//                     remove need for STBTT_sort
+//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
+//   1.04 (2015-04-15) typo in example
 //   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
 //   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
 //   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
@@ -117,6 +123,15 @@
 //           stbtt_GetFontVMetrics()
 //           stbtt_GetCodepointKernAdvance()
 //
+//   Starting with version 1.06, the rasterizer was replaced with a new,
+//   faster and generally-more-precise rasterizer. The new rasterizer more
+//   accurately measures pixel coverage for anti-aliasing, except in the case
+//   where multiple shapes overlap, in which case it overestimates the AA pixel
+//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
+//   this turns out to be a problem, you can re-enable the old rasterizer with
+//        #define STBTT_RASTERIZER_VERSION 1
+//   which will incur about a 15% speed hit.
+//
 // ADDITIONAL DOCUMENTATION
 //
 //   Immediately after this block comment are a series of sample programs.
@@ -216,7 +231,15 @@
 //   Baked bitmap interface              70 LOC  /
 //   Font name matching & access        150 LOC  ---- 150 
 //   C runtime library abstraction       60 LOC  ----  60
-
+//
+//
+// PERFORMANCE MEASUREMENTS FOR 1.06:
+//
+//                      32-bit     64-bit
+//   Previous release:  8.83 s     7.68 s
+//   Pool allocations:  7.72 s     6.34 s
+//   Inline sort     :  6.54 s     5.65 s
+//   New rasterizer  :  5.63 s     5.00 s
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -239,7 +262,7 @@ GLuint ftex;
 void my_stbtt_initfont(void)
 {
    fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
-   stbtt_BakeFontBitmap(data,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
+   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
    // can free ttf_buffer at this point
    glGenTextures(1, &ftex);
    glBindTexture(GL_TEXTURE_2D, ftex);
@@ -327,7 +350,7 @@ int main(int arg, char **argv)
    stbtt_fontinfo font;
    int i,j,ascent,baseline,ch=0;
    float scale, xpos=2; // leave a little padding in case the character extends left
-   char *text = "Heljo World!";
+   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
 
    fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
    stbtt_InitFont(&font, buffer, 0);
@@ -385,18 +408,6 @@ int main(int arg, char **argv)
    typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
    typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
 
-   #ifdef STBTT_STATIC
-   #define STBTT_DEF static
-   #else
-   #define STBTT_DEF extern
-   #endif
-
-   // #define your own STBTT_sort() to override this to avoid qsort
-   #ifndef STBTT_sort
-   #include <stdlib.h>
-   #define STBTT_sort(data,num_items,item_size,compare_func)   qsort(data,num_items,item_size,compare_func)
-   #endif
-
    // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
    #ifndef STBTT_ifloor
    #include <math.h>
@@ -443,6 +454,12 @@ int main(int arg, char **argv)
 #ifndef __STB_INCLUDE_STB_TRUETYPE_H__
 #define __STB_INCLUDE_STB_TRUETYPE_H__
 
+#ifdef STBTT_STATIC
+#define STBTT_DEF static
+#else
+#define STBTT_DEF extern
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -899,6 +916,10 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC
 
 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
 
+#ifndef STBTT_RASTERIZER_VERSION
+#define STBTT_RASTERIZER_VERSION 2
+#endif
+
 //////////////////////////////////////////////////////////////////////////
 //
 // accessors to parse data from file
@@ -1547,42 +1568,129 @@ STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codep
    stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
 }
 
+//////////////////////////////////////////////////////////////////////////////
+//
+//  Rasterizer
+
+typedef struct stbtt__hheap_chunk
+{
+   struct stbtt__hheap_chunk *next;
+} stbtt__hheap_chunk;
+
+typedef struct stbtt__hheap
+{
+   struct stbtt__hheap_chunk *head;
+   void   *first_free;
+   int    num_remaining_in_head_chunk;
+} stbtt__hheap;
+
+static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
+{
+   if (hh->first_free) {
+      void *p = hh->first_free;
+      hh->first_free = * (void **) p;
+      return p;
+   } else {
+      if (hh->num_remaining_in_head_chunk == 0) {
+         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
+         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
+         if (c == NULL)
+            return NULL;
+         c->next = hh->head;
+         hh->head = c;
+         hh->num_remaining_in_head_chunk = count;
+      }
+      --hh->num_remaining_in_head_chunk;
+      return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk;
+   }
+}
+
+static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
+{
+   *(void **) p = hh->first_free;
+   hh->first_free = p;
+}
+
+static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
+{
+   stbtt__hheap_chunk *c = hh->head;
+   while (c) {
+      stbtt__hheap_chunk *n = c->next;
+      STBTT_free(c, userdata);
+      c = n;
+   }
+}
+
 typedef struct stbtt__edge {
    float x0,y0, x1,y1;
    int invert;
 } stbtt__edge;
 
+
 typedef struct stbtt__active_edge
 {
+   struct stbtt__active_edge *next;
+   #if STBTT_RASTERIZER_VERSION==1
    int x,dx;
    float ey;
-   struct stbtt__active_edge *next;
-   int valid;
+   int direction;
+   #elif STBTT_RASTERIZER_VERSION==2
+   float fx,fdx,fdy;
+   float direction;
+   float sy;
+   float ey;
+   #else
+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+   #endif
 } stbtt__active_edge;
 
-#define FIXSHIFT   10
-#define FIX        (1 << FIXSHIFT)
-#define FIXMASK    (FIX-1)
+#if STBTT_RASTERIZER_VERSION == 1
+#define STBTT_FIXSHIFT   10
+#define STBTT_FIX        (1 << STBTT_FIXSHIFT)
+#define STBTT_FIXMASK    (STBTT_FIX-1)
 
-static stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point, void *userdata)
+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
 {
-   stbtt__active_edge *z = (stbtt__active_edge *) STBTT_malloc(sizeof(*z), userdata); // @TODO: make a pool of these!!!
+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
-   STBTT_assert(e->y0 <= start_point);
    if (!z) return z;
-   // round dx down to avoid going too far
+   
+   // round dx down to avoid overshooting
    if (dxdy < 0)
-      z->dx = -STBTT_ifloor(FIX * -dxdy);
+      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
    else
-      z->dx = STBTT_ifloor(FIX * dxdy);
-   z->x = STBTT_ifloor(FIX * (e->x0 + dxdy * (start_point - e->y0)));
-   z->x -= off_x * FIX;
+      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);
+
+   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount
+   z->x -= off_x * STBTT_FIX;
+
    z->ey = e->y1;
    z->next = 0;
-   z->valid = e->invert ? 1 : -1;
+   z->direction = e->invert ? 1 : -1;
    return z;
 }
+#elif STBTT_RASTERIZER_VERSION == 2
+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
+{
+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
+   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+   //STBTT_assert(e->y0 <= start_point);
+   if (!z) return z;
+   z->fdx = dxdy;
+   z->fdy = (1/dxdy);
+   z->fx = e->x0 + dxdy * (start_point - e->y0);
+   z->fx -= off_x;
+   z->direction = e->invert ? 1.0f : -1.0f;
+   z->sy = e->y0;
+   z->ey = e->y1;
+   z->next = 0;
+   return z;
+}
+#else
+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
 
+#if STBTT_RASTERIZER_VERSION == 1
 // note: this routine clips fills that extend off the edges... ideally this
 // wouldn't happen, but it could happen if the truetype glyph bounding boxes
 // are wrong, or if the user supplies a too-small bitmap
@@ -1594,26 +1702,26 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac
    while (e) {
       if (w == 0) {
          // if we're currently at zero, we need to record the edge start point
-         x0 = e->x; w += e->valid;
+         x0 = e->x; w += e->direction;
       } else {
-         int x1 = e->x; w += e->valid;
+         int x1 = e->x; w += e->direction;
          // if we went to zero, we need to draw
          if (w == 0) {
-            int i = x0 >> FIXSHIFT;
-            int j = x1 >> FIXSHIFT;
+            int i = x0 >> STBTT_FIXSHIFT;
+            int j = x1 >> STBTT_FIXSHIFT;
 
             if (i < len && j >= 0) {
                if (i == j) {
                   // x0,x1 are the same pixel, so compute combined coverage
-                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> FIXSHIFT);
+                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
                } else {
                   if (i >= 0) // add antialiasing for x0
-                     scanline[i] = scanline[i] + (stbtt_uint8) (((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT);
+                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
                   else
                      i = -1; // clip
 
                   if (j < len) // add antialiasing for x1
-                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & FIXMASK) * max_weight) >> FIXSHIFT);
+                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
                   else
                      j = len; // clip
 
@@ -1630,6 +1738,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac
 
 static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
 {
+   stbtt__hheap hh = { 0 };
    stbtt__active_edge *active = NULL;
    int y,j=0;
    int max_weight = (255 / vsubsample);  // weight per vertical scanline
@@ -1657,9 +1766,9 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
             stbtt__active_edge * z = *step;
             if (z->ey <= scan_y) {
                *step = z->next; // delete from list
-               STBTT_assert(z->valid);
-               z->valid = 0;
-               STBTT_free(z, userdata);
+               STBTT_assert(z->direction);
+               z->direction = 0;
+               stbtt__hheap_free(&hh, z);
             } else {
                z->x += z->dx; // advance to position for current scanline
                step = &((*step)->next); // advance through list
@@ -1688,7 +1797,7 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
          // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
          while (e->y0 <= scan_y) {
             if (e->y1 > scan_y) {
-               stbtt__active_edge *z = new_active(e, off_x, scan_y, userdata);
+               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
                // find insertion point
                if (active == NULL)
                   active = z;
@@ -1719,24 +1828,377 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
       ++j;
    }
 
-   while (active) {
-      stbtt__active_edge *z = active;
-      active = active->next;
-      STBTT_free(z, userdata);
+   stbtt__hheap_cleanup(&hh, userdata);
+
+   if (scanline != scanline_data)
+      STBTT_free(scanline, userdata);
+}
+
+#elif STBTT_RASTERIZER_VERSION == 2
+
+// the edge passed in here does not cross the vertical line at x or the vertical line at x+1
+// (i.e. it has already been clipped to those)
+static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
+{
+   if (y0 == y1) return;
+   assert(y0 < y1);
+   assert(e->sy <= e->ey);
+   if (y0 > e->ey) return;
+   if (y1 < e->sy) return;
+   if (y0 < e->sy) {
+      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
+      y0 = e->sy;
+   }
+   if (y1 > e->ey) {
+      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
+      y1 = e->ey;
+   }
+
+   if (x0 == x)
+      assert(x1 <= x+1);
+   else if (x0 == x+1)
+      assert(x1 >= x);
+   else if (x0 <= x)
+      assert(x1 <= x);
+   else if (x0 >= x+1)
+      assert(x1 >= x+1);
+   else
+      assert(x1 >= x && x1 <= x+1);
+
+   if (x0 <= x && x1 <= x)
+      scanline[x] += e->direction * (y1-y0);
+   else if (x0 >= x+1 && x1 >= x+1)
+      ;
+   else {
+      assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
+      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
    }
+}
+
+static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
+{
+   float y_bottom = y_top+1;
+
+   while (e) {
+      // brute force every pixel
+
+      // compute intersection points with top & bottom
+      assert(e->ey >= y_top);
+
+      if (e->fdx == 0) {
+         float x0 = e->fx;
+         if (x0 < len) {
+            if (x0 >= 0) {
+               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
+               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
+            } else {
+               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
+            }
+         }
+      } else {
+         float x0 = e->fx;
+         float dx = e->fdx;
+         float xb = x0 + dx;
+         float x_top, x_bottom;
+         float y0,y1;
+         float dy = e->fdy;
+         assert(e->sy <= y_bottom && e->ey >= y_top);
+
+         // compute endpoints of line segment clipped to this scanline (if the
+         // line segment starts on this scanline. x0 is the intersection of the
+         // line with y_top, but that may be off the line segment.
+         if (e->sy > y_top) {
+            x_top = x0 + dx * (e->sy - y_top);
+            y0 = e->sy;
+         } else {
+            x_top = x0;
+            y0 = y_top;
+         }
+         if (e->ey < y_bottom) {
+            x_bottom = x0 + dx * (e->ey - y_top);
+            y1 = e->ey;
+         } else {
+            x_bottom = xb;
+            y1 = y_bottom;
+         }
+
+         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
+            // from here on, we don't have to range check x values
+
+            if ((int) x_top == (int) x_bottom) {
+               float height;
+               // simple case, only spans one pixel
+               int x = (int) x_top;
+               height = y1 - y0;
+               assert(x >= 0 && x < len);
+               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;
+               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
+            } else {
+               int x,x1,x2;
+               float y_crossing, step, sign, area;
+               // covers 2+ pixels
+               if (x_top > x_bottom) {
+                  // flip scanline vertically; signed area is the same
+                  float t;
+                  y0 = y_bottom - (y0 - y_top);
+                  y1 = y_bottom - (y1 - y_top);
+                  t = y0, y0 = y1, y1 = t;
+                  t = x_bottom, x_bottom = x_top, x_top = t;
+                  dx = -dx;
+                  dy = -dy;
+                  t = x0, x0 = xb, xb = t;
+               }
+
+               x1 = (int) x_top;
+               x2 = (int) x_bottom;
+               // compute intersection with y axis at x1+1
+               y_crossing = (x1+1 - x0) * dy + y_top;
+
+               sign = e->direction;
+               // area of the rectangle covered from y0..y_crossing
+               area = sign * (y_crossing-y0);
+               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
+               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
+
+               step = sign * dy;
+               for (x = x1+1; x < x2; ++x) {
+                  scanline[x] += area + step/2;
+                  area += step;
+               }
+               y_crossing += dy * (x2 - (x1+1));
+
+               assert(fabs(area) <= 1.01f);
+
+               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (y1-y_crossing);
+
+               scanline_fill[x2] += sign * (y1-y0);
+            }
+         } else {
+            // if edge goes outside of box we're drawing, we require
+            // clipping logic. since this does not match the intended use
+            // of this library, we use a different, very slow brute
+            // force implementation
+            int x;
+            for (x=0; x < len; ++x) {
+               // cases:
+               //
+               // there can be up to two intersections with the pixel. any intersection
+               // with left or right edges can be handled by splitting into two (or three)
+               // regions. intersections with top & bottom do not necessitate case-wise logic.
+               float y0,y1;
+               float y_cur = y_top, x_cur = x0;
+               // x = e->x + e->dx * (y-y_top)
+               // (y-y_top) = (x - e->x) / e->dx
+               // y = (x - e->x) / e->dx + y_top
+               y0 = (x - x0) / dx + y_top;
+               y1 = (x+1 - x0) / dx + y_top;
+
+               if (y0 < y1) {
+                  if (y0 > y_top && y0 < y_bottom) {
+                     stbtt__handle_clipped_edge(scanline,x,e, x_cur,y_cur, (float) x,y0);
+                     y_cur = y0;
+                     x_cur = (float) x;
+                  }
+                  if (y1 >= y_cur && y1 < y_bottom) {
+                     stbtt__handle_clipped_edge(scanline,x,e, x_cur,y_cur, (float) x+1,y1);
+                     y_cur = y1;
+                     x_cur = (float) x+1;
+                  }
+               } else {
+                  if (y1 >= y_cur && y1 < y_bottom) {
+                     stbtt__handle_clipped_edge(scanline,x,e, x_cur,y_cur, (float) x+1,y1);
+                     y_cur = y1;
+                     x_cur = (float) x+1;
+                  }
+                  if (y0 > y_top && y0 < y_bottom) {
+                     stbtt__handle_clipped_edge(scanline,x,e, x_cur,y_cur, (float) x,y0);
+                     y_cur = y0;
+                     x_cur = (float) x;
+                  }
+               }
+               stbtt__handle_clipped_edge(scanline,x,e, x_cur,y_cur, xb,y_bottom);
+            }
+         }
+      }
+      e = e->next;
+   }
+}
+
+// directly AA rasterize edges w/o supersampling
+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
+{
+   stbtt__hheap hh = { 0 };
+   stbtt__active_edge *active = NULL;
+   int y,j=0, i;
+   float scanline_data[129], *scanline, *scanline2;
+
+   if (result->w > 64)
+      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
+   else
+      scanline = scanline_data;
+
+   scanline2 = scanline + result->w;
+
+   y = off_y;
+   e[n].y0 = (float) (off_y + result->h) + 1;
+
+   while (j < result->h) {
+      // find center of pixel for this scanline
+      float scan_y_top    = y + 0.0f;
+      float scan_y_bottom = y + 1.0f;
+      stbtt__active_edge **step = &active;
+
+      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
+      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
+
+      // update all active edges;
+      // remove all active edges that terminate before the top of this scanline
+      while (*step) {
+         stbtt__active_edge * z = *step;
+         if (z->ey <= scan_y_top) {
+            *step = z->next; // delete from list
+            STBTT_assert(z->direction);
+            z->direction = 0;
+            stbtt__hheap_free(&hh, z);
+         } else {
+            step = &((*step)->next); // advance through list
+         }
+      }
+
+      // insert all edges that start before the bottom of this scanline
+      while (e->y0 <= scan_y_bottom) {
+         stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
+         assert(z->ey >= scan_y_top);
+         // insert at front
+         z->next = active;
+         active = z;
+         ++e;
+      }
+
+      // now process all active edges
+      if (active)
+         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
+
+      {
+         float sum = 0;
+         for (i=0; i < result->w; ++i) {
+            float k;
+            int m;
+            sum += scanline2[i];
+            k = scanline[i] + sum;
+            k = (float) fabs(k)*255 + 0.5f;
+            m = (int) k;
+            if (m > 255) m = 255;
+            result->pixels[j*result->stride + i] = (unsigned char) m;
+         }
+      }
+      // advance all the edges
+      step = &active;
+      while (*step) {
+         stbtt__active_edge *z = *step;
+         z->fx += z->fdx; // advance to position for current scanline
+         step = &((*step)->next); // advance through list
+      }
+
+      ++y;
+      ++j;
+   }
+
+   stbtt__hheap_cleanup(&hh, userdata);
 
    if (scanline != scanline_data)
       STBTT_free(scanline, userdata);
 }
+#else
+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
+
+#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)
 
-static int stbtt__edge_compare(const void *p, const void *q)
+static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
 {
-   stbtt__edge *a = (stbtt__edge *) p;
-   stbtt__edge *b = (stbtt__edge *) q;
+   int i,j;
+   for (i=1; i < n; ++i) {
+      stbtt__edge t = p[i], *a = &t;
+      j = i;
+      while (j > 0) {
+         stbtt__edge *b = &p[j-1];
+         int c = STBTT__COMPARE(a,b);
+         if (!c) break;
+         p[j] = p[j-1];
+         --j;
+      }
+      if (i != j)
+         p[j] = t;
+   }
+}
 
-   if (a->y0 < b->y0) return -1;
-   if (a->y0 > b->y0) return  1;
-   return 0;
+static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
+{
+   /* threshhold for transitioning to insertion sort */
+   while (n > 12) {
+      stbtt__edge t;
+      int c01,c12,c,m,i,j;
+
+      /* compute median of three */
+      m = n >> 1;
+      c01 = STBTT__COMPARE(&p[0],&p[m]);
+      c12 = STBTT__COMPARE(&p[m],&p[n-1]);
+      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
+      if (c01 != c12) {
+         /* otherwise, we'll need to swap something else to middle */
+         int z;
+         c = STBTT__COMPARE(&p[0],&p[n-1]);
+         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */
+         /* 0<mid && mid>n:  0>n => 0; 0<n => n */
+         z = (c == c12) ? 0 : n-1;
+         t = p[z];
+         p[z] = p[m];
+         p[m] = t;
+      }
+      /* now p[m] is the median-of-three */
+      /* swap it to the beginning so it won't move around */
+      t = p[0];
+      p[0] = p[m];
+      p[m] = t;
+
+      /* partition loop */
+      i=1;
+      j=n-1;
+      for(;;) {
+         /* handling of equality is crucial here */
+         /* for sentinels & efficiency with duplicates */
+         for (;;++i) {
+            if (!STBTT__COMPARE(&p[i], &p[0])) break;
+         }
+         for (;;--j) {
+            if (!STBTT__COMPARE(&p[0], &p[j])) break;
+         }
+         /* make sure we haven't crossed */
+         if (i >= j) break;
+         t = p[i];
+         p[i] = p[j];
+         p[j] = t;
+
+         ++i;
+         --j;
+      }
+      /* recurse on smaller side, iterate on larger */
+      if (j < (n-i)) {
+         stbtt__sort_edges_quicksort(p,j);
+         p = p+i;
+         n = n-i;
+      } else {
+         stbtt__sort_edges_quicksort(p+i, n-i);
+         n = j;
+      }
+   }
+}
+
+static void stbtt__sort_edges(stbtt__edge *p, int n)
+{
+   stbtt__sort_edges_quicksort(p, n);
+   stbtt__sort_edges_ins_sort(p, n);
 }
 
 typedef struct
@@ -1749,7 +2211,13 @@ static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcou
    float y_scale_inv = invert ? -scale_y : scale_y;
    stbtt__edge *e;
    int n,i,j,k,m;
+#if STBTT_RASTERIZER_VERSION == 1
    int vsubsample = result->h < 8 ? 15 : 5;
+#elif STBTT_RASTERIZER_VERSION == 2
+   int vsubsample = 1;
+#else
+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
+#endif
    // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
 
    // now we have to blow out the windings into explicit edge lists
@@ -1786,7 +2254,8 @@ static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcou
    }
 
    // now sort the edges by their highest point (should snap to integer, and then by x)
-   STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
+   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
+   stbtt__sort_edges(e, n);
 
    // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
    stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);

+ 4 - 4
stb_voxel_render.h

@@ -1,4 +1,4 @@
-// stb_voxel_render.h - v0.80 - Sean Barrett, 2015 - public domain
+// stb_voxel_render.h - v0.81 - Sean Barrett, 2015 - public domain
 //
 // This library helps render large-scale "voxel" worlds for games,
 // in this case, one with blocks that can have textures and that
@@ -190,7 +190,8 @@
 //
 // VERSION HISTORY
 //
-//   0.81   (2015-04-12)  added input.packed_compact to store rot, vheight & texlerp efficiently
+//   0.82   (2015-08-01)  added input.packed_compact to store rot, vheight & texlerp efficiently
+//   0.81   (2015-05-28)  fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
 //   0.80   (2015-04-11)  fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
 //                        change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
 //                                    that header defs don't need to see config vars
@@ -2813,7 +2814,6 @@ void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int fac
    }
 }
 
-#ifndef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
 // get opposite-facing normal & texgen for opposite face, used to map up-facing vheight data to down-facing data
 static unsigned char stbvox_reverse_face[STBVF_count] =
 {
@@ -2823,7 +2823,7 @@ static unsigned char stbvox_reverse_face[STBVF_count] =
          0,       0,       0,       0, STBVF_ne_d, STBVF_ne_d, STBVF_nd, STBVF_nu
 };
 
-
+#ifndef STBVOX_CONFIG_OPTIMIZED_VHEIGHT
 // render non-planar quads by splitting into two triangles, rendering each as a degenerate quad
 static void stbvox_make_12_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, unsigned char *ht)
 {

+ 3 - 2
stretchy_buffer.h

@@ -1,7 +1,8 @@
-// stretchy_buffer.h - v1.01 - public domain - nothings.org/stb
+// stretchy_buffer.h - v1.02 - public domain - nothings.org/stb
 // a vector<>-like dynamic array for C
 //
 // version history:
+//      1.02 -  compiles as C++, but untested
 //      1.01 -  added a "common uses" documentation section
 //      1.0  -  fixed bug in the version I posted prematurely
 //      0.9  -  rewrite to try to avoid strict-aliasing optimization
@@ -193,7 +194,7 @@ static void * stb__sbgrowf(void *arr, int increment, int itemsize)
    int dbl_cur = arr ? 2*stb__sbm(arr) : 0;
    int min_needed = stb_sb_count(arr) + increment;
    int m = dbl_cur > min_needed ? dbl_cur : min_needed;
-   int *p = realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2);
+   int *p = (int *) realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2);
    if (p) {
       if (!arr)
          p[1] = 0;

+ 5 - 1
tests/stb.dsp

@@ -66,7 +66,7 @@ LINK32=link.exe
 # PROP Ignore_Export_Lib 0
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FR /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c
 # SUBTRACT CPP /YX
 # ADD BASE RSC /l 0x409 /d "_DEBUG"
 # ADD RSC /l 0x409 /d "_DEBUG"
@@ -150,6 +150,10 @@ SOURCE=..\stb_vorbis.c
 # End Source File
 # Begin Source File
 
+SOURCE=..\stb_voxel_render.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\stretchy_buffer.h
 # End Source File
 # Begin Source File

+ 0 - 1
tests/stb_cpp.cpp

@@ -80,4 +80,3 @@ int main(int argc, char **argv)
    }
    return 0;
 }
-                     

+ 103 - 1
tests/test_cpp_compilation.cpp

@@ -8,7 +8,6 @@
 #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION
 #define STB_RECT_PACK_IMPLEMENTATION
 #define STB_VOXEL_RENDER_IMPLEMENTATION
-#define STBVOX_CONFIG_MODE 1
 
 #define STBI_MALLOC     my_malloc
 #define STBI_FREE       my_free
@@ -27,9 +26,112 @@ void my_free(void *) { }
 #include "stb_c_lexer.h"
 #include "stb_divide.h"
 #include "stb_herringbone_wang_tile.h"
+
+#define STBVOX_CONFIG_MODE 1
 #include "stb_voxel_render.h"
 
 #define STBTE_DRAW_RECT(x0,y0,x1,y1,color)      do ; while(0)
 #define STBTE_DRAW_TILE(x,y,id,highlight,data)  do ; while(0)
 #define STB_TILEMAP_EDITOR_IMPLEMENTATION
 #include "stb_tilemap_editor.h"
+
+#include "stb_easy_font.h"
+
+#define STB_LEAKCHECK_IMPLEMENTATION
+#include "stb_leakcheck.h"
+
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "stb_image_resize.h"
+
+#include "stretchy_buffer.h"
+
+
+
+////////////////////////////////////////////////////////////
+//
+// text edit
+
+#include <stdlib.h>
+#include <string.h> // memmove
+#include <ctype.h>  // isspace
+
+#define STB_TEXTEDIT_CHARTYPE   char
+#define STB_TEXTEDIT_STRING     text_control
+
+// get the base type
+#include "stb_textedit.h"
+
+// define our editor structure
+typedef struct
+{
+   char *string;
+   int stringlen;
+   STB_TexteditState state;
+} text_control;
+
+// define the functions we need
+void layout_func(StbTexteditRow *row, STB_TEXTEDIT_STRING *str, int start_i)
+{
+   int remaining_chars = str->stringlen - start_i;
+   row->num_chars = remaining_chars > 20 ? 20 : remaining_chars; // should do real word wrap here
+   row->x0 = 0;
+   row->x1 = 20; // need to account for actual size of characters
+   row->baseline_y_delta = 1.25;
+   row->ymin = -1;
+   row->ymax =  0;
+}
+
+int delete_chars(STB_TEXTEDIT_STRING *str, int pos, int num)
+{
+   memmove(&str->string[pos], &str->string[pos+num], str->stringlen - (pos+num));
+   str->stringlen -= num;
+   return 1; // always succeeds
+}
+
+int insert_chars(STB_TEXTEDIT_STRING *str, int pos, STB_TEXTEDIT_CHARTYPE *newtext, int num)
+{
+   str->string = (char *) realloc(str->string, str->stringlen + num);
+   memmove(&str->string[pos+num], &str->string[pos], str->stringlen - pos);
+   memcpy(&str->string[pos], newtext, num);
+   str->stringlen += num;
+   return 1; // always succeeds
+}
+
+// define all the #defines needed 
+
+#define KEYDOWN_BIT                    0x80000000
+
+#define STB_TEXTEDIT_STRINGLEN(tc)     ((tc)->stringlen)
+#define STB_TEXTEDIT_LAYOUTROW         layout_func
+#define STB_TEXTEDIT_GETWIDTH(tc,n,i)  (1) // quick hack for monospaced
+#define STB_TEXTEDIT_KEYTOTEXT(key)    (((key) & KEYDOWN_BIT) ? 0 : (key))
+#define STB_TEXTEDIT_GETCHAR(tc,i)     ((tc)->string[i])
+#define STB_TEXTEDIT_NEWLINE           '\n'
+#define STB_TEXTEDIT_IS_SPACE(ch)      isspace(ch)
+#define STB_TEXTEDIT_DELETECHARS       delete_chars
+#define STB_TEXTEDIT_INSERTCHARS       insert_chars
+
+#define STB_TEXTEDIT_K_SHIFT           0x40000000
+#define STB_TEXTEDIT_K_CONTROL         0x20000000
+#define STB_TEXTEDIT_K_LEFT            (KEYDOWN_BIT | 1) // actually use VK_LEFT, SDLK_LEFT, etc
+#define STB_TEXTEDIT_K_RIGHT           (KEYDOWN_BIT | 2) // VK_RIGHT
+#define STB_TEXTEDIT_K_UP              (KEYDOWN_BIT | 3) // VK_UP
+#define STB_TEXTEDIT_K_DOWN            (KEYDOWN_BIT | 4) // VK_DOWN
+#define STB_TEXTEDIT_K_LINESTART       (KEYDOWN_BIT | 5) // VK_HOME
+#define STB_TEXTEDIT_K_LINEEND         (KEYDOWN_BIT | 6) // VK_END
+#define STB_TEXTEDIT_K_TEXTSTART       (STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_CONTROL)
+#define STB_TEXTEDIT_K_TEXTEND         (STB_TEXTEDIT_K_LINEEND   | STB_TEXTEDIT_K_CONTROL)
+#define STB_TEXTEDIT_K_DELETE          (KEYDOWN_BIT | 7) // VK_DELETE
+#define STB_TEXTEDIT_K_BACKSPACE       (KEYDOWN_BIT | 8) // VK_BACKSPACE
+#define STB_TEXTEDIT_K_UNDO            (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'z')
+#define STB_TEXTEDIT_K_REDO            (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'y')
+#define STB_TEXTEDIT_K_INSERT          (KEYDOWN_BIT | 9) // VK_INSERT
+#define STB_TEXTEDIT_K_WORDLEFT        (STB_TEXTEDIT_K_LEFT  | STB_TEXTEDIT_K_CONTROL)
+#define STB_TEXTEDIT_K_WORDRIGHT       (STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_CONTROL)
+#define STB_TEXTEDIT_K_PGUP            (KEYDOWN_BIT | 10) // VK_PGUP -- not implemented
+#define STB_TEXTEDIT_K_PGDOWN          (KEYDOWN_BIT | 11) // VK_PGDOWN -- not implemented
+
+#define STB_TEXTEDIT_IMPLEMENTATION
+#include "stb_textedit.h"
+
+

+ 1 - 2
tests/test_vorbis.c

@@ -8,11 +8,10 @@ extern void stb_vorbis_dumpmem(void);
 int main(int argc, char **argv)
 {
    size_t memlen;
-   unsigned char *mem = stb_fileu("c:/x/01.ogg", &memlen);
+   unsigned char *mem = stb_fileu("c:/x/theme_03.ogg", &memlen);
    int chan, samplerate;
    short *output;
    int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
-   stb_vorbis_dumpmem();
    return 0;
 }
 #endif

+ 23 - 6
tools/README.footer.md

@@ -20,6 +20,17 @@ attribution requirement). They may be less featureful, slower,
 and/or use more memory. If you're already using an equivalent
 library, there's probably no good reason to switch.
 
+#### Why do you list "lines of code"? It's a terrible metric.
+
+Just to give you some idea of the internal complexity of the library,
+to help you manage your expectations, or to let you know what you're
+getting into. While not all the libraries are written in the same
+style, they're certainly similar styles, and so comparisons between
+the libraries are probably still meaningful.
+
+Note though that the lines do include both the implementation, the
+part that corresponds to a header file, and the documentation.
+
 #### Why single-file headers?
 
 Windows doesn't have standard directories where libraries
@@ -27,12 +38,21 @@ live. That makes deploying libraries in Windows a lot more
 painful than open source developers on Unix-derivates generally
 realize. (It also makes library dependencies a lot worse in Windows.)
 
+There's also a common problem in Windows where a library was built
+against a different version of the runtime library, which causes
+link conflicts and confusion. Shipping the libs as headers means
+you normally just compile them straight into your project without
+making libraries, thus sidestepping that problem.
+
 Making them a single file makes it very easy to just
 drop them into a project that needs them. (Of course you can
 still put them in a proper shared library tree if you want.)
 
+Why not two files, one a header and one an implementation?
 The difference between 10 files and 9 files is not a big deal,
 but the difference between 2 files and 1 file is a big deal.
+You don't need to zip or tar the files up, you don't have to
+remember to attach *two* files, etc.
 
 #### Why "stb"? Is this something to do with Set-Top Boxes?
 
@@ -58,12 +78,9 @@ Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
 
 #### Why public domain?
 
-Because more people will use it. Because it's not viral, people
-are not obligated to give back, so you could argue that it hurts
-the *development* of it, and then because it doesn't develop as
-well it's not as good, and then because it's not as good, in the
-long run maybe fewer people will use it. I have total respect for
-that opinion, but I just don't believe it myself for most software.
+I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons.
+Some of them are listed here:
+https://github.com/nothings/stb/blob/master/docs/why_public_domain.md
 
 #### Why C?
 

+ 2 - 2
tools/README.header.md

@@ -3,5 +3,5 @@ stb
 
 single-file public domain libraries for C/C++
 
-library    | lastest version | category | description
---------------------- | ---- | -------- | --------------------------------
+library    | lastest version | category | LoC | description
+--------------------- | ---- | -------- | --- | --------------------------------

+ 2 - 2
tools/README.list

@@ -10,8 +10,8 @@ stb_voxel_render.h          | 3D graphics      | Minecraft-esque voxel rendering
 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_tilemap_editor.h        | game dev         | embeddable tilemap editor
+stb_herringbone_wang_tile.h | game dev         | 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

+ 24 - 8
tools/make_readme.c

@@ -4,23 +4,23 @@
 int main(int argc, char  **argv)
 {
    int i;
-   int hlen, flen, listlen;
+   int hlen, flen, listlen, total_lines = 0;
    char *header = stb_file("README.header.md", &hlen);      // stb_file - read file into malloc()ed buffer
    char *footer = stb_file("README.footer.md", &flen);      // stb_file - read file into malloc()ed buffer
    char **list  = stb_stringfile("README.list", &listlen);  // stb_stringfile - read file lines into malloced array of strings
 
    FILE *f = fopen("../README.md", "wb");
+
+   fprintf(f, "<!---   THIS FILE IS AUTOMATICALLY GENERATED, DO NOT CHANGE IT BY HAND   --->\n\n");
    fwrite(header, 1, hlen, f);
 
    for (i=0; i < listlen; ++i) {
       int num,j;
       char **tokens = stb_tokens_stripwhite(list[i], "|", &num);  // stb_tokens -- tokenize string into malloced array of strings
-      FILE *g = fopen(stb_sprintf("../%s", tokens[0]), "rb");     // stb_sprintf -- sprintf to a static temp buffer (not threadsafe or secure)
-      char buffer[256], *s1, *s2;
-      fread(buffer, 1, 256, g);
-      fclose(g);
-      buffer[255] = 0;
-      s1 = strchr(buffer, '-');
+      int num_lines;
+      char **lines = stb_stringfile(stb_sprintf("../%s", tokens[0]), &num_lines);
+      char *s1, *s2,*s3;
+      s1 = strchr(lines[0], '-');
       if (!s1) stb_fatal("Couldn't find '-' before version number in %s", tokens[0]); // stb_fatal -- print error message & exit
       s2 = strchr(s1+2, '-');
       if (!s2) stb_fatal("Couldn't find '-' after version number in %s", tokens[0]);  // stb_fatal -- print error message & exit
@@ -28,16 +28,32 @@ int main(int argc, char  **argv)
       s1 += 1;
       s1 = stb_trimwhite(s1);                  // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace
       if (*s1 == 'v') ++s1;
-      fprintf(f, "**%s** | %s", tokens[0], s1);
+      s3 = tokens[0];
+      stb_trimwhite(s3);
+      if (strlen(s3) < 21) {
+         fprintf(f, "**%s** | %s", tokens[0], s1);
+      } else {
+         char buffer[256];
+         strncpy(buffer, s3, 18);
+         buffer[18] = 0;   
+         strcat(buffer, "...");
+         fprintf(f, "**%s** | %s", buffer, s1);
+      }
       s1 = stb_trimwhite(tokens[1]);           // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace
       s2 = stb_dupreplace(s1, " ", "&nbsp;");  // stb_dupreplace -- search & replace string and malloc result
       fprintf(f, " | %s", s2);
       free(s2);
+      fprintf(f, " | %d", num_lines);
+      total_lines += num_lines;
       for (j=2; j < num; ++j)
          fprintf(f, " | %s", tokens[j]);
       fprintf(f, "\n");
    }
 
+   fprintf(f, "\n");
+   fprintf(f, "Total libraries: %d  \n", listlen);
+   fprintf(f, "Total lines of C code: %d\n\n", total_lines);
+
    fwrite(footer, 1, flen, f);
    fclose(f);
 

+ 4 - 0
tools/make_readme.dsp

@@ -87,6 +87,10 @@ SOURCE=.\make_readme.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\README.header.md
+# End Source File
+# Begin Source File
+
 SOURCE=.\README.list
 # End Source File
 # End Target