   return ptr
 
 ignoreLine = (text, ptr) ->
-  while true
+  while undefined != text[ptr]
     if '\r' == text[ptr]
       if '\r' != text[ptr + 1]
         ptr = ptr + 1

    vx: 0, vy: 0, vz: 0
  (text, ptr) ->
    ptr = ignoreSpace(text, ptr)
    {num: result.vx, ptr} = parseFloatx(text, ptr)
    ptr = ignoreSpace(text, ptr)
    {num: result.vy, ptr} = parseFloatx(text, ptr)
    ptr = ignoreSpace(text, ptr)
    {num: result.vz, ptr} = parseFloatx(text, ptr)
    result.ptr = ignoreLine(text, ptr)
    return result


# # # # # # # # # # # # # # # # # # # #

CHAR_INT = 0x1
CHAR_INDEX = 0x2
CHAR_FLOAT = 0x4

CHAR_SIZE = 128
CHAR_TABLE = new Uint32Array(CHAR_SIZE)
CHAR_TABLE[45] = CHAR_FLOAT # -
CHAR_TABLE[46] = CHAR_FLOAT # .
CHAR_TABLE[47] = CHAR_INDEX # /
CHAR_TABLE[48] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 0
CHAR_TABLE[49] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 1
CHAR_TABLE[50] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 2
CHAR_TABLE[51] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 3
CHAR_TABLE[52] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 4
CHAR_TABLE[53] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 5
CHAR_TABLE[54] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 6
CHAR_TABLE[55] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 7
CHAR_TABLE[56] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 8
CHAR_TABLE[57] = CHAR_INT | CHAR_FLOAT | CHAR_INDEX # 9
CHAR_TABLE[69] = CHAR_FLOAT # E
CHAR_TABLE[101] = CHAR_FLOAT # e

VERTEX_STRIDE = 3
TEXTURE_STRIDE = 2
NORMAL_STRIDE = 3

createContext = () ->
  return {
    vertex: new Array(512 * VERTEX_STRIDE)
    vertexLen: 0
    texture: new Array(512 * TEXTURE_STRIDE)
    textureLen: 0
    normal: new Array(512 * NORMAL_STRIDE)
    normalLen: 0

    initFlag: false
    vertexStride: 0
    textureStride: 0
    normalStride: 0
    totalStride: 0

    vtxBuf: null
    vtxBufLen: 0
    idxBuf: null
    idxBufLen: 0
    idxMap: Object.create(null)
  }

ignoreSpace = (text, ptr) ->
  if ' ' != text[ptr] and '\t' != text[ptr]
