Pārlūkot izejas kodu

Lots of module updates - mainly docs.

blitz-research 9 gadi atpakaļ
vecāks
revīzija
0d26bf663a
48 mainītis faili ar 4455 papildinājumiem un 4565 dzēšanām
  1. 0 867
      Monkey2-quick-reference.html
  2. 0 195
      modules/hoedown/hoedown.json
  3. 1 1
      modules/hoedown/hoedown.monkey2
  4. 25 3
      modules/libc/libc.monkey2
  5. 2 2
      modules/miniz/miniz.monkey2
  6. 2 0
      modules/modules.txt
  7. 0 21
      modules/monkey/assert.monkey2
  8. 12 1
      modules/monkey/debug.monkey2
  9. 22 15
      modules/monkey/math.monkey2
  10. 0 209
      modules/monkey/monkey.json
  11. 0 1
      modules/monkey/monkey.monkey2
  12. 4 4
      modules/monkey/native/bbassert.h
  13. 16 0
      modules/monkey/native/bbdebug.cpp
  14. 2 0
      modules/monkey/native/bbdebug.h
  15. 3 3
      modules/monkey/native/bbmonkey.cpp
  16. 7 10
      modules/monkey/native/bbobject.cpp
  17. 13 19
      modules/monkey/native/bbobject.h
  18. 19 15
      modules/monkey/native/bbstring.h
  19. 65 39
      modules/monkey/types.monkey2
  20. 2 0
      modules/stb-image/stb-image.monkey2
  21. 4 0
      modules/stb-truetype/native/stb_truetype.c
  22. 3235 0
      modules/stb-truetype/native/stb_truetype.h
  23. 35 0
      modules/stb-truetype/stb-truetype.monkey2
  24. 10 9
      modules/std/byteorder.monkey2
  25. 21 11
      modules/std/chartype.monkey2
  26. 11 3
      modules/std/color.monkey2
  27. 2 2
      modules/std/container.monkey2
  28. 28 3
      modules/std/databuffer.monkey2
  29. 4 4
      modules/std/datastream.monkey2
  30. 2 2
      modules/std/filestream.monkey2
  31. 235 54
      modules/std/filesystem.monkey2
  32. 0 469
      modules/std/filesystemex.monkey2
  33. 1 1
      modules/std/generator.monkey2
  34. 11 1
      modules/std/geom.monkey2
  35. 183 229
      modules/std/json.monkey2
  36. 208 95
      modules/std/list.monkey2
  37. 2 2
      modules/std/map.monkey2
  38. 21 3
      modules/std/markdown.monkey2
  39. 26 25
      modules/std/pixelformat.monkey2
  40. 43 118
      modules/std/pixmap.monkey2
  41. 70 0
      modules/std/pixmaploader.monkey2
  42. 61 54
      modules/std/stack.monkey2
  43. 19 2061
      modules/std/std.json
  44. 7 3
      modules/std/std.monkey2
  45. 12 6
      modules/std/stream.monkey2
  46. 1 1
      modules/std/stringio.monkey2
  47. 5 3
      modules/std/time.monkey2
  48. 3 1
      modules/std/zipstream.monkey2

+ 0 - 867
Monkey2-quick-reference.html

@@ -1,867 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<title>Monkey2-quick-reference</title>
-<link rel="stylesheet" href="https://stackedit.io/res-min/themes/base.css" />
-<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
-</head>
-<body><div class="container"><h3 id="primitive-types">Primitive types</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Name</th>
-  <th align="left">Description</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left"><code>Void</code></td>
-  <td align="left">No type</td>
-</tr>
-<tr>
-  <td align="left"><code>Bool</code></td>
-  <td align="left">Boolean</td>
-</tr>
-<tr>
-  <td align="left"><code>Byte</code></td>
-  <td align="left">8 bit signed integer</td>
-</tr>
-<tr>
-  <td align="left"><code>UByte</code></td>
-  <td align="left">8 bit unsigned integer</td>
-</tr>
-<tr>
-  <td align="left"><code>Short</code></td>
-  <td align="left">16 bit signed integer</td>
-</tr>
-<tr>
-  <td align="left"><code>UShort</code></td>
-  <td align="left">16 bit unsigned integer</td>
-</tr>
-<tr>
-  <td align="left"><code>Int</code></td>
-  <td align="left">32 bit signed integer</td>
-</tr>
-<tr>
-  <td align="left"><code>UInt</code></td>
-  <td align="left">32 bit unsigned integer</td>
-</tr>
-<tr>
-  <td align="left"><code>Long</code></td>
-  <td align="left">64 bit signed integer</td>
-</tr>
-<tr>
-  <td align="left"><code>ULong</code></td>
-  <td align="left">64 bit unsigned integer</td>
-</tr>
-<tr>
-  <td align="left"><code>Float</code></td>
-  <td align="left">32 bit float</td>
-</tr>
-<tr>
-  <td align="left"><code>Double</code></td>
-  <td align="left">64 bit float</td>
-</tr>
-<tr>
-  <td align="left"><code>String</code></td>
-  <td align="left">Character string</td>
-</tr>
-<tr>
-  <td align="left"><code>Object</code></td>
-  <td align="left">Class instance</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="derived-types">Derived types</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Syntax</th>
-  <th align="left">Derived type</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left">type <code>[ ]</code></td>
-  <td align="left">Array type</td>
-</tr>
-<tr>
-  <td align="left">type <code>(</code> types <code>)</code></td>
-  <td align="left">Function type</td>
-</tr>
-<tr>
-  <td align="left">type <code>&lt;</code> types <code>&gt;</code></td>
-  <td align="left">Generic type instance</td>
-</tr>
-<tr>
-  <td align="left">type <code>Ptr</code></td>
-  <td align="left">Pointer type</td>
-</tr>
-</tbody></table>
-
-
-<h3 id="native-wrapper-types">Native wrapper types</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Name</th>
-  <th align="left">Description</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left"><code>CString</code></td>
-  <td align="left">Null terminated C/C++ <code>const char *</code></td>
-</tr>
-<tr>
-  <td align="left"><code>WString</code></td>
-  <td align="left">Null terminated C/C++ <code>wchar_t *</code></td>
-</tr>
-<tr>
-  <td align="left"><code>Utf8String</code></td>
-  <td align="left">Null terminated C/C++ <code>const unsigned char *</code> in utf8 encoding.</td>
-</tr>
-</tbody></table>
-
-
-<p><code>CString</code>, <code>WString</code> and <code>Utf8String</code> should only be used when declaring parameters for extern functions.</p>
-
-
-
-<h3 id="implicit-conversions">Implicit conversions</h3>
-
-<p>These conversions are performed automatically:</p>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Source type</th>
-  <th align="left">Destination type</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left">Any non-void type</td>
-  <td align="left"><code>Bool</code></td>
-</tr>
-<tr>
-  <td align="left">Any numeric type</td>
-  <td align="left">Any numeric type, <code>String</code></td>
-</tr>
-<tr>
-  <td align="left"><code>String</code></td>
-  <td align="left"><code>CString</code>, <code>WString</code>, <code>Utf8String</code></td>
-</tr>
-<tr>
-  <td align="left">Any pointer type</td>
-  <td align="left"><code>Void Ptr</code></td>
-</tr>
-<tr>
-  <td align="left">Any enum type</td>
-  <td align="left"><code>Int</code></td>
-</tr>
-<tr>
-  <td align="left">Derived class</td>
-  <td align="left">Base class</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="explicit-conversions">Explicit conversions</h3>
-
-<p>The <code>Cast</code> <code>&lt;</code> <em>dest-type</em> <code>&gt;</code> <code>:</code> <em>dest-type</em> <code>(</code> <em>expression</em> <code>)</code> operator must be used for these conversions:</p>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Source type</th>
-  <th align="left">Destination type</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left"><code>Bool</code></td>
-  <td align="left">Any numeric type</td>
-</tr>
-<tr>
-  <td align="left"><code>String</code></td>
-  <td align="left">Any numeric type</td>
-</tr>
-<tr>
-  <td align="left">Any pointer type</td>
-  <td align="left">Any pointer type</td>
-</tr>
-<tr>
-  <td align="left"><code>Int</code></td>
-  <td align="left">Any enum type</td>
-</tr>
-<tr>
-  <td align="left">Base class</td>
-  <td align="left">Derived class</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="operators">Operators</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Operator</th>
-  <th align="left">Description</th>
-  <th align="center">Precedence</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left"><code>New</code></td>
-  <td align="left">New object or array</td>
-  <td align="center">1</td>
-</tr>
-<tr>
-  <td align="left"><code>Null</code></td>
-  <td align="left">Null value</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Self</code></td>
-  <td align="left">Self instance</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Super</code></td>
-  <td align="left">Super instance</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>True</code></td>
-  <td align="left">Boolean true</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>False</code></td>
-  <td align="left">Boolean false</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Cast</code></td>
-  <td align="left">Cast operator</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Lambda</code></td>
-  <td align="left">Lambda function</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><em>identifier</em></td>
-  <td align="left">Identifier</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><em>literal</em></td>
-  <td align="left">Literal value</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>.</code></td>
-  <td align="left">Postfix member acccess</td>
-  <td align="center">2</td>
-</tr>
-<tr>
-  <td align="left"><code>( )</code></td>
-  <td align="left">Postfix Invoke</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>[ ]</code></td>
-  <td align="left">Postfix Index</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&lt; &gt;</code></td>
-  <td align="left">Postfix Generic instance</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Varptr</code></td>
-  <td align="left">Unary variable address</td>
-  <td align="center">3</td>
-</tr>
-<tr>
-  <td align="left"><code>-</code></td>
-  <td align="left">Unary numeric negate</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>~</code></td>
-  <td align="left">Unary integer complement</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Not</code></td>
-  <td align="left">Unary boolean invert</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>*</code></td>
-  <td align="left">Numeric multiplication</td>
-  <td align="center">4</td>
-</tr>
-<tr>
-  <td align="left"><code>/</code></td>
-  <td align="left">Numeric division</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Mod</code></td>
-  <td align="left">Numeric modulo</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>+</code></td>
-  <td align="left">Numeric addition</td>
-  <td align="center">5</td>
-</tr>
-<tr>
-  <td align="left"><code>-</code></td>
-  <td align="left">Numeric subtraction</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Shl</code></td>
-  <td align="left">Integer shift left</td>
-  <td align="center">6</td>
-</tr>
-<tr>
-  <td align="left"><code>Shr</code></td>
-  <td align="left">Integer shift right</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&amp;</code></td>
-  <td align="left">Integer and</td>
-  <td align="center">7</td>
-</tr>
-<tr>
-  <td align="left"><code>~</code></td>
-  <td align="left">Integer xor</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>|</code></td>
-  <td align="left">Integer or</td>
-  <td align="center">8</td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&lt;=&gt;</code></td>
-  <td align="left">Compare</td>
-  <td align="center">9</td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&lt;</code></td>
-  <td align="left">Less than</td>
-  <td align="center">10</td>
-</tr>
-<tr>
-  <td align="left"><code>&gt;</code></td>
-  <td align="left">Greater than</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&lt;=</code></td>
-  <td align="left">Less than or equal</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>&gt;=</code></td>
-  <td align="left">Greater than or equal</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>=</code></td>
-  <td align="left">Equal</td>
-  <td align="center">11</td>
-</tr>
-<tr>
-  <td align="left"><code>&lt;&gt;</code></td>
-  <td align="left">Not equal</td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>And</code></td>
-  <td align="left">Boolean and</td>
-  <td align="center">12</td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>Or</code></td>
-  <td align="left">Boolean or</td>
-  <td align="center">13</td>
-</tr>
-<tr>
-  <td align="left"></td>
-  <td align="left"></td>
-  <td align="center"></td>
-</tr>
-<tr>
-  <td align="left"><code>?</code> <code>Else</code></td>
-  <td align="left">If-then-else</td>
-  <td align="center">14</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="string-members">String members</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Member</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left">Property Length:Int</td>
-</tr>
-<tr>
-  <td align="left">Property Utf8Length:Int</td>
-</tr>
-<tr>
-  <td align="left">Method Find:Int( str:String,from:Int=0 )</td>
-</tr>
-<tr>
-  <td align="left">Method FindLast:Int( str:String,from:Int=0 )</td>
-</tr>
-<tr>
-  <td align="left">Method Contains:Bool( str:String )</td>
-</tr>
-<tr>
-  <td align="left">Method StartsWith:Bool( str:String )</td>
-</tr>
-<tr>
-  <td align="left">Method EndsWith:Bool( str:String )</td>
-</tr>
-<tr>
-  <td align="left">Method Slice:String( from:Int )</td>
-</tr>
-<tr>
-  <td align="left">Method Slice:String( from:Int,tail:Int )</td>
-</tr>
-<tr>
-  <td align="left">Method ToUpper:String()</td>
-</tr>
-<tr>
-  <td align="left">Method ToLower:String()</td>
-</tr>
-<tr>
-  <td align="left">Method Capitalize:String()</td>
-</tr>
-<tr>
-  <td align="left">Method Trim:String()</td>
-</tr>
-<tr>
-  <td align="left">Method Replace:String( find:String,replace:String )</td>
-</tr>
-<tr>
-  <td align="left">Method Split:String<a></a></td>
-</tr>
-<tr>
-  <td align="left">Method Join:String( bits:String[] )</td>
-</tr>
-<tr>
-  <td align="left">Method ToUtf8String:Int( buf:Void Ptr,size:Int )</td>
-</tr>
-<tr>
-  <td align="left">Function FromChar:String( chr:Int )</td>
-</tr>
-<tr>
-  <td align="left">Function FromCString:String( data:Void Ptr )</td>
-</tr>
-<tr>
-  <td align="left">Function FromWString:String( data:Void Ptr )</td>
-</tr>
-<tr>
-  <td align="left">Function FromUtf8String:String( data:Void Ptr )</td>
-</tr>
-<tr>
-  <td align="left">Function FromUtf8String:String( data:Void Ptr,size:Int )</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="array-members">Array members</h3>
-
-<table>
-<thead>
-<tr>
-  <th align="left">Member</th>
-</tr>
-</thead>
-<tbody><tr>
-  <td align="left">Property Length:Int</td>
-</tr>
-</tbody></table>
-
-
-
-
-<h3 id="creating-arrays">Creating arrays</h3>
-
-<ul>
-<li><p><code>New</code> <em>element-type</em> <code>[</code> <em>length-expression</em> <code>]</code></p></li>
-<li><p><code>New</code> <em>element-type</em> <code>[]</code> <code>(</code> <em>element-expressions</em> <code>)</code></p></li>
-</ul>
-
-
-
-<h3 id="local-variables">Local variables</h3>
-
-<ul>
-<li><p><code>Local</code> <em>identifier</em> <code>:</code> <em>type</em> [ <code>=</code> <em>expression</em> ]</p></li>
-<li><p><code>Local</code> <em>identifier</em> <code>:=</code> <em>expression</em></p></li>
-</ul>
-
-
-
-<h3 id="field-variables">Field variables</h3>
-
-<ul>
-<li><p><code>Field</code> <em>identifier</em> <code>:</code> <em>type</em> [ <code>=</code> <em>expression</em> ]</p></li>
-<li><p><code>Field</code> <em>identifier</em> <code>:=</code> <em>expression</em></p></li>
-<li><p><code>Field</code> <em>identifier</em> <code>:</code> <em>type</em> <code>=</code> <em>extern-symbol</em></p></li>
-</ul>
-
-
-
-<h3 id="global-variables">Global variables</h3>
-
-<ul>
-<li><p><code>Global</code> <em>identifier</em> <code>:</code> <em>type</em> [ <code>=</code> <em>expression</em> ]</p></li>
-<li><p><code>Global</code> <em>identifier</em> <code>:=</code> <em>expression</em></p></li>
-<li><p><code>Global</code> <em>identifier</em> <code>:</code> <em>type</em> <code>=</code> <em>extern-symbol</em></p></li>
-</ul>
-
-
-
-<h3 id="constants">Constants</h3>
-
-<ul>
-<li><p><code>Const</code> <em>identifier</em> <code>:</code> <em>type</em> <code>=</code> <em>expression</em></p></li>
-<li><p><code>Const</code> <em>identifier</em> <code>:=</code> <em>expression</em></p></li>
-<li><p><code>Const</code> <em>identifier</em> <code>:</code> <em>type</em> <code>=</code> <em>extern-symbol</em></p></li>
-</ul>
-
-
-
-<h3 id="classes">Classes</h3>
-
-<ul>
-<li><code>Class</code> <em>identifier</em> [ <code>&lt;</code> <em>generic-types</em> <code>&gt;</code> ] [ <code>Extends</code> <em>type</em> ] [ <code>Implements</code> <em>types</em> ] [ <code>Abstract</code> | <code>Virtual</code> | <code>Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code> extern-symbol ]  <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>class-members</em> <br>
-<code>End</code> | <code>End Class</code></li>
-</ul>
-
-<p>Class methods are final by default and must be declared <code>Virtual</code> or <code>Abstract</code> if they are designed to be overridden, or <code>Override</code> or <code>Override Final</code> if they override a superclass method.</p>
-
-<p>This behavior can be modified by declaring a class <code>Virtual</code>. Classes declared <code>Virtual</code>  or with a superclass declared <code>Virtual</code> behave much like monkey1 or java classes - all methods are virtual by default, and will silently override any existing superclass virtual methods. It is an error to declare methods of such classes either <code>Virtual</code> or <code>Override</code>.</p>
-
-<p>Classes declared <code>Abstract</code> or that contain any abstract methods cannot be instantiated using <code>New</code>.</p>
-
-<p>Classes declared <code>Final</code> cannot be extended.</p>
-
-
-
-<h3 id="interfaces">Interfaces</h3>
-
-<ul>
-<li><code>Interface</code> <em>identifier</em> [ <code>Extends</code> <em>types</em> ] [ <code>=</code> extern-symbol ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>interface-members</em> <br>
-<code>End</code> | <code>End Interface</code></li>
-</ul>
-
-
-
-<h3 id="structs">Structs</h3>
-
-<ul>
-<li><code>Struct</code> <em>identifier</em> [ <code>=</code> extern-symbol ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>struct-members</em> <br>
-<code>End</code> | <code>End Struct</code></li>
-</ul>
-
-
-
-<h3 id="properties">Properties</h3>
-
-<ul>
-<li><p><code>Property</code> <em>identifier</em> <code>:</code> <em>type</em> <code>()</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-[ <code>Setter</code> <code>(</code> <em>param-decl</em> <code>)</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ] <br>
-<code>End</code> | <code>End Property</code></p></li>
-<li><p><code>Property</code> <em>identifier</em> <code>(</code> <em>param-decl</em> <code>)</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-[ <code>Getter</code> <code>:</code> <em>type</em> <code>()</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ] <br>
-<code>End</code> | <code>End Property</code></p></li>
-</ul>
-
-
-
-<h3 id="functions">Functions</h3>
-
-<ul>
-<li><code>Function</code> <em>identifier</em> [ <code>&lt;</code> <em>generic-types</em> <code>&gt;</code> ] [ <code>:</code> <em>return-type</em> ] <code>(</code> <em>param-decls</em><code>)</code> [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End Function</code></li>
-</ul>
-
-
-
-<h3 id="methods">Methods</h3>
-
-<ul>
-<li><code>Method</code> <em>identifier</em> [ <code>&lt;</code> <em>generic-types</em> <code>&gt;</code> ] [ <code>:</code> <em>return-type</em> ] <code>(</code> <em>param-decls</em> <code>)</code> [ <code>Virtual</code> | <code>Override</code> | <code>Final</code> | <code>Override Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End Method</code></li>
-</ul>
-
-
-
-<h3 id="properties-1">Properties</h3>
-
-<ul>
-<li><p><code>Property</code> <em>identifier</em> <code>:</code> <em>type</em> <code>()</code>  [ <code>Virtual</code> | <code>Override</code> | <code>Final</code> | <code>Override Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-[ <code>Setter</code> <code>(</code> <em>param-decl</em> <code>)</code>  [ <code>Virtual</code> | <code>Override</code> | <code>Final</code> | <code>Override Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ] <br>
-<code>End</code> | <code>End Property</code></p></li>
-<li><p><code>Property</code> <em>identifier</em> <code>(</code> <em>param-decl</em> <code>)</code>  [ <code>Virtual</code> | <code>Override</code> | <code>Final</code> | <code>Override Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-[ <code>Getter</code> <code>:</code> <em>type</em> <code>()</code>  [ <code>Virtual</code> | <code>Override</code> | <code>Final</code> | <code>Override Final</code> ] [ <code>Where</code> <em>where-expression</em> ] [ <code>=</code><em>extern-symbol</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ] <br>
-<code>End</code> | <code>End Property</code></p></li>
-</ul>
-
-<p>Example:</p>
-
-<pre>Struct S
-
-    Private
-
-    'Internal storage for the property
-    Field _seconds:Float
-
-    Public
-
-    'Read/Write 'Seconds' property...
-    Property Seconds:Float()
-
-        Return _seconds
-
-    Setter( seconds:Float )
-
-        _seconds=seconds
-    End
-
-    'Read only 'Minutes' property...
-    Property Minutes:Float()
-
-        Return _seconds/60.0
-    End
-
-End
-</pre>
-
-
-
-<h3 id="if-statement">If statement</h3>
-
-<ul>
-<li><p><code>If</code> <em>expression</em> [ <code>Then</code> ] <em>simple-statements</em> { <code>ElseIf</code> <em>expression</em> [ <code>Then</code> ] <em>simple-statements</em> } [ <code>Else</code> <em>simple-statements</em> ]</p></li>
-<li><p><code>If</code> <em>expression</em> [ <code>Then</code> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-{ <code>ElseIf</code> <em>expression</em> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> }  <br>
-[ <code>Else</code>  <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ]  <br>
-<code>End</code> | <code>End If</code> | <code>EndIf</code></p></li>
-</ul>
-
-
-
-<h3 id="while-loop">While loop</h3>
-
-<ul>
-<li><code>While</code> <em>expression</em> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End While</code> | <code>Wend</code></li>
-</ul>
-
-
-
-<h3 id="repeat-loop">Repeat loop</h3>
-
-<ul>
-<li><p><code>Repeat</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>Until</code> <em>expression</em></p></li>
-<li><p><code>Repeat</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>Forever</code></p></li>
-</ul>
-
-
-
-<h3 id="for-loop">For loop</h3>
-
-<ul>
-<li><p><code>For</code> <em>variable-expression</em> <code>=</code> <em>expression</em> <code>To</code> | <code>Until</code> <em>expression</em> [ <code>Step</code> <em>expression</em> ] <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End For</code> | <code>Next</code></p></li>
-<li><p><code>For</code> <em>variable-expression</em> <code>= Eachin</code> <em>expression</em> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End For</code> | <code>Next</code></p></li>
-<li><p><code>For</code> <em>simple-statement</em> <code>,</code> <em>expression</em> <code>,</code> <em>simple-statement</em> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>End</code> | <code>End For</code> | <code>Next</code></p></li>
-</ul>
-
-
-
-<h3 id="select-statement">Select statement</h3>
-
-<ul>
-<li><code>Select</code> <em>expression</em> <br>
-{ <code>Case</code> <em>expression</em> { <code>,</code> expression } <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> } <br>
-[ <code>Default</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> ] <br>
-<code>End</code> | <code>End Select</code></li>
-</ul>
-
-
-
-<h3 id="try-statement">Try statement</h3>
-
-<ul>
-<li><code>Try</code> <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-<code>Catch</code> ident <code>:</code> type <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> <br>
-{ <code>Catch</code> ident <code>:</code> type <br>
-&nbsp;&nbsp;&nbsp;&nbsp;    <em>statement-block</em> } <br>
-<code>End</code> | <code>End Try</code></li>
-</ul>
-
-
-
-<h3 id="return-statement">Return statement</h3>
-
-<ul>
-<li><code>Return</code> [ <em>expression</em> ]</li>
-</ul>
-
-
-
-<h3 id="throw-statement">Throw statement</h3>
-
-<ul>
-<li><code>Throw</code> [ <em>expression</em> ]</li>
-</ul>
-
-
-
-<h3 id="continue-statement">Continue statement</h3>
-
-<ul>
-<li><code>Continue</code></li>
-</ul>
-
-
-
-<h3 id="exit-statement">Exit statement</h3>
-
-<ul>
-<li><code>Exit</code></li>
-</ul>
-
-
-
-<h3 id="keywords">Keywords</h3>
-
-<p><code>Namespace Using Import Extern Public Private Protected Void Bool Byte UByte Short UShort Int UInt Long ULong Float Double String Object New Self Super Eachin True False Null Where Alias Const Local Global Field Method Function Property Getter Setter Operator Lambda Enum Class Interface Struct Extends Implements Virtual Override Abstract Final Inline Varptr Ptr Not Mod And Or Shl Shr End If Then Else Elseif Endif While Wend Repeat Until Forever For To Step Next Select Case Default Try Catch Throw Throwable Continue Exit Return Print Cast</code></p>
-
-<p>These keywords are currently unused but reserved for future use:</p>
-
-<p><code>Extension Protocol Delete Var Friend Static</code></p></div></body>
-</html>

+ 0 - 195
modules/hoedown/hoedown.json

@@ -1,195 +0,0 @@
-{
-  "module":{
-    "name":"hoedown"
-    ,"namespaces":[
-      {
-        "ident":"hoedown"
-        ,"enums":[
-          {
-            "ident":"hoedown_extensions"
-            ,"flags":129
-          }
-          ,{
-            "ident":"hoedown_html_flags"
-            ,"flags":129
-          }
-        ]
-        ,"constants":[
-          {
-            "ident":"HOEDOWN_EXT_AUTOLINK"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_DISABLE_INDENTED_CODE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_FENCED_CODE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_FOOTNOTES"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_HIGHLIGHT"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_MATH"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_MATH_EXPLICIT"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_NONE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_NO_INTRA_EMPHASIS"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_QUOTE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_SPACE_HEADERS"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_STRIKETHROUGH"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_SUPERSCRIPT"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_TABLES"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_EXT_UNDERLINE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_extensions"
-          }
-          ,{
-            "ident":"HOEDOWN_HTML_ESCAPE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_html_flags"
-          }
-          ,{
-            "ident":"HOEDOWN_HTML_HARD_WRAP"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_html_flags"
-          }
-          ,{
-            "ident":"HOEDOWN_HTML_NONE"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_html_flags"
-          }
-          ,{
-            "ident":"HOEDOWN_HTML_SKIP_HTML"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_html_flags"
-          }
-          ,{
-            "ident":"HOEDOWN_HTML_USE_XHTML"
-            ,"flags":129
-            ,"type":"hoedown.hoedown_html_flags"
-          }
-        ]
-        ,"functions":[
-          {
-            "ident":"hoedown_buffer_cstr"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.CChar Ptr"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"hoedown_buffer_free"
-          }
-          ,{
-            "ident":"hoedown_buffer_new"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"hoedown.hoedown_buffer Ptr"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"hoedown_buffer_put"
-          }
-          ,{
-            "ident":"hoedown_buffer_reset"
-          }
-          ,{
-            "ident":"hoedown_document_free"
-          }
-          ,{
-            "ident":"hoedown_document_new"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"hoedown.hoedown_document Ptr"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"hoedown_document_render"
-          }
-          ,{
-            "ident":"hoedown_document_render_inline"
-          }
-          ,{
-            "ident":"hoedown_html_renderer_free"
-          }
-          ,{
-            "ident":"hoedown_html_renderer_new"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"hoedown.hoedown_renderer Ptr"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"hoedown_html_toc_renderer_new"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"hoedown.hoedown_renderer Ptr"
-                }
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  }
-}

+ 1 - 1
modules/hoedown/hoedown.monkey2

@@ -29,7 +29,7 @@ Function hoedown_buffer_free( buf:hoedown_buffer Ptr )
 
 Function hoedown_buffer_put( buf:hoedown_buffer Ptr,data:UByte Ptr,size:Int )
 
-Function hoedown_buffer_cstr:CString( buf:hoedown_buffer Ptr )
+Function hoedown_buffer_cstr:Void Ptr( buf:hoedown_buffer Ptr )
 
 'renderer
 

+ 25 - 3
modules/libc/libc.monkey2

@@ -6,7 +6,29 @@ Namespace libc
 
 Extern
 
-Struct size_t
+#rem monkeydoc C/C++ 'char' type.
+#end
+Struct char_t="char"
+End
+
+#rem monkeydoc C/C++ 'signed char' type.
+#end
+Struct schar_t="signed char"
+End
+
+#rem monkeydoc C/C++ 'unsigned char' type
+#end
+Struct uchar_t="unsigned char"
+End
+
+#rem monkeydoc C/C++ 'wchar_t' type
+#end
+Struct wchar_t="wchar_t"
+End
+
+#rem monkeydoc C/C++ 'size_t' type
+#end
+Struct size_t="size_t"
 End
 
 Function sizeof<T>:Int( t:T )="(int)sizeof"
@@ -39,7 +61,7 @@ Function free:Void( mem:Void Ptr )
 
 Function system:Int( cmd:CString )="system_"
 Function setenv:Int( name:CString,value:CString,overwrite:Int )="setenv_"
-Function getenv:CChar Ptr( name:CString )
+Function getenv:char_t Ptr( name:CString )
 
 Function exit_:Void( status:Int )="exit"
 Function abort:Void()
@@ -83,7 +105,7 @@ Function difftime:Double( endtime:time_t,starttime:time_t )
 
 '***** unistd.h *****
 
-Function getcwd:CChar Ptr( buf:CChar Ptr,size:Int )
+Function getcwd:char_t Ptr( buf:char_t Ptr,size:Int )
 Function chdir:Int( path:CString )
 Function rmdir:Int( path:CString )
 

+ 2 - 2
modules/miniz/miniz.monkey2

@@ -59,8 +59,8 @@ Struct mz_zip_archive_file_stat
 	Field m_external_attr:UInt
 	Field m_local_header_ofs:ULong
 	Field m_comment_size:UInt
-	Field m_filename:CChar Ptr
-	Field m_comment:CChar Ptr
+	Field m_filename:char_t Ptr
+	Field m_comment:char_t Ptr
 End
 
 Function mz_free:Void( address:Void Ptr )

+ 2 - 0
modules/modules.txt

@@ -6,6 +6,8 @@ libc
 miniz
 hoedown
 stb-image
+stb-truetype
 std
 gles20
 sdl2
+sdl2-mixer

+ 0 - 21
modules/monkey/assert.monkey2

@@ -1,21 +0,0 @@
-
-Namespace monkey
-
-Extern
-
-Class RuntimeError="bbRuntimeError"
-
-	Method New( message:String )
-	
-	Property Message:String()="message"
-	
-	Property DebugStack:String[]()="debugStack"
-End
-
-Function Assert( condition:Bool )="bbAssert"
-
-Function Assert( condition:Bool,message:String )="bbAssert"
-
-Function DebugAssert( condition:Bool )="bbDebugAssert"
-
-Function DebugAssert( condition:Bool,message:String )="bbDebugAssert"

+ 12 - 1
modules/monkey/debug.monkey2

@@ -3,4 +3,15 @@ Namespace monkey.debug
 
 Extern
 
-Function Stop()="bbDB::stop"
+Function DebugStop()="bbDB::stop"
+
+Function Assert( condition:Bool )="bbAssert"
+
+Function Assert( condition:Bool,message:String )="bbAssert"
+
+Function DebugAssert( condition:Bool )="bbDebugAssert"
+
+Function DebugAssert( condition:Bool,message:String )="bbDebugAssert"
+
+Function DebugStack:String[]()="bbDebugStack"
+

+ 22 - 15
modules/monkey/math.monkey2

@@ -1,30 +1,32 @@
 
-Namespace monkey
+Namespace monkey.math
 
-Const Pi:Float=3.14159265359
+Using monkey.types
+
+Const Pi:Double=3.1415926535897932384626433832795028841971693993751058209749445923078164062
 
 Extern
 
-'Function Sin:Int( x:Int )="std::sin"
-Function Sin:Float( x:Float )="std::sin"
 Function Sin:Double( x:Double )="std::sin"
 
-'Function Cos:Int( x:Int )="std::cos"
-Function Cos:Float( x:Float )="std::cos"
 Function Cos:Double( x:Double )="std::cos"
 
-'Function Sqrt:Int( x:Int )="std::sqrt"
-Function Sqrt:Float( x:Int )="std::sqrt"
-Function Sqrt:Float( x:Float )="std::sqrt"
+Function Tan:Double( x:Double )="std::tan"
+
+Function ASin:Double( x:Double)="std::asin"
+
+Function ACos:Double( x:Double)="std::acos"
+
+Function ATan:Double( x:Double)="std::atan"
+
+Function ATan2:Double( x:Double)="std::atan2"
+
 Function Sqrt:Double( x:Double )="std::sqrt"
 
-Function Floor:Float( x:Float )="std::floor"
 Function Floor:Double( x:Double )="std::floor"
 
-Function Ceil:Float( x:Float )="std::ceil"
 Function Ceil:Double( x:Double )="std::ceil"
 
-Function Round:Float( x:Float )="std::round"
 Function Round:Double( x:Double )="std::round"
 
 Public
@@ -55,7 +57,7 @@ End
 
 #rem monkeydoc
 
-Clamps a value to range.
+Clamps a value to a range.
 
 If `x` is less than `min`, `min` is returned.
 
@@ -83,7 +85,7 @@ If `x` is greater than or equal to 0, then `x` is returned.
 @return the absolute value of `x`.
 
 #end
-Function Abs<T>:T( x:T )
+Function Abs<T>:T( x:T ) Where T Implements INumeric
 	If x>=0 Return x
 	Return -x
 End
@@ -101,9 +103,14 @@ Otherwise, if `x` is equal to 0, 0 is returned.
 @return the sign of `x`.
 
 #end
-Function Sgn<T>:Int( x:T )
+Function Sgn<T>:Int( x:T ) Where T Implements IIntegral
 	If x<0 Return -1
 	If x>0 Return 1
 	Return 0
 End
 
+Function Sgn<T>:Double( x:T ) Where T Implements IReal
+	If x<0 Return -1
+	If x>0 Return 1
+	Return 0
+End

+ 0 - 209
modules/monkey/monkey.json

@@ -1,209 +0,0 @@
-{
-  "module":{
-    "name":"monkey"
-    ,"namespaces":[
-      {
-        "ident":"monkey"
-        ,"aliases":[
-          {
-            "ident":"CString"
-            ,"flags":1
-            ,"type":"monkey.CChar Ptr"
-          }
-          ,{
-            "ident":"Utf8String"
-            ,"flags":1
-            ,"type":"monkey.Utf8Char Ptr"
-          }
-          ,{
-            "ident":"WString"
-            ,"flags":1
-            ,"type":"monkey.WChar Ptr"
-          }
-        ]
-        ,"classes":[
-          {
-            "ident":"Object"
-            ,"flags":129
-            ,"methods":[
-              {
-                "ident":"typeName"
-                ,"overloads":[
-                  {
-                    "return":{
-                      "type":"monkey.CChar Ptr"
-                    }
-                  }
-                ]
-              }
-            ]
-          }
-        ]
-        ,"constants":[
-          {
-            "ident":"Pi"
-            ,"flags":1
-            ,"type":"monkey.Float"
-          }
-        ]
-        ,"functions":[
-          {
-            "ident":"Abs"
-            ,"docs":"<p>Returns the absolute value of a number.</p>\n\n<p>If <code>x</code> is less than 0, then <code>-x</code> is returned.</p>\n\n<p>If <code>x</code> is greater than or equal to 0, then <code>x</code> is returned.</p>\n"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"T"
-                  ,"docs":"<p>the absolute value of <code>x</code>.</p>\n"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Ceil"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Clamp"
-            ,"docs":"<p>Clamps a value to range.</p>\n\n<p>If <code>x</code> is less than <code>min</code>, <code>min</code> is returned.</p>\n\n<p>If <code>x</code> is greater than <code>max</code>, <code>max</code> is returned.</p>\n\n<p>Otherwise, <code>x</code> is returned.</p>\n"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"T"
-                  ,"docs":"<p><code>x</code> clamped to the range [<code>min</code>,<code>max</code>].</p>\n"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Cos"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Floor"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Max"
-            ,"docs":"<p>Returns the larger of two values.</p>\n"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"T"
-                  ,"docs":"<p>the larger of <code>x</code> and <code>y</code>.</p>\n"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Min"
-            ,"docs":"<p>Returns the smaller of two values.</p>\n"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"T"
-                  ,"docs":"<p>the smaller of <code>x</code> and <code>y</code>.</p>\n"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Round"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Sgn"
-            ,"docs":"<p>Returns the sign of a number.</p>\n\n<p>If <code>x</code> is less than 0, the value -1 is returned.</p>\n\n<p>If <code>x</code> is equal to 0, the value 1 is returned.</p>\n\n<p>Otherwise, if <code>x</code> is equal to 0, 0 is returned.</p>\n"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Int"
-                  ,"docs":"<p>the sign of <code>x</code>.</p>\n"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Sin"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-          ,{
-            "ident":"Sqrt"
-            ,"overloads":[
-              {
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Float"
-                }
-              }
-              ,{
-                "return":{
-                  "type":"monkey.Double"
-                }
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  }
-}

+ 0 - 1
modules/monkey/monkey.monkey2

@@ -3,7 +3,6 @@ Namespace monkey
 
 #Import "types.monkey2"
 #Import "math.monkey2"
-#Import "assert.monkey2"
 #Import "debug.monkey2"
 
 #Import "native/bbtypes.cpp"

+ 4 - 4
modules/monkey/native/bbassert.h

@@ -5,19 +5,19 @@
 #include "bbobject.h"
 
 inline void bbAssert( bool cond ){
-	if( !cond ) throw new bbRuntimeError( "Assert failed" );
+	if( !cond ) throw new bbException( "Assert failed" );
 }
 
 inline void bbAssert( bool cond,bbString msg ){
-	if( !cond ) throw new bbRuntimeError( msg );
+	if( !cond ) throw new bbException( msg );
 }
 
 inline void bbDebugAssert( bool cond ){
-	if( !cond ) throw new bbRuntimeError( "Assert failed" );
+	if( !cond ) throw new bbException( "Assert failed" );
 }
 
 inline void bbDebugAssert( bool cond,bbString msg ){
-	if( !cond ) throw new bbRuntimeError( msg );
+	if( !cond ) throw new bbException( msg );
 }
 
 #endif

+ 16 - 0
modules/monkey/native/bbdebug.cpp

@@ -1,5 +1,6 @@
 
 #include "bbdebug.h"
+#include "bbarray.h"
 
 namespace bbDB{
 
@@ -38,6 +39,21 @@ namespace bbDB{
 		stopper=false;
 	}
 	
+	bbArray<bbString> *stack(){
+	
+		int n=0;
+		for( bbDBFrame *frame=frames;frame;frame=frame->succ ) ++n;
+		
+		//TODO: Fix GC issues! Can't have a free local like this in case bbString ctors cause gc sweep!!!!
+		bbArray<bbString> *st=bbArray<bbString>::create( n );
+		
+		int i=0;
+		for( bbDBFrame *frame=frames;frame;frame=frame->succ ){
+			st->at( i++ )=BB_T( frame->srcFile )+" ["+bbString( frame->srcPos>>12 )+"] "+frame->decl;
+		}
+		
+		return st;
+	}
 }
 
 bbString bbDBVar::ident()const{

+ 2 - 0
modules/monkey/native/bbdebug.h

@@ -25,6 +25,8 @@ namespace bbDB{
 	void stop();
 	
 	void stopped();
+	
+	bbArray<bbString> *stack();
 }
 
 struct bbDBFrame{

+ 3 - 3
modules/monkey/native/bbmonkey.cpp

@@ -106,9 +106,9 @@ int main( int argc,char **argv ){
 		
 		bbMain();
 		
-	}catch( bbRuntimeError *ex ){
+	}catch( bbException *ex ){
 	
-		printf( "\n***** Uncaught RuntimeError exception: %s *****\n\n",ex->message().c_str() );
+		printf( "\n***** Uncaught Monkey 2 Exception: %s *****\n\n",ex->message().c_str() );
 		
 		for( int i=0;i<ex->debugStack()->length();++i ){
 			printf( "%s\n",ex->debugStack()->at( i ).c_str() );
@@ -116,7 +116,7 @@ int main( int argc,char **argv ){
 
 	}catch(...){
 	
-		printf( "***** Uncaught native exception *****\n" );fflush( stdout );
+		printf( "***** Uncaught Native Exception *****\n" );fflush( stdout );
 //		throw;
 	}
 	

+ 7 - 10
modules/monkey/native/bbobject.cpp

@@ -3,15 +3,12 @@
 #include "bbdebug.h"
 #include "bbarray.h"
 
-bbThrowable::bbThrowable(){
+bbException::bbException(){
 
-	int n=0;
-	for( bbDBFrame *frame=bbDB::frames;frame;frame=frame->succ ) ++n;
-	
-	_debugStack=bbArray<bbString>::create( n );
-	
-	int i=0;
-	for( bbDBFrame *frame=bbDB::frames;frame;frame=frame->succ ){
-		_debugStack->at( i++ )=BB_T( frame->srcFile )+" ["+bbString( frame->srcPos>>12 )+"] "+frame->decl;
-	}
+	_debugStack=bbDB::stack();
+}
+
+bbException::bbException( bbString message ):bbException(){
+
+	_message=message;
 }

+ 13 - 19
modules/monkey/native/bbobject.h

@@ -29,15 +29,18 @@ struct bbObject : public bbGCNode{
 	}
 };
 
-class bbInterface{
-public:
-	virtual ~bbInterface(){
-	}
+struct bbThrowable : public bbObject{
 };
 
-struct bbThrowable : public bbObject{
+struct bbException : public bbThrowable{
 
-	bbThrowable();
+	bbException();
+	
+	bbException( bbString message );
+	
+	bbString message()const{
+		return _message;
+	}
 	
 	bbArray<bbString> *debugStack()const{
 		return _debugStack;
@@ -46,23 +49,14 @@ struct bbThrowable : public bbObject{
 	private:
 	
 	bbGCVar<bbArray<bbString>> _debugStack;
+	
+	bbString _message;
 };
 
-struct bbRuntimeError : public bbThrowable{
+struct bbInterface{
 
-	bbRuntimeError(){
-	}
-
-	bbRuntimeError( bbString message ):_message( message ){
-	}
-	
-	bbString message()const{ 
-		return _message; 
+	virtual ~bbInterface(){
 	}
-	
-	private:
-	
-	bbString _message;
 };
 
 template<class T,class...A> T *bbGCNew( A...a ){

+ 19 - 15
modules/monkey/native/bbstring.h

@@ -463,6 +463,10 @@ class bbCString{
 		return *this;
 	}
 	
+	operator bbString()const{
+		return _str;
+	}
+	
 	char *data()const{
 		if( _data ) return _data;
 		_data=(char*)malloc( _str.length()+1 );
@@ -471,10 +475,6 @@ class bbCString{
 		return _data;
 	}
 	
-	operator bbString()const{
-		return _str;
-	}
-	
 	operator char*()const{
 		return data();
 	}
@@ -503,6 +503,10 @@ class bbWString{
 		return *this;
 	}
 	
+	operator bbString()const{
+		return _str;
+	}
+	
 	wchar_t *data()const{
 		if( _data ) return _data;
 		_data=(wchar_t*)malloc( (_str.length()+1)*sizeof( wchar_t ) );
@@ -511,10 +515,6 @@ class bbWString{
 		return _data;
 	}
 	
-	operator bbString()const{
-		return _str;
-	}
-	
 	operator wchar_t*()const{
 		return data();
 	}
@@ -522,7 +522,7 @@ class bbWString{
 
 class bbUtf8String{
 	bbString _str;
-	mutable char *_data=nullptr;
+	mutable unsigned char *_data=nullptr;
 	
 	public:
 	
@@ -543,20 +543,24 @@ class bbUtf8String{
 		return *this;
 	}
 	
-	char *data()const{
+	operator bbString()const{
+		return _str;
+	}
+	
+	unsigned char *data()const{
 		if( _data ) return _data;
 		int n=_str.utf8Length()+1;
-		_data=(char*)malloc( n );
+		_data=(unsigned char*)malloc( n );
 		_str.toUtf8( _data,n );
 		return _data;
 	}
-
-	operator bbString()const{
-		return _str;
+	
+	operator unsigned char*()const{
+		return data();
 	}
 	
 	operator char*()const{
-		return data();
+		return (char*)data();
 	}
 };
 

+ 65 - 39
modules/monkey/types.monkey2

@@ -1,25 +1,9 @@
 
-Namespace monkey
+Namespace monkey.types
 
-Extern
-
-Struct CChar="char"
-End
-
-Struct WChar="wchar_t"
-End
-
-Struct Utf8Char="unsigned char"
-End
-
-Struct CString="bbCString"
-End
-
-Struct WString="bbWString"
-End
+Alias Exception:Throwable
 
-Struct Utf8String="bbUtf8String"
-End
+Extern
 
 Interface INumeric
 End
@@ -30,57 +14,57 @@ End
 Interface IReal Extends INumeric
 End
 
-#rem monkeydoc Primitive bool type
+#rem monkeydoc Primitive bool type.
 #end
 Struct @Bool Implements IIntegral ="bbBool"
 End
 
-#rem monkeydoc Primitive byte type
+#rem monkeydoc Primitive 8 bit byte type.
 #end
 Struct @Byte Implements IIntegral ="bbByte"
 End
 
-#rem monkeydoc Primitive unsigned byte type
+#rem monkeydoc Primitive 8 bit unsigned byte type.
 #end
 Struct @UByte Implements IIntegral ="bbUByte"
 End
 
-#rem monkeydoc Primitive short type
+#rem monkeydoc Primitive 16 bit short type.
 #end
 Struct @Short Implements IIntegral ="bbShort"
 End
 
-#rem monkeydoc Primitive unsigned short type
+#rem monkeydoc Primitive 16 bit unsigned short type.
 #end
 Struct @UShort Implements IIntegral ="bbUShort"
 End
 
-#rem monkeydoc Primitive int type
+#rem monkeydoc Primitive 32 bit int type.
 #end
 Struct @Int Implements IIntegral ="bbInt"
 End
 
-#rem monkeydoc Primitive unsigned int type
+#rem monkeydoc Primitive 32 bit unsigned int type.
 #end
 Struct @UInt Implements IIntegral ="bbUInt"
 End
 
-#rem monkeydoc Primitive long type
+#rem monkeydoc Primitive 64 bit long type.
 #end
 Struct @Long Implements IIntegral ="bbLong"
 End
 
-#rem monkeydoc Primitive unsigned long type
+#rem monkeydoc Primitive 64 bit unsigned long type.
 #end
 Struct @ULong Implements IIntegral ="bbULong"
 End
 
-#rem monkeydoc Primitive float type
+#rem monkeydoc Primitive 32 bit float type.
 #end
 Struct @Float Implements IReal ="bbFloat"
 End
 
-#rem monkeydoc Primitive double type
+#rem monkeydoc Primitive 64 bit double type.
 #end
 Struct @Double Implements IReal ="bbDouble"
 End
@@ -89,8 +73,18 @@ End
 #end
 Struct @String ="bbString"
 
+	#rem monkeydoc Gets the length of the string.
+	
+	@return The number of characters in the string.
+	
+	#end
 	Property Length:Int()="length"
 	
+	#rem monkeydoc Gets the utf8 length of the string.
+	
+	@return The size of the buffer required to store a utf8 representation of the string.
+	
+	#end
 	Property Utf8Length:Int()="utf8Length"
 	
 	Method Find:Int( str:String,from:Int=0 )="find"
@@ -139,12 +133,12 @@ Struct @String ="bbString"
 	
 	Function FromUtf8String:String( data:Void Ptr )="bbString::fromUtf8String"
 	
-	Function FromTString:String( data:Void Ptr )="bbString::fromTString"
-	
 	Function FromUtf8:String( data:Void Ptr,size:Int )="bbString::fromUtf8"
 	
 End
 
+#rem monkeydoc Primtive array type.
+#end
 Struct @Array<T>
 
 	Property Data:T Ptr()="data"
@@ -159,28 +153,60 @@ Struct @Array<T>
 
 End
 
+#rem monkeydoc Base class of all objects.
+#end
 Class @Object="bbObject"
 
-	Method typeName:CChar Ptr()="typeName"
+	#rem monkeydoc @hidden
+	#end
+	Method typeName:Void Ptr()="typeName"
 
 End
 
+#rem monkeydoc Base class of all throwable objects.
+#end
 Class @Throwable="bbThrowable"
 
-	Method DebugStack:String[]()="debugStack"
-	
 End
 
-#rem
-Class @RuntimeError Extends @Throwable="bbRuntimeError"
+#rem monkeydoc Base class of all exception objects.
+#end
+Class @Exception Extends Throwable="bbException"
 
 	Method New()
 	
 	Method New( message:String )
-	
+
 	Property Message:String()="message"
 
+	Property DebugStack:String[]()="debugStack"
+	
 End
-#end
 
+#rem monkeydoc @hidden
+#end
 Function TypeName:String( type:CString )="bbTypeName"
+
+#rem monkeydoc String wrapper type for native 'char *' strings.
+
+This type should only be used when declaring parameters for extern functions.
+
+#end
+Struct CString="bbCString"
+End
+
+#rem monkeydoc String wrapper type for native 'wchar_t *' strings.
+
+This type should only be used when declaring parameters for extern functions.
+
+#end
+Struct WString="bbWString"
+End
+
+#rem monkeydoc String wrapper type for native utf8 'unsigned char*' strings.
+
+This type should only be used when declaring parameters for extern functions.
+
+#end
+Struct Utf8String="bbUtf8String"
+End

+ 2 - 0
modules/stb-image/stb-image.monkey2

@@ -18,3 +18,5 @@ End
 Function stbi_load:UByte Ptr( filename:String,x:Int Ptr,y:Int Ptr,comp:Int Ptr,req_comp:Int )
 Function stbi_load_from_memory:UByte Ptr( buffer:UByte Ptr,x:Int Ptr,y:Int Ptr,comp:Int Ptr,req_comp:Int )
 Function stbi_load_from_callbacks:UByte Ptr( clbk:stbi_io_callbacks Ptr,user:Void Ptr,x:Int Ptr,y:Int Ptr,comp:Int Ptr,req_comp:Int )
+
+Function stbi_image_free( data:Void Ptr )

+ 4 - 0
modules/stb-truetype/native/stb_truetype.c

@@ -0,0 +1,4 @@
+
+#define STB_TRUETYPE_IMPLEMENTATION
+
+#include "stb_truetype.h"

+ 3235 - 0
modules/stb-truetype/native/stb_truetype.h

@@ -0,0 +1,3235 @@
+// stb_truetype.h - v1.08 - public domain
+// authored from 2009-2015 by Sean Barrett / RAD Game Tools
+//
+//   This library processes TrueType files:
+//        parse files
+//        extract glyph metrics
+//        extract glyph shapes
+//        render glyphs to one-channel bitmaps with antialiasing (box filter)
+//
+//   Todo:
+//        non-MS cmaps
+//        crashproof on bad data
+//        hinting? (no longer patented)
+//        cleartype-style AA?
+//        optimize: use simple memory allocator for intermediates
+//        optimize: build edge-list directly from curves
+//        optimize: rasterize directly from curves?
+//
+// ADDITIONAL CONTRIBUTORS
+//
+//   Mikko Mononen: compound shape support, more cmap formats
+//   Tor Andersson: kerning, subpixel rendering
+//
+//   Bug/warning reports/fixes:
+//       "Zer" on mollyrocket (with fix)
+//       Cass Everitt
+//       stoiko (Haemimont Games)
+//       Brian Hook 
+//       Walter van Niftrik
+//       David Gow
+//       David Given
+//       Ivan-Assen Ivanov
+//       Anthony Pesch
+//       Johan Duparc
+//       Hou Qiming
+//       Fabian "ryg" Giesen
+//       Martins Mozeiko
+//       Cap Petschulat
+//       Omar Cornut
+//       github:aloucks
+//       Peter LaValle
+//       Sergey Popov
+//       Giumo X. Clanjor
+//       Higor Euripedes
+//
+//   Misc other:
+//       Ryan Gordon
+//
+// VERSION HISTORY
+//
+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
+//                     variant PackFontRanges to pack and render in separate phases;
+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
+//                     fixed an assert() bug in the new rasterizer
+//                     replace assert() with STBTT_assert() in new rasterizer
+//   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
+//
+//   Full history can be found at the end of this file.
+//
+// LICENSE
+//
+//   This software is in the public domain. Where that dedication is not
+//   recognized, you are granted a perpetual, irrevocable license to copy,
+//   distribute, and modify this file as you see fit.
+//
+// USAGE
+//
+//   Include this file in whatever places neeed to refer to it. In ONE C/C++
+//   file, write:
+//      #define STB_TRUETYPE_IMPLEMENTATION
+//   before the #include of this file. This expands out the actual
+//   implementation into that C/C++ file.
+//
+//   To make the implementation private to the file that generates the implementation,
+//      #define STBTT_STATIC
+//
+//   Simple 3D API (don't ship this, but it's fine for tools and quick start)
+//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture
+//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char
+//
+//   Improved 3D API (more shippable):
+//           #include "stb_rect_pack.h"           -- optional, but you really want it
+//           stbtt_PackBegin()
+//           stbtt_PackSetOversample()            -- for improved quality on small fonts
+//           stbtt_PackFontRanges()               -- pack and renders
+//           stbtt_PackEnd()
+//           stbtt_GetPackedQuad()
+//
+//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)
+//           stbtt_InitFont()
+//           stbtt_GetFontOffsetForIndex()        -- use for TTC font collections
+//
+//   Render a unicode codepoint to a bitmap
+//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
+//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide
+//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be
+//
+//   Character advance/positioning
+//           stbtt_GetCodepointHMetrics()
+//           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.
+//
+//   After the sample programs is the "header file" section. This section
+//   includes documentation for each API function.
+//
+//   Some important concepts to understand to use this library:
+//
+//      Codepoint
+//         Characters are defined by unicode codepoints, e.g. 65 is
+//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
+//         the hiragana for "ma".
+//
+//      Glyph
+//         A visual character shape (every codepoint is rendered as
+//         some glyph)
+//
+//      Glyph index
+//         A font-specific integer ID representing a glyph
+//
+//      Baseline
+//         Glyph shapes are defined relative to a baseline, which is the
+//         bottom of uppercase characters. Characters extend both above
+//         and below the baseline.
+//
+//      Current Point
+//         As you draw text to the screen, you keep track of a "current point"
+//         which is the origin of each character. The current point's vertical
+//         position is the baseline. Even "baked fonts" use this model.
+//
+//      Vertical Font Metrics
+//         The vertical qualities of the font, used to vertically position
+//         and space the characters. See docs for stbtt_GetFontVMetrics.
+//
+//      Font Size in Pixels or Points
+//         The preferred interface for specifying font sizes in stb_truetype
+//         is to specify how tall the font's vertical extent should be in pixels.
+//         If that sounds good enough, skip the next paragraph.
+//
+//         Most font APIs instead use "points", which are a common typographic
+//         measurement for describing font size, defined as 72 points per inch.
+//         stb_truetype provides a point API for compatibility. However, true
+//         "per inch" conventions don't make much sense on computer displays
+//         since they different monitors have different number of pixels per
+//         inch. For example, Windows traditionally uses a convention that
+//         there are 96 pixels per inch, thus making 'inch' measurements have
+//         nothing to do with inches, and thus effectively defining a point to
+//         be 1.333 pixels. Additionally, the TrueType font data provides
+//         an explicit scale factor to scale a given font's glyphs to points,
+//         but the author has observed that this scale factor is often wrong
+//         for non-commercial fonts, thus making fonts scaled in points
+//         according to the TrueType spec incoherently sized in practice.
+//
+// ADVANCED USAGE
+//
+//   Quality:
+//
+//    - Use the functions with Subpixel at the end to allow your characters
+//      to have subpixel positioning. Since the font is anti-aliased, not
+//      hinted, this is very import for quality. (This is not possible with
+//      baked fonts.)
+//
+//    - Kerning is now supported, and if you're supporting subpixel rendering
+//      then kerning is worth using to give your text a polished look.
+//
+//   Performance:
+//
+//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
+//      if you don't do this, stb_truetype is forced to do the conversion on
+//      every call.
+//
+//    - There are a lot of memory allocations. We should modify it to take
+//      a temp buffer and allocate from the temp buffer (without freeing),
+//      should help performance a lot.
+//
+// NOTES
+//
+//   The system uses the raw data found in the .ttf file without changing it
+//   and without building auxiliary data structures. This is a bit inefficient
+//   on little-endian systems (the data is big-endian), but assuming you're
+//   caching the bitmaps or glyph shapes this shouldn't be a big deal.
+//
+//   It appears to be very hard to programmatically determine what font a
+//   given file is in a general way. I provide an API for this, but I don't
+//   recommend it.
+//
+//
+// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
+//
+//   Documentation & header file        520 LOC  \___ 660 LOC documentation
+//   Sample code                        140 LOC  /
+//   Truetype parsing                   620 LOC  ---- 620 LOC TrueType
+//   Software rasterization             240 LOC  \                           .
+//   Curve tesselation                  120 LOC   \__ 550 LOC Bitmap creation
+//   Bitmap management                  100 LOC   /
+//   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
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+////  SAMPLE PROGRAMS
+////
+//
+//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
+//
+#if 0
+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
+#include "stb_truetype.h"
+
+unsigned char ttf_buffer[1<<20];
+unsigned char temp_bitmap[512*512];
+
+stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
+GLuint ftex;
+
+void my_stbtt_initfont(void)
+{
+   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
+   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);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
+   // can free temp_bitmap at this point
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+void my_stbtt_print(float x, float y, char *text)
+{
+   // assume orthographic projection with units = screen pixels, origin at top left
+   glEnable(GL_TEXTURE_2D);
+   glBindTexture(GL_TEXTURE_2D, ftex);
+   glBegin(GL_QUADS);
+   while (*text) {
+      if (*text >= 32 && *text < 128) {
+         stbtt_aligned_quad q;
+         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
+         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
+         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
+         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
+         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
+      }
+      ++text;
+   }
+   glEnd();
+}
+#endif
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Complete program (this compiles): get a single bitmap, print as ASCII art
+//
+#if 0
+#include <stdio.h>
+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
+#include "stb_truetype.h"
+
+char ttf_buffer[1<<25];
+
+int main(int argc, char **argv)
+{
+   stbtt_fontinfo font;
+   unsigned char *bitmap;
+   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
+
+   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
+
+   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
+   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
+
+   for (j=0; j < h; ++j) {
+      for (i=0; i < w; ++i)
+         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
+      putchar('\n');
+   }
+   return 0;
+}
+#endif 
+//
+// Output:
+//
+//     .ii.
+//    @@@@@@.
+//   V@Mio@@o
+//   :i.  V@V
+//     :oM@@M
+//   :@@@MM@M
+//   @@o  o@M
+//  :@@.  M@M
+//   @@@o@@@@
+//   :M@@V:@@.
+//  
+//////////////////////////////////////////////////////////////////////////////
+// 
+// Complete program: print "Hello World!" banner, with bugs
+//
+#if 0
+char buffer[24<<20];
+unsigned char screen[20][79];
+
+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!"; // intentionally misspelled to show 'lj' brokenness
+
+   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
+   stbtt_InitFont(&font, buffer, 0);
+
+   scale = stbtt_ScaleForPixelHeight(&font, 15);
+   stbtt_GetFontVMetrics(&font, &ascent,0,0);
+   baseline = (int) (ascent*scale);
+
+   while (text[ch]) {
+      int advance,lsb,x0,y0,x1,y1;
+      float x_shift = xpos - (float) floor(xpos);
+      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
+      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
+      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
+      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
+      // because this API is really for baking character bitmaps into textures. if you want to render
+      // a sequence of characters, you really need to render each bitmap to a temp buffer, then
+      // "alpha blend" that into the working buffer
+      xpos += (advance * scale);
+      if (text[ch+1])
+         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
+      ++ch;
+   }
+
+   for (j=0; j < 20; ++j) {
+      for (i=0; i < 78; ++i)
+         putchar(" .:ioVM@"[screen[j][i]>>5]);
+      putchar('\n');
+   }
+
+   return 0;
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+////   INTEGRATION WITH YOUR CODEBASE
+////
+////   The following sections allow you to supply alternate definitions
+////   of C library functions used by stb_truetype.
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+   // #define your own (u)stbtt_int8/16/32 before including to override this
+   #ifndef stbtt_uint8
+   typedef unsigned char   stbtt_uint8;
+   typedef signed   char   stbtt_int8;
+   typedef unsigned short  stbtt_uint16;
+   typedef signed   short  stbtt_int16;
+   typedef unsigned int    stbtt_uint32;
+   typedef signed   int    stbtt_int32;
+   #endif
+
+   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
+   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
+
+   // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
+   #ifndef STBTT_ifloor
+   #include <math.h>
+   #define STBTT_ifloor(x)   ((int) floor(x))
+   #define STBTT_iceil(x)    ((int) ceil(x))
+   #endif
+
+   #ifndef STBTT_sqrt
+   #include <math.h>
+   #define STBTT_sqrt(x)      sqrt(x)
+   #endif
+
+   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
+   #ifndef STBTT_malloc
+   #include <stdlib.h>
+   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))
+   #define STBTT_free(x,u)    ((void)(u),free(x))
+   #endif
+
+   #ifndef STBTT_assert
+   #include <assert.h>
+   #define STBTT_assert(x)    assert(x)
+   #endif
+
+   #ifndef STBTT_strlen
+   #include <string.h>
+   #define STBTT_strlen(x)    strlen(x)
+   #endif
+
+   #ifndef STBTT_memcpy
+   #include <memory.h>
+   #define STBTT_memcpy       memcpy
+   #define STBTT_memset       memset
+   #endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+////   INTERFACE
+////
+////
+
+#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
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTURE BAKING API
+//
+// If you use this API, you only have to call two functions ever.
+//
+
+typedef struct
+{
+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
+   float xoff,yoff,xadvance;
+} stbtt_bakedchar;
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
+                                float pixel_height,                     // height of font in pixels
+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
+                                int first_char, int num_chars,          // characters to bake
+                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long
+// if return is positive, the first unused row of the bitmap
+// if return is negative, returns the negative of the number of characters that fit
+// if return is 0, no characters fit and no rows were used
+// This uses a very crappy packing.
+
+typedef struct
+{
+   float x0,y0,s0,t0; // top-left
+   float x1,y1,s1,t1; // bottom-right
+} stbtt_aligned_quad;
+
+STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
+                               int char_index,             // character to display
+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
+                               stbtt_aligned_quad *q,      // output: quad to draw
+                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier
+// Call GetBakedQuad with char_index = 'character - first_char', and it
+// creates the quad you need to draw and advances the current position.
+//
+// The coordinate system used assumes y increases downwards.
+//
+// Characters will extend both above and below the current position;
+// see discussion of "BASELINE" above.
+//
+// It's inefficient; you might want to c&p it and optimize it.
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// NEW TEXTURE BAKING API
+//
+// This provides options for packing multiple fonts into one atlas, not
+// perfectly but better than nothing.
+
+typedef struct
+{
+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
+   float xoff,yoff,xadvance;
+   float xoff2,yoff2;
+} stbtt_packedchar;
+
+typedef struct stbtt_pack_context stbtt_pack_context;
+typedef struct stbtt_fontinfo stbtt_fontinfo;
+#ifndef STB_RECT_PACK_VERSION
+typedef struct stbrp_rect stbrp_rect;
+#endif
+
+STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
+// Initializes a packing context stored in the passed-in stbtt_pack_context.
+// Future calls using this context will pack characters into the bitmap passed
+// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is
+// the distance from one row to the next (or 0 to mean they are packed tightly
+// together). "padding" is the amount of padding to leave between each
+// character (normally you want '1' for bitmaps you'll use as textures with
+// bilinear filtering).
+//
+// Returns 0 on failure, 1 on success.
+
+STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);
+// Cleans up the packing context and frees all memory.
+
+#define STBTT_POINT_SIZE(x)   (-(x))
+
+STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
+// Creates character bitmaps from the font_index'th font found in fontdata (use
+// font_index=0 if you don't know what that is). It creates num_chars_in_range
+// bitmaps for characters with unicode values starting at first_unicode_char_in_range
+// and increasing. Data for how to render them is stored in chardata_for_range;
+// pass these to stbtt_GetPackedQuad to get back renderable quads.
+//
+// font_size is the full height of the character from ascender to descender,
+// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
+// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
+// and pass that result as 'font_size':
+//       ...,                  20 , ... // font max minus min y is 20 pixels tall
+//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
+
+typedef struct
+{
+   float font_size;
+   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint
+   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints
+   int num_chars;
+   stbtt_packedchar *chardata_for_range; // output
+   unsigned char h_oversample, v_oversample; // don't set these, they're used internally
+} stbtt_pack_range;
+
+STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
+// Creates character bitmaps from multiple ranges of characters stored in
+// ranges. This will usually create a better-packed bitmap than multiple
+// calls to stbtt_PackFontRange. Note that you can call this multiple
+// times within a single PackBegin/PackEnd.
+
+STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
+// Oversampling a font increases the quality by allowing higher-quality subpixel
+// positioning, and is especially valuable at smaller text sizes.
+//
+// This function sets the amount of oversampling for all following calls to
+// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
+// pack context. The default (no oversampling) is achieved by h_oversample=1
+// and v_oversample=1. The total number of pixels required is
+// h_oversample*v_oversample larger than the default; for example, 2x2
+// oversampling requires 4x the storage of 1x1. For best results, render
+// oversampled textures with bilinear filtering. Look at the readme in
+// stb/tests/oversample for information about oversampled fonts
+//
+// To use with PackFontRangesGather etc., you must set it before calls
+// call to PackFontRangesGatherRects.
+
+STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph,  // same data as above
+                               int char_index,             // character to display
+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
+                               stbtt_aligned_quad *q,      // output: quad to draw
+                               int align_to_integer);
+
+STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
+STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+// Calling these functions in sequence is roughly equivalent to calling
+// stbtt_PackFontRanges(). If you more control over the packing of multiple
+// fonts, or if you want to pack custom data into a font texture, take a look
+// at the source to of stbtt_PackFontRanges() and create a custom version 
+// using these functions, e.g. call GatherRects multiple times,
+// building up a single array of rects, then call PackRects once,
+// then call RenderIntoRects repeatedly. This may result in a
+// better packing than calling PackFontRanges multiple times
+// (or it may not).
+
+// this is an opaque structure that you shouldn't mess with which holds
+// all the context needed from PackBegin to PackEnd.
+struct stbtt_pack_context {
+   void *user_allocator_context;
+   void *pack_info;
+   int   width;
+   int   height;
+   int   stride_in_bytes;
+   int   padding;
+   unsigned int   h_oversample, v_oversample;
+   unsigned char *pixels;
+   void  *nodes;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// FONT LOADING
+//
+//
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
+// Each .ttf/.ttc file may have more than one font. Each font has a sequential
+// index number starting from 0. Call this function to get the font offset for
+// a given index; it returns -1 if the index is out of range. A regular .ttf
+// file will only define one font and it always be at offset 0, so it will
+// return '0' for index 0, and -1 for all other indices. You can just skip
+// this step if you know it's that kind of font.
+
+
+// The following structure is defined publically so you can declare one on
+// the stack or as a global or etc, but you should treat it as opaque.
+typedef struct stbtt_fontinfo
+{
+   void           * userdata;
+   unsigned char  * data;              // pointer to .ttf file
+   int              fontstart;         // offset of start of font
+
+   int numGlyphs;                     // number of glyphs, needed for range checking
+
+   int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
+   int index_map;                     // a cmap mapping for our chosen character encoding
+   int indexToLocFormat;              // format needed to map from glyph index to glyph
+} stbtt_fontinfo;
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
+// Given an offset into the file that defines a font, this function builds
+// the necessary cached info for the rest of the system. You must allocate
+// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
+// need to do anything special to free it, because the contents are pure
+// value data with no additional data structures. Returns 0 on failure.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CHARACTER TO GLYPH-INDEX CONVERSIOn
+
+STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
+// If you're going to perform multiple operations on the same character
+// and you want a speed-up, call this function with the character you're
+// going to process, then use glyph-based functions instead of the
+// codepoint-based functions.
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CHARACTER PROPERTIES
+//
+
+STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
+// computes a scale factor to produce a font whose "height" is 'pixels' tall.
+// Height is measured as the distance from the highest ascender to the lowest
+// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
+// and computing:
+//       scale = pixels / (ascent - descent)
+// so if you prefer to measure height by the ascent only, use a similar calculation.
+
+STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
+// computes a scale factor to produce a font whose EM size is mapped to
+// 'pixels' tall. This is probably what traditional APIs compute, but
+// I'm not positive.
+
+STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
+// ascent is the coordinate above the baseline the font extends; descent
+// is the coordinate below the baseline the font extends (i.e. it is typically negative)
+// lineGap is the spacing between one row's descent and the next row's ascent...
+// so you should advance the vertical position by "*ascent - *descent + *lineGap"
+//   these are expressed in unscaled coordinates, so you must multiply by
+//   the scale factor for a given size
+
+STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
+// the bounding box around all possible characters
+
+STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
+// leftSideBearing is the offset from the current horizontal position to the left edge of the character
+// advanceWidth is the offset from the current horizontal position to the next horizontal position
+//   these are expressed in unscaled coordinates
+
+STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
+// an additional amount to add to the 'advance' value between ch1 and ch2
+
+STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
+// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
+
+STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
+STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
+STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+// as above, but takes one or more glyph indices for greater efficiency
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// GLYPH SHAPES (you probably don't need these, but they have to go before
+// the bitmaps for C declaration-order reasons)
+//
+
+#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
+   enum {
+      STBTT_vmove=1,
+      STBTT_vline,
+      STBTT_vcurve
+   };
+#endif
+
+#ifndef stbtt_vertex // you can predefine this to use different values
+                   // (we share this with other code at RAD)
+   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
+   typedef struct
+   {
+      stbtt_vertex_type x,y,cx,cy;
+      unsigned char type,padding;
+   } stbtt_vertex;
+#endif
+
+STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
+// returns non-zero if nothing is drawn for this glyph
+
+STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
+// returns # of vertices and fills *vertices with the pointer to them
+//   these are expressed in "unscaled" coordinates
+//
+// The shape is a series of countours. Each one starts with
+// a STBTT_moveto, then consists of a series of mixed
+// STBTT_lineto and STBTT_curveto segments. A lineto
+// draws a line from previous endpoint to its x,y; a curveto
+// draws a quadratic bezier from previous endpoint to
+// its x,y, using cx,cy as the bezier control point.
+
+STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
+// frees the data allocated above
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// BITMAP RENDERING
+//
+
+STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
+// frees the bitmap allocated below
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
+// allocates a large-enough single-channel 8bpp bitmap and renders the
+// specified character/glyph at the specified scale into it, with
+// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
+// *width & *height are filled out with the width & height of the bitmap,
+// which is stored left-to-right, top-to-bottom.
+//
+// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
+// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
+// shift for the character
+
+STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
+// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
+// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
+// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
+// width and height and positioning info for it first.
+
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
+// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
+// shift for the character
+
+STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+// get the bbox of the bitmap centered around the glyph origin; so the
+// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
+// the bitmap top left is (leftSideBearing*scale,iy0).
+// (Note that the bitmap uses y-increases-down, but the shape uses
+// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
+
+STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
+// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
+// shift for the character
+
+// the following functions are equivalent to the above functions, but operate
+// on glyph indices instead of Unicode codepoints (for efficiency)
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
+
+
+// @TODO: don't expose this structure
+typedef struct
+{
+   int w,h,stride;
+   unsigned char *pixels;
+} stbtt__bitmap;
+
+// rasterize a shape with quadratic beziers into a bitmap
+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into
+                               float flatness_in_pixels,     // allowable error of curve in pixels
+                               stbtt_vertex *vertices,       // array of vertices defining shape
+                               int num_verts,                // number of vertices in above array
+                               float scale_x, float scale_y, // scale applied to input vertices
+                               float shift_x, float shift_y, // translation applied to input vertices
+                               int x_off, int y_off,         // another translation applied to input
+                               int invert,                   // if non-zero, vertically flip shape
+                               void *userdata);              // context for to STBTT_MALLOC
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Finding the right font...
+//
+// You should really just solve this offline, keep your own tables
+// of what font is what, and don't try to get it out of the .ttf file.
+// That's because getting it out of the .ttf file is really hard, because
+// the names in the file can appear in many possible encodings, in many
+// possible languages, and e.g. if you need a case-insensitive comparison,
+// the details of that depend on the encoding & language in a complex way
+// (actually underspecified in truetype, but also gigantic).
+//
+// But you can use the provided functions in two possible ways:
+//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
+//             unicode-encoded names to try to find the font you want;
+//             you can run this before calling stbtt_InitFont()
+//
+//     stbtt_GetFontNameString() lets you get any of the various strings
+//             from the file yourself and do your own comparisons on them.
+//             You have to have called stbtt_InitFont() first.
+
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
+// returns the offset (not index) of the font that matches, or -1 if none
+//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
+//   if you use any other flag, use a font name like "Arial"; this checks
+//     the 'macStyle' header field; i don't know if fonts set this consistently
+#define STBTT_MACSTYLE_DONTCARE     0
+#define STBTT_MACSTYLE_BOLD         1
+#define STBTT_MACSTYLE_ITALIC       2
+#define STBTT_MACSTYLE_UNDERSCORE   4
+#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
+// returns 1/0 whether the first string interpreted as utf8 is identical to
+// the second string interpreted as big-endian utf16... useful for strings from next func
+
+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
+// returns the string (which may be big-endian double byte, e.g. for unicode)
+// and puts the length in bytes in *length.
+//
+// some of the values for the IDs are below; for more see the truetype spec:
+//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+//     http://www.microsoft.com/typography/otspec/name.htm
+
+enum { // platformID
+   STBTT_PLATFORM_ID_UNICODE   =0,
+   STBTT_PLATFORM_ID_MAC       =1,
+   STBTT_PLATFORM_ID_ISO       =2,
+   STBTT_PLATFORM_ID_MICROSOFT =3
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
+   STBTT_UNICODE_EID_UNICODE_1_0    =0,
+   STBTT_UNICODE_EID_UNICODE_1_1    =1,
+   STBTT_UNICODE_EID_ISO_10646      =2,
+   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
+   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
+   STBTT_MS_EID_SYMBOL        =0,
+   STBTT_MS_EID_UNICODE_BMP   =1,
+   STBTT_MS_EID_SHIFTJIS      =2,
+   STBTT_MS_EID_UNICODE_FULL  =10
+};
+
+enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
+   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,
+   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,
+   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,
+   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7
+};
+
+enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
+       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
+   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,
+   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,
+   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,
+   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,
+   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,
+   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D
+};
+
+enum { // languageID for STBTT_PLATFORM_ID_MAC
+   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,
+   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,
+   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,
+   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,
+   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,
+   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
+   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __STB_INCLUDE_STB_TRUETYPE_H__
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+////   IMPLEMENTATION
+////
+////
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+
+#ifndef STBTT_MAX_OVERSAMPLE
+#define STBTT_MAX_OVERSAMPLE   8
+#endif
+
+#if STBTT_MAX_OVERSAMPLE > 255
+#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
+#endif
+
+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
+//
+
+// on platforms that don't allow misaligned reads, if we want to allow
+// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
+
+#define ttBYTE(p)     (* (stbtt_uint8 *) (p))
+#define ttCHAR(p)     (* (stbtt_int8 *) (p))
+#define ttFixed(p)    ttLONG(p)
+
+#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)
+
+   #define ttUSHORT(p)   (* (stbtt_uint16 *) (p))
+   #define ttSHORT(p)    (* (stbtt_int16 *) (p))
+   #define ttULONG(p)    (* (stbtt_uint32 *) (p))
+   #define ttLONG(p)     (* (stbtt_int32 *) (p))
+
+#else
+
+   static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+   static stbtt_int16 ttSHORT(const stbtt_uint8 *p)   { return p[0]*256 + p[1]; }
+   static stbtt_uint32 ttULONG(const stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+   static stbtt_int32 ttLONG(const stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+
+#endif
+
+#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
+#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])
+
+static int stbtt__isfont(const stbtt_uint8 *font)
+{
+   // check the version number
+   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1
+   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!
+   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF
+   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
+   return 0;
+}
+
+// @OPTIMIZE: binary search
+static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
+{
+   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
+   stbtt_uint32 tabledir = fontstart + 12;
+   stbtt_int32 i;
+   for (i=0; i < num_tables; ++i) {
+      stbtt_uint32 loc = tabledir + 16*i;
+      if (stbtt_tag(data+loc+0, tag))
+         return ttULONG(data+loc+8);
+   }
+   return 0;
+}
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)
+{
+   // if it's just a font, there's only one valid index
+   if (stbtt__isfont(font_collection))
+      return index == 0 ? 0 : -1;
+
+   // check if it's a TTC
+   if (stbtt_tag(font_collection, "ttcf")) {
+      // version 1?
+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
+         stbtt_int32 n = ttLONG(font_collection+8);
+         if (index >= n)
+            return -1;
+         return ttULONG(font_collection+12+index*4);
+      }
+   }
+   return -1;
+}
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)
+{
+   stbtt_uint8 *data = (stbtt_uint8 *) data2;
+   stbtt_uint32 cmap, t;
+   stbtt_int32 i,numTables;
+
+   info->data = data;
+   info->fontstart = fontstart;
+
+   cmap = stbtt__find_table(data, fontstart, "cmap");       // required
+   info->loca = stbtt__find_table(data, fontstart, "loca"); // required
+   info->head = stbtt__find_table(data, fontstart, "head"); // required
+   info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required
+   info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
+   info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
+   info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
+   if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
+      return 0;
+
+   t = stbtt__find_table(data, fontstart, "maxp");
+   if (t)
+      info->numGlyphs = ttUSHORT(data+t+4);
+   else
+      info->numGlyphs = 0xffff;
+
+   // find a cmap encoding table we understand *now* to avoid searching
+   // later. (todo: could make this installable)
+   // the same regardless of glyph.
+   numTables = ttUSHORT(data + cmap + 2);
+   info->index_map = 0;
+   for (i=0; i < numTables; ++i) {
+      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
+      // find an encoding we understand:
+      switch(ttUSHORT(data+encoding_record)) {
+         case STBTT_PLATFORM_ID_MICROSOFT:
+            switch (ttUSHORT(data+encoding_record+2)) {
+               case STBTT_MS_EID_UNICODE_BMP:
+               case STBTT_MS_EID_UNICODE_FULL:
+                  // MS/Unicode
+                  info->index_map = cmap + ttULONG(data+encoding_record+4);
+                  break;
+            }
+            break;
+        case STBTT_PLATFORM_ID_UNICODE:
+            // Mac/iOS has these
+            // all the encodingIDs are unicode, so we don't bother to check it
+            info->index_map = cmap + ttULONG(data+encoding_record+4);
+            break;
+      }
+   }
+   if (info->index_map == 0)
+      return 0;
+
+   info->indexToLocFormat = ttUSHORT(data+info->head + 50);
+   return 1;
+}
+
+STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
+{
+   stbtt_uint8 *data = info->data;
+   stbtt_uint32 index_map = info->index_map;
+
+   stbtt_uint16 format = ttUSHORT(data + index_map + 0);
+   if (format == 0) { // apple byte encoding
+      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
+      if (unicode_codepoint < bytes-6)
+         return ttBYTE(data + index_map + 6 + unicode_codepoint);
+      return 0;
+   } else if (format == 6) {
+      stbtt_uint32 first = ttUSHORT(data + index_map + 6);
+      stbtt_uint32 count = ttUSHORT(data + index_map + 8);
+      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
+         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
+      return 0;
+   } else if (format == 2) {
+      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
+      return 0;
+   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
+      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
+      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
+      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
+      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
+
+      // do a binary search of the segments
+      stbtt_uint32 endCount = index_map + 14;
+      stbtt_uint32 search = endCount;
+
+      if (unicode_codepoint > 0xffff)
+         return 0;
+
+      // they lie from endCount .. endCount + segCount
+      // but searchRange is the nearest power of two, so...
+      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
+         search += rangeShift*2;
+
+      // now decrement to bias correctly to find smallest
+      search -= 2;
+      while (entrySelector) {
+         stbtt_uint16 end;
+         searchRange >>= 1;
+         end = ttUSHORT(data + search + searchRange*2);
+         if (unicode_codepoint > end)
+            search += searchRange*2;
+         --entrySelector;
+      }
+      search += 2;
+
+      {
+         stbtt_uint16 offset, start;
+         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
+
+         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
+         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
+         if (unicode_codepoint < start)
+            return 0;
+
+         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
+         if (offset == 0)
+            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
+
+         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
+      }
+   } else if (format == 12 || format == 13) {
+      stbtt_uint32 ngroups = ttULONG(data+index_map+12);
+      stbtt_int32 low,high;
+      low = 0; high = (stbtt_int32)ngroups;
+      // Binary search the right group.
+      while (low < high) {
+         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
+         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
+         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
+         if ((stbtt_uint32) unicode_codepoint < start_char)
+            high = mid;
+         else if ((stbtt_uint32) unicode_codepoint > end_char)
+            low = mid+1;
+         else {
+            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
+            if (format == 12)
+               return start_glyph + unicode_codepoint-start_char;
+            else // format == 13
+               return start_glyph;
+         }
+      }
+      return 0; // not found
+   }
+   // @TODO
+   STBTT_assert(0);
+   return 0;
+}
+
+STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
+{
+   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
+}
+
+static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
+{
+   v->type = type;
+   v->x = (stbtt_int16) x;
+   v->y = (stbtt_int16) y;
+   v->cx = (stbtt_int16) cx;
+   v->cy = (stbtt_int16) cy;
+}
+
+static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
+{
+   int g1,g2;
+
+   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
+   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format
+
+   if (info->indexToLocFormat == 0) {
+      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
+      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
+   } else {
+      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
+      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
+   }
+
+   return g1==g2 ? -1 : g1; // if length is 0, return -1
+}
+
+STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+   int g = stbtt__GetGlyfOffset(info, glyph_index);
+   if (g < 0) return 0;
+
+   if (x0) *x0 = ttSHORT(info->data + g + 2);
+   if (y0) *y0 = ttSHORT(info->data + g + 4);
+   if (x1) *x1 = ttSHORT(info->data + g + 6);
+   if (y1) *y1 = ttSHORT(info->data + g + 8);
+   return 1;
+}
+
+STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
+{
+   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
+}
+
+STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
+{
+   stbtt_int16 numberOfContours;
+   int g = stbtt__GetGlyfOffset(info, glyph_index);
+   if (g < 0) return 1;
+   numberOfContours = ttSHORT(info->data + g);
+   return numberOfContours == 0;
+}
+
+static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
+    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
+{
+   if (start_off) {
+      if (was_off)
+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
+      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
+   } else {
+      if (was_off)
+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
+      else
+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
+   }
+   return num_vertices;
+}
+
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+   stbtt_int16 numberOfContours;
+   stbtt_uint8 *endPtsOfContours;
+   stbtt_uint8 *data = info->data;
+   stbtt_vertex *vertices=0;
+   int num_vertices=0;
+   int g = stbtt__GetGlyfOffset(info, glyph_index);
+
+   *pvertices = NULL;
+
+   if (g < 0) return 0;
+
+   numberOfContours = ttSHORT(data + g);
+
+   if (numberOfContours > 0) {
+      stbtt_uint8 flags=0,flagcount;
+      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
+      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
+      stbtt_uint8 *points;
+      endPtsOfContours = (data + g + 10);
+      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
+      points = data + g + 10 + numberOfContours * 2 + 2 + ins;
+
+      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
+
+      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need
+      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
+      if (vertices == 0)
+         return 0;
+
+      next_move = 0;
+      flagcount=0;
+
+      // in first pass, we load uninterpreted data into the allocated array
+      // above, shifted to the end of the array so we won't overwrite it when
+      // we create our final data starting from the front
+
+      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
+
+      // first load flags
+
+      for (i=0; i < n; ++i) {
+         if (flagcount == 0) {
+            flags = *points++;
+            if (flags & 8)
+               flagcount = *points++;
+         } else
+            --flagcount;
+         vertices[off+i].type = flags;
+      }
+
+      // now load x coordinates
+      x=0;
+      for (i=0; i < n; ++i) {
+         flags = vertices[off+i].type;
+         if (flags & 2) {
+            stbtt_int16 dx = *points++;
+            x += (flags & 16) ? dx : -dx; // ???
+         } else {
+            if (!(flags & 16)) {
+               x = x + (stbtt_int16) (points[0]*256 + points[1]);
+               points += 2;
+            }
+         }
+         vertices[off+i].x = (stbtt_int16) x;
+      }
+
+      // now load y coordinates
+      y=0;
+      for (i=0; i < n; ++i) {
+         flags = vertices[off+i].type;
+         if (flags & 4) {
+            stbtt_int16 dy = *points++;
+            y += (flags & 32) ? dy : -dy; // ???
+         } else {
+            if (!(flags & 32)) {
+               y = y + (stbtt_int16) (points[0]*256 + points[1]);
+               points += 2;
+            }
+         }
+         vertices[off+i].y = (stbtt_int16) y;
+      }
+
+      // now convert them to our format
+      num_vertices=0;
+      sx = sy = cx = cy = scx = scy = 0;
+      for (i=0; i < n; ++i) {
+         flags = vertices[off+i].type;
+         x     = (stbtt_int16) vertices[off+i].x;
+         y     = (stbtt_int16) vertices[off+i].y;
+
+         if (next_move == i) {
+            if (i != 0)
+               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
+
+            // now start the new one               
+            start_off = !(flags & 1);
+            if (start_off) {
+               // if we start off with an off-curve point, then when we need to find a point on the curve
+               // where we can start, and we need to save some state for when we wraparound.
+               scx = x;
+               scy = y;
+               if (!(vertices[off+i+1].type & 1)) {
+                  // next point is also a curve point, so interpolate an on-point curve
+                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
+                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
+               } else {
+                  // otherwise just use the next point as our start point
+                  sx = (stbtt_int32) vertices[off+i+1].x;
+                  sy = (stbtt_int32) vertices[off+i+1].y;
+                  ++i; // we're using point i+1 as the starting point, so skip it
+               }
+            } else {
+               sx = x;
+               sy = y;
+            }
+            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
+            was_off = 0;
+            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
+            ++j;
+         } else {
+            if (!(flags & 1)) { // if it's a curve
+               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
+               cx = x;
+               cy = y;
+               was_off = 1;
+            } else {
+               if (was_off)
+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
+               else
+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
+               was_off = 0;
+            }
+         }
+      }
+      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
+   } else if (numberOfContours == -1) {
+      // Compound shapes.
+      int more = 1;
+      stbtt_uint8 *comp = data + g + 10;
+      num_vertices = 0;
+      vertices = 0;
+      while (more) {
+         stbtt_uint16 flags, gidx;
+         int comp_num_verts = 0, i;
+         stbtt_vertex *comp_verts = 0, *tmp = 0;
+         float mtx[6] = {1,0,0,1,0,0}, m, n;
+         
+         flags = ttSHORT(comp); comp+=2;
+         gidx = ttSHORT(comp); comp+=2;
+
+         if (flags & 2) { // XY values
+            if (flags & 1) { // shorts
+               mtx[4] = ttSHORT(comp); comp+=2;
+               mtx[5] = ttSHORT(comp); comp+=2;
+            } else {
+               mtx[4] = ttCHAR(comp); comp+=1;
+               mtx[5] = ttCHAR(comp); comp+=1;
+            }
+         }
+         else {
+            // @TODO handle matching point
+            STBTT_assert(0);
+         }
+         if (flags & (1<<3)) { // WE_HAVE_A_SCALE
+            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+            mtx[1] = mtx[2] = 0;
+         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
+            mtx[1] = mtx[2] = 0;
+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
+            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
+            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
+         }
+         
+         // Find transformation scales.
+         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
+         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
+
+         // Get indexed glyph.
+         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
+         if (comp_num_verts > 0) {
+            // Transform vertices.
+            for (i = 0; i < comp_num_verts; ++i) {
+               stbtt_vertex* v = &comp_verts[i];
+               stbtt_vertex_type x,y;
+               x=v->x; y=v->y;
+               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
+               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
+               x=v->cx; y=v->cy;
+               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
+               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
+            }
+            // Append vertices.
+            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
+            if (!tmp) {
+               if (vertices) STBTT_free(vertices, info->userdata);
+               if (comp_verts) STBTT_free(comp_verts, info->userdata);
+               return 0;
+            }
+            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
+            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
+            if (vertices) STBTT_free(vertices, info->userdata);
+            vertices = tmp;
+            STBTT_free(comp_verts, info->userdata);
+            num_vertices += comp_num_verts;
+         }
+         // More components ?
+         more = flags & (1<<5);
+      }
+   } else if (numberOfContours < 0) {
+      // @TODO other compound variations?
+      STBTT_assert(0);
+   } else {
+      // numberOfCounters == 0, do nothing
+   }
+
+   *pvertices = vertices;
+   return num_vertices;
+}
+
+STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
+{
+   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
+   if (glyph_index < numOfLongHorMetrics) {
+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);
+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
+   } else {
+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
+   }
+}
+
+STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
+{
+   stbtt_uint8 *data = info->data + info->kern;
+   stbtt_uint32 needle, straw;
+   int l, r, m;
+
+   // we only look at the first table. it must be 'horizontal' and format 0.
+   if (!info->kern)
+      return 0;
+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
+      return 0;
+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
+      return 0;
+
+   l = 0;
+   r = ttUSHORT(data+10) - 1;
+   needle = glyph1 << 16 | glyph2;
+   while (l <= r) {
+      m = (l + r) >> 1;
+      straw = ttULONG(data+18+(m*6)); // note: unaligned read
+      if (needle < straw)
+         r = m - 1;
+      else if (needle > straw)
+         l = m + 1;
+      else
+         return ttSHORT(data+22+(m*6));
+   }
+   return 0;
+}
+
+STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
+{
+   if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs
+      return 0;
+   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
+}
+
+STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
+{
+   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
+}
+
+STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
+{
+   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);
+   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
+   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
+}
+
+STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
+{
+   *x0 = ttSHORT(info->data + info->head + 36);
+   *y0 = ttSHORT(info->data + info->head + 38);
+   *x1 = ttSHORT(info->data + info->head + 40);
+   *y1 = ttSHORT(info->data + info->head + 42);
+}
+
+STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
+{
+   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
+   return (float) height / fheight;
+}
+
+STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
+{
+   int unitsPerEm = ttUSHORT(info->data + info->head + 18);
+   return pixels / unitsPerEm;
+}
+
+STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
+{
+   STBTT_free(v, info->userdata);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// antialiasing software rasterizer
+//
+
+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+   int x0,y0,x1,y1;
+   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
+      // e.g. space character
+      if (ix0) *ix0 = 0;
+      if (iy0) *iy0 = 0;
+      if (ix1) *ix1 = 0;
+      if (iy1) *iy1 = 0;
+   } else {
+      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
+      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
+      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
+      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
+      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
+   }
+}
+
+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
+}
+
+STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
+}
+
+STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+   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;
+   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;
+
+#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 *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);
+   if (!z) return z;
+   
+   // round dx down to avoid overshooting
+   if (dxdy < 0)
+      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
+   else
+      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->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 = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
+   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
+static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
+{
+   // non-zero winding fill
+   int x0=0, w=0;
+
+   while (e) {
+      if (w == 0) {
+         // if we're currently at zero, we need to record the edge start point
+         x0 = e->x; w += e->direction;
+      } else {
+         int x1 = e->x; w += e->direction;
+         // if we went to zero, we need to draw
+         if (w == 0) {
+            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 >> STBTT_FIXSHIFT);
+               } else {
+                  if (i >= 0) // add antialiasing for x0
+                     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 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
+                  else
+                     j = len; // clip
+
+                  for (++i; i < j; ++i) // fill pixels between x0 and x1
+                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
+               }
+            }
+         }
+      }
+      
+      e = e->next;
+   }
+}
+
+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, 0, 0 };
+   stbtt__active_edge *active = NULL;
+   int y,j=0;
+   int max_weight = (255 / vsubsample);  // weight per vertical scanline
+   int s; // vertical subsample index
+   unsigned char scanline_data[512], *scanline;
+
+   if (result->w > 512)
+      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
+   else
+      scanline = scanline_data;
+
+   y = off_y * vsubsample;
+   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
+
+   while (j < result->h) {
+      STBTT_memset(scanline, 0, result->w);
+      for (s=0; s < vsubsample; ++s) {
+         // find center of pixel for this scanline
+         float scan_y = y + 0.5f;
+         stbtt__active_edge **step = &active;
+
+         // update all active edges;
+         // remove all active edges that terminate before the center of this scanline
+         while (*step) {
+            stbtt__active_edge * z = *step;
+            if (z->ey <= scan_y) {
+               *step = z->next; // delete from list
+               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
+            }
+         }
+
+         // resort the list if needed
+         for(;;) {
+            int changed=0;
+            step = &active;
+            while (*step && (*step)->next) {
+               if ((*step)->x > (*step)->next->x) {
+                  stbtt__active_edge *t = *step;
+                  stbtt__active_edge *q = t->next;
+
+                  t->next = q->next;
+                  q->next = t;
+                  *step = q;
+                  changed = 1;
+               }
+               step = &(*step)->next;
+            }
+            if (!changed) break;
+         }
+
+         // 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 = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
+               // find insertion point
+               if (active == NULL)
+                  active = z;
+               else if (z->x < active->x) {
+                  // insert at front
+                  z->next = active;
+                  active = z;
+               } else {
+                  // find thing to insert AFTER
+                  stbtt__active_edge *p = active;
+                  while (p->next && p->next->x < z->x)
+                     p = p->next;
+                  // at this point, p->next->x is NOT < z->x
+                  z->next = p->next;
+                  p->next = z;
+               }
+            }
+            ++e;
+         }
+
+         // now process all active edges in XOR fashion
+         if (active)
+            stbtt__fill_active_edges(scanline, result->w, active, max_weight);
+
+         ++y;
+      }
+      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
+      ++j;
+   }
+
+   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;
+   STBTT_assert(y0 < y1);
+   STBTT_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)
+      STBTT_assert(x1 <= x+1);
+   else if (x0 == x+1)
+      STBTT_assert(x1 >= x);
+   else if (x0 <= x)
+      STBTT_assert(x1 <= x);
+   else if (x0 >= x+1)
+      STBTT_assert(x1 >= x+1);
+   else
+      STBTT_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 {
+      STBTT_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
+      STBTT_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 sy0,sy1;
+         float dy = e->fdy;
+         STBTT_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);
+            sy0 = e->sy;
+         } else {
+            x_top = x0;
+            sy0 = y_top;
+         }
+         if (e->ey < y_bottom) {
+            x_bottom = x0 + dx * (e->ey - y_top);
+            sy1 = e->ey;
+         } else {
+            x_bottom = xb;
+            sy1 = 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 = sy1 - sy0;
+               STBTT_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;
+                  sy0 = y_bottom - (sy0 - y_top);
+                  sy1 = y_bottom - (sy1 - y_top);
+                  t = sy0, sy0 = sy1, sy1 = 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-sy0);
+               // 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));
+
+               STBTT_assert(fabs(area) <= 1.01f);
+
+               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
+
+               scanline_fill[x2] += sign * (sy1-sy0);
+            }
+         } 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.
+               //
+               // the old way of doing this found the intersections with the left & right edges,
+               // then used some simple logic to produce up to three segments in sorted order
+               // from top-to-bottom. however, this had a problem: if an x edge was epsilon
+               // across the x border, then the corresponding y position might not be distinct
+               // from the other y segment, and it might ignored as an empty segment. to avoid
+               // that, we need to explicitly produce segments based on x positions.
+
+               // rename variables to clear pairs
+               float y0 = y_top;
+               float x1 = (float) (x);
+               float x2 = (float) (x+1);
+               float x3 = xb;
+               float y3 = y_bottom;
+               float y1,y2;
+
+               // x = e->x + e->dx * (y-y_top)
+               // (y-y_top) = (x - e->x) / e->dx
+               // y = (x - e->x) / e->dx + y_top
+               y1 = (x - x0) / dx + y_top;
+               y2 = (x+1 - x0) / dx + y_top;
+
+               if (x0 < x1 && x3 > x2) {         // three segments descending down-right
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
+               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
+               } else {  // one segment
+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
+               }
+            }
+         }
+      }
+      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, 0, 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) {
+         if (e->y0 != e->y1) {
+            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
+            STBTT_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 void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
+{
+   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;
+   }
+}
+
+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
+{
+   float x,y;
+} stbtt__point;
+
+static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
+{
+   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
+   n = 0;
+   for (i=0; i < windings; ++i)
+      n += wcount[i];
+
+   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel
+   if (e == 0) return;
+   n = 0;
+
+   m=0;
+   for (i=0; i < windings; ++i) {
+      stbtt__point *p = pts + m;
+      m += wcount[i];
+      j = wcount[i]-1;
+      for (k=0; k < wcount[i]; j=k++) {
+         int a=k,b=j;
+         // skip the edge if horizontal
+         if (p[j].y == p[k].y)
+            continue;
+         // add edge from j to k to the list
+         e[n].invert = 0;
+         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
+            e[n].invert = 1;
+            a=j,b=k;
+         }
+         e[n].x0 = p[a].x * scale_x + shift_x;
+         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
+         e[n].x1 = p[b].x * scale_x + shift_x;
+         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
+         ++n;
+      }
+   }
+
+   // 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_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);
+
+   STBTT_free(e, userdata);
+}
+
+static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
+{
+   if (!points) return; // during first pass, it's unallocated
+   points[n].x = x;
+   points[n].y = y;
+}
+
+// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
+static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
+{
+   // midpoint
+   float mx = (x0 + 2*x1 + x2)/4;
+   float my = (y0 + 2*y1 + y2)/4;
+   // versus directly drawn line
+   float dx = (x0+x2)/2 - mx;
+   float dy = (y0+y2)/2 - my;
+   if (n > 16) // 65536 segments on one curve better be enough!
+      return 1;
+   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
+      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
+      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
+   } else {
+      stbtt__add_point(points, *num_points,x2,y2);
+      *num_points = *num_points+1;
+   }
+   return 1;
+}
+
+// returns number of contours
+static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
+{
+   stbtt__point *points=0;
+   int num_points=0;
+
+   float objspace_flatness_squared = objspace_flatness * objspace_flatness;
+   int i,n=0,start=0, pass;
+
+   // count how many "moves" there are to get the contour count
+   for (i=0; i < num_verts; ++i)
+      if (vertices[i].type == STBTT_vmove)
+         ++n;
+
+   *num_contours = n;
+   if (n == 0) return 0;
+
+   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
+
+   if (*contour_lengths == 0) {
+      *num_contours = 0;
+      return 0;
+   }
+
+   // make two passes through the points so we don't need to realloc
+   for (pass=0; pass < 2; ++pass) {
+      float x=0,y=0;
+      if (pass == 1) {
+         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
+         if (points == NULL) goto error;
+      }
+      num_points = 0;
+      n= -1;
+      for (i=0; i < num_verts; ++i) {
+         switch (vertices[i].type) {
+            case STBTT_vmove:
+               // start the next contour
+               if (n >= 0)
+                  (*contour_lengths)[n] = num_points - start;
+               ++n;
+               start = num_points;
+
+               x = vertices[i].x, y = vertices[i].y;
+               stbtt__add_point(points, num_points++, x,y);
+               break;
+            case STBTT_vline:
+               x = vertices[i].x, y = vertices[i].y;
+               stbtt__add_point(points, num_points++, x, y);
+               break;
+            case STBTT_vcurve:
+               stbtt__tesselate_curve(points, &num_points, x,y,
+                                        vertices[i].cx, vertices[i].cy,
+                                        vertices[i].x,  vertices[i].y,
+                                        objspace_flatness_squared, 0);
+               x = vertices[i].x, y = vertices[i].y;
+               break;
+         }
+      }
+      (*contour_lengths)[n] = num_points - start;
+   }
+
+   return points;
+error:
+   STBTT_free(points, userdata);
+   STBTT_free(*contour_lengths, userdata);
+   *contour_lengths = 0;
+   *num_contours = 0;
+   return NULL;
+}
+
+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
+{
+   float scale = scale_x > scale_y ? scale_y : scale_x;
+   int winding_count, *winding_lengths;
+   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
+   if (windings) {
+      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
+      STBTT_free(winding_lengths, userdata);
+      STBTT_free(windings, userdata);
+   }
+}
+
+STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
+{
+   STBTT_free(bitmap, userdata);
+}
+
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
+{
+   int ix0,iy0,ix1,iy1;
+   stbtt__bitmap gbm;
+   stbtt_vertex *vertices;   
+   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+
+   if (scale_x == 0) scale_x = scale_y;
+   if (scale_y == 0) {
+      if (scale_x == 0) return NULL;
+      scale_y = scale_x;
+   }
+
+   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
+
+   // now we get the size
+   gbm.w = (ix1 - ix0);
+   gbm.h = (iy1 - iy0);
+   gbm.pixels = NULL; // in case we error
+
+   if (width ) *width  = gbm.w;
+   if (height) *height = gbm.h;
+   if (xoff  ) *xoff   = ix0;
+   if (yoff  ) *yoff   = iy0;
+   
+   if (gbm.w && gbm.h) {
+      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
+      if (gbm.pixels) {
+         gbm.stride = gbm.w;
+
+         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
+      }
+   }
+   STBTT_free(vertices, info->userdata);
+   return gbm.pixels;
+}   
+
+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
+{
+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
+}
+
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
+{
+   int ix0,iy0;
+   stbtt_vertex *vertices;
+   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+   stbtt__bitmap gbm;   
+
+   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
+   gbm.pixels = output;
+   gbm.w = out_w;
+   gbm.h = out_h;
+   gbm.stride = out_stride;
+
+   if (gbm.w && gbm.h)
+      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
+
+   STBTT_free(vertices, info->userdata);
+}
+
+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
+{
+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
+}
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
+{
+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
+}   
+
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
+{
+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
+}
+
+STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
+{
+   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
+}   
+
+STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
+{
+   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// bitmap baking
+//
+// This is SUPER-CRAPPY packing to keep source code small
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
+                                float pixel_height,                     // height of font in pixels
+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
+                                int first_char, int num_chars,          // characters to bake
+                                stbtt_bakedchar *chardata)
+{
+   float scale;
+   int x,y,bottom_y, i;
+   stbtt_fontinfo f;
+   if (!stbtt_InitFont(&f, data, offset))
+      return -1;
+   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
+   x=y=1;
+   bottom_y = 1;
+
+   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
+
+   for (i=0; i < num_chars; ++i) {
+      int advance, lsb, x0,y0,x1,y1,gw,gh;
+      int g = stbtt_FindGlyphIndex(&f, first_char + i);
+      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
+      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
+      gw = x1-x0;
+      gh = y1-y0;
+      if (x + gw + 1 >= pw)
+         y = bottom_y, x = 1; // advance to next row
+      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
+         return -i;
+      STBTT_assert(x+gw < pw);
+      STBTT_assert(y+gh < ph);
+      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
+      chardata[i].x0 = (stbtt_int16) x;
+      chardata[i].y0 = (stbtt_int16) y;
+      chardata[i].x1 = (stbtt_int16) (x + gw);
+      chardata[i].y1 = (stbtt_int16) (y + gh);
+      chardata[i].xadvance = scale * advance;
+      chardata[i].xoff     = (float) x0;
+      chardata[i].yoff     = (float) y0;
+      x = x + gw + 1;
+      if (y+gh+1 > bottom_y)
+         bottom_y = y+gh+1;
+   }
+   return bottom_y;
+}
+
+STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
+{
+   float d3d_bias = opengl_fillrule ? 0 : -0.5f;
+   float ipw = 1.0f / pw, iph = 1.0f / ph;
+   stbtt_bakedchar *b = chardata + char_index;
+   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
+   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
+
+   q->x0 = round_x + d3d_bias;
+   q->y0 = round_y + d3d_bias;
+   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
+   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
+
+   q->s0 = b->x0 * ipw;
+   q->t0 = b->y0 * iph;
+   q->s1 = b->x1 * ipw;
+   q->t1 = b->y1 * iph;
+
+   *xpos += b->xadvance;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// rectangle packing replacement routines if you don't have stb_rect_pack.h
+//
+
+#ifndef STB_RECT_PACK_VERSION
+#ifdef _MSC_VER
+#define STBTT__NOTUSED(v)  (void)(v)
+#else
+#define STBTT__NOTUSED(v)  (void)sizeof(v)
+#endif
+
+typedef int stbrp_coord;
+
+////////////////////////////////////////////////////////////////////////////////////
+//                                                                                //
+//                                                                                //
+// COMPILER WARNING ?!?!?                                                         //
+//                                                                                //
+//                                                                                //
+// if you get a compile warning due to these symbols being defined more than      //
+// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //
+//                                                                                //
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct
+{
+   int width,height;
+   int x,y,bottom_y;
+} stbrp_context;
+
+typedef struct
+{
+   unsigned char x;
+} stbrp_node;
+
+struct stbrp_rect
+{
+   stbrp_coord x,y;
+   int id,w,h,was_packed;
+};
+
+static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
+{
+   con->width  = pw;
+   con->height = ph;
+   con->x = 0;
+   con->y = 0;
+   con->bottom_y = 0;
+   STBTT__NOTUSED(nodes);
+   STBTT__NOTUSED(num_nodes);   
+}
+
+static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
+{
+   int i;
+   for (i=0; i < num_rects; ++i) {
+      if (con->x + rects[i].w > con->width) {
+         con->x = 0;
+         con->y = con->bottom_y;
+      }
+      if (con->y + rects[i].h > con->height)
+         break;
+      rects[i].x = con->x;
+      rects[i].y = con->y;
+      rects[i].was_packed = 1;
+      con->x += rects[i].w;
+      if (con->y + rects[i].h > con->bottom_y)
+         con->bottom_y = con->y + rects[i].h;
+   }
+   for (   ; i < num_rects; ++i)
+      rects[i].was_packed = 0;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// bitmap baking
+//
+// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
+// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
+
+STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
+{
+   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);
+   int            num_nodes = pw - padding;
+   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);
+
+   if (context == NULL || nodes == NULL) {
+      if (context != NULL) STBTT_free(context, alloc_context);
+      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);
+      return 0;
+   }
+
+   spc->user_allocator_context = alloc_context;
+   spc->width = pw;
+   spc->height = ph;
+   spc->pixels = pixels;
+   spc->pack_info = context;
+   spc->nodes = nodes;
+   spc->padding = padding;
+   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
+   spc->h_oversample = 1;
+   spc->v_oversample = 1;
+
+   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
+
+   if (pixels)
+      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
+
+   return 1;
+}
+
+STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)
+{
+   STBTT_free(spc->nodes    , spc->user_allocator_context);
+   STBTT_free(spc->pack_info, spc->user_allocator_context);
+}
+
+STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)
+{
+   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
+   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
+   if (h_oversample <= STBTT_MAX_OVERSAMPLE)
+      spc->h_oversample = h_oversample;
+   if (v_oversample <= STBTT_MAX_OVERSAMPLE)
+      spc->v_oversample = v_oversample;
+}
+
+#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)
+
+static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
+{
+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];
+   int safe_w = w - kernel_width;
+   int j;
+   for (j=0; j < h; ++j) {
+      int i;
+      unsigned int total;
+      STBTT_memset(buffer, 0, kernel_width);
+
+      total = 0;
+
+      // make kernel_width a constant in common cases so compiler can optimize out the divide
+      switch (kernel_width) {
+         case 2:
+            for (i=0; i <= safe_w; ++i) {
+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+               pixels[i] = (unsigned char) (total / 2);
+            }
+            break;
+         case 3:
+            for (i=0; i <= safe_w; ++i) {
+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+               pixels[i] = (unsigned char) (total / 3);
+            }
+            break;
+         case 4:
+            for (i=0; i <= safe_w; ++i) {
+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+               pixels[i] = (unsigned char) (total / 4);
+            }
+            break;
+         case 5:
+            for (i=0; i <= safe_w; ++i) {
+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+               pixels[i] = (unsigned char) (total / 5);
+            }
+            break;
+         default:
+            for (i=0; i <= safe_w; ++i) {
+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
+               pixels[i] = (unsigned char) (total / kernel_width);
+            }
+            break;
+      }
+
+      for (; i < w; ++i) {
+         STBTT_assert(pixels[i] == 0);
+         total -= buffer[i & STBTT__OVER_MASK];
+         pixels[i] = (unsigned char) (total / kernel_width);
+      }
+
+      pixels += stride_in_bytes;
+   }
+}
+
+static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
+{
+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];
+   int safe_h = h - kernel_width;
+   int j;
+   for (j=0; j < w; ++j) {
+      int i;
+      unsigned int total;
+      STBTT_memset(buffer, 0, kernel_width);
+
+      total = 0;
+
+      // make kernel_width a constant in common cases so compiler can optimize out the divide
+      switch (kernel_width) {
+         case 2:
+            for (i=0; i <= safe_h; ++i) {
+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
+            }
+            break;
+         case 3:
+            for (i=0; i <= safe_h; ++i) {
+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
+            }
+            break;
+         case 4:
+            for (i=0; i <= safe_h; ++i) {
+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
+            }
+            break;
+         case 5:
+            for (i=0; i <= safe_h; ++i) {
+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
+            }
+            break;
+         default:
+            for (i=0; i <= safe_h; ++i) {
+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
+               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
+            }
+            break;
+      }
+
+      for (; i < h; ++i) {
+         STBTT_assert(pixels[i*stride_in_bytes] == 0);
+         total -= buffer[i & STBTT__OVER_MASK];
+         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
+      }
+
+      pixels += 1;
+   }
+}
+
+static float stbtt__oversample_shift(int oversample)
+{
+   if (!oversample)
+      return 0.0f;
+
+   // The prefilter is a box filter of width "oversample",
+   // which shifts phase by (oversample - 1)/2 pixels in
+   // oversampled space. We want to shift in the opposite
+   // direction to counter this.
+   return (float)-(oversample - 1) / (2.0f * (float)oversample);
+}
+
+// rects array must be big enough to accommodate all characters in the given ranges
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+{
+   int i,j,k;
+
+   k=0;
+   for (i=0; i < num_ranges; ++i) {
+      float fh = ranges[i].font_size;
+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
+      ranges[i].h_oversample = (unsigned char) spc->h_oversample;
+      ranges[i].v_oversample = (unsigned char) spc->v_oversample;
+      for (j=0; j < ranges[i].num_chars; ++j) {
+         int x0,y0,x1,y1;
+         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
+         int glyph = stbtt_FindGlyphIndex(info, codepoint);
+         stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
+                                         scale * spc->h_oversample,
+                                         scale * spc->v_oversample,
+                                         0,0,
+                                         &x0,&y0,&x1,&y1);
+         rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
+         rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
+         ++k;
+      }
+   }
+
+   return k;
+}
+
+// rects array must be big enough to accommodate all characters in the given ranges
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+{
+   int i,j,k, return_value = 1;
+
+   // save current values
+   int old_h_over = spc->h_oversample;
+   int old_v_over = spc->v_oversample;
+
+   k = 0;
+   for (i=0; i < num_ranges; ++i) {
+      float fh = ranges[i].font_size;
+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
+      float recip_h,recip_v,sub_x,sub_y;
+      spc->h_oversample = ranges[i].h_oversample;
+      spc->v_oversample = ranges[i].v_oversample;
+      recip_h = 1.0f / spc->h_oversample;
+      recip_v = 1.0f / spc->v_oversample;
+      sub_x = stbtt__oversample_shift(spc->h_oversample);
+      sub_y = stbtt__oversample_shift(spc->v_oversample);
+      for (j=0; j < ranges[i].num_chars; ++j) {
+         stbrp_rect *r = &rects[k];
+         if (r->was_packed) {
+            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
+            int advance, lsb, x0,y0,x1,y1;
+            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
+            int glyph = stbtt_FindGlyphIndex(info, codepoint);
+            stbrp_coord pad = (stbrp_coord) spc->padding;
+
+            // pad on left and top
+            r->x += pad;
+            r->y += pad;
+            r->w -= pad;
+            r->h -= pad;
+            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
+            stbtt_GetGlyphBitmapBox(info, glyph,
+                                    scale * spc->h_oversample,
+                                    scale * spc->v_oversample,
+                                    &x0,&y0,&x1,&y1);
+            stbtt_MakeGlyphBitmapSubpixel(info,
+                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,
+                                          r->w - spc->h_oversample+1,
+                                          r->h - spc->v_oversample+1,
+                                          spc->stride_in_bytes,
+                                          scale * spc->h_oversample,
+                                          scale * spc->v_oversample,
+                                          0,0,
+                                          glyph);
+
+            if (spc->h_oversample > 1)
+               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
+                                  r->w, r->h, spc->stride_in_bytes,
+                                  spc->h_oversample);
+
+            if (spc->v_oversample > 1)
+               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
+                                  r->w, r->h, spc->stride_in_bytes,
+                                  spc->v_oversample);
+
+            bc->x0       = (stbtt_int16)  r->x;
+            bc->y0       = (stbtt_int16)  r->y;
+            bc->x1       = (stbtt_int16) (r->x + r->w);
+            bc->y1       = (stbtt_int16) (r->y + r->h);
+            bc->xadvance =                scale * advance;
+            bc->xoff     =       (float)  x0 * recip_h + sub_x;
+            bc->yoff     =       (float)  y0 * recip_v + sub_y;
+            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;
+            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;
+         } else {
+            return_value = 0; // if any fail, report failure
+         }
+
+         ++k;
+      }
+   }
+
+   // restore original values
+   spc->h_oversample = old_h_over;
+   spc->v_oversample = old_v_over;
+
+   return return_value;
+}
+
+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
+{
+   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
+}
+
+STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
+{
+   stbtt_fontinfo info;
+   int i,j,n, return_value = 1;
+   //stbrp_context *context = (stbrp_context *) spc->pack_info;
+   stbrp_rect    *rects;
+
+   // flag all characters as NOT packed
+   for (i=0; i < num_ranges; ++i)
+      for (j=0; j < ranges[i].num_chars; ++j)
+         ranges[i].chardata_for_range[j].x0 =
+         ranges[i].chardata_for_range[j].y0 =
+         ranges[i].chardata_for_range[j].x1 =
+         ranges[i].chardata_for_range[j].y1 = 0;
+
+   n = 0;
+   for (i=0; i < num_ranges; ++i)
+      n += ranges[i].num_chars;
+         
+   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
+   if (rects == NULL)
+      return 0;
+
+   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
+
+   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
+
+   stbtt_PackFontRangesPackRects(spc, rects, n);
+  
+   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
+
+   STBTT_free(rects, spc->user_allocator_context);
+   return return_value;
+}
+
+STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
+{
+   stbtt_pack_range range;
+   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
+   range.array_of_unicode_codepoints = NULL;
+   range.num_chars                   = num_chars_in_range;
+   range.chardata_for_range          = chardata_for_range;
+   range.font_size                   = font_size;
+   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
+}
+
+STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
+{
+   float ipw = 1.0f / pw, iph = 1.0f / ph;
+   stbtt_packedchar *b = chardata + char_index;
+
+   if (align_to_integer) {
+      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
+      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
+      q->x0 = x;
+      q->y0 = y;
+      q->x1 = x + b->xoff2 - b->xoff;
+      q->y1 = y + b->yoff2 - b->yoff;
+   } else {
+      q->x0 = *xpos + b->xoff;
+      q->y0 = *ypos + b->yoff;
+      q->x1 = *xpos + b->xoff2;
+      q->y1 = *ypos + b->yoff2;
+   }
+
+   q->s0 = b->x0 * ipw;
+   q->t0 = b->y0 * iph;
+   q->s1 = b->x1 * ipw;
+   q->t1 = b->y1 * iph;
+
+   *xpos += b->xadvance;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// font name matching -- recommended not to use this
+//
+
+// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) 
+{
+   stbtt_int32 i=0;
+
+   // convert utf16 to utf8 and compare the results while converting
+   while (len2) {
+      stbtt_uint16 ch = s2[0]*256 + s2[1];
+      if (ch < 0x80) {
+         if (i >= len1) return -1;
+         if (s1[i++] != ch) return -1;
+      } else if (ch < 0x800) {
+         if (i+1 >= len1) return -1;
+         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
+         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
+      } else if (ch >= 0xd800 && ch < 0xdc00) {
+         stbtt_uint32 c;
+         stbtt_uint16 ch2 = s2[2]*256 + s2[3];
+         if (i+3 >= len1) return -1;
+         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
+         if (s1[i++] != 0xf0 + (c >> 18)) return -1;
+         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
+         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;
+         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;
+         s2 += 2; // plus another 2 below
+         len2 -= 2;
+      } else if (ch >= 0xdc00 && ch < 0xe000) {
+         return -1;
+      } else {
+         if (i+2 >= len1) return -1;
+         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
+         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
+         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;
+      }
+      s2 += 2;
+      len2 -= 2;
+   }
+   return i;
+}
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 
+{
+   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2);
+}
+
+// returns results in whatever encoding you request... but note that 2-byte encodings
+// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
+{
+   stbtt_int32 i,count,stringOffset;
+   stbtt_uint8 *fc = font->data;
+   stbtt_uint32 offset = font->fontstart;
+   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
+   if (!nm) return NULL;
+
+   count = ttUSHORT(fc+nm+2);
+   stringOffset = nm + ttUSHORT(fc+nm+4);
+   for (i=0; i < count; ++i) {
+      stbtt_uint32 loc = nm + 6 + 12 * i;
+      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
+          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
+         *length = ttUSHORT(fc+loc+8);
+         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
+      }
+   }
+   return NULL;
+}
+
+static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
+{
+   stbtt_int32 i;
+   stbtt_int32 count = ttUSHORT(fc+nm+2);
+   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
+
+   for (i=0; i < count; ++i) {
+      stbtt_uint32 loc = nm + 6 + 12 * i;
+      stbtt_int32 id = ttUSHORT(fc+loc+6);
+      if (id == target_id) {
+         // find the encoding
+         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
+
+         // is this a Unicode encoding?
+         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
+            stbtt_int32 slen = ttUSHORT(fc+loc+8);
+            stbtt_int32 off = ttUSHORT(fc+loc+10);
+
+            // check if there's a prefix match
+            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
+            if (matchlen >= 0) {
+               // check for target_id+1 immediately following, with same encoding & language
+               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
+                  slen = ttUSHORT(fc+loc+12+8);
+                  off = ttUSHORT(fc+loc+12+10);
+                  if (slen == 0) {
+                     if (matchlen == nlen)
+                        return 1;
+                  } else if (matchlen < nlen && name[matchlen] == ' ') {
+                     ++matchlen;
+                     if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
+                        return 1;
+                  }
+               } else {
+                  // if nothing immediately following
+                  if (matchlen == nlen)
+                     return 1;
+               }
+            }
+         }
+
+         // @TODO handle other encodings
+      }
+   }
+   return 0;
+}
+
+static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
+{
+   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
+   stbtt_uint32 nm,hd;
+   if (!stbtt__isfont(fc+offset)) return 0;
+
+   // check italics/bold/underline flags in macStyle...
+   if (flags) {
+      hd = stbtt__find_table(fc, offset, "head");
+      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
+   }
+
+   nm = stbtt__find_table(fc, offset, "name");
+   if (!nm) return 0;
+
+   if (flags) {
+      // if we checked the macStyle flags, then just check the family and ignore the subfamily
+      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;
+      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;
+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
+   } else {
+      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;
+      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;
+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
+   }
+
+   return 0;
+}
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)
+{
+   stbtt_int32 i;
+   for (i=0;;++i) {
+      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
+      if (off < 0) return off;
+      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
+         return off;
+   }
+}
+
+#endif // STB_TRUETYPE_IMPLEMENTATION
+
+
+// FULL VERSION HISTORY
+//
+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
+//                     allow PackFontRanges to pack and render in separate phases;
+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
+//                     fixed an assert() bug in the new rasterizer
+//                     replace assert() with STBTT_assert() in new rasterizer
+//   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
+//                        non-oversampled; STBTT_POINT_SIZE for packed case only
+//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
+//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
+//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID
+//   0.8b (2014-07-07) fix a warning
+//   0.8  (2014-05-25) fix a few more warnings
+//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
+//   0.6c (2012-07-24) improve documentation
+//   0.6b (2012-07-20) fix a few more warnings
+//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
+//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
+//   0.5  (2011-12-09) bugfixes:
+//                        subpixel glyph renderer computed wrong bounding box
+//                        first vertex of shape can be off-curve (FreeSans)
+//   0.4b (2011-12-03) fixed an error in the font baking example
+//   0.4  (2011-12-01) kerning, subpixel rendering (tor)
+//                    bugfixes for:
+//                        codepoint-to-glyph conversion using table fmt=12
+//                        codepoint-to-glyph conversion using table fmt=4
+//                        stbtt_GetBakedQuad with non-square texture (Zer)
+//                    updated Hello World! sample to use kerning and subpixel
+//                    fixed some warnings
+//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)
+//                    userdata, malloc-from-userdata, non-zero fill (stb)
+//   0.2  (2009-03-11) Fix unsigned/signed char warnings
+//   0.1  (2009-03-09) First public release
+//

+ 35 - 0
modules/stb-truetype/stb-truetype.monkey2

@@ -0,0 +1,35 @@
+
+Namespace stb.truetype
+
+#Import "native/stb_truetype.c"
+#Import "native/stb_truetype.h"
+
+Extern
+
+Struct stbtt_fontinfo
+End
+
+Struct stbtt_bakedchar
+	Field x0:UShort
+	Field y0:UShort
+	Field x1:UShort
+	Field y1:UShort
+	Field xoff:Float
+	Field yoff:Float
+	Field xadvance:Float
+End
+
+Function stbtt_InitFont:Int( info:stbtt_fontinfo Ptr,data:UByte Ptr,offset:Int )
+Function stbtt_FindGlyphIndex:Int( info:stbtt_fontinfo Ptr,unicode_codepoint:Int )
+Function stbtt_ScaleForPixelHeight:Float( info:stbtt_fontinfo Ptr,pixels:Float )
+
+Function stbtt_GetFontVMetrics:Void( info:stbtt_fontinfo Ptr,ascent:Int Ptr,descent:Int Ptr,lineGap:Int Ptr )
+Function stbtt_GetCodepointHMetrics:Void( info:stbtt_fontinfo Ptr,codepoint:Int,advanceWidth:Int Ptr,leftSideBearing:Int Ptr )
+Function stbtt_GetCodepointKernAdvance:Int( info:stbtt_fontinfo Ptr,ch1:Int,ch2:Int )
+
+Function stbtt_GetGlyphHMetrics:Void( info:stbtt_fontinfo Ptr,glyph:Int,advanceWidth:Int Ptr,leftSideBearing:Int Ptr )
+
+Function stbtt_MakeGlyphBitmap:Void( info:stbtt_fontinfo Ptr,output:UByte Ptr,out_w:Int,out_h:Int,out_stride:Int,scale_x:Float,scale_y:Float,glyph:Int )
+Function stbtt_GetGlyphBitmapBox:Void( info:stbtt_fontinfo Ptr,glyph:Int,scale_x:Float,scale_y:Float,ix0:Int Ptr,iy0:Int Ptr,ix1:Int Ptr,iy1:Int Ptr )
+
+Function stbtt_BakeFontBitmap( data:UByte Ptr,offset:Int,pixel_height:Float,pixels:UByte Ptr,pw:Int,ph:Int,first_char:Int,num_chars:Int,chardata:stbtt_bakedchar Ptr )

+ 10 - 9
modules/std/byteorder.monkey2

@@ -1,15 +1,16 @@
 
-Namespace std
+Namespace std.memory
+
+#rem monkeydoc ByteOrder enumeration.
+
+| ByterOrder		| Description 
+|:------------------|:-----------
+| `LittleEndian`	| Least significant byte first.
+| `BigEndian`		| Most significant byte first.
 
-#rem monkdoc ByteOrder enumeration.
 #end
 Enum ByteOrder
 
-	#rem monkeydoc Little endian byte order.
-	#end
-	LittleEndian
-
-	#rem monkeydoc Big endian byte order.
-	#end
-	BigEndian
+	LittleEndian,BigEndian
+	
 End

+ 21 - 11
modules/std/chartype.monkey2

@@ -3,45 +3,55 @@ Namespace std.chartype
 
 #rem monkeydoc Checks if a character is whitespace.
 
+@param chr The character to check.
+
 @return True if `char` is 32 or less.
 
 #end
-Function IsSpace:Bool( ch:Int )
-	Return ch<=32
+Function IsSpace:Bool( chr:Int )
+	Return chr<=32
 End
 
-#rem monkeydoc Checks if a character is a decimal digit.
+#rem monkeydoc checks if a character is a decimal digit.
+
+@param chr The character to check.
 
 @return True if `ch` is '0'-'9'.
 
 #end
-Function IsDigit:Bool( ch:Int )
-	Return (ch>=48 And ch<58)
+Function IsDigit:Bool( chr:Int )
+	Return (chr>=48 And chr<58)
 End
 
 #rem monkeydoc Checks if a character is alphabetic.
 
+@param chr The character to check.
+
 @return True if `ch` is 'a'-'z' or 'A'-'Z'.
 
 #end
-Function IsAlpha:Bool( ch:Int )
-	Return (ch>=65 And ch<65+26) Or (ch>=97 And ch<97+26)
+Function IsAlpha:Bool( chr:Int )
+	Return (chr>=65 And chr<65+26) Or (chr>=97 And chr<97+26)
 End
 
 #rem monkeydoc Checks if a character is an identifier.
 
+@param chr The character to check.
+
 @return True if `ch` is '0'-'9', 'a'-'z', 'A'-'Z' or '_'.
 
 #end
-Function IsIdent:Bool( ch:Int )
-	Return (ch>=65 And ch<65+26) Or (ch>=97 And ch<97+26) Or (ch>=48 And ch<58) Or ch=95
+Function IsIdent:Bool( chr:Int )
+	Return (chr>=65 And chr<65+26) Or (chr>=97 And chr<97+26) Or (chr>=48 And chr<58) Or chr=95
 End
 
 #rem monkeydoc Checks if a character is a hexadecimal digit.
 
+@param chr The character to check.
+
 @return True if `ch` is '0'-'9', 'a'-'f', or 'A'-'F'.
 
 #end
-Function IsHexDigit:Bool( ch:Int )
-	Return (ch>=48 And ch<58) Or (ch>=65 And ch<71) Or (ch>=97 And ch<103)
+Function IsHexDigit:Bool( chr:Int )
+	Return (chr>=48 And chr<58) Or (chr>=65 And chr<71) Or (chr>=97 And chr<103)
 End

+ 11 - 3
modules/std/color.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.graphics
 
 Struct Color
 	
@@ -62,8 +62,8 @@ Struct Color
 		Self.a=a
 	End
 	
-	Property ARGB:UInt()
-		Return Int(a*255) Shl 24 | Int(r*255) Shl 16 | Int(g*255) Shl 8 | Int(b*255)
+	Method ToARGB:UInt()
+		Return UInt(a*255) Shl 24 | UInt(r*255) Shl 16 | UInt(g*255) Shl 8 | UInt(b*255)
 	End
 	
 	Function FromHSV:Color( h:Float,s:Float,v:Float,a:Float=1 )
@@ -90,4 +90,12 @@ Struct Color
 		Return New Color( r,g,b,a )
 	End
 	
+	Function FromARGB:Color( argb:UInt )
+		Local a:=(argb Shr 24 & $ff)/255.0
+		Local r:=(argb Shr 16 & $ff)/255.0
+		Local g:=(argb Shr 8 & $ff)/255.0
+		Local b:=(argb & $ff)/255.0
+		Return New Color( r,g,b,a )
+	End
+	
 End

+ 2 - 2
modules/std/container.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.collections
 
 #rem monkeydoc IContainer interface.
 #end
@@ -26,7 +26,7 @@ End
 #end
 Interface IIterator<T>
 
-	'Property Valid:Bool()
+	'Property AtEnd:Bool()
 	
 	'Property Current:T()
 	

+ 28 - 3
modules/std/databuffer.monkey2

@@ -1,5 +1,7 @@
 
-Namespace std
+Namespace std.memory
+
+Using std.stream
 
 #rem monkeydoc DataBuffer class.
 #end
@@ -9,7 +11,31 @@ Class DataBuffer
 	
 	The new databuffer initally uses little endian byte order. You can change this via the ByteOrder property.
 	
-	#param length The length of the databuffer to create, in bytes.
+	@example
+	
+	\#Import "<std>"
+	
+	Using std.memory
+	
+	Function Main()
+
+		Local buf:=New DataBuffer( 10 )
+		
+		Print buf.Length
+	
+		For Local i:=0 Until 10
+			buf.PokeByte( i,i*2 )
+		Next
+		
+		For Local i:=0 Until 10
+			Print buf.PeekByte( i )
+		Next
+		
+	End
+	
+	@end
+	
+	@param length The length of the databuffer to create, in bytes.
 	
 	#end
 	Method New( length:Int )
@@ -46,7 +72,6 @@ Class DataBuffer
 	End
 	
 	#rem monkeydoc The byte order of the databuffer.
-	
 	#end
 	Property ByteOrder:ByteOrder()
 		Return _byteOrder

+ 4 - 4
modules/std/datastream.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.stream
 
 #rem monkeydoc DataStream class.
 #end
@@ -31,7 +31,7 @@ Class DataStream Extends Stream
 		Return _end
 	End
 	
-	#rem monkedoc Closes the datastream.
+	#rem monkeydoc Closes the datastream.
 	
 	Closing a datastream also sets its position and length to 0.
 	
@@ -43,7 +43,7 @@ Class DataStream Extends Stream
 		_end=0
 	End
 	
-	#rem monkedoc Seeks to a position in the datastream.
+	#rem monkeydoc Seeks to a position in the datastream.
 	
 	@param position The position to seek to.
 	
@@ -54,7 +54,7 @@ Class DataStream Extends Stream
 		_pos=position
 	End
 	
-	#rem monkedoc Reads data from the datastream.
+	#rem monkeydoc Reads data from the datastream.
 	
 	@param buf A pointer to the memory to read the data into.
 	

+ 2 - 2
modules/std/filestream.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.stream
 
 Using libc
 
@@ -62,7 +62,7 @@ Class FileStream Extends Stream
 		DebugAssert( ftell( _file )=_pos )	'Sanity check...
 	End
 	
-	#rem monkedoc Reads data from the filestream.
+	#rem monkeydoc Reads data from the filestream.
 	
 	@param buf A pointer to the memory to read the data into.
 	

+ 235 - 54
modules/std/filesystem.monkey2

@@ -8,18 +8,75 @@ Using libc
 
 Extern
 
+#rem monkeydoc Gets application directory.
+
+@return The directory containing the application executable.
+
+#end
 Function AppDir:String()="bbFileSystem::appDir"
+
+#rem monkeydoc Gets the application file path.
+
+@return The path of the application executable.
+
+#end
 Function AppPath:String()="bbFileSystem::appPath"
+
+#rem monkeydoc Gets application command line arguments.
+
+@return The application command line arguments.
+#end
 Function AppArgs:String[]()="bbFileSystem::appArgs"
+
+#rem monkeydoc Copies a file.
+
+@return True if the file was successfully copied.
+
+#end
 Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
 
 Public
 
-Const FILETYPE_UNKNOWN:=-1
-Const FILETYPE_NONE:=0
-Const FILETYPE_FILE:=1
-Const FILETYPE_DIR:=2
+#rem monkeydoc FileType enumeration.
+
+| FileType		| Description
+|:--------------|:-----------
+| `None`		| File does not exist.
+| `File`		| File is a normal file.
+| `Directory`	| File is a directory.
+| `Unknown`		| File is of unknown type.
+
+#end
+Enum FileType
+	None=0
+	File=1
+	Directory=2
+	Unknown=3
+End
+
+'For backward compatibility - don't use!
+'
+#rem monkeydoc @hidden
+#end
+Const FILETYPE_NONE:=FileType.None
+
+#rem monkeydoc @hidden
+#end
+Const FILETYPE_FILE:=FileType.File
+
+#rem monkeydoc @hidden
+#end
+Const FILETYPE_DIR:=FileType.Directory
 
+#rem monkeydoc @hidden
+#end
+Const FILETYPE_UNKNOWN:=FileType.Unknown
+
+#rem monkeydoc Gets the filesystem directory of the assets folder.
+
+@return The directory app assets are stored in.
+
+#end
 Function AssetsDir:String()
 
 #If __TARGET__="desktop" And __HOSTOS__="macos"
@@ -30,6 +87,13 @@ Function AssetsDir:String()
 
 End
 
+#rem monkeydoc Extracts the root directory from a file system path.
+
+@param path The filesystem path.
+
+@return The root directory of `path`, or an empty string if `path` is not an absolute path.
+ 
+#end
 Function ExtractRootDir:String( path:String )
 
 	If path.StartsWith( "//" ) Return "//"
@@ -52,6 +116,13 @@ Function ExtractRootDir:String( path:String )
 	
 End
 
+#rem monkeydoc Checks if a path is a root directory.
+
+@param path The filesystem path to check.
+
+@return True if `path` is a root directory path.
+
+#end
 Function IsRootDir:Bool( path:String )
 
 	If path="//" Return True
@@ -73,11 +144,15 @@ Function IsRootDir:Bool( path:String )
 	Return False
 End
 
-Function IsRealPath:Bool( path:String )
+#rem monkeydoc Strips any trailing slashes from a filesystem path.
 
-	Return ExtractRootDir( path )<>""
-End
+This function will not strip slashes from a root directory path.
+
+@param path The filesystem path.
+
+@return The path stripped of trailing slashes.
 
+#end
 Function StripSlashes:String( path:String )
 
 	If Not path.EndsWith( "/" ) Return path
@@ -95,6 +170,17 @@ Function StripSlashes:String( path:String )
 	Return path
 End
 
+#rem monkeydoc Extracts the directory component from a filesystem path.
+
+If `path` is a root directory it is returned without modification.
+
+If `path` does not contain a directory component, an empty string is returned.
+
+@param path The filesystem path.
+
+@return The directory component of `path`.
+
+#end
 Function ExtractDir:String( path:String )
 
 	path=StripSlashes( path )
@@ -106,6 +192,17 @@ Function ExtractDir:String( path:String )
 	Return ""
 End
 
+#rem monkeydoc Strips the directory component from a filesystem path.
+
+If `path` is a root directory an empty string is returned.
+
+If `path` does not contain a directory component, `path` is returned without modification.
+
+@param path The filesystem path.
+
+@return The path with the directory component stripped.
+
+#end
 Function StripDir:String( path:String )
 
 	path=StripSlashes( path )
@@ -117,6 +214,13 @@ Function StripDir:String( path:String )
 	Return path
 End
 
+#rem monkeydoc Extracts the extension component from a filesystem path.
+
+@param path The filesystem path.
+
+@return The extension component of `path` including  the '.' if any.
+
+#end
 Function ExtractExt:String( path:String )
 
 	Local i:=path.FindLast( "." )
@@ -128,6 +232,13 @@ Function ExtractExt:String( path:String )
 	Return ""
 End
 
+#rem monkeydoc Strips the extension component from a filesystem path
+
+@param path The filesystem path.
+
+@return The path with the extension stripped.
+
+#end
 Function StripExt:String( path:String )
 
 	Local i:=path.FindLast( "." )
@@ -139,17 +250,26 @@ Function StripExt:String( path:String )
 	Return path
 End
 
+#rem monkeydoc Converts a path to a real path.
+
+If `path` is a relative path, it is first converted into an absolute path by prefixing the current directory.
+
+Then, any internal './' or '../' references in the path are collapsed.
+
+@param path The filesystem path.
+
+@return An absolute path with any './', '../' references collapsed.
+
+#end
 Function RealPath:String( path:String )
 
 	Local rpath:=ExtractRootDir( path )
-	If rpath
+	If rpath 
 		path=path.Slice( rpath.Length )
 	Else
 		rpath=CurrentDir()
 	Endif
 	
-	If Not rpath rpath=CurrentDir()
-	
 	While path
 		Local i:=path.Find( "/" )
 		If i=-1 Return rpath+path
@@ -159,6 +279,7 @@ Function RealPath:String( path:String )
 		Case ""
 		Case "."
 		Case ".."
+			If Not rpath rpath=CurrentDir()
 			rpath=ExtractDir( rpath )
 		Default
 			rpath+=t+"/"
@@ -168,60 +289,54 @@ Function RealPath:String( path:String )
 	Return rpath
 End
 
-Function FileTime:long( path:String )
+#rem monkeydoc Gets the time a file was most recently modified.
+
+@param path The filesystem path.
+
+@return The time the file at `path` was most recently modified.
+
+#end
+Function GetFileTime:Long( path:String )
 
 	path=StripSlashes( path )
 
 	Local st:stat_t
-	
 	If stat( path,Varptr st )<0 Return 0
 	
 	Return libc.tolong( st.st_mtime )
 End
 
-Function FileType:Int( path:String )
+#rem monkeydoc Gets the type of the file at a filesystem path.
+
+@param path The filesystem path.
+
+@return The file type of the file at `path`, one of: FileType.None, FileType.File or FileType.Directory.
+
+#end
+Function GetFileType:FileType( path:String )
 
 	path=StripSlashes( path )
 
 	Local st:stat_t
-
-	If stat( path,Varptr st )<0 Return FILETYPE_NONE
+	If stat( path,Varptr st )<0 Return FileType.None
 	
 	Select st.st_mode & S_IFMT
-	Case S_IFDIR Return FILETYPE_DIR
-	Case S_IFREG Return FILETYPE_FILE
+	Case S_IFREG Return FileType.File
+	Case S_IFDIR Return FileType.Directory
 	End
 	
-	Return FILETYPE_UNKNOWN
+	Return FileType.Unknown
 End
 
-Function DeleteFile:Bool( path:String )
-
-	remove( path )
-	
-	Return FileType( path )=FILETYPE_NONE
-End
-
-Function CreateDir:Bool( path:String,recursive:Bool=True )
-
-	path=StripSlashes( path )
-
-	If recursive
-		Local parent:=ExtractDir( path )
-		If parent And Not IsRootDir( parent ) 
-			If FileType( parent )=FILETYPE_NONE And Not CreateDir( parent,True ) Return False
-		Endif
-	Endif
+#rem monkeydoc Gets the process current directory.
 
-	mkdir( path,$1ff )
-
-	Return FileType( path )=FILETYPE_DIR
-End
+@return The current directory for the running process.
 
+#end
 Function CurrentDir:String()
 
 	Local sz:=4096
-	Local buf:=Cast<CChar Ptr>( malloc( sz ) )
+	Local buf:=Cast<char_t Ptr>( malloc( sz ) )
 	getcwd( buf,sz )
 	Local path:=String.FromCString( buf )
 	free( buf )
@@ -231,6 +346,11 @@ Function CurrentDir:String()
 	Return path+"/"
 End
 
+#rem monkeydoc Changes the process current directory.
+
+@param path The filesystem path of the directory to make current.
+
+#end
 Function ChangeDir( path:String )
 
 	path=StripSlashes( path )
@@ -238,6 +358,13 @@ Function ChangeDir( path:String )
 	chdir( path )
 End
 
+#rem monkeydoc Loads a directory.
+
+@param path The filesystem path of the directory to load.
+
+@return An array containing all filenames in the `path`, excluding '.' and '..' entries.
+
+#end
 Function LoadDir:String[]( path:String )
 
 	path=StripSlashes( path )
@@ -251,7 +378,7 @@ Function LoadDir:String[]( path:String )
 		Local ent:=readdir( dir )
 		If Not ent Exit
 		
-		Local file:=String.FromTString( ent[0].d_name )
+		Local file:=String.FromCString( ent[0].d_name )
 		If file="." Or file=".." Continue
 		
 		files.Push( file )
@@ -262,53 +389,107 @@ Function LoadDir:String[]( path:String )
 	Return files.ToArray()
 End
 
-Function DeleteAll:Bool( path:String )
+#rem monkeydoc Creates a directory at a filesystem path.
+
+@param path The filesystem path of ther directory to create.
+
+@param recursive If true, any required parent directories are also created.
+
+@return True if a directory at `path` was successfully created or already existed.
+
+#end
+Function CreateDir:Bool( path:String,recursive:Bool=True )
 
 	path=StripSlashes( path )
 
-	Select FileType( path )
-	Case FILETYPE_NONE
+	If recursive
+		Local parent:=ExtractDir( path )
+		If parent And Not IsRootDir( parent )
+			Select GetFileType( parent )
+			Case FileType.None
+				If Not CreateDir( parent,True ) Return False
+			Case FileType.File
+				Return False
+			Case FileType.Directory
+			End
+		Endif
+	Endif
+
+	mkdir( path,$1ff )
+	Return GetFileType( path )=FileType.Directory
+End
+
+Private
+
+Function DeleteAll:Bool( path:String )
+
+	Select GetFileType( path )
+	Case FileType.None
 	
 		Return True
 		
-	Case FILETYPE_FILE
+	Case FileType.File
 	
 		Return DeleteFile( path )
 		
-	Case FILETYPE_DIR
+	Case FileType.Directory
 	
 		For Local f:=Eachin LoadDir( path )
 			If Not DeleteAll( path+"/"+f ) Return False
 		Next
 		
 		rmdir( path )
-		Return FileType( path )=FILETYPE_NONE
+		Return GetFileType( path )=FileType.None
 	End
 	
 	Return False
 End
 
-Function DeleteDir:Bool( path:String,recursive:Bool=True )
+Public
+
+#rem monkeydoc Deletes a directory at a filesystem path.
+
+@param path The filesystem path.
+
+@param recursive True to delete subdirectories too.
+
+@return True if the directory was successfully deleted or never existed.
+
+#end
+Function DeleteDir:Bool( path:String,recursive:Bool=False )
 
 	path=StripSlashes( path )
 
-	Select FileType( path )
-	Case FILETYPE_NONE
+	Select GetFileType( path )
+	Case FileType.None
 
 		Return True
-
-	Case FILETYPE_FILE
+		
+	Case FileType.File
 	
 		Return False
 		
-	Case FILETYPE_DIR
+	Case FileType.Directory
 	
 		If recursive Return DeleteAll( path )
 		
 		rmdir( path )
-		Return FileType( path )=FILETYPE_NONE
+		Return GetFileType( path )=FileType.None
 	End
 	
 	Return False
 End
 
+#rem monkeydoc Deletes a file at a filesystem path.
+
+@param path The filesystem path.
+
+@return True if the file was successfully deleted.
+
+#end
+Function DeleteFile:Bool( path:String )
+
+	remove( path )
+	Return GetFileType( path )=FileType.None
+End
+

+ 0 - 469
modules/std/filesystemex.monkey2

@@ -1,469 +0,0 @@
-
-Namespace std.filesystemex
-
-Using libc
-
-#Import "native/filesystem.h"
-#Import "native/filesystem.cpp"
-
-Extern
-
-Function AppDir:String()="bbFileSystem::appDir"
-Function AppPath:String()="bbFileSystem::appPath"
-Function AppArgs:String[]()="bbFileSystem::appArgs"
-Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
-
-Public
-
-Enum FileType
-	None=0
-	File=1
-	Directory=2
-	Unknown=3
-End
-
-#rem monkeydoc Gets the filesystem directory of the assets folder.
-
-@return The directory app assets are stored in.
-
-#end
-Function AssetsDir:String()
-
-#If __TARGET__="desktop" And __HOSTOS__="macos"
-	Return AppDir()+"../Resources/"
-#Else
-	Return AppDir()+"assets/"
-#Endif
-
-End
-
-#rem monkeydoc Gets the root directory of a file system path.
-
-@param path The filesystem path.
-
-@return The root directory of `path`, or an empty string if `path` is not an absolute path.
- 
-#end
-Function GetRootDir:String( path:String )
-
-	If path.StartsWith( "//" ) Return "//"
-	
-	Local i:=path.Find( "/" )
-	If i=0 Return "/"
-	
-	If i=-1 i=path.Length
-	
-	Local j:=path.Find( "://" )
-	If j>0 And j<i Return path.Slice( 0,j+3 )
-	
-	j=path.Find( ":/" )
-	If j>0 And j<i Return path.Slice( 0,j+2 )
-	
-	j=path.Find( "::" )
-	If j>0 And j<i Return path.Slice( 0,j+2 )
-	
-	Return ""
-	
-End
-
-#rem monkeydoc Checks if a path is root directory.
-
-@param path The filesystem path to check.
-
-@return True if `path` is a root directory path.
-
-#end
-Function IsRootDir:Bool( path:String )
-
-	If path="//" Return True
-	
-	If path="/" Return True
-	
-	Local i:=path.Find( "/" )
-	If i=-1 i=path.Length
-	
-	Local j:=path.Find( "://" )
-	If j>0 And j<i Return j+3=path.Length
-	
-	j=path.Find( ":/" )
-	If j>0 And j<i Return j+2=path.Length
-	
-	j=path.Find( "::" )
-	If j>0 And j<i Return j+2=path.Length
-	
-	Return False
-End
-
-#rem monkeydoc Check if a filesystem path is an absolute path.
-
-An absolute path is a path that begins with a root directory.
-
-@param path The filesystem path to check.
-
-@return True if `path` is an absolute path.
-
-#end
-Function IsAbsolutePath:Bool( path:String )
-
-	Return GetRootDir( path )<>""
-End
-
-#rem monkeydoc Strips any trailing slashes from a filesystem path.
-
-This function will not strip slashes from a root directory path.
-
-@param path The filesystem path.
-
-@return The path stripped of trailing slashes.
-
-#end
-Function StripSlashes:String( path:String )
-
-	If Not path.EndsWith( "/" ) Return path
-	
-	Local root:=GetRootDir( path )
-	
-	Repeat
-	
-		If path=root Return path
-
-		path=path.Slice( 0,-1 )
-		
-	Until Not path.EndsWith( "/" )
-	
-	Return path
-End
-
-#rem monkeydoc Gets the parent directory component from a filesystem path.
-
-If `path` is a root directory, `path` is returned without modification.
-
-If `path` does not contain a parent directory, an empty string is returned.
-
-@param path The filesystem path.
-
-@return The parent directory of `path`.
-
-#end
-Function GetParentDir:String( path:String )
-
-	path=StripSlashes( path )
-	If IsRootDir( path ) Return path
-	
-	Local i:=path.FindLast( "/" )
-	If i>=0 Return path.Slice( 0,i+1 )
-	
-	Return ""
-End
-
-#rem monkeydoc Strips the parent directory component from a filesystem path.
-
-If `path` is a root directory, an empty string is returned.
-
-If `path` does not contain a parent directory, `path` is returned without modification.
-
-@param path The filesystem path.
-
-@return `path` with the parent directory stripped.
-
-#end
-Function StripParentDir:String( path:String )
-
-	path=StripSlashes( path )
-	If IsRootDir( path ) Return ""
-
-	Local i:=path.FindLast( "/" )
-	If i>=0 Return path.Slice( i+1 )
-	
-	Return path
-End
-
-#rem monkeydoc Gets the extension component from a filesystem path.
-
-@param path The filesystem path.
-
-@return The extension component of `path`, including  the '.' if any.
-
-#end
-Function GetExtension:String( path:String )
-
-	Local i:=path.FindLast( "." )
-	If i=-1 Return ""
-	
-	Local j:=path.Find( "/",i+1 )
-	If j=-1 Return path.Slice( i )
-	
-	Return ""
-End
-
-#rem monkeydoc Strips the extension component from a filesystem path
-
-@param path The filesystem path.
-
-@return The path with the extension stripped.
-
-#end
-Function StripExtension:String( path:String )
-
-	Local i:=path.FindLast( "." )
-	If i=-1 Return path
-	
-	Local j:=path.Find( "/",i+1 )
-	If j=-1 Return path.Slice( 0,i )
-	
-	Return path
-End
-
-#rem monkeydoc Converts a path to an absolute path.
-
-@param path The filesystem path.
-
-@return The absolute path of `path`, taking the process current directory into account.
-
-#end
-Function GetAbsolutePath:String( path:String )
-
-	path=GetRealPath( path )
-	
-	If IsAbsolutePath( path ) Return path
-	
-	Return CurrentDir()+path
-End
-
-#rem monkeydoc Converts a relative path to a real path.
-
-A real path is a path with any internal './' or '../' references collapsed.
-
-@param path The filesystem path.
-
-@param The path with any './', '../' references collapsed.
-
-#end
-Function GetRealPath:String( path:String )
-
-	Local rpath:=GetRootDir( path )
-	If rpath path=path.Slice( rpath.Length )
-	
-	While path
-		Local i:=path.Find( "/" )
-		If i=-1 Return rpath+path
-		Local t:=path.Slice( 0,i )
-		path=path.Slice( i+1 )
-		Select t
-		Case ""
-		Case "."
-		Case ".."
-			If Not rpath rpath=CurrentDir()
-			rpath=GetParentDir( rpath )
-		Default
-			rpath+=t+"/"
-		End
-	Wend
-	
-	Return rpath
-End
-
-#rem monkeydoc Gets the time a file was most recently modified.
-
-@param path The filesystem path.
-
-@return The time the file at `path` was most recently modified.
-
-#end
-Function GetFileTime:Long( path:String )
-
-	path=StripSlashes( path )
-
-	Local st:stat_t
-	If stat( path,Varptr st )<0 Return 0
-	
-	Return libc.tolong( st.st_mtime )
-End
-
-#rem monkeydoc Gets the type of the file at a filesystem path.
-
-@param path The filesystem path.
-
-@return The file type of the file at `path`, one of: FileType.None, FileType.File or FileType.Directory.
-
-#end
-Function GetFileType:FileType( path:String )
-
-	path=StripSlashes( path )
-
-	Local st:stat_t
-	If stat( path,Varptr st )<0 Return FileType.None
-	
-	Select st.st_mode & S_IFMT
-	Case S_IFREG Return FileType.File
-	Case S_IFDIR Return FileType.Directory
-	End
-	
-	Return FileType.File	'?!?
-End
-
-#rem monkeydoc Gets the current directory.
-
-@return The current directory for the running process.
-
-#end
-Function CurrentDir:String()
-
-	Local sz:=4096
-	Local buf:=Cast<CChar Ptr>( malloc( sz ) )
-	getcwd( buf,sz )
-	Local path:=String.FromCString( buf )
-	free( buf )
-	
-	path=path.Replace( "\","/" )
-	If path.EndsWith( "/" ) Return path
-	Return path+"/"
-End
-
-#rem monkeydoc Sets the current directory.
-
-@param path The file system directory to make current.
-
-#end
-Function ChangeDir( path:String )
-
-	path=StripSlashes( path )
-	
-	chdir( path )
-End
-
-#rem monkeydoc Loads a directory.
-
-@param path The filesystem path of the directory to load.
-
-@return An array containing all filenames in the `path`, excluding '.' and '..' entries.
-
-#end
-Function LoadDir:String[]( path:String )
-
-	path=StripSlashes( path )
-
-	Local dir:=opendir( path )
-	If Not dir Return Null
-	
-	Local files:=New StringStack
-	
-	Repeat
-		Local ent:=readdir( dir )
-		If Not ent Exit
-		
-		Local file:=String.FromTString( ent[0].d_name )
-		If file="." Or file=".." Continue
-		
-		files.Push( file )
-	Forever
-	
-	closedir( dir )
-	
-	Return files.ToArray()
-End
-
-#rem monkeydoc Creates a directory at a filesystem path.
-
-@param path The filesystem path.
-
-@param recursive If true, any required parent directories are also created.
-
-@return True if a directory at `path` was successfully created or already existed.
-
-#end
-Function CreateDir:Bool( path:String,recursive:Bool=True )
-
-	path=StripSlashes( path )
-
-	If recursive
-		Local parent:=GetParentDir( path )
-		If parent And Not IsRootDir( parent )
-			Select GetFileType( parent )
-			Case FileType.None
-				If Not CreateDir( parent,True ) Return False
-			Case FileType.File
-				Return False
-			Case FileType.Directory
-			End
-		Endif
-	Endif
-
-	mkdir( path,$1ff )
-	Return GetFileType( path )=FileType.Directory
-End
-
-Private
-
-Function DeleteAll:Bool( path:String )
-
-	Select GetFileType( path )
-	Case FileType.None
-	
-		Return True
-		
-	Case FileType.File
-	
-		Return DeleteFile( path )
-		
-	Case FileType.Directory
-	
-		For Local f:=Eachin LoadDir( path )
-			If Not DeleteAll( path+"/"+f ) Return False
-		Next
-		
-		rmdir( path )
-		Return GetFileType( path )=FileType.None
-	End
-	
-	Return False
-End
-
-Public
-
-#rem monkeydoc Deletes a directory at a filesystem path.
-
-@path The filesystem path.
-
-@recursive True to delete subdirectories too.
-
-@return True if the directory was successfully deleted or never existed.
-
-#end
-Function DeleteDir:Bool( path:String,recursive:Bool=False )
-
-	path=StripSlashes( path )
-
-	Select GetFileType( path )
-	Case FileType.None
-
-		Return True
-		
-	Case FileType.File
-	
-		Return False
-		
-	Case FileType.Directory
-	
-		If recursive Return DeleteAll( path )
-		
-		rmdir( path )
-		Return GetFileType( path )=FileType.None
-	End
-	
-	Return False
-End
-
-#rem monkeydoc Deletes a file at a filesystem path.
-
-@path The filesystem path.
-
-@return True if the file was successfully deleted.
-
-#end
-Function DeleteFile:Bool( path:String )
-
-	remove( path )
-	Return GetFileType( path )=FileType.None
-End
-

+ 1 - 1
modules/std/generator.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.fiber
 
 Class Generator<T>
 

+ 11 - 1
modules/std/geom.monkey2

@@ -1,5 +1,5 @@
 
-Namespace std
+Namespace std.graphics
 
 Alias Vec2i:Vec2<Int>
 Alias Vec2f:Vec2<Float>
@@ -15,6 +15,8 @@ Alias Mat4f:Mat4<Float>
 Alias Recti:Rect<Int>
 Alias Rectf:Rect<Float>
 
+#rem monkeydoc @hidden
+#end
 Struct Vec2<T>
 
 	Field x:T
@@ -146,6 +148,8 @@ Struct Vec2<T>
 
 End
 
+#rem monkeydoc @hidden
+#end
 Struct Vec3<T>
 
 	Field x:T
@@ -282,6 +286,8 @@ Struct Vec3<T>
 	
 End
 
+#rem monkeydoc @hidden
+#end
 Struct Vec4<T>
 
 	Field x:T
@@ -419,6 +425,8 @@ Struct Vec4<T>
 	
 End
 
+#rem monkeydoc @hidden
+#end
 Struct Mat4<T>
 
 	Field i:Vec4<T>
@@ -462,6 +470,8 @@ Struct Mat4<T>
 	
 End
 
+#rem monkeydoc @hidden
+#end
 Struct Rect<T>
 
 	Field min:Vec2<T>

+ 183 - 229
modules/std/json.monkey2

@@ -1,321 +1,275 @@
 
-Namespace std
+Namespace std.json
 
-Private
-
-Function ThrowError:Void()
-'	DebugStop
-	Throw New JsonError
+#rem monkeydoc JsonError class.
+#end
+Class JsonError Extends Throwable
 End
 
-Public
+#rem monkeydoc JsonValue class.
 
-Class JsonError
-End
+This is base class of all JsonValue types.
 
+#end
 Class JsonValue Abstract
 
-	Method ToBool:Bool()
-		ThrowError()
-		Return False
+	Method ToBool:Bool() Virtual
+		Assert( False )
+		Return Null
 	End
 	
-	Method ToInt:Int()
-		ThrowError()
-		Return 0
-	End
+	Method ToNumber:Double() Virtual
+		Assert( False )
+		Return Null
+	End	
 	
-	Method ToFloat:Float()
-		ThrowError()
-		Return 0.0
+	Method ToString:String() Virtual
+		Assert( False )
+		Return Null
 	End
 	
-	Method ToString:String()
-		ThrowError()
-		Return ""
+	Operator[]:JsonValue( index:Int ) Virtual
+		Assert( False )
+		Return Null
 	End
 	
-	Method ToJson:String()
-		Local buf:=New StringStack
-		PushJson( buf )
-		Return buf.Join( "" )
-	End
-		
-	Method PushJson:Void( buf:StringStack )
-		buf.Push( ToJson() )
-	End
-
-End
-
-Class JsonObject Extends JsonValue
-
-	Method New()
-		_data=New StringMap<JsonValue>
+	Operator[]=( index:Int,value:JsonValue ) Virtual
+		Assert( False )
 	End
 	
-	Method New( json:String )
-		_data=(New JsonParser( json ) ).ParseObject()
-	End
-
-	Method New( data:StringMap<JsonValue> )
-		_data=data
+	Operator[]:JsonValue( key:String ) Virtual
+		Assert( False )
+		Return Null
 	End
 	
-	Method Contains:Bool( key:String )
-		Return _data.Contains( key )
+	Operator[]=( key:String,value:JsonValue ) Virtual
+		Assert( False )
 	End
 	
-	Method Set:Void( key:String,value:JsonValue )
-		_data.Set( key,value )
-	End
-
-	Method SetBool:Void( key:String,value:Bool )
-		Set( key,New JsonBool( value ) )
+	Method ToJson:String() Virtual
+		Local buf:=New StringStack
+		PushJson( buf )
+		Return buf.Join( "" )
 	End
-	
-	Method SetInt:Void( key:String,value:Int )
-		Set( key,New JsonNumber( value ) )
+		
+	Method ToInt:Int()
+		Return Int( ToNumber() )
 	End
 	
-	Method SetFloat:Void( key:String,value:Float )
-		Set( key,New JsonNumber( value ) )
+	Method ToLong:Long()
+		Return Long( ToNumber() )
 	End
 	
-	Method SetString:Void( key:String,value:String )
-		Set( key,New JsonString( value ) )
+	Method ToFloat:Float()
+		Return Float( ToNumber() )
 	End
 	
-	Method Get:JsonValue( key:String,defval:JsonValue=Null )
-		If Not _data.Contains( key ) Return defval
-		Local val:=_data.Get( key )
-		If val Return val
-		Return JsonNull.Instance()
+	Method ToDouble:Double()
+		Return ToNumber()
 	End
 	
-	Method GetBool:Bool( key:String,defval:Bool=False )
-		If Not _data.Contains( key ) Return defval
-		Return Get( key ).ToBool()
-	End
-		
-	Method GetInt:Int( key:String,defval:Int=0 )
-		If Not _data.Contains( key ) Return defval
-		Return Get( key ).ToInt()
-	End
-		
-	Method GetFloat:Float( key:String,defval:Float=0 )
-		If Not _data.Contains( key ) Return defval
-		Return Get( key ).ToFloat()
-	End
-		
-	Method GetString:String( key:String,defval:String="" )
-		If Not _data.Contains( key ) Return defval
-		Return Get( key ).ToString()
-	End
+	Protected
 	
-	Method GetData:StringMap<JsonValue>()
-		Return _data
-	End
-		
-	Method PushJson:Void( buf:StringStack ) Override
-		buf.Push( "{" )
-		Local t:=False
-		For Local it:=Eachin _data
-			If t buf.Push( "," )
-			buf.Push( "~q"+it.Key.Replace( "~q","\~q" )+"~q:" )
-			If it.Value<>Null it.Value.PushJson( buf ) Else buf.Push( "null" )
-			t=True
-		Next
-		buf.Push( "}" )
+	#rem monkeydoc @hidden
+	#end
+	Method PushJson:Void( buf:StringStack ) Virtual
+		buf.Push( ToJson() )
 	End
 	
-	Private
-	
-	Field _data:StringMap<JsonValue>
-	
 End
 
-Class JsonArray Extends JsonValue
+#rem monkeydoc JsonBool class.
+#end
+Class JsonBool Extends JsonValue
 
-	Method New( length:Int )
-		_data=New JsonValue[length]
-	End
+	Const TrueValue:JsonBool=New JsonBool( True )
 	
-	Method New( data:JsonValue[] )
+	Const FalseValue:JsonBool=New JsonBool( False )
+
+	Method New( data:Bool=False )
 		_data=data
 	End
 	
-	Property Length:Int()
-		Return _data.Length
-	End
-	
-	Method Set:Void( index:Int,value:JsonValue )
-		If index<0 Or index>=_data.Length ThrowError()
-		_data[index]=value
+	Property Data:Bool()
+		Return _data
+	Setter( data:Bool )
+		_data=data
 	End
 	
-	Method SetBool:Void( index:Int,value:Bool )
-		Set( index,New JsonBool( value ) )
+	Method ToBool:Bool() Override
+		Return _data
 	End
 	
-	Method SetInt:Void( index:Int,value:Int )
-		Set( index,New JsonNumber( value ) )
+	Method ToNumber:Double() Override
+		Return _data
 	End
 	
-	Method SetFloat:Void( index:Int,value:Float )
-		Set( index,New JsonNumber( value ) )
+	Method ToString:String() Override
+		Return _data ? "true" Else "false"
 	End
 	
-	Method SetString:Void( index:Int,value:String )
-		Set( index,New JsonString( value ) )
+	Method ToJson:String() Override
+		Return _data ? "true" Else "false"
 	End
+
+	Private
 	
-	Method Get:JsonValue( index:Int )
-		If index<0 Or index>=_data.Length ThrowError()
-		Local val:=_data[index]
-		If val Return val
-		Return JsonNull.Instance()
+	Field _data:Bool
+End
+
+#rem monkeydoc JsonNumber class.
+#end
+Class JsonNumber Extends JsonValue
+
+	Method New( data:Double=0 )
+		_data=data
 	End
 	
-	Method GetBool:Bool( index:Int )
-		Return Get( index ).ToBool()
+	Property Data:Double()
+		Return _data
+	Setter( data:Double )
+		_data=data
 	End
 	
-	Method GetInt:Int( index:Int )
-		Return Get( index ).ToInt()
+	Method ToBool:Bool() Override
+		Return _data
 	End
 	
-	Method GetFloat:Float( index:Int )
-		Return Get( index ).ToFloat()
+	Method ToNumber:Double() Override
+		Return _data
 	End
 	
-	Method GetString:String( index:Int )
-		Return Get( index ).ToString()
-	End
-
-	Method GetData:JsonValue[]()
+	Method ToString:String() Override
 		Return _data
 	End
 	
-	Method PushJson:Void( buf:StringStack ) Override
-		buf.Push( "[" )
-		Local t:=False
-		For Local value:=Eachin _data
-			If t buf.Push( "," )
-			If value<>Null value.PushJson( buf ) Else buf.Push( "null" )
-			t=True
-		Next
-		buf.Push( "]" )
+	Method ToJson:String() Override
+		Return _data
 	End
 
 	Private
 	
-	Field _data:JsonValue[]
-	
+	Field _data:Double
 End
 
-Class JsonNull Extends JsonValue
+#rem monkeydoc JsonString class.
+#end
+Class JsonString Extends JsonValue
 
-	Method ToJson:String() Override
-		Return "null"
-	End
-	
-	Function Instance:JsonNull()
-		Return _instance
+	Method New( data:String="" )
+		_data=data
 	End
 	
-	Private
-	
-	Global _instance:=New JsonNull
-	
-End
-
-Class JsonBool Extends JsonValue
-
-	Method New( value:Bool )
-		_value=value
+	Property Data:String()
+		Return _data
+	Setter( data:String )
+		_data=data
 	End
 	
 	Method ToBool:Bool() Override
-		Return _value
+		Return _data
 	End
 	
-	Method ToJson:String() Override
-		If _value Return "true"
-		Return "false"
+	Method ToNumber:Double() Override
+		Return Double( _data )
 	End
 	
-	Function Instance:JsonBool( value:Bool )
-		If value Return _true
-		Return _false
+	Method ToString:String() Override
+		Return _data
 	End
 	
+	Method ToJson:String() Override
+		Return "~q"+_data.Replace( "~q","\~q" )+"~q"
+	End
+
 	Private
 	
-	Field _value:Bool
-	
-	Global _true:=New JsonBool( True )
-	Global _false:=New JsonBool( False )
-	
+	Field _data:String
 End
 
-Class JsonString Extends JsonValue
+#rem monkeydoc JsonArray class.
+#end
+Class JsonArray Extends JsonValue
 
-	Method New( value:String )
-		_value=value
+	Method New( data:Stack<JsonValue> =Null )
+		If Not data data=New Stack<JsonValue>
+		_data=data
 	End
 	
-	Method ToString:String() Override
-		Return _value
+	Property Data:Stack<JsonValue>()
+		Return _data
+	Setter( data:Stack<JsonValue> )
+		_data=data
 	End
 	
-	Method ToJson:String() Override
-		Return "~q"+_value.Replace( "~q","\~q" )+"~q"
+	Operator[]:JsonValue( index:Int ) Override
+		Return _data[index]
 	End
 	
-	Function Instance:JsonString( value:String )
-		If value Return New JsonString( value )
-		Return _null
+	Operator[]=( index:Int,value:JsonValue ) Override
+		_data[index]=value
 	End
 	
 	Private
 	
-	Field _value:String
+	Field _data:Stack<JsonValue>
 	
-	Global _null:=New JsonString( "" )
+	Method PushJson:Void( buf:StringStack ) Override
+		buf.Push( "[" )
+		Local t:=False
+		For Local value:=Eachin _data
+			If t buf.Push( "," )
+			If value value.PushJson( buf ) Else buf.Push( "null" )
+			t=True
+		Next
+		buf.Push( "]" )
+	End
 	
 End
 
-Class JsonNumber Extends JsonValue
+#rem monkeydoc JsonObject class.
+#end
+Class JsonObject Extends JsonValue
 
-	Method New( value:String )
-		'error check value!
-		_value=value
+	Method New( data:StringMap<JsonValue> =Null )
+		If Not data data=New StringMap<JsonValue>
+		_data=data
 	End
 	
-	Method ToInt:Int() Override
-		Return Int( _value )
+	Property Data:StringMap<JsonValue>()
+		Return _data
+	Setter( data:StringMap<JsonValue> )
+		_data=data
 	End
 	
-	Method ToFloat:Float() Override
-		Return Float( _value )
-	End	
-	
-	Method ToJson:String() Override
-		Return _value
+	Operator[]:JsonValue( key:String ) Override
+		Return _data[key]
 	End
 	
-	Function Instance:JsonNumber( value:String )
-		If value<>"0" Return New JsonNumber( value )
-		Return _zero
+	Operator[]=( key:String,value:JsonValue ) Override
+		_data[key]=value
 	End
 	
 	Private
 	
-	Field _value:String
+	Field _data:StringMap<JsonValue>
+
+	Method PushJson:Void( buf:StringStack ) Override
+		buf.Push( "{" )
+		Local t:=False
+		For Local it:=Eachin _data
+			If t buf.Push( "," )
+			buf.Push( "~q"+it.Key.Replace( "~q","\~q" )+"~q:" )
+			If it.Value it.Value.PushJson( buf ) Else buf.Push( "null" )
+			t=True
+		Next
+		buf.Push( "}" )
+	End
 	
-	Global _zero:=New JsonNumber( "0" )
 End
 
+#rem monkeydoc JsonParser class.
+#end
 Class JsonParser
 
 	Method New( json:String )
@@ -323,15 +277,15 @@ Class JsonParser
 		Bump()
 	End
 	
-	Method ParseValue:JsonValue()
-		If TokeType=T_STRING Return JsonString.Instance( ParseString() )
-		If TokeType=T_NUMBER Return JsonNumber.Instance( ParseNumber() )
+	Method ParseJson:JsonValue()
+		If TokeType=T_STRING Return New JsonString( ParseString() )
+		If TokeType=T_NUMBER Return New JsonNumber( Double( ParseNumber() ) )
 		If Toke="{" Return New JsonObject( ParseObject() )
 		If Toke="[" Return New JsonArray( ParseArray() )
-		If CParse("true") Return JsonBool.Instance( True )
-		If CParse("false") Return JsonBool.Instance( False )
-		If CParse("null") Return JsonNull.Instance()
-		ThrowError()
+		If CParse("true") Return JsonBool.TrueValue
+		If CParse("false") Return JsonBool.FalseValue
+		If CParse("null") Return Null
+		Return Null
 	End
 
 	Private
@@ -348,7 +302,7 @@ Class JsonParser
 	Field _pos:Int
 	
 	Method GetChar:Int()
-		If _pos=_text.Length ThrowError()
+		If _pos=_text.Length Throw New JsonError()
 		_pos+=1
 		Return _text[_pos-1]
 	End
@@ -359,7 +313,7 @@ Class JsonParser
 	End
 	
 	Method ParseChar:Void( chr:Int )
-		If _pos>=_text.Length Or _text[_pos]<>chr ThrowError()
+		If _pos>=_text.Length Or _text[_pos]<>chr Throw New JsonError()
 		_pos+=1
 	End
 	
@@ -402,7 +356,7 @@ Class JsonParser
 		Else If chr=45 Or (chr>=48 And chr<=57)
 			If chr=45 '-
 				chr=GetChar()
-				If chr<48 Or chr>57 ThrowError()
+				If chr<48 Or chr>57 Throw New JsonError()
 			Endif
 			If chr<>48 '0
 				CParseDigits()
@@ -412,7 +366,7 @@ Class JsonParser
 			Endif
 			If CParseChar( 69 ) Or CParseChar( 101 ) 'e E
 				If PeekChar()=43 Or PeekChar()=45 GetChar()	'+ -
-				If Not CParseDigits() ThrowError()
+				If Not CParseDigits() Throw New JsonError()
 			Endif
 			_type=T_NUMBER
 		Else If (chr>=65 And chr<91) Or (chr>=97 And chr<123)
@@ -444,7 +398,7 @@ Class JsonParser
 	End
 	
 	Method Parse:Void( toke:String )
-		If Not CParse( toke ) ThrowError()
+		If Not CParse( toke ) Throw New JsonError()
 	End
 
 	Method ParseObject:StringMap<JsonValue>()
@@ -454,33 +408,33 @@ Class JsonParser
 		Repeat
 			Local name:=ParseString()
 			Parse( ":" )
-			Local value:=ParseValue()
+			Local value:=ParseJson()
 			map.Set( name,value )
 		Until Not CParse( "," )
 		Parse( "}" )
 		Return map
 	End
 	
-	Method ParseArray:JsonValue[]()
+	Method ParseArray:Stack<JsonValue>()
 		Parse( "[" )
 		If CParse( "]" ) Return Null
 		Local stack:=New Stack<JsonValue>
 		Repeat
-			Local value:=ParseValue()
+			Local value:=ParseJson()
 			stack.Push( value )
 		Until Not CParse( "," )
 		Parse( "]" )
-		Return stack.ToArray()
+		Return stack
 	End
 	
 	Method ParseString:String()
-		If TokeType<>T_STRING ThrowError()
+		If TokeType<>T_STRING Throw New JsonError()
 		Local toke:=Toke.Slice( 1,-1 )
 		Local i:=toke.Find( "\" )
 		If i<>-1
 			Local frags:=New StringStack,p:=0,esc:=""
 			Repeat
-				If i+1>=toke.Length ThrowError()
+				If i+1>=toke.Length Throw New JsonError()
 				frags.Push( toke.Slice( p,i ) )
 				Select toke[i+1]
 				Case 34  esc="~q"				'\"
@@ -491,7 +445,7 @@ Class JsonParser
 				Case 114 esc=String.FromChar( 13 )	'\r
 				Case 110 esc=String.FromChar( 10 )	'\n
 				Case 117								'\uxxxx
-					If i+6>toke.Length ThrowError()
+					If i+6>toke.Length Throw New JsonError()
 					Local val:=0
 					For Local j:=2 Until 6
 						Local chr:=toke[i+j]
@@ -499,16 +453,16 @@ Class JsonParser
 							val=val Shl 4 | (chr-48)
 						Else If chr>=65 And chr<123
 							chr&=31
-							If chr<1 Or chr>6 ThrowError()
+							If chr<1 Or chr>6 Throw New JsonError()
 							val=val Shl 4 | (chr+9)
 						Else
-							ThrowError()
+							Throw New JsonError()
 						Endif
 					Next
 					esc=String.FromChar( val )
 					i+=4
 				Default 
-					ThrowError()
+					Throw New JsonError()
 				End
 				frags.Push( esc )
 				p=i+2
@@ -524,7 +478,7 @@ Class JsonParser
 	End
 	
 	Method ParseNumber:String()
-		If TokeType<>T_NUMBER ThrowError()
+		If TokeType<>T_NUMBER Throw New JsonError()
 		Local toke:=Toke
 		Bump()
 		Return toke

+ 208 - 95
modules/std/list.monkey2

@@ -1,17 +1,29 @@
 
-Namespace std
+Namespace std.collections
 
-#rem monkeydoc List class.
+Alias IntList:List<Int>
+
+Alias FloatList:List<Float>
+
+Alias StringList:List<String>
+
+#rem monkeydoc The List class.
 
 #end
 Class List<T> Implements IContainer<T>
 
+	Private
+	
 	Class Node
 	
+		Private
+	
 		Field _succ:Node
 		Field _pred:Node
 		Field _value:T
 		
+		Public
+		
 		Method New( value:T )
 			_value=value
 		End
@@ -30,42 +42,54 @@ Class List<T> Implements IContainer<T>
 		
 	End
 	
+	Public
+	
 	Struct Iterator 'Implements IIterator<T>
 	
+		Private
+	
 		Field _list:List
 		Field _node:Node
 		Field _seq:Int
 		
+		Method AssertSeq()
+			DebugAssert( _seq=_list._seq,"Concurrent list modification" )
+		End
+		
+		Method AssertCurrent()
+			DebugAssert( Valid,"Invalid list iterator" )
+		End
+		
+		Public
+		
 		Method New( list:List,node:Node )
 			_list=list
 			_node=node
 			_seq=list._seq
 		End
 		
-		Method AssertSeq()
-			DebugAssert( _seq=_list._seq,"Concurrent list modification" )
-		End
-		
-		Method AssertValid()
-			DebugAssert( Valid,"Invalid list iterator" )
+		Property AtEnd:Bool()
+			AssertSeq()
+			Return _node=Null
 		End
 		
+		#rem monkeydoc @hidden
+		#end
 		Property Valid:Bool()
-			AssertSeq()
-			Return _node<>Null
+			Return Not AtEnd
 		End
 		
 		Property Current:T()
-			AssertValid()
+			AssertCurrent()
 			Return _node._value
 			
 		Setter( current:T )
-			AssertValid()
+			AssertCurrent()
 			_node._value=current
 		End
 		
 		Method Bump()
-			AssertValid()
+			AssertCurrent()
 			_node=_node._succ
 		End
 		
@@ -82,11 +106,15 @@ Class List<T> Implements IContainer<T>
 		End
 	End
 	
+	Private
+	
 	Field _first:Node
 	Field _last:Node
 	Field _length:Int
 	Field _seq:Int
 	
+	Public
+	
 	#rem monkeydoc Creates a new empty list.
 	#end
 	Method New()
@@ -101,11 +129,17 @@ Class List<T> Implements IContainer<T>
 		AddAll( values )
 	End
 	
-	#rem monkeydoc Gets an iterator to all values in the list.
+	#rem monkeydoc Gets an iterator to the list.
 
 	@return A list iterator.
 	
 	#end
+'	Method GetIterator:Iterator()
+'		Return New Iterator( Self,_first )
+'	End
+	
+	#rem monkeydoc @hidden
+	#end
 	Method All:Iterator()
 		Return New Iterator( Self,_first )
 	End
@@ -216,72 +250,6 @@ Class List<T> Implements IContainer<T>
 		_seq+=1
 	End
 	
-	#rem monkeydoc Removes and returns the first value in the list.
-	
-	In debug builds, a runtime error will occur if the list is empty.
-	
-	@return The value removed from the list.
-
-	#end
-	Method RemoveFirst:T()
-		DebugAssert( _length )
-		
-		Local value:=_first._value
-		_first=_first._succ
-		If _first _first._pred=Null Else _last=Null
-		_length-=1
-		_seq+=1
-		Return value
-	End
-	
-	#rem monkeydoc Removes and returns the last value in the list.
-	
-	In debug builds, a runtime error will occur if the list is empty.
-	
-	@return The value removed from the list.
-
-	#end
-	Method RemoveLast:T()
-		DebugAssert( _length )
-		
-		Local value:=_last._value
-		_last=_last._pred
-		If _last _last._succ=Null Else _first=Null
-		_length-=1
-		_seq+=1
-		Return value
-	End
-	
-	#rem monkeydoc Finds the first node in the list that contains a given value.
-	
-	@param value The value to find.
-	
-	@return Node The node containing the value, or null if the value was not found.
-	
-	#end
-	Method FindNode:Node( value:T )
-		Local node:=_first
-		While node And node._value<>value
-			node=node._succ
-		Wend
-		Return node
-	End
-	
-	#rem monkeydoc Finds the last node in the list that contains a given value.
-	
-	@param value The value to find.
-	
-	@return Node The node containing the value, or null if the value was not found.
-	
-	#end
-	Method FindLastNode:Node( value:T )
-		Local node:=_last
-		While node And node._value<>value
-			node=node._pred
-		Wend
-		Return node
-	End
-	
 	#rem monkeydoc Removes the first value in the list equal to a given value.
 	
 	@param value The value to remove.
@@ -310,7 +278,7 @@ Class List<T> Implements IContainer<T>
 		Return True
 	End
 	
-	#rem monkedoc Removes all values in the list equal to a given value.
+	#rem monkeydoc Removes all values in the list equal to a given value.
 	
 	@param value The value to remove.
 	
@@ -329,6 +297,42 @@ Class List<T> Implements IContainer<T>
 		Wend
 		Return n
 	End
+	
+	#rem monkeydoc Removes and returns the first value in the list.
+	
+	In debug builds, a runtime error will occur if the list is empty.
+	
+	@return The value removed from the list.
+
+	#end
+	Method RemoveFirst:T()
+		DebugAssert( _length )
+		
+		Local value:=_first._value
+		_first=_first._succ
+		If _first _first._pred=Null Else _last=Null
+		_length-=1
+		_seq+=1
+		Return value
+	End
+	
+	#rem monkeydoc Removes and returns the last value in the list.
+	
+	In debug builds, a runtime error will occur if the list is empty.
+	
+	@return The value removed from the list.
+
+	#end
+	Method RemoveLast:T()
+		DebugAssert( _length )
+		
+		Local value:=_last._value
+		_last=_last._pred
+		If _last _last._succ=Null Else _first=Null
+		_length-=1
+		_seq+=1
+		Return value
+	End
 
 	#rem monkeydoc Gets an iterator for the value at a given index in the list.
 	
@@ -351,7 +355,7 @@ Class List<T> Implements IContainer<T>
 		Return New Iterator( Self,Null )
 	End
 	
-	#rem monkeydocs Adds a value to the end of the list.
+	#rem monkeydoc Adds a value to the end of the list.
 	
 	This method behaves identically to AddLast.
 	
@@ -362,7 +366,7 @@ Class List<T> Implements IContainer<T>
 		AddLast( value )
 	End
 	
-	#rem monkeydocs Adds all values in an array to the end of the list.
+	#rem monkeydoc Adds all values in an array to the end of the list.
 	
 	@param values The values to add.
 	
@@ -373,7 +377,7 @@ Class List<T> Implements IContainer<T>
 		Next
 	End
 
-	#rem monkedoc Adds all value in a container to the end of the list.
+	#rem monkedoc Adds all values in a container to the end of the list.
 	
 	@param values The values to add.
 	
@@ -383,11 +387,113 @@ Class List<T> Implements IContainer<T>
 			AddLast( value )
 		Next
 	End
+	
+	#rem monkeydoc Sorts the list.
+	
+	@param ascending True to sort the stack in ascending order, false to sort in descending order.
+	
+	@param compareFunc Function to be used to compare values when sorting.
+	
+	#end
+	Method Sort( ascending:Bool=True )
+		If ascending
+			Sort( Lambda:Int( x:T,y:T )
+				Return x<=>y
+			End )
+		Else
+			Sort( Lambda:Int( x:T,y:T )
+				Return -(x<=>y)
+			End )
+		Endif
+	End
+
+	Method Sort( compareFunc:Int( x:T,y:T ) )
+	
+		If _first=_last Return
+	
+		Local insize:=1
+		
+		Repeat
+		
+			Local merges:=0
+			Local p:=_first,tail:Node
+			
+			While p
+
+				merges+=1
+				Local q:=p._succ,qsize:=insize,psize:=1
+				
+				While psize<insize And q
+					psize+=1
+					q=q._succ
+				Wend
+
+				Repeat
+					Local t:Node
+					
+					If psize And qsize And q
+						Local cc:=compareFunc( p._value,q._value )
+						If cc<=0
+							t=p
+							p=p._succ
+							psize-=1
+						Else
+							t=q
+							q=q._succ
+							qsize-=1
+						Endif
+					Else If psize
+						t=p
+						p=p._succ
+						psize-=1
+					Else If qsize And q
+						t=q
+						q=q._succ
+						qsize-=1
+					Else
+						Exit
+					Endif
+					
+					t._pred=tail
+					If tail tail._succ=t Else _first=t
+					tail=t
+					
+'					t._pred=tail
+'					tail._succ=t
+'					tail=t
+					
+				Forever
+				
+				p=q
+				
+			Wend
+			
+			tail._succ=Null
+			_last=tail
+			
+'			tail._succ=_head
+'			_head._pred=tail
+
+			If merges<=1 Return
+
+			insize*=2
+		Forever
+
+	End Method
+	
+	#rem monkeydoc Joins the values in the string list.
+	
+	@param sepeator The separator to be used when joining values.
+	
+	@return The joined values.
+	
+	#end
+	Method Join:String( separator:String="" ) Where T=String
+		Return separator.Join( ToArray() )
+	End
 
 	Private
 	
-	'could make these public if people REALLY want...
-	'
 	Method FirstNode:Node()
 		Return _first
 	End
@@ -396,6 +502,22 @@ Class List<T> Implements IContainer<T>
 		Return _last
 	End
 	
+	Method FindNode:Node( value:T )
+		Local node:=_first
+		While node And node._value<>value
+			node=node._succ
+		Wend
+		Return node
+	End
+	
+	Method FindLastNode:Node( value:T )
+		Local node:=_last
+		While node And node._value<>value
+			node=node._pred
+		Wend
+		Return node
+	End
+	
 	Method Erase:Node( node:Node )
 		If Not node Return Null	'OK to erase tail element...
 		Local succ:=node._succ
@@ -434,12 +556,3 @@ Class List<T> Implements IContainer<T>
 	End
 	
 End
-
-Class IntList Extends List<Int>
-End
-
-Class FloatList Extends List<Float>
-End
-
-Class StringList Extends List<String>
-End

+ 2 - 2
modules/std/map.monkey2

@@ -1,7 +1,7 @@
 
-Namespace std
+Namespace std.collections
 
-#rem monkedoc The Map class.
+#rem monkeydoc The Map class.
 #end
 Class Map<K,V>
 

+ 21 - 3
modules/std/markdown.monkey2

@@ -1,10 +1,28 @@
 
 Namespace std.markdown
 
+#Import "<hoedown.monkey2>"
+
+Using hoedown
+
 Function MarkdownToHtml:String( markdown:String )
 
-	Local help:=LoadString( "asset::help.markdown" )
-	Local html:=LoadString( "asset::markdown.html" )
-	html=html.Replace( "${CONTENT}",HtmlView.MarkdownToHtml( help ) )
+	Local ob:=hoedown_buffer_new( 4096 )
+	
+	Local r:=hoedown_html_renderer_new( HOEDOWN_HTML_NONE,10 )
+	
+	Local doc:=hoedown_document_new( r,HOEDOWN_EXT_TABLES|HOEDOWN_EXT_FENCED_CODE,10 )
+		
+	hoedown_document_render( doc,ob,markdown,markdown.Utf8Length )
+	
+	Local html:=String.FromCString( hoedown_buffer_cstr( ob ) )
+	
+	hoedown_document_free( doc )
+	
+	hoedown_html_renderer_free( r )
+	
+	hoedown_buffer_free( ob )
+	
+	Return html
 
 End

+ 26 - 25
modules/std/pixelformat.monkey2

@@ -1,34 +1,35 @@
 
-Namespace std
+Namespace std.graphics
 
 #rem monkeydoc PixelFormat enumeration.
+
+| PixelFormat	| Description
+|:--------------|:-----------
+| `Unknown`		| Unknown pixel format.
+| `I8`			| 8 bit intensity.
+| `A8`			| 8 bit alpha.
+| `IA16`		| 8 bit intensity, alpha.
+| `RGB24`		| 8 bit red, green, blue.
+| `RGBA32`		| 8 bit red, green, blue, alpha.
+
 #end
 Enum PixelFormat
 
-	None=0
-	
-	#rem monkeydoc 8 bit intensity.
-	#end
-	I8=1
-	
-	#rem monkeydoc 8 bit alpha.
-	#end
-	A8=2
-	
-	#rem monkeydoc 8 bit intensity, 8 bit alpha.
-	#end
-	IA16=3
-	
-	#rem monkeydoc 8 bit r,g,b.
-	#end
-	RGB24=4
-	
-	#rem monkeydoc 8 bit r,g,b,a.
-	#end
-	RGBA32=5
+	Unknown,I8,A8,IA16,RGB24,RGBA32
+
+End
 
-	#rem monkeydoc Any format.
-	#end
-	Any=9999
+Function PixelFormatDepth:Int( format:PixelFormat )
 
+	Select format
+	Case PixelFormat.I8 Return 1
+	Case PixelFormat.A8 Return 1
+	Case PixelFormat.IA16 Return 2
+	Case PixelFormat.RGB24 Return 3
+	Case PixelFormat.RGBA32 Return 4
+	Default Assert( False )
+	End
+	
+	Return 0
+	
 End

+ 43 - 118
modules/std/pixmap.monkey2

@@ -1,10 +1,5 @@
 
-Namespace std
-
-#Import "<stb-image.monkey2>"
-
-Using libc
-Using stb.image
+Namespace std.graphics
 
 #rem monkeydoc Pixmap class.
 
@@ -21,9 +16,41 @@ Class Pixmap
 	
 	@param format The pixmap format.
 	
+	@param data A pointer to the pixmap data.
+	
+	@param pitch The pitch of the data.
+	
+	@param onDiscard A function to free the data when pixmap is discarded.
+	
 	#end
-	Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.Any )
-		Self.New( width,height,format,Null,0,Null )
+	Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.RGBA32 )
+
+		Local depth:=PixelFormatDepth( format )
+		Local pitch:=depth * height
+		Local data:=Cast<UByte Ptr>( libc.malloc( width*height*pitch ) )
+		
+		_width=width
+		_height=height
+		_format=format
+		_depth=depth
+		_data=data
+		_pitch=pitch
+		_onDiscard=Lambda( data:UByte Ptr )
+			libc.free( data )
+		End
+	End
+	
+	Method New( width:Int,height:Int,format:PixelFormat,data:UByte Ptr,pitch:Int,onDiscard:Void( data:UByte Ptr ) )
+	
+		Local depth:=PixelFormatDepth( format )
+		
+		_width=width
+		_height=height
+		_format=format
+		_depth=depth
+		_data=data
+		_pitch=pitch
+		_onDiscard=onDiscard
 	End
 
 	#rem monkeydoc Releases the memory used by a pixmap.
@@ -37,14 +64,13 @@ Class Pixmap
 	#end
 	Method Discard()
 		If Not _data Return
-		If Not _owner libc.free( _data )
+		_onDiscard( _data )
 		_width=0
 		_height=0
 		_pitch=0
 		_depth=0
-		_format=PixelFormat.None
 		_data=Null
-		_owner=Null
+		_onDiscard=Null
 	End
 	
 	#rem monkeydoc The pixmap width.
@@ -347,7 +373,7 @@ Class Pixmap
 	#rem monkeydoc Returns a rectangular window into the pixmap.
 	
 	In debug builds, a runtime error will occur if the rectangle lies outside of the pixmap area.
-s	
+	
 	@param x The x coordinate of the top left of the rectangle.
 
 	@param y The y coordinate of the top left of the rectangle.
@@ -360,7 +386,7 @@ s
 	Method Window:Pixmap( x:Int,y:Int,width:Int,height:Int )
 		DebugAssert( x>=0 And y>=0 And width>=0 And height>=0 And x+width<=_width And y+height<=_height )
 		
-		Return New Pixmap( width,height,_format,PixelPtr( x,y ),_pitch,Self )
+		Return New Pixmap( width,height,_format,PixelPtr( x,y ),_pitch,Null )
 	End
 	
 	#rem monkeydoc Loads a pixmap from a file.
@@ -372,58 +398,10 @@ s
 	@return Null if the file could not be opened, or contained invalid image data.
 	
 	#end
-	Function Load:Pixmap( path:String,format:PixelFormat=PixelFormat.Any )
+	Function LoadPixmap:Pixmap( path:String,format:PixelFormat=PixelFormat.Unknown )
 	
-		Local x:Int,y:Int,comp:Int,req_comp:Int
-		
-		Select format
-		Case PixelFormat.Any
-			req_comp=0
-		Case PixelFormat.A8,PixelFormat.I8
-			req_comp=1
-		Case PixelFormat.IA16
-			req_comp=2
-		Case PixelFormat.RGB24
-			req_comp=3
-		Case PixelFormat.RGBA32
-			req_comp=4
-		Default
-			'THROW
-		End
-		
-		Local stream:=Stream.Open( path,"r" )
-		If Not stream Return Null
-		
-		Local user:stbi_user
-		user.stream=stream
-		
-		Local clbks:stbi_io_callbacks
-		clbks.read=stbi_read
-		clbks.skip=stbi_skip
-		clbks.eof=stbi_eof
-		
-		Local data:=stbi_load_from_callbacks( Varptr clbks,Varptr user,Varptr x,Varptr y,Varptr comp,req_comp )
-		
-		stream.Close()
-		
-		If Not data Return Null
-		
-		If format=PixelFormat.Any
-			Select comp
-			Case 1 
-				format=PixelFormat.I8
-			Case 2
-				format=PixelFormat.IA16
-			Case 3
-				format=PixelFormat.RGB24
-			Case 4
-				format=PixelFormat.RGBA32
-			Default
-				Assert( False )
-			End
-		End
-		
-		Return New Pixmap( x,y,format,data,0,null )
+		Return internal.LoadPixmap( path,format )
+
 	End
 	
 	Private
@@ -434,59 +412,6 @@ s
 	Field _depth:Int
 	Field _data:UByte Ptr
 	Field _pitch:Int
-	Field _owner:Pixmap
-	
-	Struct stbi_user
-		Field stream:Stream
-	End
-	
-	Function stbi_read:Int( user:Void Ptr,data:stbi_char Ptr,count:Int )
-		Local stream:=Cast<stbi_user Ptr>( user )[0].stream
-		Return stream.Read( data,count )
-	End
-	
-	Function stbi_skip:Void( user:Void Ptr,count:Int )
-		Local stream:=Cast<stbi_user Ptr>( user )[0].stream
-		stream.Seek( stream.Position+count )
-	End
-	
-	Function stbi_eof:Int( user:Void Ptr )
-		Local stream:=Cast<stbi_user Ptr>( user )[0].stream
-		Return stream.Eof
-	End
-	
-	Method New( width:Int,height:Int,format:PixelFormat,data:UByte Ptr,pitch:Int,owner:Pixmap )
-	
-		If format=PixelFormat.Any format=PixelFormat.RGBA32
-	
-		Local depth:=0
-		Select format
-		Case PixelFormat.A8
-			depth=1
-		Case PixelFormat.I8
-			depth=1
-		Case PixelFormat.IA16
-			depth=2
-		Case PixelFormat.RGB24
-			depth=3
-		Case PixelFormat.RGBA32
-			depth=4
-		Default
-			Assert( False )
-		End
-		
-		_width=width
-		_height=height
-		_format=format
-		_depth=depth
-		
-		_data=data
-		_pitch=pitch
-		_owner=owner
-		
-		If Not _pitch _pitch=_width*_depth
-		
-		If Not _data _data=Cast<UByte Ptr>( libc.malloc( _pitch*_height ) )
-	End
+	Field _onDiscard:Void( data:UByte Ptr )
 
 End

+ 70 - 0
modules/std/pixmaploader.monkey2

@@ -0,0 +1,70 @@
+
+Namespace std.graphics.internal
+
+#Import "<stb-image>"
+
+Using stb.image
+Using std.stream
+
+Private
+
+Struct stbi_user
+	Field stream:Stream
+End
+
+Function stbi_read:Int( user:Void Ptr,data:stbi_char Ptr,count:Int )
+	Local stream:=Cast<stbi_user Ptr>( user )[0].stream
+	Return stream.Read( data,count )
+End
+
+Function stbi_skip:Void( user:Void Ptr,count:Int )
+	Local stream:=Cast<stbi_user Ptr>( user )[0].stream
+	stream.Seek( stream.Position+count )
+End
+
+Function stbi_eof:Int( user:Void Ptr )
+	Local stream:=Cast<stbi_user Ptr>( user )[0].stream
+	Return stream.Eof
+End
+
+Public
+
+#rem monkeydoc @hidden
+#end
+Function LoadPixmap:Pixmap( path:String,format:PixelFormat )
+
+	Local x:Int,y:Int,comp:Int,req_comp:Int
+	
+	If format<>PixelFormat.Unknown req_comp=PixelFormatDepth( format )
+	
+	Local stream:=Stream.Open( path,"r" )
+	If Not stream Return Null
+
+	Local user:stbi_user
+	user.stream=stream
+	
+	Local clbks:stbi_io_callbacks
+	clbks.read=stbi_read
+	clbks.skip=stbi_skip
+	clbks.eof=stbi_eof
+	
+	Local data:=stbi_load_from_callbacks( Varptr clbks,Varptr user,Varptr x,Varptr y,Varptr comp,req_comp )
+	
+	stream.Close()
+	
+	If Not data Return Null
+	
+	If format=PixelFormat.Unknown
+		Select comp
+		Case 1 format=PixelFormat.I8
+		Case 2 format=PixelFormat.IA16
+		Case 3 format=PixelFormat.RGB24
+		Case 4 format=PixelFormat.RGBA32
+		Default Assert( False )
+		End
+	End
+	
+	Return New Pixmap( x,y,format,data,PixelFormatDepth( format )*y,Lambda( data:UByte Ptr )
+		stbi_image_free( data )
+	End )
+End

+ 61 - 54
modules/std/stack.monkey2

@@ -1,45 +1,61 @@
 
-Namespace std
+Namespace std.collections
 
-Using std
+Alias IntStack:Stack<Int>
 
+Alias FloatStack:Stack<Float>
+
+Alias StringStack:Stack<String>
+
+#rem monkeydoc The Stack class.
+#end
 Class Stack<T> Implements IContainer<T>
 
 	Struct Iterator 'Implements IIterator<T>
 	
+		Private
+
 		Field _stack:Stack
 		Field _index:Int
 		Field _seq:Int
 		
+		Method AssertSeq()
+			DebugAssert( _seq=_stack._seq,"Concurrent list modification" )
+		End
+		
+		Method AssertCurrent()
+			DebugAssert( Valid,"Invalid list iterator" )
+		End
+		
+		Public
+		
 		Method New( stack:Stack,index:Int )
 			_stack=stack
 			_index=index
 			_seq=stack._seq
 		End
 		
-		Method AssertSeq()
-			DebugAssert( _seq=_stack._seq,"Concurrent list modification" )
-		End
-		
-		Method AssertValid()
-			DebugAssert( Valid,"Invalid list iterator" )
+		Property AtEnd:Bool()
+			AssertSeq()
+			Return _index=_stack._length
 		End
 		
+		#rem monkeydoc @hidden
+		#end
 		Property Valid:Bool()
-			AssertSeq()
-			Return _index<_stack._length
+			Return Not AtEnd
 		End
 		
 		Property Current:T()
-			AssertValid()
+			AssertCurrent()
 			Return _stack._data[_index]
 		Setter( current:T )
-			AssertValid()
+			AssertCurrent()
 			_stack._data[_index]=current
 		End
 		
 		Method Bump()
-			AssertValid()
+			AssertCurrent()
 			_index+=1
 		End
 		
@@ -56,7 +72,7 @@ Class Stack<T> Implements IContainer<T>
 		End
 	End
 	
-	Protected
+	Private
 
 	Field _data:T[]
 	Field _length:Int
@@ -64,7 +80,7 @@ Class Stack<T> Implements IContainer<T>
 	
 	Public
 	
-	#rem monkeydoc Creates a new empty stack.
+	#rem monkeydoc Creates a new stack.
 	#end
 	Method New()
 		_data=New T[10]
@@ -88,11 +104,17 @@ Class Stack<T> Implements IContainer<T>
 		Return _length=0
 	End
 
-	#rem monkeydoc Gets an iterator to all values in the stack.
-
+	#rem monkeydoc Gets an iterator to the stack.
+	
 	@return A stack iterator.
 	
 	#end
+'	Method GetIterator:Iterator()
+'		Return New Iterator( Self,0 )
+'	End
+
+	#rem monkeydoc @hidden
+	#end
 	Method All:Iterator()
 		Return New Iterator( Self,0 )
 	End
@@ -106,7 +128,7 @@ Class Stack<T> Implements IContainer<T>
 		Return _data.Slice( 0,_length )
 	End
 	
-	#rem monkedoc Gets the underlying array used by the stack.
+	#rem monkeydoc Gets the underlying array used by the stack.
 	
 	Note that the returned array may be longer than the stack length.
 	
@@ -277,7 +299,7 @@ Class Stack<T> Implements IContainer<T>
 		_data[index]=value
 	End
 	
-	#rem monkeydoc Gets the value a stack element.
+	#rem monkeydoc Gets the value of a stack element.
 	
 	In debug builds, a runtime error will occur if `index` is less than 0, or greather than or equal to the length of the stack.
 	
@@ -527,39 +549,31 @@ Class Stack<T> Implements IContainer<T>
 	#rem monkeydoc Sorts the stack.
 
 	@param ascending True to sort the stack in ascending order, false to sort in descending order.
+	
+	@param compareFunc Function to be used to compare values when sorting.
+	
+	@param lo Index of first value to sort.
+	
+	@param hi Index of last value to sort.
 
 	#end
 	Method Sort( ascending:Bool=True )
 		If ascending
-			Sort( 0,_length-1,Lambda:Int( x:T,y:T )
+			Sort( Lambda:Int( x:T,y:T )
 				Return x<=>y
 			End )
 		Else
-			Sort( 0,_length-1,Lambda:Int( x:T,y:T )
+			Sort( Lambda:Int( x:T,y:T )
 				Return y<=>x
 			End )
 		Endif
 	End
-	
-	#rem monkeydoc Sorts the stack using a comparison function.
-	
-	@param compareFunc The function used to compare values.
-	
-	#end
+
 	Method Sort( compareFunc:Int( x:T,y:T ) )
-		Sort( 0,_length-1,compareFunc )
+		Sort( compareFunc,0,_length-1 )
 	End
-	
-	#rem monkeydoc Sorts a range of stack elements using a comparison function.
 
-	@param lo The first element.
-	
-	@param hi The last element.
-	 
-	@param compareFunc The function used to compare values.
-
-	#end	
-	Method Sort( lo:Int,hi:Int,compareFunc:Int( x:T,y:T ) )
+	Method Sort( compareFunc:Int( x:T,y:T ),lo:Int,hi:int )
 	
 		If hi<=lo Return
 		
@@ -596,8 +610,8 @@ Class Stack<T> Implements IContainer<T>
 			y-=1
 		Until x>y
 
-		Sort( lo,y,compareFunc )
-		Sort( x,hi,compareFunc )
+		Sort( compareFunc,lo,y )
+		Sort( compareFunc,x,hi )
 	End
 	
 	'***** Stack style extensions *****
@@ -642,21 +656,14 @@ Class Stack<T> Implements IContainer<T>
 		Add( value )
 	End
 
-'	Method Join:String( separator:String ) Where T=String
-'		Return separator.Join( ToArray() )
-'	End
+	#rem monkeydoc Joins the values in the string list.
 	
-End
-
-Class IntStack Extends Stack<Int>
-End
-
-Class FloatStack Extends Stack<Float>
-End
-
-Class StringStack Extends Stack<String>
-
-	Method Join:String( separator:String )
+	@param sepeator The separator to be used when joining values.
+	
+	@return The joined values.
+	
+	#end
+	Method Join:String( separator:String ) Where T=String
 		Return separator.Join( ToArray() )
 	End
 	

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 19 - 2061
modules/std/std.json


+ 7 - 3
modules/std/std.monkey2

@@ -9,9 +9,7 @@ Namespace std
 #Import "map.monkey2"
 #Import "random.monkey2"
 #Import "chartype.monkey2"
-
 #Import "filesystem.monkey2"
-#Import "filesystemex.monkey2"
 
 #Import "byteorder.monkey2"
 
@@ -27,14 +25,20 @@ Namespace std
 #Import "pixelformat.monkey2"
 #Import "color.monkey2"
 #Import "pixmap.monkey2"
+#Import "pixmaploader.monkey2"
 
 #Import "generator.monkey2"
 
 #Import "geom.monkey2"
-'#Import "json.monkey2"
+
+#Import "json.monkey2"
+
+#Import "markdown.monkey2"
 
 #Import "time.monkey2"
 
+Private
+
 Function Main()
 
 	Stream.OpenFuncs["file"]=Lambda:Stream( proto:String,path:String,mode:String )

+ 12 - 6
modules/std/stream.monkey2

@@ -1,7 +1,9 @@
 
-Namespace std
+Namespace std.stream
 
 Using libc
+Using std.memory
+Using std.collections
 
 #rem monkeydoc Stream class.
 #end
@@ -38,27 +40,27 @@ Class Stream
 	#end
 	Method Seek( position:Int ) Abstract
 	
-	#rem monkedoc Reads data from the filestream to memory.
+	#rem monkeydoc Reads data from the filestream to memory.
 	
-	@param buf A pointer to the memory to read the data into.
+	@param mem A pointer to the memory to read the data into.
 	
 	@param count The number of bytes to read.
 	
 	@return The number of bytes actually read.
 	
 	#end
-	Method Read:Int( buf:Void Ptr,count:Int ) Abstract
+	Method Read:Int( mem:Void Ptr,count:Int ) Abstract
 	
 	#rem monkeydoc Writes data to the stream from memory.
 	
-	@param buf A pointer to the memory to write the data from.
+	@param mem A pointer to the memory to write the data from.
 	
 	@param count The number of bytes to write.
 	
 	@return The number of bytes actually written.
 	
 	#end
-	Method Write:Int( buf:Void Ptr,count:Int ) Abstract
+	Method Write:Int( mem:Void Ptr,count:Int ) Abstract
 	
 	#rem monkeydoc The byte order of the stream.
 	#end
@@ -362,8 +364,12 @@ Class Stream
 
 	End
 	
+	#rem monkeydoc @hidden
+	#end
 	Alias OpenFunc:Stream( proto:String,path:String,mode:String )
 	
+	#rem monkeydoc @hidden
+	#end
 	Const OpenFuncs:=New StringMap<OpenFunc>
 	
 	Private

+ 1 - 1
modules/std/stringio.monkey2

@@ -5,7 +5,7 @@ Using libc
 
 'These will eventually be string extensions, eg: Function String.Load() and Method String.Save()
 
-#rem monkeydoc Load a utf8 encoded string from a file.
+#rem monkeydoc Loads a utf8 encoded string from a file.
 
 An empty string will be returned if the file could not be opened.
 

+ 5 - 3
modules/std/time.monkey2

@@ -1,7 +1,9 @@
 
 Namespace std.time
 
-#rem monkeydoc DateTime class.
+Private
+
+#rem monkeydoc @hidden Time class.
 #end
 Class Time
 
@@ -103,7 +105,7 @@ Class Time
 	
 End
 
-#rem monkeydoc Gets the number of seconds since the app started.
+#rem monkeydoc @hidden Gets the number of seconds since the app started.
 #end
 Function Seconds:Double()
 	Return Double(clock())/Double(CLOCKS_PER_SEC)
@@ -111,7 +113,7 @@ End
 
 #rem monkeydoc Gets the number of milliseconds since the app started.
 #end
-Function Millisecs:Long()
+Function Millisecs:Int()
 	'Note:CLOCKS_PER_SECOND=1000000 on macos/linux, 1000 on windows...
 	If CLOCKS_PER_SEC>=1000 Return clock()/(CLOCKS_PER_SEC/1000)
 	Return clock()*(1000/CLOCKS_PER_SEC)	'is that right?!?

+ 3 - 1
modules/std/zipstream.monkey2

@@ -1,11 +1,13 @@
 
-Namespace std
+Namespace std.stream
 
 #Import "<miniz.monkey2>"
 
 Using libc
 Using miniz
 
+#rem monkeydoc @hidden ZipStream class.
+#end
 Class ZipStream Extends DataStream
 
 	Method New( buf:DataBuffer )

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels