"""Convert Wavefront OBJ / MTL files into Three.js (JSON model version, to be used with ascii / binary loader)

-------------------------
How to use this converter
-------------------------

python convert_obj_three.py -i infile.obj -o outfile.js [-m "morphfiles*.obj"] [-c "morphcolors*.obj"] [-a center|centerxz|top|bottom|none] [-s smooth|flat] [-t ascii|binary] [-d invert|normal] [-b] [-e]

Notes:
    - flags
        -i infile.obj			input OBJ file
        -o outfile.js			output JS file
        -m "morphfiles*.obj"	morph OBJ files (can use wildcards, enclosed in quotes multiple patterns separate by space)
        -c "morphcolors*.obj"	morph colors OBJ files (can use wildcards, enclosed in quotes multiple patterns separate by space)
        -a center|centerxz|top|bottom|none model alignment
        -s smooth|flat			smooth = export vertex normals, flat = no normals (face normals computed in loader)
        -t ascii|binary			export ascii or binary format (ascii has more features, binary just supports vertices, faces, normals, uvs and materials)
        -d invert|normal		invert transparency
        -b						bake material colors into face colors
        -x 10.0                 scale and truncate
        -f 2                    morph frame sampling step

    - by default:
        use smooth shading (if there were vertex normals in the original model)
        will be in ASCII format
        original model is assumed to use non-inverted transparency / dissolve (0.0 fully transparent, 1.0 fully opaque)
        no face colors baking
        no scale and truncate
        morph frame step = 1 (all files will be processed)

    - binary conversion will create two files:
        outfile.js  (materials)
        outfile.bin (binary buffers)

--------------------------------------------------
How to use generated JS file in your HTML document
--------------------------------------------------

    <script type="text/javascript" src="Three.js"></script>

    ...

    <script type="text/javascript">
        ...

        // load ascii model

        var jsonLoader = new THREE.JSONLoader();
        jsonLoader.load( "Model_ascii.js", function( geometry ) { createScene( geometry ) } );

        // load binary model

        var binLoader = new THREE.BinaryLoader();
        binLoader.load( "Model_bin.js", function( geometry ) { createScene( geometry) } );

        function createScene( geometry ) {

            var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );

        }

        ...
    </script>

-------------------------------------
Parsers based on formats descriptions
-------------------------------------

    http://en.wikipedia.org/wiki/Obj
    http://en.wikipedia.org/wiki/Material_Template_Library

-------------------
Current limitations
-------------------

    - for the moment, only diffuse color and texture are used
      (will need to extend shaders / renderers / materials in Three)

    - texture coordinates can be wrong in canvas renderer
      (there is crude normalization, but it doesn't
       work for all cases)

    - smoothing can be turned on/off only for the whole mesh

----------------------------------------------
How to get proper OBJ + MTL files with Blender
----------------------------------------------

    0. Remove default cube (press DEL and ENTER)

    1. Import / create model

    2. Select all meshes (Select -> Select All by Type -> Mesh)

    3. Export to OBJ (File -> Export -> Wavefront .obj)
        - enable following options in exporter
            Material Groups
            Rotate X90
            Apply Modifiers
            High Quality Normals
            Copy Images
            Selection Only
            Objects as OBJ Objects
            UVs
            Normals
            Materials

        - select empty folder
        - give your exported file name with "obj" extension
        - click on "Export OBJ" button

    4. Your model is now all files in this folder (OBJ, MTL, nu
mber of images)
        - this converter assumes all files staying in the same folder,
          (OBJ / MTL files use relative paths)

        - for WebGL, textures must be power of 2 sized

------
Author
------
AlteredQualia http://alteredqualia.com

"""

import fileinput
import operator
import random
import os.path
import getopt
import sys
import struct
import math
import glob

# #######################################
##############
# Configuration
# #####################################################
ALIGN = "none"        	# center centerxz bottom top none
SHADING = "smooth"      # smooth flat
TYPE = "ascii"          # ascii binary
TRANSPARENCY = "normal" # normal invert

TRUNCATE = False
SCALE = 1.0

FRAMESTEP = 1

BAKE_COLORS = False

# default colors for debugging (each material gets one distinct color):
# white, red, green, blue, yellow, cyan, magenta
COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]

# #####################################################
# Templates
# #####################################################
TEMPLATE_FILE_ASCII = u"""\
{

    "metadata" :
    {
        "formatVersion" : 3,
        "sourceFile"    : "%(fname)s",
        "generatedBy"   : "OBJConverter",
        "vertices"      : %(nvertex)d,
        "faces"         : %(nface)d,
        "normals"       : %(nnormal)d,
        "colors"        : %(ncolor)d,
        "uvs"           : %(nuv)d,
        "materials"     : %(nmaterial)d
    },

    "scale" : %(scale)f,

    "materials": [%(materials)s],

    "vertices": [%(vertices)s],

    "morphTargets": [%(morphTargets)s],

    "morphColors": [%(morphColors)s],

    "normals": [%(normals)s],

    "colors": [%(colors)s],

    "uvs": [[%(uvs)s]],

    "faces": [%(faces)s]

}
"""

TEMPLATE_FILE_BIN = u"""\
{

    "metadata" :
    {
        "formatVersion" : 3,
        "sourceFile"    : "%(fname)s",
        "generatedBy"   : "OBJConverter",
        "vertices"      : %(nvertex)d,
        "faces"         : %(nface)d,
        "normals"       : %(nnormal)d,
        "uvs"           : %(nuv)d,
        "materials"     : %(nmaterial)d
    },

    "materials": [%(materials)s],

    "buffers": "%(buffers)s"

}
"""

TEMPLATE_VERTEX = "%f,%f,%f"
TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"

TEMPLATE_N = "%.5g,%.5g,%.5g"
TEMPLATE_UV = "%.5g,%.5g"
TEMPLATE_COLOR = "%.3g,%.3g,%.3g"
TEMPLATE_COLOR_DEC = "%d"

TEMPLATE_MORPH_VERTICES = '\t{ "name": "%s", "vertices": [%s] }'
TEMPLATE_MORPH_COLORS   = '\t{ "name": "%s", "colors": [%s] }'

# #####################################################
# Utils
# #####################################################
def file_exists(filename):
    """Return true if file exists and is accessible for reading.

    Should be safer than just testing for existence due to links and
    permissions magic on Unix filesystems.

    @rtype: boolean
    """

    try:
        f = open(filename, 'r')
        f.close()
        return True
    except IOError:
        return False


def get_name(fname):
    """Create model name based of filename ("path/fname.js" -> "fname").
    """

    return os.path.splitext(os.path.basename(fname))[0]

def bbox(vertices):
    """Compute bounding box of vertex array.
    """

    if len(vertices)>0:
        minx = maxx = vertices[0][0]
        miny = maxy = vertices[0][1]
        minz = maxz = vertices[0][2]

        for v in vertices[1:]:
            if v[0]<minx:
                minx = v[0]
            elif v[0]>maxx:
                maxx = v[0]

            if v[1]<miny:
                miny = v[1]
            elif v[1]>maxy:
                maxy = v[1]

            if v[2]<minz:
                minz = v[2]
            elif v[2]>maxz:
                maxz = v[2]

        return { 'x':[minx,maxx], 'y':[miny,maxy], 'z':[minz,maxz] }

    else:
        return { 'x':[0,0], 'y':[0,0], 'z':[0,0] }

def translate(vertices, t):
    """Translate array of vertices by vector t.
    """

    for i in xrange(len(vertices)):
        vertices[i][0] += t[0]
        vertices[i][1] += t[1]
        vertices[i][2] += t[2]

def center(vertices):
    """Center model (middle of bounding box).
    """

    bb = bbox(vertices)

    cx = bb['x'][0] 